XEmacs 21.2.32 "Kastor & Polydeukes".
[chise/xemacs-chise.git.1] / src / sound.c
1 /* Sound functions.
2    Copyright (C) 1992, 1993, 1994 Lucid Inc.
3    Copyright (C) 1994, 1995 Free Software Foundation, Inc.
4
5 This file is part of XEmacs.
6
7 XEmacs is free software; you can redistribute it and/or modify it
8 under the terms of the GNU General Public License as published by the
9 Free Software Foundation; either version 2, or (at your option) any
10 later version.
11
12 XEmacs is distributed in the hope that it will be useful, but WITHOUT
13 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
15 for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with XEmacs; see the file COPYING.  If not, write to
19 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20 Boston, MA 02111-1307, USA.  */
21
22 /* Synched up with: Not in FSF. */
23
24 /* Originally written by Jamie Zawinski.
25    Hacked on quite a bit by various others. */
26
27 #include <config.h>
28 #include <time.h>
29 #include "lisp.h"
30
31 #include "buffer.h"
32 #ifdef HAVE_X_WINDOWS
33 #include "console-x.h"
34 #endif
35
36 #include "device.h"
37 #include "redisplay.h"
38 #include "sysdep.h"
39
40 #ifdef HAVE_UNISTD_H
41 #include <unistd.h>
42 #endif
43
44 #ifdef HAVE_NATIVE_SOUND
45 # include <netdb.h>
46 #endif
47
48 #ifdef HAVE_ESD_SOUND
49 extern int esd_play_sound_file (char *file, int vol);
50 extern int esd_play_sound_data (unsigned char *data, size_t length, int vol);
51 # define DEVICE_CONNECTED_TO_ESD_P(x) 1 /* FIXME: better check */
52 #endif
53
54 int bell_volume;
55 int bell_inhibit_time;
56 Lisp_Object Vsound_alist;
57 Lisp_Object Vsynchronous_sounds;
58 Lisp_Object Vnative_sound_only_on_console;
59 Lisp_Object Q_volume, Q_pitch, Q_duration, Q_sound;
60
61 /* These are defined in the appropriate file (sunplay.c, sgiplay.c,
62    or hpplay.c). */
63
64 extern void play_sound_file (char *name, int volume);
65 extern void play_sound_data (unsigned char *data, int length, int volume);
66
67 #ifdef HAVE_NAS_SOUND
68 extern int nas_play_sound_file (char *name, int volume);
69 extern int nas_play_sound_data (unsigned char *data, int length, int volume);
70 extern int nas_wait_for_sounds (void);
71 extern char *nas_init_play (Display *);
72
73 Lisp_Object Qnas;
74 #endif
75
76 DEFUN ("play-sound-file", Fplay_sound_file, 1, 3, "fSound file name: ", /*
77 Play the named sound file on DEVICE's speaker at the specified volume
78 \(0-100, default specified by the `bell-volume' variable).
79 On Unix machines the sound file must be in the Sun/NeXT U-LAW format
80 except under Linux where WAV files are also supported.  On Microsoft
81 Windows the sound file must be in WAV format.
82   DEVICE defaults to the selected device.
83 */
84      (file, volume, device))
85 {
86   /* This function can call lisp */
87   int vol;
88 #if defined (HAVE_NATIVE_SOUND) || defined (HAVE_NAS_SOUND) \
89        || defined (HAVE_ESD_SOUND)
90   struct device *d = decode_device (device);
91 #endif
92   struct gcpro gcpro1;
93
94   CHECK_STRING (file);
95   if (NILP (volume))
96     vol = bell_volume;
97   else
98     {
99       CHECK_INT (volume);
100       vol = XINT (volume);
101     }
102
103   GCPRO1 (file);
104   while (1)
105     {
106       file = Fexpand_file_name (file, Qnil);
107       if (!NILP(Ffile_readable_p (file)))
108         break;
109       else
110         {
111           /* #### This is crockish.  It might be a better idea to try
112              to open the file, and use report_file_error() if it
113              fails.  --hniksic */
114           if (NILP (Ffile_exists_p (file)))
115             file =
116               signal_simple_continuable_error ("File does not exist", file);
117           else
118             file =
119               signal_simple_continuable_error ("File is unreadable", file);
120         }
121     }
122   UNGCPRO;
123
124 #ifdef HAVE_NAS_SOUND
125   if (DEVICE_CONNECTED_TO_NAS_P (d))
126     {
127       char *fileext;
128
129       TO_EXTERNAL_FORMAT (LISP_STRING, file,
130                           C_STRING_ALLOCA, fileext,
131                           Qfile_name);
132       /* #### NAS code should allow specification of a device. */
133       if (nas_play_sound_file (fileext, vol))
134         return Qnil;
135     }
136 #endif /* HAVE_NAS_SOUND */
137
138 #ifdef HAVE_ESD_SOUND
139   if (DEVICE_CONNECTED_TO_ESD_P (d))
140     {
141       char *fileext;
142
143       TO_EXTERNAL_FORMAT (LISP_STRING, file,
144                           C_STRING_ALLOCA, fileext,
145                           Qfile_name);
146       if (esd_play_sound_file (fileext, vol))
147        return Qnil;
148     }
149 #endif /* HAVE_ESD_SOUND */
150
151 #ifdef HAVE_NATIVE_SOUND
152   if (NILP (Vnative_sound_only_on_console) || DEVICE_ON_CONSOLE_P (d))
153     {
154       const char *fileext;
155
156       TO_EXTERNAL_FORMAT (LISP_STRING, file,
157                           C_STRING_ALLOCA, fileext,
158                           Qfile_name);
159       /* The sound code doesn't like getting SIGIO interrupts.
160          Unix sucks! */
161       stop_interrupts ();
162       play_sound_file ((char *) fileext, vol);
163       start_interrupts ();
164       QUIT;
165     }
166 #endif /* HAVE_NATIVE_SOUND */
167
168   return Qnil;
169 }
170
171 static void
172 parse_sound_alist_elt (Lisp_Object elt,
173                        Lisp_Object *volume,
174                        Lisp_Object *pitch,
175                        Lisp_Object *duration,
176                        Lisp_Object *sound)
177 {
178   *volume = Qnil;
179   *pitch = Qnil;
180   *duration = Qnil;
181   *sound = Qnil;
182   if (! CONSP (elt))
183     return;
184
185   /* The things we do for backward compatibility...
186      I wish I had just forced this to be a plist to begin with.
187    */
188
189   if (SYMBOLP (elt) || STRINGP (elt))           /* ( name . <sound> ) */
190     {
191       *sound = elt;
192     }
193   else if (!CONSP (elt))
194     {
195       return;
196     }
197   else if (NILP (XCDR (elt)) &&         /* ( name <sound> ) */
198            (SYMBOLP (XCAR (elt)) ||
199             STRINGP (XCAR (elt))))
200     {
201       *sound = XCAR (elt);
202     }
203   else if (INT_OR_FLOATP (XCAR (elt)) &&        /* ( name <vol> . <sound> ) */
204            (SYMBOLP (XCDR (elt)) ||
205             STRINGP (XCDR (elt))))
206     {
207       *volume = XCAR (elt);
208       *sound = XCDR (elt);
209     }
210   else if (INT_OR_FLOATP (XCAR (elt)) &&        /* ( name <vol> <sound> ) */
211            CONSP (XCDR (elt)) &&
212            NILP (XCDR (XCDR (elt))) &&
213            (SYMBOLP (XCAR (XCDR (elt))) ||
214             STRINGP (XCAR (XCDR (elt)))))
215     {
216       *volume = XCAR (elt);
217       *sound = XCAR (XCDR (elt));
218     }
219   else if ((SYMBOLP (XCAR (elt)) ||     /* ( name <sound> . <vol> ) */
220             STRINGP (XCAR (elt))) &&
221            INT_OR_FLOATP (XCDR (elt)))
222     {
223       *sound = XCAR (elt);
224       *volume = XCDR (elt);
225     }
226 #if 0 /* this one is ambiguous with the plist form */
227   else if ((SYMBOLP (XCAR (elt)) ||     /* ( name <sound> <vol> ) */
228             STRINGP (XCAR (elt))) &&
229            CONSP (XCDR (elt)) &&
230            NILP (XCDR (XCDR (elt))) &&
231            INT_OR_FLOATP (XCAR (XCDR (elt))))
232     {
233       *sound = XCAR (elt);
234       *volume = XCAR (XCDR (elt));
235     }
236 #endif /* 0 */
237   else                                  /* ( name [ keyword <value> ]* ) */
238     {
239       while (CONSP (elt))
240         {
241           Lisp_Object key, val;
242           key = XCAR (elt);
243           val = XCDR (elt);
244           if (!CONSP (val))
245             return;
246           elt = XCDR (val);
247           val = XCAR (val);
248           if (EQ (key, Q_volume))
249             {
250               if (INT_OR_FLOATP (val)) *volume = val;
251             }
252           else if (EQ (key, Q_pitch))
253             {
254               if (INT_OR_FLOATP (val)) *pitch = val;
255               if (NILP (*sound)) *sound = Qt;
256             }
257           else if (EQ (key, Q_duration))
258             {
259               if (INT_OR_FLOATP (val)) *duration = val;
260               if (NILP (*sound)) *sound = Qt;
261             }
262           else if (EQ (key, Q_sound))
263             {
264               if (SYMBOLP (val) || STRINGP (val)) *sound = val;
265             }
266         }
267     }
268 }
269
270 DEFUN ("play-sound", Fplay_sound, 1, 3, 0, /*
271 Play a sound of the provided type.
272 See the variable `sound-alist'.
273 */
274        (sound, volume, device))
275 {
276   int looking_for_default = 0;
277   /* variable `sound' is anything that can be a cdr in sound-alist */
278   Lisp_Object new_volume, pitch, duration, data;
279   int loop_count = 0;
280   int vol, pit, dur;
281   struct device *d = decode_device (device);
282
283   /* NOTE!  You'd better not signal an error in here. */
284
285
286  try_it_again:
287   while (1)
288     {
289       if (SYMBOLP (sound))
290         sound = Fcdr (Fassq (sound, Vsound_alist));
291       parse_sound_alist_elt (sound, &new_volume, &pitch, &duration, &data);
292       sound = data;
293       if (NILP (volume)) volume = new_volume;
294       if (EQ (sound, Qt) || EQ (sound, Qnil) || STRINGP (sound))
295         break;
296       if (loop_count++ > 500)   /* much bogosity has occurred */
297         break;
298     }
299
300   if (NILP (sound) && !looking_for_default)
301     {
302       looking_for_default = 1;
303       loop_count = 0;
304       sound = Qdefault;
305       goto try_it_again;
306     }
307
308
309   vol = (INT_OR_FLOATP (volume)   ? (int) XFLOATINT (volume)   : bell_volume);
310   pit = (INT_OR_FLOATP (pitch)    ? (int) XFLOATINT (pitch)    : -1);
311   dur = (INT_OR_FLOATP (duration) ? (int) XFLOATINT (duration) : -1);
312
313   /* If the sound is a string, and we're connected to Nas, do that.
314      Else if the sound is a string, and we're on console, play it natively.
315      Else just beep.
316    */
317 #ifdef HAVE_NAS_SOUND
318   if (DEVICE_CONNECTED_TO_NAS_P (d) && STRINGP (sound))
319     {
320       const Extbyte *soundext;
321       Extcount soundextlen;
322
323       TO_EXTERNAL_FORMAT (LISP_STRING, sound,
324                           ALLOCA, (soundext, soundextlen),
325                           Qbinary);
326       if (nas_play_sound_data ((unsigned char*)soundext, soundextlen, vol))
327         return Qnil;
328     }
329 #endif /* HAVE_NAS_SOUND */
330
331 #ifdef HAVE_ESD_SOUND
332   if (DEVICE_CONNECTED_TO_ESD_P (d) && STRINGP (sound))
333     {
334       Extbyte *soundext;
335       Extcount soundextlen;
336
337       TO_EXTERNAL_FORMAT (LISP_STRING, sound, ALLOCA, (soundext, soundextlen),
338                           Qbinary);
339       if (esd_play_sound_data (soundext, soundextlen, vol))
340        return Qnil;
341     }
342 #endif /* HAVE_ESD_SOUND */
343
344 #ifdef HAVE_NATIVE_SOUND
345   if ((NILP (Vnative_sound_only_on_console) || DEVICE_ON_CONSOLE_P (d))
346       && STRINGP (sound))
347     {
348       const Extbyte *soundext;
349       Extcount soundextlen;
350
351       TO_EXTERNAL_FORMAT (LISP_STRING, sound,
352                           ALLOCA, (soundext, soundextlen),
353                           Qbinary);
354       /* The sound code doesn't like getting SIGIO interrupts. Unix sucks! */
355       stop_interrupts ();
356       play_sound_data ((unsigned char*)soundext, soundextlen, vol);
357       start_interrupts ();
358       QUIT;
359       return Qnil;
360     }
361 #endif  /* HAVE_NATIVE_SOUND */
362
363   DEVMETH (d, ring_bell, (d, vol, pit, dur));
364   return Qnil;
365 }
366
367 DEFUN ("device-sound-enabled-p", Fdevice_sound_enabled_p, 0, 1, 0, /*
368 Return t if DEVICE is able to play sound.  Defaults to selected device.
369 */
370        (device))
371 {
372 #ifdef HAVE_NAS_SOUND
373   if (DEVICE_CONNECTED_TO_NAS_P (decode_device (device)))
374     return Qt;
375 #endif
376 #ifdef HAVE_NATIVE_SOUND
377   if (DEVICE_ON_CONSOLE_P (decode_device (device)))
378     return Qt;
379 #endif
380   return Qnil;
381 }
382
383 DEFUN ("ding", Fding, 0, 3, 0, /*
384 Beep, or flash the frame.
385 Also, unless an argument is given,
386 terminate any keyboard macro currently executing.
387 When called from lisp, the second argument is what sound to make, and
388 the third argument is the device to make it in (defaults to the selected
389 device).
390 */
391        (arg, sound, device))
392 {
393   static time_t last_bell_time;
394   static struct device *last_bell_device;
395   time_t now;
396   struct device *d = decode_device (device);     
397
398   XSETDEVICE (device, d);
399   now = time (0);
400
401   if (NILP (arg) && !NILP (Vexecuting_macro))
402     /* Stop executing a keyboard macro. */
403     error ("Keyboard macro terminated by a command ringing the bell");
404   
405   if (d == last_bell_device && now-last_bell_time < bell_inhibit_time)
406     return Qnil;
407   else if (!NILP (Vvisible_bell) && DEVMETH (d, flash, (d)))
408     ;
409   else
410     Fplay_sound (sound, Qnil, device);
411   
412   last_bell_time = now;
413   last_bell_device = d;
414   return Qnil;    
415 }
416
417 DEFUN ("wait-for-sounds", Fwait_for_sounds, 0, 1, 0, /*
418 Wait for all sounds to finish playing on DEVICE.
419 */
420        (device))
421
422 {
423 #ifdef HAVE_NAS_SOUND
424   struct device *d = decode_device (device);
425   if (DEVICE_CONNECTED_TO_NAS_P (d))
426     {
427       /* #### somebody fix this to be device-dependent. */
428       nas_wait_for_sounds ();
429     }
430 #endif
431   return Qnil;
432 }
433
434 DEFUN ("connected-to-nas-p", Fconnected_to_nas_p, 0, 1, 0, /*
435 Return t if connected to NAS server for sounds on DEVICE.
436 */
437        (device))
438 {
439 #ifdef HAVE_NAS_SOUND
440   return DEVICE_CONNECTED_TO_NAS_P (decode_device (device)) ? Qt : Qnil;
441 #else
442   return Qnil;
443 #endif
444 }
445 #ifdef HAVE_NAS_SOUND
446
447 static void
448 init_nas_sound (struct device *d)
449 {
450 #ifdef HAVE_X_WINDOWS
451   if (DEVICE_X_P (d))
452     {
453       char *err_message = nas_init_play (DEVICE_X_DISPLAY (d));
454       DEVICE_CONNECTED_TO_NAS_P (d) = !err_message;
455       /* Print out the message? */
456     }
457 #endif /* HAVE_X_WINDOWS */
458 }
459
460 #endif /* HAVE_NAS_SOUND */
461
462 #ifdef HAVE_NATIVE_SOUND
463
464 static void
465 init_native_sound (struct device *d)
466 {
467   if (DEVICE_TTY_P (d) || DEVICE_STREAM_P (d) || DEVICE_MSWINDOWS_P(d))
468     DEVICE_ON_CONSOLE_P (d) = 1;
469 #ifdef HAVE_X_WINDOWS
470   else
471     {
472       /* When running on a machine with native sound support, we cannot use
473          digitized sounds as beeps unless emacs is running on the same machine
474          that $DISPLAY points to, and $DISPLAY points to frame 0 of that
475          machine.
476          */
477
478       Display *display = DEVICE_X_DISPLAY (d);
479       char *dpy = DisplayString (display);
480       char *tail = (char *) strchr (dpy, ':');
481       if (! tail ||
482           strncmp (tail, ":0", 2))
483         DEVICE_ON_CONSOLE_P (d) = 0;
484       else
485         {
486           char dpyname[255], localname[255];
487
488           /* some systems can't handle SIGIO or SIGALARM in gethostbyname. */
489           stop_interrupts ();
490           strncpy (dpyname, dpy, tail-dpy);
491           dpyname [tail-dpy] = 0;
492           if (!*dpyname ||
493               !strcmp (dpyname, "unix") ||
494               !strcmp (dpyname, "localhost"))
495             DEVICE_ON_CONSOLE_P (d) = 1;
496           else if (gethostname (localname, sizeof (localname)))
497             DEVICE_ON_CONSOLE_P (d) = 0;        /* can't find hostname? */
498           else
499             {
500               /* We have to call gethostbyname() on the result of gethostname()
501                  because the two aren't guaranteed to be the same name for the
502                  same host: on some losing systems, one is a FQDN and the other
503                  is not.  Here in the wide wonderful world of Unix it's rocket
504                  science to obtain the local hostname in a portable fashion.
505
506                  And don't forget, gethostbyname() reuses the structure it
507                  returns, so we have to copy the fucker before calling it
508                  again.
509
510                  Thank you master, may I have another.
511                  */
512               struct hostent *h = gethostbyname (dpyname);
513               if (!h)
514                 DEVICE_ON_CONSOLE_P (d) = 0;
515               else
516                 {
517                   char hn [255];
518                   struct hostent *l;
519                   strcpy (hn, h->h_name);
520                   l = gethostbyname (localname);
521                   DEVICE_ON_CONSOLE_P (d) = (l && !(strcmp (l->h_name, hn)));
522                 }
523             }
524           start_interrupts ();
525         }
526     }
527 #endif /* HAVE_X_WINDOWS */
528 }
529
530 #endif /* HAVE_NATIVE_SOUND */
531
532 void
533 init_device_sound (struct device *d)
534 {
535 #ifdef HAVE_NAS_SOUND
536   init_nas_sound (d);
537 #endif
538
539 #ifdef HAVE_NATIVE_SOUND
540   init_native_sound (d);
541 #endif
542 }
543
544 void
545 syms_of_sound (void)
546 {
547   defkeyword (&Q_volume,   ":volume");
548   defkeyword (&Q_pitch,    ":pitch");
549   defkeyword (&Q_duration, ":duration");
550   defkeyword (&Q_sound,    ":sound");
551
552 #ifdef HAVE_NAS_SOUND
553   defsymbol (&Qnas, "nas");
554 #endif
555
556   DEFSUBR (Fplay_sound_file);
557   DEFSUBR (Fplay_sound);
558   DEFSUBR (Fding);
559   DEFSUBR (Fwait_for_sounds);
560   DEFSUBR (Fconnected_to_nas_p);
561   DEFSUBR (Fdevice_sound_enabled_p);
562 }
563
564
565 void
566 vars_of_sound (void)
567 {
568 #ifdef HAVE_NATIVE_SOUND
569   Fprovide (intern ("native-sound"));
570 #endif
571 #ifdef HAVE_NAS_SOUND
572   Fprovide (intern ("nas-sound"));
573 #endif
574 #ifdef HAVE_ESD_SOUND
575   Fprovide (intern ("esd-sound"));
576 #endif
577
578   DEFVAR_INT ("bell-volume", &bell_volume /*
579 *How loud to be, from 0 to 100.
580 */ );
581   bell_volume = 50;
582   
583   DEFVAR_INT ("bell-inhibit-time", &bell_inhibit_time /*
584 *Don't ring the bell on the same device more than once within this many seconds.
585 */ );
586   bell_inhibit_time = 0;
587
588   DEFVAR_LISP ("sound-alist", &Vsound_alist /*
589 An alist associating names with sounds.
590 When `beep' or `ding' is called with one of the name symbols, the associated
591 sound will be generated instead of the standard beep.
592
593 Each element of `sound-alist' is a list describing a sound.
594 The first element of the list is the name of the sound being defined.
595 Subsequent elements of the list are alternating keyword/value pairs:
596
597    Keyword:     Value:
598    -------      -----
599    sound        A string of raw sound data, or the name of another sound to
600                 play.   The symbol `t' here means use the default X beep.
601    volume       An integer from 0-100, defaulting to `bell-volume'
602    pitch        If using the default X beep, the pitch (Hz) to generate.
603    duration     If using the default X beep, the duration (milliseconds).
604
605 For compatibility, elements of `sound-alist' may also be:
606
607    ( sound-name . <sound> )
608    ( sound-name <volume> <sound> )
609
610 You should probably add things to this list by calling the function
611 load-sound-file.
612
613 Caveats:
614  - XEmacs must be built with sound support for your system.  Not all
615    systems support sound. 
616
617  - The pitch, duration, and volume options are available everywhere, but
618    many X servers ignore the `pitch' option.
619
620 The following beep-types are used by emacs itself:
621
622     auto-save-error     when an auto-save does not succeed
623     command-error       when the emacs command loop catches an error
624     undefined-key       when you type a key that is undefined
625     undefined-click     when you use an undefined mouse-click combination
626     no-completion       during completing-read
627     y-or-n-p            when you type something other than 'y' or 'n'
628     yes-or-no-p         when you type something other than 'yes' or 'no'
629     default             used when nothing else is appropriate.
630
631 Other lisp packages may use other beep types, but these are the ones that
632 the C kernel of Emacs uses.
633 */ );
634   Vsound_alist = Qnil;
635
636   DEFVAR_LISP ("synchronous-sounds", &Vsynchronous_sounds /*
637 Play sounds synchronously, if non-nil.
638 Only applies if NAS is used and supports asynchronous playing
639 of sounds.  Otherwise, sounds are always played synchronously.
640 */ );
641   Vsynchronous_sounds = Qnil;
642
643   DEFVAR_LISP ("native-sound-only-on-console", &Vnative_sound_only_on_console /*
644 Non-nil value means play sounds only if XEmacs is running
645 on the system console.
646 Nil means always always play sounds, even if running on a non-console tty
647 or a secondary X display.
648
649 This variable only applies to native sound support.
650 */ );
651   Vnative_sound_only_on_console = Qt;
652
653 #if defined (HAVE_NATIVE_SOUND) && defined (hp9000s800)
654   {
655     void vars_of_hpplay (void);
656     vars_of_hpplay ();
657   }
658 #endif
659 }