comparison src/linuxplay.c @ 412:697ef44129c6 r21-2-14

Import from CVS: tag r21-2-14
author cvs
date Mon, 13 Aug 2007 11:20:41 +0200
parents b8cc9ab3f761
children 11054d720c21
comparison
equal deleted inserted replaced
411:12e008d41344 412:697ef44129c6
1 /* linuxplay.c - play a sound file on the speaker 1 /* linuxplay.c - play a sound file on the speaker
2 ** 2 **
3 ** Copyright (C) 1995,96 by Markus Gutschke (gutschk@math.uni-muenster.de) 3 ** Copyright (C) 1995,96 by Markus Gutschke (gutschk@math.uni-muenster.de)
4 ** This is version 1.3 of linuxplay.c, with platform-independent functions 4 ** This is version 1.3 of linuxplay.c
5 ** moved to a different file by Robert Bihlmeyer <robbe@orcus.priv.at>.
6 ** 5 **
7 ** Parts of this code were inspired by sunplay.c, which is copyright 1989 by 6 ** Parts of this code were inspired by sunplay.c, which is copyright 1989 by
8 ** Jef Poskanzer and 1991,92 by Jamie Zawinski; c.f. sunplay.c for further 7 ** Jef Poskanzer and 1991,92 by Jamie Zawinski; c.f. sunplay.c for further
9 ** information. 8 ** information.
10 ** 9 **
44 ** some soundcards cannot handle signed 8bit data. 43 ** some soundcards cannot handle signed 8bit data.
45 */ 44 */
46 45
47 /* Synched up with: Not in FSF. */ 46 /* Synched up with: Not in FSF. */
48 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
49 /* XEmacs beta testers say: undef this by default. */ 51 /* XEmacs beta testers say: undef this by default. */
50 #undef NOVOLUMECTRLFORMULAW /* Changing the volume for uLaw-encoded 52 #undef NOVOLUMECTRLFORMULAW /* Changing the volume for uLaw-encoded
51 samples sounds very poor; possibly, 53 samples sounds very poor; possibly,
52 this is true only for the PC-Snd 54 this is true only for the PC-Snd
53 driver, so undefine this symbol at your 55 driver, so undefine this symbol at your
55 57
56 #ifdef HAVE_CONFIG_H 58 #ifdef HAVE_CONFIG_H
57 #include <config.h> 59 #include <config.h>
58 #endif 60 #endif
59 61
60 #include "miscplay.h"
61 #include "nativesound.h"
62
63 #include <errno.h> 62 #include <errno.h>
64 #include <fcntl.h> 63 #include <fcntl.h>
65 #include SOUNDCARD_H_FILE /* Path computed by configure */ 64 #include SOUNDCARD_H_PATH /* Path computed by configure */
66 #include <stdio.h> 65 #include <stdio.h>
67 #include <stdlib.h> 66 #include <stdlib.h>
68 #include <string.h> 67 #include <string.h>
69 #include <fcntl.h> 68 #include <fcntl.h>
70 #include <sys/file.h> 69 #include <sys/file.h>
81 #include "sysfile.h" 80 #include "sysfile.h"
82 #define perror(str) message("audio: %s, %s ",str,strerror(errno)) 81 #define perror(str) message("audio: %s, %s ",str,strerror(errno))
83 #define warn(str) message("audio: %s ",GETTEXT(str)) 82 #define warn(str) message("audio: %s ",GETTEXT(str))
84 #endif 83 #endif
85 84
86 static SIGTYPE (*sighup_handler) (int); 85 #ifdef __GNUC__
87 static SIGTYPE (*sigint_handler) (int); 86 #define UNUSED(x) ((void)(x))
87 #else
88 #define UNUSED(x)
89 #define __inline__
90 #endif
91
92 static void (*sighup_handler)(int);
93 static void (*sigint_handler)(int);
94
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... */
99 enum wvState
100 { wvMain,
101 wvSubchunk,
102 wvOutOfBlock,
103 wvSkipChunk,
104 wvSoundChunk,
105 wvFatal,
106 wvFatalNotify
107 };
108
109 static union {
110 struct {
111 int align;
112 enum wvState state;
113 size_t left;
114 unsigned char leftover[HEADERSZ];
115 signed long chunklength;
116 } wave;
117 struct {
118 int align;
119 int isdata;
120 int skipping;
121 size_t left;
122 unsigned char leftover[HEADERSZ];
123 } audio;
124 } parsestate;
125
126 /* Use a global buffer as scratch-pad for possible conversions of the
127 sampling format */
128 unsigned char linuxplay_sndbuf[SNDBUFSZ];
88 129
89 static int mix_fd; 130 static int mix_fd;
90 static int audio_vol; 131 static int audio_vol;
91 static int audio_fd; 132 static int audio_fd;
92 static char *audio_dev = "/dev/dsp"; 133 static char *audio_dev = "/dev/dsp";
93 134
135 typedef enum {fmtIllegal,fmtRaw,fmtVoc,fmtWave,fmtSunAudio} fmtType;
136
94 /* Intercept SIGINT and SIGHUP in order to close the audio and mixer 137 /* Intercept SIGINT and SIGHUP in order to close the audio and mixer
95 devices before terminating sound output; this requires reliable 138 devices before terminating sound output; this requires reliable
96 signals as provided by "syssignal.h" */ 139 signals as provided by "syssignal.h" */
97 static SIGTYPE 140 static void sighandler(int sig)
98 sighandler (int sig)
99 { 141 {
100 if (mix_fd > 0) { 142 if (mix_fd > 0) {
101 if (audio_vol >= 0) { 143 if (audio_vol >= 0) {
102 ioctl(mix_fd,SOUND_MIXER_WRITE_PCM,&audio_vol); 144 ioctl(mix_fd,SOUND_MIXER_WRITE_PCM,&audio_vol);
103 audio_vol = -1; } 145 audio_vol = -1; }
110 close(audio_fd); 152 close(audio_fd);
111 audio_fd = -1; } 153 audio_fd = -1; }
112 if (sig == SIGHUP && sighup_handler) sighup_handler(sig); 154 if (sig == SIGHUP && sighup_handler) sighup_handler(sig);
113 else if (sig == SIGINT && sigint_handler) sigint_handler(sig); 155 else if (sig == SIGINT && sigint_handler) sigint_handler(sig);
114 else exit(1); 156 else exit(1);
157 }
158
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)
163 {
164 int rc = *sz;
165
166 *outbuf = *data;
167 *sz = 0;
168 return(rc);
169 }
170
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)
174 {
175 UNUSED(data);
176 UNUSED(sz);
177 UNUSED(outbuf);
178 return(0);
179 }
180
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)
186 {
187 int rc = 1;
188
189 if (rq > HEADERSZ) {
190 warn("Header size exceeded while parsing WAVE file");
191 parsestate.wave.state = wvFatal;
192 *sz = 0;
193 return(0); }
194 if ((rq -= parsestate.wave.left) <= 0)
195 return(rc);
196 if (rq > *sz) {rq = *sz; rc = 0;}
197 memcpy(parsestate.wave.leftover+parsestate.wave.left,
198 *data,rq);
199 parsestate.wave.left += rq;
200 (*(unsigned char **)data) += rq;
201 *sz -= rq;
202 return(rc);
203 }
204
205 /* ...and next we remove this many bytes from the buffer */
206 static __inline__ void waveremove(size_t rq)
207 {
208 if (parsestate.wave.left <= rq)
209 parsestate.wave.left = 0;
210 else {
211 parsestate.wave.left -= rq;
212 memmove(parsestate.wave.leftover,
213 parsestate.wave.leftover+rq,
214 parsestate.wave.left); }
215 return;
216 }
217
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)
221 {
222 for (;;)
223 switch (parsestate.wave.state) {
224 case wvMain:
225 if (!waverequire(data,sz,20))
226 return(0);
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]));
232 waveremove(20);
233 parsestate.wave.state = wvSubchunk;
234 break;
235 case wvSubchunk:
236 if (!waverequire(data,sz,parsestate.wave.chunklength))
237 return(0);
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; }
245 else
246 parsestate.wave.state = wvOutOfBlock;
247 waveremove(parsestate.wave.chunklength);
248 break;
249 case wvOutOfBlock:
250 if (!waverequire(data,sz,8))
251 return(0);
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;
259 else
260 parsestate.wave.state = wvSoundChunk;
261 waveremove(8);
262 break;
263 case wvSkipChunk:
264 if (parsestate.wave.chunklength > 0 && *sz > 0 &&
265 (signed long)*sz < (signed long)parsestate.wave.chunklength) {
266 parsestate.wave.chunklength -= *sz;
267 *sz = 0; }
268 else {
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; }
273 break;
274 case wvSoundChunk: {
275 size_t count,rq;
276 if (parsestate.wave.left) { /* handle leftover bytes from last
277 alignment operation */
278 count = parsestate.wave.left;
279 rq = HEADERSZ-count;
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;
284 return(0); }
285 parsestate.wave.chunklength -= rq;
286 *outbuf = parsestate.wave.leftover;
287 parsestate.wave.left = 0;
288 return(rq); }
289 if (*sz >= (size_t) parsestate.wave.chunklength) {
290 count = parsestate.wave.chunklength;
291 rq = 0; }
292 else {
293 count = *sz;
294 count -= rq = count % parsestate.wave.align; }
295 *outbuf = *data;
296 (*(unsigned char **)data) += count;
297 *sz -= 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; }
304 else if (rq)
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);
309 return(count); }
310 case wvFatalNotify:
311 warn("Irrecoverable error while parsing WAVE file");
312 parsestate.wave.state = wvFatal;
313 break;
314 case wvFatal:
315 default:
316 *sz = 0;
317 return(0); }
318 }
319
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)
325 {
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
328 single entry */
329 if (parsestate.audio.left) {
330 if (parsestate.audio.left + *sz > (size_t) parsestate.audio.align) {
331 int count;
332 memmove(parsestate.audio.leftover + parsestate.audio.left,
333 *data,
334 count = parsestate.audio.align - parsestate.audio.left);
335 *outbuf = parsestate.audio.leftover;
336 *sz -= count;
337 *data = (*(char **)data) + count;
338 parsestate.audio.left = 0;
339 return(parsestate.audio.align); }
340 else {
341 /* We need even more data in order to get one complete single entry! */
342 memmove(parsestate.audio.leftover + parsestate.audio.left,
343 *data,
344 *sz);
345 *data = (*(char **)data) + *sz;
346 parsestate.audio.left += *sz;
347 *sz = 0;
348 return(0); } }
349
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) {
353 int rc = *sz;
354 *outbuf = *data;
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; }
360 *sz = 0;
361 return(rc); }
362
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;
368 if (*sz < 8) {
369 warn("Irrecoverable error while parsing Sun/DEC audio file");
370 return(0); }
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])); }}
380
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; }
395 *sz = 0;
396 parsestate.audio.skipping = 0;
397 parsestate.audio.isdata++;
398 return(rc); }
399 else {
400 /* Skip everything */
401 parsestate.audio.skipping -= *sz;
402 return(0); }
403 }
404
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)
409 {
410 int rc = *sz;
411
412 *outbuf = *data;
413 *sz = 0;
414 return(rc);
415 }
416
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)
419 {
420 REGISTER unsigned char *src;
421 REGISTER unsigned char *dest;
422 int rc,count;
423
424 count = *sz / 2;
425 if (count > SNDBUFSZ) { *sz -= 2*SNDBUFSZ; count = SNDBUFSZ; }
426 else *sz = 0;
427 rc = count;
428 src = (unsigned char *) *data;
429 *outbuf =
430 dest = linuxplay_sndbuf;
431 while (count--)
432 *dest++ = (unsigned char)(((int)*(src)++ +
433 (int)*(src)++) / 2);
434 *data = src;
435 return(rc);
436 }
437
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)
440 {
441 REGISTER unsigned char *src;
442 REGISTER unsigned char *dest;
443 int rc, count;
444
445 count = *sz / 2;
446 if (count > SNDBUFSZ) { *sz -= 2*SNDBUFSZ; count = SNDBUFSZ; }
447 else *sz = 0;
448 rc = count;
449 src = (unsigned char *) *data;
450 *outbuf =
451 dest = linuxplay_sndbuf;
452 while (count--)
453 *dest++ = (unsigned char)(((int)*((signed char *)(src++)) +
454 (int)*((signed char *)(src++))) / 2);
455 *data = src;
456 return(rc);
457 }
458
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)
461 {
462 REGISTER unsigned char *src;
463 REGISTER unsigned char *dest;
464 int rc,count;
465
466 count = *sz / 2;
467 if (count > SNDBUFSZ) { *sz -= 2*SNDBUFSZ; count = SNDBUFSZ; }
468 else *sz = 0;
469 rc = count;
470 src = (unsigned char *) *data;
471 *outbuf =
472 dest = linuxplay_sndbuf;
473 while (count--)
474 *dest++ = (unsigned char)(((int)*((signed char *)(src++)) +
475 (int)*((signed char *)(src++))) / 2) ^ 0x80;
476 *data = src;
477 return(rc);
478 }
479
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)
482 {
483 REGISTER unsigned char *src;
484 REGISTER unsigned char *dest;
485 int rc,count;
486
487 count = *sz;
488 if (count > SNDBUFSZ) { *sz -= SNDBUFSZ; count = SNDBUFSZ; }
489 else *sz = 0;
490 rc = count;
491 src = (unsigned char *) *data;
492 *outbuf =
493 dest = linuxplay_sndbuf;
494 while (count--)
495 *dest++ = *(src)++ ^ 0x80;
496 *data = src;
497 return(rc);
498 }
499
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)
503 {
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;
511
512 /* unrolling this condition (hopefully) improves execution speed */
513 if (i < 0) {
514 if ((i = (132-i)) > 0x7FFF) i = 0x7FFF;
515 logi = (i >> ((bits = t_bits[i/256])+4));
516 return((bits << 4 | logi) ^ 0x7F); }
517 else {
518 if ((i = 132+i) > 0x7FFF) i = 0x7FFF;
519 logi = (i >> ((bits = t_bits[i/256])+4));
520 return(~(bits << 4 | logi)); }
521 }
522
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)
525 {
526
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};
561
562 REGISTER unsigned char *src;
563 REGISTER unsigned char *dest;
564 int rc,count;
565
566 count = *sz / 2;
567 if (count > SNDBUFSZ) { *sz -= 2*SNDBUFSZ; count = SNDBUFSZ; }
568 else *sz = 0;
569 rc = count;
570 src = (unsigned char *) *data;
571 *outbuf =
572 dest = linuxplay_sndbuf;
573 while (count--)
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)++] +
578 ulaw2int[*(src)++]);
579 *data = src;
580 return(rc);
581 }
582
583 /* Convert 16 bit little endian signed stereo data to 16 bit little endian
584 signed mono data */
585 static size_t sndcnv16_2monoLE(void **data,size_t *sz,void **outbuf)
586 {
587 REGISTER unsigned char *src;
588 REGISTER unsigned char *dest;
589 int rc,count;
590 signed short i;
591
592 count = *sz / 2;
593 if (count > SNDBUFSZ) { *sz -= 2*SNDBUFSZ; count = SNDBUFSZ; }
594 else *sz = 0;
595 rc = count;
596 src = (unsigned char *) *data;
597 *outbuf =
598 dest = linuxplay_sndbuf;
599 for (count /= 2; count--; ) {
600 i = ((int)(src[0]) +
601 256*(int)(src[1]) +
602 (int)(src[2]) +
603 256*(int)(src[3])) / 2;
604 src += 4;
605 *dest++ = (unsigned char)(i & 0xFF);
606 *dest++ = (unsigned char)((i / 256) & 0xFF); }
607 *data = src;
608 return(rc);
609 }
610
611 /* Convert 16 bit big endian signed stereo data to 16 bit big endian
612 signed mono data */
613 static size_t sndcnv16_2monoBE(void **data,size_t *sz,void **outbuf)
614 {
615 REGISTER unsigned char *src;
616 REGISTER unsigned char *dest;
617 int rc,count;
618 signed short i;
619
620 count = *sz / 2;
621 if (count > SNDBUFSZ) { *sz -= 2*SNDBUFSZ; count = SNDBUFSZ; }
622 else *sz = 0;
623 rc = count;
624 src = (unsigned char *) *data;
625 *outbuf =
626 dest = linuxplay_sndbuf;
627 for (count /= 2; count--; ) {
628 i = ((int)(src[1]) +
629 256*(int)(src[0]) +
630 (int)(src[3]) +
631 256*(int)(src[2])) / 2;
632 src += 4;
633 *dest++ = (unsigned char)((i / 256) & 0xFF);
634 *dest++ = (unsigned char)(i & 0xFF); }
635 *data = src;
636 return(rc);
637 }
638
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)
641 {
642 REGISTER unsigned char *src;
643 REGISTER unsigned char *dest;
644 int rc,count;
645
646 count = *sz / 2;
647 if (count > SNDBUFSZ) { *sz -= 2*SNDBUFSZ; count = SNDBUFSZ; }
648 else *sz = 0;
649 rc = count;
650 src = (unsigned char *) *data;
651 *outbuf =
652 dest = linuxplay_sndbuf;
653 while (count--) {
654 *dest++ = (unsigned char)(((signed char *)src)[1] ^ (signed char)0x80);
655 src += 2;
656 }
657 *data = src;
658 return(rc);
659 }
660
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)
663 {
664 REGISTER unsigned char *src;
665 REGISTER unsigned char *dest;
666 int rc,count;
667
668 count = *sz / 2;
669 if (count > SNDBUFSZ) { *sz -= 2*SNDBUFSZ; count = SNDBUFSZ; }
670 else *sz = 0;
671 rc = count;
672 src = (unsigned char *) *data;
673 *outbuf =
674 dest = linuxplay_sndbuf;
675 while (count--) {
676 *dest++ = (unsigned char)(((signed char *)src)[0] ^ (signed char)0x80);
677 src += 2;
678 }
679 *data = src;
680 return(rc);
681 }
682
683 /* Convert 16 bit little endian signed stereo data to 8 bit unsigned
684 mono data */
685 static size_t sndcnv2monobyteLE(void **data,size_t *sz,void **outbuf)
686 {
687 REGISTER unsigned char *src;
688 REGISTER unsigned char *dest;
689 int rc,count;
690
691 count = *sz / 4;
692 if (count > SNDBUFSZ) { *sz -= 4*SNDBUFSZ; count = SNDBUFSZ; }
693 else *sz = 0;
694 rc = count;
695 src = (unsigned char *) *data;
696 *outbuf =
697 dest = linuxplay_sndbuf;
698 while (count--) {
699 *dest++ = (unsigned char)(((int)((signed char *)src)[1] +
700 (int)((signed char *)src)[3]) / 2 ^ 0x80);
701 src += 4;
702 }
703 *data = src;
704 return(rc);
705 }
706
707 /* Convert 16 bit big endian signed stereo data to 8 bit unsigned
708 mono data */
709 static size_t sndcnv2monobyteBE(void **data,size_t *sz,void **outbuf)
710 {
711 REGISTER unsigned char *src;
712 REGISTER unsigned char *dest;
713 int rc,count;
714
715 count = *sz / 4;
716 if (count > SNDBUFSZ) { *sz -= 4*SNDBUFSZ; count = SNDBUFSZ; }
717 else *sz = 0;
718 rc = count;
719 src = (unsigned char *) *data;
720 *outbuf =
721 dest = linuxplay_sndbuf;
722 while (count--) {
723 *dest++ = (unsigned char)(((int)((signed char *)src)[0] +
724 (int)((signed char *)src)[2]) / 2 ^ 0x80);
725 src += 4;
726 }
727 *data = src;
728 return(rc);
729 }
730
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,
735 int *tracks,
736 size_t (**parsesndfile)(void **,size_t *sz,
737 void **))
738 {
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 */
743 *fmt = AFMT_U8;
744 *speed = 8000;
745 *tracks = 2;
746 *parsesndfile = parsevoc;
747 return(fmtVoc); }
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))
752 return(fmtIllegal);
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;
759 return(fmtWave); }
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) {
762 *fmt = AFMT_MU_LAW;
763 *speed = 8000;
764 *tracks = 1;
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) {
779 *fmt = AFMT_MU_LAW;
780 *speed = 8000;
781 *tracks = 1;
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); }
794 else {
795 *fmt = AFMT_U8;
796 *speed = 8000;
797 *tracks = 1;
798 *parsesndfile = parseraw;
799 return(fmtRaw); }
115 } 800 }
116 801
117 /* Initialize the soundcard and mixer device with the parameters that we 802 /* Initialize the soundcard and mixer device with the parameters that we
118 found in the header of the sound file. If the soundcard is not capable of 803 found in the header of the sound file. If the soundcard is not capable of
119 natively supporting the required parameters, then try to set up conversion 804 natively supporting the required parameters, then try to set up conversion
276 961
277 return(1); 962 return(1);
278 } 963 }
279 964
280 /* XEmacs requires code both for playback of pre-loaded data and for playback 965 /* XEmacs requires code both for playback of pre-loaded data and for playback
281 from a soundfile; we use one function for both cases. 966 from a soundfile; we use one function for both cases */
282 967 static void linux_play_data_or_file(int fd,unsigned char *data,
283 Returns 1 on succes. 0 otherwise.
284 */
285 static int linux_play_data_or_file(int fd,unsigned char *data,
286 int length,int volume) 968 int length,int volume)
287 { 969 {
288 size_t (*parsesndfile)(void **dayta,size_t *sz,void **outbuf); 970 size_t (*parsesndfile)(void **dayta,size_t *sz,void **outbuf);
289 size_t (*sndcnv)(void **dayta,size_t *sz,void **); 971 size_t (*sndcnv)(void **dayta,size_t *sz,void **);
290 fmtType ffmt; 972 fmtType ffmt;
291 int fmt,speed,tracks; 973 int fmt,speed,tracks;
292 unsigned char *pptr,*optr,*cptr,*sptr; 974 unsigned char *pptr,*optr,*cptr,*sptr;
293 int wrtn,rrtn,crtn,prtn; 975 int wrtn,rrtn,crtn,prtn;
294 unsigned char sndbuf[SNDBUFSZ];
295 976
296 /* We need to read at least the header information before we can start 977 /* We need to read at least the header information before we can start
297 doing anything */ 978 doing anything */
298 if (!data || length < HEADERSZ) { 979 if (!data || length < HEADERSZ) {
299 if (fd < 0) return 0; 980 if (fd < 0) return;
300 else { 981 else {
301 length = read(fd,sndbuf,SNDBUFSZ); 982 length = read(fd,linuxplay_sndbuf,SNDBUFSZ);
302 if (length < HEADERSZ) 983 if (length < HEADERSZ)
303 return 0; 984 return;
304 data = sndbuf; 985 data = linuxplay_sndbuf;
305 length = SNDBUFSZ; } 986 length = SNDBUFSZ; }
306 } 987 }
307 988
308 ffmt = analyze_format(data,&fmt,&speed,&tracks,&parsesndfile); 989 ffmt = analyze_format(data,&fmt,&speed,&tracks,&parsesndfile);
309 990
310 if (ffmt != fmtRaw && ffmt != fmtSunAudio && ffmt != fmtWave) { 991 if (ffmt != fmtRaw && ffmt != fmtSunAudio && ffmt != fmtWave) {
311 warn("Unsupported file format (neither RAW, nor Sun/DECAudio, nor WAVE)"); 992 warn("Unsupported file format (neither RAW, nor Sun/DECAudio, nor WAVE)");
312 return 0; } 993 return; }
313 994
314 /* The VoxWare-SDK discourages opening /dev/audio; opening /dev/dsp and 995 /* The VoxWare-SDK discourages opening /dev/audio; opening /dev/dsp and
315 properly initializing it via ioctl() is preferred */ 996 properly initializing it via ioctl() is preferred */
316 if ((audio_fd=open(audio_dev, O_WRONLY | O_NONBLOCK, 0)) < 0) { 997 if ((audio_fd=open(audio_dev, O_WRONLY | O_NONBLOCK, 0)) < 0) {
317 /* JV. Much too verbose. In addition this can crash. See NOTE: in 998 perror(audio_dev);
318 Fplay_sound
319 perror(audio_dev); */
320 if (mix_fd > 0 && mix_fd != audio_fd) { close(mix_fd); mix_fd = -1; } 999 if (mix_fd > 0 && mix_fd != audio_fd) { close(mix_fd); mix_fd = -1; }
321 return 0; } 1000 return; }
322 1001
323 /* The VoxWare-SDK discourages direct manipulation of the mixer device as 1002 /* The VoxWare-SDK discourages direct manipulation of the mixer device as
324 this could lead to problems, when multiple sound cards are installed */ 1003 this could lead to problems, when multiple sound cards are installed */
325 mix_fd = audio_fd; 1004 mix_fd = audio_fd;
326 1005
329 1008
330 if (!audio_init(mix_fd,audio_fd,fmt,speed,tracks,&volume,&sndcnv)) 1009 if (!audio_init(mix_fd,audio_fd,fmt,speed,tracks,&volume,&sndcnv))
331 goto END_OF_PLAY; 1010 goto END_OF_PLAY;
332 audio_vol = volume; 1011 audio_vol = volume;
333 1012
334 reset_parsestate(); 1013 /* Initialize global parser state information to zero */
1014 memset(&parsestate,0,sizeof(parsestate));
335 1015
336 /* Mainloop: read a block of data, parse its contents, perform all 1016 /* Mainloop: read a block of data, parse its contents, perform all
337 the necessary conversions and output it to the sound 1017 the necessary conversions and output it to the sound
338 device; repeat until all data has been processed */ 1018 device; repeat until all data has been processed */
339 rrtn = length; 1019 rrtn = length;
352 char buf[255]; 1032 char buf[255];
353 sprintf(buf,"play: crtn = %d, wrtn = %d",crtn,wrtn); 1033 sprintf(buf,"play: crtn = %d, wrtn = %d",crtn,wrtn);
354 warn(buf); 1034 warn(buf);
355 goto END_OF_PLAY; } } 1035 goto END_OF_PLAY; } }
356 if (fd >= 0) { 1036 if (fd >= 0) {
357 if ((rrtn = read(fd,sndbuf,SNDBUFSZ)) < 0) { 1037 if ((rrtn = read(fd,linuxplay_sndbuf,SNDBUFSZ)) < 0) {
358 perror("read"); goto END_OF_PLAY; } } 1038 perror("read"); goto END_OF_PLAY; } }
359 else 1039 else
360 break; 1040 break;
361 } while (rrtn > 0); 1041 } while (rrtn > 0);
362 1042
363 if (ffmt == fmtWave) 1043 /* Verify that we could fully parse the entire soundfile; this is needed
364 parse_wave_complete(); 1044 only for files in WAVE format */
365 1045 if (ffmt == fmtWave && parsestate.wave.state != wvOutOfBlock &&
1046 parsestate.wave.state != wvFatal)
1047 warn("Unexpected end of WAVE file");
366 1048
367 END_OF_PLAY: 1049 END_OF_PLAY:
368 /* Now cleanup all used resources */ 1050 /* Now cleanup all used resources */
369 1051
370 ioctl(audio_fd,SNDCTL_DSP_SYNC,NULL); 1052 ioctl(audio_fd,SNDCTL_DSP_SYNC,NULL);
382 mix_fd = -1; } 1064 mix_fd = -1; }
383 1065
384 close(audio_fd); 1066 close(audio_fd);
385 audio_fd = -1; 1067 audio_fd = -1;
386 1068
387 return 1; 1069 return;
388 } 1070 }
389 1071
390 /* Call "linux_play_data_or_file" with the appropriate parameters for 1072 /* Call "linux_play_data_or_file" with the appropriate parameters for
391 playing a soundfile */ 1073 playing a soundfile */
1074 void play_sound_file (char *sound_file, int volume);
392 void play_sound_file (char *sound_file, int volume) 1075 void play_sound_file (char *sound_file, int volume)
393 { 1076 {
394 int fd; 1077 int fd;
395 1078
396 if ((fd=open(sound_file,O_RDONLY,0)) < 0) { 1079 if ((fd=open(sound_file,O_RDONLY,0)) < 0) {
401 return; 1084 return;
402 } 1085 }
403 1086
404 /* Call "linux_play_data_or_file" with the appropriate parameters for 1087 /* Call "linux_play_data_or_file" with the appropriate parameters for
405 playing pre-loaded data */ 1088 playing pre-loaded data */
406 int play_sound_data (unsigned char *data, int length, int volume) 1089 void play_sound_data (unsigned char *data, int length, int volume);
407 { 1090 void play_sound_data (unsigned char *data, int length, int volume)
408 return linux_play_data_or_file(-1,data,length,volume); 1091 {
409 } 1092 linux_play_data_or_file(-1,data,length,volume);
1093 return;
1094 }