Updated TODO.
[ahxm.git] / ss_outdev.c
blobcadfbdd00e861cffec26a70fad2fbfb73cd6e508
1 /*
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
26 /*******************
27 Data
28 ********************/
30 #include "config.h"
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <string.h>
36 /*******************
37 Code
38 ********************/
40 /* unsupported stub function */
42 static void * d_unsupp(char * drvname, char * filename,
43 int freq, int n_channels, int * ssize) { return(NULL); }
46 #ifdef CONFOPT_ARTS
48 /* Arts driver */
50 #include <artsc.h>
52 struct ss_outdrv_arts
53 /* control structure */
55 void (*func)(void *, short int *);
56 arts_stream_t arts;
57 int size;
60 static void d_arts_func(void * d, short int * frame)
61 /* writing / close function */
63 struct ss_outdrv_arts * drv=d;
65 if(frame != NULL)
66 arts_write(drv->arts, frame, drv->size);
67 else
68 arts_free();
71 static void * d_arts(char * drvname, char * filename,
72 int freq, int n_channels, int * ssize)
73 /* init function */
75 static struct ss_outdrv_arts drv;
77 if(drvname && strcmp("arts", drvname) != 0)
78 return(NULL);
80 /* filename specified? get out */
81 if(filename != NULL) return(NULL);
83 *ssize=sizeof(struct ss_outdrv_arts);
84 drv.func=d_arts_func;
85 drv.size=n_channels >= 2 ? 2 : 1;
87 if(arts_init() || (drv.arts=arts_play_stream(freq, 16,
88 drv.size, "annhell")) == NULL)
89 return(NULL);
91 drv.size *= sizeof(short int);
93 return(&drv);
97 #else /* CONFOPT_ARTS */
99 #define d_arts d_unsupp
101 #endif /* CONFOPT_ARTS */
103 /************************************************/
105 #ifdef CONFOPT_ESD
107 /* ESD driver */
109 #include <unistd.h>
110 #include <esd.h>
112 struct ss_outdrv_esd
113 /* control structure */
115 void (*func)(void *, short int *);
116 int fd;
117 int size;
120 static void d_esd_func(void * d, short int * frame)
121 /* write / close function */
123 struct ss_outdrv_esd * drv=d;
125 if(frame != NULL)
126 write(drv->fd, frame, drv->size);
127 else
128 close(drv->fd);
131 static void * d_esd(char * drvname, char * filename,
132 int freq, int n_channels, int * ssize)
133 /* init function */
135 static struct ss_outdrv_esd drv;
136 esd_format_t format;
138 if(drvname && strcmp("esd", drvname) != 0)
139 return(NULL);
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, "annhell")) < 0)
150 return(NULL);
152 drv.size *= sizeof(short int);
154 return(&drv);
158 #else /* CONFOPT_ESD */
160 #define d_esd d_unsupp
162 #endif /* CONFOPT_ESD */
164 /************************************************/
166 #ifdef CONFOPT_SGI
168 /* SGI Irix driver */
170 #include <dmedia/audio.h>
172 struct ss_outdrv_sgi
173 /* control structure */
175 void (*func)(void *, short int *);
176 ALconfig ac;
177 ALport ap;
180 static void d_sgi_func(void * d, short int * frame)
181 /* write / close function */
183 struct ss_outdrv_sgi * drv=d;
185 if(frame != NULL)
186 alWriteFrames(drv->ap, frame, 1);
187 else
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)
196 /* init function */
198 static struct ss_outdrv_sgi drv;
199 ALpv p[2];
201 if(drvname && strcmp("sgi", drvname) != 0)
202 return(NULL);
204 /* filename specified? get out */
205 if(filename != NULL) return(NULL);
207 *ssize=sizeof(struct ss_outdrv_sgi);
208 drv.func=d_sgi_func;
210 p[0].param=AL_MASTER_CLOCK;
211 p[0].value.i=AL_CRYSTAL_MCLK_TYPE;
212 p[1].param=AL_RATE;
213 p[1].value.ll=alDoubleToFixed((double) freq);
215 if(!(drv.ac=alNewConfig()))
216 return(NULL);
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);
227 return(NULL);
230 return(&drv);
233 #else /* CONFOPT_SGI */
235 #define d_sgi d_unsupp
237 #endif /* CONFOPT_SGI */
239 /************************************************/
241 #ifdef CONFOPT_LINUX_OSS
243 /* Linux OSS driver */
245 #include <fcntl.h>
246 #include <sys/ioctl.h>
247 #include <linux/soundcard.h>
248 #include <unistd.h>
250 struct ss_outdrv_oss
251 /* control structure */
253 void (*func)(void *, short int *);
254 int fd;
255 int size;
258 static int is_little_endian(void)
259 /* is this machine little endian? */
261 short s=1;
262 unsigned char * c=(unsigned char *) &s;
264 return(*c == 1);
267 static void d_oss_func(void * d, short int * frame)
268 /* write / close function */
270 struct ss_outdrv_oss * drv=d;
272 if(frame != NULL)
273 write(drv->fd, frame, drv->size);
274 else
275 close(drv->fd);
279 static void * d_oss(char * drvname, char * filename,
280 int freq, int n_channels, int * ssize)
281 /* init function */
283 static struct ss_outdrv_oss drv;
284 int fr, st, fm;
286 if(drvname && strcmp("oss", drvname) != 0)
287 return(NULL);
289 if(filename == NULL) filename="/dev/dsp";
291 fr=(2 << 16)|14;
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);
296 drv.func=d_oss_func;
297 drv.size=n_channels >= 2 ? 2 : 1;
299 if((drv.fd=open(filename, O_WRONLY)) < 0)
300 return(NULL);
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)
308 close(drv.fd);
309 return(NULL);
312 drv.size *= sizeof(short int);
314 return(&drv);
317 #else /* CONFOPT_LINUX_OSS */
319 #define d_oss d_unsupp
321 #endif /* CONFOPT_LINUX_OSS */
323 /************************************************/
325 /* WAV file driver */
327 struct ss_outdrv_wav
328 /* control structure */
330 void (*func)(void *, short int *);
331 FILE * fd;
332 int size;
333 int n_frames;
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;
357 if(frame != NULL)
359 int n;
361 for(n=0;n < drv->size;n++)
362 fput16(frame[n], drv->fd);
364 drv->n_frames++;
366 else
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);
375 fclose(drv->fd);
379 static void * d_wav(char * drvname, char * filename,
380 int freq, int n_channels, int * ssize)
381 /* init function */
383 static struct ss_outdrv_wav drv;
385 if(drvname && strcmp("wav", drvname) != 0)
386 return(NULL);
388 if(filename == NULL) filename="output.wav";
390 *ssize=sizeof(struct ss_outdrv_wav);
391 drv.func=d_wav_func;
392 drv.size=n_channels;
393 drv.n_frames=0;
395 if((drv.fd=fopen(filename, "w")) == NULL)
396 return(0);
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) */
414 return(&drv);
418 /*******************************************/
420 /* interface */
422 void * ss_outdev_open(char * drvname, char * file, int freq, int n_channels)
424 int size;
425 void * drv;
426 void * ret=NULL;
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)
434 ret=malloc(size);
435 memcpy(ret, drv, size);
438 return(ret);
442 void ss_outdev_write(void * drv, short int * frame)
444 void (**func)(void *, short int *)=drv;
446 (*func)(drv, frame);
450 void * ss_outdev_close(void * drv)
452 if(drv != NULL)
454 ss_outdev_write(drv, NULL);
455 free(drv);
458 return(NULL);