Print the configured drivers in config and help.
[ahxm.git] / ss_outdev.c
blob7f6444d9d0eb24865d7e18a340d80a8386ce8569
1 /*
3 Ann Hell Ex Machina - Music Software
4 Copyright (C) 2005/2011 Angel Ortega <angel@triptico.com>
6 ss_outdev.c - Softsynth output devices
8 This program is free software; you can redistribute it and/or
9 modify it under the terms of the GNU General Public License
10 as published by the Free Software Foundation; either version 2
11 of the License, or (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
22 http://www.triptico.com
26 #include "config.h"
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <string.h>
32 static void *d_unsupp(const char *drvname, const char *filename, int freq,
33 int n_channels, int *ssize)
34 /* unsupported stub function */
36 return NULL;
40 /** Arts driver **/
42 #ifdef CONFOPT_ARTS
44 #include <artsc.h>
46 struct ss_outdrv_arts
47 /* control structure */
49 void (*func) (void *, short int *);
50 arts_stream_t arts;
51 int size;
54 static void d_arts_func(void *d, short int *frame)
55 /* writing / close function */
57 struct ss_outdrv_arts *drv = d;
59 if (frame != NULL)
60 arts_write(drv->arts, frame, drv->size);
61 else
62 arts_free();
65 static void *d_arts(const char *drvname, const char *filename, int freq,
66 int n_channels, int *ssize)
67 /* init function */
69 static struct ss_outdrv_arts drv;
71 if (drvname && strcmp("arts", drvname) != 0)
72 return NULL;
74 /* filename specified? get out */
75 if (filename != NULL)
76 return NULL;
78 *ssize = sizeof(struct ss_outdrv_arts);
79 drv.func = d_arts_func;
80 drv.size = n_channels >= 2 ? 2 : 1;
82 if (arts_init()
83 || (drv.arts =
84 arts_play_stream(freq, 16, drv.size, "ahxm")) == NULL)
85 return NULL;
87 drv.size *= sizeof(short int);
89 return &drv;
93 #else /* CONFOPT_ARTS */
95 #define d_arts d_unsupp
97 #endif /* CONFOPT_ARTS */
100 /** ESD driver **/
102 #ifdef CONFOPT_ESD
104 #include <unistd.h>
105 #include <esd.h>
107 struct ss_outdrv_esd
108 /* control structure */
110 void (*func) (void *, short int *);
111 int fd;
112 int size;
115 static void d_esd_func(void *d, short int *frame)
116 /* write / close function */
118 struct ss_outdrv_esd *drv = d;
120 if (frame != NULL)
121 write(drv->fd, frame, drv->size);
122 else
123 close(drv->fd);
126 static void *d_esd(const char *drvname, const char *filename, int freq,
127 int n_channels, int *ssize)
128 /* init function */
130 static struct ss_outdrv_esd drv;
131 esd_format_t format;
133 if (drvname && strcmp("esd", drvname) != 0)
134 return NULL;
136 *ssize = sizeof(struct ss_outdrv_esd);
137 drv.func = d_esd_func;
138 drv.size = n_channels >= 2 ? 2 : 1;
140 format = ESD_STREAM | ESD_PLAY | ESD_BITS16;
141 format |= drv.size == 2 ? ESD_STEREO : ESD_MONO;
143 if (esd_open_sound(filename) < 0 ||
144 (drv.fd =
145 esd_play_stream_fallback(format, freq, NULL, "ahxm")) < 0)
146 return NULL;
148 drv.size *= sizeof(short int);
150 return &drv;
154 #else /* CONFOPT_ESD */
156 #define d_esd d_unsupp
158 #endif /* CONFOPT_ESD */
161 /** Pulseaudio driver **/
163 #ifdef CONFOPT_PULSEAUDIO
165 #include <pulse/simple.h>
166 #include <pulse/error.h>
168 struct ss_outdrv_pulse
169 /* control structure */
171 void (*func) (void *, short int *);
172 pa_simple *pa;
173 int size;
176 static void d_pulse_func(void *d, short int *frame)
177 /* write / close function */
179 struct ss_outdrv_pulse *drv = d;
180 int error;
182 if (frame != NULL)
183 pa_simple_write(drv->pa, frame, drv->size, &error);
184 else {
185 pa_simple_drain(drv->pa, &error);
186 pa_simple_free(drv->pa);
190 static void *d_pulse(const char *drvname, const char *filename, int freq,
191 int n_channels, int *ssize)
192 /* init function */
194 static struct ss_outdrv_pulse drv;
195 pa_sample_spec ss;
197 if (drvname && strcmp("pulse", drvname) != 0)
198 return NULL;
200 ss.format = PA_SAMPLE_S16LE;
201 ss.rate = freq;
202 ss.channels = n_channels;
204 *ssize = sizeof(struct ss_outdrv_pulse);
205 drv.func = d_pulse_func;
206 drv.size = n_channels * sizeof(short int);
208 if ((drv.pa = pa_simple_new(filename, "ahxm", PA_STREAM_PLAYBACK,
209 NULL, "ahxm", &ss, NULL, NULL,
210 NULL)) == NULL)
211 return NULL;
213 return &drv;
216 #else /* CONFOPT_PULSEAUDIO */
218 #define d_pulse d_unsupp
220 #endif /* CONFOPT_PULSEAUDIO */
223 /** SGI Irix driver **/
225 #ifdef CONFOPT_SGI
227 #include <dmedia/audio.h>
229 struct ss_outdrv_sgi
230 /* control structure */
232 void (*func) (void *, short int *);
233 ALconfig ac;
234 ALport ap;
237 static void d_sgi_func(void *d, short int *frame)
238 /* write / close function */
240 struct ss_outdrv_sgi *drv = d;
242 if (frame != NULL)
243 alWriteFrames(drv->ap, frame, 1);
244 else {
245 alClosePort(drv->ap);
246 alFreeConfig(drv->ac);
250 static void *d_sgi(const char *drvname, const char *filename, int freq,
251 int n_channels, int *ssize)
252 /* init function */
254 static struct ss_outdrv_sgi drv;
255 ALpv p[2];
257 if (drvname && strcmp("sgi", drvname) != 0)
258 return NULL;
260 /* filename specified? get out */
261 if (filename != NULL)
262 return NULL;
264 *ssize = sizeof(struct ss_outdrv_sgi);
265 drv.func = d_sgi_func;
267 p[0].param = AL_MASTER_CLOCK;
268 p[0].value.i = AL_CRYSTAL_MCLK_TYPE;
269 p[1].param = AL_RATE;
270 p[1].value.ll = alDoubleToFixed((double) freq);
272 if (!(drv.ac = alNewConfig()))
273 return NULL;
275 if (alSetChannels(drv.ac, n_channels) < 0 ||
276 alSetWidth(drv.ac, AL_SAMPLE_16) < 0 ||
277 alSetSampFmt(drv.ac, AL_SAMPFMT_TWOSCOMP) < 0 ||
278 alSetQueueSize(drv.ac, 2048) < 0 ||
279 alSetDevice(drv.ac, AL_DEFAULT_OUTPUT) < 0 ||
280 alSetParams(alGetDevice(drv.ac), p, 2) < 0 ||
281 !(drv.ap = alOpenPort("ahxm", "w", drv.ac))) {
282 alFreeConfig(drv.ac);
283 return NULL;
286 return &drv;
289 #else /* CONFOPT_SGI */
291 #define d_sgi d_unsupp
293 #endif /* CONFOPT_SGI */
296 /** Linux OSS driver **/
298 #ifdef CONFOPT_LINUX_OSS
300 #include <fcntl.h>
301 #include <sys/ioctl.h>
302 #include <linux/soundcard.h>
303 #include <unistd.h>
305 struct ss_outdrv_oss
306 /* control structure */
308 void (*func) (void *, short int *);
309 int fd;
310 int size;
313 static int is_little_endian(void)
314 /* is this machine little endian? */
316 short s = 1;
317 unsigned char *c = (unsigned char *) &s;
319 return *c == 1;
322 static void d_oss_func(void *d, short int *frame)
323 /* write / close function */
325 struct ss_outdrv_oss *drv = d;
327 if (frame != NULL)
328 write(drv->fd, frame, drv->size);
329 else
330 close(drv->fd);
334 static void *d_oss(const char *drvname, const char *filename, int freq,
335 int n_channels, int *ssize)
336 /* init function */
338 static struct ss_outdrv_oss drv;
339 int fr, st, fm;
341 if (drvname && strcmp("oss", drvname) != 0)
342 return NULL;
344 if (filename == NULL)
345 filename = "/dev/dsp";
347 fr = (2 << 16) | 12;
348 st = n_channels >= 2 ? 1 : 0;
349 fm = is_little_endian()? AFMT_S16_LE : AFMT_S16_BE;
351 *ssize = sizeof(struct ss_outdrv_oss);
352 drv.func = d_oss_func;
353 drv.size = n_channels >= 2 ? 2 : 1;
355 if ((drv.fd = open(filename, O_WRONLY)) < 0)
356 return NULL;
358 if (ioctl(drv.fd, SNDCTL_DSP_SETFRAGMENT, &fr) < 0 ||
359 ioctl(drv.fd, SNDCTL_DSP_RESET, 0) < 0 ||
360 ioctl(drv.fd, SNDCTL_DSP_SPEED, &freq) < 0 ||
361 ioctl(drv.fd, SNDCTL_DSP_STEREO, &st) < 0 ||
362 ioctl(drv.fd, SNDCTL_DSP_SETFMT, &fm) < 0) {
363 close(drv.fd);
364 return NULL;
367 drv.size *= sizeof(short int);
369 return &drv;
372 #else /* CONFOPT_LINUX_OSS */
374 #define d_oss d_unsupp
376 #endif /* CONFOPT_LINUX_OSS */
379 /** WAV file driver **/
381 struct ss_outdrv_wav
382 /* control structure */
384 void (*func) (void *, short int *);
385 FILE *fd;
386 int size;
387 int n_frames;
390 static void fput16(short int i, FILE * f)
391 /* writes a 16 bit integer, in any machine order */
393 fputc(i & 0x00ff, f);
394 fputc((i & 0xff00) >> 8, f);
397 static void fput32(int i, FILE * f)
398 /* writes a 32 bit integer, in any machine order */
400 fputc(i & 0x000000ff, f);
401 fputc((i & 0x0000ff00) >> 8, f);
402 fputc((i & 0x00ff0000) >> 16, f);
403 fputc((i & 0xff000000) >> 24, f);
406 static void d_wav_func(void *d, short int *frame)
407 /* write / close function */
409 struct ss_outdrv_wav *drv = d;
411 if (frame != NULL) {
412 int n;
414 for (n = 0; n < drv->size; n++)
415 fput16(frame[n], drv->fd);
417 drv->n_frames++;
419 else {
420 /* rewind file and write total size */
421 fseek(drv->fd, 4, SEEK_SET);
422 fput32((drv->n_frames * drv->size * 2) + 36, drv->fd);
424 fseek(drv->fd, 40, SEEK_SET);
425 fput32((drv->n_frames * drv->size * 2), drv->fd);
427 fclose(drv->fd);
431 static void *d_wav(const char *drvname, const char *filename, int freq,
432 int n_channels, int *ssize)
433 /* init function */
435 static struct ss_outdrv_wav drv;
437 if (drvname && strcmp("wav", drvname) != 0)
438 return NULL;
440 if (filename == NULL)
441 filename = "output.wav";
443 *ssize = sizeof(struct ss_outdrv_wav);
444 drv.func = d_wav_func;
445 drv.size = n_channels;
446 drv.n_frames = 0;
448 if ((drv.fd = fopen(filename, "wb")) == NULL)
449 return 0;
451 /* write wav header */
453 fwrite("RIFF", 1, 4, drv.fd);
454 fput32(36, drv.fd); /* first checkpoint (offset: 4) */
455 fwrite("WAVE", 1, 4, drv.fd);
456 fwrite("fmt ", 1, 4, drv.fd);
457 fput32(16, drv.fd); /* chunk size */
458 fput16(1, drv.fd); /* 1: uncompressed PCM */
459 fput16(n_channels, drv.fd); /* # of channels */
460 fput32(freq, drv.fd); /* sample rate */
461 fput32(freq * n_channels * 2, drv.fd); /* bytes per second */
462 fput16(n_channels * 2, drv.fd); /* 'block align' */
463 fput16(16, drv.fd); /* 16 bits per sample */
464 fwrite("data", 1, 4, drv.fd);
465 fput32(0, drv.fd); /* second checkpoint (offset: 40) */
467 return &drv;
471 /** Pthread support **/
473 #ifdef CONFOPT_PTHREADS
475 #include <pthread.h>
477 static pthread_t consumer;
478 static pthread_mutex_t mutex;
479 static pthread_cond_t cond;
481 /* the real function inside the driver */
482 static void (*real_drv_func) (void *, short int *) = NULL;
484 /* number of ints in frame_cpy */
485 static int frame_cpy_n = 0;
487 /* a copy of the frame */
488 static short int *frame_cpy = NULL;
490 static void *outdev_thread(void *driver)
491 /* pthread 'consumer' function */
493 pthread_mutex_lock(&mutex);
495 for (;;) {
496 /* wait for data available */
497 pthread_cond_wait(&cond, &mutex);
499 /* call the real function */
500 real_drv_func(driver, frame_cpy);
502 /* no more? */
503 if (frame_cpy == NULL)
504 break;
507 pthread_mutex_unlock(&mutex);
508 return NULL;
512 static void outdev_producer_wrapper(void *d, short int *frame)
513 /* wrapper 'producer' function */
515 int n;
517 pthread_mutex_lock(&mutex);
519 if (frame == NULL) {
520 /* close */
521 free(frame_cpy);
522 frame_cpy = NULL;
523 frame_cpy_n = 0;
525 else {
526 /* copy the frame */
527 for (n = 0; n < frame_cpy_n; n++)
528 frame_cpy[n] = frame[n];
531 pthread_cond_signal(&cond);
532 pthread_mutex_unlock(&mutex);
536 static void thread_setup(void *d, int n_channels)
538 void (**drv) (void *, short int *) = d;
540 /* create the buffer */
541 frame_cpy_n = n_channels;
542 frame_cpy = malloc(frame_cpy_n * sizeof(short int));
544 pthread_mutex_init(&mutex, NULL);
545 pthread_cond_init(&cond, NULL);
547 /* 'patch' the driver */
548 real_drv_func = *drv;
549 *drv = outdev_producer_wrapper;
551 /* launch the thread */
552 pthread_create(&consumer, NULL, outdev_thread, d);
556 #else /* CONFOPT_PTHREADS */
558 void thread_setup(void *d, int n)
560 /* do nothing */
563 #endif /* CONFOPT_PTHREADS */
566 /** win32 waveout support **/
568 #ifdef CONFOPT_WIN32
570 #include <windows.h>
571 #include <mmsystem.h>
573 #define WAVEOUT_BUF_SIZE 4096 * 4
574 #define WAVEOUT_N_BUFFERS 8
576 struct _wob {
577 WAVEHDR header;
578 unsigned char buf[WAVEOUT_BUF_SIZE];
579 int offset;
582 struct ss_outdrv_win32
583 /* control structure */
585 void (*func) (void *, short int *);
586 HWAVEOUT hwaveout;
587 struct _wob wob[WAVEOUT_N_BUFFERS];
588 int wob_i;
589 int size;
592 static void d_win32_func(void *d, short int *frame)
594 struct ss_outdrv_win32 *drv = d;
595 struct _wob *b = &drv->wob[drv->wob_i];
596 int w = 1;
598 if (frame != NULL) {
599 /* fill buffer */
600 memcpy(b->buf + b->offset, frame, drv->size);
601 b->offset += drv->size;
603 /* still not full? do not write then */
604 if (b->offset + drv->size < WAVEOUT_BUF_SIZE)
605 w = 0;
608 if (w) {
609 /* clean previous buffer, if needed */
610 if (b->header.lpData)
611 waveOutUnprepareHeader(drv->hwaveout, &b->header,
612 sizeof(WAVEHDR));
614 /* prepare new buffer */
615 b->header.dwBufferLength = b->offset;
616 b->header.lpData = (LPSTR) b->buf;
618 /* send it */
619 waveOutPrepareHeader(drv->hwaveout, &b->header, sizeof(WAVEHDR));
620 waveOutWrite(drv->hwaveout, &b->header, sizeof(WAVEHDR));
622 if (frame != NULL) {
623 /* next buffer */
624 if (++drv->wob_i == WAVEOUT_N_BUFFERS)
625 drv->wob_i = 0;
627 b = &drv->wob[drv->wob_i];
629 /* reset */
630 b->offset = 0;
633 /* wait until buffer is done */
634 while (b->header.lpData != NULL
635 && !(b->header.dwFlags & WHDR_DONE))
636 Sleep(1);
641 static void *d_win32(const char *drvname, const char *filename, int freq,
642 int n_channels, int *ssize)
644 static struct ss_outdrv_win32 drv;
645 WAVEFORMATEX wfx;
647 if (drvname && strcmp("win32", drvname) != 0)
648 return NULL;
650 memset(&drv, '\0', sizeof(drv));
652 wfx.nSamplesPerSec = freq;
653 wfx.wBitsPerSample = 16;
654 wfx.nChannels = n_channels;
655 wfx.cbSize = 0;
656 wfx.wFormatTag = WAVE_FORMAT_PCM;
657 wfx.nBlockAlign = (wfx.wBitsPerSample >> 3) * wfx.nChannels;
658 wfx.nAvgBytesPerSec = wfx.nBlockAlign * wfx.nSamplesPerSec;
660 if (waveOutOpen(&drv.hwaveout, WAVE_MAPPER,
661 &wfx, 0, 0, CALLBACK_NULL) != MMSYSERR_NOERROR)
662 return NULL;
664 drv.func = d_win32_func;
665 drv.size = n_channels * sizeof(short int);
666 drv.wob_i = 0;
668 *ssize = sizeof(struct ss_outdrv_win32);
670 return &drv;
674 #else /* CONFOPT_WIN32 */
676 #define d_win32 d_unsupp
678 #endif /* CONFOPT_WIN32 */
681 /** Interface **/
683 void *ss_outdev_open(const char *drvname, const char *file, int freq,
684 int n_channels)
686 int size;
687 void *drv;
688 void *ret = NULL;
690 if ((drv = d_arts(drvname, file, freq, n_channels, &size)) != NULL ||
691 (drv = d_esd(drvname, file, freq, n_channels, &size)) != NULL ||
692 (drv = d_pulse(drvname, file, freq, n_channels, &size)) != NULL ||
693 (drv = d_sgi(drvname, file, freq, n_channels, &size)) != NULL ||
694 (drv = d_oss(drvname, file, freq, n_channels, &size)) != NULL ||
695 (drv = d_win32(drvname, file, freq, n_channels, &size)) != NULL ||
696 (drv = d_wav(drvname, file, freq, n_channels, &size)) != NULL) {
697 ret = malloc(size);
698 memcpy(ret, drv, size);
701 thread_setup(ret, n_channels);
703 return ret;
707 void ss_outdev_write(void *drv, short int *frame)
709 void (**func) (void *, short int *) = drv;
711 (*func) (drv, frame);
715 void *ss_outdev_close(void *drv)
717 if (drv != NULL) {
718 ss_outdev_write(drv, NULL);
719 free(drv);
722 return NULL;