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;
}