3 Ann Hell Ex Machina - Music Software
4 Copyright (C) 2005 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
,
43 int freq
, int n_channels
, int * ssize
) { return(NULL
); }
53 /* control structure */
55 void (*func
)(void *, short int *);
60 static void d_arts_func(void * d
, short int * frame
)
61 /* writing / close function */
63 struct ss_outdrv_arts
* drv
=d
;
66 arts_write(drv
->arts
, frame
, drv
->size
);
71 static void * d_arts(char * drvname
, char * filename
,
72 int freq
, int n_channels
, int * ssize
)
75 static struct ss_outdrv_arts drv
;
77 if(drvname
&& strcmp("arts", drvname
) != 0)
80 *ssize
=sizeof(struct ss_outdrv_arts
);
82 drv
.size
=n_channels
>= 2 ? 2 : 1;
84 if(arts_init() || (drv
.arts
=arts_play_stream(freq
, 16,
85 drv
.size
, "annhell")) == NULL
)
88 drv
.size
*= sizeof(short int);
94 #else /* CONFOPT_ARTS */
96 #define d_arts d_unsupp
98 #endif /* CONFOPT_ARTS */
100 /************************************************/
110 /* control structure */
112 void (*func
)(void *, short int *);
117 static void d_esd_func(void * d
, short int * frame
)
118 /* write / close function */
120 struct ss_outdrv_esd
* drv
=d
;
123 write(drv
->fd
, frame
, drv
->size
);
128 static void * d_esd(char * drvname
, char * filename
,
129 int freq
, int n_channels
, int * ssize
)
132 static struct ss_outdrv_esd drv
;
135 if(drvname
&& strcmp("esd", drvname
) != 0)
138 *ssize
=sizeof(struct ss_outdrv_esd
);
140 drv
.size
=n_channels
>= 2 ? 2 : 1;
142 format
= ESD_STREAM
| ESD_PLAY
| ESD_BITS16
;
143 format
|= drv
.size
== 2 ? ESD_STEREO
: ESD_MONO
;
145 if(esd_open_sound(filename
) < 0 ||
146 (drv
->fd
=esd_play_stream_fallback(format
, freq
, NULL
, "annhell")) < 0)
149 drv
.size
*= sizeof(short int);
155 #else /* CONFOPT_ESD */
157 #define d_esd d_unsupp
159 #endif /* CONFOPT_ESD */
161 /************************************************/
165 /* SGI Irix driver */
167 #include <dmedia/audio.h>
170 /* control structure */
172 void (*func
)(void *, short int *);
177 static void d_sgi_func(void * d
, short int * frame
)
178 /* write / close function */
180 struct ss_outdrv_sgi
* drv
=d
;
183 alWriteFrames(drv
->ap
, frame
, 1);
186 alClosePort(drv
->ap
);
187 alFreeConfig(drv
->ac
);
191 static void * d_sgi(char * drvname
, char * filename
,
192 int freq
, int n_channels
, int * ssize
)
195 static struct ss_outdrv_sgi drv
;
198 if(drvname
&& strcmp("sgi", drvname
) != 0)
201 *ssize
=sizeof(struct ss_outdrv_sgi
);
204 p
[0].param
=AL_MASTER_CLOCK
;
205 p
[0].value
.i
=AL_CRYSTAL_MCLK_TYPE
;
207 p
[1].value
.ll
=alDoubleToFixed((double) freq
);
209 if(!(drv
.ac
=alNewConfig()))
212 if(alSetChannels(drv
.ac
, n_channels
) < 0 ||
213 alSetWidth(drv
.ac
, AL_SAMPLE_16
) < 0 ||
214 alSetSampFmt(drv
.ac
, AL_SAMPFMT_TWOSCOMP
) < 0 ||
215 alSetQueueSize(drv
.ac
, 2048) < 0 ||
216 alSetDevice(drv
.ac
, AL_DEFAULT_OUTPUT
) < 0 ||
217 alSetParams(alGetDevice(drv
.ac
), p
, 2) < 0 ||
218 !(drv
.ap
=alOpenPort("annhell", "w", drv
.ac
)))
220 alFreeConfig(drv
.ac
);
227 #else /* CONFOPT_SGI */
229 #define d_sgi d_unsupp
231 #endif /* CONFOPT_SGI */
233 /************************************************/
235 #ifdef CONFOPT_LINUX_OSS
237 /* Linux OSS driver */
240 #include <sys/ioctl.h>
241 #include <linux/soundcard.h>
245 /* control structure */
247 void (*func
)(void *, short int *);
252 static int is_little_endian(void)
253 /* is this machine little endian? */
256 unsigned char * c
=(unsigned char *) &s
;
261 static void d_oss_func(void * d
, short int * frame
)
262 /* write / close function */
264 struct ss_outdrv_oss
* drv
=d
;
267 write(drv
->fd
, frame
, drv
->size
);
273 static void * d_oss(char * drvname
, char * filename
,
274 int freq
, int n_channels
, int * ssize
)
277 static struct ss_outdrv_oss drv
;
280 if(drvname
&& strcmp("oss", drvname
) != 0)
283 if(filename
== NULL
) filename
="/dev/dsp";
285 fr
=(2 << 16)|(1 << 10);
286 st
=n_channels
== 2 ? 1 : 0;
287 fm
=is_little_endian() ? AFMT_S16_LE
: AFMT_S16_BE
;
289 *ssize
=sizeof(struct ss_outdrv_oss
);
291 drv
.size
=n_channels
>= 2 ? 2 : 1;
293 if((drv
.fd
=open(filename
, O_WRONLY
)) < 0)
296 if(ioctl(drv
.fd
, SNDCTL_DSP_SETFRAGMENT
, &fr
) < 0 ||
297 ioctl(drv
.fd
, SNDCTL_DSP_RESET
, 0) < 0 ||
298 ioctl(drv
.fd
, SNDCTL_DSP_SPEED
, &freq
) < 0 ||
299 ioctl(drv
.fd
, SNDCTL_DSP_STEREO
, &st
) < 0 ||
300 ioctl(drv
.fd
, SNDCTL_DSP_SETFMT
, &fm
) < 0)
306 drv
.size
*= sizeof(short int);
311 #else /* CONFOPT_LINUX_OSS */
313 #define d_oss d_unsupp
315 #endif /* CONFOPT_LINUX_OSS */
317 /************************************************/
319 /* WAV file driver */
322 /* control structure */
324 void (*func
)(void *, short int *);
330 static void fput16(short int i
, FILE * f
)
331 /* writes a 16 bit integer, in any machine order */
333 fputc(i
& 0x00ff, f
);
334 fputc((i
& 0xff00) >> 8, f
);
337 static void fput32(int i
, FILE * f
)
338 /* writes a 32 bit integer, in any machine order */
340 fputc(i
& 0x000000ff, f
);
341 fputc((i
& 0x0000ff00) >> 8, f
);
342 fputc((i
& 0x00ff0000) >> 16, f
);
343 fputc((i
& 0xff000000) >> 24, f
);
346 static void d_wav_func(void * d
, short int * frame
)
347 /* write / close function */
349 struct ss_outdrv_wav
* drv
=d
;
355 for(n
=0;n
< drv
->size
;n
++)
356 fput16(frame
[n
], drv
->fd
);
362 /* rewind file and write total size */
363 fseek(drv
->fd
, 4, SEEK_SET
);
364 fput32((drv
->n_frames
* drv
->size
* 2) + 36, drv
->fd
);
366 fseek(drv
->fd
, 40, SEEK_SET
);
367 fput32((drv
->n_frames
* drv
->size
* 2), drv
->fd
);
373 static void * d_wav(char * drvname
, char * filename
,
374 int freq
, int n_channels
, int * ssize
)
377 static struct ss_outdrv_wav drv
;
379 if(drvname
&& strcmp("wav", drvname
) != 0)
382 if(filename
== NULL
) filename
="output.wav";
384 *ssize
=sizeof(struct ss_outdrv_wav
);
389 if((drv
.fd
=fopen(filename
, "w")) == NULL
)
392 /* write wav header */
394 fwrite("RIFF", 1, 4, drv
.fd
);
395 fput32(36, drv
.fd
); /* first checkpoint (offset: 4) */
396 fwrite("WAVE", 1, 4, drv
.fd
);
397 fwrite("fmt ", 1, 4, drv
.fd
);
398 fput32(16, drv
.fd
); /* chunk size */
399 fput16(1, drv
.fd
); /* 1: uncompressed PCM */
400 fput16(n_channels
, drv
.fd
); /* # of channels */
401 fput32(freq
, drv
.fd
); /* sample rate */
402 fput32(freq
* n_channels
* 2, drv
.fd
); /* bytes per second */
403 fput16(n_channels
* 2, drv
.fd
); /* 'block align' */
404 fput16(16, drv
.fd
); /* 16 bits per sample */
405 fwrite("data", 1, 4, drv
.fd
);
406 fput32(0, drv
.fd
); /* second checkpoint (offset: 40) */
412 /*******************************************/
416 void * ss_outdev_open(char * drvname
, char * file
, int freq
, int n_channels
)
422 if((drv
=d_arts(drvname
, file
, freq
, n_channels
, &size
)) != NULL
||
423 (drv
=d_esd(drvname
, file
, freq
, n_channels
, &size
)) != NULL
||
424 (drv
=d_sgi(drvname
, file
, freq
, n_channels
, &size
)) != NULL
||
425 (drv
=d_oss(drvname
, file
, freq
, n_channels
, &size
)) != NULL
||
426 (drv
=d_wav(drvname
, file
, freq
, n_channels
, &size
)) != NULL
)
429 memcpy(ret
, drv
, size
);
436 void ss_outdev_write(void * drv
, short int * frame
)
438 void (**func
)(void *, short int *)=drv
;
444 void ss_outdev_close(void * drv
)
446 ss_outdev_write(drv
, NULL
);