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
32 static void *d_unsupp(const char *drvname
, const char *filename
, int freq
, int n_channels
, int *ssize
)
33 /* unsupported stub function */
46 /* control structure */
48 void (*func
) (void *, short int *);
53 static void d_arts_func(void *d
, short int *frame
)
54 /* writing / close function */
56 struct ss_outdrv_arts
*drv
= d
;
59 arts_write(drv
->arts
, frame
, drv
->size
);
64 static void *d_arts(const char *drvname
, const char *filename
, int freq
, int n_channels
, int *ssize
)
67 static struct ss_outdrv_arts drv
;
69 if (drvname
&& strcmp("arts", drvname
) != 0)
72 /* filename specified? get out */
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
)
83 drv
.size
*= sizeof(short int);
89 #else /* CONFOPT_ARTS */
91 #define d_arts d_unsupp
93 #endif /* CONFOPT_ARTS */
104 /* control structure */
106 void (*func
) (void *, short int *);
111 static void d_esd_func(void *d
, short int *frame
)
112 /* write / close function */
114 struct ss_outdrv_esd
*drv
= d
;
117 write(drv
->fd
, frame
, drv
->size
);
122 static void *d_esd(const char *drvname
, const char *filename
, int freq
, int n_channels
, int *ssize
)
125 static struct ss_outdrv_esd drv
;
128 if (drvname
&& strcmp("esd", drvname
) != 0)
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)
142 drv
.size
*= sizeof(short int);
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 *);
170 static void d_pulse_func(void *d
, short int *frame
)
171 /* write / close function */
173 struct ss_outdrv_pulse
*drv
= d
;
177 pa_simple_write(drv
->pa
, frame
, drv
->size
, &error
);
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
)
187 static struct ss_outdrv_pulse drv
;
190 if (drvname
&& strcmp("pulse", drvname
) != 0)
193 ss
.format
= PA_SAMPLE_S16LE
;
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
)
208 #else /* CONFOPT_PULSEAUDIO */
210 #define d_pulse d_unsupp
212 #endif /* CONFOPT_PULSEAUDIO */
215 /** SGI Irix driver **/
219 #include <dmedia/audio.h>
222 /* control structure */
224 void (*func
) (void *, short int *);
229 static void d_sgi_func(void *d
, short int *frame
)
230 /* write / close function */
232 struct ss_outdrv_sgi
*drv
= d
;
235 alWriteFrames(drv
->ap
, frame
, 1);
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
)
245 static struct ss_outdrv_sgi drv
;
248 if (drvname
&& strcmp("sgi", drvname
) != 0)
251 /* filename specified? get out */
252 if (filename
!= 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()))
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
);
280 #else /* CONFOPT_SGI */
282 #define d_sgi d_unsupp
284 #endif /* CONFOPT_SGI */
287 /** Linux OSS driver **/
289 #ifdef CONFOPT_LINUX_OSS
292 #include <sys/ioctl.h>
293 #include <linux/soundcard.h>
297 /* control structure */
299 void (*func
) (void *, short int *);
304 static int is_little_endian(void)
305 /* is this machine little endian? */
308 unsigned char *c
= (unsigned char *) &s
;
313 static void d_oss_func(void *d
, short int *frame
)
314 /* write / close function */
316 struct ss_outdrv_oss
*drv
= d
;
319 write(drv
->fd
, frame
, drv
->size
);
325 static void *d_oss(const char *drvname
, const char *filename
, int freq
, int n_channels
, int *ssize
)
328 static struct ss_outdrv_oss drv
;
331 if (drvname
&& strcmp("oss", drvname
) != 0)
334 if (filename
== NULL
)
335 filename
= "/dev/dsp";
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)
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) {
357 drv
.size
*= sizeof(short int);
362 #else /* CONFOPT_LINUX_OSS */
364 #define d_oss d_unsupp
366 #endif /* CONFOPT_LINUX_OSS */
369 /** WAV file driver **/
372 /* control structure */
374 void (*func
) (void *, short int *);
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
;
404 for (n
= 0; n
< drv
->size
; n
++)
405 fput16(frame
[n
], drv
->fd
);
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
);
421 static void *d_wav(const char *drvname
, const char *filename
, int freq
, int n_channels
, int *ssize
)
424 static struct ss_outdrv_wav drv
;
426 if (drvname
&& strcmp("wav", drvname
) != 0)
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
;
437 if ((drv
.fd
= fopen(filename
, "wb")) == NULL
)
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) */
460 /** Pthread support **/
462 #ifdef CONFOPT_PTHREADS
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
);
485 /* wait for data available */
486 pthread_cond_wait(&cond
, &mutex
);
488 /* call the real function */
489 real_drv_func(driver
, frame_cpy
);
492 if (frame_cpy
== NULL
)
496 pthread_mutex_unlock(&mutex
);
501 static void outdev_producer_wrapper(void *d
, short int *frame
)
502 /* wrapper 'producer' function */
506 pthread_mutex_lock(&mutex
);
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
)
552 #endif /* CONFOPT_PTHREADS */
555 /** win32 waveout support **/
560 #include <mmsystem.h>
562 #define WAVEOUT_BUF_SIZE 4096 * 4
563 #define WAVEOUT_N_BUFFERS 8
567 unsigned char buf
[WAVEOUT_BUF_SIZE
];
571 struct ss_outdrv_win32
572 /* control structure */
574 void (*func
) (void *, short int *);
576 struct _wob wob
[WAVEOUT_N_BUFFERS
];
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
];
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
)
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
;
607 waveOutPrepareHeader(drv
->hwaveout
, &b
->header
, sizeof(WAVEHDR
));
608 waveOutWrite(drv
->hwaveout
, &b
->header
, sizeof(WAVEHDR
));
612 if (++drv
->wob_i
== WAVEOUT_N_BUFFERS
)
615 b
= &drv
->wob
[drv
->wob_i
];
621 /* wait until buffer is done */
622 while (b
->header
.lpData
!= NULL
&& !(b
->header
.dwFlags
& WHDR_DONE
))
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
;
633 if (drvname
&& strcmp("win32", drvname
) != 0)
636 memset(&drv
, '\0', sizeof(drv
));
638 wfx
.nSamplesPerSec
= freq
;
639 wfx
.wBitsPerSample
= 16;
640 wfx
.nChannels
= n_channels
;
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
)
650 drv
.func
= d_win32_func
;
651 drv
.size
= n_channels
* sizeof(short int);
654 *ssize
= sizeof(struct ss_outdrv_win32
);
660 #else /* CONFOPT_WIN32 */
662 #define d_win32 d_unsupp
664 #endif /* CONFOPT_WIN32 */
669 void *ss_outdev_open(const char *drvname
, const char *file
, int freq
, int n_channels
)
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
) {
683 memcpy(ret
, drv
, size
);
686 thread_setup(ret
, n_channels
);
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
)
703 ss_outdev_write(drv
, NULL
);