1 /* sound-arts.c - play a sound over the arts
3 Copyright (C) 2006 Sebastian Freundt
5 This file is part of SXEmacs
7 SXEmacs is free software: you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation, either version 3 of the License, or
10 (at your option) any later version.
12 SXEmacs is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program. If not, see <http://www.gnu.org/licenses/>. */
21 /* Synched up with: Not in FSF. */
36 #include "sound-arts.h"
40 #define MYSELF ADRIVER_ARTS
42 #define __ARTS_DEBUG__(args...) fprintf(stderr, "ARTS " args)
43 #ifndef ARTS_DEBUG_FLAG
44 #define ARTS_DEBUG(args...)
46 #define ARTS_DEBUG(args...) __ARTS_DEBUG__(args)
48 #define ARTS_DEBUG_C(args...) ARTS_DEBUG("[connection]: " args)
49 #define ARTS_DEBUG_S(args...) ARTS_DEBUG("[stream]: " args)
50 #define ARTS_DEBUG_COE(args...) ARTS_DEBUG("[coerce]: " args)
51 #define ARTS_DEBUG_AJ(args...) ARTS_DEBUG("[audio-job]: " args)
52 #define ARTS_CRITICAL(args...) __ARTS_DEBUG__("CRITICAL: " args)
55 DECLARE_AUDIO_DEVICE_SIMPLE_METHS(sound_arts);
56 DEFINE_AUDIO_DEVICE_SIMPLE(sound_arts);
60 sound_arts_mark(ad_device_data *devdata)
62 sound_arts_data_t *sad = devdata;
70 sound_arts_print(Lisp_Object device, Lisp_Object pcfun, int ef)
72 sound_arts_data_t *sad = NULL;
74 sad = get_audio_device_data(device);
76 /* cannot use incomplete or corrupt audio devices */
77 if (XAUDIO_DEVICE_DRIVER(device) != MYSELF || sad == NULL) {
78 write_c_string(" VOID", pcfun);
79 /* now that we are here, mark AO device as dead */
80 XAUDIO_DEVICE_STATE(device) = ASTATE_DEAD;
84 /* info about the connected output plugin */
91 static ad_device_data *
92 sound_arts_create(Lisp_Object arts_options)
94 sound_arts_data_t *sad;
95 Lisp_Object opt_server = Qnil;
98 opt_server = Fplist_get(arts_options, intern(":server"), Qnil);
99 if (!NILP(opt_server) && !STRINGP(opt_server)) {
100 wrong_type_argument(Qstringp, opt_server);
104 /* -- initialise -- */
105 sad = xnew_and_zero(sound_arts_data_t);
106 SXE_MUTEX_INIT(&sad->mtx);
108 ARTS_DEBUG_C("created: 0x%x\n", (unsigned int)sad);
114 sound_arts_finish(ad_device_data *data)
116 ARTS_DEBUG("finishing ARTS: 0x%lx\n",
117 (long unsigned int)data);
119 SXE_MUTEX_FINI(&((sound_arts_data_t*)data)->mtx);
120 ARTS_DEBUG("audio-device finished.\n");
127 sound_arts_change_volume(audio_job_t aj, audio_job_event_args_t args)
129 SXE_MUTEX_LOCK(&aj->mtx);
130 aj->volume = args->volume_args;
131 SXE_MUTEX_UNLOCK(&aj->mtx);
135 sound_arts_change_rate(audio_job_t aj, audio_job_event_args_t args)
137 SXE_MUTEX_LOCK(&aj->mtx);
138 aj->ratetrafo = args->rate_args;
139 SXE_MUTEX_UNLOCK(&aj->mtx);
143 sound_arts_change_state(audio_job_t aj, audio_job_event_args_t args)
145 SXE_MUTEX_LOCK(&aj->mtx);
146 switch (args->state_args) {
148 ARTS_DEBUG_AJ("->pause state\n");
149 aj->play_state = MTPSTATE_PAUSE;
152 ARTS_DEBUG_AJ("->resume state\n");
153 aj->play_state = MTPSTATE_RUN;
156 ARTS_DEBUG_AJ("->start state\n");
159 ARTS_DEBUG_AJ("->stop state\n");
160 aj->play_state = MTPSTATE_STOP;
163 case no_audio_job_change_states:
165 ARTS_DEBUG_AJ("->unknown state\n");
168 SXE_MUTEX_UNLOCK(&aj->mtx);
172 sound_arts_handle_aj_events(audio_job_t aj)
173 __attribute__((always_inline));
175 sound_arts_handle_aj_events(audio_job_t aj)
177 sound_arts_aj_data_t *sasd;
178 audio_job_event_t ev = NULL;
181 assert(audio_job_queue(aj));
184 SXE_MUTEX_LOCK(&aj->mtx);
185 sasd = audio_job_device_data(aj);
186 if ((ev = eq_noseeum_dequeue(audio_job_queue(aj))) == NULL) {
187 SXE_MUTEX_UNLOCK(&aj->mtx);
190 SXE_MUTEX_UNLOCK(&aj->mtx);
192 ARTS_DEBUG_AJ("Event 0x%lx\n", (long unsigned int)ev);
193 switch (audio_job_event_kind(ev)) {
194 case aj_change_state:
195 ARTS_DEBUG_AJ("change state event\n");
196 sound_arts_change_state(aj, &audio_job_event_args(ev));
198 case aj_change_volume:
199 ARTS_DEBUG_AJ("change volume event\n");
200 sound_arts_change_volume(aj, &audio_job_event_args(ev));
203 ARTS_DEBUG_AJ("change rate event\n");
204 sound_arts_change_rate(aj, &audio_job_event_args(ev));
206 case no_audio_job_event_kinds:
208 ARTS_CRITICAL("unknown event\n");
211 free_audio_job_event(ev);
213 #endif /* EF_USE_ASYNEQ */
216 arts_push(audio_job_t aj, int nframes)
218 size_t len = 0, tmplen = 0;
219 sxe_media_sample_t *tmpbuf;
220 sound_arts_aj_data_t *sasd = audio_job_device_data(aj);
223 tmpbuf = (sxe_media_sample_t*)(aj->buffer);
224 len = media_stream_meth(aj->substream->up, read)(
225 aj->substream, aj->buffer, nframes);
227 /* set up the volume args */
228 sasd->volargs->volume[0] = sasd->volargs->volume[1] =
230 /* set up the rerate args */
231 sasd->rrargs->tweak = aj->ratetrafo;
233 /* coerce the stuff */
234 tmplen = sasd->mtap->channels*len;
235 for (i = 0; i < sasd->coe_ch_cnt; i++) {
236 ARTS_DEBUG_COE("calling coerce "
237 "%d on b:0x%x l:%d\n",
238 i, (unsigned int)tmpbuf, tmplen);
239 tmplen = CALL_MEDIA_SAMPLE_EFFECT(
240 sasd->coe_chain, i, tmpbuf, tmpbuf, tmplen);
242 /* bring back to S16 or U8 */
243 MEDIA_SAMPLE_FORMAT_DOWNSAMPLE(sasd->msf)(
244 aj->buffer, aj->buffer, tmplen);
246 ARTS_DEBUG_S("writing %u samples...\n", tmplen);
248 tmplen *= sasd->framesize/sasd->mtap->channels;
249 while (i < 500 && /* very arbitrary choice */
250 !(len = arts_write(sasd->as, aj->buffer, tmplen))) {
254 ARTS_DEBUG_S("ACK (written %u)\n", len);
260 sound_arts_play(audio_job_t aj)
263 Lisp_Media_Stream *ms;
264 media_substream *mss;
266 media_thread_play_state mtp;
269 Lisp_Audio_Device *lad = NULL;
270 sound_arts_data_t *sad = NULL;
273 /* subthread stuff */
274 sound_arts_aj_data_t _sasd, *sasd = &_sasd;
275 sxe_mse_volume_args _volargs, *volargs = &_volargs;
276 sxe_mse_rerate_args _rrargs, *rrargs = &_rrargs;
278 int alloced_myself = 0;
280 SOUND_UNPACK_MT(aj, device, ms, mss, lad, sad, sasd->mtap);
282 SXE_MUTEX_LOCK(&sad->mtx);
284 ARTS_DEBUG_C("Device locked.\n");
285 message(GETTEXT("audio-arts: "
287 /* this lock is probably unnecessary */
288 SXE_MUTEX_UNLOCK(&sad->mtx);
295 if (arts_init() == 0) {
297 int sz = snprintf(tmp, sizeof(tmp), "SXEmacs%lx", pthread_self());
298 assert(sz>=0 && sz<sizeof(tmp));
299 sasd->as = arts_play_stream(sasd->mtap->samplerate,
301 sasd->mtap->channels, tmp);
302 arts_stream_set(sasd->as, ARTS_P_BLOCKING, 0);
304 message(GETTEXT("Connecting to aRts daemon failed."));
306 SXE_MUTEX_UNLOCK(&sad->mtx);
310 /* fill the subthread data structure */
311 sasd->msf = MEDIA_SAMPLE_FORMAT(sxe_msf_S16);
312 sasd->framesize = sasd->mtap->channels * sizeof(int16_t);
313 sasd->coe_ch_cnt = 0;
314 audio_job_device_data(aj) = sasd;
316 /* the volume effect */
317 ADD_MEDIA_SAMPLE_EFFECT(
318 sasd->coe_chain, sasd->coe_ch_cnt,
319 MEDIA_SAMPLE_EFFECT(sxe_mse_volume), volargs);
320 volargs->num_channels = sasd->mtap->channels;
321 sasd->volargs = volargs;
323 /* the rerate effect */
324 ADD_MEDIA_SAMPLE_EFFECT(
325 sasd->coe_chain, sasd->coe_ch_cnt,
326 MEDIA_SAMPLE_EFFECT(sxe_mse_rerate), rrargs);
327 rrargs->num_channels = sasd->mtap->channels;
328 rrargs->srcrate = rrargs->tgtrate = 1;
329 sasd->rrargs = rrargs;
332 media_stream_meth(ms, rewind)(mss);
334 if (aj->buffer_alloc_size < SOUND_MAX_AUDIO_FRAME_SIZE) {
336 aj->buffer = xmalloc_atomic(SOUND_MAX_AUDIO_FRAME_SIZE);
337 aj->buffer_alloc_size = SOUND_MAX_AUDIO_FRAME_SIZE;
339 resolution = (sasd->mtap->samplerate * MTPSTATE_REACT_TIME) / 1000000;
341 while (aj->play_state != MTPSTATE_STOP) {
344 if (audio_job_queue(aj)) {
345 sound_arts_handle_aj_events(aj);
349 SXE_MUTEX_LOCK(&sad->mtx);
350 mtp = aj->play_state;
351 SXE_MUTEX_UNLOCK(&sad->mtx);
354 if (!arts_push(aj, resolution))
355 aj->play_state = MTPSTATE_STOP;
358 ARTS_DEBUG("sleeping for %d\n", resolution);
362 case MTPSTATE_UNKNOWN:
364 case NUMBER_OF_MEDIA_THREAD_PLAY_STATES:
366 ARTS_DEBUG("ACK, quit\n");
367 SXE_MUTEX_LOCK(&sad->mtx);
368 aj->play_state = MTPSTATE_STOP;
369 SXE_MUTEX_UNLOCK(&sad->mtx);
374 /* -- Close and shutdown -- */
375 SXE_MUTEX_LOCK(&sad->mtx);
376 if (alloced_myself && aj->buffer) {
380 aj->buffer_alloc_size = 0;
381 SXE_MUTEX_UNLOCK(&sad->mtx);
383 if (sasd && sasd->as) {
384 arts_close_stream(sasd->as);
391 SXE_MUTEX_UNLOCK(&sad->mtx);
397 /* sound-arts.c ends here */