Use const in ss_output.c where possible.
[ahxm.git] / ss_outdev.c
blobd35dd6dead8b972ff9578049a1f44d9ad7bbe62c
1 /*
3 Ann Hell Ex Machina - Music Software
4 Copyright (C) 2005/2007 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 /*******************
27 Data
28 ********************/
30 #include "config.h"
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <string.h>
36 /*******************
37 Code
38 ********************/
40 /* unsupported stub function */
42 static void *d_unsupp(char *drvname, char *filename, int freq, int n_channels, int *ssize)
44 return NULL;
48 #ifdef CONFOPT_ARTS
50 /* Arts driver */
52 #include <artsc.h>
54 struct ss_outdrv_arts
55 /* control structure */
57 void (*func) (void *, short int *);
58 arts_stream_t arts;
59 int size;
62 static void d_arts_func(void *d, short int *frame)
63 /* writing / close function */
65 struct ss_outdrv_arts *drv = d;
67 if (frame != NULL)
68 arts_write(drv->arts, frame, drv->size);
69 else
70 arts_free();
73 static void *d_arts(char *drvname, char *filename, int freq, int n_channels, int *ssize)
74 /* init function */
76 static struct ss_outdrv_arts drv;
78 if (drvname && strcmp("arts", drvname) != 0)
79 return NULL;
81 /* filename specified? get out */
82 if (filename != NULL)
83 return NULL;
85 *ssize = sizeof(struct ss_outdrv_arts);
86 drv.func = d_arts_func;
87 drv.size = n_channels >= 2 ? 2 : 1;
89 if (arts_init() || (drv.arts = arts_play_stream(freq, 16, drv.size, "ahxm")) == NULL)
90 return NULL;
92 drv.size *= sizeof(short int);
94 return &drv;
98 #else /* CONFOPT_ARTS */
100 #define d_arts d_unsupp
102 #endif /* CONFOPT_ARTS */
104 /************************************************/
106 #ifdef CONFOPT_ESD
108 /* ESD driver */
110 #include <unistd.h>
111 #include <esd.h>
113 struct ss_outdrv_esd
114 /* control structure */
116 void (*func) (void *, short int *);
117 int fd;
118 int size;
121 static void d_esd_func(void *d, short int *frame)
122 /* write / close function */
124 struct ss_outdrv_esd *drv = d;
126 if (frame != NULL)
127 write(drv->fd, frame, drv->size);
128 else
129 close(drv->fd);
132 static void *d_esd(char *drvname, char *filename, int freq, int n_channels, int *ssize)
133 /* init function */
135 static struct ss_outdrv_esd drv;
136 esd_format_t format;
138 if (drvname && strcmp("esd", drvname) != 0)
139 return NULL;
141 *ssize = sizeof(struct ss_outdrv_esd);
142 drv.func = d_esd_func;
143 drv.size = n_channels >= 2 ? 2 : 1;
145 format = ESD_STREAM | ESD_PLAY | ESD_BITS16;
146 format |= drv.size == 2 ? ESD_STEREO : ESD_MONO;
148 if (esd_open_sound(filename) < 0 ||
149 (drv.fd = esd_play_stream_fallback(format, freq, NULL, "ahxm")) < 0)
150 return NULL;
152 drv.size *= sizeof(short int);
154 return &drv;
158 #else /* CONFOPT_ESD */
160 #define d_esd d_unsupp
162 #endif /* CONFOPT_ESD */
164 /************************************************/
166 #ifdef CONFOPT_PULSEAUDIO
168 /* Pulseaudio driver */
170 #include <pulse/simple.h>
171 #include <pulse/error.h>
173 struct ss_outdrv_pulse
174 /* control structure */
176 void (*func) (void *, short int *);
177 pa_simple * pa;
178 int size;
181 static void d_pulse_func(void *d, short int *frame)
182 /* write / close function */
184 struct ss_outdrv_pulse *drv = d;
185 int error;
187 if (frame != NULL)
188 pa_simple_write(drv->pa, frame, drv->size, &error);
189 else {
190 pa_simple_drain(drv->pa, &error);
191 pa_simple_free(drv->pa);
195 static void *d_pulse(char *drvname, char *filename, int freq, int n_channels, int *ssize)
196 /* init function */
198 static struct ss_outdrv_pulse drv;
199 pa_sample_spec ss;
201 if (drvname && strcmp("pulse", drvname) != 0)
202 return NULL;
204 ss.format = PA_SAMPLE_S16LE;
205 ss.rate = freq;
206 ss.channels = n_channels;
208 *ssize = sizeof(struct ss_outdrv_pulse);
209 drv.func = d_pulse_func;
210 drv.size = n_channels * sizeof(short int);
212 if ((drv.pa = pa_simple_new(filename, "ahxm", PA_STREAM_PLAYBACK,
213 NULL, "ahxm", &ss, NULL, NULL, NULL)) == NULL)
214 return NULL;
216 return &drv;
219 #else /* CONFOPT_PULSEAUDIO */
221 #define d_pulse d_unsupp
223 #endif /* CONFOPT_PULSEAUDIO */
225 /************************************************/
227 #ifdef CONFOPT_SGI
229 /* SGI Irix driver */
231 #include <dmedia/audio.h>
233 struct ss_outdrv_sgi
234 /* control structure */
236 void (*func) (void *, short int *);
237 ALconfig ac;
238 ALport ap;
241 static void d_sgi_func(void *d, short int *frame)
242 /* write / close function */
244 struct ss_outdrv_sgi *drv = d;
246 if (frame != NULL)
247 alWriteFrames(drv->ap, frame, 1);
248 else {
249 alClosePort(drv->ap);
250 alFreeConfig(drv->ac);
254 static void *d_sgi(char *drvname, char *filename, int freq, int n_channels, int *ssize)
255 /* init function */
257 static struct ss_outdrv_sgi drv;
258 ALpv p[2];
260 if (drvname && strcmp("sgi", drvname) != 0)
261 return NULL;
263 /* filename specified? get out */
264 if (filename != NULL)
265 return NULL;
267 *ssize = sizeof(struct ss_outdrv_sgi);
268 drv.func = d_sgi_func;
270 p[0].param = AL_MASTER_CLOCK;
271 p[0].value.i = AL_CRYSTAL_MCLK_TYPE;
272 p[1].param = AL_RATE;
273 p[1].value.ll = alDoubleToFixed((double) freq);
275 if (!(drv.ac = alNewConfig()))
276 return NULL;
278 if (alSetChannels(drv.ac, n_channels) < 0 ||
279 alSetWidth(drv.ac, AL_SAMPLE_16) < 0 ||
280 alSetSampFmt(drv.ac, AL_SAMPFMT_TWOSCOMP) < 0 ||
281 alSetQueueSize(drv.ac, 2048) < 0 ||
282 alSetDevice(drv.ac, AL_DEFAULT_OUTPUT) < 0 ||
283 alSetParams(alGetDevice(drv.ac), p, 2) < 0 ||
284 !(drv.ap = alOpenPort("ahxm", "w", drv.ac))) {
285 alFreeConfig(drv.ac);
286 return NULL;
289 return &drv;
292 #else /* CONFOPT_SGI */
294 #define d_sgi d_unsupp
296 #endif /* CONFOPT_SGI */
298 /************************************************/
300 #ifdef CONFOPT_LINUX_OSS
302 /* Linux OSS driver */
304 #include <fcntl.h>
305 #include <sys/ioctl.h>
306 #include <linux/soundcard.h>
307 #include <unistd.h>
309 struct ss_outdrv_oss
310 /* control structure */
312 void (*func) (void *, short int *);
313 int fd;
314 int size;
317 static int is_little_endian(void)
318 /* is this machine little endian? */
320 short s = 1;
321 unsigned char *c = (unsigned char *) &s;
323 return *c == 1;
326 static void d_oss_func(void *d, short int *frame)
327 /* write / close function */
329 struct ss_outdrv_oss *drv = d;
331 if (frame != NULL)
332 write(drv->fd, frame, drv->size);
333 else
334 close(drv->fd);
338 static void *d_oss(char *drvname, char *filename, int freq, int n_channels, int *ssize)
339 /* init function */
341 static struct ss_outdrv_oss drv;
342 int fr, st, fm;
344 if (drvname && strcmp("oss", drvname) != 0)
345 return NULL;
347 if (filename == NULL)
348 filename = "/dev/dsp";
350 fr = (2 << 16) | 12;
351 st = n_channels >= 2 ? 1 : 0;
352 fm = is_little_endian()? AFMT_S16_LE : AFMT_S16_BE;
354 *ssize = sizeof(struct ss_outdrv_oss);
355 drv.func = d_oss_func;
356 drv.size = n_channels >= 2 ? 2 : 1;
358 if ((drv.fd = open(filename, O_WRONLY)) < 0)
359 return NULL;
361 if (ioctl(drv.fd, SNDCTL_DSP_SETFRAGMENT, &fr) < 0 ||
362 ioctl(drv.fd, SNDCTL_DSP_RESET, 0) < 0 ||
363 ioctl(drv.fd, SNDCTL_DSP_SPEED, &freq) < 0 ||
364 ioctl(drv.fd, SNDCTL_DSP_STEREO, &st) < 0 ||
365 ioctl(drv.fd, SNDCTL_DSP_SETFMT, &fm) < 0) {
366 close(drv.fd);
367 return NULL;
370 drv.size *= sizeof(short int);
372 return &drv;
375 #else /* CONFOPT_LINUX_OSS */
377 #define d_oss d_unsupp
379 #endif /* CONFOPT_LINUX_OSS */
381 /************************************************/
383 /* WAV file driver */
385 struct ss_outdrv_wav
386 /* control structure */
388 void (*func) (void *, short int *);
389 FILE *fd;
390 int size;
391 int n_frames;
394 static void fput16(short int i, FILE * f)
395 /* writes a 16 bit integer, in any machine order */
397 fputc(i & 0x00ff, f);
398 fputc((i & 0xff00) >> 8, f);
401 static void fput32(int i, FILE * f)
402 /* writes a 32 bit integer, in any machine order */
404 fputc(i & 0x000000ff, f);
405 fputc((i & 0x0000ff00) >> 8, f);
406 fputc((i & 0x00ff0000) >> 16, f);
407 fputc((i & 0xff000000) >> 24, f);
410 static void d_wav_func(void *d, short int *frame)
411 /* write / close function */
413 struct ss_outdrv_wav *drv = d;
415 if (frame != NULL) {
416 int n;
418 for (n = 0; n < drv->size; n++)
419 fput16(frame[n], drv->fd);
421 drv->n_frames++;
423 else {
424 /* rewind file and write total size */
425 fseek(drv->fd, 4, SEEK_SET);
426 fput32((drv->n_frames * drv->size * 2) + 36, drv->fd);
428 fseek(drv->fd, 40, SEEK_SET);
429 fput32((drv->n_frames * drv->size * 2), drv->fd);
431 fclose(drv->fd);
435 static void *d_wav(char *drvname, char *filename, int freq, int n_channels, int *ssize)
436 /* init function */
438 static struct ss_outdrv_wav drv;
440 if (drvname && strcmp("wav", drvname) != 0)
441 return NULL;
443 if (filename == NULL)
444 filename = "output.wav";
446 *ssize = sizeof(struct ss_outdrv_wav);
447 drv.func = d_wav_func;
448 drv.size = n_channels;
449 drv.n_frames = 0;
451 if ((drv.fd = fopen(filename, "w")) == NULL)
452 return 0;
454 /* write wav header */
456 fwrite("RIFF", 1, 4, drv.fd);
457 fput32(36, drv.fd); /* first checkpoint (offset: 4) */
458 fwrite("WAVE", 1, 4, drv.fd);
459 fwrite("fmt ", 1, 4, drv.fd);
460 fput32(16, drv.fd); /* chunk size */
461 fput16(1, drv.fd); /* 1: uncompressed PCM */
462 fput16(n_channels, drv.fd); /* # of channels */
463 fput32(freq, drv.fd); /* sample rate */
464 fput32(freq * n_channels * 2, drv.fd); /* bytes per second */
465 fput16(n_channels * 2, drv.fd); /* 'block align' */
466 fput16(16, drv.fd); /* 16 bits per sample */
467 fwrite("data", 1, 4, drv.fd);
468 fput32(0, drv.fd); /* second checkpoint (offset: 40) */
470 return &drv;
474 /*******************************************/
476 #ifdef CONFOPT_PTHREADS
478 /* pthread support */
480 #include <pthread.h>
482 static pthread_t consumer;
483 static pthread_mutex_t mutex;
484 static pthread_cond_t cond;
486 /* the real function inside the driver */
487 static void (*real_drv_func) (void *, short int *) = NULL;
489 /* number of ints in frame_cpy */
490 static int frame_cpy_n = 0;
492 /* a copy of the frame */
493 static short int *frame_cpy = NULL;
495 static void *outdev_thread(void *driver)
496 /* pthread 'consumer' function */
498 pthread_mutex_lock(&mutex);
500 for (;;) {
501 /* wait for data available */
502 pthread_cond_wait(&cond, &mutex);
504 /* call the real function */
505 real_drv_func(driver, frame_cpy);
507 /* no more? */
508 if (frame_cpy == NULL)
509 break;
512 pthread_mutex_unlock(&mutex);
513 return NULL;
517 static void outdev_producer_wrapper(void *d, short int *frame)
518 /* wrapper 'producer' function */
520 int n;
522 pthread_mutex_lock(&mutex);
524 if (frame == NULL) {
525 /* close */
526 free(frame_cpy);
527 frame_cpy = NULL;
528 frame_cpy_n = 0;
530 else {
531 /* copy the frame */
532 for (n = 0; n < frame_cpy_n; n++)
533 frame_cpy[n] = frame[n];
536 pthread_cond_signal(&cond);
537 pthread_mutex_unlock(&mutex);
541 static void thread_setup(void *d, int n_channels)
543 void (**drv) (void *, short int *) = d;
545 /* create the buffer */
546 frame_cpy_n = n_channels;
547 frame_cpy = malloc(frame_cpy_n * sizeof(short int));
549 pthread_mutex_init(&mutex, NULL);
550 pthread_cond_init(&cond, NULL);
552 /* 'patch' the driver */
553 real_drv_func = *drv;
554 *drv = outdev_producer_wrapper;
556 /* launch the thread */
557 pthread_create(&consumer, NULL, outdev_thread, d);
561 #else /* CONFOPT_PTHREADS */
563 void thread_setup(void *d, int n)
565 /* do nothing */
568 #endif /* CONFOPT_PTHREADS */
570 /*******************************************/
572 /* interface */
574 void *ss_outdev_open(char *drvname, char *file, int freq, int n_channels)
576 int size;
577 void *drv;
578 void *ret = NULL;
580 if ((drv = d_arts(drvname, file, freq, n_channels, &size)) != NULL ||
581 (drv = d_esd(drvname, file, freq, n_channels, &size)) != NULL ||
582 (drv = d_pulse(drvname, file, freq, n_channels, &size)) != NULL ||
583 (drv = d_sgi(drvname, file, freq, n_channels, &size)) != NULL ||
584 (drv = d_oss(drvname, file, freq, n_channels, &size)) != NULL ||
585 (drv = d_wav(drvname, file, freq, n_channels, &size)) != NULL) {
586 ret = malloc(size);
587 memcpy(ret, drv, size);
590 thread_setup(ret, n_channels);
592 return ret;
596 void ss_outdev_write(void *drv, short int *frame)
598 void (**func) (void *, short int *) = drv;
600 (*func) (drv, frame);
604 void *ss_outdev_close(void *drv)
606 if (drv != NULL) {
607 ss_outdev_write(drv, NULL);
608 free(drv);
611 return NULL;