Mercurial > hg > xemacs-beta
annotate src/nas.c @ 5802:236e4afc565d
Autoload within #'keymapp, as documented.
src/ChangeLog addition:
2014-07-02 Aidan Kehoe <kehoea@parhasard.net>
* keymap.c (Fkeymapp):
Autoload within this, as documented. Our callers are not prepared
to do the intelligent thing if a symbol that is fboundp to an
autoloaded keymap, is not itself #'keymapp.
lisp/ChangeLog addition:
2014-07-02 Aidan Kehoe <kehoea@parhasard.net>
* byte-optimize.el (side-effect-free-fns):
#'keymapp is not side-effect-free, it can autoload.
author | Aidan Kehoe <kehoea@parhasard.net> |
---|---|
date | Wed, 02 Jul 2014 17:45:49 +0100 |
parents | 8b63e21b0436 |
children |
rev | line source |
---|---|
428 | 1 /* nas.c --- XEmacs support for the Network Audio System server. |
2 * | |
3 * Author: Richard Caley <R.Caley@ed.ac.uk> | |
4 * | |
5 * Copyright 1994 Free Software Foundation, Inc. | |
6 * Copyright 1993 Network Computing Devices, Inc. | |
7 * | |
8 * Permission to use, copy, modify, distribute, and sell this software and | |
9 * its documentation for any purpose is hereby granted without fee, provided | |
10 * that the above copyright notice appear in all copies and that both that | |
11 * copyright notice and this permission notice appear in supporting | |
12 * documentation, and that the name Network Computing Devices, Inc. not be | |
2108 | 13 * used in advertising or publicity pertaining to distribution of this |
428 | 14 * software without specific, written prior permission. |
2108 | 15 * |
428 | 16 * THIS SOFTWARE IS PROVIDED 'AS-IS'. NETWORK COMPUTING DEVICES, INC., |
17 * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING WITHOUT | |
18 * LIMITATION ALL IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A | |
19 * PARTICULAR PURPOSE, OR NONINFRINGEMENT. IN NO EVENT SHALL NETWORK | |
20 * COMPUTING DEVICES, INC., BE LIABLE FOR ANY DAMAGES WHATSOEVER, INCLUDING | |
21 * SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES, INCLUDING LOSS OF USE, DATA, | |
22 * OR PROFITS, EVEN IF ADVISED OF THE POSSIBILITY THEREOF, AND REGARDLESS OF | |
23 * WHETHER IN AN ACTION IN CONTRACT, TORT OR NEGLIGENCE, ARISING OUT OF OR IN | |
24 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |
25 */ | |
26 | |
27 /* Synched up with: Not in FSF. */ | |
28 | |
563 | 29 /* This file Mule-ized by Ben Wing, 5-15-01. */ |
30 | |
428 | 31 /* There are four compile-time options. |
32 * | |
33 * XTOOLKIT This will be part of an Xt program. | |
2108 | 34 * |
428 | 35 * XTEVENTS The playing will be supervised asynchronously by the Xt event |
36 * loop. If not set, playing will be completed within the call | |
2108 | 37 * to play_file etc. |
428 | 38 * |
39 * ROBUST_PLAY Causes errors in nas to be caught. This means that the | |
40 * program will attempt not to die if the nas server does. | |
41 * | |
42 * CACHE_SOUNDS Causes the sounds to be played in buckets in the NAS | |
43 * server. They are named by their comment field, or if that is | |
44 * empty by the filename, or for play_sound_data by a name made up | |
45 * from the sample itself. | |
46 */ | |
47 | |
48 /* CHANGES: | |
49 * 10/8/94, rjc Changed names from netaudio to nas | |
50 * Added back asynchronous play if nas library has | |
51 * correct error facilities. | |
52 * 4/11/94, rjc Added wait_for_sounds to be called when user wants to | |
53 * be sure all play has finished. | |
54 * 1998-10-01 rlt Added support for WAVE files. | |
1097 | 55 * 2002-10-16 Jon Trulson modifed this to work with NAS releases |
56 * 1.5f and higher. We were using the private variable | |
57 * SoundFileInfo that doesn't exist anymore. But preserve | |
58 * backward compatibility. This will not work for some | |
59 * versions of NAS around 1.5b to 1.5f or so. Known to | |
60 * work on 1.2p5 and 1.6. | |
428 | 61 */ |
62 | |
63 #include <config.h> | |
64 #include "lisp.h" | |
563 | 65 |
66 #include "sound.h" | |
67 | |
428 | 68 #include "sysdep.h" |
69 #include "syssignal.h" | |
70 | |
442 | 71 /* NAS <= 1.2p5 defines {BIG,LITTLE}_ENDIAN in <audio/fileutil.h>, |
72 conflicting with GNU libc (at least); newer versions avoid this | |
73 name space pollution. | |
428 | 74 |
442 | 75 DO NOT USE THOSE MACROS in this file. Use NAS_{BIG,LITTLE}_ENDIAN. |
76 | |
77 It would be slightly more reliable to do this via configure, but that | |
78 seems unnecessarily complex. | |
79 */ | |
428 | 80 #undef LITTLE_ENDIAN |
81 #undef BIG_ENDIAN | |
442 | 82 |
2119 | 83 BEGIN_C_DECLS |
428 | 84 #include <audio/audiolib.h> |
85 #include <audio/soundlib.h> | |
86 #include <audio/snd.h> | |
87 #include <audio/wave.h> | |
88 #include <audio/fileutil.h> | |
2119 | 89 END_C_DECLS |
2110 | 90 |
428 | 91 |
442 | 92 /* NAS <= 1.2p5 <audio/fileutil.h> doesn't define the NAS_ versions */ |
93 #ifndef NAS_LITTLE_ENDIAN | |
613 | 94 # define NAS_LITTLE_ENDIAN LITTLE_ENDIAN |
95 # define NAS_BIG_ENDIAN BIG_ENDIAN | |
442 | 96 #endif |
97 | |
613 | 98 #define XTOOLKIT |
99 #define XTEVENTS | |
100 #define ROBUST_PLAY | |
101 #define CACHE_SOUNDS | |
428 | 102 |
103 /* | |
104 * For old NAS libraries, force playing to be synchronous | |
105 * and declare the long jump point locally. | |
106 */ | |
107 | |
613 | 108 #if defined (NAS_NO_ERROR_JUMP) |
109 # undef XTEVENTS | |
110 # include <setjmp.h> | |
111 jmp_buf AuXtErrorJump; | |
112 #endif | |
428 | 113 |
114 #ifdef XTOOLKIT | |
613 | 115 # include <X11/Intrinsic.h> |
116 # include <audio/Xtutil.h> | |
428 | 117 #endif |
118 | |
1746 | 119 /* audiolib <= some version doesn't define major and minor versions */ |
120 /* Do NOT use AudioLibraryVersion in this file. */ | |
121 #ifndef AudioLibraryVersion | |
122 #define AudioLibraryVersion 1 | |
123 #endif | |
124 #ifndef AudioLibraryVersionMajor | |
125 #define AudioLibraryVersionMajor AudioLibraryVersion | |
126 #endif | |
127 #ifndef AudioLibraryVersionMinor | |
128 #define AudioLibraryVersionMinor 0 | |
129 #endif | |
130 | |
428 | 131 #if defined (ROBUST_PLAY) |
132 static AuBool CatchIoErrorAndJump (AuServer *aud); | |
133 static AuBool CatchErrorAndJump (AuServer *aud, AuErrorEvent *event); | |
134 SIGTYPE sigpipe_handle (int signo); | |
135 #endif | |
136 | |
137 extern Lisp_Object Vsynchronous_sounds; | |
138 | |
2367 | 139 static Sound SoundOpenDataForReading (Binbyte *data, int length); |
428 | 140 |
141 static AuServer *aud; | |
142 | |
143 /* count of sounds currently being played. */ | |
144 static int sounds_in_play; | |
145 | |
146 | |
147 #ifdef XTOOLKIT | |
148 static Display *aud_server; | |
149 static XtInputId input_id; | |
150 #else | |
563 | 151 static Extbyte *aud_server; |
428 | 152 #endif /* XTOOLKIT */ |
153 | |
563 | 154 Extbyte * |
613 | 155 nas_init_play ( |
428 | 156 #ifdef XTOOLKIT |
157 Display *display | |
158 #else | |
563 | 159 Extbyte *server |
428 | 160 #endif |
432 | 161 ); |
563 | 162 Extbyte * |
613 | 163 nas_init_play ( |
432 | 164 #ifdef XTOOLKIT |
165 Display *display | |
166 #else | |
563 | 167 Extbyte *server |
432 | 168 #endif |
428 | 169 ) |
170 { | |
563 | 171 Extbyte *err_message; |
432 | 172 SIGTYPE (*old_sigpipe) (int); |
428 | 173 |
174 #ifdef XTOOLKIT | |
563 | 175 Extbyte * server = DisplayString (display); |
428 | 176 XtAppContext app_context = XtDisplayToApplicationContext (display); |
177 | |
178 aud_server = display; | |
179 #else | |
180 | |
181 aud_server = server; | |
182 #endif | |
183 | |
184 #ifdef ROBUST_PLAY | |
613 | 185 old_sigpipe = EMACS_SIGNAL (SIGPIPE, sigpipe_handle); |
428 | 186 if (setjmp (AuXtErrorJump)) |
187 { | |
613 | 188 EMACS_SIGNAL (SIGPIPE, old_sigpipe); |
428 | 189 start_interrupts (); |
4932 | 190 return (Extbyte *) "error in NAS"; |
428 | 191 } |
192 #endif | |
193 | |
194 #if defined (ROBUST_PLAY) && !defined (NAS_NO_ERROR_JUMP) | |
195 AuDefaultIOErrorHandler = CatchIoErrorAndJump; | |
196 AuDefaultErrorHandler = CatchErrorAndJump; | |
197 #endif | |
198 | |
199 stop_interrupts (); | |
200 aud = AuOpenServer (server, 0, NULL, 0, NULL, &err_message); | |
201 start_interrupts (); | |
202 if (!aud) | |
203 { | |
204 #ifdef ROBUST_PLAY | |
613 | 205 EMACS_SIGNAL (SIGPIPE, old_sigpipe); |
428 | 206 #endif |
207 if (err_message == NULL) | |
4932 | 208 return (Extbyte *) "Can't connect to audio server"; |
428 | 209 else |
210 return err_message; | |
211 } | |
212 | |
213 #if defined (ROBUST_PLAY) | |
214 # if defined (NAS_NO_ERROR_JUMP) | |
215 aud->funcs.ioerror_handler = CatchIoErrorAndJump; | |
216 aud->funcs.error_handler = CatchErrorAndJump; | |
217 # else /* !NAS_NO_ERROR_JUMP */ | |
218 AuDefaultIOErrorHandler = NULL; | |
219 AuDefaultErrorHandler = NULL; | |
220 # endif | |
221 #endif | |
222 | |
223 #ifdef XTEVENTS | |
2108 | 224 input_id = AuXtAppAddAudioHandler (app_context, aud); |
428 | 225 #endif |
226 | |
227 #ifdef CACHE_SOUNDS | |
228 AuSetCloseDownMode (aud, AuCloseDownRetainPermanent, NULL); | |
229 #endif | |
230 | |
231 #ifdef ROBUST_PLAY | |
613 | 232 EMACS_SIGNAL (SIGPIPE, old_sigpipe); |
428 | 233 #endif |
234 | |
235 sounds_in_play = 0; | |
236 | |
237 return NULL; | |
238 } | |
239 | |
4824
c12b646d84ee
changes to get things to compile under latest cygwin
Ben Wing <ben@xemacs.org>
parents:
3462
diff
changeset
|
240 # if 0 /* not currently used */ |
c12b646d84ee
changes to get things to compile under latest cygwin
Ben Wing <ben@xemacs.org>
parents:
3462
diff
changeset
|
241 |
432 | 242 static void |
613 | 243 nas_close_down_play (void) |
428 | 244 |
245 { | |
246 AuCloseServer (aud); | |
563 | 247 sound_warn ("disconnected from audio server"); |
428 | 248 } |
249 | |
4824
c12b646d84ee
changes to get things to compile under latest cygwin
Ben Wing <ben@xemacs.org>
parents:
3462
diff
changeset
|
250 #endif |
c12b646d84ee
changes to get things to compile under latest cygwin
Ben Wing <ben@xemacs.org>
parents:
3462
diff
changeset
|
251 |
428 | 252 /********************************************************************\ |
253 * * | |
254 * Callback which is run when the sound finishes playing. * | |
255 * * | |
256 \********************************************************************/ | |
257 | |
258 static void | |
2286 | 259 doneCB (AuServer *UNUSED (auserver), |
260 AuEventHandlerRec *UNUSED (handler), | |
261 AuEvent *UNUSED (ev), | |
428 | 262 AuPointer data) |
263 { | |
264 int *in_play_p = (int *) data; | |
265 | |
266 (*in_play_p) --; | |
267 } | |
268 | |
269 #ifdef CACHE_SOUNDS | |
270 | |
271 /********************************************************************\ | |
272 * * | |
273 * Play a sound by playing the relevant bucket, if any or * | |
274 * downloading it if not. * | |
275 * * | |
276 \********************************************************************/ | |
277 | |
278 static void | |
279 do_caching_play (Sound s, | |
280 int volume, | |
2367 | 281 Binbyte *buf) |
428 | 282 |
283 { | |
284 AuBucketAttributes *list, b; | |
285 AuBucketID id; | |
286 int n; | |
287 | |
288 AuSetString (AuBucketDescription (&b), | |
289 AuStringLatin1, strlen (SoundComment (s)), SoundComment (s)); | |
290 | |
291 list = AuListBuckets (aud, AuCompCommonDescriptionMask, &b, &n, NULL); | |
292 | |
293 if (list == NULL) | |
294 { | |
432 | 295 AuPointer my_buf; |
428 | 296 |
297 if (buf==NULL) | |
298 { | |
432 | 299 if ((my_buf= (AuPointer) malloc (SoundNumBytes (s)))==NULL) |
428 | 300 { |
301 return; | |
302 } | |
303 | |
563 | 304 if (SoundReadFile ((Extbyte *) my_buf, SoundNumBytes (s), s) != SoundNumBytes (s)) |
428 | 305 { |
306 free (my_buf); | |
307 return; | |
308 } | |
309 } | |
310 else | |
432 | 311 my_buf = (AuPointer) buf; |
428 | 312 |
2108 | 313 id = AuSoundCreateBucketFromData (aud, |
428 | 314 s, |
315 my_buf, | |
2108 | 316 AuAccessAllMasks, |
428 | 317 NULL, |
318 NULL); | |
319 if (buf == NULL) | |
320 free (my_buf); | |
321 } | |
322 else /* found cached sound */ | |
323 { | |
324 id = AuBucketIdentifier (list); | |
325 AuFreeBucketAttributes (aud, n, list); | |
326 } | |
327 | |
328 sounds_in_play++; | |
329 | |
2108 | 330 AuSoundPlayFromBucket (aud, |
331 id, | |
428 | 332 AuNone, |
2108 | 333 AuFixedPointFromFraction (volume, 100), |
428 | 334 doneCB, (AuPointer) &sounds_in_play, |
335 1, | |
336 NULL, NULL, | |
337 NULL, NULL); | |
338 | |
339 } | |
340 #endif /* CACHE_SOUNDS */ | |
341 | |
342 | |
613 | 343 void nas_wait_for_sounds (void); |
2108 | 344 void |
613 | 345 nas_wait_for_sounds (void) |
428 | 346 |
347 { | |
348 AuEvent ev; | |
349 | |
350 while (sounds_in_play>0) | |
351 { | |
352 AuNextEvent (aud, AuTrue, &ev); | |
353 AuDispatchEvent (aud, &ev); | |
354 } | |
355 } | |
356 | |
613 | 357 int nas_play_sound_file (Extbyte *sound_file, int volume); |
428 | 358 int |
613 | 359 nas_play_sound_file (Extbyte *sound_file, |
360 int volume) | |
428 | 361 { |
432 | 362 SIGTYPE (*old_sigpipe) (int); |
428 | 363 |
364 #ifdef ROBUST_PLAY | |
613 | 365 old_sigpipe = EMACS_SIGNAL (SIGPIPE, sigpipe_handle); |
428 | 366 if (setjmp (AuXtErrorJump)) |
367 { | |
613 | 368 EMACS_SIGNAL (SIGPIPE, old_sigpipe); |
428 | 369 return 0; |
370 } | |
371 #endif | |
372 | |
613 | 373 if (aud==NULL) |
374 { | |
375 if (aud_server != NULL) | |
376 { | |
377 Extbyte *m; | |
378 /* attempt to reconect */ | |
379 if ((m = nas_init_play (aud_server)) != NULL) | |
380 { | |
2108 | 381 |
428 | 382 #ifdef ROBUST_PLAY |
613 | 383 EMACS_SIGNAL (SIGPIPE, old_sigpipe); |
428 | 384 #endif |
613 | 385 return 0; |
386 } | |
387 } | |
388 else | |
389 { | |
390 sound_warn ("Attempt to play with no audio init\n"); | |
428 | 391 #ifdef ROBUST_PLAY |
613 | 392 EMACS_SIGNAL (SIGPIPE, old_sigpipe); |
428 | 393 #endif |
613 | 394 return 0; |
395 } | |
396 } | |
428 | 397 |
398 #ifndef CACHE_SOUNDS | |
399 sounds_in_play++; | |
400 AuSoundPlayFromFile (aud, | |
401 sound_file, | |
402 AuNone, | |
403 AuFixedPointFromFraction (volume,100), | |
404 doneCB, (AuPointer) &sounds_in_play, | |
405 NULL, | |
406 NULL, | |
407 NULL, | |
408 NULL); | |
409 #else | |
410 /* Cache the sounds in buckets on the server */ | |
411 | |
412 { | |
413 Sound s; | |
414 | |
415 if ((s = SoundOpenFileForReading (sound_file))==NULL) | |
416 { | |
417 #ifdef ROBUST_PLAY | |
613 | 418 EMACS_SIGNAL (SIGPIPE, old_sigpipe); |
428 | 419 #endif |
420 return 0; | |
421 } | |
422 | |
423 if (SoundComment (s) == NULL || SoundComment (s)[0] == '\0') | |
424 { | |
425 SoundComment (s) = FileCommentFromFilename (sound_file); | |
426 } | |
427 | |
428 do_caching_play (s, volume, NULL); | |
429 | |
430 SoundCloseFile (s); | |
431 | |
432 } | |
433 #endif /* CACHE_SOUNDS */ | |
434 | |
435 #ifndef XTEVENTS | |
613 | 436 nas_wait_for_sounds (); |
428 | 437 #else |
438 if (!NILP (Vsynchronous_sounds)) | |
613 | 439 nas_wait_for_sounds (); |
428 | 440 #endif |
441 | |
442 #ifdef ROBUST_PLAY | |
613 | 443 EMACS_SIGNAL (SIGPIPE, old_sigpipe); |
428 | 444 #endif |
445 | |
446 return 1; | |
447 } | |
448 | |
2367 | 449 int nas_play_sound_data (Binbyte *data, int length, int volume); |
428 | 450 int |
2367 | 451 nas_play_sound_data (Binbyte *data, int length, int volume) |
428 | 452 { |
453 Sound s; | |
454 int offset; | |
432 | 455 SIGTYPE (*old_sigpipe) (int); |
428 | 456 |
457 #if !defined (XTEVENTS) | |
458 AuEvent ev; | |
459 #endif | |
460 | |
461 #ifdef ROBUST_PLAY | |
613 | 462 old_sigpipe = EMACS_SIGNAL (SIGPIPE, sigpipe_handle); |
463 if (setjmp (AuXtErrorJump) != 0) | |
428 | 464 { |
613 | 465 EMACS_SIGNAL (SIGPIPE, old_sigpipe); |
428 | 466 return 0; |
467 } | |
468 #endif | |
469 | |
470 | |
471 if (aud == NULL) { | |
472 if (aud_server != NULL) | |
473 { | |
563 | 474 Extbyte *m; |
428 | 475 /* attempt to reconect */ |
613 | 476 if ((m = nas_init_play (aud_server)) != NULL) |
428 | 477 { |
478 #ifdef ROBUST_PLAY | |
613 | 479 EMACS_SIGNAL (SIGPIPE, old_sigpipe); |
428 | 480 #endif |
481 return 0; | |
482 } | |
483 } | |
484 else | |
485 { | |
563 | 486 sound_warn ("Attempt to play with no audio init\n"); |
428 | 487 #ifdef ROBUST_PLAY |
613 | 488 EMACS_SIGNAL (SIGPIPE, old_sigpipe); |
428 | 489 #endif |
490 return 0; | |
491 } | |
492 } | |
493 | |
494 if ((s=SoundOpenDataForReading (data, length))==NULL) | |
495 { | |
563 | 496 sound_warn ("unknown sound type"); |
428 | 497 #ifdef ROBUST_PLAY |
613 | 498 EMACS_SIGNAL (SIGPIPE, old_sigpipe); |
428 | 499 #endif |
500 return 0; | |
501 } | |
502 | |
503 if (SoundFileFormat (s) == SoundFileFormatSnd) | |
504 { | |
505 /* hack, hack */ | |
506 offset = ((SndInfo *) (s->formatInfo))->h.dataOffset; | |
507 } | |
508 else if (SoundFileFormat (s) == SoundFileFormatWave) | |
509 { | |
510 offset = ((WaveInfo *) (s->formatInfo))->dataOffset; | |
511 } | |
512 else | |
513 { | |
563 | 514 sound_warn ("only understand snd and wave files at the moment"); |
428 | 515 SoundCloseFile (s); |
516 #ifdef ROBUST_PLAY | |
613 | 517 EMACS_SIGNAL (SIGPIPE, old_sigpipe); |
428 | 518 #endif |
519 return 0; | |
520 } | |
521 | |
522 #ifndef CACHE_SOUNDS | |
523 sounds_in_play++; | |
524 AuSoundPlayFromData (aud, | |
525 s, | |
526 data+offset, | |
527 AuNone, | |
528 AuFixedPointFromFraction (volume,100), | |
529 doneCB, (AuPointer) &sounds_in_play, | |
530 NULL, | |
531 NULL, | |
532 NULL, | |
533 NULL); | |
534 #else | |
535 /* Cache the sounds in buckets on the server */ | |
536 | |
613 | 537 do_caching_play (s, volume, data+offset); |
428 | 538 #endif /* CACHE_SOUNDS */ |
539 | |
540 | |
541 #ifndef XTEVENTS | |
613 | 542 nas_wait_for_sounds (); |
428 | 543 #else |
544 if (!NILP (Vsynchronous_sounds)) | |
613 | 545 nas_wait_for_sounds (); |
428 | 546 #endif |
547 | |
2108 | 548 SoundCloseFile (s); |
428 | 549 |
550 #ifdef ROBUST_PLAY | |
613 | 551 EMACS_SIGNAL (SIGPIPE, old_sigpipe); |
428 | 552 #endif |
553 | |
554 return 1; | |
555 } | |
556 | |
557 #if defined (ROBUST_PLAY) | |
558 | |
559 /********************************************************************\ | |
560 * * | |
561 * Code to protect the client from server shutdowns. * | |
562 * * | |
563 * This is unbelievably horrible. * | |
564 * * | |
565 \********************************************************************/ | |
566 | |
567 static AuBool | |
568 CatchIoErrorAndJump (AuServer *old_aud) | |
569 { | |
570 if (old_aud) | |
2108 | 571 sound_warn ("Audio Server connection broken"); |
428 | 572 else |
563 | 573 sound_warn ("Audio Server connection broken because of signal"); |
428 | 574 |
575 #ifdef XTEVENTS | |
576 #ifdef XTOOLKIT | |
2108 | 577 AuXtAppRemoveAudioHandler (aud, input_id); |
428 | 578 #endif |
579 | |
580 if (aud) | |
581 AuCloseServer (aud); | |
582 aud = NULL; | |
583 sounds_in_play = 0; | |
584 | |
585 longjmp (AuXtErrorJump, 1); | |
586 | |
587 #else /* not XTEVENTS */ | |
588 | |
589 if (aud) | |
590 AuCloseServer (aud); | |
591 aud = NULL; | |
592 sounds_in_play = 0; | |
593 longjmp (AuXtErrorJump, 1); | |
2108 | 594 |
428 | 595 #endif /* XTEVENTS */ |
596 return 0; | |
597 } | |
598 | |
599 SIGTYPE | |
2286 | 600 sigpipe_handle (int UNUSED (signo)) |
428 | 601 { |
602 CatchIoErrorAndJump (NULL); | |
603 } | |
604 | |
605 static AuBool | |
606 CatchErrorAndJump (AuServer *old_aud, | |
2286 | 607 AuErrorEvent *UNUSED (event)) |
428 | 608 { |
609 return CatchIoErrorAndJump (old_aud); | |
610 } | |
611 | |
612 #endif /* ROBUST_PLAY */ | |
613 | |
614 /********************************************************************\ | |
615 * * | |
616 * This code is here because the nas Sound library doesn't * | |
617 * support playing from a file buffered in memory. It's a fairly * | |
618 * direct translation of the file-based equivalent. * | |
619 * * | |
620 * Since we don't have a filename, samples with no comment field * | |
621 * are named by a section of their content. * | |
622 * * | |
623 \********************************************************************/ | |
624 | |
625 /* Create a name from the sound. */ | |
626 | |
563 | 627 static Extbyte * |
2367 | 628 NameFromData (const CBinbyte *buf, |
428 | 629 int len) |
630 | |
631 { | |
563 | 632 Extbyte name[9]; |
428 | 633 int i; |
563 | 634 Extbyte *s; |
428 | 635 |
636 buf+=len/2; | |
637 len -= len/2; | |
638 | |
639 i=0; | |
640 while (i<8 && len >0) | |
641 { | |
642 while (*buf < 32 && len>0) | |
643 { | |
644 buf++; | |
645 len--; | |
646 } | |
647 name[i]= *buf; | |
648 i++; | |
649 buf++; | |
650 len--; | |
651 } | |
652 | |
653 name[i]='\0'; | |
654 | |
655 if (i==8) | |
656 { | |
563 | 657 strcpy (s = (Extbyte *) malloc (10), name); |
428 | 658 } |
2108 | 659 else |
428 | 660 { |
563 | 661 strcpy (s = (Extbyte *) malloc (15), "short sound"); |
428 | 662 } |
663 | |
664 return s; | |
665 } | |
666 | |
667 /* Code to do a pseudo-open on a data buffer. Only for snd files at the | |
2108 | 668 moment. |
428 | 669 */ |
670 | |
671 static SndInfo * | |
2367 | 672 SndOpenDataForReading (const CBinbyte *data, |
428 | 673 int length) |
674 | |
675 { | |
676 SndInfo *si; | |
677 int size; | |
678 | |
679 if (!(si = (SndInfo *) malloc (sizeof (SndInfo)))) | |
680 return NULL; | |
681 | |
682 si->comment = NULL; | |
683 si->writing = 0; | |
684 | |
685 memcpy (&si->h, data, sizeof (SndHeader)); | |
686 | |
442 | 687 if (NAS_LITTLE_ENDIAN) |
428 | 688 { |
2367 | 689 CBinbyte n; |
2108 | 690 |
428 | 691 swapl (&si->h.magic, n); |
692 swapl (&si->h.dataOffset, n); | |
693 swapl (&si->h.dataSize, n); | |
694 swapl (&si->h.format, n); | |
695 swapl (&si->h.sampleRate, n); | |
696 swapl (&si->h.tracks, n); | |
697 } | |
698 | |
699 if (si->h.magic != SND_MAGIC_NUM) | |
700 { | |
701 free (si); | |
702 return NULL; | |
703 } | |
704 | |
705 size = si->h.dataOffset - sizeof (SndHeader); | |
706 | |
707 if (size) | |
708 { | |
563 | 709 if (!(si->comment = (Extbyte *) malloc (size + 1))) |
428 | 710 { |
711 free (si); | |
712 return NULL; | |
713 } | |
714 | |
715 memcpy (si->comment, data+sizeof (SndHeader), size); | |
716 | |
717 *(si->comment + size) = 0; | |
718 if (*si->comment == '\0') | |
719 si->comment = | |
720 NameFromData (data+si->h.dataOffset, length-si->h.dataOffset); | |
721 } | |
722 else | |
723 si->comment = NameFromData (data+si->h.dataOffset, length-si->h.dataOffset); | |
724 | |
725 si->h.dataSize = length-si->h.dataOffset; | |
726 | |
727 si->fp=NULL; | |
728 | |
729 return si; | |
730 } | |
731 | |
732 /* Stuff taken from wave.c from NAS. Just like snd files, NAS can't | |
733 read wave data from memory, so these functions do that for us. */ | |
734 | |
3462 | 735 #define Err() { free(wi); return NULL; } |
428 | 736 #define readFourcc(_f) dread(_f, sizeof(RIFF_FOURCC), 1) |
737 #define cmpID(_x, _y) \ | |
2367 | 738 strncmp((CBinbyte *) (_x), (CBinbyte *) (_y), sizeof(RIFF_FOURCC)) |
428 | 739 #define PAD2(_x) (((_x) + 1) & ~1) |
740 | |
741 /* These functions here are for faking file I/O from buffer. */ | |
742 | |
743 /* The "file" position */ | |
432 | 744 static size_t file_posn; |
428 | 745 /* The length of the "file" */ |
432 | 746 static size_t file_len; |
428 | 747 /* The actual "file" data. */ |
442 | 748 static const void* file_data; |
428 | 749 |
750 /* Like fopen, but for a buffer in memory */ | |
751 static void | |
442 | 752 dopen (const void* data, size_t length) |
428 | 753 { |
754 file_data = data; | |
755 file_len = length; | |
756 file_posn = 0; | |
757 } | |
758 | |
759 /* Like fread, but for a buffer in memory */ | |
760 static int | |
432 | 761 dread (void* buf, size_t size, size_t nitems) |
428 | 762 { |
432 | 763 size_t nread = size * nitems; |
2108 | 764 |
428 | 765 if (file_posn + nread <= file_len) |
766 { | |
2367 | 767 memcpy(buf, (CBinbyte *) file_data + file_posn, size * nitems); |
428 | 768 file_posn += nread; |
769 return nitems; | |
770 } | |
771 else | |
772 { | |
773 return EOF; | |
774 } | |
775 } | |
776 | |
777 /* Like fgetc, but for a buffer in memory */ | |
778 static int | |
432 | 779 dgetc (void) |
428 | 780 { |
781 if (file_posn < file_len) | |
2367 | 782 return ((CBinbyte *)file_data)[file_posn++]; |
428 | 783 else |
784 return -1; | |
785 } | |
786 | |
787 /* Like fseek, but for a buffer in memory */ | |
788 static int | |
432 | 789 dseek (long offset, int from) |
428 | 790 { |
791 if (from == 0) | |
792 file_posn = offset; | |
793 else if (from == 1) | |
794 file_posn += offset; | |
795 else if (from == 2) | |
796 file_posn = file_len + offset; | |
797 | |
798 return 0; | |
799 } | |
800 | |
801 /* Like ftell, but for a buffer in memory */ | |
432 | 802 static long |
440 | 803 dtell (void) |
428 | 804 { |
805 return file_posn; | |
806 } | |
807 | |
808 /* Data buffer analogs for FileReadS and FileReadL in NAS. */ | |
809 | |
810 static unsigned short | |
440 | 811 DataReadS (int swapit) |
428 | 812 { |
613 | 813 unsigned short us; |
428 | 814 |
613 | 815 dread(&us, 2, 1); |
816 if (swapit) | |
817 us = FileSwapS(us); | |
818 return us; | |
428 | 819 } |
820 | |
821 static AuUint32 | |
440 | 822 DataReadL (int swapit) |
428 | 823 { |
613 | 824 AuUint32 ul; |
428 | 825 |
613 | 826 dread(&ul, 4, 1); |
827 if (swapit) | |
828 ul = FileSwapL(ul); | |
829 return ul; | |
428 | 830 } |
831 | |
832 static int | |
440 | 833 readChunk (RiffChunk *c) |
428 | 834 { |
613 | 835 int status; |
2367 | 836 CBinbyte n; |
428 | 837 |
613 | 838 if ((status = dread(c, sizeof(RiffChunk), 1))) |
839 if (NAS_BIG_ENDIAN) | |
840 swapl(&c->ckSize, n); | |
428 | 841 |
613 | 842 return status; |
428 | 843 } |
844 | |
845 /* A very straight-forward translation of WaveOpenFileForReading to | |
846 read the wave data from a buffer in memory. */ | |
847 | |
848 static WaveInfo * | |
2367 | 849 WaveOpenDataForReading (const CBinbyte *data, |
440 | 850 int length) |
428 | 851 { |
613 | 852 RiffChunk ck; |
853 RIFF_FOURCC fourcc; | |
854 AuInt32 fileSize; | |
855 WaveInfo *wi; | |
428 | 856 |
2108 | 857 |
613 | 858 if (!(wi = (WaveInfo *) malloc(sizeof(WaveInfo)))) |
859 return NULL; | |
428 | 860 |
613 | 861 wi->comment = NULL; |
862 wi->dataOffset = wi->format = wi->writing = 0; | |
428 | 863 |
613 | 864 dopen(data, length); |
2108 | 865 |
613 | 866 if (!readChunk(&ck) || |
867 cmpID(&ck.ckID, RIFF_RiffID) || | |
868 !readFourcc(&fourcc) || | |
869 cmpID(&fourcc, RIFF_WaveID)) | |
870 Err(); | |
871 | |
872 fileSize = PAD2(ck.ckSize) - sizeof(RIFF_FOURCC); | |
873 | |
1346 | 874 while (fileSize >= (AuInt32) sizeof(RiffChunk)) |
613 | 875 { |
876 if (!readChunk(&ck)) | |
428 | 877 Err(); |
878 | |
613 | 879 fileSize -= sizeof(RiffChunk) + PAD2(ck.ckSize); |
428 | 880 |
613 | 881 /* LIST chunk */ |
882 if (!cmpID(&ck.ckID, RIFF_ListID)) | |
883 { | |
884 if (!readFourcc(&fourcc)) | |
428 | 885 Err(); |
886 | |
613 | 887 /* INFO chunk */ |
888 if (!cmpID(&fourcc, RIFF_ListInfoID)) | |
889 { | |
890 ck.ckSize -= sizeof(RIFF_FOURCC); | |
428 | 891 |
613 | 892 while (ck.ckSize) |
893 { | |
894 RiffChunk c; | |
428 | 895 |
613 | 896 if (!readChunk(&c)) |
897 Err(); | |
428 | 898 |
613 | 899 /* ICMT chunk */ |
900 if (!cmpID(&c.ckID, RIFF_InfoIcmtID)) | |
901 { | |
902 if (!(wi->comment = (Extbyte *) malloc(c.ckSize)) || | |
903 !dread(wi->comment, c.ckSize, 1)) | |
428 | 904 Err(); |
905 | |
613 | 906 if (c.ckSize & 1) |
907 dgetc(); /* eat the pad byte */ | |
908 } | |
909 else | |
910 /* skip unknown chunk */ | |
911 dseek(PAD2(c.ckSize), 1); | |
428 | 912 |
613 | 913 ck.ckSize -= sizeof(RiffChunk) + PAD2(c.ckSize); |
428 | 914 } |
915 } | |
613 | 916 else |
917 /* skip unknown chunk */ | |
918 dseek(PAD2(ck.ckSize) - sizeof(RIFF_FOURCC), 1); | |
428 | 919 } |
613 | 920 /* wave format chunk */ |
921 else if (!cmpID(&ck.ckID, RIFF_WaveFmtID) && !wi->format) | |
428 | 922 { |
613 | 923 AuInt32 dummy; |
428 | 924 |
613 | 925 wi->format = DataReadS(NAS_BIG_ENDIAN); |
926 wi->channels = DataReadS(NAS_BIG_ENDIAN); | |
927 wi->sampleRate = DataReadL(NAS_BIG_ENDIAN); | |
428 | 928 |
613 | 929 /* we don't care about the next two fields */ |
930 dummy = DataReadL(NAS_BIG_ENDIAN); | |
931 dummy = DataReadS(NAS_BIG_ENDIAN); | |
428 | 932 |
613 | 933 if (wi->format != RIFF_WAVE_FORMAT_PCM) |
934 Err(); | |
428 | 935 |
613 | 936 wi->bitsPerSample = DataReadS(NAS_BIG_ENDIAN); |
428 | 937 |
613 | 938 /* skip any other format specific fields */ |
939 dseek(PAD2(ck.ckSize - 16), 1); | |
428 | 940 } |
613 | 941 /* wave data chunk */ |
942 else if (!cmpID(&ck.ckID, RIFF_WaveDataID) && !wi->dataOffset) | |
428 | 943 { |
613 | 944 long endOfFile; |
428 | 945 |
613 | 946 wi->dataOffset = dtell(); |
947 wi->dataSize = ck.ckSize; | |
948 dseek(0, 2); | |
949 endOfFile = dtell(); | |
428 | 950 |
613 | 951 /* seek past the data */ |
952 if (dseek(wi->dataOffset + PAD2(ck.ckSize), 0) || | |
953 dtell() > endOfFile) | |
428 | 954 { |
613 | 955 /* the seek failed, assume the size is bogus */ |
956 dseek(0, 2); | |
957 wi->dataSize = dtell() - wi->dataOffset; | |
428 | 958 } |
959 | |
613 | 960 wi->dataOffset -= sizeof(long); |
428 | 961 } |
613 | 962 else |
963 /* skip unknown chunk */ | |
964 dseek(PAD2(ck.ckSize), 1); | |
428 | 965 } |
966 | |
613 | 967 if (!wi->dataOffset) |
968 Err(); | |
428 | 969 |
613 | 970 wi->numSamples = wi->dataSize / wi->channels / (wi->bitsPerSample >> 3); |
428 | 971 |
613 | 972 if (!wi->comment) |
973 wi->comment = NameFromData (data + wi->dataOffset, | |
974 length - wi->dataOffset); | |
428 | 975 |
613 | 976 wi->fp = NULL; |
2108 | 977 |
613 | 978 return wi; |
428 | 979 } |
980 | |
981 | |
982 static Sound | |
2367 | 983 SoundOpenDataForReading (Binbyte *data, |
428 | 984 int length) |
985 | |
986 { | |
987 Sound s; | |
1097 | 988 #if (AudioLibraryVersionMajor >= 2 ) && (AudioLibraryVersionMinor >= 3) |
989 SoundFileInfoProc toProc; | |
990 #endif | |
428 | 991 |
992 if (!(s = (Sound) malloc (sizeof (SoundRec)))) | |
993 return NULL; | |
994 | |
2367 | 995 if ((s->formatInfo = SndOpenDataForReading ((CBinbyte *) data, length)) != NULL) |
428 | 996 { |
1097 | 997 #if (AudioLibraryVersionMajor >= 2 ) && (AudioLibraryVersionMinor >= 3) |
2108 | 998 if ((toProc = SoundFileGetProc(SoundFileFormatSnd, |
1097 | 999 SoundFileInfoProcTo)) == NULL) |
1000 { | |
1001 SndCloseFile ((SndInfo *) (s->formatInfo)); | |
1002 free (s); | |
1003 | |
1004 return NULL; | |
1005 } | |
1006 if (!((*toProc)(s))) | |
1007 #else | |
432 | 1008 if (!((int(*)(Sound))(SoundFileInfo[SoundFileFormatSnd].toSound)) (s)) |
1097 | 1009 #endif |
428 | 1010 { |
432 | 1011 SndCloseFile ((SndInfo *) (s->formatInfo)); |
428 | 1012 free (s); |
1013 return NULL; | |
1014 } | |
1015 } | |
2367 | 1016 else if ((s->formatInfo = WaveOpenDataForReading ((CBinbyte *) data, length)) != NULL) |
428 | 1017 { |
1097 | 1018 #if (AudioLibraryVersionMajor >= 2 ) && (AudioLibraryVersionMinor >= 3) |
2108 | 1019 if ((toProc = SoundFileGetProc(SoundFileFormatWave, |
1097 | 1020 SoundFileInfoProcTo)) == NULL) |
1021 { | |
1022 WaveCloseFile ((WaveInfo *) (s->formatInfo)); | |
1023 free (s); | |
1024 | |
1025 return NULL; | |
1026 } | |
1027 if (!((*toProc)(s))) | |
1028 #else | |
432 | 1029 if (!((int(*)(Sound))(SoundFileInfo[SoundFileFormatWave].toSound)) (s)) |
1097 | 1030 #endif |
428 | 1031 { |
432 | 1032 WaveCloseFile ((WaveInfo *) (s->formatInfo)); |
428 | 1033 free (s); |
1034 return NULL; | |
1035 } | |
1036 } | |
1037 | |
1038 return s; | |
1039 } |