New (incomplete) code created towards closing #1075 and #1076.
[ahxm.git] / ss_outdev.c
blobbf5cf2cec904b69a6bacf492d9fd2358315c1f9c
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 *ssize=sizeof(struct ss_outdrv_arts);
81 drv.func=d_arts_func;
82 drv.size=n_channels >= 2 ? 2 : 1;
84 if(arts_init() || (drv.arts=arts_play_stream(freq, 16,
85 drv.size, "annhell")) == NULL)
86 return(NULL);
88 drv.size *= sizeof(short int);
90 return(&drv);
94 #else /* CONFOPT_ARTS */
96 #define d_arts d_unsupp
98 #endif /* CONFOPT_ARTS */
100 /************************************************/
102 #ifdef CONFOPT_ESD
104 /* ESD driver */
106 #include <unistd.h>
107 #include <esd.h>
109 struct ss_outdrv_esd
110 /* control structure */
112 void (*func)(void *, short int *);
113 int fd;
114 int size;
117 static void d_esd_func(void * d, short int * frame)
118 /* write / close function */
120 struct ss_outdrv_esd * drv=d;
122 if(frame != NULL)
123 write(drv->fd, frame, drv->size);
124 else
125 close(drv->fd);
128 static void * d_esd(char * drvname, char * filename,
129 int freq, int n_channels, int * ssize)
130 /* init function */
132 static struct ss_outdrv_esd drv;
133 esd_format_t format;
135 if(drvname && strcmp("esd", drvname) != 0)
136 return(NULL);
138 *ssize=sizeof(struct ss_outdrv_esd);
139 drv.func=d_esd_func;
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)
147 return(NULL);
149 drv.size *= sizeof(short int);
151 return(&drv);
155 #else /* CONFOPT_ESD */
157 #define d_esd d_unsupp
159 #endif /* CONFOPT_ESD */
161 /************************************************/
163 #ifdef CONFOPT_SGI
165 /* SGI Irix driver */
167 #include <dmedia/audio.h>
169 struct ss_outdrv_sgi
170 /* control structure */
172 void (*func)(void *, short int *);
173 ALconfig ac;
174 ALport ap;
177 static void d_sgi_func(void * d, short int * frame)
178 /* write / close function */
180 struct ss_outdrv_sgi * drv=d;
182 if(frame != NULL)
183 alWriteFrames(drv->ap, frame, 1);
184 else
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)
193 /* init function */
195 static struct ss_outdrv_sgi drv;
196 ALpv p[2];
198 if(drvname && strcmp("sgi", drvname) != 0)
199 return(NULL);
201 *ssize=sizeof(struct ss_outdrv_sgi);
202 drv.func=d_sgi_func;
204 p[0].param=AL_MASTER_CLOCK;
205 p[0].value.i=AL_CRYSTAL_MCLK_TYPE;
206 p[1].param=AL_RATE;
207 p[1].value.ll=alDoubleToFixed((double) freq);
209 if(!(drv.ac=alNewConfig()))
210 return(NULL);
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);
221 return(NULL);
224 return(&drv);
227 #else /* CONFOPT_SGI */
229 #define d_sgi d_unsupp
231 #endif /* CONFOPT_SGI */
233 /************************************************/
235 #ifdef CONFOPT_LINUX_OSS
237 /* Linux OSS driver */
239 #include <fcntl.h>
240 #include <sys/ioctl.h>
241 #include <linux/soundcard.h>
242 #include <unistd.h>
244 struct ss_outdrv_oss
245 /* control structure */
247 void (*func)(void *, short int *);
248 int fd;
249 int size;
252 static int is_little_endian(void)
253 /* is this machine little endian? */
255 short s=1;
256 unsigned char * c=(unsigned char *) &s;
258 return(*c == 1);
261 static void d_oss_func(void * d, short int * frame)
262 /* write / close function */
264 struct ss_outdrv_oss * drv=d;
266 if(frame != NULL)
267 write(drv->fd, frame, drv->size);
268 else
269 close(drv->fd);
273 static void * d_oss(char * drvname, char * filename,
274 int freq, int n_channels, int * ssize)
275 /* init function */
277 static struct ss_outdrv_oss drv;
278 int fr, st, fm;
280 if(drvname && strcmp("oss", drvname) != 0)
281 return(NULL);
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);
290 drv.func=d_oss_func;
291 drv.size=n_channels >= 2 ? 2 : 1;
293 if((drv.fd=open(filename, O_WRONLY)) < 0)
294 return(NULL);
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)
302 close(drv.fd);
303 return(NULL);
306 drv.size *= sizeof(short int);
308 return(&drv);
311 #else /* CONFOPT_LINUX_OSS */
313 #define d_oss d_unsupp
315 #endif /* CONFOPT_LINUX_OSS */
317 /************************************************/
319 /* WAV file driver */
321 struct ss_outdrv_wav
322 /* control structure */
324 void (*func)(void *, short int *);
325 FILE * fd;
326 int size;
327 int n_frames;
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;
351 if(frame != NULL)
353 int n;
355 for(n=0;n < drv->size;n++)
356 fput16(frame[n], drv->fd);
358 drv->n_frames++;
360 else
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);
369 fclose(drv->fd);
373 static void * d_wav(char * drvname, char * filename,
374 int freq, int n_channels, int * ssize)
375 /* init function */
377 static struct ss_outdrv_wav drv;
379 if(drvname && strcmp("wav", drvname) != 0)
380 return(NULL);
382 if(filename == NULL) filename="output.wav";
384 *ssize=sizeof(struct ss_outdrv_wav);
385 drv.func=d_wav_func;
386 drv.size=n_channels;
387 drv.n_frames=0;
389 if((drv.fd=fopen(filename, "w")) == NULL)
390 return(0);
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) */
408 return(&drv);
412 /*******************************************/
414 /* interface */
416 void * ss_outdev_open(char * drvname, char * file, int freq, int n_channels)
418 int size;
419 void * drv;
420 void * ret=NULL;
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)
428 ret=malloc(size);
429 memcpy(ret, drv, size);
432 return(ret);
436 void ss_outdev_write(void * drv, short int * frame)
438 void (**func)(void *, short int *)=drv;
440 (*func)(drv, frame);
444 void ss_outdev_close(void * drv)
446 ss_outdev_write(drv, NULL);
447 free(drv);