ac6c32aa46a1f18407c64a2d8949833f4fa7f8e4
[sxemacs] / src / media / media-internal.c
1 /* media-internal.c - general routines related to playing sounds
2  **
3  ** Copyright (C) 1995,96 by Markus Gutschke (gutschk@math.uni-muenster.de)
4  ** This was sawed out from version 1.3 of linuxplay.c by
5  ** Robert Bihlmeyer <robbe@orcus.priv.at>.
6  **
7  ** Copyright (C) 2006
8  **
9  ** Parts of this code were inspired by sunplay.c, which is copyright 1989 by
10  ** Jef Poskanzer and 1991,92 by Jamie Zawinski; c.f. sunplay.c for further
11  ** information.
12  **
13  ** Permission to use, copy, modify, and distribute this software and its
14  ** documentation for any purpose and without fee is hereby granted, provided
15  ** that the above copyright notice appear in all copies and that both that
16  ** copyright notice and this permission notice appear in supporting
17  ** documentation.  This software is provided "as is" without express or
18  ** implied warranty.
19  */
20
21 #ifdef HAVE_CONFIG_H
22 #include <config.h>
23 #endif
24
25 #include "lisp.h"
26 #include "syssignal.h"
27 #include "sysfile.h"
28 #define warn(str)   message("audio: %s ",GETTEXT(str))
29
30 #include <stdlib.h>
31
32 #include "media-internal.h"
33
34 #define MYSELF MDRIVER_INTERNAL
35
36 /* Maintain global variable for keeping parser state information; this struct
37    is set to zero before the first invocation of the parser. The use of a
38    global variable prevents multiple concurrent executions of this code, but
39    this does not happen anyways... */
40 enum wvState { wvMain,
41         wvSubchunk,
42         wvOutOfBlock,
43         wvSkipChunk,
44         wvSoundChunk,
45         wvFatal,
46         wvFatalNotify
47 };
48
49 static union {
50         struct {
51                 int align;
52                 enum wvState state;
53                 size_t left;
54                 unsigned char leftover[HEADERSZ];
55                 signed long chunklength;
56         } wave;
57         struct {
58                 int align;
59                 int isdata;
60                 int skipping;
61                 size_t left;
62                 unsigned char leftover[HEADERSZ];
63         } audio;
64 } parsestate;
65
66 /* Use a global buffer as scratch-pad for possible conversions of the
67    sampling format */
68 unsigned char miscplay_sndbuf[SNDBUFSZ];
69
70 /* Initialize global parser state information to zero */
71 void reset_parsestate()
72 {
73         memset(&parsestate, 0, sizeof(parsestate));
74 }
75
76 /* Verify that we could fully parse the entire soundfile; this is needed
77    only for files in WAVE format */
78 int parse_wave_complete()
79 {
80         if (parsestate.wave.state != wvOutOfBlock &&
81             parsestate.wave.state != wvFatal) {
82                 warn("Unexpected end of WAVE file");
83                 return 0;
84         } else
85                 return 1;
86 }
87
88 /* There is no special treatment required for parsing raw data files; we
89    assume that these files contain data in 8bit unsigned format that
90    has been sampled at 8kHz; there is no extra header */
91 static size_t parseraw(void **data, size_t * sz, void **outbuf)
92 {
93         int rc = *sz;
94
95         *outbuf = *data;
96         *sz = 0;
97         return (rc);
98 }
99
100 /* Currently we cannot cope with files in VOC format; if you really need
101    to play these files, they should be converted by using SOX */
102 static size_t parsevoc(void **SXE_UNUSED(data), size_t *SXE_UNUSED(sz),
103                        void **SXE_UNUSED(outbuf))
104 {
105         return (0);
106 }
107
108 /* We need to perform some look-ahead in order to parse files in WAVE format;
109    this might require re-partioning of the data segments if headers cross the
110    boundaries between two read operations. This is done in a two-step way:
111    first we request a certain amount of bytes... */
112 static inline int waverequire(void **data, size_t * sz, size_t rq)
113 {
114         int rc = 1;
115
116         if (rq > HEADERSZ) {
117                 warn("Header size exceeded while parsing WAVE file");
118                 parsestate.wave.state = wvFatal;
119                 *sz = 0;
120                 return (0);
121         }
122         if ((rq -= parsestate.wave.left) <= 0)
123                 return (rc);
124         if (rq > *sz) {
125                 rq = *sz;
126                 rc = 0;
127         }
128         memcpy(parsestate.wave.leftover + parsestate.wave.left, *data, rq);
129         parsestate.wave.left += rq;
130         (*(unsigned char **)data) += rq;
131         *sz -= rq;
132         return (rc);
133 }
134
135 /* ...and next we remove this many bytes from the buffer */
136 static inline void waveremove(size_t rq)
137 {
138         if (parsestate.wave.left <= rq)
139                 parsestate.wave.left = 0;
140         else {
141                 parsestate.wave.left -= rq;
142                 memmove(parsestate.wave.leftover,
143                         parsestate.wave.leftover + rq, parsestate.wave.left);
144         }
145         return;
146 }
147
148 /* Sound files in WAVE format can contain an arbitrary amount of tagged
149    chunks; this requires quite some effort for parsing the data */
150 static size_t parsewave(void **data, size_t * sz, void **outbuf)
151 {
152         for (;;)
153                 switch (parsestate.wave.state) {
154                 case wvMain:
155                         if (!waverequire(data, sz, 20))
156                                 return (0);
157                         /* Keep compatibility with Linux 68k, etc. by not relying on byte-sex  */
158                         parsestate.wave.chunklength =
159                             parsestate.wave.leftover[16] +
160                             256 * (parsestate.wave.leftover[17] +
161                                    256 * (parsestate.wave.leftover[18] +
162                                           256 * parsestate.wave.leftover[19]));
163                         waveremove(20);
164                         parsestate.wave.state = wvSubchunk;
165                         break;
166                 case wvSubchunk:
167                         if (!waverequire(data, sz, parsestate.wave.chunklength))
168                                 return (0);
169                         parsestate.wave.align =
170                             parsestate.wave.chunklength <
171                             14 ? 1 : parsestate.wave.leftover[12];
172                         if (parsestate.wave.align != 1
173                             && parsestate.wave.align != 2
174                             && parsestate.wave.align != 4) {
175                                 warn("Illegal datawidth detected while parsing WAVE file");
176                                 parsestate.wave.state = wvFatal;
177                         } else
178                                 parsestate.wave.state = wvOutOfBlock;
179                         waveremove(parsestate.wave.chunklength);
180                         break;
181                 case wvOutOfBlock:
182                         if (!waverequire(data, sz, 8))
183                                 return (0);
184                         /* Keep compatibility with Linux 68k, etc. by not relying on byte-sex  */
185                         parsestate.wave.chunklength =
186                             parsestate.wave.leftover[4] +
187                             256 * (parsestate.wave.leftover[5] +
188                                    256 * (parsestate.wave.leftover[6] +
189                                           256 *
190                                           (parsestate.wave.
191                                            leftover[7] & 0x7F)));
192                         if (memcmp(parsestate.wave.leftover, "data", 4))
193                                 parsestate.wave.state = wvSkipChunk;
194                         else
195                                 parsestate.wave.state = wvSoundChunk;
196                         waveremove(8);
197                         break;
198                 case wvSkipChunk:
199                         if (parsestate.wave.chunklength > 0 && *sz > 0 &&
200                             (signed long)*sz <
201                             (signed long)parsestate.wave.chunklength) {
202                                 parsestate.wave.chunklength -= *sz;
203                                 *sz = 0;
204                         } else {
205                                 if (parsestate.wave.chunklength > 0 && *sz > 0) {
206                                         *sz -= parsestate.wave.chunklength;
207                                         (*(unsigned char **)data) +=
208                                             parsestate.wave.chunklength;
209                                 }
210                                 parsestate.wave.state = wvOutOfBlock;
211                         }
212                         break;
213                 case wvSoundChunk:{
214                                 size_t count, rq;
215                                 if (parsestate.wave.left) {     /* handle leftover bytes from last
216                                                                    alignment operation */
217                                         count = parsestate.wave.left;
218                                         rq = HEADERSZ - count;
219                                         if (rq >
220                                             (size_t) parsestate.wave.
221                                             chunklength)
222                                                 rq = parsestate.wave.
223                                                     chunklength;
224                                         if (!waverequire(data, sz, rq)) {
225                                                 parsestate.wave.chunklength -=
226                                                     parsestate.wave.left -
227                                                     count;
228                                                 return (0);
229                                         }
230                                         parsestate.wave.chunklength -= rq;
231                                         *outbuf = parsestate.wave.leftover;
232                                         parsestate.wave.left = 0;
233                                         return (rq);
234                                 }
235                                 if (*sz >= (size_t) parsestate.wave.chunklength) {
236                                         count = parsestate.wave.chunklength;
237                                         rq = 0;
238                                 } else {
239                                         count = *sz;
240                                         count -= rq =
241                                             count % parsestate.wave.align;
242                                 }
243                                 *outbuf = *data;
244                                 (*(unsigned char **)data) += count;
245                                 *sz -= count;
246                                 if ((parsestate.wave.chunklength -=
247                                      count) < parsestate.wave.align) {
248                                         parsestate.wave.state = wvOutOfBlock;
249                                         /* Some broken software (e.g. SOX) attaches junk to the end of a sound
250                                            chunk; so, let's ignore this... */
251                                         if (parsestate.wave.chunklength)
252                                                 parsestate.wave.state =
253                                                     wvSkipChunk;
254                                 } else if (rq)
255                                         /* align data length to a multiple of datasize; keep additional data
256                                            in "leftover" buffer --- this is necessary to ensure proper
257                                            functioning of the sndcnv... routines */
258                                         waverequire(data, sz, rq);
259                                 return (count);
260                         }
261                 case wvFatalNotify:
262                         warn("Irrecoverable error while parsing WAVE file");
263                         parsestate.wave.state = wvFatal;
264                         break;
265                 case wvFatal:
266                 default:
267                         *sz = 0;
268                         return (0);
269                 }
270 }
271
272 /* Strip the header from files in Sun/DEC audio format; this requires some
273    extra processing as the header can be an arbitrary size and it might
274    result in alignment errors for subsequent conversions --- thus we do
275    some buffering, where needed */
276 static size_t parsesundecaudio(void **data, size_t * sz, void **outbuf)
277 {
278         /* There is data left over from the last invocation of this function; join
279            it with the new data and return a sound chunk that is as big as a
280            single entry */
281         if (parsestate.audio.left) {
282                 if (parsestate.audio.left + *sz >
283                     (size_t) parsestate.audio.align) {
284                         int count;
285                         memmove(parsestate.audio.leftover +
286                                 parsestate.audio.left, *data, count =
287                                 parsestate.audio.align - parsestate.audio.left);
288                         *outbuf = parsestate.audio.leftover;
289                         *sz -= count;
290                         *data = (*(char **)data) + count;
291                         parsestate.audio.left = 0;
292                         return (parsestate.audio.align);
293                 } else {
294                         /* We need even more data in order to get one complete single entry! */
295                         memmove(parsestate.audio.leftover +
296                                 parsestate.audio.left, *data, *sz);
297                         *data = (*(char **)data) + *sz;
298                         parsestate.audio.left += *sz;
299                         *sz = 0;
300                         return (0);
301                 }
302         }
303
304         /* This is the main sound chunk, strip of any extra data that does not fit
305            the alignment requirements and move these bytes into the leftover buffer */
306         if (parsestate.audio.isdata) {
307                 int rc = *sz;
308                 *outbuf = *data;
309                 if ((parsestate.audio.left = rc % parsestate.audio.align) != 0) {
310                         memmove(parsestate.audio.leftover,
311                                 (char *)*outbuf + rc - parsestate.audio.left,
312                                 parsestate.audio.left);
313                         rc -= parsestate.audio.left;
314                 }
315                 *sz = 0;
316                 return (rc);
317         }
318
319         /* This is the first invocation of this function; we need to parse the
320            header information and determine how many bytes we need to skip until
321            the start of the sound chunk */
322         if (!parsestate.audio.skipping) {
323                 unsigned char *header = (unsigned char *)*data;
324                 if (*sz < 8) {
325                         warn("Irrecoverable error while parsing Sun/DEC audio file");
326                         return (0);
327                 }
328                 /* Keep compatibility with Linux 68k, etc. by not relying on
329                    byte-sex  */
330                 if (header[3]) {        /* Sun audio (big endian) */
331                         parsestate.audio.align =
332                             ((header[15] > 2) + 1) * header[23];
333                         parsestate.audio.skipping =
334                             header[7] + 256 * (header[6] +
335                                                256 * (header[5] +
336                                                       256 * header[4]));
337                 } else {        /* DEC audio (little endian) */
338                         parsestate.audio.align =
339                             ((header[12] > 2) + 1) * header[20];
340                         parsestate.audio.skipping =
341                             header[4] + 256 * (header[5] +
342                                                256 * (header[6] +
343                                                       256 * header[7]));
344                 }
345         }
346
347         /* We are skipping extra data that has been attached to header; most
348            usually this will be just a comment, such as the original filename
349            and/or the creation date. Make sure that we do not return less than
350            one single sound sample entry to the caller; if this happens, rather
351            decide to move those few bytes into the leftover buffer and deal with
352            it later */
353         if (*sz >= (size_t) parsestate.audio.skipping) {
354                 /* Skip just the header information and return the sound chunk */
355                 int rc = *sz - parsestate.audio.skipping;
356                 *outbuf = (char *)*data + parsestate.audio.skipping;
357                 if ((parsestate.audio.left = rc % parsestate.audio.align) != 0) {
358                         memmove(parsestate.audio.leftover,
359                                 (char *)*outbuf + rc - parsestate.audio.left,
360                                 parsestate.audio.left);
361                         rc -= parsestate.audio.left;
362                 }
363                 *sz = 0;
364                 parsestate.audio.skipping = 0;
365                 parsestate.audio.isdata++;
366                 return (rc);
367         } else {
368                 /* Skip everything */
369                 parsestate.audio.skipping -= *sz;
370                 return (0);
371         }
372 }
373
374 /* If the soundcard could not be set to internally support the data format, we
375    try to do some limited on-the-fly conversion to a different format; if
376    no conversion is needed, though, we can output directly */
377 size_t sndcnvnop(void **data, size_t * sz, void **outbuf)
378 {
379         int rc = *sz;
380
381         *outbuf = *data;
382         *sz = 0;
383         return (rc);
384 }
385
386 /* Convert 8 bit unsigned stereo data to 8 bit unsigned mono data */
387 size_t sndcnv8U_2mono(void **data, size_t * sz, void **outbuf)
388 {
389         REGISTER unsigned char *src;
390         REGISTER unsigned char *dest;
391         int rc, count;
392
393         count = *sz / 2;
394         if (count > SNDBUFSZ) {
395                 *sz -= 2 * SNDBUFSZ;
396                 count = SNDBUFSZ;
397         } else
398                 *sz = 0;
399         rc = count;
400         src = (unsigned char *)*data;
401         *outbuf = dest = miscplay_sndbuf;
402         while (count--) {
403                 *dest++ = (unsigned char)(((int)*(src) + (int)*(src + 1)) / 2);
404                 src += 2;
405         }
406         *data = src;
407         return (rc);
408 }
409
410 /* Convert 8 bit signed stereo data to 8 bit signed mono data */
411 size_t sndcnv8S_2mono(void **data, size_t * sz, void **outbuf)
412 {
413         REGISTER unsigned char *src;
414         REGISTER unsigned char *dest;
415         int rc, count;
416
417         count = *sz / 2;
418         if (count > SNDBUFSZ) {
419                 *sz -= 2 * SNDBUFSZ;
420                 count = SNDBUFSZ;
421         } else
422                 *sz = 0;
423         rc = count;
424         src = (unsigned char *)*data;
425         *outbuf = dest = miscplay_sndbuf;
426         while (count--) {
427                 *dest++ = (unsigned char)(((int)*((signed char *)(src)) +
428                                            (int)*((signed char *)(src + 1))) /
429                                           2);
430                 src += 2;
431         }
432         *data = src;
433         return (rc);
434 }
435
436 /* Convert 8 bit signed stereo data to 8 bit unsigned mono data */
437 size_t sndcnv2monounsigned(void **data, size_t * sz, void **outbuf)
438 {
439         REGISTER unsigned char *src;
440         REGISTER unsigned char *dest;
441         int rc, count;
442
443         count = *sz / 2;
444         if (count > SNDBUFSZ) {
445                 *sz -= 2 * SNDBUFSZ;
446                 count = SNDBUFSZ;
447         } else
448                 *sz = 0;
449         rc = count;
450         src = (unsigned char *)*data;
451         *outbuf = dest = miscplay_sndbuf;
452         while (count--) {
453                 *dest++ = (unsigned char)(((int)*((signed char *)(src)) +
454                                            (int)*((signed char *)(src + 1))) /
455                                           2) ^ 0x80;
456                 src += 2;
457         }
458         *data = src;
459         return (rc);
460 }
461
462 /* Convert 8 bit signed mono data to 8 bit unsigned mono data */
463 size_t sndcnv2unsigned(void **data, size_t * sz, void **outbuf)
464 {
465         REGISTER unsigned char *src;
466         REGISTER unsigned char *dest;
467         int rc, count;
468
469         count = *sz;
470         if (count > SNDBUFSZ) {
471                 *sz -= SNDBUFSZ;
472                 count = SNDBUFSZ;
473         } else
474                 *sz = 0;
475         rc = count;
476         src = (unsigned char *)*data;
477         *outbuf = dest = miscplay_sndbuf;
478         while (count--)
479                 *dest++ = *(src)++ ^ 0x80;
480         *data = src;
481         return (rc);
482 }
483
484 /* Convert a number in the range -32768..32767 to an 8 bit ulaw encoded
485    number --- I hope, I got this conversion right :-) */
486 static inline signed char int2ulaw(int i)
487 {
488         /* Lookup table for fast calculation of number of bits that need shifting */
489         static short int t_bits[128] = {
490                 0, 1, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5,
491                     5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
492                 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
493                     6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
494                 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
495                     7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
496                 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
497                     7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7
498         };
499         REGISTER int bits, logi;
500
501         /* unrolling this condition (hopefully) improves execution speed */
502         if (i < 0) {
503                 if ((i = (132 - i)) > 0x7FFF)
504                         i = 0x7FFF;
505                 logi = (i >> ((bits = t_bits[i / 256]) + 4));
506                 return ((bits << 4 | logi) ^ 0x7F);
507         } else {
508                 if ((i = 132 + i) > 0x7FFF)
509                         i = 0x7FFF;
510                 logi = (i >> ((bits = t_bits[i / 256]) + 4));
511                 return (~(bits << 4 | logi));
512         }
513 }
514
515 /* Convert from 8 bit ulaw mono to 8 bit linear mono */
516 size_t sndcnvULaw_2linear(void **data, size_t * sz, void **outbuf)
517 {
518         /* conversion table stolen from Linux's ulaw.h */
519         static unsigned char ulaw_dsp[] = {
520                 3, 7, 11, 15, 19, 23, 27, 31,
521                 35, 39, 43, 47, 51, 55, 59, 63,
522                 66, 68, 70, 72, 74, 76, 78, 80,
523                 82, 84, 86, 88, 90, 92, 94, 96,
524                 98, 99, 100, 101, 102, 103, 104, 105,
525                 106, 107, 108, 109, 110, 111, 112, 113,
526                 113, 114, 114, 115, 115, 116, 116, 117,
527                 117, 118, 118, 119, 119, 120, 120, 121,
528                 121, 121, 122, 122, 122, 122, 123, 123,
529                 123, 123, 124, 124, 124, 124, 125, 125,
530                 125, 125, 125, 125, 126, 126, 126, 126,
531                 126, 126, 126, 126, 127, 127, 127, 127,
532                 127, 127, 127, 127, 127, 127, 127, 127,
533                 128, 128, 128, 128, 128, 128, 128, 128,
534                 128, 128, 128, 128, 128, 128, 128, 128,
535                 128, 128, 128, 128, 128, 128, 128, 128,
536                 253, 249, 245, 241, 237, 233, 229, 225,
537                 221, 217, 213, 209, 205, 201, 197, 193,
538                 190, 188, 186, 184, 182, 180, 178, 176,
539                 174, 172, 170, 168, 166, 164, 162, 160,
540                 158, 157, 156, 155, 154, 153, 152, 151,
541                 150, 149, 148, 147, 146, 145, 144, 143,
542                 143, 142, 142, 141, 141, 140, 140, 139,
543                 139, 138, 138, 137, 137, 136, 136, 135,
544                 135, 135, 134, 134, 134, 134, 133, 133,
545                 133, 133, 132, 132, 132, 132, 131, 131,
546                 131, 131, 131, 131, 130, 130, 130, 130,
547                 130, 130, 130, 130, 129, 129, 129, 129,
548                 129, 129, 129, 129, 129, 129, 129, 129,
549                 128, 128, 128, 128, 128, 128, 128, 128,
550                 128, 128, 128, 128, 128, 128, 128, 128,
551                 128, 128, 128, 128, 128, 128, 128, 128,
552         };
553         unsigned char *p = (unsigned char *)*data;
554
555         *outbuf = *data;
556         while ((*sz)--) {
557                 *p = ulaw_dsp[*p];
558                 p++;
559         }
560         *sz = 0;
561         *data = p;
562         return p - (unsigned char *)*outbuf;
563 }
564
565 /* Convert 8 bit ulaw stereo data to 8 bit ulaw mono data */
566 size_t sndcnvULaw_2mono(void **data, size_t * sz, void **outbuf)
567 {
568
569         static short int ulaw2int[256] = {
570                 /* Precomputed lookup table for conversion from ulaw to 15 bit signed */
571                 -16062, -15550, -15038, -14526, -14014, -13502, -12990, -12478,
572                 -11966, -11454, -10942, -10430, -9918, -9406, -8894, -8382,
573                 -7998, -7742, -7486, -7230, -6974, -6718, -6462, -6206,
574                 -5950, -5694, -5438, -5182, -4926, -4670, -4414, -4158,
575                 -3966, -3838, -3710, -3582, -3454, -3326, -3198, -3070,
576                 -2942, -2814, -2686, -2558, -2430, -2302, -2174, -2046,
577                 -1950, -1886, -1822, -1758, -1694, -1630, -1566, -1502,
578                 -1438, -1374, -1310, -1246, -1182, -1118, -1054, -990,
579                 -942, -910, -878, -846, -814, -782, -750, -718,
580                 -686, -654, -622, -590, -558, -526, -494, -462,
581                 -438, -422, -406, -390, -374, -358, -342, -326,
582                 -310, -294, -278, -262, -246, -230, -214, -198,
583                 -186, -178, -170, -162, -154, -146, -138, -130,
584                 -122, -114, -106, -98, -90, -82, -74, -66,
585                 -60, -56, -52, -48, -44, -40, -36, -32,
586                 -28, -24, -20, -16, -12, -8, -4, +0,
587                 +16062, +15550, +15038, +14526, +14014, +13502, +12990, +12478,
588                 +11966, +11454, +10942, +10430, +9918, +9406, +8894, +8382,
589                 +7998, +7742, +7486, +7230, +6974, +6718, +6462, +6206,
590                 +5950, +5694, +5438, +5182, +4926, +4670, +4414, +4158,
591                 +3966, +3838, +3710, +3582, +3454, +3326, +3198, +3070,
592                 +2942, +2814, +2686, +2558, +2430, +2302, +2174, +2046,
593                 +1950, +1886, +1822, +1758, +1694, +1630, +1566, +1502,
594                 +1438, +1374, +1310, +1246, +1182, +1118, +1054, +990,
595                 +942, +910, +878, +846, +814, +782, +750, +718,
596                 +686, +654, +622, +590, +558, +526, +494, +462,
597                 +438, +422, +406, +390, +374, +358, +342, +326,
598                 +310, +294, +278, +262, +246, +230, +214, +198,
599                 +186, +178, +170, +162, +154, +146, +138, +130,
600                 +122, +114, +106, +98, +90, +82, +74, +66,
601                 +60, +56, +52, +48, +44, +40, +36, +32,
602                 +28, +24, +20, +16, +12, +8, +4, +0
603         };
604
605         REGISTER unsigned char *src;
606         REGISTER unsigned char *dest;
607         int rc, count;
608
609         count = *sz / 2;
610         if (count > SNDBUFSZ) {
611                 *sz -= 2 * SNDBUFSZ;
612                 count = SNDBUFSZ;
613         } else
614                 *sz = 0;
615         rc = count;
616         src = (unsigned char *)*data;
617         *outbuf = dest = miscplay_sndbuf;
618         while (count--) {
619                 /* it is not possible to directly interpolate between two ulaw encoded
620                    data bytes, thus we need to convert to linear format first and later
621                    we convert back to ulaw format */
622                 *dest++ = int2ulaw(ulaw2int[*src] + ulaw2int[*(src + 1)]);
623                 src += 2;
624         }
625         *data = src;
626         return (rc);
627 }
628
629 size_t sndcnv16swap(void **data, size_t * sz, void **outbuf)
630 {
631         size_t cnt = *sz / 2;
632         unsigned short *p;
633
634         *outbuf = *data;
635         p = (unsigned short *)*outbuf;
636         while (cnt--) {
637                 *p = ((*p & 0x00ff) << 8) | (*p >> 8);
638                 p++;
639         }
640         *data = p;
641         cnt = *sz;
642         *sz = 0;
643         return cnt;
644 }
645
646 /* Convert 16 bit little endian signed stereo data to 16 bit little endian
647    signed mono data */
648 size_t sndcnv16_2monoLE(void **data, size_t * sz, void **outbuf)
649 {
650         REGISTER unsigned char *src;
651         REGISTER unsigned char *dest;
652         int rc, count;
653         signed short i;
654
655         count = *sz / 2;
656         if (count > SNDBUFSZ) {
657                 *sz -= 2 * SNDBUFSZ;
658                 count = SNDBUFSZ;
659         } else
660                 *sz = 0;
661         rc = count;
662         src = (unsigned char *)*data;
663         *outbuf = dest = miscplay_sndbuf;
664         for (count /= 2; count--;) {
665                 i = ((int)(src[0]) +
666                      256 * (int)(src[1]) +
667                      (int)(src[2]) + 256 * (int)(src[3])) / 2;
668                 src += 4;
669                 *dest++ = (unsigned char)(i & 0xFF);
670                 *dest++ = (unsigned char)((i / 256) & 0xFF);
671         }
672         *data = src;
673         return (rc);
674 }
675
676 /* Convert 16 bit big endian signed stereo data to 16 bit big endian
677    signed mono data */
678 size_t sndcnv16_2monoBE(void **data, size_t * sz, void **outbuf)
679 {
680         REGISTER unsigned char *src;
681         REGISTER unsigned char *dest;
682         int rc, count;
683         signed short i;
684
685         count = *sz / 2;
686         if (count > SNDBUFSZ) {
687                 *sz -= 2 * SNDBUFSZ;
688                 count = SNDBUFSZ;
689         } else
690                 *sz = 0;
691         rc = count;
692         src = (unsigned char *)*data;
693         *outbuf = dest = miscplay_sndbuf;
694         for (count /= 2; count--;) {
695                 i = ((int)(src[1]) +
696                      256 * (int)(src[0]) +
697                      (int)(src[3]) + 256 * (int)(src[2])) / 2;
698                 src += 4;
699                 *dest++ = (unsigned char)((i / 256) & 0xFF);
700                 *dest++ = (unsigned char)(i & 0xFF);
701         }
702         *data = src;
703         return (rc);
704 }
705
706 /* Convert 16 bit little endian signed data to 8 bit unsigned data */
707 size_t sndcnv2byteLE(void **data, size_t * sz, void **outbuf)
708 {
709         REGISTER unsigned char *src;
710         REGISTER unsigned char *dest;
711         int rc, count;
712
713         count = *sz / 2;
714         if (count > SNDBUFSZ) {
715                 *sz -= 2 * SNDBUFSZ;
716                 count = SNDBUFSZ;
717         } else
718                 *sz = 0;
719         rc = count;
720         src = (unsigned char *)*data;
721         *outbuf = dest = miscplay_sndbuf;
722         while (count--) {
723                 *dest++ =
724                     (unsigned char)(((signed char *)src)[1] ^ (signed char)
725                                     0x80);
726                 src += 2;
727         }
728         *data = src;
729         return (rc);
730 }
731
732 /* Convert 16 bit big endian signed data to 8 bit unsigned data */
733 size_t sndcnv2byteBE(void **data, size_t * sz, void **outbuf)
734 {
735         REGISTER unsigned char *src;
736         REGISTER unsigned char *dest;
737         int rc, count;
738
739         count = *sz / 2;
740         if (count > SNDBUFSZ) {
741                 *sz -= 2 * SNDBUFSZ;
742                 count = SNDBUFSZ;
743         } else
744                 *sz = 0;
745         rc = count;
746         src = (unsigned char *)*data;
747         *outbuf = dest = miscplay_sndbuf;
748         while (count--) {
749                 *dest++ =
750                     (unsigned char)(((signed char *)src)[0] ^ (signed char)
751                                     0x80);
752                 src += 2;
753         }
754         *data = src;
755         return (rc);
756 }
757
758 /* Convert 16 bit little endian signed stereo data to 8 bit unsigned
759    mono data */
760 size_t sndcnv2monobyteLE(void **data, size_t * sz, void **outbuf)
761 {
762         REGISTER unsigned char *src;
763         REGISTER unsigned char *dest;
764         int rc, count;
765
766         count = *sz / 4;
767         if (count > SNDBUFSZ) {
768                 *sz -= 4 * SNDBUFSZ;
769                 count = SNDBUFSZ;
770         } else
771                 *sz = 0;
772         rc = count;
773         src = (unsigned char *)*data;
774         *outbuf = dest = miscplay_sndbuf;
775         while (count--) {
776                 *dest++ = (unsigned char)(((int)((signed char *)src)[1] +
777                                            (int)((signed char *)src)[3]) /
778                                           2 ^ 0x80);
779                 src += 4;
780         }
781         *data = src;
782         return (rc);
783 }
784
785 /* Convert 16 bit big endian signed stereo data to 8 bit unsigned
786    mono data */
787 size_t sndcnv2monobyteBE(void **data, size_t * sz, void **outbuf)
788 {
789         REGISTER unsigned char *src;
790         REGISTER unsigned char *dest;
791         int rc, count;
792
793         count = *sz / 4;
794         if (count > SNDBUFSZ) {
795                 *sz -= 4 * SNDBUFSZ;
796                 count = SNDBUFSZ;
797         } else
798                 *sz = 0;
799         rc = count;
800         src = (unsigned char *)*data;
801         *outbuf = dest = miscplay_sndbuf;
802         while (count--) {
803                 *dest++ = (unsigned char)(((int)((signed char *)src)[0] +
804                                            (int)((signed char *)src)[2]) /
805                                           2 ^ 0x80);
806                 src += 4;
807         }
808         *data = src;
809         return (rc);
810 }
811
812 \f
813 static void
814 media_internal_analyse_data(Lisp_Media_Stream *ms, char *data)
815 {
816         /* we always assume to deal with audio data */
817         media_substream *mss = media_stream_nsub(ms);
818         mtype_audio_properties *mtap;
819         char *name;
820
821         /* initialise */
822         mtap = xnew_and_zero(mtype_audio_properties);
823         name = xmalloc_atomic(20);
824
825         mtap->samplerate = 0;
826
827         /* Keep compatibility with Linux 68k, etc. by not relying on byte-sex */
828         if (!memcmp(data, "Creative Voice File\x1A\x1A\x00", 22) &&
829             (data[22] + 256 * data[23]) ==
830             ((0x1233 - data[24] - 256 * data[25]) & 0xFFFF)) { /* VOC */
831                 memcpy(name, "VOC", 3);
832                 name[3] = '\0';
833                 mtap->name = name;
834                 mtap->channels = 2;
835                 mtap->samplerate = 8000;
836                 mtap->samplewidth = 16;
837                 mtap->framesize = 4;
838                 mtap->endianness = 0;
839         } else if (!memcmp(data, "RIFF", 4) &&
840                    !memcmp(data + 8, "WAVEfmt ", 8)) { /* WAVE */
841                 memcpy(name, "WAV", 3);
842                 name[3] = '\0';
843                 mtap->name = name;
844                 mtap->channels = data[22];
845                 mtap->samplerate = data[24] + 256 *
846                         (data[25] + 256 * (data[26] + 256 * data[27]));
847                 mtap->samplewidth = 16;
848                 mtap->framesize = mtap->channels * 2;
849                 mtap->endianness = 0;
850         } else if (!memcmp(data, ".snd", 4)) {  /* Sun Audio (big endian) */
851                 if (data[7] + 256 * (data[6] + 256 *
852                                      (data[5] + 256 * data[4])) < 24) {
853                         memcpy(name, "SunAudio", 8);
854                         name[8] = '\0';
855                         mtap->name = name;
856                         mtap->channels = 1;
857                         mtap->samplerate = 8000;
858                         mtap->samplewidth = 16;
859                         mtap->framesize = 2;
860                         mtap->endianness = 0;
861                 } else if (!memcmp(data + 12, "\000\000\000\001", 4) ||
862                            !memcmp(data + 12, "\000\000\000\002", 4) ||
863                            !memcmp(data + 12, "\000\000\000\003", 4)) {
864                         memcpy(name, "SunAudio", 8);
865                         name[8] = '\0';
866                         mtap->name = name;
867                         mtap->channels = data[23];
868                         mtap->samplerate = data[19] +
869                                 256 * (data[18] + 256 *
870                                        (data[17] + 256 * data[16]));
871                         mtap->samplewidth = 16;
872                         mtap->framesize = mtap->channels * 2;
873                         mtap->endianness = 0;
874                 }
875         } else if (!memcmp(data, ".sd", 4)) { /* DEC Audio (little endian) */
876                 if (data[4] + 256 * (data[5] + 256 *
877                                      (data[6] + 256 * data[7])) < 24) {
878                         memcpy(name, "SunAudio", 8);
879                         name[8] = '\0';
880                         mtap->name = name;
881                         mtap->channels = 1;
882                         mtap->samplerate = 8000;
883                         mtap->samplewidth = 16;
884                         mtap->framesize = 2;
885                         mtap->endianness = 0;
886                 } else if (!memcmp(data + 12, "\001\000\000", 4) ||
887                            !memcmp(data + 12, "\002\000\000", 4) ||
888                            !memcmp(data + 12, "\003\000\000", 4)) {
889                         memcpy(name, "SunAudio", 8);
890                         name[8] = '\0';
891                         mtap->name = name;
892                         mtap->channels = data[20];
893                         mtap->samplerate = data[16] +
894                                 256 * (data[17] + 256 *
895                                        (data[18] + 256 * data[19]));
896                         mtap->samplewidth = 16;
897                         mtap->framesize = mtap->channels * 2;
898                         mtap->endianness = 0;
899                 }
900         } else {
901 #if 0
902                 memcpy(name, "Raw", 3);
903                 name[3] = '\0';
904                 mtap->name = name;
905                 mtap->channels = 1;
906                 mtap->samplerate = 8000;
907                 mtap->samplewidth = 16;
908                 mtap->framesize = 2;
909                 mtap->endianness = 0;
910 #endif
911         }
912
913         /* create a substream and assign */
914         if (mtap->samplerate) {
915                 media_substream_type(mss) = MTYPE_AUDIO;
916                 media_substream_type_properties(mss).aprops = mtap;
917         } else {
918                 xfree(mtap);
919                 xfree(name);
920         }
921 }
922
923 void media_internal_analyse_stream(Lisp_Media_Stream *ms)
924 {
925         /* stuff for file handling */
926         int fd = -1, len;
927         /* data probe for the internal analyser */
928         char *data;
929         /* stream stuff */
930         media_substream *mss;
931
932         data = xmalloc_atomic(48);
933
934         switch (media_stream_kind(ms)) {
935         case MKIND_FILE: {
936                 mkind_file_properties *mkfp = NULL;
937                 const char *file;
938                 int file_len = 0;
939
940                 /* open the file */
941                 mkfp = media_stream_kind_properties(ms).fprops;
942                 TO_EXTERNAL_FORMAT(LISP_STRING, mkfp->filename,
943                                    ALLOCA, (file, file_len), Qnil);
944                 if ((fd = open(file, O_RDONLY, 0)) < 0)
945                         return;
946
947                 /* take a data probe */
948                 len = read(fd, data, 44);
949                 if (len < 44) {
950                         xfree(data);
951                         close(fd);
952                         return;
953                 }
954                 break;
955         }
956         case MKIND_STRING: {
957                 mkind_string_properties *mksp = NULL;
958
959                 /* prepare our user_data */
960                 mksp = media_stream_kind_properties(ms).sprops;
961                 if (mksp->size < 44) {
962                         xfree(data);
963                         return;
964                 }
965                 memcpy(data, mksp->stream_data, 44);
966                 break;
967         }
968         case MKIND_UNKNOWN:
969         case MKIND_FIFO:
970         case MKIND_STREAM:
971         case NUMBER_OF_MEDIA_KINDS:
972         default:
973                 break;
974         }
975
976         /* create a substream */
977         mss = make_media_substream_append(ms);
978
979         media_internal_analyse_data(ms, data);
980
981         if (media_substream_type(mss) == MTYPE_AUDIO) {
982                 media_stream_driver(ms) = MYSELF;
983         }
984
985         /* shutdown */
986         xfree(data);
987         close(fd);
988 }
989
990 /* Look at the header of the sound file and try to determine the format;
991    we can recognize files in VOC, WAVE, and, Sun/DEC-audio format--- everything
992    else is assumed to be raw 8 bit unsigned data sampled at 8kHz */
993 fmtType analyze_format(unsigned char *format, int *fmt, int *speed,
994                        int *tracks,
995                        size_t(**parsesndfile) (void **, size_t * sz, void **))
996 {
997         /* Keep compatibility with Linux 68k, etc. by not relying on byte-sex */
998         if (!memcmp(format, "Creative Voice File\x1A\x1A\x00", 22) &&
999             (format[22] + 256 * format[23]) ==
1000             ((0x1233 - format[24] - 256 * format[25]) & 0xFFFF)) { /* VOC */
1001                 *fmt = AFMT_U8;
1002                 *speed = 8000;
1003                 *tracks = 2;
1004                 *parsesndfile = parsevoc;
1005                 return (fmtVoc);
1006         } else if (!memcmp(format, "RIFF", 4) &&
1007                    !memcmp(format + 8, "WAVEfmt ", 8)) { /* WAVE */
1008                 if (memcmp(format + 20, "\001\000\001" /* PCM mono */ , 4) &&
1009                     memcmp(format + 20, "\001\000\002" /* PCM stereo */ , 4))
1010                         return (fmtIllegal);
1011                 *fmt = (format[32] / (*tracks = format[22])) == 1 ?
1012                     AFMT_U8 : AFMT_S16_LE;
1013                 /* Keep compatibility with Linux 68k, etc.
1014                  * by not relying on byte-sex
1015                  */
1016                 *speed = format[24] + 256 * (format[25] + 256 *
1017                                              (format[26] + 256 * format[27]));
1018                 *parsesndfile = parsewave;
1019                 return (fmtWave);
1020         } else if (!memcmp(format, ".snd", 4)) { /* Sun Audio (big endian) */
1021                 if (format[7] +
1022                     256 * (format[6] + 256 * (format[5] + 256 * format[4])) <
1023                     24) {
1024                         *fmt = AFMT_MU_LAW;
1025                         *speed = 8000;
1026                         *tracks = 1;
1027                         *parsesndfile = parsesundecaudio;
1028                         return (fmtSunAudio);
1029                 }
1030                 if (!memcmp(format + 12, "\000\000\000\001", 4))
1031                         *fmt = AFMT_MU_LAW;
1032                 else if (!memcmp(format + 12, "\000\000\000\002", 4))
1033                         *fmt = AFMT_S8;
1034                 else if (!memcmp(format + 12, "\000\000\000\003", 4))
1035                         *fmt = AFMT_S16_BE;
1036                 else
1037                         return (fmtIllegal);
1038                 /* Keep compatibility with Linux 68k, etc.
1039                  * by not relying on byte-sex
1040                  */
1041                 *speed = format[19] + 256 * (format[18] + 256 *
1042                                              (format[17] + 256 * format[16]));
1043                 *tracks = format[23];
1044                 *parsesndfile = parsesundecaudio;
1045                 return (fmtSunAudio);
1046         } else if (!memcmp(format, ".sd", 4)) { /* DEC Audio (little endian) */
1047                 if (format[4] +
1048                     256 * (format[5] + 256 * (format[6] + 256 * format[7])) <
1049                     24) {
1050                         *fmt = AFMT_MU_LAW;
1051                         *speed = 8000;
1052                         *tracks = 1;
1053                         *parsesndfile = parsesundecaudio;
1054                         return (fmtSunAudio);
1055                 }
1056                 if (!memcmp(format + 12, "\001\000\000", 4))
1057                         *fmt = AFMT_MU_LAW;
1058                 else if (!memcmp(format + 12, "\002\000\000", 4))
1059                         *fmt = AFMT_S8;
1060                 else if (!memcmp(format + 12, "\003\000\000", 4))
1061                         *fmt = AFMT_S16_LE;
1062                 else
1063                         return (fmtIllegal);
1064                 /* Keep compatibility with Linux 68k, etc.
1065                  * by not relying on byte-sex
1066                  */
1067                 *speed = format[16] + 256 * (format[17] + 256 *
1068                                              (format[18] + 256 * format[19]));
1069                 *tracks = format[20];
1070                 *parsesndfile = parsesundecaudio;
1071                 return (fmtSunAudio);
1072         } else {
1073                 *fmt = AFMT_U8;
1074                 *speed = 8000;
1075                 *tracks = 1;
1076                 *parsesndfile = parseraw;
1077                 return (fmtRaw);
1078         }
1079 }
1080
1081 #undef MYSELF