comparison src/linuxplay.c @ 398:74fd4e045ea6 r21-2-29

Import from CVS: tag r21-2-29
author cvs
date Mon, 13 Aug 2007 11:13:30 +0200
parents 8626e4521993
children b8cc9ab3f761
comparison
equal deleted inserted replaced
397:f4aeb21a5bad 398:74fd4e045ea6
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 4 ** This is version 1.3 of linuxplay.c, with platform-independent functions
5 ** moved to a different file by Robert Bihlmeyer <robbe@orcus.priv.at>.
5 ** 6 **
6 ** Parts of this code were inspired by sunplay.c, which is copyright 1989 by 7 ** 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 ** Jef Poskanzer and 1991,92 by Jamie Zawinski; c.f. sunplay.c for further
8 ** information. 9 ** information.
9 ** 10 **
43 ** some soundcards cannot handle signed 8bit data. 44 ** some soundcards cannot handle signed 8bit data.
44 */ 45 */
45 46
46 /* Synched up with: Not in FSF. */ 47 /* Synched up with: Not in FSF. */
47 48
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. */ 49 /* XEmacs beta testers say: undef this by default. */
52 #undef NOVOLUMECTRLFORMULAW /* Changing the volume for uLaw-encoded 50 #undef NOVOLUMECTRLFORMULAW /* Changing the volume for uLaw-encoded
53 samples sounds very poor; possibly, 51 samples sounds very poor; possibly,
54 this is true only for the PC-Snd 52 this is true only for the PC-Snd
55 driver, so undefine this symbol at your 53 driver, so undefine this symbol at your
56 discretion */ 54 discretion */
57 55
58 #ifdef HAVE_CONFIG_H 56 #ifdef HAVE_CONFIG_H
59 #include <config.h> 57 #include <config.h>
60 #endif 58 #endif
59
60 #include "miscplay.h"
61 61
62 #include <errno.h> 62 #include <errno.h>
63 #include <fcntl.h> 63 #include <fcntl.h>
64 #include SOUNDCARD_H_PATH /* Path computed by configure */ 64 #include SOUNDCARD_H_PATH /* Path computed by configure */
65 #include <stdio.h> 65 #include <stdio.h>
80 #include "sysfile.h" 80 #include "sysfile.h"
81 #define perror(str) message("audio: %s, %s ",str,strerror(errno)) 81 #define perror(str) message("audio: %s, %s ",str,strerror(errno))
82 #define warn(str) message("audio: %s ",GETTEXT(str)) 82 #define warn(str) message("audio: %s ",GETTEXT(str))
83 #endif 83 #endif
84 84
85 #ifdef __GNUC__ 85 static SIGTYPE (*sighup_handler) (int);
86 #define UNUSED(x) ((void)(x)) 86 static SIGTYPE (*sigint_handler) (int);
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];
129 87
130 static int mix_fd; 88 static int mix_fd;
131 static int audio_vol; 89 static int audio_vol;
132 static int audio_fd; 90 static int audio_fd;
133 static char *audio_dev = "/dev/dsp"; 91 static char *audio_dev = "/dev/dsp";
134 92
135 typedef enum {fmtIllegal,fmtRaw,fmtVoc,fmtWave,fmtSunAudio} fmtType;
136
137 /* Intercept SIGINT and SIGHUP in order to close the audio and mixer 93 /* Intercept SIGINT and SIGHUP in order to close the audio and mixer
138 devices before terminating sound output; this requires reliable 94 devices before terminating sound output; this requires reliable
139 signals as provided by "syssignal.h" */ 95 signals as provided by "syssignal.h" */
140 static void sighandler(int sig) 96 static SIGTYPE
97 sighandler (int sig)
141 { 98 {
142 if (mix_fd > 0) { 99 if (mix_fd > 0) {
143 if (audio_vol >= 0) { 100 if (audio_vol >= 0) {
144 ioctl(mix_fd,SOUND_MIXER_WRITE_PCM,&audio_vol); 101 ioctl(mix_fd,SOUND_MIXER_WRITE_PCM,&audio_vol);
145 audio_vol = -1; } 102 audio_vol = -1; }
152 close(audio_fd); 109 close(audio_fd);
153 audio_fd = -1; } 110 audio_fd = -1; }
154 if (sig == SIGHUP && sighup_handler) sighup_handler(sig); 111 if (sig == SIGHUP && sighup_handler) sighup_handler(sig);
155 else if (sig == SIGINT && sigint_handler) sigint_handler(sig); 112 else if (sig == SIGINT && sigint_handler) sigint_handler(sig);
156 else exit(1); 113 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); }
800 } 114 }
801 115
802 /* Initialize the soundcard and mixer device with the parameters that we 116 /* 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 117 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 118 natively supporting the required parameters, then try to set up conversion
971 size_t (*sndcnv)(void **dayta,size_t *sz,void **); 285 size_t (*sndcnv)(void **dayta,size_t *sz,void **);
972 fmtType ffmt; 286 fmtType ffmt;
973 int fmt,speed,tracks; 287 int fmt,speed,tracks;
974 unsigned char *pptr,*optr,*cptr,*sptr; 288 unsigned char *pptr,*optr,*cptr,*sptr;
975 int wrtn,rrtn,crtn,prtn; 289 int wrtn,rrtn,crtn,prtn;
290 unsigned char sndbuf[SNDBUFSZ];
976 291
977 /* We need to read at least the header information before we can start 292 /* We need to read at least the header information before we can start
978 doing anything */ 293 doing anything */
979 if (!data || length < HEADERSZ) { 294 if (!data || length < HEADERSZ) {
980 if (fd < 0) return; 295 if (fd < 0) return;
981 else { 296 else {
982 length = read(fd,linuxplay_sndbuf,SNDBUFSZ); 297 length = read(fd,sndbuf,SNDBUFSZ);
983 if (length < HEADERSZ) 298 if (length < HEADERSZ)
984 return; 299 return;
985 data = linuxplay_sndbuf; 300 data = sndbuf;
986 length = SNDBUFSZ; } 301 length = SNDBUFSZ; }
987 } 302 }
988 303
989 ffmt = analyze_format(data,&fmt,&speed,&tracks,&parsesndfile); 304 ffmt = analyze_format(data,&fmt,&speed,&tracks,&parsesndfile);
990 305
1008 323
1009 if (!audio_init(mix_fd,audio_fd,fmt,speed,tracks,&volume,&sndcnv)) 324 if (!audio_init(mix_fd,audio_fd,fmt,speed,tracks,&volume,&sndcnv))
1010 goto END_OF_PLAY; 325 goto END_OF_PLAY;
1011 audio_vol = volume; 326 audio_vol = volume;
1012 327
1013 /* Initialize global parser state information to zero */ 328 reset_parsestate();
1014 memset(&parsestate,0,sizeof(parsestate));
1015 329
1016 /* Mainloop: read a block of data, parse its contents, perform all 330 /* Mainloop: read a block of data, parse its contents, perform all
1017 the necessary conversions and output it to the sound 331 the necessary conversions and output it to the sound
1018 device; repeat until all data has been processed */ 332 device; repeat until all data has been processed */
1019 rrtn = length; 333 rrtn = length;
1032 char buf[255]; 346 char buf[255];
1033 sprintf(buf,"play: crtn = %d, wrtn = %d",crtn,wrtn); 347 sprintf(buf,"play: crtn = %d, wrtn = %d",crtn,wrtn);
1034 warn(buf); 348 warn(buf);
1035 goto END_OF_PLAY; } } 349 goto END_OF_PLAY; } }
1036 if (fd >= 0) { 350 if (fd >= 0) {
1037 if ((rrtn = read(fd,linuxplay_sndbuf,SNDBUFSZ)) < 0) { 351 if ((rrtn = read(fd,sndbuf,SNDBUFSZ)) < 0) {
1038 perror("read"); goto END_OF_PLAY; } } 352 perror("read"); goto END_OF_PLAY; } }
1039 else 353 else
1040 break; 354 break;
1041 } while (rrtn > 0); 355 } while (rrtn > 0);
1042 356
1043 /* Verify that we could fully parse the entire soundfile; this is needed 357 if (ffmt == fmtWave)
1044 only for files in WAVE format */ 358 parse_wave_complete();
1045 if (ffmt == fmtWave && parsestate.wave.state != wvOutOfBlock && 359
1046 parsestate.wave.state != wvFatal)
1047 warn("Unexpected end of WAVE file");
1048 360
1049 END_OF_PLAY: 361 END_OF_PLAY:
1050 /* Now cleanup all used resources */ 362 /* Now cleanup all used resources */
1051 363
1052 ioctl(audio_fd,SNDCTL_DSP_SYNC,NULL); 364 ioctl(audio_fd,SNDCTL_DSP_SYNC,NULL);