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