chiark / gitweb /
exclude nonsense finkbindir
[disorder] / server / decode.c
1 /*
2  * This file is part of DisOrder
3  * Copyright (C) 2007 Richard Kettlewell
4  *
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 2 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful, but
11  * WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
18  * USA
19  */
20 /** @file server/decode.c
21  * @brief General-purpose decoder for use by speaker process
22  */
23
24 #include <config.h>
25 #include "types.h"
26
27 #include <getopt.h>
28 #include <unistd.h>
29 #include <fcntl.h>
30 #include <errno.h>
31 #include <stdlib.h>
32 #include <locale.h>
33 #include <assert.h>
34 #include <fnmatch.h>
35 #include <mad.h>
36 #include <vorbis/vorbisfile.h>
37
38 #include "log.h"
39 #include "syscalls.h"
40 #include "defs.h"
41 #include "speaker-protocol.h"
42
43 /** @brief Encoding lookup table type */
44 struct decoder {
45   /** @brief Glob pattern matching file */
46   const char *pattern;
47   /** @brief Decoder function */
48   void (*decode)(void);
49 };
50
51 /** @brief Input file */
52 static int inputfd;
53
54 /** @brief Output file */
55 static FILE *outputfp;
56
57 /** @brief Filename */
58 static const char *path;
59
60 /** @brief Input buffer */
61 static char buffer[1048576];
62
63 /** @brief Open the input file */
64 static void open_input(void) {
65   if((inputfd = open(path, O_RDONLY)) < 0)
66     fatal(errno, "opening %s", path);
67 }
68
69 /** @brief Fill the buffer
70  * @return Number of bytes read
71  */
72 static size_t fill(void) {
73   int n = read(inputfd, buffer, sizeof buffer);
74
75   if(n < 0)
76     fatal(errno, "reading from %s", path);
77   return n;
78 }
79
80 /** @brief Write a 16-bit word in bigendian format */
81 static inline void output_16(uint16_t n) {
82   if(putc(n >> 8, outputfp) < 0
83      || putc(n & 0xFF, outputfp) < 0)
84     fatal(errno, "decoding %s: output error", path);
85 }
86
87 /** @brief Write the header
88  * If called more than once, either does nothing (if you kept the same
89  * output encoding) or fails (if you changed it).
90  */
91 static void output_header(int rate,
92                           int channels,
93                           int bits,
94                           int nbytes) {
95   struct stream_header header;
96
97   header.rate = rate;
98   header.bits = bits;
99   header.channels = channels;
100   header.endian = ENDIAN_BIG;
101   header.nbytes = nbytes;
102   if(fwrite(&header, sizeof header, 1, outputfp) < 1)
103     fatal(errno, "decoding %s: writing format header", path);
104 }
105
106 /** @brief Dithering state
107  * Filched from mpg321, which credits it to Robert Leslie */
108 struct audio_dither {
109   mad_fixed_t error[3];
110   mad_fixed_t random;
111 };
112
113 /** @brief 32-bit PRNG
114  * Filched from mpg321, which credits it to Robert Leslie */
115 static inline unsigned long prng(unsigned long state)
116 {
117   return (state * 0x0019660dL + 0x3c6ef35fL) & 0xffffffffL;
118 }
119
120 /** @brief Generic linear sample quantize and dither routine
121  * Filched from mpg321, which credits it to Robert Leslie */
122 #define bits 16
123 static long audio_linear_dither(mad_fixed_t sample,
124                                 struct audio_dither *dither) {
125   unsigned int scalebits;
126   mad_fixed_t output, mask, rnd;
127
128   enum {
129     MIN = -MAD_F_ONE,
130     MAX =  MAD_F_ONE - 1
131   };
132
133   /* noise shape */
134   sample += dither->error[0] - dither->error[1] + dither->error[2];
135
136   dither->error[2] = dither->error[1];
137   dither->error[1] = dither->error[0] / 2;
138
139   /* bias */
140   output = sample + (1L << (MAD_F_FRACBITS + 1 - bits - 1));
141
142   scalebits = MAD_F_FRACBITS + 1 - bits;
143   mask = (1L << scalebits) - 1;
144
145   /* dither */
146   rnd  = prng(dither->random);
147   output += (rnd & mask) - (dither->random & mask);
148
149   dither->random = rnd;
150
151   /* clip */
152   if (output > MAX) {
153     output = MAX;
154
155     if (sample > MAX)
156       sample = MAX;
157   }
158   else if (output < MIN) {
159     output = MIN;
160
161     if (sample < MIN)
162       sample = MIN;
163   }
164
165   /* quantize */
166   output &= ~mask;
167
168   /* error feedback */
169   dither->error[0] = sample - output;
170
171   /* scale */
172   return output >> scalebits;
173 }
174 #undef bits
175
176 /** @brief MP3 output callback */
177 static enum mad_flow mp3_output(void attribute((unused)) *data,
178                                 struct mad_header const *header,
179                                 struct mad_pcm *pcm) {
180   size_t n = pcm->length;
181   const mad_fixed_t *l = pcm->samples[0], *r = pcm->samples[1];
182   static struct audio_dither ld[1], rd[1];
183
184   output_header(header->samplerate,
185                 pcm->channels,
186                 16,
187                 2 * pcm->channels * pcm->length);
188   switch(pcm->channels) {
189   case 1:
190     while(n--)
191       output_16(audio_linear_dither(*l++, ld));
192     break;
193   case 2:
194     while(n--) {
195       output_16(audio_linear_dither(*l++, ld));
196       output_16(audio_linear_dither(*r++, rd));
197     }
198     break;
199   default:
200     fatal(0, "decoding %s: unsupported channel count %d", path, pcm->channels);
201   }
202   return MAD_FLOW_CONTINUE;
203 }
204
205 /** @brief MP3 input callback */
206 static enum mad_flow mp3_input(void attribute((unused)) *data,
207                                struct mad_stream *stream) {
208   const size_t n = fill();
209
210   if(!n)
211     return MAD_FLOW_STOP;
212   mad_stream_buffer(stream, (unsigned char *)buffer, n);
213   return MAD_FLOW_CONTINUE;
214 }
215
216
217 /** @brief MP3 error callback */
218 static enum mad_flow mp3_error(void attribute((unused)) *data,
219                                struct mad_stream *stream,
220                                struct mad_frame attribute((unused)) *frame) {
221   if(0)
222     /* Just generates pointless verbosity l-( */
223     error(0, "decoding %s: %s (%#04x)",
224           path, mad_stream_errorstr(stream), stream->error);
225   return MAD_FLOW_CONTINUE;
226 }
227
228 /** @brief MP3 decoder */
229 static void decode_mp3(void) {
230   struct mad_decoder mad[1];
231
232   open_input();
233   mad_decoder_init(mad, 0/*data*/, mp3_input, 0/*header*/, 0/*filter*/,
234                    mp3_output, mp3_error, 0/*message*/);
235   if(mad_decoder_run(mad, MAD_DECODER_MODE_SYNC))
236     exit(1);
237   mad_decoder_finish(mad);
238 }
239
240 /** @brief OGG decoder */
241 static void decode_ogg(void) {
242   FILE *fp;
243   OggVorbis_File vf[1];
244   int err;
245   long n;
246   int bitstream;
247   vorbis_info *vi;
248
249   if(!(fp = fopen(path, "rb")))
250     fatal(errno, "cannot open %s", path);
251   /* There doesn't seem to be any standard function for mapping the error codes
252    * to strings l-( */
253   if((err = ov_open(fp, vf, 0/*initial*/, 0/*ibytes*/)))
254     fatal(0, "ov_fopen %s: %d", path, err);
255   if(!(vi = ov_info(vf, 0/*link*/)))
256     fatal(0, "ov_info %s: failed", path);
257   while((n = ov_read(vf, buffer, sizeof buffer, 1/*bigendianp*/,
258                      2/*bytes/word*/, 1/*signed*/, &bitstream))) {
259     if(n < 0)
260       fatal(0, "ov_read %s: %ld", path, n);
261     if(bitstream > 0)
262       fatal(0, "only single-bitstream ogg files are supported");
263     output_header(vi->rate, vi->channels, 16/*bits*/, n);
264     if(fwrite(buffer, 1, n, outputfp) < (size_t)n)
265       fatal(errno, "decoding %s: writing sample data", path);
266   }
267 }
268
269 /** @brief Lookup table of decoders */
270 static const struct decoder decoders[] = {
271   { "*.mp3", decode_mp3 },
272   { "*.MP3", decode_mp3 },
273   { "*.ogg", decode_ogg },
274   { "*.OGG", decode_ogg },
275   { 0, 0 }
276 };
277
278 static const struct option options[] = {
279   { "help", no_argument, 0, 'h' },
280   { "version", no_argument, 0, 'V' },
281   { 0, 0, 0, 0 }
282 };
283
284 /* Display usage message and terminate. */
285 static void help(void) {
286   xprintf("Usage:\n"
287           "  disorder-decode [OPTIONS] PATH\n"
288           "Options:\n"
289           "  --help, -h              Display usage message\n"
290           "  --version, -V           Display version number\n"
291           "\n"
292           "Audio decoder for DisOrder.  Only intended to be used by speaker\n"
293           "process, not for normal users.\n");
294   xfclose(stdout);
295   exit(0);
296 }
297
298 /* Display version number and terminate. */
299 static void version(void) {
300   xprintf("disorder-decode version %s\n", disorder_version_string);
301   xfclose(stdout);
302   exit(0);
303 }
304
305 int main(int argc, char **argv) {
306   int n;
307   const char *e;
308
309   set_progname(argv);
310   if(!setlocale(LC_CTYPE, "")) fatal(errno, "calling setlocale");
311   while((n = getopt_long(argc, argv, "hV", options, 0)) >= 0) {
312     switch(n) {
313     case 'h': help();
314     case 'V': version();
315     default: fatal(0, "invalid option");
316     }
317   }
318   if(optind >= argc)
319     fatal(0, "missing filename");
320   if(optind + 1 < argc)
321     fatal(0, "excess arguments");
322   if((e = getenv("DISORDER_RAW_FD"))) {
323     if(!(outputfp = fdopen(atoi(e), "wb")))
324       fatal(errno, "fdopen");
325   } else
326     outputfp = stdout;
327   path = argv[optind];
328   for(n = 0;
329       decoders[n].pattern
330         && fnmatch(decoders[n].pattern, path, 0) != 0;
331       ++n)
332     ;
333   if(!decoders[n].pattern)
334     fatal(0, "cannot determine file type for %s", path);
335   decoders[n].decode();
336   xfclose(outputfp);
337   return 0;
338 }
339
340 /*
341 Local Variables:
342 c-basic-offset:2
343 comment-column:40
344 fill-column:79
345 indent-tabs-mode:nil
346 End:
347 */