The forked output process detaches from the group id.
[ahxm.git] / ss_outdev.c
blob26082f987e51ed331b6ed27027fdb09b99671c51
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 /*******************
38 Code
39 ********************/
41 static int o_unsupp(int i, char * o, int f, int n) { return(0); }
43 /************************************************/
45 #ifdef CONFOPT_ARTS
47 #include <artsc.h>
49 static int o_arts(int i, char * file, int freq, int n_channels)
51 int ret=0;
52 short int ibuf[128];
53 int n, nc;
54 static arts_stream_t arts;
56 nc=n_channels >= 2 ? 2 : 1;
58 if(!arts_init() && (arts=arts_play_stream(freq, 16, nc, "annhell")))
60 n_channels *= sizeof(short int);
61 nc *= sizeof(short int);
63 while((n=read(i, ibuf, n_channels)) > 0)
64 arts_write(arts, ibuf, nc);
66 arts_free();
68 ret=1;
71 return(ret);
74 #else /* CONFOPT_ARTS */
76 #define o_arts o_unsupp
78 #endif /* CONFOPT_ARTS */
80 /************************************************/
82 #ifdef CONFOPT_ESD
84 #include <unistd.h>
85 #include <esd.h>
87 static int o_esd(int i, char * file, int freq, int n_channels)
89 int ret=0;
90 short int ibuf[128];
91 int o, nc, n;
92 esd_format_t format;
94 nc=n_channels >= 2 ? 2 : 1;
96 format = ESD_STREAM | ESD_PLAY | ESD_BITS16;
97 format |= nc == 2 ? ESD_STEREO : ESD_MONO;
99 if(esd_open_sound(file) >= 0 &&
100 (o=esd_play_stream_fallback(format, freq, NULL, "annhell")) >= 0)
102 n_channels *= sizeof(short int);
103 nc *= sizeof(short int);
105 while((n=read(i, ibuf, n_channels)) > 0)
106 write(o, ibuf, nc);
108 esd_close(o);
110 ret=1;
113 return(ret);
116 #else /* CONFOPT_ESD */
118 #define o_esd o_unsupp
120 #endif /* CONFOPT_ESD */
122 /************************************************/
124 #ifdef CONFOPT_SGI
126 #include <dmedia/audio.h>
128 static int o_sgi(int i, char * file, int freq, int n_channels)
130 int ret=0;
131 short int ibuf[128];
132 ALconfig ac;
133 ALport ap;
134 ALpv p[2];
136 p[0].param=AL_MASTER_CLOCK;
137 p[0].value.i=AL_CRYSTAL_MCLK_TYPE;
138 p[1].param=AL_RATE;
139 p[1].value.ll=alDoubleToFixed((double) freq);
141 if((ac=alNewConfig()))
143 if(alSetChannels(ac, n_channels) >= 0 &&
144 alSetWidth(ac, AL_SAMPLE_16) >= 0 &&
145 alSetSampFmt(ac, AL_SAMPFMT_TWOSCOMP) >= 0 &&
146 alSetQueueSize(ac, 2048) >=0 &&
147 alSetDevice(ac, AL_DEFAULT_OUTPUT) >= 0 &&
148 alSetParams(alGetDevice(ac), p, 2) >= 0 &&
149 (ap=alOpenPort("annhell", "w", ac)))
151 n_channels *= sizeof(short int);
153 while((n=read(i, ibuf, n_channels)) > 0)
154 alWriteFrames(ap, ibuf, 1);
156 alClosePort(ap);
158 ret=1;
161 alFreeConfig(ac);
164 return(ret);
167 #else /* CONFOPT_SGI */
169 #define o_sgi o_unsupp
171 #endif /* CONFOPT_SGI */
173 /************************************************/
175 #ifdef CONFOPT_LINUX_OSS
177 #include <fcntl.h>
178 #include <sys/ioctl.h>
179 #include <linux/soundcard.h>
181 static int is_little_endian(void)
183 short s=1;
184 unsigned char * c=(unsigned char *) &s;
186 return(*c == 1);
190 static int o_oss(int i, char * file, int freq, int n_channels)
192 int ret=0;
193 short int ibuf[128];
194 int o, n, nc, fr, st, fm;
196 nc=n_channels >= 2 ? 2 : 1;
197 fr=(2 << 16)|(1 << 10);
198 st=nc == 2 ? 1 : 0;
199 fm=is_little_endian() ? AFMT_S16_LE : AFMT_S16_BE;
201 if((o=open(file, O_WRONLY)) >= 0)
203 if(ioctl(o, SNDCTL_DSP_SETFRAGMENT, &fr) >= 0 &&
204 ioctl(o, SNDCTL_DSP_RESET, 0) >= 0 &&
205 ioctl(o, SNDCTL_DSP_SPEED, &freq) >= 0 &&
206 ioctl(o, SNDCTL_DSP_STEREO, &st) >= 0 &&
207 ioctl(o, SNDCTL_DSP_SETFMT, &fm) >= 0)
209 n_channels *= sizeof(short int);
210 nc *= sizeof(short int);
212 while((n=read(i, ibuf, n_channels)) > 0)
213 write(o, ibuf, nc);
215 ret=1;
218 close(o);
221 return(ret);
224 #else /* CONFOPT_LINUX_OSS */
226 #define o_oss o_unsupp
228 #endif /* CONFOPT_LINUX_OSS */
230 /************************************************/
232 static void fput16(short int i, FILE * f)
234 fputc(i & 0x00ff, f);
235 fputc((i & 0xff00) >> 8, f);
239 static void fput32(int i, FILE * f)
241 fputc(i & 0x000000ff, f);
242 fputc((i & 0x0000ff00) >> 8, f);
243 fputc((i & 0x00ff0000) >> 16, f);
244 fputc((i & 0xff000000) >> 24, f);
248 static int o_wav(int i, char * file, int freq, int n_channels)
250 short int ibuf[128];
251 FILE * f;
252 int n, m, c;
254 if((f=fopen(file, "w")) == NULL) return(0);
256 /* write wav header */
258 fwrite("RIFF",1,4,f);
259 fput32(36, f); /* first checkpoint (offset: 4) */
260 fwrite("WAVE",1,4,f);
261 fwrite("fmt ",1,4,f);
262 fput32(16,f); /* chunk size */
263 fput16(1, f); /* 1: uncompressed PCM */
264 fput16(n_channels, f); /* # of channels */
265 fput32(freq, f); /* sample rate */
266 fput32(freq * n_channels * 2, f); /* bytes per second */
267 fput16(n_channels * 2, f); /* 'block align' */
268 fput16(16, f); /* 16 bits per sample */
269 fwrite("data",1,4,f);
270 fput32(0, f); /* second checkpoint (offset: 40) */
272 n_channels *= sizeof(short int);
274 for(c=0;(n=read(i, ibuf, n_channels)) > 0;c++)
276 n /= sizeof(short int);
278 for(m=0;m < n;m++)
279 fput16(ibuf[m], f);
282 /* rewind file and write total size */
283 fseek(f, 4, SEEK_SET);
284 fput32((c * n_channels) + 36, f);
286 fseek(f, 40, SEEK_SET);
287 fput32(c * n_channels, f);
289 fclose(f);
291 return(1);
295 static struct
297 char * drvname;
298 char * deffile;
299 int (* func)(int, char *, int, int);
300 } drivers[] = {
301 { "arts", NULL, o_arts },
302 { "esd", NULL, o_esd },
303 { "sgi", NULL, o_sgi },
304 { "oss", "/dev/dsp", o_oss },
305 { "wav", "output.wav", o_wav },
306 { NULL, NULL, NULL }
309 int ss_outdev(char * drv, char * file, int freq, int n_channels)
311 int p[2], n;
313 pipe(p);
315 if(fork() != 0)
317 /* parent; return immediately */
318 close(p[0]);
319 return(p[1]);
322 /* forked child */
324 /* closes the writing part of the pipe */
325 close(p[1]);
327 /* detaches from group */
328 setpgid(0, 0);
330 /* find the appropriate driver */
331 for(n=0;drivers[n].drvname != NULL;n++)
333 if(drv == NULL || strcmp(drv, drivers[n].drvname) == 0)
335 if(drivers[n].func(p[0],
336 file ? file : drivers[n].deffile,
337 freq, n_channels))
338 break;
342 close(p[0]);
343 exit(0);
345 return(0);