Chris@0: /* Chris@0: * libmad - MPEG audio decoder library Chris@0: * Copyright (C) 2000-2004 Underbit Technologies, Inc. Chris@0: * Chris@0: * This program is free software; you can redistribute it and/or modify Chris@0: * it under the terms of the GNU General Public License as published by Chris@0: * the Free Software Foundation; either version 2 of the License, or Chris@0: * (at your option) any later version. Chris@0: * Chris@0: * This program is distributed in the hope that it will be useful, Chris@0: * but WITHOUT ANY WARRANTY; without even the implied warranty of Chris@0: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the Chris@0: * GNU General Public License for more details. Chris@0: * Chris@0: * You should have received a copy of the GNU General Public License Chris@0: * along with this program; if not, write to the Free Software Chris@0: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Chris@0: * Chris@0: * $Id: minimad.c,v 1.4 2004/01/23 09:41:32 rob Exp $ Chris@0: */ Chris@0: Chris@0: # include Chris@0: # include Chris@0: # include Chris@0: # include Chris@0: Chris@0: # include "mad.h" Chris@0: Chris@0: /* Chris@0: * This is perhaps the simplest example use of the MAD high-level API. Chris@0: * Standard input is mapped into memory via mmap(), then the high-level API Chris@0: * is invoked with three callbacks: input, output, and error. The output Chris@0: * callback converts MAD's high-resolution PCM samples to 16 bits, then Chris@0: * writes them to standard output in little-endian, stereo-interleaved Chris@0: * format. Chris@0: */ Chris@0: Chris@0: static int decode(unsigned char const *, unsigned long); Chris@0: Chris@0: int main(int argc, char *argv[]) Chris@0: { Chris@0: struct stat stat; Chris@0: void *fdm; Chris@0: Chris@0: if (argc != 1) Chris@0: return 1; Chris@0: Chris@0: if (fstat(STDIN_FILENO, &stat) == -1 || Chris@0: stat.st_size == 0) Chris@0: return 2; Chris@0: Chris@0: fdm = mmap(0, stat.st_size, PROT_READ, MAP_SHARED, STDIN_FILENO, 0); Chris@0: if (fdm == MAP_FAILED) Chris@0: return 3; Chris@0: Chris@0: decode(fdm, stat.st_size); Chris@0: Chris@0: if (munmap(fdm, stat.st_size) == -1) Chris@0: return 4; Chris@0: Chris@0: return 0; Chris@0: } Chris@0: Chris@0: /* Chris@0: * This is a private message structure. A generic pointer to this structure Chris@0: * is passed to each of the callback functions. Put here any data you need Chris@0: * to access from within the callbacks. Chris@0: */ Chris@0: Chris@0: struct buffer { Chris@0: unsigned char const *start; Chris@0: unsigned long length; Chris@0: }; Chris@0: Chris@0: /* Chris@0: * This is the input callback. The purpose of this callback is to (re)fill Chris@0: * the stream buffer which is to be decoded. In this example, an entire file Chris@0: * has been mapped into memory, so we just call mad_stream_buffer() with the Chris@0: * address and length of the mapping. When this callback is called a second Chris@0: * time, we are finished decoding. Chris@0: */ Chris@0: Chris@0: static Chris@0: enum mad_flow input(void *data, Chris@0: struct mad_stream *stream) Chris@0: { Chris@0: struct buffer *buffer = data; Chris@0: Chris@0: if (!buffer->length) Chris@0: return MAD_FLOW_STOP; Chris@0: Chris@0: mad_stream_buffer(stream, buffer->start, buffer->length); Chris@0: Chris@0: buffer->length = 0; Chris@0: Chris@0: return MAD_FLOW_CONTINUE; Chris@0: } Chris@0: Chris@0: /* Chris@0: * The following utility routine performs simple rounding, clipping, and Chris@0: * scaling of MAD's high-resolution samples down to 16 bits. It does not Chris@0: * perform any dithering or noise shaping, which would be recommended to Chris@0: * obtain any exceptional audio quality. It is therefore not recommended to Chris@0: * use this routine if high-quality output is desired. Chris@0: */ Chris@0: Chris@0: static inline Chris@0: signed int scale(mad_fixed_t sample) Chris@0: { Chris@0: /* round */ Chris@0: sample += (1L << (MAD_F_FRACBITS - 16)); Chris@0: Chris@0: /* clip */ Chris@0: if (sample >= MAD_F_ONE) Chris@0: sample = MAD_F_ONE - 1; Chris@0: else if (sample < -MAD_F_ONE) Chris@0: sample = -MAD_F_ONE; Chris@0: Chris@0: /* quantize */ Chris@0: return sample >> (MAD_F_FRACBITS + 1 - 16); Chris@0: } Chris@0: Chris@0: /* Chris@0: * This is the output callback function. It is called after each frame of Chris@0: * MPEG audio data has been completely decoded. The purpose of this callback Chris@0: * is to output (or play) the decoded PCM audio. Chris@0: */ Chris@0: Chris@0: static Chris@0: enum mad_flow output(void *data, Chris@0: struct mad_header const *header, Chris@0: struct mad_pcm *pcm) Chris@0: { Chris@0: unsigned int nchannels, nsamples; Chris@0: mad_fixed_t const *left_ch, *right_ch; Chris@0: Chris@0: /* pcm->samplerate contains the sampling frequency */ Chris@0: Chris@0: nchannels = pcm->channels; Chris@0: nsamples = pcm->length; Chris@0: left_ch = pcm->samples[0]; Chris@0: right_ch = pcm->samples[1]; Chris@0: Chris@0: while (nsamples--) { Chris@0: signed int sample; Chris@0: Chris@0: /* output sample(s) in 16-bit signed little-endian PCM */ Chris@0: Chris@0: sample = scale(*left_ch++); Chris@0: putchar((sample >> 0) & 0xff); Chris@0: putchar((sample >> 8) & 0xff); Chris@0: Chris@0: if (nchannels == 2) { Chris@0: sample = scale(*right_ch++); Chris@0: putchar((sample >> 0) & 0xff); Chris@0: putchar((sample >> 8) & 0xff); Chris@0: } Chris@0: } Chris@0: Chris@0: return MAD_FLOW_CONTINUE; Chris@0: } Chris@0: Chris@0: /* Chris@0: * This is the error callback function. It is called whenever a decoding Chris@0: * error occurs. The error is indicated by stream->error; the list of Chris@0: * possible MAD_ERROR_* errors can be found in the mad.h (or stream.h) Chris@0: * header file. Chris@0: */ Chris@0: Chris@0: static Chris@0: enum mad_flow error(void *data, Chris@0: struct mad_stream *stream, Chris@0: struct mad_frame *frame) Chris@0: { Chris@0: struct buffer *buffer = data; Chris@0: Chris@0: fprintf(stderr, "decoding error 0x%04x (%s) at byte offset %u\n", Chris@0: stream->error, mad_stream_errorstr(stream), Chris@0: stream->this_frame - buffer->start); Chris@0: Chris@0: /* return MAD_FLOW_BREAK here to stop decoding (and propagate an error) */ Chris@0: Chris@0: return MAD_FLOW_CONTINUE; Chris@0: } Chris@0: Chris@0: /* Chris@0: * This is the function called by main() above to perform all the decoding. Chris@0: * It instantiates a decoder object and configures it with the input, Chris@0: * output, and error callback functions above. A single call to Chris@0: * mad_decoder_run() continues until a callback function returns Chris@0: * MAD_FLOW_STOP (to stop decoding) or MAD_FLOW_BREAK (to stop decoding and Chris@0: * signal an error). Chris@0: */ Chris@0: Chris@0: static Chris@0: int decode(unsigned char const *start, unsigned long length) Chris@0: { Chris@0: struct buffer buffer; Chris@0: struct mad_decoder decoder; Chris@0: int result; Chris@0: Chris@0: /* initialize our private message structure */ Chris@0: Chris@0: buffer.start = start; Chris@0: buffer.length = length; Chris@0: Chris@0: /* configure input, output, and error functions */ Chris@0: Chris@0: mad_decoder_init(&decoder, &buffer, Chris@0: input, 0 /* header */, 0 /* filter */, output, Chris@0: error, 0 /* message */); Chris@0: Chris@0: /* start decoding */ Chris@0: Chris@0: result = mad_decoder_run(&decoder, MAD_DECODER_MODE_SYNC); Chris@0: Chris@0: /* release the decoder */ Chris@0: Chris@0: mad_decoder_finish(&decoder); Chris@0: Chris@0: return result; Chris@0: }