XEmacs 21.2.28 "Hermes".
[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 (visible_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   char *error;
451
452 #ifdef HAVE_X_WINDOWS
453   if (DEVICE_X_P (d))
454     {
455       error = nas_init_play (DEVICE_X_DISPLAY (d));
456       DEVICE_CONNECTED_TO_NAS_P (d) = !error;
457       /* Print out the message? */
458     }
459 #endif /* HAVE_X_WINDOWS */
460 }
461
462 #endif /* HAVE_NAS_SOUND */
463
464 #ifdef HAVE_NATIVE_SOUND
465
466 static void
467 init_native_sound (struct device *d)
468 {
469   if (DEVICE_TTY_P (d) || DEVICE_STREAM_P (d) || DEVICE_MSWINDOWS_P(d))
470     DEVICE_ON_CONSOLE_P (d) = 1;
471 #ifdef HAVE_X_WINDOWS
472   else
473     {
474       /* When running on a machine with native sound support, we cannot use
475          digitized sounds as beeps unless emacs is running on the same machine
476          that $DISPLAY points to, and $DISPLAY points to frame 0 of that
477          machine.
478          */
479
480       Display *display = DEVICE_X_DISPLAY (d);
481       char *dpy = DisplayString (display);
482       char *tail = (char *) strchr (dpy, ':');
483       if (! tail ||
484           strncmp (tail, ":0", 2))
485         DEVICE_ON_CONSOLE_P (d) = 0;
486       else
487         {
488           char dpyname[255], localname[255];
489
490           /* some systems can't handle SIGIO or SIGALARM in gethostbyname. */
491           stop_interrupts ();
492           strncpy (dpyname, dpy, tail-dpy);
493           dpyname [tail-dpy] = 0;
494           if (!*dpyname ||
495               !strcmp (dpyname, "unix") ||
496               !strcmp (dpyname, "localhost"))
497             DEVICE_ON_CONSOLE_P (d) = 1;
498           else if (gethostname (localname, sizeof (localname)))
499             DEVICE_ON_CONSOLE_P (d) = 0;        /* can't find hostname? */
500           else
501             {
502               /* We have to call gethostbyname() on the result of gethostname()
503                  because the two aren't guaranteed to be the same name for the
504                  same host: on some losing systems, one is a FQDN and the other
505                  is not.  Here in the wide wonderful world of Unix it's rocket
506                  science to obtain the local hostname in a portable fashion.
507
508                  And don't forget, gethostbyname() reuses the structure it
509                  returns, so we have to copy the fucker before calling it
510                  again.
511
512                  Thank you master, may I have another.
513                  */
514               struct hostent *h = gethostbyname (dpyname);
515               if (!h)
516                 DEVICE_ON_CONSOLE_P (d) = 0;
517               else
518                 {
519                   char hn [255];
520                   struct hostent *l;
521                   strcpy (hn, h->h_name);
522                   l = gethostbyname (localname);
523                   DEVICE_ON_CONSOLE_P (d) = (l && !(strcmp (l->h_name, hn)));
524                 }
525             }
526           start_interrupts ();
527         }
528     }
529 #endif /* HAVE_X_WINDOWS */
530 }
531
532 #endif /* HAVE_NATIVE_SOUND */
533
534 void
535 init_device_sound (struct device *d)
536 {
537 #ifdef HAVE_NAS_SOUND
538   init_nas_sound (d);
539 #endif
540
541 #ifdef HAVE_NATIVE_SOUND
542   init_native_sound (d);
543 #endif
544 }
545
546 void
547 syms_of_sound (void)
548 {
549   defkeyword (&Q_volume,   ":volume");
550   defkeyword (&Q_pitch,    ":pitch");
551   defkeyword (&Q_duration, ":duration");
552   defkeyword (&Q_sound,    ":sound");
553
554 #ifdef HAVE_NAS_SOUND
555   defsymbol (&Qnas, "nas");
556 #endif
557
558   DEFSUBR (Fplay_sound_file);
559   DEFSUBR (Fplay_sound);
560   DEFSUBR (Fding);
561   DEFSUBR (Fwait_for_sounds);
562   DEFSUBR (Fconnected_to_nas_p);
563   DEFSUBR (Fdevice_sound_enabled_p);
564 }
565
566
567 void
568 vars_of_sound (void)
569 {
570 #ifdef HAVE_NATIVE_SOUND
571   Fprovide (intern ("native-sound"));
572 #endif
573 #ifdef HAVE_NAS_SOUND
574   Fprovide (intern ("nas-sound"));
575 #endif
576 #ifdef HAVE_ESD_SOUND
577   Fprovide (intern ("esd-sound"));
578 #endif
579
580   DEFVAR_INT ("bell-volume", &bell_volume /*
581 *How loud to be, from 0 to 100.
582 */ );
583   bell_volume = 50;
584   
585   DEFVAR_INT ("bell-inhibit-time", &bell_inhibit_time /*
586 *Don't ring the bell on the same device more than once within this many seconds.
587 */ );
588   bell_inhibit_time = 0;
589
590   DEFVAR_LISP ("sound-alist", &Vsound_alist /*
591 An alist associating names with sounds.
592 When `beep' or `ding' is called with one of the name symbols, the associated
593 sound will be generated instead of the standard beep.
594
595 Each element of `sound-alist' is a list describing a sound.
596 The first element of the list is the name of the sound being defined.
597 Subsequent elements of the list are alternating keyword/value pairs:
598
599    Keyword:     Value:
600    -------      -----
601    sound        A string of raw sound data, or the name of another sound to
602                 play.   The symbol `t' here means use the default X beep.
603    volume       An integer from 0-100, defaulting to `bell-volume'
604    pitch        If using the default X beep, the pitch (Hz) to generate.
605    duration     If using the default X beep, the duration (milliseconds).
606
607 For compatibility, elements of `sound-alist' may also be:
608
609    ( sound-name . <sound> )
610    ( sound-name <volume> <sound> )
611
612 You should probably add things to this list by calling the function
613 load-sound-file.
614
615 Caveats:
616  - XEmacs must be built with sound support for your system.  Not all
617    systems support sound. 
618
619  - The pitch, duration, and volume options are available everywhere, but
620    many X servers ignore the `pitch' option.
621
622 The following beep-types are used by emacs itself:
623
624     auto-save-error     when an auto-save does not succeed
625     command-error       when the emacs command loop catches an error
626     undefined-key       when you type a key that is undefined
627     undefined-click     when you use an undefined mouse-click combination
628     no-completion       during completing-read
629     y-or-n-p            when you type something other than 'y' or 'n'
630     yes-or-no-p         when you type something other than 'yes' or 'no'
631     default             used when nothing else is appropriate.
632
633 Other lisp packages may use other beep types, but these are the ones that
634 the C kernel of Emacs uses.
635 */ );
636   Vsound_alist = Qnil;
637
638   DEFVAR_LISP ("synchronous-sounds", &Vsynchronous_sounds /*
639 Play sounds synchronously, if non-nil.
640 Only applies if NAS is used and supports asynchronous playing
641 of sounds.  Otherwise, sounds are always played synchronously.
642 */ );
643   Vsynchronous_sounds = Qnil;
644
645   DEFVAR_LISP ("native-sound-only-on-console", &Vnative_sound_only_on_console /*
646 Non-nil value means play sounds only if XEmacs is running
647 on the system console.
648 Nil means always always play sounds, even if running on a non-console tty
649 or a secondary X display.
650
651 This variable only applies to native sound support.
652 */ );
653   Vnative_sound_only_on_console = Qt;
654
655 #if defined (HAVE_NATIVE_SOUND) && defined (hp9000s800)
656   {
657     void vars_of_hpplay (void);
658     vars_of_hpplay ();
659   }
660 #endif
661 }