Mercurial > hg > xemacs-beta
annotate src/nas.c @ 5090:0ca81354c4c7
Further frame-geometry cleanups
-------------------- ChangeLog entries follow: --------------------
man/ChangeLog addition:
2010-03-03 Ben Wing <ben@xemacs.org>
* internals/internals.texi (Intro to Window and Frame Geometry):
* internals/internals.texi (The Paned Area):
* internals/internals.texi (The Displayable Area):
Update to make note of e.g. the fact that the bottom gutter is
actually above the minibuffer.
src/ChangeLog addition:
2010-03-03 Ben Wing <ben@xemacs.org>
* emacs.c:
* emacs.c (assert_equal_failed):
* lisp.h:
* lisp.h (assert_equal):
New fun assert_equal, asserting that two values == each other, and
printing out both values upon failure.
* frame-gtk.c (gtk_initialize_frame_size):
* frame-impl.h:
* frame-impl.h (FRAME_TOP_INTERNAL_BORDER_START):
* frame-impl.h (FRAME_BOTTOM_INTERNAL_BORDER_START):
* frame-impl.h (FRAME_LEFT_INTERNAL_BORDER_START):
* frame-impl.h (FRAME_PANED_TOP_EDGE):
* frame-impl.h (FRAME_NONPANED_SIZE):
* frame-x.c (x_initialize_frame_size):
* frame.c:
* gutter.c (get_gutter_coords):
* gutter.c (calculate_gutter_size):
* gutter.h:
* gutter.h (WINDOW_REAL_TOP_GUTTER_BOUNDS):
* gutter.h (FRAME_TOP_GUTTER_BOUNDS):
* input-method-xlib.c:
* input-method-xlib.c (XIM_SetGeometry):
* redisplay-output.c (clear_left_border):
* redisplay-output.c (clear_right_border):
* redisplay-output.c (redisplay_output_pixmap):
* redisplay-output.c (redisplay_clear_region):
* redisplay-output.c (redisplay_clear_top_of_window):
* redisplay-output.c (redisplay_clear_to_window_end):
* redisplay-xlike-inc.c (XLIKE_clear_frame):
* redisplay.c:
* redisplay.c (UPDATE_CACHE_RETURN):
* redisplay.c (pixel_to_glyph_translation):
* toolbar.c (update_frame_toolbars_geometry):
* window.c (Fwindow_pixel_edges):
Get rid of some redundant macros. Consistently use the
FRAME_TOP_*_START, FRAME_RIGHT_*_END, etc. format. Rename
FRAME_*_BORDER_* to FRAME_*_INTERNAL_BORDER_*. Comment out
FRAME_BOTTOM_* for gutters and the paned area due to the
uncertainty over where the paned area actually begins. (Eventually
we should probably move the gutters outside the minibuffer so that
the paned area is contiguous.) Use FRAME_PANED_* more often in the
code to make things clearer.
Update the diagram to show that the bottom gutter is inside the
minibuffer (!) and that there are "junk boxes" when you have left
and/or right gutters (dead boxes that are mistakenly left uncleared,
unlike the corresponding scrollbar dead boxes). Update the text
appropriately to cover the bottom gutter position, etc.
Rewrite gutter-geometry code to use the FRAME_*_GUTTER_* in place of
equivalent expressions referencing other frame elements, to make the
code more portable in case we move around the gutter location.
Cleanup FRAME_*_GUTTER_BOUNDS() in gutter.h.
Add some #### GEOM! comments where I think code is incorrect --
typically, it wasn't fixed up properly when the gutter was added.
Some cosmetic changes.
author | Ben Wing <ben@xemacs.org> |
---|---|
date | Wed, 03 Mar 2010 05:07:47 -0600 |
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 } |