Mercurial > hg > xemacs-beta
comparison src/miscplay.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 | |
children | 2f8bb876ab1d |
comparison
equal
deleted
inserted
replaced
397:f4aeb21a5bad | 398:74fd4e045ea6 |
---|---|
1 /* miscplay.c - general routines related to playing sounds | |
2 ** | |
3 ** Copyright (C) 1995,96 by Markus Gutschke (gutschk@math.uni-muenster.de) | |
4 ** This was sawed out from version 1.3 of linuxplay.c by | |
5 ** Robert Bihlmeyer <robbe@orcus.priv.at>. | |
6 ** | |
7 ** 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 | |
9 ** information. | |
10 ** | |
11 ** Permission to use, copy, modify, and distribute this software and its | |
12 ** documentation for any purpose and without fee is hereby granted, provided | |
13 ** that the above copyright notice appear in all copies and that both that | |
14 ** copyright notice and this permission notice appear in supporting | |
15 ** documentation. This software is provided "as is" without express or | |
16 ** implied warranty. | |
17 */ | |
18 | |
19 #ifdef HAVE_CONFIG_H | |
20 #include <config.h> | |
21 #endif | |
22 | |
23 #include "miscplay.h" | |
24 #include "lisp.h" | |
25 #include "syssignal.h" | |
26 #include "sysfile.h" | |
27 #define warn(str) message("audio: %s ",GETTEXT(str)) | |
28 | |
29 #include <stdlib.h> | |
30 | |
31 #ifdef __GNUC__ | |
32 #define UNUSED(x) ((void)(x)) | |
33 #else | |
34 #define UNUSED(x) | |
35 #define __inline__ | |
36 #endif | |
37 | |
38 /* Maintain global variable for keeping parser state information; this struct | |
39 is set to zero before the first invocation of the parser. The use of a | |
40 global variable prevents multiple concurrent executions of this code, but | |
41 this does not happen anyways... */ | |
42 enum wvState | |
43 { wvMain, | |
44 wvSubchunk, | |
45 wvOutOfBlock, | |
46 wvSkipChunk, | |
47 wvSoundChunk, | |
48 wvFatal, | |
49 wvFatalNotify | |
50 }; | |
51 | |
52 static union { | |
53 struct { | |
54 int align; | |
55 enum wvState state; | |
56 size_t left; | |
57 unsigned char leftover[HEADERSZ]; | |
58 signed long chunklength; | |
59 } wave; | |
60 struct { | |
61 int align; | |
62 int isdata; | |
63 int skipping; | |
64 size_t left; | |
65 unsigned char leftover[HEADERSZ]; | |
66 } audio; | |
67 } parsestate; | |
68 | |
69 /* Use a global buffer as scratch-pad for possible conversions of the | |
70 sampling format */ | |
71 unsigned char miscplay_sndbuf[SNDBUFSZ]; | |
72 | |
73 /* Initialize global parser state information to zero */ | |
74 void reset_parsestate() | |
75 { | |
76 memset(&parsestate,0,sizeof(parsestate)); | |
77 } | |
78 | |
79 /* Verify that we could fully parse the entire soundfile; this is needed | |
80 only for files in WAVE format */ | |
81 int parse_wave_complete() | |
82 { | |
83 if (parsestate.wave.state != wvOutOfBlock && | |
84 parsestate.wave.state != wvFatal) { | |
85 warn("Unexpected end of WAVE file"); | |
86 return 0; | |
87 } else | |
88 return 1; | |
89 } | |
90 | |
91 /* There is no special treatment required for parsing raw data files; we | |
92 assume that these files contain data in 8bit unsigned format that | |
93 has been sampled at 8kHz; there is no extra header */ | |
94 static size_t parseraw(void **data,size_t *sz,void **outbuf) | |
95 { | |
96 int rc = *sz; | |
97 | |
98 *outbuf = *data; | |
99 *sz = 0; | |
100 return(rc); | |
101 } | |
102 | |
103 /* Currently we cannot cope with files in VOC format; if you really need | |
104 to play these files, they should be converted by using SOX */ | |
105 static size_t parsevoc(void **data,size_t *sz,void **outbuf) | |
106 { | |
107 UNUSED(data); | |
108 UNUSED(sz); | |
109 UNUSED(outbuf); | |
110 return(0); | |
111 } | |
112 | |
113 /* We need to perform some look-ahead in order to parse files in WAVE format; | |
114 this might require re-partioning of the data segments if headers cross the | |
115 boundaries between two read operations. This is done in a two-step way: | |
116 first we request a certain amount of bytes... */ | |
117 static __inline__ int waverequire(void **data,size_t *sz,size_t rq) | |
118 { | |
119 int rc = 1; | |
120 | |
121 if (rq > HEADERSZ) { | |
122 warn("Header size exceeded while parsing WAVE file"); | |
123 parsestate.wave.state = wvFatal; | |
124 *sz = 0; | |
125 return(0); } | |
126 if ((rq -= parsestate.wave.left) <= 0) | |
127 return(rc); | |
128 if (rq > *sz) {rq = *sz; rc = 0;} | |
129 memcpy(parsestate.wave.leftover+parsestate.wave.left, | |
130 *data,rq); | |
131 parsestate.wave.left += rq; | |
132 (*(unsigned char **)data) += rq; | |
133 *sz -= rq; | |
134 return(rc); | |
135 } | |
136 | |
137 /* ...and next we remove this many bytes from the buffer */ | |
138 static __inline__ void waveremove(size_t rq) | |
139 { | |
140 if (parsestate.wave.left <= rq) | |
141 parsestate.wave.left = 0; | |
142 else { | |
143 parsestate.wave.left -= rq; | |
144 memmove(parsestate.wave.leftover, | |
145 parsestate.wave.leftover+rq, | |
146 parsestate.wave.left); } | |
147 return; | |
148 } | |
149 | |
150 /* Sound files in WAVE format can contain an arbitrary amount of tagged | |
151 chunks; this requires quite some effort for parsing the data */ | |
152 static size_t parsewave(void **data,size_t *sz,void **outbuf) | |
153 { | |
154 for (;;) | |
155 switch (parsestate.wave.state) { | |
156 case wvMain: | |
157 if (!waverequire(data,sz,20)) | |
158 return(0); | |
159 /* Keep compatibility with Linux 68k, etc. by not relying on byte-sex */ | |
160 parsestate.wave.chunklength = parsestate.wave.leftover[16] + | |
161 256*(parsestate.wave.leftover[17] + | |
162 256*(parsestate.wave.leftover[18] + | |
163 256*parsestate.wave.leftover[19])); | |
164 waveremove(20); | |
165 parsestate.wave.state = wvSubchunk; | |
166 break; | |
167 case wvSubchunk: | |
168 if (!waverequire(data,sz,parsestate.wave.chunklength)) | |
169 return(0); | |
170 parsestate.wave.align = parsestate.wave.chunklength < 14 ? 1 | |
171 : parsestate.wave.leftover[12]; | |
172 if (parsestate.wave.align != 1 && | |
173 parsestate.wave.align != 2 && | |
174 parsestate.wave.align != 4) { | |
175 warn("Illegal datawidth detected while parsing WAVE file"); | |
176 parsestate.wave.state = wvFatal; } | |
177 else | |
178 parsestate.wave.state = wvOutOfBlock; | |
179 waveremove(parsestate.wave.chunklength); | |
180 break; | |
181 case wvOutOfBlock: | |
182 if (!waverequire(data,sz,8)) | |
183 return(0); | |
184 /* Keep compatibility with Linux 68k, etc. by not relying on byte-sex */ | |
185 parsestate.wave.chunklength = parsestate.wave.leftover[4] + | |
186 256*(parsestate.wave.leftover[5] + | |
187 256*(parsestate.wave.leftover[6] + | |
188 256*(parsestate.wave.leftover[7] & 0x7F))); | |
189 if (memcmp(parsestate.wave.leftover,"data",4)) | |
190 parsestate.wave.state = wvSkipChunk; | |
191 else | |
192 parsestate.wave.state = wvSoundChunk; | |
193 waveremove(8); | |
194 break; | |
195 case wvSkipChunk: | |
196 if (parsestate.wave.chunklength > 0 && *sz > 0 && | |
197 (signed long)*sz < (signed long)parsestate.wave.chunklength) { | |
198 parsestate.wave.chunklength -= *sz; | |
199 *sz = 0; } | |
200 else { | |
201 if (parsestate.wave.chunklength > 0 && *sz > 0) { | |
202 *sz -= parsestate.wave.chunklength; | |
203 (*(unsigned char **)data) += parsestate.wave.chunklength; } | |
204 parsestate.wave.state = wvOutOfBlock; } | |
205 break; | |
206 case wvSoundChunk: { | |
207 size_t count,rq; | |
208 if (parsestate.wave.left) { /* handle leftover bytes from last | |
209 alignment operation */ | |
210 count = parsestate.wave.left; | |
211 rq = HEADERSZ-count; | |
212 if (rq > (size_t) parsestate.wave.chunklength) | |
213 rq = parsestate.wave.chunklength; | |
214 if (!waverequire(data,sz,rq)) { | |
215 parsestate.wave.chunklength -= parsestate.wave.left - count; | |
216 return(0); } | |
217 parsestate.wave.chunklength -= rq; | |
218 *outbuf = parsestate.wave.leftover; | |
219 parsestate.wave.left = 0; | |
220 return(rq); } | |
221 if (*sz >= (size_t) parsestate.wave.chunklength) { | |
222 count = parsestate.wave.chunklength; | |
223 rq = 0; } | |
224 else { | |
225 count = *sz; | |
226 count -= rq = count % parsestate.wave.align; } | |
227 *outbuf = *data; | |
228 (*(unsigned char **)data) += count; | |
229 *sz -= count; | |
230 if ((parsestate.wave.chunklength -= count) < parsestate.wave.align) { | |
231 parsestate.wave.state = wvOutOfBlock; | |
232 /* Some broken software (e.g. SOX) attaches junk to the end of a sound | |
233 chunk; so, let's ignore this... */ | |
234 if (parsestate.wave.chunklength) | |
235 parsestate.wave.state = wvSkipChunk; } | |
236 else if (rq) | |
237 /* align data length to a multiple of datasize; keep additional data | |
238 in "leftover" buffer --- this is necessary to ensure proper | |
239 functioning of the sndcnv... routines */ | |
240 waverequire(data,sz,rq); | |
241 return(count); } | |
242 case wvFatalNotify: | |
243 warn("Irrecoverable error while parsing WAVE file"); | |
244 parsestate.wave.state = wvFatal; | |
245 break; | |
246 case wvFatal: | |
247 default: | |
248 *sz = 0; | |
249 return(0); } | |
250 } | |
251 | |
252 /* Strip the header from files in Sun/DEC audio format; this requires some | |
253 extra processing as the header can be an arbitrary size and it might | |
254 result in alignment errors for subsequent conversions --- thus we do | |
255 some buffering, where needed */ | |
256 static size_t parsesundecaudio(void **data,size_t *sz,void **outbuf) | |
257 { | |
258 /* There is data left over from the last invocation of this function; join | |
259 it with the new data and return a sound chunk that is as big as a | |
260 single entry */ | |
261 if (parsestate.audio.left) { | |
262 if (parsestate.audio.left + *sz > (size_t) parsestate.audio.align) { | |
263 int count; | |
264 memmove(parsestate.audio.leftover + parsestate.audio.left, | |
265 *data, | |
266 count = parsestate.audio.align - parsestate.audio.left); | |
267 *outbuf = parsestate.audio.leftover; | |
268 *sz -= count; | |
269 *data = (*(char **)data) + count; | |
270 parsestate.audio.left = 0; | |
271 return(parsestate.audio.align); } | |
272 else { | |
273 /* We need even more data in order to get one complete single entry! */ | |
274 memmove(parsestate.audio.leftover + parsestate.audio.left, | |
275 *data, | |
276 *sz); | |
277 *data = (*(char **)data) + *sz; | |
278 parsestate.audio.left += *sz; | |
279 *sz = 0; | |
280 return(0); } } | |
281 | |
282 /* This is the main sound chunk, strip of any extra data that does not fit | |
283 the alignment requirements and move these bytes into the leftover buffer*/ | |
284 if (parsestate.audio.isdata) { | |
285 int rc = *sz; | |
286 *outbuf = *data; | |
287 if ((parsestate.audio.left = rc % parsestate.audio.align) != 0) { | |
288 memmove(parsestate.audio.leftover, | |
289 (char *)*outbuf + rc - parsestate.audio.left, | |
290 parsestate.audio.left); | |
291 rc -= parsestate.audio.left; } | |
292 *sz = 0; | |
293 return(rc); } | |
294 | |
295 /* This is the first invocation of this function; we need to parse the | |
296 header information and determine how many bytes we need to skip until | |
297 the start of the sound chunk */ | |
298 if (!parsestate.audio.skipping) { | |
299 unsigned char *header = (unsigned char *) *data; | |
300 if (*sz < 8) { | |
301 warn("Irrecoverable error while parsing Sun/DEC audio file"); | |
302 return(0); } | |
303 /* Keep compatibility with Linux 68k, etc. by not relying on byte-sex */ | |
304 if (header[3]) { /* Sun audio (big endian) */ | |
305 parsestate.audio.align = ((header[15] > 2)+1)*header[23]; | |
306 parsestate.audio.skipping = header[7]+256*(header[6]+256* | |
307 (header[5]+256*header[4])); } | |
308 else { /* DEC audio (little endian) */ | |
309 parsestate.audio.align = ((header[12] > 2)+1)*header[20]; | |
310 parsestate.audio.skipping = header[4]+256*(header[5]+256* | |
311 (header[6]+256*header[7])); }} | |
312 | |
313 /* We are skipping extra data that has been attached to header; most usually | |
314 this will be just a comment, such as the original filename and/or the | |
315 creation date. Make sure that we do not return less than one single sound | |
316 sample entry to the caller; if this happens, rather decide to move those | |
317 few bytes into the leftover buffer and deal with it later */ | |
318 if (*sz >= (size_t) parsestate.audio.skipping) { | |
319 /* Skip just the header information and return the sound chunk */ | |
320 int rc = *sz - parsestate.audio.skipping; | |
321 *outbuf = (char *)*data + parsestate.audio.skipping; | |
322 if ((parsestate.audio.left = rc % parsestate.audio.align) != 0) { | |
323 memmove(parsestate.audio.leftover, | |
324 (char *)*outbuf + rc - parsestate.audio.left, | |
325 parsestate.audio.left); | |
326 rc -= parsestate.audio.left; } | |
327 *sz = 0; | |
328 parsestate.audio.skipping = 0; | |
329 parsestate.audio.isdata++; | |
330 return(rc); } | |
331 else { | |
332 /* Skip everything */ | |
333 parsestate.audio.skipping -= *sz; | |
334 return(0); } | |
335 } | |
336 | |
337 /* If the soundcard could not be set to natively support the data format, we | |
338 try to do some limited on-the-fly conversion to a different format; if | |
339 no conversion is needed, though, we can output directly */ | |
340 size_t sndcnvnop(void **data,size_t *sz,void **outbuf) | |
341 { | |
342 int rc = *sz; | |
343 | |
344 *outbuf = *data; | |
345 *sz = 0; | |
346 return(rc); | |
347 } | |
348 | |
349 /* Convert 8 bit unsigned stereo data to 8 bit unsigned mono data */ | |
350 size_t sndcnv8U_2mono(void **data,size_t *sz,void **outbuf) | |
351 { | |
352 REGISTER unsigned char *src; | |
353 REGISTER unsigned char *dest; | |
354 int rc,count; | |
355 | |
356 count = *sz / 2; | |
357 if (count > SNDBUFSZ) { *sz -= 2*SNDBUFSZ; count = SNDBUFSZ; } | |
358 else *sz = 0; | |
359 rc = count; | |
360 src = (unsigned char *) *data; | |
361 *outbuf = | |
362 dest = miscplay_sndbuf; | |
363 while (count--) | |
364 *dest++ = (unsigned char)(((int)*(src)++ + | |
365 (int)*(src)++) / 2); | |
366 *data = src; | |
367 return(rc); | |
368 } | |
369 | |
370 /* Convert 8 bit signed stereo data to 8 bit signed mono data */ | |
371 size_t sndcnv8S_2mono(void **data,size_t *sz,void **outbuf) | |
372 { | |
373 REGISTER unsigned char *src; | |
374 REGISTER unsigned char *dest; | |
375 int rc, count; | |
376 | |
377 count = *sz / 2; | |
378 if (count > SNDBUFSZ) { *sz -= 2*SNDBUFSZ; count = SNDBUFSZ; } | |
379 else *sz = 0; | |
380 rc = count; | |
381 src = (unsigned char *) *data; | |
382 *outbuf = | |
383 dest = miscplay_sndbuf; | |
384 while (count--) | |
385 *dest++ = (unsigned char)(((int)*((signed char *)(src++)) + | |
386 (int)*((signed char *)(src++))) / 2); | |
387 *data = src; | |
388 return(rc); | |
389 } | |
390 | |
391 /* Convert 8 bit signed stereo data to 8 bit unsigned mono data */ | |
392 size_t sndcnv2monounsigned(void **data,size_t *sz,void **outbuf) | |
393 { | |
394 REGISTER unsigned char *src; | |
395 REGISTER unsigned char *dest; | |
396 int rc,count; | |
397 | |
398 count = *sz / 2; | |
399 if (count > SNDBUFSZ) { *sz -= 2*SNDBUFSZ; count = SNDBUFSZ; } | |
400 else *sz = 0; | |
401 rc = count; | |
402 src = (unsigned char *) *data; | |
403 *outbuf = | |
404 dest = miscplay_sndbuf; | |
405 while (count--) | |
406 *dest++ = (unsigned char)(((int)*((signed char *)(src++)) + | |
407 (int)*((signed char *)(src++))) / 2) ^ 0x80; | |
408 *data = src; | |
409 return(rc); | |
410 } | |
411 | |
412 /* Convert 8 bit signed mono data to 8 bit unsigned mono data */ | |
413 size_t sndcnv2unsigned(void **data,size_t *sz,void **outbuf) | |
414 { | |
415 REGISTER unsigned char *src; | |
416 REGISTER unsigned char *dest; | |
417 int rc,count; | |
418 | |
419 count = *sz; | |
420 if (count > SNDBUFSZ) { *sz -= SNDBUFSZ; count = SNDBUFSZ; } | |
421 else *sz = 0; | |
422 rc = count; | |
423 src = (unsigned char *) *data; | |
424 *outbuf = | |
425 dest = miscplay_sndbuf; | |
426 while (count--) | |
427 *dest++ = *(src)++ ^ 0x80; | |
428 *data = src; | |
429 return(rc); | |
430 } | |
431 | |
432 /* Convert a number in the range -32768..32767 to an 8 bit ulaw encoded | |
433 number --- I hope, I got this conversion right :-) */ | |
434 static __inline__ signed char int2ulaw(int i) | |
435 { | |
436 /* Lookup table for fast calculation of number of bits that need shifting*/ | |
437 static short int t_bits[128] = { | |
438 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, | |
439 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, | |
440 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, | |
441 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}; | |
442 REGISTER int bits,logi; | |
443 | |
444 /* unrolling this condition (hopefully) improves execution speed */ | |
445 if (i < 0) { | |
446 if ((i = (132-i)) > 0x7FFF) i = 0x7FFF; | |
447 logi = (i >> ((bits = t_bits[i/256])+4)); | |
448 return((bits << 4 | logi) ^ 0x7F); } | |
449 else { | |
450 if ((i = 132+i) > 0x7FFF) i = 0x7FFF; | |
451 logi = (i >> ((bits = t_bits[i/256])+4)); | |
452 return(~(bits << 4 | logi)); } | |
453 } | |
454 | |
455 /* Convert from 8 bit ulaw mono to 8 bit linear mono */ | |
456 size_t sndcnvULaw_2linear(void **data,size_t *sz,void **outbuf) | |
457 { | |
458 /* conversion table stolen from Linux's ulaw.h */ | |
459 static unsigned char ulaw_dsp[] = { | |
460 3, 7, 11, 15, 19, 23, 27, 31, | |
461 35, 39, 43, 47, 51, 55, 59, 63, | |
462 66, 68, 70, 72, 74, 76, 78, 80, | |
463 82, 84, 86, 88, 90, 92, 94, 96, | |
464 98, 99, 100, 101, 102, 103, 104, 105, | |
465 106, 107, 108, 109, 110, 111, 112, 113, | |
466 113, 114, 114, 115, 115, 116, 116, 117, | |
467 117, 118, 118, 119, 119, 120, 120, 121, | |
468 121, 121, 122, 122, 122, 122, 123, 123, | |
469 123, 123, 124, 124, 124, 124, 125, 125, | |
470 125, 125, 125, 125, 126, 126, 126, 126, | |
471 126, 126, 126, 126, 127, 127, 127, 127, | |
472 127, 127, 127, 127, 127, 127, 127, 127, | |
473 128, 128, 128, 128, 128, 128, 128, 128, | |
474 128, 128, 128, 128, 128, 128, 128, 128, | |
475 128, 128, 128, 128, 128, 128, 128, 128, | |
476 253, 249, 245, 241, 237, 233, 229, 225, | |
477 221, 217, 213, 209, 205, 201, 197, 193, | |
478 190, 188, 186, 184, 182, 180, 178, 176, | |
479 174, 172, 170, 168, 166, 164, 162, 160, | |
480 158, 157, 156, 155, 154, 153, 152, 151, | |
481 150, 149, 148, 147, 146, 145, 144, 143, | |
482 143, 142, 142, 141, 141, 140, 140, 139, | |
483 139, 138, 138, 137, 137, 136, 136, 135, | |
484 135, 135, 134, 134, 134, 134, 133, 133, | |
485 133, 133, 132, 132, 132, 132, 131, 131, | |
486 131, 131, 131, 131, 130, 130, 130, 130, | |
487 130, 130, 130, 130, 129, 129, 129, 129, | |
488 129, 129, 129, 129, 129, 129, 129, 129, | |
489 128, 128, 128, 128, 128, 128, 128, 128, | |
490 128, 128, 128, 128, 128, 128, 128, 128, | |
491 128, 128, 128, 128, 128, 128, 128, 128, | |
492 }; | |
493 unsigned char *p=(unsigned char *)*data; | |
494 | |
495 *outbuf = *data; | |
496 while ((*sz)--) | |
497 *p++ = ulaw_dsp[*p]; | |
498 *sz = 0; | |
499 *data = p; | |
500 return p - (unsigned char *)*outbuf; | |
501 } | |
502 | |
503 /* Convert 8 bit ulaw stereo data to 8 bit ulaw mono data */ | |
504 size_t sndcnvULaw_2mono(void **data,size_t *sz,void **outbuf) | |
505 { | |
506 | |
507 static short int ulaw2int[256] = { | |
508 /* Precomputed lookup table for conversion from ulaw to 15 bit signed */ | |
509 -16062,-15550,-15038,-14526,-14014,-13502,-12990,-12478, | |
510 -11966,-11454,-10942,-10430, -9918, -9406, -8894, -8382, | |
511 -7998, -7742, -7486, -7230, -6974, -6718, -6462, -6206, | |
512 -5950, -5694, -5438, -5182, -4926, -4670, -4414, -4158, | |
513 -3966, -3838, -3710, -3582, -3454, -3326, -3198, -3070, | |
514 -2942, -2814, -2686, -2558, -2430, -2302, -2174, -2046, | |
515 -1950, -1886, -1822, -1758, -1694, -1630, -1566, -1502, | |
516 -1438, -1374, -1310, -1246, -1182, -1118, -1054, -990, | |
517 -942, -910, -878, -846, -814, -782, -750, -718, | |
518 -686, -654, -622, -590, -558, -526, -494, -462, | |
519 -438, -422, -406, -390, -374, -358, -342, -326, | |
520 -310, -294, -278, -262, -246, -230, -214, -198, | |
521 -186, -178, -170, -162, -154, -146, -138, -130, | |
522 -122, -114, -106, -98, -90, -82, -74, -66, | |
523 -60, -56, -52, -48, -44, -40, -36, -32, | |
524 -28, -24, -20, -16, -12, -8, -4, +0, | |
525 +16062,+15550,+15038,+14526,+14014,+13502,+12990,+12478, | |
526 +11966,+11454,+10942,+10430, +9918, +9406, +8894, +8382, | |
527 +7998, +7742, +7486, +7230, +6974, +6718, +6462, +6206, | |
528 +5950, +5694, +5438, +5182, +4926, +4670, +4414, +4158, | |
529 +3966, +3838, +3710, +3582, +3454, +3326, +3198, +3070, | |
530 +2942, +2814, +2686, +2558, +2430, +2302, +2174, +2046, | |
531 +1950, +1886, +1822, +1758, +1694, +1630, +1566, +1502, | |
532 +1438, +1374, +1310, +1246, +1182, +1118, +1054, +990, | |
533 +942, +910, +878, +846, +814, +782, +750, +718, | |
534 +686, +654, +622, +590, +558, +526, +494, +462, | |
535 +438, +422, +406, +390, +374, +358, +342, +326, | |
536 +310, +294, +278, +262, +246, +230, +214, +198, | |
537 +186, +178, +170, +162, +154, +146, +138, +130, | |
538 +122, +114, +106, +98, +90, +82, +74, +66, | |
539 +60, +56, +52, +48, +44, +40, +36, +32, | |
540 +28, +24, +20, +16, +12, +8, +4, +0}; | |
541 | |
542 REGISTER unsigned char *src; | |
543 REGISTER unsigned char *dest; | |
544 int rc,count; | |
545 | |
546 count = *sz / 2; | |
547 if (count > SNDBUFSZ) { *sz -= 2*SNDBUFSZ; count = SNDBUFSZ; } | |
548 else *sz = 0; | |
549 rc = count; | |
550 src = (unsigned char *) *data; | |
551 *outbuf = | |
552 dest = miscplay_sndbuf; | |
553 while (count--) | |
554 /* it is not possible to directly interpolate between two ulaw encoded | |
555 data bytes, thus we need to convert to linear format first and later | |
556 we convert back to ulaw format */ | |
557 *dest++ = int2ulaw(ulaw2int[*(src)++] + | |
558 ulaw2int[*(src)++]); | |
559 *data = src; | |
560 return(rc); | |
561 } | |
562 | |
563 size_t sndcnv16swap(void **data,size_t *sz,void **outbuf) | |
564 { | |
565 size_t cnt = *sz / 2; | |
566 unsigned short *p; | |
567 | |
568 *outbuf = *data; | |
569 p = (unsigned short *) *outbuf; | |
570 while (cnt--) { | |
571 *p++ = ((*p & 0x00ff) << 8) | (*p >> 8); | |
572 } | |
573 *data = p; | |
574 cnt = *sz; | |
575 *sz = 0; | |
576 return cnt; | |
577 } | |
578 | |
579 /* Convert 16 bit little endian signed stereo data to 16 bit little endian | |
580 signed mono data */ | |
581 size_t sndcnv16_2monoLE(void **data,size_t *sz,void **outbuf) | |
582 { | |
583 REGISTER unsigned char *src; | |
584 REGISTER unsigned char *dest; | |
585 int rc,count; | |
586 signed short i; | |
587 | |
588 count = *sz / 2; | |
589 if (count > SNDBUFSZ) { *sz -= 2*SNDBUFSZ; count = SNDBUFSZ; } | |
590 else *sz = 0; | |
591 rc = count; | |
592 src = (unsigned char *) *data; | |
593 *outbuf = | |
594 dest = miscplay_sndbuf; | |
595 for (count /= 2; count--; ) { | |
596 i = ((int)(src[0]) + | |
597 256*(int)(src[1]) + | |
598 (int)(src[2]) + | |
599 256*(int)(src[3])) / 2; | |
600 src += 4; | |
601 *dest++ = (unsigned char)(i & 0xFF); | |
602 *dest++ = (unsigned char)((i / 256) & 0xFF); } | |
603 *data = src; | |
604 return(rc); | |
605 } | |
606 | |
607 /* Convert 16 bit big endian signed stereo data to 16 bit big endian | |
608 signed mono data */ | |
609 size_t sndcnv16_2monoBE(void **data,size_t *sz,void **outbuf) | |
610 { | |
611 REGISTER unsigned char *src; | |
612 REGISTER unsigned char *dest; | |
613 int rc,count; | |
614 signed short i; | |
615 | |
616 count = *sz / 2; | |
617 if (count > SNDBUFSZ) { *sz -= 2*SNDBUFSZ; count = SNDBUFSZ; } | |
618 else *sz = 0; | |
619 rc = count; | |
620 src = (unsigned char *) *data; | |
621 *outbuf = | |
622 dest = miscplay_sndbuf; | |
623 for (count /= 2; count--; ) { | |
624 i = ((int)(src[1]) + | |
625 256*(int)(src[0]) + | |
626 (int)(src[3]) + | |
627 256*(int)(src[2])) / 2; | |
628 src += 4; | |
629 *dest++ = (unsigned char)((i / 256) & 0xFF); | |
630 *dest++ = (unsigned char)(i & 0xFF); } | |
631 *data = src; | |
632 return(rc); | |
633 } | |
634 | |
635 /* Convert 16 bit little endian signed data to 8 bit unsigned data */ | |
636 size_t sndcnv2byteLE(void **data,size_t *sz,void **outbuf) | |
637 { | |
638 REGISTER unsigned char *src; | |
639 REGISTER unsigned char *dest; | |
640 int rc,count; | |
641 | |
642 count = *sz / 2; | |
643 if (count > SNDBUFSZ) { *sz -= 2*SNDBUFSZ; count = SNDBUFSZ; } | |
644 else *sz = 0; | |
645 rc = count; | |
646 src = (unsigned char *) *data; | |
647 *outbuf = | |
648 dest = miscplay_sndbuf; | |
649 while (count--) { | |
650 *dest++ = (unsigned char)(((signed char *)src)[1] ^ (signed char)0x80); | |
651 src += 2; | |
652 } | |
653 *data = src; | |
654 return(rc); | |
655 } | |
656 | |
657 /* Convert 16 bit big endian signed data to 8 bit unsigned data */ | |
658 size_t sndcnv2byteBE(void **data,size_t *sz,void **outbuf) | |
659 { | |
660 REGISTER unsigned char *src; | |
661 REGISTER unsigned char *dest; | |
662 int rc,count; | |
663 | |
664 count = *sz / 2; | |
665 if (count > SNDBUFSZ) { *sz -= 2*SNDBUFSZ; count = SNDBUFSZ; } | |
666 else *sz = 0; | |
667 rc = count; | |
668 src = (unsigned char *) *data; | |
669 *outbuf = | |
670 dest = miscplay_sndbuf; | |
671 while (count--) { | |
672 *dest++ = (unsigned char)(((signed char *)src)[0] ^ (signed char)0x80); | |
673 src += 2; | |
674 } | |
675 *data = src; | |
676 return(rc); | |
677 } | |
678 | |
679 /* Convert 16 bit little endian signed stereo data to 8 bit unsigned | |
680 mono data */ | |
681 size_t sndcnv2monobyteLE(void **data,size_t *sz,void **outbuf) | |
682 { | |
683 REGISTER unsigned char *src; | |
684 REGISTER unsigned char *dest; | |
685 int rc,count; | |
686 | |
687 count = *sz / 4; | |
688 if (count > SNDBUFSZ) { *sz -= 4*SNDBUFSZ; count = SNDBUFSZ; } | |
689 else *sz = 0; | |
690 rc = count; | |
691 src = (unsigned char *) *data; | |
692 *outbuf = | |
693 dest = miscplay_sndbuf; | |
694 while (count--) { | |
695 *dest++ = (unsigned char)(((int)((signed char *)src)[1] + | |
696 (int)((signed char *)src)[3]) / 2 ^ 0x80); | |
697 src += 4; | |
698 } | |
699 *data = src; | |
700 return(rc); | |
701 } | |
702 | |
703 /* Convert 16 bit big endian signed stereo data to 8 bit unsigned | |
704 mono data */ | |
705 size_t sndcnv2monobyteBE(void **data,size_t *sz,void **outbuf) | |
706 { | |
707 REGISTER unsigned char *src; | |
708 REGISTER unsigned char *dest; | |
709 int rc,count; | |
710 | |
711 count = *sz / 4; | |
712 if (count > SNDBUFSZ) { *sz -= 4*SNDBUFSZ; count = SNDBUFSZ; } | |
713 else *sz = 0; | |
714 rc = count; | |
715 src = (unsigned char *) *data; | |
716 *outbuf = | |
717 dest = miscplay_sndbuf; | |
718 while (count--) { | |
719 *dest++ = (unsigned char)(((int)((signed char *)src)[0] + | |
720 (int)((signed char *)src)[2]) / 2 ^ 0x80); | |
721 src += 4; | |
722 } | |
723 *data = src; | |
724 return(rc); | |
725 } | |
726 | |
727 /* Look at the header of the sound file and try to determine the format; | |
728 we can recognize files in VOC, WAVE, and, Sun/DEC-audio format--- everything | |
729 else is assumed to be raw 8 bit unsigned data sampled at 8kHz */ | |
730 fmtType analyze_format(unsigned char *format,int *fmt,int *speed, | |
731 int *tracks, | |
732 size_t (**parsesndfile)(void **,size_t *sz, | |
733 void **)) | |
734 { | |
735 /* Keep compatibility with Linux 68k, etc. by not relying on byte-sex */ | |
736 if (!memcmp(format,"Creative Voice File\x1A\x1A\x00",22) && | |
737 (format[22]+256*format[23]) == | |
738 ((0x1233-format[24]-256*format[25])&0xFFFF)) { /* VOC */ | |
739 *fmt = AFMT_U8; | |
740 *speed = 8000; | |
741 *tracks = 2; | |
742 *parsesndfile = parsevoc; | |
743 return(fmtVoc); } | |
744 else if (!memcmp(format,"RIFF",4) && | |
745 !memcmp(format+8,"WAVEfmt ",8)) { /* WAVE */ | |
746 if (memcmp(format+20,"\001\000\001"/* PCM mono */,4) && | |
747 memcmp(format+20,"\001\000\002"/* PCM stereo */,4)) | |
748 return(fmtIllegal); | |
749 *fmt = (format[32]/(*tracks = format[22])) == 1 ? | |
750 AFMT_U8 : AFMT_S16_LE; | |
751 /* Keep compatibility with Linux 68k, etc. by not relying on byte-sex */ | |
752 *speed = format[24]+256*(format[25]+256* | |
753 (format[26]+256*format[27])); | |
754 *parsesndfile = parsewave; | |
755 return(fmtWave); } | |
756 else if (!memcmp(format,".snd",4)) { /* Sun Audio (big endian) */ | |
757 if (format[7]+256*(format[6]+256*(format[5]+256*format[4])) < 24) { | |
758 *fmt = AFMT_MU_LAW; | |
759 *speed = 8000; | |
760 *tracks = 1; | |
761 *parsesndfile = parsesundecaudio; | |
762 return(fmtSunAudio); } | |
763 if (!memcmp(format+12,"\000\000\000\001",4)) *fmt = AFMT_MU_LAW; | |
764 else if (!memcmp(format+12,"\000\000\000\002",4)) *fmt = AFMT_S8; | |
765 else if (!memcmp(format+12,"\000\000\000\003",4)) *fmt = AFMT_S16_BE; | |
766 else return(fmtIllegal); | |
767 /* Keep compatibility with Linux 68k, etc. by not relying on byte-sex */ | |
768 *speed = format[19]+256*(format[18]+256* | |
769 (format[17]+256*format[16])); | |
770 *tracks = format[23]; | |
771 *parsesndfile = parsesundecaudio; | |
772 return(fmtSunAudio); } | |
773 else if (!memcmp(format,".sd",4)) { /* DEC Audio (little endian) */ | |
774 if (format[4]+256*(format[5]+256*(format[6]+256*format[7])) < 24) { | |
775 *fmt = AFMT_MU_LAW; | |
776 *speed = 8000; | |
777 *tracks = 1; | |
778 *parsesndfile = parsesundecaudio; | |
779 return(fmtSunAudio); } | |
780 if (!memcmp(format+12,"\001\000\000",4)) *fmt = AFMT_MU_LAW; | |
781 else if (!memcmp(format+12,"\002\000\000",4)) *fmt = AFMT_S8; | |
782 else if (!memcmp(format+12,"\003\000\000",4)) *fmt = AFMT_S16_LE; | |
783 else return(fmtIllegal); | |
784 /* Keep compatibility with Linux 68k, etc. by not relying on byte-sex */ | |
785 *speed = format[16]+256*(format[17]+256* | |
786 (format[18]+256*format[19])); | |
787 *tracks = format[20]; | |
788 *parsesndfile = parsesundecaudio; | |
789 return(fmtSunAudio); } | |
790 else { | |
791 *fmt = AFMT_U8; | |
792 *speed = 8000; | |
793 *tracks = 1; | |
794 *parsesndfile = parseraw; | |
795 return(fmtRaw); } | |
796 } |