Joe Drew wrote some good info on the MAD high-level API that I hope will be helpful to others.
By way of clarification, MAD also has a low-level API which does not use callbacks. You can control the entire decoding process yourself more or less as follows:
/* load buffer with your MPEG audio data */
mad_stream_buffer(&stream, buffer, buflen);
while (1) { mad_frame_decode(&frame, &stream); mad_synth_frame(&synth, &frame);
/* output PCM samples in synth.pcm */ }
This is vastly simplified, but it shows the general idea. mad_frame_decode() decodes the next frame's header and subband samples. mad_synth_frame() takes those subband samples and synthesizes PCM samples.
It is also possible to call mad_header_decode() before mad_frame_decode(). This just gives you the frame's header info, in case that's all you want, or perhaps to help you decide whether you want to decode the rest of the frame.
As Joe mentions, each of the stream, frame, and synth structs needs to be initialized and "finished" before and after use:
struct mad_stream stream; struct mad_frame frame; struct mad_synth synth;
mad_stream_init(&stream); mad_frame_init(&frame); mad_synth_init(&synth);
/* ... */
mad_synth_finish(&synth); mad_frame_finish(&frame); mad_stream_finish(&stream);
You can work with just a struct mad_header instead of a struct mad_frame if you only want to decode frame headers.
Joe writes:
MAD always outputs 32-bit (well, mad_fixed_t) little-endian data. Take this into account when outputting samples to the sound card.
This isn't quite right: the mad_fixed_t type is not necessarily little-endian. It's the same endianness as the native integer types. Also, it's only guaranteed to be *at least* 32 bits wide.
The fixed-point sample format is important to understand, and I recommend reading the comments in libmad/fixed.h. The thing to remember when converting MAD's fixed-point integer samples to 16-bit PCM (or whatever) is that MAD encodes samples as numbers in the full-scale range [-1.0, +1.0) where the binary point is placed 28 (MAD_F_FRACBITS) bits to the left of the integer. However, you need to be prepared to handle clipping as some numbers may be less than -1.0 (-MAD_F_ONE) or greater than or equal to +1.0 (MAD_F_ONE, aka 1 << MAD_F_FRACBITS).
Information on the other (error, filter, message) functions would be appreciated, though I think in knowing this information anyone should be able to puzzle it out.
In the high-level API, the error callback function is called whenever a decoding error occurs. The error number is in stream->error.
The filter callback function is called after decoding a frame, but before synthesis. Here it is possible to modify the frame's subband samples, for example to perform a uniform attenuation/amplification, or to do other special processing in the frequency domain.
The message callback function is only used with MAD_DECODER_MODE_ASYNC, and is called whenever the parent process sends a message via mad_decoder_message(). This callback can generate a reply by overwriting the message buffer that is passed to it. (The size of the reply must be the same or smaller than the message.)
Cheers, -rob