Hi everyone,
After many tries I've finally succeed decoding a mp3 file. But now the
sound seems whitout dynamic, I don't know if the problem is the function
that I'm using to scale the samples or the routine that I've used to
save it to a file (using libsndfile). Can anyone help me ?
Thank you !
Daniel
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "mad.h"
#include "sndfile.h"
#define INPUT_BUFFER_SIZE 65535
struct private_data {
FILE *file;
unsigned char *inputBuffer;
int numChannels;
int samplerate;
int len;
float *sample;
int icount,
ocount;
bool firstRun;
void *userData; //nao sei pra que vai usar...
};
/* The MAD callbacks */
enum mad_flow input_cb (void *_data, struct mad_stream *stream);
enum mad_flow output_cb(void *_data, struct mad_header const *header, struct mad_pcm *pcm);
enum mad_flow error_cb (void *_data, struct mad_stream *stream, struct mad_frame *frame);
inline float scale(mad_fixed_t sample)
{
return (float) (sample / (float) (1L << MAD_F_FRACBITS));
}
int main(){
struct private_data mPrivateData;
mad_decoder mDecoder;
int chn;
const char *filename="saida.wav";
SF_INFO info;
SNDFILE *outfile;
/* Prepare decoder data, initialize decoder */
mPrivateData.len = 0;
mPrivateData.file = fopen("weapon2.mp3","rb");
mPrivateData.inputBuffer = new unsigned char [INPUT_BUFFER_SIZE];
mPrivateData.numChannels = 0;
mPrivateData.samplerate = 0;
mPrivateData.icount = mPrivateData.ocount = 0;
mPrivateData.firstRun = true;
mad_decoder_init(&mDecoder, &mPrivateData, input_cb, 0, 0, output_cb, error_cb, 0);
if(mad_decoder_run(&mDecoder, MAD_DECODER_MODE_SYNC) == 0)
{
/* success */
printf("success\n");
//GRAVAR O ARQUIVO COM A SNDFILE
info.samplerate = mPrivateData.samplerate;
info.channels = mPrivateData.numChannels;
//printf("Sample rate %d\n",info.samplerate);
//printf("Channels %d\n",info.channels);
//info.samplerate = 44100;
//info.channels = 1;
info.format = 65538;
info.sections = 1;
info.seekable = 1;
info.frames = 0;
outfile = sf_open(filename , SFM_WRITE , &info);
sf_write_float( outfile, mPrivateData.sample , mPrivateData.len) ;
sf_close(outfile);
mad_decoder_finish(&mDecoder);
/* copy the WaveTrack pointers into the Track pointer list that
* we are expected to fill */
//*outTracks = new Track* [mPrivateData.numChannels];
//for(chn = 0; chn < mPrivateData.numChannels; chn++) {
// mPrivateData.channels[chn]->Flush();
// (*outTracks)[chn] = mPrivateData.channels[chn];
//}
//*outNumTracks = mPrivateData.numChannels;
//delete mPrivateData.inputBuffer;
//delete[] mPrivateData.channels;
//return true;
}
else {
/* failure */
printf("failure\n");
mad_decoder_finish(&mDecoder);
/* delete everything */
//for(chn = 0; chn < mPrivateData.numChannels; chn++)
// delete mPrivateData.channels[chn];
//delete[] mPrivateData.channels;
//delete mPrivateData.inputBuffer;
//return false;
}
//mad_decoder_finish(&mDecoder);
/* delete everything */
//for(chn = 0; chn < mPrivateData.numChannels; chn++)
//delete mPrivateData.channels[chn];
printf("Input %d Output %d\n",mPrivateData.icount, mPrivateData.ocount);
delete mPrivateData.inputBuffer;
fclose(mPrivateData.file);
return(0);
}
//
// MAD Callbacks
//
/* The input callback is called when the decoder wants more data. */
enum mad_flow input_cb(void *_data, struct mad_stream *stream)
{
struct private_data *data = (struct private_data *)_data;
data->icount += 1;
if(feof(data->file))
return MAD_FLOW_STOP;
/* "Each time you refill your buffer, you need to preserve the data in
* your existing buffer from stream.next_frame to the end.
*
* This usually amounts to calling memmove() on this unconsumed portion
* of the buffer and appending new data after it, before calling
* mad_stream_buffer()"
* -- Rob Leslie, on the mad-dev mailing list */
unsigned int unconsumedBytes;
if(stream->next_frame) {
unconsumedBytes = data->inputBuffer + INPUT_BUFFER_SIZE - stream->next_frame;
memmove(data->inputBuffer, stream->next_frame, unconsumedBytes);
}
else
unconsumedBytes = 0;
//off_t read = data->file->Read(data->inputBuffer + unconsumedBytes,
// IsNPUT_BUFFER_SIZE - unconsumedBytes);
//size_t Read(void* buffer, size_t count)
int read = fread(data->inputBuffer + unconsumedBytes,
1,
INPUT_BUFFER_SIZE - unconsumedBytes,
data->file);
mad_stream_buffer(stream, data->inputBuffer, read + unconsumedBytes);
return MAD_FLOW_CONTINUE;
}
/* The output callback is called every time the decoder has finished decoding
* a frame, allowing us to use the decoded data */
enum mad_flow output_cb(void *_data,
struct mad_header const *header,
struct mad_pcm *pcm)
{
int channels,
samplerate,
samples;
struct private_data *data = (struct private_data *)_data;
int chn,
smpl,
cont;
float *bufferL,
*bufferR;
samplerate= pcm->samplerate;
channels = pcm->channels;
samples = pcm->length;
if (data->firstRun){
data->numChannels = channels;
data->samplerate = samplerate;
data->firstRun = false;
}
if(data->ocount == 0)
data->sample = (float *) malloc(channels*samples*sizeof(float) );
else
data->sample = (float *) realloc (data->sample , (data->len + samples)*sizeof(float)*channels );
data->ocount += 1;
if (!data->sample){
printf("NAo alocou memo\n");
exit(1);
}
float *buffer = new float[channels*samples];
if (channels == 1){
for(smpl = 0; smpl < samples; smpl++)
buffer[smpl] = scale(pcm->samples[0][smpl]);
}
if (channels == 2){
bufferL = new float[samples];
bufferR = new float[samples];
for(smpl = 0; smpl < samples; smpl++){
bufferL[smpl] = scale(pcm->samples[0][smpl]);
bufferR[smpl] = scale(pcm->samples[1][smpl]);
}
//Interleaving
cont = 0;
while (cont < samples){
buffer[cont] = bufferL[cont];
cont++;
buffer[cont] = bufferR[cont];
cont++;
}
}
memcpy(data->sample + data->len ,buffer ,channels*samples);
data->len +=channels*samples;
if (channels == 2){
delete [] bufferL;
delete [] bufferR;
}
delete [] buffer;
//Codigo para somente 1 canal
/*if(data->ocount == 0)
data->sample = (float *) malloc(samples*sizeof(float) );
else
data->sample = (float *) realloc (data->sample , (data->len + samples)*sizeof(float) );
data->ocount += 1;
if (!data->sample){
printf("NAo alocou memo\n");
exit(1);
}
float *buffer = new float[samples];
for(smpl = 0; smpl < samples; smpl++)
buffer[smpl] = scale(pcm->samples[0][smpl]);
memcpy(data->sample + data->len ,buffer ,samples);
data->len +=samples;*/
/* If this is the first run, we need to create the WaveTracks that
* will hold the data. We do this now because now is the first
* moment when we know how many channels there are. */
/*
if(!data->channels) {
data->channels = new WaveTrack* [channels];
for(chn = 0; chn < channels; chn++) {
data->channels[chn] = data->trackFactory->NewWaveTrack(floatSample);
data->channels[chn]->SetRate(samplerate);
data->channels[chn]->SetChannel(Track::MonoChannel);
}
/* special case: 2 channels is understood to be stereo
if(channels == 2) {
data->channels[0]->SetChannel(Track::LeftChannel);
data->channels[1]->SetChannel(Track::RightChannel);
data->channels[0]->SetLinked(true);
}
data->numChannels = channels;
}
else {
// This is not the first run, protect us from libmad glitching
// on the number of channels
channels = data->numChannels;
}
*/
/* TODO: get rid of this by adding fixed-point support to SampleFormat.
* For now, we allocate temporary float buffers to convert the fixed
* point samples into something we can feed to the WaveTrack. Allocating
* big blocks of data like this isn't a great idea, but it's temporary.*/
/*
float **channelBuffers = new float* [channels];
for(chn = 0; chn < channels; chn++)
channelBuffers[chn] = new float [samples];
for(smpl = 0; smpl < samples; smpl++)
for(chn = 0; chn < channels; chn++)
channelBuffers[chn][smpl] = scale(pcm->samples[chn][smpl]);
for(chn = 0; chn < channels; chn++)
data->channels[chn]->Append((samplePtr)channelBuffers[chn],
floatSample,
samples);
for(chn = 0; chn < channels; chn++)
delete[] channelBuffers[chn];
delete[] channelBuffers;
*/
return MAD_FLOW_CONTINUE;
}
enum mad_flow error_cb(void *_data, struct mad_stream *stream,
struct mad_frame *frame)
{
/* enum mad_flow {
MAD_FLOW_CONTINUE = 0x0000,
MAD_FLOW_STOP = 0x0010,
MAD_FLOW_BREAK = 0x0011,
MAD_FLOW_IGNORE = 0x0020
}; */
/*
printf("decoding error 0x%04x (%s)\n",
stream->error, mad_stream_errorstr(stream));
*/
return MAD_FLOW_CONTINUE;
/* return MAD_FLOW_BREAK; */
}
No virus found in this outgoing message.
Checked by AVG Anti-Virus.
Version: 7.0.323 / Virus Database: 267.6.2 - Release Date: 4/6/2005