#include #include #include #include #include #include #include #include #include #include "gl-int.h" #include "sounds.h" extern const char *__progname; static const char *defaudiodev = "/dev/audio"; static int afd = -1; static char repeating[SOUND__N]; typedef struct snd SND; struct snd { SND *link; int id; const signed short int *data; unsigned int len; unsigned int ptr; unsigned int repeat : 1; } ; static SND *playing = 0; static SND *freesnds = 0; static int paused = 0; /* QSIZE should be a bit more than enough samples to fill up DELAY at 8kHz */ #define QSIZE 250 /* samples */ #define DELAY 20000 /* usec */ /* mulaw seems to be a floating-point format that splits up eight bits as sign(1), exponent(3), mantissa(4) - and for then some incomprehensible reason bit-complements the whole thing. */ static unsigned char linear_to_ulaw(signed long int linear) { unsigned char sign; unsigned char exp; unsigned char mant; static unsigned exptbl[128] = { 0,1,2,2,3,3,3,3,4,4,4,4,4,4,4,4, 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6, 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7 }; if (linear < 0) { linear = - linear; sign = 0x80; } else { sign = 0; } linear += 0x84; /* where does this magic number come from?? */ if (linear > 32767) linear = 32767; exp = exptbl[linear>>8]; mant = (linear >> (exp+3)) & 0xf; return(~(sign|(exp<<4)|mant)); } static SND *getsnd(void) { SND *s; if (freesnds) { s = freesnds; freesnds = s->link; } else { s = malloc(sizeof(SND)); } return(s); } static void freesnd(SND *s) { s->link = freesnds; freesnds = s; } static void playsome(int n) { signed long int linear[QSIZE]; unsigned char ulaw[QSIZE]; SND *s; SND **sp; int i; int j; int c; if (n < 1) return; for (i=0;irepeat) { if (repeating[s->id]) { j = s->ptr; c = s->len; for (i=0;idata[j]; j ++; if (j >= c) j = 0; } s->ptr = j; sp = &s->link; } else { *sp = s->link; freesnd(s); } } else { c = s->len - s->ptr; if (c > n) c = n; for (i=0,j=s->ptr;idata[j]; s->ptr += c; if (s->ptr >= s->len) { *sp = s->link; freesnd(s); } else { sp = &s->link; } } } } for (i=0;i= 0) { close(afd); afd = -1; } } static void sound_setselect( fd_set *r __attribute__((__unused__)), fd_set *w __attribute__((__unused__)), fd_set *x __attribute__((__unused__)), struct timeval *now __attribute__((__unused__)), struct timeval *delay ) { audio_info_t ai; if (afd < 0) return; if (ioctl(afd,AUDIO_GETINFO,&ai) < 0) { fprintf(stderr,"%s: AUDIO_GETINFO: %s\n",__progname,strerror(errno)); exit(1); } playsome(QSIZE-ai.play.seek); if ( (delay->tv_sec > (DELAY/1000000)) || ( (delay->tv_sec == (DELAY/1000000)) && (delay->tv_usec > (DELAY%1000000)) ) ) { delay->tv_sec = DELAY / 1000000; delay->tv_usec = DELAY % 1000000; } } void sound_start(const char *audiodev) { audio_info_t ai; if (! audiodev) audiodev = defaudiodev; afd = open(audiodev,O_WRONLY,0); if (afd < 0) { nosound("open %s: %s",audiodev,strerror(errno)); return; } AUDIO_INITINFO(&ai); ai.blocksize = 1; if (ioctl(afd,AUDIO_SETINFO,&ai) < 0) { nosound("AUDIO_SETINFO: %s",strerror(errno)); return; } if (ai.blocksize > 1) { nosound("audio blocksize too large"); return; } register_setselect(sound_setselect); } void sound_once(int id) { SND *s; if (afd < 0) return; s = getsnd(); s->id = id; s->data = sound_dat(id); s->len = sound_len(id); s->ptr = 0; s->repeat = 0; s->link = playing; playing = s; } void sound_repeat(int id, int play) { SND *s; if (afd < 0) return; if (play && repeating[id]) return; if (!play && !repeating[id]) return; repeating[id] = play ? 1 : 0; if (play) { s = getsnd(); s->id = id; s->data = sound_dat(id); s->len = sound_len(id); s->ptr = 0; s->repeat = 1; s->link = playing; playing = s; } } void sound_pause(int stop) { if (afd < 0) return; paused = stop ? 1 : 0; }