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
32 static void *d_unsupp(const char *drvname
, const char *filename
, int freq
,
33 int n_channels
, int *ssize
)
34 /* unsupported stub function */
47 /* control structure */
49 void (*func
) (void *, short int *);
54 static void d_arts_func(void *d
, short int *frame
)
55 /* writing / close function */
57 struct ss_outdrv_arts
*drv
= d
;
60 arts_write(drv
->arts
, frame
, drv
->size
);
65 static void *d_arts(const char *drvname
, const char *filename
, int freq
,
66 int n_channels
, int *ssize
)
69 static struct ss_outdrv_arts drv
;
71 if (drvname
&& strcmp("arts", drvname
) != 0)
74 /* filename specified? get out */
78 *ssize
= sizeof(struct ss_outdrv_arts
);
79 drv
.func
= d_arts_func
;
80 drv
.size
= n_channels
>= 2 ? 2 : 1;
84 arts_play_stream(freq
, 16, drv
.size
, "ahxm")) == NULL
)
87 drv
.size
*= sizeof(short int);
93 #else /* CONFOPT_ARTS */
95 #define d_arts d_unsupp
97 #endif /* CONFOPT_ARTS */
108 /* control structure */
110 void (*func
) (void *, short int *);
115 static void d_esd_func(void *d
, short int *frame
)
116 /* write / close function */
118 struct ss_outdrv_esd
*drv
= d
;
121 write(drv
->fd
, frame
, drv
->size
);
126 static void *d_esd(const char *drvname
, const char *filename
, int freq
,
127 int n_channels
, int *ssize
)
130 static struct ss_outdrv_esd drv
;
133 if (drvname
&& strcmp("esd", drvname
) != 0)
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 ||
145 esd_play_stream_fallback(format
, freq
, NULL
, "ahxm")) < 0)
148 drv
.size
*= sizeof(short int);
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 *);
176 static void d_pulse_func(void *d
, short int *frame
)
177 /* write / close function */
179 struct ss_outdrv_pulse
*drv
= d
;
183 pa_simple_write(drv
->pa
, frame
, drv
->size
, &error
);
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
)
194 static struct ss_outdrv_pulse drv
;
197 if (drvname
&& strcmp("pulse", drvname
) != 0)
200 ss
.format
= PA_SAMPLE_S16LE
;
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
,
216 #else /* CONFOPT_PULSEAUDIO */
218 #define d_pulse d_unsupp
220 #endif /* CONFOPT_PULSEAUDIO */
223 /** SGI Irix driver **/
227 #include <dmedia/audio.h>
230 /* control structure */
232 void (*func
) (void *, short int *);
237 static void d_sgi_func(void *d
, short int *frame
)
238 /* write / close function */
240 struct ss_outdrv_sgi
*drv
= d
;
243 alWriteFrames(drv
->ap
, frame
, 1);
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
)
254 static struct ss_outdrv_sgi drv
;
257 if (drvname
&& strcmp("sgi", drvname
) != 0)
260 /* filename specified? get out */
261 if (filename
!= 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()))
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
);
289 #else /* CONFOPT_SGI */
291 #define d_sgi d_unsupp
293 #endif /* CONFOPT_SGI */
296 /** Linux OSS driver **/
298 #ifdef CONFOPT_LINUX_OSS
301 #include <sys/ioctl.h>
302 #include <linux/soundcard.h>
306 /* control structure */
308 void (*func
) (void *, short int *);
313 static int is_little_endian(void)
314 /* is this machine little endian? */
317 unsigned char *c
= (unsigned char *) &s
;
322 static void d_oss_func(void *d
, short int *frame
)
323 /* write / close function */
325 struct ss_outdrv_oss
*drv
= d
;
328 write(drv
->fd
, frame
, drv
->size
);
334 static void *d_oss(const char *drvname
, const char *filename
, int freq
,
335 int n_channels
, int *ssize
)
338 static struct ss_outdrv_oss drv
;
341 if (drvname
&& strcmp("oss", drvname
) != 0)
344 if (filename
== NULL
)
345 filename
= "/dev/dsp";
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)
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) {
367 drv
.size
*= sizeof(short int);
372 #else /* CONFOPT_LINUX_OSS */
374 #define d_oss d_unsupp
376 #endif /* CONFOPT_LINUX_OSS */
379 /** WAV file driver **/
382 /* control structure */
384 void (*func
) (void *, short int *);
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
;
414 for (n
= 0; n
< drv
->size
; n
++)
415 fput16(frame
[n
], drv
->fd
);
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
);
431 static void *d_wav(const char *drvname
, const char *filename
, int freq
,
432 int n_channels
, int *ssize
)
435 static struct ss_outdrv_wav drv
;
437 if (drvname
&& strcmp("wav", drvname
) != 0)
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
;
448 if ((drv
.fd
= fopen(filename
, "wb")) == NULL
)
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) */
471 /** Pthread support **/
473 #ifdef CONFOPT_PTHREADS
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
);
496 /* wait for data available */
497 pthread_cond_wait(&cond
, &mutex
);
499 /* call the real function */
500 real_drv_func(driver
, frame_cpy
);
503 if (frame_cpy
== NULL
)
507 pthread_mutex_unlock(&mutex
);
512 static void outdev_producer_wrapper(void *d
, short int *frame
)
513 /* wrapper 'producer' function */
517 pthread_mutex_lock(&mutex
);
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
)
563 #endif /* CONFOPT_PTHREADS */
566 /** win32 waveout support **/
571 #include <mmsystem.h>
573 #define WAVEOUT_BUF_SIZE 4096 * 4
574 #define WAVEOUT_N_BUFFERS 8
578 unsigned char buf
[WAVEOUT_BUF_SIZE
];
582 struct ss_outdrv_win32
583 /* control structure */
585 void (*func
) (void *, short int *);
587 struct _wob wob
[WAVEOUT_N_BUFFERS
];
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
];
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
)
609 /* clean previous buffer, if needed */
610 if (b
->header
.lpData
)
611 waveOutUnprepareHeader(drv
->hwaveout
, &b
->header
,
614 /* prepare new buffer */
615 b
->header
.dwBufferLength
= b
->offset
;
616 b
->header
.lpData
= (LPSTR
) b
->buf
;
619 waveOutPrepareHeader(drv
->hwaveout
, &b
->header
, sizeof(WAVEHDR
));
620 waveOutWrite(drv
->hwaveout
, &b
->header
, sizeof(WAVEHDR
));
624 if (++drv
->wob_i
== WAVEOUT_N_BUFFERS
)
627 b
= &drv
->wob
[drv
->wob_i
];
633 /* wait until buffer is done */
634 while (b
->header
.lpData
!= NULL
635 && !(b
->header
.dwFlags
& WHDR_DONE
))
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
;
647 if (drvname
&& strcmp("win32", drvname
) != 0)
650 memset(&drv
, '\0', sizeof(drv
));
652 wfx
.nSamplesPerSec
= freq
;
653 wfx
.wBitsPerSample
= 16;
654 wfx
.nChannels
= n_channels
;
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
)
664 drv
.func
= d_win32_func
;
665 drv
.size
= n_channels
* sizeof(short int);
668 *ssize
= sizeof(struct ss_outdrv_win32
);
674 #else /* CONFOPT_WIN32 */
676 #define d_win32 d_unsupp
678 #endif /* CONFOPT_WIN32 */
683 void *ss_outdev_open(const char *drvname
, const char *file
, int freq
,
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
) {
698 memcpy(ret
, drv
, size
);
701 thread_setup(ret
, n_channels
);
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
)
718 ss_outdev_write(drv
, NULL
);