waveout outdev now works much better.
[ahxm.git] / ss_outdev.c
blob4c7c878a1deafaa1f9aa36e8d77801837d83f9c1
1 /*
3 Ann Hell Ex Machina - Music Software
4 Copyright (C) 2005/2008 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, int n_channels, int *ssize)
33 /* unsupported stub function */
35 return NULL;
39 /** Arts driver **/
41 #ifdef CONFOPT_ARTS
43 #include <artsc.h>
45 struct ss_outdrv_arts
46 /* control structure */
48 void (*func) (void *, short int *);
49 arts_stream_t arts;
50 int size;
53 static void d_arts_func(void *d, short int *frame)
54 /* writing / close function */
56 struct ss_outdrv_arts *drv = d;
58 if (frame != NULL)
59 arts_write(drv->arts, frame, drv->size);
60 else
61 arts_free();
64 static void *d_arts(const char *drvname, const char *filename, int freq, int n_channels, int *ssize)
65 /* init function */
67 static struct ss_outdrv_arts drv;
69 if (drvname && strcmp("arts", drvname) != 0)
70 return NULL;
72 /* filename specified? get out */
73 if (filename != NULL)
74 return NULL;
76 *ssize = sizeof(struct ss_outdrv_arts);
77 drv.func = d_arts_func;
78 drv.size = n_channels >= 2 ? 2 : 1;
80 if (arts_init() || (drv.arts = arts_play_stream(freq, 16, drv.size, "ahxm")) == NULL)
81 return NULL;
83 drv.size *= sizeof(short int);
85 return &drv;
89 #else /* CONFOPT_ARTS */
91 #define d_arts d_unsupp
93 #endif /* CONFOPT_ARTS */
96 /** ESD driver **/
98 #ifdef CONFOPT_ESD
100 #include <unistd.h>
101 #include <esd.h>
103 struct ss_outdrv_esd
104 /* control structure */
106 void (*func) (void *, short int *);
107 int fd;
108 int size;
111 static void d_esd_func(void *d, short int *frame)
112 /* write / close function */
114 struct ss_outdrv_esd *drv = d;
116 if (frame != NULL)
117 write(drv->fd, frame, drv->size);
118 else
119 close(drv->fd);
122 static void *d_esd(const char *drvname, const char *filename, int freq, int n_channels, int *ssize)
123 /* init function */
125 static struct ss_outdrv_esd drv;
126 esd_format_t format;
128 if (drvname && strcmp("esd", drvname) != 0)
129 return NULL;
131 *ssize = sizeof(struct ss_outdrv_esd);
132 drv.func = d_esd_func;
133 drv.size = n_channels >= 2 ? 2 : 1;
135 format = ESD_STREAM | ESD_PLAY | ESD_BITS16;
136 format |= drv.size == 2 ? ESD_STEREO : ESD_MONO;
138 if (esd_open_sound(filename) < 0 ||
139 (drv.fd = esd_play_stream_fallback(format, freq, NULL, "ahxm")) < 0)
140 return NULL;
142 drv.size *= sizeof(short int);
144 return &drv;
148 #else /* CONFOPT_ESD */
150 #define d_esd d_unsupp
152 #endif /* CONFOPT_ESD */
155 /** Pulseaudio driver **/
157 #ifdef CONFOPT_PULSEAUDIO
159 #include <pulse/simple.h>
160 #include <pulse/error.h>
162 struct ss_outdrv_pulse
163 /* control structure */
165 void (*func) (void *, short int *);
166 pa_simple * pa;
167 int size;
170 static void d_pulse_func(void *d, short int *frame)
171 /* write / close function */
173 struct ss_outdrv_pulse *drv = d;
174 int error;
176 if (frame != NULL)
177 pa_simple_write(drv->pa, frame, drv->size, &error);
178 else {
179 pa_simple_drain(drv->pa, &error);
180 pa_simple_free(drv->pa);
184 static void *d_pulse(const char *drvname, const char *filename, int freq, int n_channels, int *ssize)
185 /* init function */
187 static struct ss_outdrv_pulse drv;
188 pa_sample_spec ss;
190 if (drvname && strcmp("pulse", drvname) != 0)
191 return NULL;
193 ss.format = PA_SAMPLE_S16LE;
194 ss.rate = freq;
195 ss.channels = n_channels;
197 *ssize = sizeof(struct ss_outdrv_pulse);
198 drv.func = d_pulse_func;
199 drv.size = n_channels * sizeof(short int);
201 if ((drv.pa = pa_simple_new(filename, "ahxm", PA_STREAM_PLAYBACK,
202 NULL, "ahxm", &ss, NULL, NULL, NULL)) == NULL)
203 return NULL;
205 return &drv;
208 #else /* CONFOPT_PULSEAUDIO */
210 #define d_pulse d_unsupp
212 #endif /* CONFOPT_PULSEAUDIO */
215 /** SGI Irix driver **/
217 #ifdef CONFOPT_SGI
219 #include <dmedia/audio.h>
221 struct ss_outdrv_sgi
222 /* control structure */
224 void (*func) (void *, short int *);
225 ALconfig ac;
226 ALport ap;
229 static void d_sgi_func(void *d, short int *frame)
230 /* write / close function */
232 struct ss_outdrv_sgi *drv = d;
234 if (frame != NULL)
235 alWriteFrames(drv->ap, frame, 1);
236 else {
237 alClosePort(drv->ap);
238 alFreeConfig(drv->ac);
242 static void *d_sgi(const char *drvname, const char *filename, int freq, int n_channels, int *ssize)
243 /* init function */
245 static struct ss_outdrv_sgi drv;
246 ALpv p[2];
248 if (drvname && strcmp("sgi", drvname) != 0)
249 return NULL;
251 /* filename specified? get out */
252 if (filename != NULL)
253 return NULL;
255 *ssize = sizeof(struct ss_outdrv_sgi);
256 drv.func = d_sgi_func;
258 p[0].param = AL_MASTER_CLOCK;
259 p[0].value.i = AL_CRYSTAL_MCLK_TYPE;
260 p[1].param = AL_RATE;
261 p[1].value.ll = alDoubleToFixed((double) freq);
263 if (!(drv.ac = alNewConfig()))
264 return NULL;
266 if (alSetChannels(drv.ac, n_channels) < 0 ||
267 alSetWidth(drv.ac, AL_SAMPLE_16) < 0 ||
268 alSetSampFmt(drv.ac, AL_SAMPFMT_TWOSCOMP) < 0 ||
269 alSetQueueSize(drv.ac, 2048) < 0 ||
270 alSetDevice(drv.ac, AL_DEFAULT_OUTPUT) < 0 ||
271 alSetParams(alGetDevice(drv.ac), p, 2) < 0 ||
272 !(drv.ap = alOpenPort("ahxm", "w", drv.ac))) {
273 alFreeConfig(drv.ac);
274 return NULL;
277 return &drv;
280 #else /* CONFOPT_SGI */
282 #define d_sgi d_unsupp
284 #endif /* CONFOPT_SGI */
287 /** Linux OSS driver **/
289 #ifdef CONFOPT_LINUX_OSS
291 #include <fcntl.h>
292 #include <sys/ioctl.h>
293 #include <linux/soundcard.h>
294 #include <unistd.h>
296 struct ss_outdrv_oss
297 /* control structure */
299 void (*func) (void *, short int *);
300 int fd;
301 int size;
304 static int is_little_endian(void)
305 /* is this machine little endian? */
307 short s = 1;
308 unsigned char *c = (unsigned char *) &s;
310 return *c == 1;
313 static void d_oss_func(void *d, short int *frame)
314 /* write / close function */
316 struct ss_outdrv_oss *drv = d;
318 if (frame != NULL)
319 write(drv->fd, frame, drv->size);
320 else
321 close(drv->fd);
325 static void *d_oss(const char *drvname, const char *filename, int freq, int n_channels, int *ssize)
326 /* init function */
328 static struct ss_outdrv_oss drv;
329 int fr, st, fm;
331 if (drvname && strcmp("oss", drvname) != 0)
332 return NULL;
334 if (filename == NULL)
335 filename = "/dev/dsp";
337 fr = (2 << 16) | 12;
338 st = n_channels >= 2 ? 1 : 0;
339 fm = is_little_endian()? AFMT_S16_LE : AFMT_S16_BE;
341 *ssize = sizeof(struct ss_outdrv_oss);
342 drv.func = d_oss_func;
343 drv.size = n_channels >= 2 ? 2 : 1;
345 if ((drv.fd = open(filename, O_WRONLY)) < 0)
346 return NULL;
348 if (ioctl(drv.fd, SNDCTL_DSP_SETFRAGMENT, &fr) < 0 ||
349 ioctl(drv.fd, SNDCTL_DSP_RESET, 0) < 0 ||
350 ioctl(drv.fd, SNDCTL_DSP_SPEED, &freq) < 0 ||
351 ioctl(drv.fd, SNDCTL_DSP_STEREO, &st) < 0 ||
352 ioctl(drv.fd, SNDCTL_DSP_SETFMT, &fm) < 0) {
353 close(drv.fd);
354 return NULL;
357 drv.size *= sizeof(short int);
359 return &drv;
362 #else /* CONFOPT_LINUX_OSS */
364 #define d_oss d_unsupp
366 #endif /* CONFOPT_LINUX_OSS */
369 /** WAV file driver **/
371 struct ss_outdrv_wav
372 /* control structure */
374 void (*func) (void *, short int *);
375 FILE *fd;
376 int size;
377 int n_frames;
380 static void fput16(short int i, FILE * f)
381 /* writes a 16 bit integer, in any machine order */
383 fputc(i & 0x00ff, f);
384 fputc((i & 0xff00) >> 8, f);
387 static void fput32(int i, FILE * f)
388 /* writes a 32 bit integer, in any machine order */
390 fputc(i & 0x000000ff, f);
391 fputc((i & 0x0000ff00) >> 8, f);
392 fputc((i & 0x00ff0000) >> 16, f);
393 fputc((i & 0xff000000) >> 24, f);
396 static void d_wav_func(void *d, short int *frame)
397 /* write / close function */
399 struct ss_outdrv_wav *drv = d;
401 if (frame != NULL) {
402 int n;
404 for (n = 0; n < drv->size; n++)
405 fput16(frame[n], drv->fd);
407 drv->n_frames++;
409 else {
410 /* rewind file and write total size */
411 fseek(drv->fd, 4, SEEK_SET);
412 fput32((drv->n_frames * drv->size * 2) + 36, drv->fd);
414 fseek(drv->fd, 40, SEEK_SET);
415 fput32((drv->n_frames * drv->size * 2), drv->fd);
417 fclose(drv->fd);
421 static void *d_wav(const char *drvname, const char *filename, int freq, int n_channels, int *ssize)
422 /* init function */
424 static struct ss_outdrv_wav drv;
426 if (drvname && strcmp("wav", drvname) != 0)
427 return NULL;
429 if (filename == NULL)
430 filename = "output.wav";
432 *ssize = sizeof(struct ss_outdrv_wav);
433 drv.func = d_wav_func;
434 drv.size = n_channels;
435 drv.n_frames = 0;
437 if ((drv.fd = fopen(filename, "wb")) == NULL)
438 return 0;
440 /* write wav header */
442 fwrite("RIFF", 1, 4, drv.fd);
443 fput32(36, drv.fd); /* first checkpoint (offset: 4) */
444 fwrite("WAVE", 1, 4, drv.fd);
445 fwrite("fmt ", 1, 4, drv.fd);
446 fput32(16, drv.fd); /* chunk size */
447 fput16(1, drv.fd); /* 1: uncompressed PCM */
448 fput16(n_channels, drv.fd); /* # of channels */
449 fput32(freq, drv.fd); /* sample rate */
450 fput32(freq * n_channels * 2, drv.fd); /* bytes per second */
451 fput16(n_channels * 2, drv.fd); /* 'block align' */
452 fput16(16, drv.fd); /* 16 bits per sample */
453 fwrite("data", 1, 4, drv.fd);
454 fput32(0, drv.fd); /* second checkpoint (offset: 40) */
456 return &drv;
460 /** Pthread support **/
462 #ifdef CONFOPT_PTHREADS
464 #include <pthread.h>
466 static pthread_t consumer;
467 static pthread_mutex_t mutex;
468 static pthread_cond_t cond;
470 /* the real function inside the driver */
471 static void (*real_drv_func) (void *, short int *) = NULL;
473 /* number of ints in frame_cpy */
474 static int frame_cpy_n = 0;
476 /* a copy of the frame */
477 static short int *frame_cpy = NULL;
479 static void *outdev_thread(void *driver)
480 /* pthread 'consumer' function */
482 pthread_mutex_lock(&mutex);
484 for (;;) {
485 /* wait for data available */
486 pthread_cond_wait(&cond, &mutex);
488 /* call the real function */
489 real_drv_func(driver, frame_cpy);
491 /* no more? */
492 if (frame_cpy == NULL)
493 break;
496 pthread_mutex_unlock(&mutex);
497 return NULL;
501 static void outdev_producer_wrapper(void *d, short int *frame)
502 /* wrapper 'producer' function */
504 int n;
506 pthread_mutex_lock(&mutex);
508 if (frame == NULL) {
509 /* close */
510 free(frame_cpy);
511 frame_cpy = NULL;
512 frame_cpy_n = 0;
514 else {
515 /* copy the frame */
516 for (n = 0; n < frame_cpy_n; n++)
517 frame_cpy[n] = frame[n];
520 pthread_cond_signal(&cond);
521 pthread_mutex_unlock(&mutex);
525 static void thread_setup(void *d, int n_channels)
527 void (**drv) (void *, short int *) = d;
529 /* create the buffer */
530 frame_cpy_n = n_channels;
531 frame_cpy = malloc(frame_cpy_n * sizeof(short int));
533 pthread_mutex_init(&mutex, NULL);
534 pthread_cond_init(&cond, NULL);
536 /* 'patch' the driver */
537 real_drv_func = *drv;
538 *drv = outdev_producer_wrapper;
540 /* launch the thread */
541 pthread_create(&consumer, NULL, outdev_thread, d);
545 #else /* CONFOPT_PTHREADS */
547 void thread_setup(void *d, int n)
549 /* do nothing */
552 #endif /* CONFOPT_PTHREADS */
555 /** win32 waveout support **/
557 #ifdef CONFOPT_WIN32
559 #include <windows.h>
560 #include <mmsystem.h>
562 #define WAVEOUT_BUF_SIZE 4096 * 4
563 #define WAVEOUT_N_BUFFERS 8
565 struct _wob {
566 WAVEHDR header;
567 unsigned char buf[WAVEOUT_BUF_SIZE];
568 int offset;
571 struct ss_outdrv_win32
572 /* control structure */
574 void (*func) (void *, short int *);
575 HWAVEOUT hwaveout;
576 struct _wob wob[WAVEOUT_N_BUFFERS];
577 int wob_i;
578 int size;
581 static void d_win32_func(void *d, short int *frame)
583 struct ss_outdrv_win32 *drv = d;
584 struct _wob *b = &drv->wob[drv->wob_i];
585 int w = 1;
587 if (frame != NULL) {
588 /* fill buffer */
589 memcpy(b->buf + b->offset, frame, drv->size);
590 b->offset += drv->size;
592 /* still not full? do not write then */
593 if (b->offset + drv->size < WAVEOUT_BUF_SIZE)
594 w = 0;
597 if (w) {
598 /* clean previous buffer, if needed */
599 if (b->header.lpData)
600 waveOutUnprepareHeader(drv->hwaveout, &b->header, sizeof(WAVEHDR));
602 /* prepare new buffer */
603 b->header.dwBufferLength = b->offset;
604 b->header.lpData = (LPSTR) b->buf;
606 /* send it */
607 waveOutPrepareHeader(drv->hwaveout, &b->header, sizeof(WAVEHDR));
608 waveOutWrite(drv->hwaveout, &b->header, sizeof(WAVEHDR));
610 if (frame != NULL) {
611 /* next buffer */
612 if (++drv->wob_i == WAVEOUT_N_BUFFERS)
613 drv->wob_i = 0;
615 b = &drv->wob[drv->wob_i];
617 /* reset */
618 b->offset = 0;
621 /* wait until buffer is done */
622 while (b->header.lpData != NULL && !(b->header.dwFlags & WHDR_DONE))
623 Sleep(1);
628 static void *d_win32(const char *drvname, const char *filename, int freq, int n_channels, int *ssize)
630 static struct ss_outdrv_win32 drv;
631 WAVEFORMATEX wfx;
633 if (drvname && strcmp("win32", drvname) != 0)
634 return NULL;
636 memset(&drv, '\0', sizeof(drv));
638 wfx.nSamplesPerSec = freq;
639 wfx.wBitsPerSample = 16;
640 wfx.nChannels = n_channels;
641 wfx.cbSize = 0;
642 wfx.wFormatTag = WAVE_FORMAT_PCM;
643 wfx.nBlockAlign = (wfx.wBitsPerSample >> 3) * wfx.nChannels;
644 wfx.nAvgBytesPerSec = wfx.nBlockAlign * wfx.nSamplesPerSec;
646 if (waveOutOpen(&drv.hwaveout, WAVE_MAPPER,
647 &wfx, 0, 0, CALLBACK_NULL) != MMSYSERR_NOERROR)
648 return NULL;
650 drv.func = d_win32_func;
651 drv.size = n_channels * sizeof(short int);
652 drv.wob_i = 0;
654 *ssize = sizeof(struct ss_outdrv_win32);
656 return &drv;
660 #else /* CONFOPT_WIN32 */
662 #define d_win32 d_unsupp
664 #endif /* CONFOPT_WIN32 */
667 /** Interface **/
669 void *ss_outdev_open(const char *drvname, const char *file, int freq, int n_channels)
671 int size;
672 void *drv;
673 void *ret = NULL;
675 if ((drv = d_arts(drvname, file, freq, n_channels, &size)) != NULL ||
676 (drv = d_esd(drvname, file, freq, n_channels, &size)) != NULL ||
677 (drv = d_pulse(drvname, file, freq, n_channels, &size)) != NULL ||
678 (drv = d_sgi(drvname, file, freq, n_channels, &size)) != NULL ||
679 (drv = d_oss(drvname, file, freq, n_channels, &size)) != NULL ||
680 (drv = d_win32(drvname, file, freq, n_channels, &size)) != NULL ||
681 (drv = d_wav(drvname, file, freq, n_channels, &size)) != NULL) {
682 ret = malloc(size);
683 memcpy(ret, drv, size);
686 thread_setup(ret, n_channels);
688 return ret;
692 void ss_outdev_write(void *drv, short int *frame)
694 void (**func) (void *, short int *) = drv;
696 (*func) (drv, frame);
700 void *ss_outdev_close(void *drv)
702 if (drv != NULL) {
703 ss_outdev_write(drv, NULL);
704 free(drv);
707 return NULL;