1 /* New Generation Sound Functions.
2 Copyright (C) 2006 Sebastian Freundt
4 This file is part of SXEmacs
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.
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.
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/>. */
20 /* Inspired by XEmacs' sound.c written by Jamie Zawinski */
22 /* Synched up with: Not in FSF. */
28 #include "syssignal.h"
32 #include "ui/device.h"
33 #include "ui/redisplay.h"
38 #include "semaphore.h"
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;
55 #ifdef HAVE_ARTS_SOUND
56 #include "sound-arts.h"
58 #ifdef HAVE_POLYP_SOUND
59 #include "sound-polyp.h"
61 #ifdef HAVE_PULSE_SOUND
62 #include "sound-pulse.h"
65 #include "sound-esd.h"
68 #include "sound-nas.h"
70 #ifdef HAVE_JACK_SOUND
71 #include "sound-jack.h"
73 #ifdef HAVE_ALSA_SOUND
74 #include "sound-alsa.h"
78 #include "sound-oss.h"
81 Lisp_Object Qaudio_devicep;
82 Lisp_Object Qaudio_jobp;
83 Lisp_Object Vdefault_audio_device;
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);
89 exec_sentinel(void *job, Lisp_Object, Lisp_Object, Lisp_Object);
92 #include "events/worker-asyneq.h"
94 /*****************************************************************/
96 /*****************************************************************/
97 /* sound-mst handler */
100 mark_audio_job(worker_job_t job)
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);
122 print_audio_job(worker_job_t job, Lisp_Object pcf)
124 audio_job_t aj = audio_job(job);
125 char *str = alloca(64);
127 SXE_MUTEX_LOCK(&aj->mtx);
128 write_c_string(" carrying ", pcf);
129 snprintf(str, 63, " #<audio-job 0x%lx>", (long unsigned int)aj);
130 write_c_string(str, pcf);
131 SXE_MUTEX_UNLOCK(&aj->mtx);
136 finish_audio_job(worker_job_t job)
140 lock_worker_job(job);
143 SOUND_DEBUG_AJ("Finishing audio job 0x%lx (job 0x%lx)\n",
144 (long unsigned int)aj,
145 (long unsigned int)job);
147 finish_audio_job_data(aj);
149 worker_job_data(job) = NULL;
150 unlock_worker_job(job);
155 audio_job_handle(worker_job_t job)
158 /* usually called from aux threads */
161 #if !defined HAVE_BDWGC || !defined EF_USE_BDWGC
162 Lisp_Object ljob = (Lisp_Object)job;
164 int(*playfun)(audio_job_t);
168 lock_worker_job(job);
170 SXE_MUTEX_LOCK(&aj->mtx);
171 SOUND_DEBUG_AJ("inherit scratch buffer 0x%lx (sz=%ld)\n",
172 (long unsigned int)worker_job_buffer(job),
173 (long int)worker_job_buffer_alloc_size(job));
174 aj->buffer = worker_job_buffer(job);
175 aj->buffer_alloc_size = worker_job_buffer_alloc_size(job);
176 device = audio_job_device(job);
177 SOUND_DEBUG_MT("starting thread 0x%lx@0x%lx\n",
178 (long unsigned int)aj,
179 (long unsigned int)job);
180 aj->play_state = MTPSTATE_RUN;
182 SOUND_DEBUG_AJ("fetching play function\n");
183 playfun = XAUDIO_DEVICE(device)->meths->play;
184 SOUND_DEBUG_AJ("fetched 0x%lx\n", (long unsigned int)playfun);
186 SXE_MUTEX_UNLOCK(&aj->mtx);
187 SOUND_DEBUG_AJ("calling play function\n");
189 SOUND_DEBUG_AJ("play function finished\n");
190 unlock_worker_job(job);
196 audio_job_started(worker_job_t job)
198 if (NILP(audio_job_sentinel(job) /* sentinel */)) {
201 /* called from main thread */
202 exec_sentinel(job, audio_job_stream(job), intern("started"),
203 audio_job_sentinel(job));
208 audio_job_finished(worker_job_t job)
210 if (NILP(audio_job_sentinel(job) /* sentinel */)) {
213 /* called from main thread */
214 exec_sentinel(job, audio_job_stream(job), intern("finished"),
215 audio_job_sentinel(job));
219 static struct work_handler_s audio_job_handler = {
220 mark_audio_job, print_audio_job, finish_audio_job,
221 audio_job_handle, audio_job_started, audio_job_finished
225 make_audio_asyneq_job(audio_job_t aj)
227 /* create a job digestible by the asyneq */
228 Lisp_Object job = Qnil;
233 j = make_worker_job(&audio_job_handler);
234 job = wrap_object(j);
235 XWORKER_JOB_DATA(job) = aj;
236 /* the scratch buffer thingie */
237 SXE_MUTEX_LOCK(&aj->mtx);
238 aj->buffer = XWORKER_JOB_BUFFER(job);
239 aj->buffer_alloc_size = XWORKER_JOB_BUFFER_ALLOC_SIZE(job);
240 /* generate an event queue for job control */
241 audio_job_queue(aj) = make_noseeum_event_queue();
242 SXE_MUTEX_UNLOCK(&aj->mtx);
248 DEFUN("set-audio-job-sentinel", Fset_audio_job_sentinel, 2, 2, 0, /*
249 Give JOB the sentinel SENTINEL; `nil' for none.
250 The sentinel is called as a function whenever the stream state changes.
252 The function should take three (optional four) arguments
253 (JOB STREAM STATE &optional OLD-STATE)
255 - JOB is the worker job object currently coping with the stream,
256 - STREAM is bound to the stream object, and
257 - STATE is one of 'unknown, 'started, 'paused, 'stopped, 'finished
258 and indicates the current state of the job
259 - OLD-STATE is again one of the above state symbols but indicates
260 the previous state of the job.
264 CHECK_AUDIO_JOB(job);
265 XAUDIO_JOB_SENTINEL(job) = sentinel;
269 DEFUN("play-media-stream&", Fplay_media_streamX,
271 Play the media stream STREAM on an audio device DEVICE.
273 Optional second argument DEVICE must be an audio device
274 created by `make-audio-device'.
275 If omitted DEVICE defaults to the value of `default-audio-device'.
277 Optional third argument SENTINEL specifies a lisp function to be
278 called whenever the stream state changes. The function should
279 take three (optional four) arguments
280 (JOB STREAM STATE &optional OLD-STATE)
282 - JOB is the worker job object currently coping with the stream,
283 - STREAM is bound to the stream object, and
284 - STATE is one of 'unknown, 'started, 'paused, 'stopped and indicates
285 the current state of the job
286 - OLD-STATE is again one of the above state symbols but indicates
287 the previous state of the job.
289 See also `set-media-thread-sentinel'.
291 Optional fourth argument VOLUME specifies an intial value for
294 (stream, device, sentinel, volume))
297 Lisp_Object job = Qnil;
299 struct gcpro gcpro1, gcpro2, gcpro3, gcpro4;
301 CHECK_MEDIA_STREAM(stream);
304 device = Vdefault_audio_device;
306 CHECK_AUDIO_DEVICE(device);
308 /* hm, it's useful to stop here if default-audio-device is nil,
309 * i merely spit out a warning and return nil, that should suffice
314 GETTEXT("play-media-stream: "
315 "no device specified, "
316 "consider setting `default-audio-device'."));
321 CHECK_NUMBER(volume);
322 volume = Fcoerce_number(volume, Qint, Qnil);
324 if (vol < MEDIA_SAMPLE_VOLUME_MIN)
326 else if (vol > MEDIA_SAMPLE_VOLUME_MAX)
327 vol = MEDIA_SAMPLE_VOLUME_MAX;
329 vol = MEDIA_SAMPLE_VOLUME_NORM;
331 GCPRO4(job, device, stream, sentinel);
332 /* create the job data object */
333 aj = make_audio_job(stream, device, sentinel);
334 if (aj == Qnull_pointer) {
340 /* now prepare the job to dispatch */
341 job = make_audio_asyneq_job(aj);
343 /* ... and dispatch it */
344 eq_enqueue(delegate_eq, job);
345 /* brag about new jobs in the queue */
346 eq_queue_trigger_all(delegate_eq);
350 #endif /* EF_USE_ASYNEQ */
353 /* media thread sentinels */
355 exec_sentinel_unwind(Lisp_Object UNUSED(datum))
361 exec_sentinel(void *job, Lisp_Object stream,
362 Lisp_Object state, Lisp_Object sentinel)
364 /* This function can GC */
365 /* called from main thread */
366 Lisp_Object funcell[4] = {sentinel, (Lisp_Object)job, stream, state};
367 int speccount = specpdl_depth();
370 GCPROn(funcell, countof(funcell));
372 record_unwind_protect(exec_sentinel_unwind, Qnil);
373 /* call the funcell */
374 Ffuncall(countof(funcell), funcell);
375 /* reset to previous state */
376 restore_match_data();
378 unbind_to(speccount, Qnil);
382 static inline audio_job_t
383 allocate_audio_job(void)
385 audio_job_t aj = xnew(struct audio_job_s);
386 SOUND_DEBUG_AJ("allocated: 0x%lx\n", (long unsigned int)aj);
391 make_audio_job(Lisp_Object stream, Lisp_Object device, Lisp_Object sentinel)
393 audio_job_t aj = NULL;
394 media_substream *mss;
396 /* traverse the substreams, try to find the first audio stream */
397 for (mss = XMEDIA_STREAM_FIRST(stream);
398 mss && media_substream_type(mss) != MTYPE_AUDIO;
399 mss = media_substream_next(mss));
403 return Qnull_pointer;
406 aj = allocate_audio_job();
411 aj->sentinel = sentinel;
413 aj->state = MTSTATE_UNKNOWN;
414 aj->play_state = MTPSTATE_UNKNOWN;
416 SXE_MUTEX_INIT(&aj->mtx);
417 audio_job_queue(aj) = NULL;
420 aj->job_device_data = NULL;
421 aj->job_stream_data = NULL;
424 aj->buffer_alloc_size = 0;
426 SOUND_DEBUG_AJ("created: 0x%lx\n", (long unsigned int)aj);
431 finish_audio_job_data(audio_job_t aj)
433 SOUND_DEBUG_AJ("finishing: 0x%lx\n", (long unsigned int)aj);
434 SXE_MUTEX_LOCK(&aj->mtx);
435 if (audio_job_device_data(aj)) {
436 SOUND_DEBUG_AJ("audio-job device data still alive. Bug?\n");
437 audio_job_device_data(aj) = NULL;
439 if (audio_job_stream_data(aj)) {
440 SOUND_DEBUG_AJ("audio-job stream data still alive. Bug?\n");
441 audio_job_stream_data(aj) = NULL;
445 SOUND_CRITICAL("strange, buffer is non-NULL: 0x%lx\n",
446 (long unsigned int)aj->buffer);
447 /* xfree(aj->buffer); */
449 aj->buffer_alloc_size = 0;
452 if (audio_job_queue(aj)) {
453 SOUND_DEBUG_AJ("finishing audio job queue\n");
454 free_event_queue(audio_job_queue(aj));
456 audio_job_queue(aj) = (void*)0xB16B00B5;
457 #endif /* EF_USE_ASYNEQ */
463 SXE_MUTEX_UNLOCK(&aj->mtx);
464 SXE_MUTEX_FINI(&aj->mtx);
466 SOUND_DEBUG_AJ("finished: 0x%lx\n", (long unsigned int)aj);
472 sound_DO_NOT_play_stream(audio_job_t mst)
473 __attribute__((unused));
476 sound_DO_NOT_play_stream(audio_job_t mst)
478 /* just a dummy function */
482 DEFUN("play-media-stream-synchronously", Fplay_media_stream_synchronously,
484 Play the media stream STREAM on an audio device synchronously.
485 This function disregards the value of `synchronous-sounds',
486 instead streams will always be played in synchronous mode.
488 Optional second argument DEVICE must be an audio device
489 created by `make-audio-device'.
490 If omitted DEVICE defaults to the value of `default-audio-device'.
492 Optional third argument SENTINEL specifies a lisp function to be
493 called after the stream playback finishes. The function should
494 take one argument (STREAM) where STREAM is bound to the
495 media stream which finished. See `set-media-thread-sentinel'.
497 Optional fourth argument VOLUME specifies an intial value for
500 (stream, device, sentinel, volume))
505 CHECK_MEDIA_STREAM(stream);
508 device = Vdefault_audio_device;
510 CHECK_AUDIO_DEVICE(device);
512 /* hm, it's useful to stop here if default-audio-device is nil,
513 * i merely spit out a warning and return nil, that should suffice
518 GETTEXT("play-media-stream: "
519 "no device specified, "
520 "consider setting `default-audio-device'."));
525 CHECK_NUMBER(volume);
526 volume = Fcoerce_number(volume, Qint, Qnil);
528 if (vol < MEDIA_SAMPLE_VOLUME_MIN)
530 else if (vol > MEDIA_SAMPLE_VOLUME_MAX)
531 vol = MEDIA_SAMPLE_VOLUME_MAX;
533 vol = MEDIA_SAMPLE_VOLUME_NORM;
536 aj = make_audio_job(stream, device, Qnil);
537 if (aj == Qnull_pointer) {
538 SOUND_DEBUG_AJ("audio job is void ... cancelling play\n");
543 aj->play_state = MTPSTATE_RUN;
545 #if defined EF_USE_ASYNEQ
549 SOUND_DEBUG_AJ("calling play meth\n");
550 XAUDIO_DEVICE(device)->meths->play(aj);
552 if (!NILP(sentinel)) {
554 (void*)Qnil, stream, intern("finished"), sentinel);
557 finish_audio_job_data(aj);
564 struct audio_job_event_s pause_event = {aj_change_state, {aj_pause}, 0};
565 struct audio_job_event_s resume_event = {aj_change_state, {aj_resume}, 0};
566 struct audio_job_event_s start_event = {aj_change_state, {aj_start}, 0};
567 struct audio_job_event_s stop_event = {aj_change_state, {aj_stop}, 0};
568 struct audio_job_event_s volnorm_event = {
569 aj_change_volume, {MEDIA_SAMPLE_VOLUME_NORM}, 0};
570 struct audio_job_event_s volmute_event = {
571 aj_change_volume, {MEDIA_SAMPLE_VOLUME_MIN}, 0};
573 DEFUN("pause-audio-job", Fpause_audio_job, 1, 1, 0, /*
574 Pause the audio job JOB.
575 Optionally JOB can be 'all in which case all running
576 media threads are paused.
580 if (!EQ(job, Qall)) {
581 CHECK_AUDIO_JOB(job);
582 /* connect to job's queue and place a PAUSE event there */
583 if (XAUDIO_JOB_QUEUE(job)) {
584 eq_noseeum_enqueue(XAUDIO_JOB_QUEUE(job), &pause_event);
590 DEFUN("resume-audio-job", Fresume_audio_job, 1, 1, 0, /*
591 Resume a paused audio job JOB.
592 Optionally JOB can be 'all in which case all paused
593 media threads are resumed.
597 if (!EQ(job, Qall)) {
598 CHECK_AUDIO_JOB(job);
599 /* connect to job's queue and place a RESUME event there */
600 if (XAUDIO_JOB_QUEUE(job)) {
601 eq_noseeum_enqueue(XAUDIO_JOB_QUEUE(job),
608 DEFUN("stop-audio-job", Fstop_audio_job, 1, 1, 0, /*
609 Stop a audio job JOB.
610 Optionally JOB can be 'all in which case all media threads
615 if (!EQ(job, Qall)) {
616 CHECK_AUDIO_JOB(job);
617 /* connect to job's queue and place a STOP event there */
618 if (XAUDIO_JOB_QUEUE(job)) {
619 eq_noseeum_enqueue(XAUDIO_JOB_QUEUE(job), &stop_event);
625 DEFUN("set-audio-job-volume", Fset_audio_job_volume, 1, 2, 0, /*
626 Set the volume of the audio job JOB to VOLUME.
628 JOB is assumed to be a media thread object with an audio substream.
629 Optionally JOB can be 'all in which case the volume change
630 applies to all (currently handled) media threads.
632 VOLUME is either a comparable number (see `comparablep') or
633 a vector of comparable numbers.
634 In the former case VOLUME sets the master volume of all channels.
635 In the latter case VOLUME sets the volumes channelwise.
637 Any volume value is coerced to an integer.
638 A volume of 128 is the norm.
639 A volume of 0 is muting the respective channels.
640 Volumes greater than 128 cause an amplification of the stream,
641 255 is the maximal volume value. Note that clipping may occur.
646 Lisp_Object tmpv = Qnil;
648 CHECK_AUDIO_JOB(job);
650 if (XAUDIO_JOB_QUEUE(job)) {
652 XAUDIO_JOB_QUEUE(job), &volnorm_event);
654 return make_int(MEDIA_SAMPLE_VOLUME_NORM);
655 } else if (volume == Qnil) {
656 if (XAUDIO_JOB_QUEUE(job)) {
658 XAUDIO_JOB_QUEUE(job), &volmute_event);
660 return make_int(MEDIA_SAMPLE_VOLUME_NORM);
661 } else if (COMPARABLEP(volume)) {
662 volume = Fcoerce_number(volume, Qint, Qnil);
666 vol = MEDIA_SAMPLE_VOLUME_MIN;
667 else if (vol > MEDIA_SAMPLE_VOLUME_MAX)
668 vol = MEDIA_SAMPLE_VOLUME_MAX;
669 } else if (VECTORP(volume)) {
670 tmpv = XVECTOR_DATA(volume)[0];
671 tmpv = Fcoerce_number(tmpv, Qint, Qnil);
675 vol = MEDIA_SAMPLE_VOLUME_MIN;
676 else if (vol > MEDIA_SAMPLE_VOLUME_MAX)
677 vol = MEDIA_SAMPLE_VOLUME_MAX;
679 return wrong_type_argument(Qnumberp, volume);
682 /* place an VOLCHANGE event in job's queue */
683 if (XAUDIO_JOB_QUEUE(job)) {
684 audio_job_event_t aje = make_audio_job_event(aj_change_volume);
685 audio_job_event_args(aje).volume_args = vol;
686 eq_noseeum_enqueue(XAUDIO_JOB_QUEUE(job), aje);
691 DEFUN("audio-job-volume", Faudio_job_volume, 1, 1, 0, /*
692 Return the current volume of audio job JOB.
696 CHECK_AUDIO_JOB(job);
698 return make_int(XAUDIO_JOB(job)->volume);
701 DEFUN("set-audio-job-rate", Fset_audio_job_rate, 1, 2, 0, /*
702 Set the rate of audio job JOB to RATE.
704 If RATE is `t' or `nil', reset the rate to 1.0.
710 CHECK_AUDIO_JOB(job);
711 if (rate == Qt || rate == Qnil) {
713 } else if (COMPARABLEP(rate)) {
714 rate = Fcoerce_number(rate, Qfloat, Qnil);
715 ratetrafo = XFLOAT_DATA(rate);
717 if (ratetrafo <= 0.5)
719 else if (ratetrafo > 2.0)
722 return wrong_type_argument(Qnumberp, rate);
725 /* place a rate change event in job's queue */
726 if (XAUDIO_JOB_QUEUE(job)) {
727 audio_job_event_t aje = make_audio_job_event(aj_change_rate);
728 audio_job_event_args(aje).rate_args = ratetrafo;
729 eq_noseeum_enqueue(XAUDIO_JOB_QUEUE(job), aje);
734 DEFUN("audio-job-rate", Faudio_job_rate, 1, 1, 0, /*
735 Return the current rate of audio job JOB.
739 CHECK_AUDIO_JOB(job);
741 return make_float(XAUDIO_JOB(job)->ratetrafo);
743 #endif /* EF_USE_ASYNEQ */
746 DEFUN("ding", Fding, 0, 3, 0, /*
747 Beep, or flash the frame.
748 Also, unless an argument is given,
749 terminate any keyboard macro currently executing.
750 When called from lisp, the second argument is what sound to make, and
751 the third argument is the device to make it in (defaults to the selected
752 device), but may also be an audio device created by `make-audio-device'.
754 (arg, sound, device))
756 static time_t last_bell_time;
757 static struct device *last_bell_device;
759 struct device *d = decode_device(device);
760 struct gcpro gcpro1, gcpro2, gcpro3;
762 GCPRO3(arg, sound, device);
764 /* XSETDEVICE(device, d); */
767 if (NILP(arg) && !NILP(Vexecuting_macro))
768 /* Stop executing a keyboard macro. */
770 ("Keyboard macro terminated by a command ringing the bell");
772 if (d == last_bell_device && now - last_bell_time < bell_inhibit_time) {
774 } else if (!NILP(Vvisible_bell) && DEVMETH(d, flash, (d))) {
776 } else if (NILP(sound)) {
777 DEVMETH(d, ring_bell, (d, bell_volume, -1, -1));
778 } else if (!NILP(Ffboundp(Qplay_sound))) {
779 call3(Qplay_sound, sound, Qnil, device);
782 last_bell_time = now;
783 last_bell_device = d;
784 RETURN_UNGCPRO(Qnil);
789 DEFUN("device-sound-enabled-p", Fdevice_sound_enabled_p, 0, 1, 0, /*
790 Return t if DEVICE is able to play sound. Defaults to selected device.
794 if (DEVICEP(device)) {
795 #ifdef HAVE_NAS_SOUND
796 if (DEVICE_CONNECTED_TO_NAS_P(decode_device(device)))
799 #ifdef HAVE_OSS_SOUND
800 if (DEVICE_ON_CONSOLE_P(decode_device(device)))
806 device = Vdefault_audio_device;
809 AUDIO_DEVICEP(device) &&
810 XAUDIO_DEVICE_STATE(device) != ASTATE_DEAD)
817 DEFUN("wait-for-sounds", Fwait_for_sounds, 0, 1, 0, /*
818 Wait for all sounds to finish playing on DEVICE.
826 DEFUN("connected-to-nas-p", Fconnected_to_nas_p, 0, 1, 0, /*
827 Return t if connected to NAS server for sounds on DEVICE.
831 #ifdef HAVE_NAS_SOUND
832 return DEVICE_CONNECTED_TO_NAS_P(decode_device(device)) ? Qt : Qnil;
839 /*****************************************************************/
840 /* audio device hack */
841 /*****************************************************************/
842 /* Indeed the console->device->frame->window structure is not what I'd call
843 * applicable to audio devices. That is why this seamless fake here exists :)
847 audio_device_mark(Lisp_Object obj)
849 if (XAUDIO_DEVICE_METH(obj, mark))
850 return XAUDIO_DEVICE_METH(obj, mark)(
851 XAUDIO_DEVICE_DATA(obj));
857 audio_device_finalise(void *header, int for_disksave)
859 Lisp_Audio_Device *ad = (Lisp_Audio_Device*)header;
861 SOUND_DEBUG_DEV("GCor asked me to finalise: 0x%lx\n",
862 (long unsigned int)ad);
864 if (audio_device_data(ad) &&
865 audio_device_meth(ad, finish))
866 audio_device_meth(ad, finish)(audio_device_data(ad));
868 if (audio_device_data(ad))
869 xfree(audio_device_data(ad));
870 audio_device_data(ad) = NULL;
872 /* avoid some warning */
873 if (for_disksave || ad == NULL);
877 audio_device_print(Lisp_Object obj, Lisp_Object printcharfun, int escapeflag)
879 write_c_string("#<audio-device :type ", printcharfun);
882 switch (XAUDIO_DEVICE_DRIVER(obj)) {
884 write_c_string("oss", printcharfun);
888 write_c_string("arts", printcharfun);
892 write_c_string("nas", printcharfun);
896 write_c_string("esd", printcharfun);
900 write_c_string("polyp", printcharfun);
904 write_c_string("pulse", printcharfun);
908 write_c_string("ao", printcharfun);
912 write_c_string("jack", printcharfun);
916 write_c_string("alsa", printcharfun);
919 case NUMBER_OF_AUDIO_DRIVERS:
920 case ADRIVER_UNKNOWN:
922 write_c_string("unknown", printcharfun);
926 if (XAUDIO_DEVICE_METH(obj, print)) {
927 XAUDIO_DEVICE_METH(obj, print)(obj, printcharfun, escapeflag);
930 /* info about the general state */
931 write_c_string(" :device-state ", printcharfun);
932 switch (XAUDIO_DEVICE_STATE(obj)) {
934 case ASTATE_SUSPENDED:
935 write_c_string("#dead", printcharfun);
938 write_c_string("#ready", printcharfun);
941 case NUMBER_OF_AUDIO_STATES:
944 write_c_string("#unknown", printcharfun);
948 write_c_string(">", printcharfun);
952 audio_device_equal(Lisp_Object obj1, Lisp_Object obj2, int depth)
957 if (depth || obj1 || obj2);
961 audio_device_hash (Lisp_Object obj, int UNUSED(depth))
963 return (unsigned long)obj;
964 /* audio_device_hashcode(XAUDIO_DEVICE_DATA(obj)); */
967 static const struct lrecord_description audio_device_description[] = {
968 { XD_INT, offsetof(Lisp_Audio_Device, driver) },
969 { XD_INT, offsetof(Lisp_Audio_Device, state) },
970 { XD_OPAQUE_PTR, offsetof(Lisp_Audio_Device, device_data) },
974 DEFINE_LRECORD_IMPLEMENTATION("audio_device", audio_device,
975 audio_device_mark, audio_device_print,
976 audio_device_finalise,
977 audio_device_equal, audio_device_hash,
978 audio_device_description,
981 static Lisp_Audio_Device *
982 audio_device_allocate(void)
984 Lisp_Audio_Device *ad;
986 ad = alloc_lcrecord_type(Lisp_Audio_Device, &lrecord_audio_device);
990 audio_driver decode_audio_type(Lisp_Object type)
992 audio_driver ad = ADRIVER_UNKNOWN;
995 #ifdef HAVE_OSS_SOUND
996 else if (EQ(type, Qoss))
999 #ifdef HAVE_NAS_SOUND
1000 else if (EQ(type, Qnas))
1003 #ifdef HAVE_ESD_SOUND
1004 else if (EQ(type, Qesd))
1007 #ifdef HAVE_POLYP_SOUND
1008 else if (EQ(type, Qpolyp))
1011 #ifdef HAVE_PULSE_SOUND
1012 else if (EQ(type, Qpulse))
1015 #ifdef HAVE_AO_SOUND
1016 else if (EQ(type, Qao))
1019 #ifdef HAVE_ARTS_SOUND
1020 else if (EQ(type, Qarts))
1023 #ifdef HAVE_JACK_SOUND
1024 else if (EQ(type, Qjack))
1027 #ifdef HAVE_ALSA_SOUND
1028 else if (EQ(type, Qalsa))
1035 audio_driver decode_audio_device(Lisp_Object device)
1037 struct device *d = NULL;
1038 audio_driver ad = ADRIVER_UNKNOWN;
1040 if (NILP(device) && !NILP(Vdefault_audio_device))
1041 device = Vdefault_audio_device;
1043 if (AUDIO_DEVICEP(device)) {
1044 ad = XAUDIO_DEVICE_DRIVER(device);
1046 } else if (DEVICEP(device) || NILP(device)) {
1047 d = decode_device(device);
1050 #ifdef HAVE_NAS_SOUND
1051 else if (DEVICE_CONNECTED_TO_NAS_P(d))
1054 #ifdef HAVE_AO_SOUND
1055 else if (DEVICE_CONNECTED_TO_AO_P(d))
1058 #ifdef HAVE_PULSE_SOUND
1059 else if (DEVICE_CONNECTED_TO_PULSE_P(d))
1062 #ifdef HAVE_POLYP_SOUND
1063 else if (DEVICE_CONNECTED_TO_POLYP_P(d))
1066 #ifdef HAVE_ESD_SOUND
1067 else if (DEVICE_CONNECTED_TO_ESD_P(d))
1070 #ifdef HAVE_ARTS_SOUND
1071 else if (DEVICE_CONNECTED_TO_ARTS_P(d))
1074 #ifdef HAVE_ALSA_SOUND
1075 else if (DEVICE_CONNECTED_TO_ALSA_P(d))
1078 #ifdef HAVE_OSS_SOUND
1079 else if (NILP(Vnative_sound_only_on_console) ||
1080 DEVICE_ON_CONSOLE_P(d))
1088 void *get_audio_device_data(Lisp_Object device)
1090 if (AUDIO_DEVICEP(device))
1091 return XAUDIO_DEVICE_DATA(device);
1096 Lisp_Audio_Device *get_audio_device(Lisp_Object device)
1098 if (AUDIO_DEVICEP(device))
1099 return XAUDIO_DEVICE(device);
1106 make_audio_device(Lisp_Object type)
1108 Lisp_Audio_Device *ad;
1113 ad = audio_device_allocate();
1114 audio_device_driver(ad) = decode_audio_type(type);
1115 audio_device_data(ad) = NULL;
1116 XSETAUDIO_DEVICE(lad, ad);
1117 XAUDIO_DEVICE_STATE(lad) = ASTATE_UNKNOWN;
1122 DEFUN("make-audio-device", Fmake_audio_device, 1, MANY, 0, /*
1123 DRIVER &rest DEVICE-OPTIONS
1125 Create a new device to output audio via DRIVER.
1126 DRIVER should be a symbol out of 'oss, 'nas, 'esd, 'pulse,
1127 'jack, 'alsa, 'arts or 'ao.
1129 The rest arguments may be used to pass options to the selected
1130 output driver. These should be `:keyword value' pairs.
1132 Valid keywords for ALSA are:
1133 :device - the name of the hardware interface (default: "default"),
1134 you may want to try "plughw:0,0" first
1135 :keep-open - whether to exclusively reserve the device.
1136 Note this may prevent other applications from using the device.
1138 Valid keywords for (deprecated) OSS are:
1139 :device - the name of the hardware interface (default: "/dev/dsp")
1140 :keep-open - whether to exclusively reserve the device.
1141 Note this may prevent other applications from using the device.
1143 Valid keywords for ESD are:
1144 :server - to use a distant ESD daemon (e.g. "my.machine.box:16001")
1145 The default for ESD output is to use a locally running daemon and
1146 to connect to it via unix domain sockets.
1148 Valid keywords for Pulse are:
1149 :server - the host name to connect to (default: "localhost")
1150 :sink - the name of the sink to connect to (e.g. "output")
1151 :source - the name of the source to record from (e.g. "mic_in")
1152 :client - how to call the client on the server (default "SXEmacs")
1153 :stream - how to call the stream on the server (e.g. "fancy-sound")
1154 :immediate - connect to sink immediately and keep the connection
1155 alive as long as the audio device exists (default `t')
1156 :threaded - initiate a threaded mainloop (default `t')
1157 :force - if non-nil the device object is created even though the
1158 pulse mainloop could not be started; if `nil' any mainloop failure
1159 results in an error. This can be useful if you want to have an
1160 audio device object although the server is not (yet) up or not
1161 (yet) accepting connections from you. (default `nil')
1163 Valid keywords for Jack are:
1164 :server - the jack server to connect to (default "default")
1165 :client - how to call the client on the server (default "SXEmacs")
1167 Valid keywords for AO are:
1168 :driver - the name of the output driver (e.g. "alsa", "esd", etc.)
1169 :options - a list of AO suboptions (see AO documentation)
1170 The default for AO output is to pass nothing and entirely use the
1171 system and user configuration files.
1173 Valid keywords for NAS are:
1174 :server - the NAS server to connect to. This can be either:
1175 - an X display string like "localhost:0.0", the X display string
1176 the current frame is on can be obtained by the function
1178 - or a SXEmacs device name like "localhost-11-0" which can be
1179 obtained by `device-name'
1180 - or a SXEmacs device object, obtainable by `frame-device', like
1181 #<x-device on "localhost:11.0" 0xee4>
1182 If the :server keyword is omitted SXEmacs tries to determine a
1183 sensible default in this order:
1184 - use the frame device of the current frame
1185 - use the frame device of the initial frame
1186 - use the display specified in $AUDIOSERVER
1187 - use the display specified in $DISPLAY
1188 - try "localhost:0.0"
1190 Valid keywords for aRts are:
1194 (int nargs, Lisp_Object *args))
1196 Lisp_Object ad, driver, device_options = Qnil;
1197 audio_driver dev_driver;
1198 ad_device_data *device_data = NULL;
1202 CHECK_SYMBOL(driver);
1203 ad = make_audio_device(driver);
1205 dev_driver = XAUDIO_DEVICE_DRIVER(ad);
1207 switch (dev_driver) {
1209 #ifdef HAVE_NAS_SOUND
1210 XAUDIO_DEVICE_METHS(ad) = sound_nas;
1214 #ifdef HAVE_ARTS_SOUND
1215 XAUDIO_DEVICE_METHS(ad) = sound_arts;
1219 #ifdef HAVE_ALSA_SOUND
1220 XAUDIO_DEVICE_METHS(ad) = sound_alsa;
1224 #ifdef HAVE_OSS_SOUND
1225 XAUDIO_DEVICE_METHS(ad) = sound_oss;
1229 #ifdef HAVE_AO_SOUND
1230 XAUDIO_DEVICE_METHS(ad) = sound_ao;
1235 #ifdef HAVE_PULSE_SOUND
1236 XAUDIO_DEVICE_METHS(ad) = sound_pulse;
1240 #ifdef HAVE_ESD_SOUND
1241 XAUDIO_DEVICE_METHS(ad) = sound_esd;
1245 #ifdef HAVE_JACK_SOUND
1246 XAUDIO_DEVICE_METHS(ad) = sound_jack;
1249 case ADRIVER_UNKNOWN:
1250 case NUMBER_OF_AUDIO_DRIVERS:
1257 Lisp_Object tmp = Flist(nargs, args);
1258 device_options = XCDR(tmp);
1261 if (XAUDIO_DEVICE_METH(ad, create) &&
1262 !(device_data = XAUDIO_DEVICE_METH(ad, create)(device_options))) {
1263 XAUDIO_DEVICE_STATE(ad) = ASTATE_DEAD;
1265 XAUDIO_DEVICE_DATA(ad) = device_data;
1269 DEFUN("audio-device-p", Faudio_device_p, 1, 1, 0, /*
1270 Return non-nil if OBJECT is an audio-device.
1274 if (AUDIO_DEVICEP(object))
1281 DEFUN("delete-audio-device", Fdelete_audio_device, 1, 1, 0, /*
1282 Deinitialise the audio device DEVICE and free its resources.
1286 CHECK_AUDIO_DEVICE(device);
1288 audio_device_finalise(XAUDIO_DEVICE(device), 0);
1294 void syms_of_sound(void)
1296 INIT_LRECORD_IMPLEMENTATION(audio_device);
1298 defkeyword(&Q_volume, ":volume");
1299 defkeyword(&Q_pitch, ":pitch");
1300 defkeyword(&Q_duration, ":duration");
1301 defkeyword(&Q_sound, ":sound");
1303 /* located in sound.el */
1304 defsymbol(&Qplay_sound, "play-sound");
1306 #ifdef HAVE_NAS_SOUND
1307 defsymbol(&Qnas, "nas");
1309 #ifdef HAVE_ESD_SOUND
1310 defsymbol(&Qesd, "esd");
1312 #ifdef HAVE_POLYP_SOUND
1313 defsymbol(&Qpolyp, "polyp");
1315 #ifdef HAVE_PULSE_SOUND
1316 defsymbol(&Qpulse, "pulse");
1318 #ifdef HAVE_AO_SOUND
1319 defsymbol(&Qao, "ao");
1321 #ifdef HAVE_ARTS_SOUND
1322 defsymbol(&Qarts, "arts");
1324 #ifdef HAVE_ALSA_SOUND
1325 defsymbol(&Qalsa, "alsa");
1327 #ifdef HAVE_JACK_SOUND
1328 defsymbol(&Qjack, "jack");
1330 #ifdef HAVE_OSS_SOUND
1331 defsymbol(&Qoss, "oss");
1333 defsymbol(&Qaudio_devicep, "audio-device-p");
1334 defsymbol(&Qaudio_jobp, "audio-job-p");
1336 /* some more symbols */
1337 defsymbol(&Q_device, ":device");
1338 defsymbol(&Q_keep_open, ":keep-open");
1339 defsymbol(&Q_server, ":server");
1340 defsymbol(&Q_client, ":client");
1342 DEFSUBR(Fplay_media_stream_synchronously);
1343 #ifdef EF_USE_ASYNEQ
1344 DEFSUBR(Fplay_media_streamX);
1345 DEFSUBR(Fset_audio_job_sentinel);
1346 DEFSUBR(Fpause_audio_job);
1347 DEFSUBR(Fresume_audio_job);
1348 DEFSUBR(Fstop_audio_job);
1349 DEFSUBR(Fset_audio_job_volume);
1350 DEFSUBR(Faudio_job_volume);
1351 DEFSUBR(Fset_audio_job_rate);
1352 DEFSUBR(Faudio_job_rate);
1356 DEFSUBR(Fwait_for_sounds);
1357 DEFSUBR(Fconnected_to_nas_p);
1358 DEFSUBR(Fdevice_sound_enabled_p);
1360 /* audio device fake */
1361 DEFSUBR(Fmake_audio_device);
1362 DEFSUBR(Faudio_device_p);
1364 DEFSUBR(Fdelete_audio_device); /* too dangerous atm */
1368 void vars_of_sound(void)
1370 #ifdef HAVE_OSS_SOUND
1372 Fprovide(intern("native-sound")); /* for compatibility */
1373 /* transition time is over! */
1375 Fprovide(intern("oss-sound"));
1377 #ifdef HAVE_NAS_SOUND
1378 Fprovide(intern("nas-sound"));
1380 #ifdef HAVE_ESD_SOUND
1381 Fprovide(intern("esd-sound"));
1383 #ifdef HAVE_POLYP_SOUND
1384 Fprovide(intern("polyp-sound"));
1386 #ifdef HAVE_PULSE_SOUND
1387 Fprovide(intern("pulse-sound"));
1389 #ifdef HAVE_AO_SOUND
1390 Fprovide(intern("ao-sound"));
1392 #ifdef HAVE_ARTS_SOUND
1393 Fprovide(intern("arts-sound"));
1395 #ifdef HAVE_ALSA_SOUND
1396 Fprovide(intern("alsa-sound"));
1398 Fprovide(intern("audio"));
1400 DEFVAR_INT("bell-volume", &bell_volume /*
1401 *How loud to be, from 0 to 255, where 127 is the norm (100%).
1402 Values above raise the volume and values below lower it.
1406 DEFVAR_INT("bell-inhibit-time", &bell_inhibit_time /*
1407 *Don't ring the bell on the same device more than once within this many seconds.
1409 bell_inhibit_time = 0;
1411 DEFVAR_LISP("sound-alist", &Vsound_alist /*
1412 An alist associating names with sounds.
1413 When `beep' or `ding' is called with one of the name symbols, the associated
1414 sound will be generated instead of the standard beep.
1416 Each element of `sound-alist' is a list describing a sound.
1417 The first element of the list is the name of the sound being defined.
1418 Subsequent elements of the list are alternating keyword/value pairs:
1422 sound A string of raw sound data (deprecated), or the name of another
1423 sound to play. The symbol `t' here means use the default X beep.
1424 volume An integer from 0-100, defaulting to `bell-volume'
1425 pitch If using the default X beep, the pitch (Hz) to generate.
1426 duration If using the default X beep, the duration (milliseconds).
1427 stream A media stream object containing the sound.
1429 You should probably add things to this list by calling the function
1432 Note: SXEmacs must be built with sound support for your system. Not all
1433 systems support sound.
1434 Note: The pitch, duration, and volume options are available everywhere,
1435 but many X servers ignore the `pitch' option.
1437 The following beep-types are used by SXEmacs itself:
1439 auto-save-error when an auto-save does not succeed
1440 command-error when the emacs command loop catches an error
1441 undefined-key when you type a key that is undefined
1442 undefined-click when you use an undefined mouse-click combination
1443 no-completion during completing-read
1444 y-or-n-p when you type something other than 'y' or 'n'
1445 yes-or-no-p when you type something other than 'yes' or 'no'
1446 default used when nothing else is appropriate.
1448 Other lisp packages may use other beep types, but these are the ones that
1449 the C kernel of Emacs uses.
1451 Vsound_alist = Qnil;
1453 DEFVAR_LISP("synchronous-sounds", &Vsynchronous_sounds /*
1454 Play sounds synchronously, if non-nil.
1455 Only applies if SXEmacs has been compiled with a threading library.
1456 Otherwise, sounds are always played synchronously.
1458 Vsynchronous_sounds = Qt;
1460 DEFVAR_LISP("native-sound-only-on-console", &Vnative_sound_only_on_console /*
1461 Non-nil value means play sounds only if SXEmacs is running
1462 on the system console.
1463 Nil means always play sounds, even if running on a non-console tty
1464 or a secondary X display.
1466 This variable only applies to native sound support.
1468 Vnative_sound_only_on_console = Qt;
1470 DEFVAR_LISP("default-audio-device", &Vdefault_audio_device /*
1471 Default audio device to use.
1473 Vdefault_audio_device = Qnil;
1476 /* sound.c ends here */