Mercurial > hg > xemacs-beta
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); |