1 /* linuxplay.c - play a sound file on the speaker
3 ** Copyright (C) 1995,96 by Markus Gutschke (gutschk@math.uni-muenster.de)
4 ** This is version 1.3 of linuxplay.c
6 ** Parts of this code were inspired by sunplay.c, which is copyright 1989 by
7 ** Jef Poskanzer and 1991,92 by Jamie Zawinski; c.f. sunplay.c for further
10 ** Permission to use, copy, modify, and distribute this software and its
11 ** documentation for any purpose and without fee is hereby granted, provided
12 ** that the above copyright notice appear in all copies and that both that
13 ** copyright notice and this permission notice appear in supporting
14 ** documentation. This software is provided "as is" without express or
18 ** 1.0 -- first release; supports SunAudio, Wave and RAW file formats
19 ** detects (and rejects) VOC file format
20 ** tested with PC-Speaker driver only
21 ** 1.1 -- fixed bug with playback of stereo Wave files
22 ** fixed VOC file detection
23 ** fixed mono/8bit conversion
24 ** cleaned up mixer programming (c.f. VoxWare-SDK)
25 ** tested with PC-Speaker driver and with PAS16 soundcard
26 ** 1.2 -- first (incompatible) attempt at fixing reliable signal handling
27 ** 1.3 -- changed signal handling to use reliable signals; this is done
28 ** by including "syssignal.h"; it fixes nasty program crashes
29 ** when using native sound in TTY mode.
30 ** added support for DEC audio file format (this is basically the
31 ** same as Sun audio, but uses little endian format, instead).
32 ** strip the header from Sun audio and DEC audio files in order to
33 ** prevent noise at beginning of samples (thanks to Thomas Pundt
34 ** <pundtt@math.uni-muenster.de> for pointing out this bug and
35 ** providing information on the file format).
36 ** added a few more conversion routines.
37 ** made the code even more tolerant to the limits imposed by some
38 ** soundcards and try to accept soundfiles even if they are not
39 ** fully conformant to the standard.
40 ** 1.4 -- increased header size to 256; I hope there is no sample software
41 ** that requires this much.
42 ** added code for converting from signed to unsigned format as
43 ** some soundcards cannot handle signed 8bit data.
46 /* Synched up with: Not in FSF. */
48 #define HEADERSZ 256 /* has to be at least as big as the biggest header */
49 #define SNDBUFSZ 2048 /* has to be at least as big as HEADERSZ */
51 /* XEmacs beta testers say: undef this by default. */
52 #undef NOVOLUMECTRLFORMULAW /* Changing the volume for uLaw-encoded
53 samples sounds very poor; possibly,
54 this is true only for the PC-Snd
55 driver, so undefine this symbol at your
64 #include SOUNDCARD_H_PATH /* Path computed by configure */
70 #include <sys/ioctl.h>
71 #include <sys/signal.h>
74 #ifdef LINUXPLAYSTANDALONE
75 #define perror(str) fprintf(stderr,"audio: %s %s\n",str,strerror(errno));
76 #define warn(str) fprintf(stderr,"audio: %s\n",str);
79 #include "syssignal.h"
81 #define perror(str) message("audio: %s, %s ",str,strerror(errno))
82 #define warn(str) message("audio: %s ",GETTEXT(str))
86 #define UNUSED(x) ((void)(x))
92 static void (*sighup_handler)(int);
93 static void (*sigint_handler)(int);
95 /* Maintain global variable for keeping parser state information; this struct
96 is set to zero before the first invocation of the parser. The use of a
97 global variable prevents multiple concurrent executions of this code, but
98 this does not happen anyways... */
114 unsigned char leftover[HEADERSZ];
115 signed long chunklength;
122 unsigned char leftover[HEADERSZ];
126 /* Use a global buffer as scratch-pad for possible conversions of the
128 unsigned char linuxplay_sndbuf[SNDBUFSZ];
131 static int audio_vol;
133 static char *audio_dev = "/dev/dsp";
135 typedef enum {fmtIllegal,fmtRaw,fmtVoc,fmtWave,fmtSunAudio} fmtType;
137 /* Intercept SIGINT and SIGHUP in order to close the audio and mixer
138 devices before terminating sound output; this requires reliable
139 signals as provided by "syssignal.h" */
140 static void sighandler(int sig)
143 if (audio_vol >= 0) {
144 ioctl(mix_fd,SOUND_MIXER_WRITE_PCM,&audio_vol);
146 if (mix_fd != audio_fd)
150 ioctl(audio_fd,SNDCTL_DSP_SYNC,NULL);
151 ioctl(audio_fd,SNDCTL_DSP_RESET,NULL);
154 if (sig == SIGHUP && sighup_handler) sighup_handler(sig);
155 else if (sig == SIGINT && sigint_handler) sigint_handler(sig);
159 /* There is no special treatment required for parsing raw data files; we
160 assume that these files contain data in 8bit unsigned format that
161 has been sampled at 8kHz; there is no extra header */
162 static size_t parseraw(void **data,size_t *sz,void **outbuf)
171 /* Currently we cannot cope with files in VOC format; if you really need
172 to play these files, they should be converted by using SOX */
173 static size_t parsevoc(void **data,size_t *sz,void **outbuf)
181 /* We need to perform some look-ahead in order to parse files in WAVE format;
182 this might require re-partioning of the data segments if headers cross the
183 boundaries between two read operations. This is done in a two-step way:
184 first we request a certain amount of bytes... */
185 static __inline__ int waverequire(void **data,size_t *sz,size_t rq)
190 warn("Header size exceeded while parsing WAVE file");
191 parsestate.wave.state = wvFatal;
194 if ((rq -= parsestate.wave.left) <= 0)
196 if (rq > *sz) {rq = *sz; rc = 0;}
197 memcpy(parsestate.wave.leftover+parsestate.wave.left,
199 parsestate.wave.left += rq;
200 (*(unsigned char **)data) += rq;
205 /* ...and next we remove this many bytes from the buffer */
206 static __inline__ void waveremove(size_t rq)
208 if (parsestate.wave.left <= rq)
209 parsestate.wave.left = 0;
211 parsestate.wave.left -= rq;
212 memmove(parsestate.wave.leftover,
213 parsestate.wave.leftover+rq,
214 parsestate.wave.left); }
218 /* Sound files in WAVE format can contain an arbitrary amount of tagged
219 chunks; this requires quite some effort for parsing the data */
220 static size_t parsewave(void **data,size_t *sz,void **outbuf)
223 switch (parsestate.wave.state) {
225 if (!waverequire(data,sz,20))
227 /* Keep compatibility with Linux 68k, etc. by not relying on byte-sex */
228 parsestate.wave.chunklength = parsestate.wave.leftover[16] +
229 256*(parsestate.wave.leftover[17] +
230 256*(parsestate.wave.leftover[18] +
231 256*parsestate.wave.leftover[19]));
233 parsestate.wave.state = wvSubchunk;
236 if (!waverequire(data,sz,parsestate.wave.chunklength))
238 parsestate.wave.align = parsestate.wave.chunklength < 14 ? 1
239 : parsestate.wave.leftover[12];
240 if (parsestate.wave.align != 1 &&
241 parsestate.wave.align != 2 &&
242 parsestate.wave.align != 4) {
243 warn("Illegal datawidth detected while parsing WAVE file");
244 parsestate.wave.state = wvFatal; }
246 parsestate.wave.state = wvOutOfBlock;
247 waveremove(parsestate.wave.chunklength);
250 if (!waverequire(data,sz,8))
252 /* Keep compatibility with Linux 68k, etc. by not relying on byte-sex */
253 parsestate.wave.chunklength = parsestate.wave.leftover[4] +
254 256*(parsestate.wave.leftover[5] +
255 256*(parsestate.wave.leftover[6] +
256 256*(parsestate.wave.leftover[7] & 0x7F)));
257 if (memcmp(parsestate.wave.leftover,"data",4))
258 parsestate.wave.state = wvSkipChunk;
260 parsestate.wave.state = wvSoundChunk;
264 if (parsestate.wave.chunklength > 0 && *sz > 0 &&
265 (signed long)*sz < (signed long)parsestate.wave.chunklength) {
266 parsestate.wave.chunklength -= *sz;
269 if (parsestate.wave.chunklength > 0 && *sz > 0) {
270 *sz -= parsestate.wave.chunklength;
271 (*(unsigned char **)data) += parsestate.wave.chunklength; }
272 parsestate.wave.state = wvOutOfBlock; }
276 if (parsestate.wave.left) { /* handle leftover bytes from last
277 alignment operation */
278 count = parsestate.wave.left;
280 if (rq > (size_t) parsestate.wave.chunklength)
281 rq = parsestate.wave.chunklength;
282 if (!waverequire(data,sz,rq)) {
283 parsestate.wave.chunklength -= parsestate.wave.left - count;
285 parsestate.wave.chunklength -= rq;
286 *outbuf = parsestate.wave.leftover;
287 parsestate.wave.left = 0;
289 if (*sz >= (size_t) parsestate.wave.chunklength) {
290 count = parsestate.wave.chunklength;
294 count -= rq = count % parsestate.wave.align; }
296 (*(unsigned char **)data) += count;
298 if ((parsestate.wave.chunklength -= count) < parsestate.wave.align) {
299 parsestate.wave.state = wvOutOfBlock;
300 /* Some broken software (e.g. SOX) attaches junk to the end of a sound
301 chunk; so, let's ignore this... */
302 if (parsestate.wave.chunklength)
303 parsestate.wave.state = wvSkipChunk; }
305 /* align data length to a multiple of datasize; keep additional data
306 in "leftover" buffer --- this is necessary to ensure proper
307 functioning of the sndcnv... routines */
308 waverequire(data,sz,rq);
311 warn("Irrecoverable error while parsing WAVE file");
312 parsestate.wave.state = wvFatal;
320 /* Strip the header from files in Sun/DEC audio format; this requires some
321 extra processing as the header can be an arbitrary size and it might
322 result in alignment errors for subsequent conversions --- thus we do
323 some buffering, where needed */
324 static size_t parsesundecaudio(void **data,size_t *sz,void **outbuf)
326 /* There is data left over from the last invocation of this function; join
327 it with the new data and return a sound chunk that is as big as a
329 if (parsestate.audio.left) {
330 if (parsestate.audio.left + *sz > (size_t) parsestate.audio.align) {
332 memmove(parsestate.audio.leftover + parsestate.audio.left,
334 count = parsestate.audio.align - parsestate.audio.left);
335 *outbuf = parsestate.audio.leftover;
337 *data = (*(char **)data) + count;
338 parsestate.audio.left = 0;
339 return(parsestate.audio.align); }
341 /* We need even more data in order to get one complete single entry! */
342 memmove(parsestate.audio.leftover + parsestate.audio.left,
345 *data = (*(char **)data) + *sz;
346 parsestate.audio.left += *sz;
350 /* This is the main sound chunk, strip of any extra data that does not fit
351 the alignment requirements and move these bytes into the leftover buffer*/
352 if (parsestate.audio.isdata) {
355 if ((parsestate.audio.left = rc % parsestate.audio.align) != 0) {
356 memmove(parsestate.audio.leftover,
357 (char *)*outbuf + rc - parsestate.audio.left,
358 parsestate.audio.left);
359 rc -= parsestate.audio.left; }
363 /* This is the first invocation of this function; we need to parse the
364 header information and determine how many bytes we need to skip until
365 the start of the sound chunk */
366 if (!parsestate.audio.skipping) {
367 unsigned char *header = (unsigned char *) *data;
369 warn("Irrecoverable error while parsing Sun/DEC audio file");
371 /* Keep compatibility with Linux 68k, etc. by not relying on byte-sex */
372 if (header[3]) { /* Sun audio (big endian) */
373 parsestate.audio.align = ((header[15] > 2)+1)*header[23];
374 parsestate.audio.skipping = header[7]+256*(header[6]+256*
375 (header[5]+256*header[4])); }
376 else { /* DEC audio (little endian) */
377 parsestate.audio.align = ((header[12] > 2)+1)*header[20];
378 parsestate.audio.skipping = header[4]+256*(header[5]+256*
379 (header[6]+256*header[7])); }}
381 /* We are skipping extra data that has been attached to header; most usually
382 this will be just a comment, such as the original filename and/or the
383 creation date. Make sure that we do not return less than one single sound
384 sample entry to the caller; if this happens, rather decide to move those
385 few bytes into the leftover buffer and deal with it later */
386 if (*sz >= (size_t) parsestate.audio.skipping) {
387 /* Skip just the header information and return the sound chunk */
388 int rc = *sz - parsestate.audio.skipping;
389 *outbuf = (char *)*data + parsestate.audio.skipping;
390 if ((parsestate.audio.left = rc % parsestate.audio.align) != 0) {
391 memmove(parsestate.audio.leftover,
392 (char *)*outbuf + rc - parsestate.audio.left,
393 parsestate.audio.left);
394 rc -= parsestate.audio.left; }
396 parsestate.audio.skipping = 0;
397 parsestate.audio.isdata++;
400 /* Skip everything */
401 parsestate.audio.skipping -= *sz;
405 /* If the soundcard could not be set to natively support the data format, we
406 try to do some limited on-the-fly conversion to a different format; if
407 no conversion is needed, though, we can output directly */
408 static size_t sndcnvnop(void **data,size_t *sz,void **outbuf)
417 /* Convert 8 bit unsigned stereo data to 8 bit unsigned mono data */
418 static size_t sndcnv8U_2mono(void **data,size_t *sz,void **outbuf)
420 REGISTER unsigned char *src;
421 REGISTER unsigned char *dest;
425 if (count > SNDBUFSZ) { *sz -= 2*SNDBUFSZ; count = SNDBUFSZ; }
428 src = (unsigned char *) *data;
430 dest = linuxplay_sndbuf;
432 *dest++ = (unsigned char)(((int)*(src)++ +
438 /* Convert 8 bit signed stereo data to 8 bit signed mono data */
439 static size_t sndcnv8S_2mono(void **data,size_t *sz,void **outbuf)
441 REGISTER unsigned char *src;
442 REGISTER unsigned char *dest;
446 if (count > SNDBUFSZ) { *sz -= 2*SNDBUFSZ; count = SNDBUFSZ; }
449 src = (unsigned char *) *data;
451 dest = linuxplay_sndbuf;
453 *dest++ = (unsigned char)(((int)*((signed char *)(src++)) +
454 (int)*((signed char *)(src++))) / 2);
459 /* Convert 8 bit signed stereo data to 8 bit unsigned mono data */
460 static size_t sndcnv2monounsigned(void **data,size_t *sz,void **outbuf)
462 REGISTER unsigned char *src;
463 REGISTER unsigned char *dest;
467 if (count > SNDBUFSZ) { *sz -= 2*SNDBUFSZ; count = SNDBUFSZ; }
470 src = (unsigned char *) *data;
472 dest = linuxplay_sndbuf;
474 *dest++ = (unsigned char)(((int)*((signed char *)(src++)) +
475 (int)*((signed char *)(src++))) / 2) ^ 0x80;
480 /* Convert 8 bit signed mono data to 8 bit unsigned mono data */
481 static size_t sndcnv2unsigned(void **data,size_t *sz,void **outbuf)
483 REGISTER unsigned char *src;
484 REGISTER unsigned char *dest;
488 if (count > SNDBUFSZ) { *sz -= SNDBUFSZ; count = SNDBUFSZ; }
491 src = (unsigned char *) *data;
493 dest = linuxplay_sndbuf;
495 *dest++ = *(src)++ ^ 0x80;
500 /* Convert a number in the range -32768..32767 to an 8 bit ulaw encoded
501 number --- I hope, I got this conversion right :-) */
502 static __inline__ signed char int2ulaw(int i)
504 /* Lookup table for fast calculation of number of bits that need shifting*/
505 static short int t_bits[128] = {
506 0,1,2,2,3,3,3,3,4,4,4,4,4,4,4,4,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
507 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
508 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
509 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7};
510 REGISTER int bits,logi;
512 /* unrolling this condition (hopefully) improves execution speed */
514 if ((i = (132-i)) > 0x7FFF) i = 0x7FFF;
515 logi = (i >> ((bits = t_bits[i/256])+4));
516 return((bits << 4 | logi) ^ 0x7F); }
518 if ((i = 132+i) > 0x7FFF) i = 0x7FFF;
519 logi = (i >> ((bits = t_bits[i/256])+4));
520 return(~(bits << 4 | logi)); }
523 /* Convert 8 bit ulaw stereo data to 8 bit ulaw mono data */
524 static size_t sndcnvULaw_2mono(void **data,size_t *sz,void **outbuf)
527 static short int ulaw2int[256] = {
528 /* Precomputed lookup table for conversion from ulaw to 15 bit signed */
529 -16062,-15550,-15038,-14526,-14014,-13502,-12990,-12478,
530 -11966,-11454,-10942,-10430, -9918, -9406, -8894, -8382,
531 -7998, -7742, -7486, -7230, -6974, -6718, -6462, -6206,
532 -5950, -5694, -5438, -5182, -4926, -4670, -4414, -4158,
533 -3966, -3838, -3710, -3582, -3454, -3326, -3198, -3070,
534 -2942, -2814, -2686, -2558, -2430, -2302, -2174, -2046,
535 -1950, -1886, -1822, -1758, -1694, -1630, -1566, -1502,
536 -1438, -1374, -1310, -1246, -1182, -1118, -1054, -990,
537 -942, -910, -878, -846, -814, -782, -750, -718,
538 -686, -654, -622, -590, -558, -526, -494, -462,
539 -438, -422, -406, -390, -374, -358, -342, -326,
540 -310, -294, -278, -262, -246, -230, -214, -198,
541 -186, -178, -170, -162, -154, -146, -138, -130,
542 -122, -114, -106, -98, -90, -82, -74, -66,
543 -60, -56, -52, -48, -44, -40, -36, -32,
544 -28, -24, -20, -16, -12, -8, -4, +0,
545 +16062,+15550,+15038,+14526,+14014,+13502,+12990,+12478,
546 +11966,+11454,+10942,+10430, +9918, +9406, +8894, +8382,
547 +7998, +7742, +7486, +7230, +6974, +6718, +6462, +6206,
548 +5950, +5694, +5438, +5182, +4926, +4670, +4414, +4158,
549 +3966, +3838, +3710, +3582, +3454, +3326, +3198, +3070,
550 +2942, +2814, +2686, +2558, +2430, +2302, +2174, +2046,
551 +1950, +1886, +1822, +1758, +1694, +1630, +1566, +1502,
552 +1438, +1374, +1310, +1246, +1182, +1118, +1054, +990,
553 +942, +910, +878, +846, +814, +782, +750, +718,
554 +686, +654, +622, +590, +558, +526, +494, +462,
555 +438, +422, +406, +390, +374, +358, +342, +326,
556 +310, +294, +278, +262, +246, +230, +214, +198,
557 +186, +178, +170, +162, +154, +146, +138, +130,
558 +122, +114, +106, +98, +90, +82, +74, +66,
559 +60, +56, +52, +48, +44, +40, +36, +32,
560 +28, +24, +20, +16, +12, +8, +4, +0};
562 REGISTER unsigned char *src;
563 REGISTER unsigned char *dest;
567 if (count > SNDBUFSZ) { *sz -= 2*SNDBUFSZ; count = SNDBUFSZ; }
570 src = (unsigned char *) *data;
572 dest = linuxplay_sndbuf;
574 /* it is not possible to directly interpolate between two ulaw encoded
575 data bytes, thus we need to convert to linear format first and later
576 we convert back to ulaw format */
577 *dest++ = int2ulaw(ulaw2int[*(src)++] +
583 /* Convert 16 bit little endian signed stereo data to 16 bit little endian
585 static size_t sndcnv16_2monoLE(void **data,size_t *sz,void **outbuf)
587 REGISTER unsigned char *src;
588 REGISTER unsigned char *dest;
593 if (count > SNDBUFSZ) { *sz -= 2*SNDBUFSZ; count = SNDBUFSZ; }
596 src = (unsigned char *) *data;
598 dest = linuxplay_sndbuf;
599 for (count /= 2; count--; ) {
603 256*(int)(src[3])) / 2;
605 *dest++ = (unsigned char)(i & 0xFF);
606 *dest++ = (unsigned char)((i / 256) & 0xFF); }
611 /* Convert 16 bit big endian signed stereo data to 16 bit big endian
613 static size_t sndcnv16_2monoBE(void **data,size_t *sz,void **outbuf)
615 REGISTER unsigned char *src;
616 REGISTER unsigned char *dest;
621 if (count > SNDBUFSZ) { *sz -= 2*SNDBUFSZ; count = SNDBUFSZ; }
624 src = (unsigned char *) *data;
626 dest = linuxplay_sndbuf;
627 for (count /= 2; count--; ) {
631 256*(int)(src[2])) / 2;
633 *dest++ = (unsigned char)((i / 256) & 0xFF);
634 *dest++ = (unsigned char)(i & 0xFF); }
639 /* Convert 16 bit little endian signed data to 8 bit unsigned data */
640 static size_t sndcnv2byteLE(void **data,size_t *sz,void **outbuf)
642 REGISTER unsigned char *src;
643 REGISTER unsigned char *dest;
647 if (count > SNDBUFSZ) { *sz -= 2*SNDBUFSZ; count = SNDBUFSZ; }
650 src = (unsigned char *) *data;
652 dest = linuxplay_sndbuf;
654 *dest++ = (unsigned char)(((signed char *)src)[1] ^ (signed char)0x80);
661 /* Convert 16 bit big endian signed data to 8 bit unsigned data */
662 static size_t sndcnv2byteBE(void **data,size_t *sz,void **outbuf)
664 REGISTER unsigned char *src;
665 REGISTER unsigned char *dest;
669 if (count > SNDBUFSZ) { *sz -= 2*SNDBUFSZ; count = SNDBUFSZ; }
672 src = (unsigned char *) *data;
674 dest = linuxplay_sndbuf;
676 *dest++ = (unsigned char)(((signed char *)src)[0] ^ (signed char)0x80);
683 /* Convert 16 bit little endian signed stereo data to 8 bit unsigned
685 static size_t sndcnv2monobyteLE(void **data,size_t *sz,void **outbuf)
687 REGISTER unsigned char *src;
688 REGISTER unsigned char *dest;
692 if (count > SNDBUFSZ) { *sz -= 4*SNDBUFSZ; count = SNDBUFSZ; }
695 src = (unsigned char *) *data;
697 dest = linuxplay_sndbuf;
699 *dest++ = (unsigned char)(((int)((signed char *)src)[1] +
700 (int)((signed char *)src)[3]) / 2 ^ 0x80);
707 /* Convert 16 bit big endian signed stereo data to 8 bit unsigned
709 static size_t sndcnv2monobyteBE(void **data,size_t *sz,void **outbuf)
711 REGISTER unsigned char *src;
712 REGISTER unsigned char *dest;
716 if (count > SNDBUFSZ) { *sz -= 4*SNDBUFSZ; count = SNDBUFSZ; }
719 src = (unsigned char *) *data;
721 dest = linuxplay_sndbuf;
723 *dest++ = (unsigned char)(((int)((signed char *)src)[0] +
724 (int)((signed char *)src)[2]) / 2 ^ 0x80);
731 /* Look at the header of the sound file and try to determine the format;
732 we can recognize files in VOC, WAVE, and, Sun/DEC-audio format--- everything
733 else is assumed to be raw 8 bit unsigned data sampled at 8kHz */
734 static fmtType analyze_format(unsigned char *format,int *fmt,int *speed,
736 size_t (**parsesndfile)(void **,size_t *sz,
739 /* Keep compatibility with Linux 68k, etc. by not relying on byte-sex */
740 if (!memcmp(format,"Creative Voice File\x1A\x1A\x00",22) &&
741 (format[22]+256*format[23]) ==
742 ((0x1233-format[24]-256*format[25])&0xFFFF)) { /* VOC */
746 *parsesndfile = parsevoc;
748 else if (!memcmp(format,"RIFF",4) &&
749 !memcmp(format+8,"WAVEfmt ",8)) { /* WAVE */
750 if (memcmp(format+20,"\001\000\001"/* PCM mono */,4) &&
751 memcmp(format+20,"\001\000\002"/* PCM stereo */,4))
753 *fmt = (format[32]/(*tracks = format[22])) == 1 ?
754 AFMT_U8 : AFMT_S16_LE;
755 /* Keep compatibility with Linux 68k, etc. by not relying on byte-sex */
756 *speed = format[24]+256*(format[25]+256*
757 (format[26]+256*format[27]));
758 *parsesndfile = parsewave;
760 else if (!memcmp(format,".snd",4)) { /* Sun Audio (big endian) */
761 if (format[7]+256*(format[6]+256*(format[5]+256*format[4])) < 24) {
765 *parsesndfile = parsesundecaudio;
766 return(fmtSunAudio); }
767 if (!memcmp(format+12,"\000\000\000\001",4)) *fmt = AFMT_MU_LAW;
768 else if (!memcmp(format+12,"\000\000\000\002",4)) *fmt = AFMT_S8;
769 else if (!memcmp(format+12,"\000\000\000\003",4)) *fmt = AFMT_S16_BE;
770 else return(fmtIllegal);
771 /* Keep compatibility with Linux 68k, etc. by not relying on byte-sex */
772 *speed = format[19]+256*(format[18]+256*
773 (format[17]+256*format[16]));
774 *tracks = format[23];
775 *parsesndfile = parsesundecaudio;
776 return(fmtSunAudio); }
777 else if (!memcmp(format,".sd",4)) { /* DEC Audio (little endian) */
778 if (format[4]+256*(format[5]+256*(format[6]+256*format[7])) < 24) {
782 *parsesndfile = parsesundecaudio;
783 return(fmtSunAudio); }
784 if (!memcmp(format+12,"\001\000\000",4)) *fmt = AFMT_MU_LAW;
785 else if (!memcmp(format+12,"\002\000\000",4)) *fmt = AFMT_S8;
786 else if (!memcmp(format+12,"\003\000\000",4)) *fmt = AFMT_S16_LE;
787 else return(fmtIllegal);
788 /* Keep compatibility with Linux 68k, etc. by not relying on byte-sex */
789 *speed = format[16]+256*(format[17]+256*
790 (format[18]+256*format[19]));
791 *tracks = format[20];
792 *parsesndfile = parsesundecaudio;
793 return(fmtSunAudio); }
798 *parsesndfile = parseraw;
802 /* Initialize the soundcard and mixer device with the parameters that we
803 found in the header of the sound file. If the soundcard is not capable of
804 natively supporting the required parameters, then try to set up conversion
806 The difficulty with setting up the sound card is that the parameters are
807 not fully orthogonal; changing one of them might affect some of the
808 others, too. Thus we do quite a lot of double checking; actually most of
809 this is not needed right now, but it will come in handy, if the kernel's
810 sounddriver ever changes or if third-party sounddrivers are used. */
811 static int audio_init(int mixx_fd, int auddio_fd, int fmt, int speed,
812 int tracks, int *volume,
813 size_t (**sndcnv) (void **, size_t *sz, void **))
815 int i,the_speed,the_stereo,the_fmt;
819 if (ioctl(auddio_fd,SNDCTL_DSP_SYNC,NULL) < 0) {
820 perror("SNDCTL_DSP_SYNC");
823 /* Initialize sound hardware with preferred parameters */
825 /* If the sound hardware cannot support 16 bit format or requires a
826 different byte sex then try to drop to 8 bit format */
829 if(ioctl(audio_fd,SNDCTL_DSP_SETFMT,&the_fmt) < 0) {
830 perror("SNDCTL_DSP_SETFMT");
834 if (fmt != the_fmt) {
835 if (fmt == AFMT_S16_LE || fmt == AFMT_S16_BE) {
836 *sndcnv = fmt == AFMT_S16_BE ? sndcnv2byteBE : sndcnv2byteLE;
837 if (((i=fmt=AFMT_U8),ioctl(audio_fd,SNDCTL_DSP_SETFMT,&i)) < 0 ||
838 fmt != i || ioctl(audio_fd,SNDCTL_DSP_SETFMT,&the_fmt) < 0 ||
840 perror("SNDCTL_DSP_SETFMT");
842 else if (fmt == AFMT_MU_LAW && the_fmt == AFMT_U8 ) {
843 /* the kernel will convert for us */ }
845 perror("SNDCTL_DSP_SETFMT");
847 else if (fmt == AFMT_S8) {
848 *sndcnv = sndcnv2unsigned;
849 if (((i=fmt=AFMT_U8),ioctl(audio_fd,SNDCTL_DSP_SETFMT,&i)) < 0 ||
850 fmt != i || ioctl(audio_fd,SNDCTL_DSP_SETFMT,&the_fmt) < 0 ||
852 perror("SNDCTRL_DSP_SETFMT");
855 /* The PCSP driver does not support reading of the sampling rate via the
856 SOUND_PCM_READ_RATE ioctl; determine "the_speed" here */
857 the_speed = speed; ioctl(audio_fd,SNDCTL_DSP_SPEED,&the_speed);
858 /* The PCSP driver does not support reading of the mono/stereo flag, thus
859 we assume, that failure to change this mode means we are in mono mode */
860 if (((i = (the_stereo = tracks)-1),ioctl(audio_fd,SNDCTL_DSP_STEREO,&i)) < 0)
863 /* Try to request stereo playback (if needed); if this cannot be supported
864 by the hardware, then install conversion routines for mono playback */
866 /* This ioctl will fail if we use the PCSP driver; thus the value of
867 "the_stereo" is still unchanged */
868 ioctl(audio_fd,SOUND_PCM_READ_CHANNELS,&the_stereo);
869 if (tracks != the_stereo) {
872 *sndcnv = *sndcnv == sndcnv2byteLE ? sndcnv2monobyteLE :
873 *sndcnv == sndcnv2byteBE ? sndcnv2monobyteBE :
874 *sndcnv == sndcnv2unsigned ? sndcnv2monounsigned :
875 the_fmt == AFMT_S16_LE ? sndcnv16_2monoLE :
876 the_fmt == AFMT_S16_BE ? sndcnv16_2monoBE :
877 the_fmt == AFMT_S8 ? sndcnv8S_2mono :
878 the_fmt == AFMT_U8 ? sndcnv8U_2mono :
879 the_fmt == AFMT_MU_LAW ? sndcnvULaw_2mono : NULL;
880 if (*sndcnv == NULL) { /* this should not happen */
881 perror("SNDCTL_DSP_STEREO");
883 /* Switch to mono mode */
884 if (((i = 0),ioctl(audio_fd,SNDCTL_DSP_STEREO,&i)) < 0 || i) {
885 perror("SNDCTL_DSP_STEREO");
887 /* Now double check that everything is set as expected */
888 if (((i = AFMT_QUERY),ioctl(audio_fd,SNDCTL_DSP_SETFMT,&i)) < 0 ||
890 (((i=the_fmt),ioctl(audio_fd,SNDCTL_DSP_SETFMT,&i)) < 0 ||
892 ((i = AFMT_QUERY),ioctl(audio_fd,SNDCTL_DSP_SETFMT,&i)) < 0 ||
894 (ioctl(audio_fd,SOUND_PCM_READ_CHANNELS,&i) >= 0 &&
896 /* There was no way that we could set the soundcard to a meaningful
898 perror("SNDCTL_DSP_SETFMT and SNDCTL_DSP_STEREO");
901 /* Somebody set the soundcard to stereo even though we requested
902 mono; this should not happen... */
903 if (((i = the_stereo = tracks),ioctl(audio_fd,SNDCTL_DSP_STEREO,&i))<0 ||
905 perror("SNDCTL_DSP_STEREO");
907 if (((i = AFMT_QUERY),ioctl(audio_fd,SNDCTL_DSP_SETFMT,&i)) < 0 ||
909 perror("SNDCTL_DSP_SETFMT");
912 /* Fail if deviations from desired sampling frequency are too big */
914 /* This ioctl will fail if we use the PCSP driver; thus the value of
915 "the_speed" is still unchanged */
916 ioctl(audio_fd,SOUND_PCM_READ_RATE,&the_speed);
917 if (speed*14 < the_speed*10 || speed*6 > the_speed*10) {
919 sprintf(buffer,"SNDCTL_DSP_SPEED (req: %d, rtn: %d)",speed,the_speed);
923 /* Use the mixer device for setting the playback volume */
925 int vol = *volume & 0xFF;
926 if (ioctl(mixx_fd,SOUND_MIXER_READ_PCM,volume) < 0)
928 if (vol < 0) vol = 0; else if (vol > 100) vol = 100;
929 #ifdef NOVOLUMECTRLFORMULAW
930 if (fmt == AFMT_MU_LAW)
934 /* Do not signal an error, if volume control is unavailable! */
935 ioctl(mixx_fd,SOUND_MIXER_WRITE_PCM,&vol); }
937 #if defined(LINUXPLAYSTANDALONE) && 1
938 /* Debugging output is displayed only when compiled as stand-alone version */
940 the_fmt = AFMT_QUERY;
941 ioctl(audio_fd,SNDCTL_DSP_SETFMT,&the_fmt);
942 ioctl(auddio_fd,SOUND_PCM_READ_CHANNELS,&the_stereo);
943 ioctl(auddio_fd,SOUND_PCM_READ_RATE,&the_speed);
944 ioctl(mixx_fd,SOUND_MIXER_READ_PCM,&the_volume);
945 fprintf(stderr,"%s, %s, %dHz, L:%d/R:%d\n",
946 the_fmt == AFMT_MU_LAW ? "AFMT_MU_LAW" :
947 the_fmt == AFMT_A_LAW ? "AFMT_A_LAW" :
948 the_fmt == AFMT_IMA_ADPCM ? "AFMT_IMA_ADPCM" :
949 the_fmt == AFMT_U8 ? "AFMT_U8" :
950 the_fmt == AFMT_S16_LE ? "AFMT_S16_LE" :
951 the_fmt == AFMT_S16_BE ? "AFMT_S16_BE" :
952 the_fmt == AFMT_S8 ? "AFMT_S8" :
953 the_fmt == AFMT_U16_LE ? "AFMT_U16_LE" :
954 the_fmt == AFMT_U16_BE ? "AFMT_U16_BE" :
955 the_fmt == AFMT_MPEG ? "AFMT_MPEG" :
957 the_stereo == 2 ? "stereo" : "mono",
959 the_volume / 256, the_volume % 256); }
965 /* XEmacs requires code both for playback of pre-loaded data and for playback
966 from a soundfile; we use one function for both cases */
967 static void linux_play_data_or_file(int fd,unsigned char *data,
968 int length,int volume)
970 size_t (*parsesndfile)(void **dayta,size_t *sz,void **outbuf);
971 size_t (*sndcnv)(void **dayta,size_t *sz,void **);
973 int fmt,speed,tracks;
974 unsigned char *pptr,*optr,*cptr,*sptr;
975 int wrtn,rrtn,crtn,prtn;
977 /* We need to read at least the header information before we can start
979 if (!data || length < HEADERSZ) {
982 length = read(fd,linuxplay_sndbuf,SNDBUFSZ);
983 if (length < HEADERSZ)
985 data = linuxplay_sndbuf;
989 ffmt = analyze_format(data,&fmt,&speed,&tracks,&parsesndfile);
991 if (ffmt != fmtRaw && ffmt != fmtSunAudio && ffmt != fmtWave) {
992 warn("Unsupported file format (neither RAW, nor Sun/DECAudio, nor WAVE)");
995 /* The VoxWare-SDK discourages opening /dev/audio; opening /dev/dsp and
996 properly initializing it via ioctl() is preferred */
997 if ((audio_fd=open(audio_dev, O_WRONLY | O_NONBLOCK, 0)) < 0) {
999 if (mix_fd > 0 && mix_fd != audio_fd) { close(mix_fd); mix_fd = -1; }
1002 /* The VoxWare-SDK discourages direct manipulation of the mixer device as
1003 this could lead to problems, when multiple sound cards are installed */
1006 sighup_handler = signal(SIGHUP, sighandler);
1007 sigint_handler = signal(SIGINT, sighandler);
1009 if (!audio_init(mix_fd,audio_fd,fmt,speed,tracks,&volume,&sndcnv))
1013 /* Initialize global parser state information to zero */
1014 memset(&parsestate,0,sizeof(parsestate));
1016 /* Mainloop: read a block of data, parse its contents, perform all
1017 the necessary conversions and output it to the sound
1018 device; repeat until all data has been processed */
1021 for (pptr = data; (prtn = parsesndfile((void **)&pptr,(size_t *)&rrtn,
1022 (void **)&optr)) > 0; )
1023 for (cptr = optr; (crtn = sndcnv((void **)&cptr,(size_t *) &prtn,
1024 (void **)&sptr)) > 0; ) {
1026 if ((wrtn = write(audio_fd,sptr,crtn)) < 0) {
1027 perror("write"); goto END_OF_PLAY; }
1028 else if (wrtn) break;
1029 else if (ioctl(audio_fd,SNDCTL_DSP_SYNC,NULL) < 0) {
1030 perror("SNDCTL_DSP_SYNC"); goto END_OF_PLAY; } }
1033 sprintf(buf,"play: crtn = %d, wrtn = %d",crtn,wrtn);
1035 goto END_OF_PLAY; } }
1037 if ((rrtn = read(fd,linuxplay_sndbuf,SNDBUFSZ)) < 0) {
1038 perror("read"); goto END_OF_PLAY; } }
1043 /* Verify that we could fully parse the entire soundfile; this is needed
1044 only for files in WAVE format */
1045 if (ffmt == fmtWave && parsestate.wave.state != wvOutOfBlock &&
1046 parsestate.wave.state != wvFatal)
1047 warn("Unexpected end of WAVE file");
1050 /* Now cleanup all used resources */
1052 ioctl(audio_fd,SNDCTL_DSP_SYNC,NULL);
1053 ioctl(audio_fd,SNDCTL_DSP_RESET,NULL);
1055 signal(SIGHUP,sighup_handler);
1056 signal(SIGINT,sigint_handler);
1059 if (audio_vol >= 0) {
1060 ioctl(mix_fd,SOUND_MIXER_WRITE_PCM,&audio_vol);
1062 if (mix_fd != audio_fd)
1072 /* Call "linux_play_data_or_file" with the appropriate parameters for
1073 playing a soundfile */
1074 void play_sound_file (char *sound_file, int volume);
1075 void play_sound_file (char *sound_file, int volume)
1079 if ((fd=open(sound_file,O_RDONLY,0)) < 0) {
1082 linux_play_data_or_file(fd,NULL,0,volume);
1087 /* Call "linux_play_data_or_file" with the appropriate parameters for
1088 playing pre-loaded data */
1089 void play_sound_data (unsigned char *data, int length, int volume);
1090 void play_sound_data (unsigned char *data, int length, int volume)
1092 linux_play_data_or_file(-1,data,length,volume);