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
40 /* unsupported stub function */
42 static void *d_unsupp(char *drvname
, char *filename
, int freq
, int n_channels
, int *ssize
)
55 /* control structure */
57 void (*func
) (void *, short int *);
62 static void d_arts_func(void *d
, short int *frame
)
63 /* writing / close function */
65 struct ss_outdrv_arts
*drv
= d
;
68 arts_write(drv
->arts
, frame
, drv
->size
);
73 static void *d_arts(char *drvname
, char *filename
, int freq
, int n_channels
, int *ssize
)
76 static struct ss_outdrv_arts drv
;
78 if (drvname
&& strcmp("arts", drvname
) != 0)
81 /* filename specified? get out */
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
)
92 drv
.size
*= sizeof(short int);
98 #else /* CONFOPT_ARTS */
100 #define d_arts d_unsupp
102 #endif /* CONFOPT_ARTS */
104 /************************************************/
114 /* control structure */
116 void (*func
) (void *, short int *);
121 static void d_esd_func(void *d
, short int *frame
)
122 /* write / close function */
124 struct ss_outdrv_esd
*drv
= d
;
127 write(drv
->fd
, frame
, drv
->size
);
132 static void *d_esd(char *drvname
, char *filename
, int freq
, int n_channels
, int *ssize
)
135 static struct ss_outdrv_esd drv
;
138 if (drvname
&& strcmp("esd", drvname
) != 0)
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)
152 drv
.size
*= sizeof(short int);
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 *);
181 static void d_pulse_func(void *d
, short int *frame
)
182 /* write / close function */
184 struct ss_outdrv_pulse
*drv
= d
;
188 pa_simple_write(drv
->pa
, frame
, drv
->size
, &error
);
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
)
198 static struct ss_outdrv_pulse drv
;
201 if (drvname
&& strcmp("pulse", drvname
) != 0)
204 ss
.format
= PA_SAMPLE_S16LE
;
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
)
219 #else /* CONFOPT_PULSEAUDIO */
221 #define d_pulse d_unsupp
223 #endif /* CONFOPT_PULSEAUDIO */
225 /************************************************/
229 /* SGI Irix driver */
231 #include <dmedia/audio.h>
234 /* control structure */
236 void (*func
) (void *, short int *);
241 static void d_sgi_func(void *d
, short int *frame
)
242 /* write / close function */
244 struct ss_outdrv_sgi
*drv
= d
;
247 alWriteFrames(drv
->ap
, frame
, 1);
249 alClosePort(drv
->ap
);
250 alFreeConfig(drv
->ac
);
254 static void *d_sgi(char *drvname
, char *filename
, int freq
, int n_channels
, int *ssize
)
257 static struct ss_outdrv_sgi drv
;
260 if (drvname
&& strcmp("sgi", drvname
) != 0)
263 /* filename specified? get out */
264 if (filename
!= 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()))
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
);
292 #else /* CONFOPT_SGI */
294 #define d_sgi d_unsupp
296 #endif /* CONFOPT_SGI */
298 /************************************************/
300 #ifdef CONFOPT_LINUX_OSS
302 /* Linux OSS driver */
305 #include <sys/ioctl.h>
306 #include <linux/soundcard.h>
310 /* control structure */
312 void (*func
) (void *, short int *);
317 static int is_little_endian(void)
318 /* is this machine little endian? */
321 unsigned char *c
= (unsigned char *) &s
;
326 static void d_oss_func(void *d
, short int *frame
)
327 /* write / close function */
329 struct ss_outdrv_oss
*drv
= d
;
332 write(drv
->fd
, frame
, drv
->size
);
338 static void *d_oss(char *drvname
, char *filename
, int freq
, int n_channels
, int *ssize
)
341 static struct ss_outdrv_oss drv
;
344 if (drvname
&& strcmp("oss", drvname
) != 0)
347 if (filename
== NULL
)
348 filename
= "/dev/dsp";
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)
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) {
370 drv
.size
*= sizeof(short int);
375 #else /* CONFOPT_LINUX_OSS */
377 #define d_oss d_unsupp
379 #endif /* CONFOPT_LINUX_OSS */
381 /************************************************/
383 /* WAV file driver */
386 /* control structure */
388 void (*func
) (void *, short int *);
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
;
418 for (n
= 0; n
< drv
->size
; n
++)
419 fput16(frame
[n
], drv
->fd
);
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
);
435 static void *d_wav(char *drvname
, char *filename
, int freq
, int n_channels
, int *ssize
)
438 static struct ss_outdrv_wav drv
;
440 if (drvname
&& strcmp("wav", drvname
) != 0)
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
;
451 if ((drv
.fd
= fopen(filename
, "w")) == NULL
)
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) */
474 /*******************************************/
476 #ifdef CONFOPT_PTHREADS
478 /* pthread support */
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
);
501 /* wait for data available */
502 pthread_cond_wait(&cond
, &mutex
);
504 /* call the real function */
505 real_drv_func(driver
, frame_cpy
);
508 if (frame_cpy
== NULL
)
512 pthread_mutex_unlock(&mutex
);
517 static void outdev_producer_wrapper(void *d
, short int *frame
)
518 /* wrapper 'producer' function */
522 pthread_mutex_lock(&mutex
);
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
)
568 #endif /* CONFOPT_PTHREADS */
570 /*******************************************/
574 void *ss_outdev_open(char *drvname
, char *file
, int freq
, int n_channels
)
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
) {
587 memcpy(ret
, drv
, size
);
590 thread_setup(ret
, n_channels
);
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
)
607 ss_outdev_write(drv
, NULL
);