The song statistics message in ss_song.c (shown when
[ahxm.git] / ss_outdev.c
blob22ef73abb7fcf38d5ffcf92bd10ba055dd8983e6
1 /*
3 Ann Hell Ex Machina - Music Software
4 Copyright (C) 2005/2006 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, "ahxm")) == 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, "ahxm")) < 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("ahxm", "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)|12;
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 #ifdef CONFOPT_PTHREADS
422 /* pthread support */
424 #include <pthread.h>
426 static pthread_t consumer;
427 static pthread_mutex_t mutex;
428 static pthread_cond_t cond;
430 /* the real function inside the driver */
431 static void (* real_drv_func)(void *, short int *) = NULL;
433 /* number of ints in frame_cpy */
434 static int frame_cpy_n = 0;
436 /* a copy of the frame */
437 static short int * frame_cpy = NULL;
439 static void * outdev_thread(void * driver)
440 /* pthread 'consumer' function */
442 pthread_mutex_lock(&mutex);
444 for(;;)
446 /* wait for data available */
447 pthread_cond_wait(&cond, &mutex);
449 /* call the real function */
450 real_drv_func(driver, frame_cpy);
452 /* no more? */
453 if(frame_cpy == NULL)
454 break;
457 pthread_mutex_unlock(&mutex);
458 return(NULL);
462 static void outdev_producer_wrapper(void * d, short int * frame)
463 /* wrapper 'producer' function */
465 int n;
467 pthread_mutex_lock(&mutex);
469 if(frame == NULL)
471 /* close */
472 free(frame_cpy);
473 frame_cpy = NULL;
474 frame_cpy_n = 0;
476 else
478 /* copy the frame */
479 for(n = 0;n < frame_cpy_n;n++)
480 frame_cpy[n] = frame[n];
483 pthread_cond_signal(&cond);
484 pthread_mutex_unlock(&mutex);
488 static void thread_setup(void * d, int n_channels)
490 void (**drv)(void *, short int *) = d;
492 /* create the buffer */
493 frame_cpy_n = n_channels;
494 frame_cpy = malloc(frame_cpy_n * sizeof(short int));
496 pthread_mutex_init(&mutex, NULL);
497 pthread_cond_init(&cond, NULL);
499 /* 'patch' the driver */
500 real_drv_func = *drv;
501 *drv = outdev_producer_wrapper;
503 /* launch the thread */
504 pthread_create(&consumer, NULL, outdev_thread, d);
508 #else /* CONFOPT_PTHREADS */
510 void thread_setup(void * d, int n)
512 /* do nothing */
515 #endif /* CONFOPT_PTHREADS */
517 /*******************************************/
519 /* interface */
521 void * ss_outdev_open(char * drvname, char * file, int freq, int n_channels)
523 int size;
524 void * drv;
525 void * ret = NULL;
527 if((drv = d_arts(drvname, file, freq, n_channels, &size)) != NULL ||
528 (drv = d_esd(drvname, file, freq, n_channels, &size)) != NULL ||
529 (drv = d_sgi(drvname, file, freq, n_channels, &size)) != NULL ||
530 (drv = d_oss(drvname, file, freq, n_channels, &size)) != NULL ||
531 (drv = d_wav(drvname, file, freq, n_channels, &size)) != NULL)
533 ret = malloc(size);
534 memcpy(ret, drv, size);
537 thread_setup(ret, n_channels);
539 return(ret);
543 void ss_outdev_write(void * drv, short int * frame)
545 void (**func)(void *, short int *) = drv;
547 (*func)(drv, frame);
551 void * ss_outdev_close(void * drv)
553 if(drv != NULL)
555 ss_outdev_write(drv, NULL);
556 free(drv);
559 return(NULL);