Fix build on powerpc64 from Sebastian
[sxemacs] / src / media / sound.c
1 /* New Generation Sound Functions.
2    Copyright (C) 2006 Sebastian Freundt
3
4 This file is part of SXEmacs
5
6 SXEmacs is free software: you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation, either version 3 of the License, or
9 (at your option) any later version.
10
11 SXEmacs is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program.  If not, see <http://www.gnu.org/licenses/>. */
18
19
20 /* Inspired by XEmacs' sound.c written by Jamie Zawinski */
21
22 /* Synched up with: Not in FSF. */
23
24 #include <config.h>
25 #include <time.h>
26 #include "lisp.h"
27
28 #include "syssignal.h"
29
30 #include "buffer.h"
31
32 #include "ui/device.h"
33 #include "ui/redisplay.h"
34 #include "sysdep.h"
35
36 #include "sysfile.h"
37 #include "opaque.h"
38 #include "semaphore.h"
39
40 #include "media.h"
41 #include "sound.h"
42
43 Fixnum bell_volume;
44 Fixnum bell_inhibit_time;
45 Lisp_Object Vsound_alist;
46 Lisp_Object Vsynchronous_sounds;
47 Lisp_Object Vnative_sound_only_on_console;
48 Lisp_Object Q_volume, Q_pitch, Q_duration, Q_sound;
49 Lisp_Object Q_device, Q_server, Q_client, Q_keep_open;
50 Lisp_Object Qplay_sound;
51
52 #ifdef HAVE_AO_SOUND
53 #include "sound-ao.h"
54 #endif
55 #ifdef HAVE_POLYP_SOUND
56 #include "sound-polyp.h"
57 #endif
58 #ifdef HAVE_PULSE_SOUND
59 #include "sound-pulse.h"
60 #endif
61 #ifdef HAVE_ESD_SOUND
62 #include "sound-esd.h"
63 #endif
64 #ifdef HAVE_NAS_SOUND
65 #include "sound-nas.h"
66 #endif
67 #ifdef HAVE_JACK_SOUND
68 #include "sound-jack.h"
69 #endif
70 #ifdef HAVE_ALSA_SOUND
71 #include "sound-alsa.h"
72 #endif
73 #ifdef HAVE_OSS_SOUND
74 #include "sysproc.h"
75 #include "sound-oss.h"
76 #endif
77
78 /* for CHECK_NUMBER and COMPARABLEP */
79 #include "ent/ent.h"
80
81 Lisp_Object Qaudio_devicep;
82 Lisp_Object Qaudio_jobp;
83 Lisp_Object Vdefault_audio_device;
84
85 static audio_job_t make_audio_job(Lisp_Object, Lisp_Object, Lisp_Object);
86 static Lisp_Object make_audio_asyneq_job(audio_job_t);
87 static inline void finish_audio_job_data(audio_job_t);
88 static inline void
89 exec_sentinel(void *job, Lisp_Object, Lisp_Object, Lisp_Object);
90
91 #ifdef EF_USE_ASYNEQ
92 #include "events/worker-asyneq.h"
93
94 /*****************************************************************/
95 /*                      Audio Jobs                               */
96 /*****************************************************************/
97 /* sound-mst handler */
98 \f
99 static void
100 mark_audio_job(worker_job_t job)
101 {
102         audio_job_t aj;
103
104         aj = audio_job(job);
105         if (aj == NULL) {
106                 return;
107         }
108
109         SOUND_DEBUG_AJ("Marking audio job 0x%lx (job 0x%lx)\n",
110                        (long unsigned int)aj,
111                        (long unsigned int)job);
112         SXE_MUTEX_LOCK(&aj->mtx);
113         mark_object(aj->stream);
114         mark_object(aj->device);
115         mark_object(aj->result);
116         mark_object(aj->sentinel);
117         SXE_MUTEX_UNLOCK(&aj->mtx);
118         return;
119 }
120
121 static void
122 print_audio_job(worker_job_t job, Lisp_Object pcf)
123 {
124         audio_job_t aj = audio_job(job);
125         SXE_MUTEX_LOCK(&aj->mtx);
126         write_fmt_string(pcf, " carrying  #<audio-job 0x%lx>", (long unsigned int)aj);
127         SXE_MUTEX_UNLOCK(&aj->mtx);
128         return;
129 }
130
131 static void
132 finish_audio_job(worker_job_t job)
133 {
134         audio_job_t aj;
135
136         lock_worker_job(job);
137         aj = audio_job(job);
138
139         SOUND_DEBUG_AJ("Finishing audio job 0x%lx (job 0x%lx)\n",
140                        (long unsigned int)aj,
141                        (long unsigned int)job);
142         if (aj) {
143                 finish_audio_job_data(aj);
144         }
145         worker_job_data(job) = NULL;
146         unlock_worker_job(job);
147         return;
148 }
149
150 static void
151 audio_job_handle(worker_job_t job)
152 {
153         /* thread-safe */
154         /* usually called from aux threads */
155         audio_job_t aj;
156         Lisp_Object device;
157 #if !defined HAVE_BDWGC || !defined EF_USE_BDWGC
158         Lisp_Object ljob = (Lisp_Object)job;
159 #endif  /* !BDWGC */
160         int(*playfun)(audio_job_t);
161         struct gcpro gcpro1;
162
163         GCPRO1(ljob);
164         lock_worker_job(job);
165         aj = audio_job(job);
166         SXE_MUTEX_LOCK(&aj->mtx);
167         SOUND_DEBUG_AJ("inherit scratch buffer 0x%lx (sz=%ld)\n",
168                        (long unsigned int)worker_job_buffer(job),
169                        (long int)worker_job_buffer_alloc_size(job));
170         aj->buffer = worker_job_buffer(job);
171         aj->buffer_alloc_size = worker_job_buffer_alloc_size(job);
172         device = audio_job_device(job);
173         SOUND_DEBUG_MT("starting thread 0x%lx@0x%lx\n",
174                        (long unsigned int)aj,
175                        (long unsigned int)job);
176         aj->play_state = MTPSTATE_RUN;
177
178         SOUND_DEBUG_AJ("fetching play function\n");
179         playfun = XAUDIO_DEVICE(device)->meths->play;
180         SOUND_DEBUG_AJ("fetched 0x%lx\n", (long unsigned int)playfun);
181
182         SXE_MUTEX_UNLOCK(&aj->mtx);
183         SOUND_DEBUG_AJ("calling play function\n");
184         (void)playfun(aj);
185         SOUND_DEBUG_AJ("play function finished\n");
186         unlock_worker_job(job);
187         UNGCPRO;
188         return;
189 }
190
191 static void
192 audio_job_started(worker_job_t job)
193 {
194         if (NILP(audio_job_sentinel(job) /* sentinel */)) {
195                 return;
196         }
197         /* called from main thread */
198         exec_sentinel(job, audio_job_stream(job), intern("started"),
199                       audio_job_sentinel(job));
200         return;
201 }
202
203 static void
204 audio_job_finished(worker_job_t job)
205 {
206         if (NILP(audio_job_sentinel(job) /* sentinel */)) {
207                 return;
208         }
209         /* called from main thread */
210         exec_sentinel(job, audio_job_stream(job), intern("finished"),
211                       audio_job_sentinel(job));
212         return;
213 }
214
215 static struct work_handler_s audio_job_handler = {
216         mark_audio_job, print_audio_job, finish_audio_job,
217         audio_job_handle, audio_job_started, audio_job_finished
218 };
219
220 static Lisp_Object
221 make_audio_asyneq_job(audio_job_t aj)
222 {
223         /* create a job digestible by the asyneq */
224         Lisp_Object job = Qnil;
225         struct gcpro gcpro1;
226         worker_job_t j;
227
228         GCPRO1(job);
229         j = make_worker_job(&audio_job_handler);
230         job = wrap_object(j);
231         XWORKER_JOB_DATA(job) = aj;
232         /* the scratch buffer thingie */
233         SXE_MUTEX_LOCK(&aj->mtx);
234         aj->buffer = XWORKER_JOB_BUFFER(job);
235         aj->buffer_alloc_size = XWORKER_JOB_BUFFER_ALLOC_SIZE(job);
236         /* generate an event queue for job control */
237         audio_job_queue(aj) = make_noseeum_event_queue();
238         SXE_MUTEX_UNLOCK(&aj->mtx);
239         UNGCPRO;
240         return job;
241 }
242
243 \f
244 DEFUN("set-audio-job-sentinel", Fset_audio_job_sentinel, 2, 2, 0, /*
245 Give JOB the sentinel SENTINEL; `nil' for none.
246 The sentinel is called as a function whenever the stream state changes.
247
248 The function should take three (optional four) arguments
249   (JOB STREAM STATE &optional OLD-STATE)
250 where
251 - JOB is the worker job object currently coping with the stream,
252 - STREAM is bound to the stream object, and
253 - STATE is one of 'unknown, 'started, 'paused, 'stopped, 'finished
254   and indicates the current state of the job
255 - OLD-STATE is again one of the above state symbols but indicates
256   the previous state of the job.
257 */
258       (job, sentinel))
259 {
260         CHECK_AUDIO_JOB(job);
261         XAUDIO_JOB_SENTINEL(job) = sentinel;
262         return sentinel;
263 }
264
265 DEFUN("play-media-stream&", Fplay_media_streamX,
266       1, 4, 0, /*
267 Play the media stream STREAM on an audio device DEVICE.
268
269 Optional second argument DEVICE must be an audio device
270 created by `make-audio-device'.
271 If omitted DEVICE defaults to the value of `default-audio-device'.
272
273 Optional third argument SENTINEL specifies a lisp function to be
274 called whenever the stream state changes.  The function should
275 take three (optional four) arguments
276   (JOB STREAM STATE &optional OLD-STATE)
277 where
278 - JOB is the worker job object currently coping with the stream,
279 - STREAM is bound to the stream object, and
280 - STATE is one of 'unknown, 'started, 'paused, 'stopped and indicates
281   the current state of the job
282 - OLD-STATE is again one of the above state symbols but indicates
283   the previous state of the job.
284
285 See also `set-media-thread-sentinel'.
286
287 Optional fourth argument VOLUME specifies an intial value for
288 the playback volume.
289 */
290       (stream, device, sentinel, volume))
291 {
292         audio_job_t aj;
293         Lisp_Object job = Qnil;
294         int vol;
295         struct gcpro gcpro1, gcpro2, gcpro3, gcpro4;
296
297         CHECK_MEDIA_STREAM(stream);
298
299         if (NILP(device))
300                 device = Vdefault_audio_device;
301         else
302                 CHECK_AUDIO_DEVICE(device);
303
304         /* hm, it's useful to stop here if default-audio-device is nil,
305          * i merely spit out a warning and return nil, that should suffice
306          */
307         if (NILP(device)) {
308                 warn_when_safe(
309                         Qdevice, Qnotice,
310                         GETTEXT("play-media-stream: "
311                                 "no device specified, "
312                                 "consider setting `default-audio-device'."));
313                 return Qnil;
314         }
315
316         if (!NILP(volume)) {
317                 CHECK_NUMBER(volume);
318                 volume = Fcoerce_number(volume, Qint, Qnil);
319                 vol = XINT(volume);
320                 if (vol < MEDIA_SAMPLE_VOLUME_MIN)
321                         vol = 0;
322                 else if (vol > MEDIA_SAMPLE_VOLUME_MAX)
323                         vol = MEDIA_SAMPLE_VOLUME_MAX;
324         } else
325                 vol = MEDIA_SAMPLE_VOLUME_NORM;
326
327         GCPRO4(job, device, stream, sentinel);
328         /* create the job data object */
329         aj = make_audio_job(stream, device, sentinel);
330         if (aj == Qnull_pointer) {
331                 UNGCPRO;
332                 return Qnil;
333         }
334         aj->volume = vol;
335         aj->ratetrafo = 1.0;
336         /* now prepare the job to dispatch */
337         job = make_audio_asyneq_job(aj);
338         /* add some props */
339         /* ... and dispatch it */
340         eq_enqueue(delegate_eq, job);
341         /* brag about new jobs in the queue */
342         eq_queue_trigger_all(delegate_eq);
343         UNGCPRO;
344         return job;
345 }
346 #endif  /* EF_USE_ASYNEQ */
347
348 \f
349 /* media thread sentinels */
350 static Lisp_Object
351 exec_sentinel_unwind(Lisp_Object SXE_UNUSED(datum))
352 {
353         return Qnil;
354 }
355
356 static inline void
357 exec_sentinel(void *job, Lisp_Object stream,
358               Lisp_Object state, Lisp_Object sentinel)
359 {
360         /* This function can GC */
361         /* called from main thread */
362         Lisp_Object funcell[4] = {sentinel, (Lisp_Object)job, stream, state};
363         int speccount = specpdl_depth();
364         struct gcpro gcpro1;
365
366         GCPROn(funcell, countof(funcell));
367
368         record_unwind_protect(exec_sentinel_unwind, Qnil);
369         /* call the funcell */
370         Ffuncall(countof(funcell), funcell);
371         /* reset to previous state */
372         restore_match_data();
373         UNGCPRO;
374         unbind_to(speccount, Qnil);
375         return;
376 }
377
378 static inline audio_job_t
379 allocate_audio_job(void)
380 {
381         audio_job_t aj = xnew(struct audio_job_s);
382         SOUND_DEBUG_AJ("allocated: 0x%lx\n", (long unsigned int)aj);
383         return aj;
384 }
385
386 static audio_job_t
387 make_audio_job(Lisp_Object stream, Lisp_Object device, Lisp_Object sentinel)
388 {
389         audio_job_t aj = NULL;
390         media_substream *mss;
391
392         /* traverse the substreams, try to find the first audio stream */
393         for (mss = XMEDIA_STREAM_FIRST(stream);
394              mss && media_substream_type(mss) != MTYPE_AUDIO;
395              mss = media_substream_next(mss));
396
397         if (mss == NULL) {
398                 /* throw error */
399                 return Qnull_pointer;
400         }
401
402         aj = allocate_audio_job();
403         aj->stream = stream;
404         aj->device = device;
405         aj->substream = mss;
406         aj->result = Qnil;
407         aj->sentinel = sentinel;
408
409         aj->state = MTSTATE_UNKNOWN;
410         aj->play_state = MTPSTATE_UNKNOWN;
411 #ifdef EF_USE_ASYNEQ
412         SXE_MUTEX_INIT(&aj->mtx);
413         audio_job_queue(aj) = NULL;
414 #endif
415
416         aj->job_device_data = NULL;
417         aj->job_stream_data = NULL;
418
419         aj->buffer = NULL;
420         aj->buffer_alloc_size = 0;
421
422         SOUND_DEBUG_AJ("created: 0x%lx\n", (long unsigned int)aj);
423         return aj;
424 }
425
426 static inline void
427 finish_audio_job_data(audio_job_t aj)
428 {
429         SOUND_DEBUG_AJ("finishing: 0x%lx\n", (long unsigned int)aj);
430         SXE_MUTEX_LOCK(&aj->mtx);
431         if (audio_job_device_data(aj)) {
432                 SOUND_DEBUG_AJ("audio-job device data still alive. Bug?\n");
433                 audio_job_device_data(aj) = NULL;
434         }
435         if (audio_job_stream_data(aj)) {
436                 SOUND_DEBUG_AJ("audio-job stream data still alive. Bug?\n");
437                 audio_job_stream_data(aj) = NULL;
438         }
439
440         if (aj->buffer) {
441                 SOUND_CRITICAL("strange, buffer is non-NULL: 0x%lx\n",
442                                (long unsigned int)aj->buffer);
443                 /* xfree(aj->buffer); */
444         }
445         aj->buffer_alloc_size = 0;
446
447 #ifdef EF_USE_ASYNEQ
448         if (audio_job_queue(aj)) {
449                 SOUND_DEBUG_AJ("finishing audio job queue\n");
450                 free_event_queue(audio_job_queue(aj));
451         }
452         audio_job_queue(aj) = (void*)0xB16B00B5;
453 #endif  /* EF_USE_ASYNEQ */
454
455         aj->resolution = 0;
456         aj->framesize = 0;
457         aj->channels = 0;
458         aj->volume = 0;
459         SXE_MUTEX_UNLOCK(&aj->mtx);
460         SXE_MUTEX_FINI(&aj->mtx);
461
462         SOUND_DEBUG_AJ("finished: 0x%lx\n", (long unsigned int)aj);
463         xfree(aj);
464 }
465
466 #if defined __GNUC__
467 static int
468 sound_DO_NOT_play_stream(audio_job_t mst)
469         __attribute__((unused));
470 #endif
471 static int
472 sound_DO_NOT_play_stream(audio_job_t mst)
473 {
474         /* just a dummy function */
475         return 0;
476 }
477
478 DEFUN("play-media-stream-synchronously", Fplay_media_stream_synchronously,
479       1, 4, 0, /*
480 Play the media stream STREAM on an audio device synchronously.
481 This function disregards the value of `synchronous-sounds',
482 instead streams will always be played in synchronous mode.
483
484 Optional second argument DEVICE must be an audio device
485 created by `make-audio-device'.
486 If omitted DEVICE defaults to the value of `default-audio-device'.
487
488 Optional third argument SENTINEL specifies a lisp function to be
489 called after the stream playback finishes.  The function should
490 take one argument (STREAM) where STREAM is bound to the
491 media stream which finished.  See `set-media-thread-sentinel'.
492
493 Optional fourth argument VOLUME specifies an intial value for
494 the playback volume.
495 */
496       (stream, device, sentinel, volume))
497 {
498         audio_job_t aj;
499         int vol;
500
501         CHECK_MEDIA_STREAM(stream);
502
503         if (NILP(device))
504                 device = Vdefault_audio_device;
505         else
506                 CHECK_AUDIO_DEVICE(device);
507
508         /* hm, it's useful to stop here if default-audio-device is nil,
509          * i merely spit out a warning and return nil, that should suffice
510          */
511         if (NILP(device)) {
512                 warn_when_safe(
513                         Qdevice, Qnotice,
514                         GETTEXT("play-media-stream: "
515                                 "no device specified, "
516                                 "consider setting `default-audio-device'."));
517                 return Qnil;
518         }
519
520         if (!NILP(volume)) {
521                 CHECK_NUMBER(volume);
522                 volume = Fcoerce_number(volume, Qint, Qnil);
523                 vol = XINT(volume);
524                 if (vol < MEDIA_SAMPLE_VOLUME_MIN)
525                         vol = 0;
526                 else if (vol > MEDIA_SAMPLE_VOLUME_MAX)
527                         vol = MEDIA_SAMPLE_VOLUME_MAX;
528         } else {
529                 vol = MEDIA_SAMPLE_VOLUME_NORM;
530         }
531
532         aj = make_audio_job(stream, device, Qnil);
533         if (aj == Qnull_pointer) {
534                 SOUND_DEBUG_AJ("audio job is void ... cancelling play\n");
535                 return Qnil;
536         }
537         aj->volume = vol;
538         aj->ratetrafo = 1.0;
539         aj->play_state = MTPSTATE_RUN;
540
541 #if defined EF_USE_ASYNEQ
542         aj->queue = NULL;
543 #endif
544
545         SOUND_DEBUG_AJ("calling play meth\n");
546         XAUDIO_DEVICE(device)->meths->play(aj);
547
548         if (!NILP(sentinel)) {
549                 exec_sentinel(
550                         (void*)Qnil, stream, intern("finished"), sentinel);
551         }
552
553         finish_audio_job_data(aj);
554
555         return Qt;
556 }
557
558 \f
559 #ifdef EF_USE_ASYNEQ
560 struct audio_job_event_s pause_event = {aj_change_state, {aj_pause}, 0};
561 struct audio_job_event_s resume_event = {aj_change_state, {aj_resume}, 0};
562 struct audio_job_event_s start_event = {aj_change_state, {aj_start}, 0};
563 struct audio_job_event_s stop_event = {aj_change_state, {aj_stop}, 0};
564 struct audio_job_event_s volnorm_event = {
565         aj_change_volume, {MEDIA_SAMPLE_VOLUME_NORM}, 0};
566 struct audio_job_event_s volmute_event = {
567         aj_change_volume, {MEDIA_SAMPLE_VOLUME_MIN}, 0};
568
569 DEFUN("pause-audio-job", Fpause_audio_job, 1, 1, 0, /*
570 Pause the audio job JOB.
571 Optionally JOB can be 'all in which case all running
572 media threads are paused.
573 */
574       (job))
575 {
576         if (!EQ(job, Qall)) {
577                 CHECK_AUDIO_JOB(job);
578                 /* connect to job's queue and place a PAUSE event there */
579                 if (XAUDIO_JOB_QUEUE(job)) {
580                         eq_noseeum_enqueue(XAUDIO_JOB_QUEUE(job), &pause_event);
581                 }
582         }
583         return Qt;
584 }
585
586 DEFUN("resume-audio-job", Fresume_audio_job, 1, 1, 0, /*
587 Resume a paused audio job JOB.
588 Optionally JOB can be 'all in which case all paused
589 media threads are resumed.
590 */
591       (job))
592 {
593         if (!EQ(job, Qall)) {
594                 CHECK_AUDIO_JOB(job);
595                 /* connect to job's queue and place a RESUME event there */
596                 if (XAUDIO_JOB_QUEUE(job)) {
597                         eq_noseeum_enqueue(XAUDIO_JOB_QUEUE(job),
598                                            &resume_event);
599                 }
600         }
601         return Qt;
602 }
603
604 DEFUN("stop-audio-job", Fstop_audio_job, 1, 1, 0, /*
605 Stop a audio job JOB.
606 Optionally JOB can be 'all in which case all media threads
607 are stopped.
608 */
609       (job))
610 {
611         if (!EQ(job, Qall)) {
612                 CHECK_AUDIO_JOB(job);
613                 /* connect to job's queue and place a STOP event there */
614                 if (XAUDIO_JOB_QUEUE(job)) {
615                         eq_noseeum_enqueue(XAUDIO_JOB_QUEUE(job), &stop_event);
616                 }
617         }
618         return Qt;
619 }
620
621 DEFUN("set-audio-job-volume", Fset_audio_job_volume, 1, 2, 0, /*
622 Set the volume of the audio job JOB to VOLUME.
623
624 JOB is assumed to be a media thread object with an audio substream.
625 Optionally JOB can be 'all in which case the volume change
626 applies to all (currently handled) media threads.
627
628 VOLUME is either a comparable number (see `comparablep') or
629 a vector of comparable numbers.
630 In the former case VOLUME sets the master volume of all channels.
631 In the latter case VOLUME sets the volumes channelwise.
632
633 Any volume value is coerced to an integer.
634 A volume of 128 is the norm.
635 A volume of 0 is muting the respective channels.
636 Volumes greater than 128 cause an amplification of the stream,
637 255 is the maximal volume value.  Note that clipping may occur.
638 */
639       (job, volume))
640 {
641         int vol = 0;
642         Lisp_Object tmpv = Qnil;
643
644         CHECK_AUDIO_JOB(job);
645         if (volume == Qt) {
646                 if (XAUDIO_JOB_QUEUE(job)) {
647                         eq_noseeum_enqueue(
648                                 XAUDIO_JOB_QUEUE(job), &volnorm_event);
649                 }
650                 return make_int(MEDIA_SAMPLE_VOLUME_NORM);
651         } else if (volume == Qnil) {
652                 if (XAUDIO_JOB_QUEUE(job)) {
653                         eq_noseeum_enqueue(
654                                 XAUDIO_JOB_QUEUE(job), &volmute_event);
655                 }
656                 return make_int(MEDIA_SAMPLE_VOLUME_NORM);
657         } else if (COMPARABLEP(volume)) {
658                 volume = Fcoerce_number(volume, Qint, Qnil);
659                 vol = XINT(volume);
660
661                 if (vol < 0)
662                         vol = MEDIA_SAMPLE_VOLUME_MIN;
663                 else if (vol > MEDIA_SAMPLE_VOLUME_MAX)
664                         vol = MEDIA_SAMPLE_VOLUME_MAX;
665         } else if (VECTORP(volume)) {
666                 tmpv = XVECTOR_DATA(volume)[0];
667                 tmpv = Fcoerce_number(tmpv, Qint, Qnil);
668                 vol = XINT(tmpv);
669
670                 if (vol < 0)
671                         vol = MEDIA_SAMPLE_VOLUME_MIN;
672                 else if (vol > MEDIA_SAMPLE_VOLUME_MAX)
673                         vol = MEDIA_SAMPLE_VOLUME_MAX;
674         } else {
675                 return wrong_type_argument(Qnumberp, volume);
676         }
677
678         /* place an VOLCHANGE event in job's queue */
679         if (XAUDIO_JOB_QUEUE(job)) {
680                 audio_job_event_t aje = make_audio_job_event(aj_change_volume);
681                 audio_job_event_args(aje).volume_args = vol;
682                 eq_noseeum_enqueue(XAUDIO_JOB_QUEUE(job), aje);
683         }
684         return volume;
685 }
686
687 DEFUN("audio-job-volume", Faudio_job_volume, 1, 1, 0, /*
688 Return the current volume of audio job JOB.
689 */
690       (job))
691 {
692         CHECK_AUDIO_JOB(job);
693
694         return make_int(XAUDIO_JOB(job)->volume);
695 }
696
697 DEFUN("set-audio-job-rate", Fset_audio_job_rate, 1, 2, 0, /*
698 Set the rate of audio job JOB to RATE.
699
700 If RATE is `t' or `nil', reset the rate to 1.0.
701 */
702       (job, rate))
703 {
704         float ratetrafo;
705
706         CHECK_AUDIO_JOB(job);
707         if (rate == Qt || rate == Qnil) {
708                 ratetrafo = 1.0;
709         } else if (COMPARABLEP(rate)) {
710                 rate = Fcoerce_number(rate, Qfloat, Qnil);
711                 ratetrafo = XFLOAT_DATA(rate);
712
713                 if (ratetrafo <= 0.5)
714                         ratetrafo = 0.5;
715                 else if (ratetrafo > 2.0)
716                         ratetrafo = 2.0;
717         } else {
718                 return wrong_type_argument(Qnumberp, rate);
719         }
720
721         /* place a rate change event in job's queue */
722         if (XAUDIO_JOB_QUEUE(job)) {
723                 audio_job_event_t aje = make_audio_job_event(aj_change_rate);
724                 audio_job_event_args(aje).rate_args = ratetrafo;
725                 eq_noseeum_enqueue(XAUDIO_JOB_QUEUE(job), aje);
726         }
727         return rate;
728 }
729
730 DEFUN("audio-job-rate", Faudio_job_rate, 1, 1, 0, /*
731 Return the current rate of audio job JOB.
732 */
733       (job))
734 {
735         CHECK_AUDIO_JOB(job);
736
737         return make_float(XAUDIO_JOB(job)->ratetrafo);
738 }
739 #endif  /* EF_USE_ASYNEQ */
740
741 \f
742 DEFUN("ding", Fding, 0, 3, 0,   /*
743 Beep, or flash the frame.
744 Also, unless an argument is given,
745 terminate any keyboard macro currently executing.
746 When called from lisp, the second argument is what sound to make, and
747 the third argument is the device to make it in (defaults to the selected
748 device), but may also be an audio device created by `make-audio-device'.
749 */
750       (arg, sound, device))
751 {
752         static time_t last_bell_time;
753         static struct device *last_bell_device;
754         time_t now;
755         struct device *d = decode_device(device);
756         struct gcpro gcpro1, gcpro2, gcpro3;
757
758         GCPRO3(arg, sound, device);
759
760         /* XSETDEVICE(device, d); */
761         now = time(0);
762
763         if (NILP(arg) && !NILP(Vexecuting_macro))
764                 /* Stop executing a keyboard macro. */
765                 error
766                     ("Keyboard macro terminated by a command ringing the bell");
767
768         if (d == last_bell_device && now - last_bell_time < bell_inhibit_time) {
769                 return Qnil;
770         } else if (!NILP(Vvisible_bell) && DEVMETH(d, flash, (d))) {
771                 ;
772         } else if (NILP(sound)) {
773                 DEVMETH(d, ring_bell, (d, bell_volume, -1, -1));
774         } else if (!NILP(Ffboundp(Qplay_sound))) {
775                 call3(Qplay_sound, sound, Qnil, device);
776         }
777
778         last_bell_time = now;
779         last_bell_device = d;
780         RETURN_UNGCPRO(Qnil);
781 }
782
783 \f
784 /* LEGACY */
785 DEFUN("device-sound-enabled-p", Fdevice_sound_enabled_p, 0, 1, 0,       /*
786 Return t if DEVICE is able to play sound.  Defaults to selected device.
787 */
788       (device))
789 {
790         if (DEVICEP(device)) {
791 #ifdef HAVE_NAS_SOUND
792                 if (DEVICE_CONNECTED_TO_NAS_P(decode_device(device)))
793                         return Qt;
794 #endif
795 #ifdef HAVE_OSS_SOUND
796                 if (DEVICE_ON_CONSOLE_P(decode_device(device)))
797                         return Qt;
798 #endif
799         }
800
801         if (NILP(device))
802                 device = Vdefault_audio_device;
803
804         if (!NILP(device) &&
805             AUDIO_DEVICEP(device) &&
806             XAUDIO_DEVICE_STATE(device) != ASTATE_DEAD)
807                 return Qt;
808
809         return Qnil;
810 }
811
812 /* LEGACY */
813 DEFUN("wait-for-sounds", Fwait_for_sounds, 0, 1, 0,     /*
814 Wait for all sounds to finish playing on DEVICE.
815 */
816       (device))
817 {
818         return Qnil;
819 }
820
821 /* LEGACY */
822 DEFUN("connected-to-nas-p", Fconnected_to_nas_p, 0, 1, 0,       /*
823 Return t if connected to NAS server for sounds on DEVICE.
824 */
825       (device))
826 {
827 #ifdef HAVE_NAS_SOUND
828         return DEVICE_CONNECTED_TO_NAS_P(decode_device(device)) ? Qt : Qnil;
829 #else
830         return Qnil;
831 #endif
832 }
833
834 \f
835 /*****************************************************************/
836 /*                      audio device hack                        */
837 /*****************************************************************/
838 /* Indeed the console->device->frame->window structure is not what I'd call
839  * applicable to audio devices. That is why this seamless fake here exists :)
840  * -hroptatyr
841  */
842 static Lisp_Object
843 audio_device_mark(Lisp_Object obj)
844 {
845         if (XAUDIO_DEVICE_METH(obj, mark))
846                 return XAUDIO_DEVICE_METH(obj, mark)(
847                         XAUDIO_DEVICE_DATA(obj));
848
849         return Qnil;
850 }
851
852 static void
853 audio_device_finalise(void *header, int for_disksave)
854 {
855         Lisp_Audio_Device *ad = (Lisp_Audio_Device*)header;
856
857         SOUND_DEBUG_DEV("GCor asked me to finalise: 0x%lx\n",
858                         (long unsigned int)ad);
859
860         if ( ad == NULL )
861                 return;
862
863         if (audio_device_data(ad) &&
864             audio_device_meth(ad, finish))
865                 audio_device_meth(ad, finish)(audio_device_data(ad));
866
867         if (audio_device_data(ad))
868                 xfree(audio_device_data(ad));
869         audio_device_data(ad) = NULL;
870
871         /* avoid some warning */
872         if (for_disksave);
873 }
874
875 static void
876 audio_device_print(Lisp_Object obj, Lisp_Object printcharfun, int escapeflag)
877 {
878         write_c_string("#<audio-device :type ", printcharfun);
879
880
881         switch (XAUDIO_DEVICE_DRIVER(obj)) {
882         case ADRIVER_OSS:
883                 write_c_string("oss", printcharfun);
884                 break;
885
886         case ADRIVER_NAS:
887                 write_c_string("nas", printcharfun);
888                 break;
889
890         case ADRIVER_ESD:
891                 write_c_string("esd", printcharfun);
892                 break;
893
894         case ADRIVER_POLYP:
895                 write_c_string("polyp", printcharfun);
896                 break;
897
898         case ADRIVER_PULSE:
899                 write_c_string("pulse", printcharfun);
900                 break;
901
902         case ADRIVER_AO:
903                 write_c_string("ao", printcharfun);
904                 break;
905
906         case ADRIVER_JACK:
907                 write_c_string("jack", printcharfun);
908                 break;
909
910         case ADRIVER_ALSA:
911                 write_c_string("alsa", printcharfun);
912                 break;
913
914         case NUMBER_OF_AUDIO_DRIVERS:
915         case ADRIVER_UNKNOWN:
916         default:
917                 write_c_string("unknown", printcharfun);
918                 break;
919         }
920
921         if (XAUDIO_DEVICE_METH(obj, print)) {
922                 XAUDIO_DEVICE_METH(obj, print)(obj, printcharfun, escapeflag);
923         }
924
925         /* info about the general state */
926         write_c_string(" :device-state ", printcharfun);
927         switch (XAUDIO_DEVICE_STATE(obj)) {
928         case ASTATE_DEAD:
929         case ASTATE_SUSPENDED:
930                 write_c_string("#dead", printcharfun);
931                 break;
932         case ASTATE_ALIVE:
933                 write_c_string("#ready", printcharfun);
934                 break;
935
936         case NUMBER_OF_AUDIO_STATES:
937         case ASTATE_UNKNOWN:
938         default:
939                 write_c_string("#unknown", printcharfun);
940                 break;
941         }
942
943         write_c_string(">", printcharfun);
944 }
945
946 static int
947 audio_device_equal(Lisp_Object obj1, Lisp_Object obj2, int depth)
948 {
949         return Qnil;
950
951         /* less warnings */
952         if (depth || obj1 || obj2);
953 }
954
955 static unsigned long
956 audio_device_hash (Lisp_Object obj, int SXE_UNUSED(depth))
957 {
958         return (unsigned long)obj;
959         /* audio_device_hashcode(XAUDIO_DEVICE_DATA(obj)); */
960 }
961
962 static const struct lrecord_description audio_device_description[] = {
963         { XD_INT, offsetof(Lisp_Audio_Device, driver) },
964         { XD_INT, offsetof(Lisp_Audio_Device, state) },
965         { XD_OPAQUE_PTR, offsetof(Lisp_Audio_Device, device_data) },
966         { XD_END }
967 };
968
969 DEFINE_LRECORD_IMPLEMENTATION("audio_device", audio_device,
970                               audio_device_mark, audio_device_print,
971                               audio_device_finalise,
972                               audio_device_equal, audio_device_hash,
973                               audio_device_description,
974                               Lisp_Audio_Device);
975
976 static Lisp_Audio_Device *
977 audio_device_allocate(void)
978 {
979         Lisp_Audio_Device *ad;
980
981         ad = alloc_lcrecord_type(Lisp_Audio_Device, &lrecord_audio_device);
982         return ad;
983 }
984
985 audio_driver decode_audio_type(Lisp_Object type)
986 {
987         audio_driver ad = ADRIVER_UNKNOWN;
988
989         if (0);
990 #ifdef HAVE_OSS_SOUND
991         else if (EQ(type, Qoss))
992                 ad = ADRIVER_OSS;
993 #endif
994 #ifdef HAVE_NAS_SOUND
995         else if (EQ(type, Qnas))
996                 ad = ADRIVER_NAS;
997 #endif
998 #ifdef HAVE_ESD_SOUND
999         else if (EQ(type, Qesd))
1000                 ad = ADRIVER_ESD;
1001 #endif
1002 #ifdef HAVE_POLYP_SOUND
1003         else if (EQ(type, Qpolyp))
1004                 ad = ADRIVER_POLYP;
1005 #endif
1006 #ifdef HAVE_PULSE_SOUND
1007         else if (EQ(type, Qpulse))
1008                 ad = ADRIVER_PULSE;
1009 #endif
1010 #ifdef HAVE_AO_SOUND
1011         else if (EQ(type, Qao))
1012                 ad = ADRIVER_AO;
1013 #endif
1014 #ifdef HAVE_JACK_SOUND
1015         else if (EQ(type, Qjack))
1016                 ad = ADRIVER_JACK;
1017 #endif
1018 #ifdef HAVE_ALSA_SOUND
1019         else if (EQ(type, Qalsa))
1020                 ad = ADRIVER_ALSA;
1021 #endif
1022
1023         return ad;
1024 }
1025
1026 audio_driver decode_audio_device(Lisp_Object device)
1027 {
1028         struct device *d = NULL;
1029         audio_driver ad = ADRIVER_UNKNOWN;
1030
1031         if (NILP(device) && !NILP(Vdefault_audio_device))
1032                 device = Vdefault_audio_device;
1033
1034         if (AUDIO_DEVICEP(device)) {
1035                 ad = XAUDIO_DEVICE_DRIVER(device);
1036
1037         } else if (DEVICEP(device) || NILP(device)) {
1038                 d = decode_device(device);
1039
1040                 if (0);
1041 #ifdef HAVE_NAS_SOUND
1042                 else if (DEVICE_CONNECTED_TO_NAS_P(d))
1043                         ad = ADRIVER_NAS;
1044 #endif
1045 #ifdef HAVE_AO_SOUND
1046                 else if (DEVICE_CONNECTED_TO_AO_P(d))
1047                         ad = ADRIVER_AO;
1048 #endif
1049 #ifdef HAVE_PULSE_SOUND
1050                 else if (DEVICE_CONNECTED_TO_PULSE_P(d))
1051                         ad = ADRIVER_PULSE;
1052 #endif
1053 #ifdef HAVE_POLYP_SOUND
1054                 else if (DEVICE_CONNECTED_TO_POLYP_P(d))
1055                         ad = ADRIVER_POLYP;
1056 #endif
1057 #ifdef HAVE_ESD_SOUND
1058                 else if (DEVICE_CONNECTED_TO_ESD_P(d))
1059                         ad = ADRIVER_ESD;
1060 #endif
1061 #ifdef HAVE_ALSA_SOUND
1062                 else if (DEVICE_CONNECTED_TO_ALSA_P(d))
1063                         ad = ADRIVER_ALSA;
1064 #endif
1065 #ifdef HAVE_OSS_SOUND
1066                 else if (NILP(Vnative_sound_only_on_console) ||
1067                          DEVICE_ON_CONSOLE_P(d))
1068                         ad = ADRIVER_OSS;
1069 #endif
1070         }
1071
1072         return ad;
1073 }
1074
1075 void *get_audio_device_data(Lisp_Object device)
1076 {
1077         if (AUDIO_DEVICEP(device))
1078                 return XAUDIO_DEVICE_DATA(device);
1079         else
1080                 return NULL;
1081 }
1082
1083 Lisp_Audio_Device *get_audio_device(Lisp_Object device)
1084 {
1085         if (AUDIO_DEVICEP(device))
1086                 return XAUDIO_DEVICE(device);
1087         else
1088                 return NULL;
1089 }
1090
1091 \f
1092 static Lisp_Object
1093 make_audio_device(Lisp_Object type)
1094 {
1095         Lisp_Audio_Device *ad;
1096         Lisp_Object lad;
1097
1098         CHECK_SYMBOL(type);
1099
1100         ad = audio_device_allocate();
1101         audio_device_driver(ad) = decode_audio_type(type);
1102         audio_device_data(ad) = NULL;
1103         XSETAUDIO_DEVICE(lad, ad);
1104         XAUDIO_DEVICE_STATE(lad) = ASTATE_UNKNOWN;
1105
1106         return lad;
1107 }
1108
1109 DEFUN("make-audio-device", Fmake_audio_device, 1, MANY, 0,      /*
1110 DRIVER &rest DEVICE-OPTIONS
1111
1112 Create a new device to output audio via DRIVER.
1113 DRIVER should be a symbol out of 'oss, 'nas, 'esd, 'pulse,
1114 'jack, 'alsa, or 'ao.
1115
1116 The rest arguments may be used to pass options to the selected
1117 output driver. These should be `:keyword value' pairs.
1118
1119 Valid keywords for ALSA are:
1120 :device - the name of the hardware interface (default: "default"),
1121   you may want to try "plughw:0,0" first
1122 :keep-open - whether to exclusively reserve the device.
1123   Note this may prevent other applications from using the device.
1124
1125 Valid keywords for (deprecated) OSS are:
1126 :device - the name of the hardware interface (default: "/dev/dsp")
1127 :keep-open - whether to exclusively reserve the device.
1128   Note this may prevent other applications from using the device.
1129
1130 Valid keywords for ESD are:
1131 :server - to use a distant ESD daemon (e.g. "my.machine.box:16001")
1132 The default for ESD output is to use a locally running daemon and
1133 to connect to it via unix domain sockets.
1134
1135 Valid keywords for Pulse are:
1136 :server - the host name to connect to (default: "localhost")
1137 :sink - the name of the sink to connect to (e.g. "output")
1138 :source - the name of the source to record from (e.g. "mic_in")
1139 :client - how to call the client on the server (default "SXEmacs")
1140 :stream - how to call the stream on the server (e.g. "fancy-sound")
1141 :immediate - connect to sink immediately and keep the connection
1142   alive as long as the audio device exists (default `t')
1143 :threaded - initiate a threaded mainloop (default `t')
1144 :force - if non-nil the device object is created even though the
1145   pulse mainloop could not be started; if `nil' any mainloop failure
1146   results in an error.  This can be useful if you want to have an
1147   audio device object although the server is not (yet) up or not
1148   (yet) accepting connections from you. (default `nil')
1149
1150 Valid keywords for Jack are:
1151 :server - the jack server to connect to (default "default")
1152 :client - how to call the client on the server (default "SXEmacs")
1153
1154 Valid keywords for AO are:
1155 :driver - the name of the output driver (e.g. "alsa", "esd", etc.)
1156 :options - a list of AO suboptions (see AO documentation)
1157 The default for AO output is to pass nothing and entirely use the
1158 system and user configuration files.
1159
1160 Valid keywords for NAS are:
1161 :server - the NAS server to connect to.  This can be either:
1162   - an X display string like "localhost:0.0", the X display string
1163     the current frame is on can be obtained by the function
1164     `device-connection'
1165   - or a SXEmacs device name like "localhost-11-0" which can be
1166     obtained by `device-name'
1167   - or a SXEmacs device object, obtainable by `frame-device', like
1168     #<x-device on "localhost:11.0" 0xee4>
1169 If the :server keyword is omitted SXEmacs tries to determine a
1170 sensible default in this order:
1171   - use the frame device of the current frame
1172   - use the frame device of the initial frame
1173   - use the display specified in $AUDIOSERVER
1174   - use the display specified in $DISPLAY
1175   - try "localhost:0.0"
1176
1177 */
1178       (int nargs, Lisp_Object *args))
1179 {
1180         Lisp_Object ad, driver, device_options = Qnil;
1181         audio_driver dev_driver;
1182         ad_device_data *device_data = NULL;
1183
1184         driver = args[0];
1185
1186         CHECK_SYMBOL(driver);
1187         ad = make_audio_device(driver);
1188
1189         dev_driver = XAUDIO_DEVICE_DRIVER(ad);
1190
1191         switch (dev_driver) {
1192         case ADRIVER_NAS:
1193 #ifdef HAVE_NAS_SOUND
1194                 XAUDIO_DEVICE_METHS(ad) = sound_nas;
1195                 break;
1196 #endif
1197         case ADRIVER_ALSA:
1198 #ifdef HAVE_ALSA_SOUND
1199                 XAUDIO_DEVICE_METHS(ad) = sound_alsa;
1200                 break;
1201 #endif
1202         case ADRIVER_OSS:
1203 #ifdef HAVE_OSS_SOUND
1204                 XAUDIO_DEVICE_METHS(ad) = sound_oss;
1205                 break;
1206 #endif
1207         case ADRIVER_AO:
1208 #ifdef HAVE_AO_SOUND
1209                 XAUDIO_DEVICE_METHS(ad) = sound_ao;
1210                 break;
1211 #endif
1212         case ADRIVER_POLYP:
1213         case ADRIVER_PULSE:
1214 #ifdef HAVE_PULSE_SOUND
1215                 XAUDIO_DEVICE_METHS(ad) = sound_pulse;
1216                 break;
1217 #endif
1218         case ADRIVER_ESD:
1219 #ifdef HAVE_ESD_SOUND
1220                 XAUDIO_DEVICE_METHS(ad) = sound_esd;
1221                 break;
1222 #endif
1223         case ADRIVER_JACK:
1224 #ifdef HAVE_JACK_SOUND
1225                 XAUDIO_DEVICE_METHS(ad) = sound_jack;
1226                 break;
1227 #endif
1228         case ADRIVER_UNKNOWN:
1229         case NUMBER_OF_AUDIO_DRIVERS:
1230         default:
1231                 return Qnil;
1232                 break;
1233         }
1234
1235         {
1236                 Lisp_Object tmp = Flist(nargs, args);
1237                 device_options = XCDR(tmp);
1238         }
1239
1240         if (XAUDIO_DEVICE_METH(ad, create) &&
1241             !(device_data = XAUDIO_DEVICE_METH(ad, create)(device_options))) {
1242                 XAUDIO_DEVICE_STATE(ad) = ASTATE_DEAD;
1243         }
1244         XAUDIO_DEVICE_DATA(ad) = device_data;
1245         return ad;
1246 }
1247
1248 DEFUN("audio-device-p", Faudio_device_p, 1, 1, 0, /*
1249 Return non-nil if OBJECT is an audio-device.
1250 */
1251       (object))
1252 {
1253         if (AUDIO_DEVICEP(object))
1254                 return Qt;
1255         else
1256                 return Qnil;
1257 }
1258
1259 #if 0
1260 DEFUN("delete-audio-device", Fdelete_audio_device, 1, 1, 0, /*
1261 Deinitialise the audio device DEVICE and free its resources.
1262 */
1263       (device))
1264 {
1265         CHECK_AUDIO_DEVICE(device);
1266
1267         audio_device_finalise(XAUDIO_DEVICE(device), 0);
1268         return device;
1269 }
1270 #endif
1271
1272 \f
1273 void syms_of_sound(void)
1274 {
1275         INIT_LRECORD_IMPLEMENTATION(audio_device);
1276
1277         defkeyword(&Q_volume, ":volume");
1278         defkeyword(&Q_pitch, ":pitch");
1279         defkeyword(&Q_duration, ":duration");
1280         defkeyword(&Q_sound, ":sound");
1281
1282         /* located in sound.el */
1283         defsymbol(&Qplay_sound, "play-sound");
1284
1285 #ifdef HAVE_NAS_SOUND
1286         defsymbol(&Qnas, "nas");
1287 #endif
1288 #ifdef HAVE_ESD_SOUND
1289         defsymbol(&Qesd, "esd");
1290 #endif
1291 #ifdef HAVE_POLYP_SOUND
1292         defsymbol(&Qpolyp, "polyp");
1293 #endif
1294 #ifdef HAVE_PULSE_SOUND
1295         defsymbol(&Qpulse, "pulse");
1296 #endif
1297 #ifdef HAVE_AO_SOUND
1298         defsymbol(&Qao, "ao");
1299 #endif
1300 #ifdef HAVE_ALSA_SOUND
1301         defsymbol(&Qalsa, "alsa");
1302 #endif
1303 #ifdef HAVE_JACK_SOUND
1304         defsymbol(&Qjack, "jack");
1305 #endif
1306 #ifdef HAVE_OSS_SOUND
1307         defsymbol(&Qoss, "oss");
1308 #endif
1309         defsymbol(&Qaudio_devicep, "audio-device-p");
1310         defsymbol(&Qaudio_jobp, "audio-job-p");
1311
1312         /* some more symbols */
1313         defsymbol(&Q_device, ":device");
1314         defsymbol(&Q_keep_open, ":keep-open");
1315         defsymbol(&Q_server, ":server");
1316         defsymbol(&Q_client, ":client");
1317
1318         DEFSUBR(Fplay_media_stream_synchronously);
1319 #ifdef EF_USE_ASYNEQ
1320         DEFSUBR(Fplay_media_streamX);
1321         DEFSUBR(Fset_audio_job_sentinel);
1322         DEFSUBR(Fpause_audio_job);
1323         DEFSUBR(Fresume_audio_job);
1324         DEFSUBR(Fstop_audio_job);
1325         DEFSUBR(Fset_audio_job_volume);
1326         DEFSUBR(Faudio_job_volume);
1327         DEFSUBR(Fset_audio_job_rate);
1328         DEFSUBR(Faudio_job_rate);
1329 #endif
1330
1331         DEFSUBR(Fding);
1332         DEFSUBR(Fwait_for_sounds);
1333         DEFSUBR(Fconnected_to_nas_p);
1334         DEFSUBR(Fdevice_sound_enabled_p);
1335
1336         /* audio device fake */
1337         DEFSUBR(Fmake_audio_device);
1338         DEFSUBR(Faudio_device_p);
1339 #if 0
1340         DEFSUBR(Fdelete_audio_device); /* too dangerous atm */
1341 #endif
1342 }
1343
1344 void vars_of_sound(void)
1345 {
1346 #ifdef HAVE_OSS_SOUND
1347 #  if 0
1348         Fprovide(intern("native-sound")); /* for compatibility */
1349         /* transition time is over! */
1350 #  endif
1351         Fprovide(intern("oss-sound"));
1352 #endif
1353 #ifdef HAVE_NAS_SOUND
1354         Fprovide(intern("nas-sound"));
1355 #endif
1356 #ifdef HAVE_ESD_SOUND
1357         Fprovide(intern("esd-sound"));
1358 #endif
1359 #ifdef HAVE_POLYP_SOUND
1360         Fprovide(intern("polyp-sound"));
1361 #endif
1362 #ifdef HAVE_PULSE_SOUND
1363         Fprovide(intern("pulse-sound"));
1364 #endif
1365 #ifdef HAVE_AO_SOUND
1366         Fprovide(intern("ao-sound"));
1367 #endif
1368 #ifdef HAVE_ALSA_SOUND
1369         Fprovide(intern("alsa-sound"));
1370 #endif
1371         Fprovide(intern("audio"));
1372
1373         DEFVAR_INT("bell-volume", &bell_volume  /*
1374 *How loud to be, from 0 to 255, where 127 is the norm (100%).
1375 Values above raise the volume and values below lower it.
1376                                                  */ );
1377         bell_volume = 63;
1378
1379         DEFVAR_INT("bell-inhibit-time", &bell_inhibit_time      /*
1380 *Don't ring the bell on the same device more than once within this many seconds.
1381                                                                  */ );
1382         bell_inhibit_time = 0;
1383
1384         DEFVAR_LISP("sound-alist", &Vsound_alist        /*
1385 An alist associating names with sounds.
1386 When `beep' or `ding' is called with one of the name symbols, the associated
1387 sound will be generated instead of the standard beep.
1388
1389 Each element of `sound-alist' is a list describing a sound.
1390 The first element of the list is the name of the sound being defined.
1391 Subsequent elements of the list are alternating keyword/value pairs:
1392
1393 Keyword: Value:
1394 -------  -----
1395 sound    A string of raw sound data (deprecated), or the name of another
1396          sound to play.   The symbol `t' here means use the default X beep.
1397 volume   An integer from 0-100, defaulting to `bell-volume'
1398 pitch    If using the default X beep, the pitch (Hz) to generate.
1399 duration If using the default X beep, the duration (milliseconds).
1400 stream   A media stream object containing the sound.
1401
1402 You should probably add things to this list by calling the function
1403 load-sound-file.
1404
1405 Note: SXEmacs must be built with sound support for your system.  Not all
1406 systems support sound.
1407 Note: The pitch, duration, and volume options are available everywhere,
1408 but many X servers ignore the `pitch' option.
1409
1410 The following beep-types are used by SXEmacs itself:
1411
1412 auto-save-error  when an auto-save does not succeed
1413 command-error    when the emacs command loop catches an error
1414 undefined-key    when you type a key that is undefined
1415 undefined-click  when you use an undefined mouse-click combination
1416 no-completion    during completing-read
1417 y-or-n-p         when you type something other than 'y' or 'n'
1418 yes-or-no-p      when you type something other than 'yes' or 'no'
1419 default          used when nothing else is appropriate.
1420
1421 Other lisp packages may use other beep types, but these are the ones that
1422 the C kernel of Emacs uses.
1423                                                          */ );
1424         Vsound_alist = Qnil;
1425
1426         DEFVAR_LISP("synchronous-sounds", &Vsynchronous_sounds  /*
1427 Play sounds synchronously, if non-nil.
1428 Only applies if SXEmacs has been compiled with a threading library.
1429 Otherwise, sounds are always played synchronously.
1430                                                                  */ );
1431         Vsynchronous_sounds = Qt;
1432
1433         DEFVAR_LISP("native-sound-only-on-console", &Vnative_sound_only_on_console      /*
1434 Non-nil value means play sounds only if SXEmacs is running
1435 on the system console.
1436 Nil means always play sounds, even if running on a non-console tty
1437 or a secondary X display.
1438
1439 This variable only applies to native sound support.
1440                                                                                          */ );
1441         Vnative_sound_only_on_console = Qt;
1442
1443         DEFVAR_LISP("default-audio-device", &Vdefault_audio_device      /*
1444 Default audio device to use.
1445                                                                          */ );
1446         Vdefault_audio_device = Qnil;
1447 }
1448
1449 /* sound.c ends here */