comparison src/linuxplay.c @ 0:376386a54a3c r19-14

Import from CVS: tag r19-14
author cvs
date Mon, 13 Aug 2007 08:45:50 +0200
parents
children 8fc7fe29b841
comparison
equal deleted inserted replaced
-1:000000000000 0:376386a54a3c
1 /* linuxplay.c - play a sound file on the speaker
2 **
3 ** Copyright (C) 1995,96 by Markus Gutschke (gutschk@math.uni-muenster.de)
4 ** This is version 1.3 of linuxplay.c
5 **
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
8 ** information.
9 **
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
15 ** implied warranty.
16 **
17 ** Changelog:
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.
44 */
45
46 /* Synched up with: Not in FSF. */
47
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 */
50
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
56 discretion */
57
58 #ifdef HAVE_CONFIG_H
59 #include <config.h>
60 #endif
61
62 #include <errno.h>
63 #include <fcntl.h>
64 #include <linux/soundcard.h>
65 #include <stdio.h>
66 #include <stdlib.h>
67 #include <string.h>
68 #include <sys/fcntl.h>
69 #include <sys/file.h>
70 #include <sys/ioctl.h>
71 #include <sys/signal.h>
72 #include <unistd.h>
73
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);
77 #else
78 #include "lisp.h"
79 #include "syssignal.h"
80 #define perror(str) message("audio: %s, %s ",str,strerror(errno))
81 #define warn(str) message("audio: %s ",GETTEXT(str))
82 #endif
83
84 #ifdef __GNUC__
85 #define UNUSED(x) ((void)(x))
86 #else
87 #define UNUSED(x)
88 #define __inline__
89 #endif
90
91 static __sighandler_t sighup_handler;
92 static __sighandler_t sigint_handler;
93
94 /* Maintain global variable for keeping parser state information; this struct
95 is set to zero before the first invocation of the parser. The use of a
96 global variable prevents multiple concurrent executions of this code, but
97 this does not happen anyways... */
98 static union {
99 struct {
100 int align;
101 enum {wvMain,wvSubchunk,wvOutOfBlock,wvSkipChunk,
102 wvSoundChunk,wvFatal,wvFatalNotify} state;
103 size_t left;
104 unsigned char leftover[HEADERSZ];
105 signed long chunklength;
106 } wave;
107 struct {
108 int align;
109 int isdata;
110 int skipping;
111 size_t left;
112 unsigned char leftover[HEADERSZ];
113 } audio;
114 } parsestate;
115
116 /* Use a global buffer as scratch-pad for possible conversions of the
117 sampling format */
118 static unsigned char sndbuf[SNDBUFSZ];
119
120 static int mix_fd = -1;
121 static int audio_vol = -1;
122 static int audio_fd = -1;
123 static char *audio_dev = "";
124
125 typedef enum {fmtIllegal,fmtRaw,fmtVoc,fmtWave,fmtSunAudio} fmtType;
126
127 /* Intercept SIGINT and SIGHUP in order to close the audio and mixer
128 devices before terminating sound output; this requires reliable
129 signals as provided by "syssignal.h" */
130 static void sighandler(int sig)
131 {
132 if (mix_fd > 0) {
133 if (audio_vol >= 0) {
134 ioctl(mix_fd,SOUND_MIXER_WRITE_PCM,&audio_vol);
135 audio_vol = -1; }
136 if (mix_fd != audio_fd)
137 close(mix_fd);
138 mix_fd = -1; }
139 if (audio_fd > 0) {
140 ioctl(audio_fd,SNDCTL_DSP_SYNC,NULL);
141 ioctl(audio_fd,SNDCTL_DSP_RESET,NULL);
142 close(audio_fd);
143 audio_fd = -1; }
144 if (sig == SIGHUP && sighup_handler) sighup_handler(sig);
145 else if (sig == SIGINT && sigint_handler) sigint_handler(sig);
146 else exit(1);
147 }
148
149 /* There is no special treatment required for parsing raw data files; we
150 assume that these files contain data in 8bit unsigned format that
151 has been sampled at 8kHz; there is no extra header */
152 static size_t parseraw(void **data,size_t *sz,void **outbuf)
153 {
154 int rc = *sz;
155
156 *outbuf = *data;
157 *sz = 0;
158 return(rc);
159 }
160
161 /* Currently we cannot cope with files in VOC format; if you really need
162 to play these files, they should be converted by using SOX */
163 static size_t parsevoc(void **data,size_t *sz,void **outbuf)
164 {
165 UNUSED(data);
166 UNUSED(sz);
167 UNUSED(outbuf);
168 return(0);
169 }
170
171 /* We need to perform some look-ahead in order to parse files in WAVE format;
172 this might require re-partioning of the data segments if headers cross the
173 boundaries between two read operations. This is done in a two-step way:
174 first we request a certain amount of bytes... */
175 static __inline__ int waverequire(void **data,size_t *sz,size_t rq)
176 {
177 int rc = 1;
178
179 if (rq > HEADERSZ) {
180 warn("Header size exceeded while parsing WAVE file");
181 parsestate.wave.state = wvFatal;
182 *sz = 0;
183 return(0); }
184 if ((rq -= parsestate.wave.left) <= 0)
185 return(rc);
186 if (rq > *sz) {rq = *sz; rc = 0;}
187 memcpy(parsestate.wave.leftover+parsestate.wave.left,
188 *data,rq);
189 parsestate.wave.left += rq;
190 ((unsigned char *)*data) += rq;
191 *sz -= rq;
192 return(rc);
193 }
194
195 /* ...and next we remove this many bytes from the buffer */
196 static __inline__ void waveremove(size_t rq)
197 {
198 if (parsestate.wave.left <= rq)
199 parsestate.wave.left = 0;
200 else {
201 parsestate.wave.left -= rq;
202 memmove(parsestate.wave.leftover,
203 parsestate.wave.leftover+rq,
204 parsestate.wave.left); }
205 return;
206 }
207
208 /* Sound files in WAVE format can contain an arbitrary amount of tagged
209 chunks; this requires quite some effort for parsing the data */
210 static size_t parsewave(void **data,size_t *sz,void **outbuf)
211 {
212 for (;;)
213 switch (parsestate.wave.state) {
214 case wvMain:
215 if (!waverequire(data,sz,20))
216 return(0);
217 /* Keep compatibility with Linux 68k, etc. by not relying on byte-sex */
218 parsestate.wave.chunklength = parsestate.wave.leftover[16] +
219 256*(parsestate.wave.leftover[17] +
220 256*(parsestate.wave.leftover[18] +
221 256*parsestate.wave.leftover[19]));
222 waveremove(20);
223 parsestate.wave.state = wvSubchunk;
224 break;
225 case wvSubchunk:
226 if (!waverequire(data,sz,parsestate.wave.chunklength))
227 return(0);
228 parsestate.wave.align = parsestate.wave.chunklength < 14 ? 1
229 : parsestate.wave.leftover[12];
230 if (parsestate.wave.align != 1 &&
231 parsestate.wave.align != 2 &&
232 parsestate.wave.align != 4) {
233 warn("Illegal datawidth detected while parsing WAVE file");
234 parsestate.wave.state = wvFatal; }
235 else
236 parsestate.wave.state = wvOutOfBlock;
237 waveremove(parsestate.wave.chunklength);
238 break;
239 case wvOutOfBlock:
240 if (!waverequire(data,sz,8))
241 return(0);
242 /* Keep compatibility with Linux 68k, etc. by not relying on byte-sex */
243 parsestate.wave.chunklength = parsestate.wave.leftover[4] +
244 256*(parsestate.wave.leftover[5] +
245 256*(parsestate.wave.leftover[6] +
246 256*(parsestate.wave.leftover[7] & 0x7F)));
247 if (memcmp(parsestate.wave.leftover,"data",4))
248 parsestate.wave.state = wvSkipChunk;
249 else
250 parsestate.wave.state = wvSoundChunk;
251 waveremove(8);
252 break;
253 case wvSkipChunk:
254 if (parsestate.wave.chunklength > 0 && *sz > 0 &&
255 (signed long)*sz < (signed long)parsestate.wave.chunklength) {
256 parsestate.wave.chunklength -= *sz;
257 *sz = 0; }
258 else {
259 if (parsestate.wave.chunklength > 0 && *sz > 0) {
260 *sz -= parsestate.wave.chunklength;
261 ((unsigned char *)*data) += parsestate.wave.chunklength; }
262 parsestate.wave.state = wvOutOfBlock; }
263 break;
264 case wvSoundChunk: {
265 size_t count,rq;
266 if (parsestate.wave.left) { /* handle leftover bytes from last
267 alignment operation */
268 count = parsestate.wave.left;
269 rq = HEADERSZ-count;
270 if (rq > parsestate.wave.chunklength)
271 rq = parsestate.wave.chunklength;
272 if (!waverequire(data,sz,rq)) {
273 parsestate.wave.chunklength -= parsestate.wave.left - count;
274 return(0); }
275 parsestate.wave.chunklength -= rq;
276 *outbuf = parsestate.wave.leftover;
277 parsestate.wave.left = 0;
278 return(rq); }
279 if (*sz >= parsestate.wave.chunklength) {
280 count = parsestate.wave.chunklength;
281 rq = 0; }
282 else {
283 count = *sz;
284 count -= rq = count % parsestate.wave.align; }
285 *outbuf = *data;
286 ((unsigned char *)*data) += count;
287 *sz -= count;
288 if ((parsestate.wave.chunklength -= count) < parsestate.wave.align) {
289 parsestate.wave.state = wvOutOfBlock;
290 /* Some broken software (e.g. SOX) attaches junk to the end of a sound
291 chunk; so, let's ignore this... */
292 if (parsestate.wave.chunklength)
293 parsestate.wave.state = wvSkipChunk; }
294 else if (rq)
295 /* align data length to a multiple of datasize; keep additional data
296 in "leftover" buffer --- this is neccessary to ensure proper
297 functioning of the sndcnv... routines */
298 waverequire(data,sz,rq);
299 return(count); }
300 case wvFatalNotify:
301 warn("Irrecoverable error while parsing WAVE file");
302 parsestate.wave.state = wvFatal;
303 break;
304 case wvFatal:
305 default:
306 *sz = 0;
307 return(0); }
308 }
309
310 /* Strip the header from files in Sun/DEC audio format; this requires some
311 extra processing as the header can be an arbitrary size and it might
312 result in alignment errors for subsequent conversions --- thus we do
313 some buffering, where needed */
314 static size_t parsesundecaudio(void **data,size_t *sz,void **outbuf)
315 {
316 /* There is data left over from the last invocation of this function; join
317 it with the new data and return a sound chunk that is as big as a
318 single entry */
319 if (parsestate.audio.left) {
320 if (parsestate.audio.left + *sz > parsestate.audio.align) {
321 int count;
322 memmove(parsestate.audio.leftover + parsestate.audio.left,
323 *data,
324 count = parsestate.audio.align - parsestate.audio.left);
325 *outbuf = parsestate.audio.leftover;
326 *sz -= count;
327 *data = (*(char **)data) + count;
328 parsestate.audio.left = 0;
329 return(parsestate.audio.align); }
330 else {
331 /* We need even more data in order to get one complete single entry! */
332 memmove(parsestate.audio.leftover + parsestate.audio.left,
333 *data,
334 *sz);
335 *data = (*(char **)data) + *sz;
336 parsestate.audio.left += *sz;
337 *sz = 0;
338 return(0); } }
339
340 /* This is the main sound chunk, strip of any extra data that does not fit
341 the alignment requirements and move these bytes into the leftover buffer*/
342 if (parsestate.audio.isdata) {
343 int rc = *sz;
344 *outbuf = *data;
345 if ((parsestate.audio.left = rc % parsestate.audio.align) != 0) {
346 memmove(parsestate.audio.leftover,
347 (char *)*outbuf + rc - parsestate.audio.left,
348 parsestate.audio.left);
349 rc -= parsestate.audio.left; }
350 *sz = 0;
351 return(rc); }
352
353 /* This is the first invocation of this function; we need to parse the
354 header information and determine how many bytes we need to skip until
355 the start of the sound chunk */
356 if (!parsestate.audio.skipping) {
357 unsigned char *header = *data;
358 if (*sz < 8) {
359 warn("Irrecoverable error while parsing Sun/DEC audio file");
360 return(0); }
361 /* Keep compatibility with Linux 68k, etc. by not relying on byte-sex */
362 if (header[3]) { /* Sun audio (big endian) */
363 parsestate.audio.align = ((header[15] > 2)+1)*header[23];
364 parsestate.audio.skipping = header[7]+256*(header[6]+256*
365 (header[5]+256*header[4])); }
366 else { /* DEC audio (little endian) */
367 parsestate.audio.align = ((header[12] > 2)+1)*header[20];
368 parsestate.audio.skipping = header[4]+256*(header[5]+256*
369 (header[6]+256*header[7])); }}
370
371 /* We are skipping extra data that has been attached to header; most usually
372 this will be just a comment, such as the original filename and/or the
373 creation date. Make sure that we do not return less than one single sound
374 sample entry to the caller; if this happens, rather decide to move those
375 few bytes into the leftover buffer and deal with it later */
376 if (*sz >= parsestate.audio.skipping) {
377 /* Skip just the header information and return the sound chunk */
378 int rc = *sz - parsestate.audio.skipping;
379 *outbuf = (char *)*data + parsestate.audio.skipping;
380 if ((parsestate.audio.left = rc % parsestate.audio.align) != 0) {
381 memmove(parsestate.audio.leftover,
382 (char *)*outbuf + rc - parsestate.audio.left,
383 parsestate.audio.left);
384 rc -= parsestate.audio.left; }
385 *sz = 0;
386 parsestate.audio.skipping = 0;
387 parsestate.audio.isdata++;
388 return(rc); }
389 else {
390 /* Skip everything */
391 parsestate.audio.skipping -= *sz;
392 return(0); }
393 }
394
395 /* If the soundcard could not be set to natively support the data format, we
396 try to do some limited on-the-fly conversion to a different format; if
397 no conversion is needed, though, we can output directly */
398 static size_t sndcnvnop(void **data,size_t *sz,void **outbuf)
399 {
400 int rc = *sz;
401
402 *outbuf = *data;
403 *sz = 0;
404 return(rc);
405 }
406
407 /* Convert 8 bit unsigned stereo data to 8 bit unsigned mono data */
408 static size_t sndcnv8U_2mono(void **data,size_t *sz,void **outbuf)
409 {
410 register unsigned char *src;
411 register unsigned char *dest;
412 int rc,count;
413
414 count = *sz / 2;
415 if (count > SNDBUFSZ) { *sz -= 2*SNDBUFSZ; count = SNDBUFSZ; }
416 else *sz = 0;
417 rc = count;
418 src = *data;
419 *outbuf =
420 dest = sndbuf;
421 while (count--)
422 *dest++ = (unsigned char)(((int)*((unsigned char *)src)++ +
423 (int)*((unsigned char *)src)++) / 2);
424 *data = src;
425 return(rc);
426 }
427
428 /* Convert 8 bit signed stereo data to 8 bit signed mono data */
429 static size_t sndcnv8S_2mono(void **data,size_t *sz,void **outbuf)
430 {
431 register unsigned char *src;
432 register unsigned char *dest;
433 int rc,count;
434
435 count = *sz / 2;
436 if (count > SNDBUFSZ) { *sz -= 2*SNDBUFSZ; count = SNDBUFSZ; }
437 else *sz = 0;
438 rc = count;
439 src = *data;
440 *outbuf =
441 dest = sndbuf;
442 while (count--)
443 *dest++ = (unsigned char)(((int)*((signed char *)src)++ +
444 (int)*((signed char *)src)++) / 2);
445 *data = src;
446 return(rc);
447 }
448
449 /* Convert 8 bit signed stereo data to 8 bit unsigned mono data */
450 static size_t sndcnv2monounsigned(void **data,size_t *sz,void **outbuf)
451 {
452 register unsigned char *src;
453 register unsigned char *dest;
454 int rc,count;
455
456 count = *sz / 2;
457 if (count > SNDBUFSZ) { *sz -= 2*SNDBUFSZ; count = SNDBUFSZ; }
458 else *sz = 0;
459 rc = count;
460 src = *data;
461 *outbuf =
462 dest = sndbuf;
463 while (count--)
464 *dest++ = (unsigned char)(((int)*((signed char *)src)++ +
465 (int)*((signed char *)src)++) / 2) ^ 0x80;
466 *data = src;
467 return(rc);
468 }
469
470 /* Convert 8 bit signed mono data to 8 bit unsigned mono data */
471 static size_t sndcnv2unsigned(void **data,size_t *sz,void **outbuf)
472 {
473 register unsigned char *src;
474 register unsigned char *dest;
475 int rc,count;
476
477 count = *sz;
478 if (count > SNDBUFSZ) { *sz -= SNDBUFSZ; count = SNDBUFSZ; }
479 else *sz = 0;
480 rc = count;
481 src = *data;
482 *outbuf =
483 dest = sndbuf;
484 while (count--)
485 *dest++ = *((unsigned char *)src)++ ^ 0x80;
486 *data = src;
487 return(rc);
488 }
489
490 /* Convert a number in the range -32768..32767 to an 8 bit ulaw encoded
491 number --- I hope, I got this conversion right :-) */
492 static __inline__ signed char int2ulaw(int i)
493 {
494 /* Lookup table for fast calculation of number of bits that need shifting*/
495 static short int t_bits[128] = {
496 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,
497 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,
498 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,
499 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};
500 register int bits,logi;
501
502 /* unrolling this condition (hopefully) improves execution speed */
503 if (i < 0) {
504 if ((i = (132-i)) > 0x7FFF) 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) i = 0x7FFF;
509 logi = (i >> ((bits = t_bits[i/256])+4));
510 return(~(bits << 4 | logi)); }
511 }
512
513 /* Convert 8 bit ulaw stereo data to 8 bit ulaw mono data */
514 static size_t sndcnvULaw_2mono(void **data,size_t *sz,void **outbuf)
515 {
516
517 static short int ulaw2int[256] = {
518 /* Precomputed lookup table for conversion from ulaw to 15 bit signed */
519 -16062,-15550,-15038,-14526,-14014,-13502,-12990,-12478,
520 -11966,-11454,-10942,-10430, -9918, -9406, -8894, -8382,
521 -7998, -7742, -7486, -7230, -6974, -6718, -6462, -6206,
522 -5950, -5694, -5438, -5182, -4926, -4670, -4414, -4158,
523 -3966, -3838, -3710, -3582, -3454, -3326, -3198, -3070,
524 -2942, -2814, -2686, -2558, -2430, -2302, -2174, -2046,
525 -1950, -1886, -1822, -1758, -1694, -1630, -1566, -1502,
526 -1438, -1374, -1310, -1246, -1182, -1118, -1054, -990,
527 -942, -910, -878, -846, -814, -782, -750, -718,
528 -686, -654, -622, -590, -558, -526, -494, -462,
529 -438, -422, -406, -390, -374, -358, -342, -326,
530 -310, -294, -278, -262, -246, -230, -214, -198,
531 -186, -178, -170, -162, -154, -146, -138, -130,
532 -122, -114, -106, -98, -90, -82, -74, -66,
533 -60, -56, -52, -48, -44, -40, -36, -32,
534 -28, -24, -20, -16, -12, -8, -4, +0,
535 +16062,+15550,+15038,+14526,+14014,+13502,+12990,+12478,
536 +11966,+11454,+10942,+10430, +9918, +9406, +8894, +8382,
537 +7998, +7742, +7486, +7230, +6974, +6718, +6462, +6206,
538 +5950, +5694, +5438, +5182, +4926, +4670, +4414, +4158,
539 +3966, +3838, +3710, +3582, +3454, +3326, +3198, +3070,
540 +2942, +2814, +2686, +2558, +2430, +2302, +2174, +2046,
541 +1950, +1886, +1822, +1758, +1694, +1630, +1566, +1502,
542 +1438, +1374, +1310, +1246, +1182, +1118, +1054, +990,
543 +942, +910, +878, +846, +814, +782, +750, +718,
544 +686, +654, +622, +590, +558, +526, +494, +462,
545 +438, +422, +406, +390, +374, +358, +342, +326,
546 +310, +294, +278, +262, +246, +230, +214, +198,
547 +186, +178, +170, +162, +154, +146, +138, +130,
548 +122, +114, +106, +98, +90, +82, +74, +66,
549 +60, +56, +52, +48, +44, +40, +36, +32,
550 +28, +24, +20, +16, +12, +8, +4, +0};
551
552 register unsigned char *src;
553 register unsigned char *dest;
554 int rc,count;
555
556 count = *sz / 2;
557 if (count > SNDBUFSZ) { *sz -= 2*SNDBUFSZ; count = SNDBUFSZ; }
558 else *sz = 0;
559 rc = count;
560 src = *data;
561 *outbuf =
562 dest = sndbuf;
563 while (count--)
564 /* it is not possible to directly interpolate between two ulaw encoded
565 data bytes, thus we need to convert to linear format first and later
566 we convert back to ulaw format */
567 *dest++ = int2ulaw(ulaw2int[*((unsigned char *)src)++] +
568 ulaw2int[*((unsigned char *)src)++]);
569 *data = src;
570 return(rc);
571 }
572
573 /* Convert 16 bit little endian signed stereo data to 16 bit little endian
574 signed mono data */
575 static size_t sndcnv16_2monoLE(void **data,size_t *sz,void **outbuf)
576 {
577 register unsigned char *src;
578 register unsigned char *dest;
579 int rc,count;
580 signed short i;
581
582 count = *sz / 2;
583 if (count > SNDBUFSZ) { *sz -= 2*SNDBUFSZ; count = SNDBUFSZ; }
584 else *sz = 0;
585 rc = count;
586 src = *data;
587 *outbuf =
588 dest = sndbuf;
589 for (count /= 2; count--; ) {
590 i = ((int)(((unsigned char *)src)[0]) +
591 256*(int)(((unsigned char *)src)[1]) +
592 (int)(((unsigned char *)src)[2]) +
593 256*(int)(((unsigned char *)src)[3])) / 2;
594 src += 4;
595 *dest++ = (unsigned char)(i & 0xFF);
596 *dest++ = (unsigned char)((i / 256) & 0xFF); }
597 *data = src;
598 return(rc);
599 }
600
601 /* Convert 16 bit big endian signed stereo data to 16 bit big endian
602 signed mono data */
603 static size_t sndcnv16_2monoBE(void **data,size_t *sz,void **outbuf)
604 {
605 register unsigned char *src;
606 register unsigned char *dest;
607 int rc,count;
608 signed short i;
609
610 count = *sz / 2;
611 if (count > SNDBUFSZ) { *sz -= 2*SNDBUFSZ; count = SNDBUFSZ; }
612 else *sz = 0;
613 rc = count;
614 src = *data;
615 *outbuf =
616 dest = sndbuf;
617 for (count /= 2; count--; ) {
618 i = ((int)(((unsigned char *)src)[1]) +
619 256*(int)(((unsigned char *)src)[0]) +
620 (int)(((unsigned char *)src)[3]) +
621 256*(int)(((unsigned char *)src)[2])) / 2;
622 src += 4;
623 *dest++ = (unsigned char)((i / 256) & 0xFF);
624 *dest++ = (unsigned char)(i & 0xFF); }
625 *data = src;
626 return(rc);
627 }
628
629 /* Convert 16 bit little endian signed data to 8 bit unsigned data */
630 static size_t sndcnv2byteLE(void **data,size_t *sz,void **outbuf)
631 {
632 register unsigned char *src;
633 register unsigned char *dest;
634 int rc,count;
635
636 count = *sz / 2;
637 if (count > SNDBUFSZ) { *sz -= 2*SNDBUFSZ; count = SNDBUFSZ; }
638 else *sz = 0;
639 rc = count;
640 src = *data;
641 *outbuf =
642 dest = sndbuf;
643 while (count--) {
644 *dest++ = (unsigned char)(((signed char *)src)[1] ^ (signed char)0x80);
645 ((char *)src) += 2; }
646 *data = src;
647 return(rc);
648 }
649
650 /* Convert 16 bit big endian signed data to 8 bit unsigned data */
651 static size_t sndcnv2byteBE(void **data,size_t *sz,void **outbuf)
652 {
653 register unsigned char *src;
654 register unsigned char *dest;
655 int rc,count;
656
657 count = *sz / 2;
658 if (count > SNDBUFSZ) { *sz -= 2*SNDBUFSZ; count = SNDBUFSZ; }
659 else *sz = 0;
660 rc = count;
661 src = *data;
662 *outbuf =
663 dest = sndbuf;
664 while (count--) {
665 *dest++ = (unsigned char)(((signed char *)src)[0] ^ (signed char)0x80);
666 ((char *)src) += 2; }
667 *data = src;
668 return(rc);
669 }
670
671 /* Convert 16 bit little endian signed stereo data to 8 bit unsigned
672 mono data */
673 static size_t sndcnv2monobyteLE(void **data,size_t *sz,void **outbuf)
674 {
675 register unsigned char *src;
676 register unsigned char *dest;
677 int rc,count;
678
679 count = *sz / 4;
680 if (count > SNDBUFSZ) { *sz -= 4*SNDBUFSZ; count = SNDBUFSZ; }
681 else *sz = 0;
682 rc = count;
683 src = *data;
684 *outbuf =
685 dest = sndbuf;
686 while (count--) {
687 *dest++ = (unsigned char)(((int)((signed char *)src)[1] +
688 (int)((signed char *)src)[3]) / 2 ^ 0x80);
689 ((char *)src) += 4; }
690 *data = src;
691 return(rc);
692 }
693
694 /* Convert 16 bit big endian signed stereo data to 8 bit unsigned
695 mono data */
696 static size_t sndcnv2monobyteBE(void **data,size_t *sz,void **outbuf)
697 {
698 register unsigned char *src;
699 register unsigned char *dest;
700 int rc,count;
701
702 count = *sz / 4;
703 if (count > SNDBUFSZ) { *sz -= 4*SNDBUFSZ; count = SNDBUFSZ; }
704 else *sz = 0;
705 rc = count;
706 src = *data;
707 *outbuf =
708 dest = sndbuf;
709 while (count--) {
710 *dest++ = (unsigned char)(((int)((signed char *)src)[0] +
711 (int)((signed char *)src)[2]) / 2 ^ 0x80);
712 ((char *)src) += 4; }
713 *data = src;
714 return(rc);
715 }
716
717 /* Look at the header of the sound file and try to determine the format;
718 we can recognize files in VOC, WAVE, and, Sun/DEC-audio format--- everything
719 else is assumed to be raw 8 bit unsigned data sampled at 8kHz */
720 static fmtType analyze_format(unsigned char *format,int *fmt,int *speed,
721 int *tracks,
722 size_t (**parsesndfile)(void **,size_t *sz,
723 void **))
724 {
725 /* Keep compatibility with Linux 68k, etc. by not relying on byte-sex */
726 if (!memcmp(format,"Creative Voice File\x1A\x1A\x00",22) &&
727 (format[22]+256*format[23]) ==
728 ((0x1233-format[24]-256*format[25])&0xFFFF)) { /* VOC */
729 *fmt = AFMT_U8;
730 *speed = 8000;
731 *tracks = 2;
732 *parsesndfile = parsevoc;
733 return(fmtVoc); }
734 else if (!memcmp(format,"RIFF",4) &&
735 !memcmp(format+8,"WAVEfmt ",8)) { /* WAVE */
736 if (memcmp(format+20,"\001\000\001"/* PCM mono */,4) &&
737 memcmp(format+20,"\001\000\002"/* PCM stereo */,4))
738 return(fmtIllegal);
739 *fmt = (format[32]/(*tracks = format[22])) == 1 ?
740 AFMT_U8 : AFMT_S16_LE;
741 /* Keep compatibility with Linux 68k, etc. by not relying on byte-sex */
742 *speed = format[24]+256*(format[25]+256*
743 (format[26]+256*format[27]));
744 *parsesndfile = parsewave;
745 return(fmtWave); }
746 else if (!memcmp(format,".snd",4)) { /* Sun Audio (big endian) */
747 if (format[7]+256*(format[6]+256*(format[5]+256*format[4])) < 24) {
748 *fmt = AFMT_MU_LAW;
749 *speed = 8000;
750 *tracks = 1;
751 *parsesndfile = parsesundecaudio;
752 return(fmtSunAudio); }
753 if (!memcmp(format+12,"\000\000\000\001",4)) *fmt = AFMT_MU_LAW;
754 else if (!memcmp(format+12,"\000\000\000\002",4)) *fmt = AFMT_S8;
755 else if (!memcmp(format+12,"\000\000\000\003",4)) *fmt = AFMT_S16_BE;
756 else return(fmtIllegal);
757 /* Keep compatibility with Linux 68k, etc. by not relying on byte-sex */
758 *speed = format[19]+256*(format[18]+256*
759 (format[17]+256*format[16]));
760 *tracks = format[23];
761 *parsesndfile = parsesundecaudio;
762 return(fmtSunAudio); }
763 else if (!memcmp(format,".sd",4)) { /* DEC Audio (little endian) */
764 if (format[4]+256*(format[5]+256*(format[6]+256*format[7])) < 24) {
765 *fmt = AFMT_MU_LAW;
766 *speed = 8000;
767 *tracks = 1;
768 *parsesndfile = parsesundecaudio;
769 return(fmtSunAudio); }
770 if (!memcmp(format+12,"\001\000\000",4)) *fmt = AFMT_MU_LAW;
771 else if (!memcmp(format+12,"\002\000\000",4)) *fmt = AFMT_S8;
772 else if (!memcmp(format+12,"\003\000\000",4)) *fmt = AFMT_S16_LE;
773 else return(fmtIllegal);
774 /* Keep compatibility with Linux 68k, etc. by not relying on byte-sex */
775 *speed = format[16]+256*(format[17]+256*
776 (format[18]+256*format[19]));
777 *tracks = format[20];
778 *parsesndfile = parsesundecaudio;
779 return(fmtSunAudio); }
780 else {
781 *fmt = AFMT_U8;
782 *speed = 8000;
783 *tracks = 1;
784 *parsesndfile = parseraw;
785 return(fmtRaw); }
786 }
787
788 /* Initialize the soundcard and mixer device with the parameters that we
789 found in the header of the sound file. If the soundcard is not capable of
790 natively supporting the required parameters, then try to set up conversion
791 routines.
792 The difficulty with setting up the sound card is that the parameters are
793 not fully orthogonal; changing one of them might affect some of the
794 others, too. Thus we do quite a lot of double checking; actually most of
795 this is not needed right now, but it will come in handy, if the kernel's
796 sounddriver ever changes or if third-party sounddrivers are used. */
797 static int audio_init(int mixx_fd, int auddio_fd, int fmt, int speed,
798 int tracks, int *volume,
799 size_t (**sndcnv) (void **, size_t *sz, void **))
800 {
801 int i,the_speed,the_stereo,the_fmt;
802
803 *sndcnv = sndcnvnop;
804
805 if (ioctl(auddio_fd,SNDCTL_DSP_SYNC,NULL) < 0) {
806 perror("SNDCTL_DSP_SYNC");
807 return(0); }
808
809 /* Initialize sound hardware with prefered parameters */
810
811 /* The PCSP driver does not support reading of the sampling rate via the
812 SOUND_PCM_READ_RATE ioctl; determine "the_speed" here */
813 the_speed = speed; ioctl(audio_fd,SNDCTL_DSP_SPEED,&the_speed);
814 /* The PCSP driver does not support reading of the mono/stereo flag, thus
815 we assume, that failure to change this mode means we are in mono mode */
816 if (((i = (the_stereo = tracks)-1),ioctl(audio_fd,SNDCTL_DSP_STEREO,&i)) < 0)
817 the_stereo = 1;
818 the_fmt = fmt; ioctl(audio_fd,SNDCTL_DSP_SETFMT,&the_fmt);
819
820 /* If the sound hardware cannot support 16 bit format or requires a
821 different byte sex then try to drop to 8 bit format */
822 the_fmt = AFMT_QUERY; ioctl(audio_fd,SNDCTL_DSP_SETFMT,&the_fmt);
823 if (fmt != the_fmt) {
824 if (fmt == AFMT_S16_LE || fmt == AFMT_S16_BE) {
825 *sndcnv = fmt == AFMT_S16_BE ? sndcnv2byteBE : sndcnv2byteLE;
826 if (((i=fmt=AFMT_U8),ioctl(audio_fd,SNDCTL_DSP_SETFMT,&i)) < 0 ||
827 fmt != i || ioctl(audio_fd,SNDCTL_DSP_SETFMT,&the_fmt) < 0 ||
828 fmt != the_fmt) {
829 perror("SNDCTL_DSP_SETFMT");
830 return(0); } }
831 else {
832 perror("SNDCTL_DSP_SETFMT");
833 return(0); } }
834 else if (fmt == AFMT_S8) {
835 *sndcnv = sndcnv2unsigned;
836 if (((i=fmt=AFMT_U8),ioctl(audio_fd,SNDCTL_DSP_SETFMT,&i)) < 0 ||
837 fmt != i || ioctl(audio_fd,SNDCTL_DSP_SETFMT,&the_fmt) < 0 ||
838 fmt != the_fmt) {
839 perror("SNDCTRL_DSP_SETFMT");
840 return(0); } }
841
842 /* Try to request stereo playback (if needed); if this cannot be supported
843 by the hardware, then install conversion routines for mono playback */
844
845 /* This ioctl will fail if we use the PCSP driver; thus the value of
846 "the_stereo" is still unchanged */
847 ioctl(audio_fd,SOUND_PCM_READ_CHANNELS,&the_stereo);
848 if (tracks != the_stereo) {
849 if (tracks == 2) {
850 tracks = 1;
851 *sndcnv = *sndcnv == sndcnv2byteLE ? sndcnv2monobyteLE :
852 *sndcnv == sndcnv2byteBE ? sndcnv2monobyteBE :
853 *sndcnv == sndcnv2unsigned ? sndcnv2monounsigned :
854 the_fmt == AFMT_S16_LE ? sndcnv16_2monoLE :
855 the_fmt == AFMT_S16_BE ? sndcnv16_2monoBE :
856 the_fmt == AFMT_S8 ? sndcnv8S_2mono :
857 the_fmt == AFMT_U8 ? sndcnv8U_2mono :
858 the_fmt == AFMT_MU_LAW ? sndcnvULaw_2mono : NULL;
859 if (*sndcnv == NULL) { /* this should not happen */
860 perror("SNDCTL_DSP_STEREO");
861 return(0); }
862 /* Switch to mono mode */
863 if (((i = 0),ioctl(audio_fd,SNDCTL_DSP_STEREO,&i)) < 0 || i) {
864 perror("SNDCTL_DSP_STEREO");
865 return(0); }
866 /* Now double check that everything is set as expected */
867 if (((i = AFMT_QUERY),ioctl(audio_fd,SNDCTL_DSP_SETFMT,&i)) < 0 ||
868 (i != the_fmt &&
869 (((i=the_fmt),ioctl(audio_fd,SNDCTL_DSP_SETFMT,&i)) < 0 ||
870 i != the_fmt ||
871 ((i = AFMT_QUERY),ioctl(audio_fd,SNDCTL_DSP_SETFMT,&i)) < 0 ||
872 i != the_fmt)) ||
873 (ioctl(audio_fd,SOUND_PCM_READ_CHANNELS,&i) >= 0 &&
874 i != 1)) {
875 /* There was no way that we could set the soundcard to a meaningful
876 mode */
877 perror("SNDCTL_DSP_SETFMT and SNDCTL_DSP_STEREO");
878 return(0); } }
879 else {
880 /* Somebody set the soundcard to stereo even though we requested
881 mono; this should not happen... */
882 if (((i = the_stereo = tracks),ioctl(audio_fd,SNDCTL_DSP_STEREO,&i))<0 ||
883 i != the_stereo-1) {
884 perror("SNDCTL_DSP_STEREO");
885 return(0); }
886 if (((i = AFMT_QUERY),ioctl(audio_fd,SNDCTL_DSP_SETFMT,&i)) < 0 ||
887 i != the_fmt) {
888 perror("SNDCTL_DSP_SETFMT");
889 return(0); } } }
890
891 /* Fail if deviations from desired sampling frequency are too big */
892
893 /* This ioctl will fail if we use the PCSP driver; thus the value of
894 "the_speed" is still unchanged */
895 ioctl(audio_fd,SOUND_PCM_READ_RATE,&the_speed);
896 if (speed*14 < the_speed*10 || speed*6 > the_speed*10) {
897 char buffer[256];
898 sprintf(buffer,"SNDCTL_DSP_SPEED (req: %d, rtn: %d)",speed,the_speed);
899 perror(buffer);
900 return(0); }
901
902 /* Use the mixer device for setting the playback volume */
903 if (mixx_fd > 0) {
904 int vol = *volume & 0xFF;
905 if (ioctl(mixx_fd,SOUND_MIXER_READ_PCM,volume) < 0)
906 *volume = -1;
907 if (vol < 0) vol = 0; else if (vol > 100) vol = 100;
908 #ifdef NOVOLUMECTRLFORMULAW
909 if (fmt == AFMT_MU_LAW)
910 vol = 100;
911 #endif
912 vol |= 256*vol;
913 /* Do not signal an error, if volume control is unavailable! */
914 ioctl(mixx_fd,SOUND_MIXER_WRITE_PCM,&vol); }
915
916 #if defined(LINUXPLAYSTANDALONE) && 1
917 /* Debugging output is displayed only when compiled as stand-alone version */
918 {int the_volume;
919 the_fmt = AFMT_QUERY;
920 ioctl(audio_fd,SNDCTL_DSP_SETFMT,&the_fmt);
921 ioctl(auddio_fd,SOUND_PCM_READ_CHANNELS,&the_stereo);
922 ioctl(auddio_fd,SOUND_PCM_READ_RATE,&the_speed);
923 ioctl(mixx_fd,SOUND_MIXER_READ_PCM,&the_volume);
924 fprintf(stderr,"%s, %s, %dHz, L:%d/R:%d\n",
925 the_fmt == AFMT_MU_LAW ? "AFMT_MU_LAW" :
926 the_fmt == AFMT_A_LAW ? "AFMT_A_LAW" :
927 the_fmt == AFMT_IMA_ADPCM ? "AFMT_IMA_ADPCM" :
928 the_fmt == AFMT_U8 ? "AFMT_U8" :
929 the_fmt == AFMT_S16_LE ? "AFMT_S16_LE" :
930 the_fmt == AFMT_S16_BE ? "AFMT_S16_BE" :
931 the_fmt == AFMT_S8 ? "AFMT_S8" :
932 the_fmt == AFMT_U16_LE ? "AFMT_U16_LE" :
933 the_fmt == AFMT_U16_BE ? "AFMT_U16_BE" :
934 the_fmt == AFMT_MPEG ? "AFMT_MPEG" :
935 "AFMT_???",
936 the_stereo == 2 ? "stereo" : "mono",
937 the_speed,
938 the_volume / 256, the_volume % 256); }
939 #endif
940
941 return(1);
942 }
943
944 /* XEmacs requires code both for playback of pre-loaded data and for playback
945 from a soundfile; we use one function for both cases */
946 static void linux_play_data_or_file(int fd,unsigned char *data,
947 int length,int volume)
948 {
949 size_t (*parsesndfile)(void **dayta,size_t *sz,void **outbuf);
950 size_t (*sndcnv)(void **dayta,size_t *sz,void **);
951 fmtType ffmt;
952 int fmt,speed,tracks;
953 unsigned char *pptr,*optr,*cptr,*sptr;
954 int wrtn,rrtn,crtn,prtn;
955
956 /* We need to read at least the header information before we can start
957 doing anything */
958 if (!data || length < HEADERSZ)
959 if (fd < 0) return;
960 else {
961 length = read(fd,sndbuf,SNDBUFSZ);
962 if (length < HEADERSZ)
963 return;
964 data = sndbuf;
965 length = SNDBUFSZ; }
966
967 ffmt = analyze_format(data,&fmt,&speed,&tracks,&parsesndfile);
968
969 if (ffmt != fmtRaw && ffmt != fmtSunAudio && ffmt != fmtWave) {
970 warn("Unsupported file format (neither RAW, nor Sun/DECAudio, nor WAVE)");
971 return; }
972
973 /* The VoxWare-SDK discourages opening /dev/audio; opening /dev/dsp and
974 properly intializing it via ioctl() is prefered */
975 if ((audio_fd=open((audio_dev="/dev/dsp"),
976 (O_WRONLY|O_NDELAY),0)) < 0) {
977 perror(audio_dev);
978 if (mix_fd > 0 && mix_fd != audio_fd) { close(mix_fd); mix_fd = -1; }
979 return; }
980
981 /* The VoxWare-SDK discourages direct manipulation of the mixer device as
982 this could lead to problems, when multiple sound cards are installed */
983 mix_fd = audio_fd;
984
985 sighup_handler = signal(SIGHUP,(__sighandler_t)sighandler);
986 sigint_handler = signal(SIGINT,(__sighandler_t)sighandler);
987
988 if (!audio_init(mix_fd,audio_fd,fmt,speed,tracks,&volume,&sndcnv))
989 goto END_OF_PLAY;
990 audio_vol = volume;
991
992 /* Initialize global parser state information to zero */
993 memset(&parsestate,0,sizeof(parsestate));
994
995 /* Mainloop: read a block of data, parse its contents, perform all
996 the neccessary conversions and output it to the sound
997 device; repeat until all data has been processed */
998 rrtn = length;
999 do {
1000 for (pptr = data; (prtn = parsesndfile((void **)&pptr,&rrtn,
1001 (void **)&optr)) > 0; )
1002 for (cptr = optr; (crtn = sndcnv((void **)&cptr,&prtn,
1003 (void **)&sptr)) > 0; ) {
1004 for (;;) {
1005 if ((wrtn = write(audio_fd,sptr,crtn)) < 0) {
1006 perror("write"); goto END_OF_PLAY; }
1007 else if (wrtn) break;
1008 else if (ioctl(audio_fd,SNDCTL_DSP_SYNC,NULL) < 0) {
1009 perror("SNDCTL_DSP_SYNC"); goto END_OF_PLAY; } }
1010 if (wrtn != crtn) {
1011 char buf[255];
1012 sprintf(buf,"play: crtn = %d, wrtn = %d",crtn,wrtn);
1013 warn(buf);
1014 goto END_OF_PLAY; } }
1015 if (fd >= 0) {
1016 if ((rrtn = read(fd,sndbuf,SNDBUFSZ)) < 0) {
1017 perror("read"); goto END_OF_PLAY; } }
1018 else
1019 break;
1020 } while (rrtn > 0);
1021
1022 /* Verify that we could fully parse the entire soundfile; this is needed
1023 only for files in WAVE format */
1024 if (ffmt == fmtWave && parsestate.wave.state != wvOutOfBlock &&
1025 parsestate.wave.state != wvFatal)
1026 warn("Unexpected end of WAVE file");
1027
1028 END_OF_PLAY:
1029 /* Now cleanup all used resources */
1030
1031 ioctl(audio_fd,SNDCTL_DSP_SYNC,NULL);
1032 ioctl(audio_fd,SNDCTL_DSP_RESET,NULL);
1033
1034 signal(SIGHUP,sighup_handler);
1035 signal(SIGINT,sigint_handler);
1036
1037 if (mix_fd > 0) {
1038 if (audio_vol >= 0) {
1039 ioctl(mix_fd,SOUND_MIXER_WRITE_PCM,&audio_vol);
1040 audio_vol = -1; }
1041 if (mix_fd != audio_fd)
1042 close(mix_fd);
1043 mix_fd = -1; }
1044
1045 close(audio_fd);
1046 audio_fd = -1;
1047
1048 return;
1049 }
1050
1051 /* Call "linux_play_data_or_file" with the appropriate parameters for
1052 playing a soundfile */
1053 void play_sound_file (char *sound_file, int volume);
1054 void play_sound_file (char *sound_file, int volume)
1055 {
1056 int fd;
1057
1058 if ((fd=open(sound_file,O_RDONLY,0)) < 0) {
1059 perror(sound_file);
1060 return; }
1061 linux_play_data_or_file(fd,NULL,0,volume);
1062 close(fd);
1063 return;
1064 }
1065
1066 /* Call "linux_play_data_or_file" with the appropriate parameters for
1067 playing pre-loaded data */
1068 void play_sound_data (unsigned char *data, int length, int volume);
1069 void play_sound_data (unsigned char *data, int length, int volume)
1070 {
1071 linux_play_data_or_file(-1,data,length,volume);
1072 return;
1073 }