Hi!
I want to use MAD for audio playback, and looked at the minimad.c example. My problem is that I can't map the whole input to memory at once (as is done there) but I have to use fixed size blocks (size of my input buffer), which I feed to MAD and refill in my input callback.
I've adapted the minimad.c code (my version is included below) to use fixed size blocks of input; if that buffer size is greater then my file size it works quite fine; but when it is smaller, I get loads of errors (mostly lost synchronization) after a few blocks are read.
As there's not much documentation about that, I hope you can help me: When I use stream_buffer(...), how long is that buffer data needed to be available? Can I clear (or reuse) that buffer the next time my input callback is called?
Thank you very much for your help! Yours, Daniel
/* ************************************************************* */
# include <stdio.h> # include <unistd.h> # include <sys/stat.h> # include <sys/mman.h> #include <assert.h> #include <malloc.h>
# include "mad.h"
#define BUFFER_SIZE (1<<10)
typedef struct { unsigned char* start; unsigned long length; FILE* in; } mydata;
static int decode(mydata*);
int main(int argc, char *argv[]) { mydata buffer;
buffer.in=fopen(argv[1], "rb"); assert(buffer.in);
buffer.start=malloc(BUFFER_SIZE); buffer.length=0;
decode(&buffer);
free(buffer.start); fclose(buffer.in);
return 0; }
static enum mad_flow input(void *data, struct mad_stream *stream) { mydata *buffer = data;
if(!buffer->length) { buffer->length=fread(buffer->start, sizeof(*buffer->start), BUFFER_SIZE, buffer->in); if(!buffer->length) return MAD_FLOW_STOP; }
mad_stream_buffer(stream, buffer->start, buffer->length); buffer->length=0;
return MAD_FLOW_CONTINUE; }
static inline signed int scale(mad_fixed_t sample) { /* round */ sample += (1L << (MAD_F_FRACBITS - 16));
/* clip */ if (sample >= MAD_F_ONE) sample = MAD_F_ONE - 1; else if (sample < -MAD_F_ONE) sample = -MAD_F_ONE;
/* quantize */ return sample >> (MAD_F_FRACBITS + 1 - 16); }
static enum mad_flow output(void *data, struct mad_header const *header, struct mad_pcm *pcm) { unsigned int nchannels, nsamples; mad_fixed_t const *left_ch, *right_ch;
/* pcm->samplerate contains the sampling frequency */
nchannels = pcm->channels; nsamples = pcm->length; left_ch = pcm->samples[0]; right_ch = pcm->samples[1];
while (nsamples--) { signed int sample;
/* output sample(s) in 16-bit signed little-endian PCM */
sample = scale(*left_ch++); putchar((sample >> 0) & 0xff); putchar((sample >> 8) & 0xff);
if (nchannels == 2) { sample = scale(*right_ch++); putchar((sample >> 0) & 0xff); putchar((sample >> 8) & 0xff); } }
return MAD_FLOW_CONTINUE; }
static enum mad_flow error(void *data, struct mad_stream *stream, struct mad_frame *frame) { mydata *buffer = data;
fprintf(stderr, "decoding error 0x%04x (%s) at byte offset %u\n", stream->error, mad_stream_errorstr(stream), stream->this_frame - buffer->start);
/* return MAD_FLOW_BREAK here to stop decoding (and propagate an error) */
return MAD_FLOW_CONTINUE; }
static int decode(mydata* buffer) { struct mad_decoder decoder; int result;
/* configure input, output, and error functions */
mad_decoder_init(&decoder, buffer, input, 0 /* header */, 0 /* filter */, output, error, 0 /* message */);
/* start decoding */
result = mad_decoder_run(&decoder, MAD_DECODER_MODE_SYNC);
/* release the decoder */
mad_decoder_finish(&decoder);
return result; }