More ss_outdev rewriting.
[ahxm.git] / ss_outdev.c
blobe52e77803a2fa21e8d82fa110445ea29fa38e09b
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 <unistd.h>
35 #include <string.h>
37 struct ss_outdrv
39 char * drvname; /* driver name */
40 int (*open)(char *, int, int); /* open function */
41 void (*write)(int *, int); /* write frame function */
42 void (*close)(void); /* close function */
43 char * deffile; /* default file or device */
44 int max_channels; /* maximum channels (0, unlimited) */
47 struct ss_outdrv * drv=NULL;
49 /*******************
50 Code
51 ********************/
53 #ifdef CONFOPT_ARTS
55 #include <artsc.h>
57 static arts_stream_t arts;
59 static int d_arts_open(char * file, int freq, int n_channels)
61 int ret=0;
63 if(!arts_init() &&
64 (arts=arts_play_stream(freq, 16, n_channels, "annhell")))
65 ret=1;
67 return(ret);
71 static void d_arts_write(int frame[], int size)
73 arts_write(arts, frame, size);
77 static void d_arts_close(void)
79 arts_free();
82 struct ss_outdrv outdrv_arts=
83 { "arts", d_arts_open, d_arts_write, d_arts_close, NULL, 2 };
85 #else /* CONFOPT_ARTS */
87 struct ss_outdrv outdrv_arts=
88 { "arts", NULL, NULL, NULL, NULL, 2 };
90 #endif /* CONFOPT_ARTS */
92 /************************************************/
94 #ifdef CONFOPT_ESD
96 #include <unistd.h>
97 #include <esd.h>
99 static int esd_fd;
101 static int d_esd_open(char * file, int freq, int n_channels)
103 int ret=0;
104 esd_format_t format;
106 format = ESD_STREAM | ESD_PLAY | ESD_BITS16;
107 format |= n_channels == 2 ? ESD_STEREO : ESD_MONO;
109 if(esd_open_sound(file) >= 0 &&
110 (esd_fd=esd_play_stream_fallback(format, freq, NULL, "annhell")) >= 0)
111 ret=1;
113 return(ret);
116 static void d_esd_write(int frame[], int size)
118 write(esd_fd, frame, size);
122 static void d_esd_close(void)
124 close(esd_fd);
127 struct ss_outdrv outdrv_esd=
128 { "esd", d_esd_open, d_esd_write, d_esd_close, NULL, 2 };
130 #else /* CONFOPT_ESD */
132 struct ss_outdrv outdrv_esd=
133 { "esd", NULL, NULL, NULL, NULL, 2 };
135 #endif /* CONFOPT_ESD */
137 /************************************************/
139 #ifdef CONFOPT_SGI
141 #include <dmedia/audio.h>
143 static ALconfig ac;
144 static ALport ap;
146 static int d_sgi_open(char * file, int freq, int n_channels)
148 int ret=0;
149 ALpv p[2];
151 p[0].param=AL_MASTER_CLOCK;
152 p[0].value.i=AL_CRYSTAL_MCLK_TYPE;
153 p[1].param=AL_RATE;
154 p[1].value.ll=alDoubleToFixed((double) freq);
156 if((ac=alNewConfig()))
158 if(alSetChannels(ac, n_channels) >= 0 &&
159 alSetWidth(ac, AL_SAMPLE_16) >= 0 &&
160 alSetSampFmt(ac, AL_SAMPFMT_TWOSCOMP) >= 0 &&
161 alSetQueueSize(ac, 2048) >=0 &&
162 alSetDevice(ac, AL_DEFAULT_OUTPUT) >= 0 &&
163 alSetParams(alGetDevice(ac), p, 2) >= 0 &&
164 (ap=alOpenPort("annhell", "w", ac)))
165 ret=1;
168 return(ret);
172 static int d_sgi_write(int frame[], int size)
174 alWriteFrames(ap, frame, 1);
178 static int d_sgi_close(void)
180 alClosePort(ap);
181 alFreeConfig(ac);
184 struct ss_outdrv outdrv_sgi=
185 { "sgi", d_sgi_open, d_sgi_write, d_sgi_close, NULL, 0 };
187 #else /* CONFOPT_SGI */
189 struct ss_outdrv outdrv_sgi=
190 { "sgi", NULL, NULL, NULL, NULL, 0 };
193 #endif /* CONFOPT_SGI */
195 /************************************************/
197 #ifdef CONFOPT_LINUX_OSS
199 #include <fcntl.h>
200 #include <sys/ioctl.h>
201 #include <linux/soundcard.h>
203 static int is_little_endian(void)
205 short s=1;
206 unsigned char * c=(unsigned char *) &s;
208 return(*c == 1);
211 static int oss_fd;
213 static int d_oss_open(char * file, int freq, int n_channels)
215 int ret=0;
216 int fr, st, fm;
218 fr=(2 << 16)|(1 << 10);
219 st=n_channels == 2 ? 1 : 0;
220 fm=is_little_endian() ? AFMT_S16_LE : AFMT_S16_BE;
222 if((oss_fd=open(file, O_WRONLY)) >= 0)
224 if(ioctl(oss_fd, SNDCTL_DSP_SETFRAGMENT, &fr) >= 0 &&
225 ioctl(oss_fd, SNDCTL_DSP_RESET, 0) >= 0 &&
226 ioctl(oss_fd, SNDCTL_DSP_SPEED, &freq) >= 0 &&
227 ioctl(oss_fd, SNDCTL_DSP_STEREO, &st) >= 0 &&
228 ioctl(oss_fd, SNDCTL_DSP_SETFMT, &fm) >= 0)
229 ret=1;
232 return(ret);
236 static void d_oss_write(int frame[], int size)
238 write(oss_fd, frame, size);
242 static void d_oss_close(void)
244 close(oss_fd);
247 struct ss_outdrv outdrv_oss=
248 { "oss", d_oss_open, d_oss_write, d_oss_close, "/dev/dsp", 2 };
250 #else /* CONFOPT_LINUX_OSS */
252 struct ss_outdrv outdrv_oss=
253 { "oss", NULL, NULL, NULL, NULL, 2 };
255 #endif /* CONFOPT_LINUX_OSS */
257 /************************************************/
259 static void fput16(short int i, FILE * f)
261 fputc(i & 0x00ff, f);
262 fputc((i & 0xff00) >> 8, f);
266 static void fput32(int i, FILE * f)
268 fputc(i & 0x000000ff, f);
269 fputc((i & 0x0000ff00) >> 8, f);
270 fputc((i & 0x00ff0000) >> 16, f);
271 fputc((i & 0xff000000) >> 24, f);
274 static FILE * wav_fd;
275 static int wav_frames;
277 static int d_wav_open(char * file, int freq, int n_channels)
279 if((wav_fd=fopen(file, "w")) == NULL) return(0);
281 /* write wav header */
283 fwrite("RIFF", 1, 4, wav_fd);
284 fput32(36, wav_fd); /* first checkpoint (offset: 4) */
285 fwrite("WAVE", 1, 4, wav_fd);
286 fwrite("fmt ", 1, 4, wav_fd);
287 fput32(16, wav_fd); /* chunk size */
288 fput16(1, wav_fd); /* 1: uncompressed PCM */
289 fput16(n_channels, wav_fd); /* # of channels */
290 fput32(freq, wav_fd); /* sample rate */
291 fput32(freq * n_channels * 2, wav_fd); /* bytes per second */
292 fput16(n_channels * 2, wav_fd); /* 'block align' */
293 fput16(16, wav_fd); /* 16 bits per sample */
294 fwrite("data", 1, 4, wav_fd);
295 fput32(0, wav_fd); /* second checkpoint (offset: 40) */
297 wav_frames=0;
299 return(1);
303 static void d_wav_write(int frame[], int size)
305 int n;
307 size /= sizeof(short int);
309 for(n=0;n < size;n++)
310 fput16(frame[n], wav_fd);
312 wav_frames++;
316 static void d_wav_close(void)
318 /* rewind file and write total size */
319 fseek(wav_fd, 4, SEEK_SET);
320 fput32((wav_frames * n_channels) + 36, wav_fd);
322 fseek(wav_fd, 40, SEEK_SET);
323 fput32(wav_frames * n_channels, wav_fd);
325 fclose(wav_fd);
328 struct ss_outdrv outdrv_wav=
329 { "wav", d_wav_open, d_wav_write, d_wav_close, "output.wav", 0 };
331 static struct ss_outdrvs[] = {
332 &outdrv_arts,
333 &outdrv_esd,
334 &outdrv_sgi,
335 &outdrv_oss,
336 &outdrv_wav,
337 NULL
340 int ss_outdev(char * drv, char * file, int freq, int n_channels)
342 int p[2], n;
344 pipe(p);
346 if(fork() != 0)
348 /* parent; return immediately */
349 close(p[0]);
350 return(p[1]);
353 /* forked child */
355 /* closes the writing part of the pipe */
356 close(p[1]);
358 /* detaches from group */
359 setpgid(0, 0);
361 /* find the appropriate driver */
362 for(n=0;drivers[n].drvname != NULL;n++)
364 if(drv == NULL || strcmp(drv, drivers[n].drvname) == 0)
366 if(drivers[n].func(p[0],
367 file ? file : drivers[n].deffile,
368 freq, n_channels))
369 break;
373 close(p[0]);
374 exit(0);
376 return(0);