2 * This file is part of DisOrder
3 * Copyright (C) 2007-2010 Richard Kettlewell
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 /** @file server/decode-mp3.c
19 * @brief Decode MP3 files.
24 static struct hreader input[1];
26 /** @brief Dithering state
27 * Filched from mpg321, which credits it to Robert Leslie */
33 /** @brief 32-bit PRNG
34 * Filched from mpg321, which credits it to Robert Leslie */
35 static inline unsigned long prng(unsigned long state)
37 return (state * 0x0019660dL + 0x3c6ef35fL) & 0xffffffffL;
40 /** @brief Generic linear sample quantize and dither routine
41 * Filched from mpg321, which credits it to Robert Leslie */
42 static long audio_linear_dither(mad_fixed_t sample,
43 struct audio_dither *dither) {
44 unsigned int scalebits;
45 mad_fixed_t output, mask, rnd;
54 sample += dither->error[0] - dither->error[1] + dither->error[2];
56 dither->error[2] = dither->error[1];
57 dither->error[1] = dither->error[0] / 2;
60 output = sample + (1L << (MAD_F_FRACBITS + 1 - bits - 1));
62 scalebits = MAD_F_FRACBITS + 1 - bits;
63 mask = (1L << scalebits) - 1;
66 rnd = prng(dither->random);
67 output += (rnd & mask) - (dither->random & mask);
78 else if (output < MIN) {
89 dither->error[0] = sample - output;
92 return output >> scalebits;
95 /** @brief MP3 output callback */
96 static enum mad_flow mp3_output(void attribute((unused)) *data,
97 struct mad_header const *header,
98 struct mad_pcm *pcm) {
99 size_t n = pcm->length;
100 const mad_fixed_t *l = pcm->samples[0], *r = pcm->samples[1];
101 static struct audio_dither ld[1], rd[1];
103 output_header(header->samplerate,
106 2 * pcm->channels * pcm->length,
108 switch(pcm->channels) {
111 output_16(audio_linear_dither(*l++, ld));
115 output_16(audio_linear_dither(*l++, ld));
116 output_16(audio_linear_dither(*r++, rd));
120 return MAD_FLOW_CONTINUE;
123 /** @brief MP3 input callback */
124 static enum mad_flow mp3_input(void attribute((unused)) *data,
125 struct mad_stream *stream) {
128 /* libmad requires its caller to do ALL the buffering work, including coping
129 * with partial frames. Given that it appears to be completely undocumented
130 * you could perhaps be forgiven for not discovering this... */
132 /* Compute total number of bytes consumed */
133 used = (char *)stream->next_frame - input_buffer;
134 /* Compute number of bytes left to consume */
135 remain = input_count - used;
136 memmove(input_buffer, input_buffer + used, remain);
141 n = hreader_read(input,
142 input_buffer + remain,
143 (sizeof input_buffer) - remain);
145 disorder_fatal(errno, "reading from %s", path);
146 /* Compute total number of bytes available */
147 input_count = remain + n;
149 mad_stream_buffer(stream, (unsigned char *)input_buffer, input_count);
151 return MAD_FLOW_CONTINUE;
153 return MAD_FLOW_STOP;
156 /** @brief MP3 error callback */
157 static enum mad_flow mp3_error(void attribute((unused)) *data,
158 struct mad_stream *stream,
159 struct mad_frame attribute((unused)) *frame) {
161 /* Just generates pointless verbosity l-( */
162 disorder_error(0, "decoding %s: %s (%#04x)",
163 path, mad_stream_errorstr(stream), stream->error);
164 return MAD_FLOW_CONTINUE;
167 /** @brief MP3 decoder */
168 void decode_mp3(void) {
169 struct mad_decoder mad[1];
171 if(hreader_init(path, input))
172 disorder_fatal(errno, "opening %s", path);
173 mad_decoder_init(mad, 0/*data*/, mp3_input, 0/*header*/, 0/*filter*/,
174 mp3_output, mp3_error, 0/*message*/);
175 if(mad_decoder_run(mad, MAD_DECODER_MODE_SYNC))
177 mad_decoder_finish(mad);