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