annotate src/libmad-0.15.1b/minimad.c @ 83:ae30d91d2ffe

Replace these with versions built using an older toolset (so as to avoid ABI compatibilities when linking on Ubuntu 14.04 for packaging purposes)
author Chris Cannam
date Fri, 07 Feb 2020 11:51:13 +0000
parents c7265573341e
children
rev   line source
Chris@0 1 /*
Chris@0 2 * libmad - MPEG audio decoder library
Chris@0 3 * Copyright (C) 2000-2004 Underbit Technologies, Inc.
Chris@0 4 *
Chris@0 5 * This program is free software; you can redistribute it and/or modify
Chris@0 6 * it under the terms of the GNU General Public License as published by
Chris@0 7 * the Free Software Foundation; either version 2 of the License, or
Chris@0 8 * (at your option) any later version.
Chris@0 9 *
Chris@0 10 * This program is distributed in the hope that it will be useful,
Chris@0 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
Chris@0 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
Chris@0 13 * GNU General Public License for more details.
Chris@0 14 *
Chris@0 15 * You should have received a copy of the GNU General Public License
Chris@0 16 * along with this program; if not, write to the Free Software
Chris@0 17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Chris@0 18 *
Chris@0 19 * $Id: minimad.c,v 1.4 2004/01/23 09:41:32 rob Exp $
Chris@0 20 */
Chris@0 21
Chris@0 22 # include <stdio.h>
Chris@0 23 # include <unistd.h>
Chris@0 24 # include <sys/stat.h>
Chris@0 25 # include <sys/mman.h>
Chris@0 26
Chris@0 27 # include "mad.h"
Chris@0 28
Chris@0 29 /*
Chris@0 30 * This is perhaps the simplest example use of the MAD high-level API.
Chris@0 31 * Standard input is mapped into memory via mmap(), then the high-level API
Chris@0 32 * is invoked with three callbacks: input, output, and error. The output
Chris@0 33 * callback converts MAD's high-resolution PCM samples to 16 bits, then
Chris@0 34 * writes them to standard output in little-endian, stereo-interleaved
Chris@0 35 * format.
Chris@0 36 */
Chris@0 37
Chris@0 38 static int decode(unsigned char const *, unsigned long);
Chris@0 39
Chris@0 40 int main(int argc, char *argv[])
Chris@0 41 {
Chris@0 42 struct stat stat;
Chris@0 43 void *fdm;
Chris@0 44
Chris@0 45 if (argc != 1)
Chris@0 46 return 1;
Chris@0 47
Chris@0 48 if (fstat(STDIN_FILENO, &stat) == -1 ||
Chris@0 49 stat.st_size == 0)
Chris@0 50 return 2;
Chris@0 51
Chris@0 52 fdm = mmap(0, stat.st_size, PROT_READ, MAP_SHARED, STDIN_FILENO, 0);
Chris@0 53 if (fdm == MAP_FAILED)
Chris@0 54 return 3;
Chris@0 55
Chris@0 56 decode(fdm, stat.st_size);
Chris@0 57
Chris@0 58 if (munmap(fdm, stat.st_size) == -1)
Chris@0 59 return 4;
Chris@0 60
Chris@0 61 return 0;
Chris@0 62 }
Chris@0 63
Chris@0 64 /*
Chris@0 65 * This is a private message structure. A generic pointer to this structure
Chris@0 66 * is passed to each of the callback functions. Put here any data you need
Chris@0 67 * to access from within the callbacks.
Chris@0 68 */
Chris@0 69
Chris@0 70 struct buffer {
Chris@0 71 unsigned char const *start;
Chris@0 72 unsigned long length;
Chris@0 73 };
Chris@0 74
Chris@0 75 /*
Chris@0 76 * This is the input callback. The purpose of this callback is to (re)fill
Chris@0 77 * the stream buffer which is to be decoded. In this example, an entire file
Chris@0 78 * has been mapped into memory, so we just call mad_stream_buffer() with the
Chris@0 79 * address and length of the mapping. When this callback is called a second
Chris@0 80 * time, we are finished decoding.
Chris@0 81 */
Chris@0 82
Chris@0 83 static
Chris@0 84 enum mad_flow input(void *data,
Chris@0 85 struct mad_stream *stream)
Chris@0 86 {
Chris@0 87 struct buffer *buffer = data;
Chris@0 88
Chris@0 89 if (!buffer->length)
Chris@0 90 return MAD_FLOW_STOP;
Chris@0 91
Chris@0 92 mad_stream_buffer(stream, buffer->start, buffer->length);
Chris@0 93
Chris@0 94 buffer->length = 0;
Chris@0 95
Chris@0 96 return MAD_FLOW_CONTINUE;
Chris@0 97 }
Chris@0 98
Chris@0 99 /*
Chris@0 100 * The following utility routine performs simple rounding, clipping, and
Chris@0 101 * scaling of MAD's high-resolution samples down to 16 bits. It does not
Chris@0 102 * perform any dithering or noise shaping, which would be recommended to
Chris@0 103 * obtain any exceptional audio quality. It is therefore not recommended to
Chris@0 104 * use this routine if high-quality output is desired.
Chris@0 105 */
Chris@0 106
Chris@0 107 static inline
Chris@0 108 signed int scale(mad_fixed_t sample)
Chris@0 109 {
Chris@0 110 /* round */
Chris@0 111 sample += (1L << (MAD_F_FRACBITS - 16));
Chris@0 112
Chris@0 113 /* clip */
Chris@0 114 if (sample >= MAD_F_ONE)
Chris@0 115 sample = MAD_F_ONE - 1;
Chris@0 116 else if (sample < -MAD_F_ONE)
Chris@0 117 sample = -MAD_F_ONE;
Chris@0 118
Chris@0 119 /* quantize */
Chris@0 120 return sample >> (MAD_F_FRACBITS + 1 - 16);
Chris@0 121 }
Chris@0 122
Chris@0 123 /*
Chris@0 124 * This is the output callback function. It is called after each frame of
Chris@0 125 * MPEG audio data has been completely decoded. The purpose of this callback
Chris@0 126 * is to output (or play) the decoded PCM audio.
Chris@0 127 */
Chris@0 128
Chris@0 129 static
Chris@0 130 enum mad_flow output(void *data,
Chris@0 131 struct mad_header const *header,
Chris@0 132 struct mad_pcm *pcm)
Chris@0 133 {
Chris@0 134 unsigned int nchannels, nsamples;
Chris@0 135 mad_fixed_t const *left_ch, *right_ch;
Chris@0 136
Chris@0 137 /* pcm->samplerate contains the sampling frequency */
Chris@0 138
Chris@0 139 nchannels = pcm->channels;
Chris@0 140 nsamples = pcm->length;
Chris@0 141 left_ch = pcm->samples[0];
Chris@0 142 right_ch = pcm->samples[1];
Chris@0 143
Chris@0 144 while (nsamples--) {
Chris@0 145 signed int sample;
Chris@0 146
Chris@0 147 /* output sample(s) in 16-bit signed little-endian PCM */
Chris@0 148
Chris@0 149 sample = scale(*left_ch++);
Chris@0 150 putchar((sample >> 0) & 0xff);
Chris@0 151 putchar((sample >> 8) & 0xff);
Chris@0 152
Chris@0 153 if (nchannels == 2) {
Chris@0 154 sample = scale(*right_ch++);
Chris@0 155 putchar((sample >> 0) & 0xff);
Chris@0 156 putchar((sample >> 8) & 0xff);
Chris@0 157 }
Chris@0 158 }
Chris@0 159
Chris@0 160 return MAD_FLOW_CONTINUE;
Chris@0 161 }
Chris@0 162
Chris@0 163 /*
Chris@0 164 * This is the error callback function. It is called whenever a decoding
Chris@0 165 * error occurs. The error is indicated by stream->error; the list of
Chris@0 166 * possible MAD_ERROR_* errors can be found in the mad.h (or stream.h)
Chris@0 167 * header file.
Chris@0 168 */
Chris@0 169
Chris@0 170 static
Chris@0 171 enum mad_flow error(void *data,
Chris@0 172 struct mad_stream *stream,
Chris@0 173 struct mad_frame *frame)
Chris@0 174 {
Chris@0 175 struct buffer *buffer = data;
Chris@0 176
Chris@0 177 fprintf(stderr, "decoding error 0x%04x (%s) at byte offset %u\n",
Chris@0 178 stream->error, mad_stream_errorstr(stream),
Chris@0 179 stream->this_frame - buffer->start);
Chris@0 180
Chris@0 181 /* return MAD_FLOW_BREAK here to stop decoding (and propagate an error) */
Chris@0 182
Chris@0 183 return MAD_FLOW_CONTINUE;
Chris@0 184 }
Chris@0 185
Chris@0 186 /*
Chris@0 187 * This is the function called by main() above to perform all the decoding.
Chris@0 188 * It instantiates a decoder object and configures it with the input,
Chris@0 189 * output, and error callback functions above. A single call to
Chris@0 190 * mad_decoder_run() continues until a callback function returns
Chris@0 191 * MAD_FLOW_STOP (to stop decoding) or MAD_FLOW_BREAK (to stop decoding and
Chris@0 192 * signal an error).
Chris@0 193 */
Chris@0 194
Chris@0 195 static
Chris@0 196 int decode(unsigned char const *start, unsigned long length)
Chris@0 197 {
Chris@0 198 struct buffer buffer;
Chris@0 199 struct mad_decoder decoder;
Chris@0 200 int result;
Chris@0 201
Chris@0 202 /* initialize our private message structure */
Chris@0 203
Chris@0 204 buffer.start = start;
Chris@0 205 buffer.length = length;
Chris@0 206
Chris@0 207 /* configure input, output, and error functions */
Chris@0 208
Chris@0 209 mad_decoder_init(&decoder, &buffer,
Chris@0 210 input, 0 /* header */, 0 /* filter */, output,
Chris@0 211 error, 0 /* message */);
Chris@0 212
Chris@0 213 /* start decoding */
Chris@0 214
Chris@0 215 result = mad_decoder_run(&decoder, MAD_DECODER_MODE_SYNC);
Chris@0 216
Chris@0 217 /* release the decoder */
Chris@0 218
Chris@0 219 mad_decoder_finish(&decoder);
Chris@0 220
Chris@0 221 return result;
Chris@0 222 }