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 /* filename specified? get out */
81 if(filename
!= NULL
) return(NULL
);
83 *ssize
=sizeof(struct ss_outdrv_arts
);
85 drv
.size
=n_channels
>= 2 ? 2 : 1;
87 if(arts_init() || (drv
.arts
=arts_play_stream(freq
, 16,
88 drv
.size
, "annhell")) == NULL
)
91 drv
.size
*= sizeof(short int);
97 #else /* CONFOPT_ARTS */
99 #define d_arts d_unsupp
101 #endif /* CONFOPT_ARTS */
103 /************************************************/
113 /* control structure */
115 void (*func
)(void *, short int *);
120 static void d_esd_func(void * d
, short int * frame
)
121 /* write / close function */
123 struct ss_outdrv_esd
* drv
=d
;
126 write(drv
->fd
, frame
, drv
->size
);
131 static void * d_esd(char * drvname
, char * filename
,
132 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
);
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
, "annhell")) < 0)
152 drv
.size
*= sizeof(short int);
158 #else /* CONFOPT_ESD */
160 #define d_esd d_unsupp
162 #endif /* CONFOPT_ESD */
164 /************************************************/
168 /* SGI Irix driver */
170 #include <dmedia/audio.h>
173 /* control structure */
175 void (*func
)(void *, short int *);
180 static void d_sgi_func(void * d
, short int * frame
)
181 /* write / close function */
183 struct ss_outdrv_sgi
* drv
=d
;
186 alWriteFrames(drv
->ap
, frame
, 1);
189 alClosePort(drv
->ap
);
190 alFreeConfig(drv
->ac
);
194 static void * d_sgi(char * drvname
, char * filename
,
195 int freq
, int n_channels
, int * ssize
)
198 static struct ss_outdrv_sgi drv
;
201 if(drvname
&& strcmp("sgi", drvname
) != 0)
204 /* filename specified? get out */
205 if(filename
!= NULL
) return(NULL
);
207 *ssize
=sizeof(struct ss_outdrv_sgi
);
210 p
[0].param
=AL_MASTER_CLOCK
;
211 p
[0].value
.i
=AL_CRYSTAL_MCLK_TYPE
;
213 p
[1].value
.ll
=alDoubleToFixed((double) freq
);
215 if(!(drv
.ac
=alNewConfig()))
218 if(alSetChannels(drv
.ac
, n_channels
) < 0 ||
219 alSetWidth(drv
.ac
, AL_SAMPLE_16
) < 0 ||
220 alSetSampFmt(drv
.ac
, AL_SAMPFMT_TWOSCOMP
) < 0 ||
221 alSetQueueSize(drv
.ac
, 2048) < 0 ||
222 alSetDevice(drv
.ac
, AL_DEFAULT_OUTPUT
) < 0 ||
223 alSetParams(alGetDevice(drv
.ac
), p
, 2) < 0 ||
224 !(drv
.ap
=alOpenPort("annhell", "w", drv
.ac
)))
226 alFreeConfig(drv
.ac
);
233 #else /* CONFOPT_SGI */
235 #define d_sgi d_unsupp
237 #endif /* CONFOPT_SGI */
239 /************************************************/
241 #ifdef CONFOPT_LINUX_OSS
243 /* Linux OSS driver */
246 #include <sys/ioctl.h>
247 #include <linux/soundcard.h>
251 /* control structure */
253 void (*func
)(void *, short int *);
258 static int is_little_endian(void)
259 /* is this machine little endian? */
262 unsigned char * c
=(unsigned char *) &s
;
267 static void d_oss_func(void * d
, short int * frame
)
268 /* write / close function */
270 struct ss_outdrv_oss
* drv
=d
;
273 write(drv
->fd
, frame
, drv
->size
);
279 static void * d_oss(char * drvname
, char * filename
,
280 int freq
, int n_channels
, int * ssize
)
283 static struct ss_outdrv_oss drv
;
286 if(drvname
&& strcmp("oss", drvname
) != 0)
289 if(filename
== NULL
) filename
="/dev/dsp";
292 st
=n_channels
>= 2 ? 1 : 0;
293 fm
=is_little_endian() ? AFMT_S16_LE
: AFMT_S16_BE
;
295 *ssize
=sizeof(struct ss_outdrv_oss
);
297 drv
.size
=n_channels
>= 2 ? 2 : 1;
299 if((drv
.fd
=open(filename
, O_WRONLY
)) < 0)
302 if(ioctl(drv
.fd
, SNDCTL_DSP_SETFRAGMENT
, &fr
) < 0 ||
303 ioctl(drv
.fd
, SNDCTL_DSP_RESET
, 0) < 0 ||
304 ioctl(drv
.fd
, SNDCTL_DSP_SPEED
, &freq
) < 0 ||
305 ioctl(drv
.fd
, SNDCTL_DSP_STEREO
, &st
) < 0 ||
306 ioctl(drv
.fd
, SNDCTL_DSP_SETFMT
, &fm
) < 0)
312 drv
.size
*= sizeof(short int);
317 #else /* CONFOPT_LINUX_OSS */
319 #define d_oss d_unsupp
321 #endif /* CONFOPT_LINUX_OSS */
323 /************************************************/
325 /* WAV file driver */
328 /* control structure */
330 void (*func
)(void *, short int *);
336 static void fput16(short int i
, FILE * f
)
337 /* writes a 16 bit integer, in any machine order */
339 fputc(i
& 0x00ff, f
);
340 fputc((i
& 0xff00) >> 8, f
);
343 static void fput32(int i
, FILE * f
)
344 /* writes a 32 bit integer, in any machine order */
346 fputc(i
& 0x000000ff, f
);
347 fputc((i
& 0x0000ff00) >> 8, f
);
348 fputc((i
& 0x00ff0000) >> 16, f
);
349 fputc((i
& 0xff000000) >> 24, f
);
352 static void d_wav_func(void * d
, short int * frame
)
353 /* write / close function */
355 struct ss_outdrv_wav
* drv
=d
;
361 for(n
=0;n
< drv
->size
;n
++)
362 fput16(frame
[n
], drv
->fd
);
368 /* rewind file and write total size */
369 fseek(drv
->fd
, 4, SEEK_SET
);
370 fput32((drv
->n_frames
* drv
->size
* 2) + 36, drv
->fd
);
372 fseek(drv
->fd
, 40, SEEK_SET
);
373 fput32((drv
->n_frames
* drv
->size
* 2), drv
->fd
);
379 static void * d_wav(char * drvname
, char * filename
,
380 int freq
, int n_channels
, int * ssize
)
383 static struct ss_outdrv_wav drv
;
385 if(drvname
&& strcmp("wav", drvname
) != 0)
388 if(filename
== NULL
) filename
="output.wav";
390 *ssize
=sizeof(struct ss_outdrv_wav
);
395 if((drv
.fd
=fopen(filename
, "w")) == NULL
)
398 /* write wav header */
400 fwrite("RIFF", 1, 4, drv
.fd
);
401 fput32(36, drv
.fd
); /* first checkpoint (offset: 4) */
402 fwrite("WAVE", 1, 4, drv
.fd
);
403 fwrite("fmt ", 1, 4, drv
.fd
);
404 fput32(16, drv
.fd
); /* chunk size */
405 fput16(1, drv
.fd
); /* 1: uncompressed PCM */
406 fput16(n_channels
, drv
.fd
); /* # of channels */
407 fput32(freq
, drv
.fd
); /* sample rate */
408 fput32(freq
* n_channels
* 2, drv
.fd
); /* bytes per second */
409 fput16(n_channels
* 2, drv
.fd
); /* 'block align' */
410 fput16(16, drv
.fd
); /* 16 bits per sample */
411 fwrite("data", 1, 4, drv
.fd
);
412 fput32(0, drv
.fd
); /* second checkpoint (offset: 40) */
418 /*******************************************/
422 void * ss_outdev_open(char * drvname
, char * file
, int freq
, int n_channels
)
428 if((drv
=d_arts(drvname
, file
, freq
, n_channels
, &size
)) != NULL
||
429 (drv
=d_esd(drvname
, file
, freq
, n_channels
, &size
)) != NULL
||
430 (drv
=d_sgi(drvname
, file
, freq
, n_channels
, &size
)) != NULL
||
431 (drv
=d_oss(drvname
, file
, freq
, n_channels
, &size
)) != NULL
||
432 (drv
=d_wav(drvname
, file
, freq
, n_channels
, &size
)) != NULL
)
435 memcpy(ret
, drv
, size
);
442 void ss_outdev_write(void * drv
, short int * frame
)
444 void (**func
)(void *, short int *)=drv
;
450 void * ss_outdev_close(void * drv
)
454 ss_outdev_write(drv
, NULL
);