From: John Tsiombikas Date: Fri, 1 Feb 2019 05:17:13 +0000 (+0200) Subject: fixed by preloading samples. the audio callback is being called from the X-Git-Url: http://git.mutantstargoat.com/user/nuclear/?p=dos_auplay;a=commitdiff_plain;h=49ef4e243def029b7e68bf92141acbeac600e1e8 fixed by preloading samples. the audio callback is being called from the context of the interrupt handler, and can't perform file I/O --- diff --git a/src/au_sb.c b/src/au_sb.c index a1ea830..0daa7c0 100644 --- a/src/au_sb.c +++ b/src/au_sb.c @@ -86,13 +86,12 @@ static const char *sbname(int ver); static int base_port; static int irq, dma_chan, dma16_chan, dsp_ver; static int dsp4; -static int xfer_mode; static void *buffer[2]; -static int wrbuf; +static volatile int wrbuf; -static int isplaying; -static int cur_bits, cur_mode; +static volatile int isplaying; +static int cur_bits, cur_mode, auto_init; static void (INTERRUPT *prev_intr_handler)(); @@ -190,11 +189,11 @@ void *sb_buffer(int *size) void sb_start(int rate, int bits, int nchan) { uint16_t seg, pmsel; - uint32_t addr; - int size; + uint32_t addr, next64k; + int size, num_samples; - if(!buffer[0]) { - /* allocate a 64k-aligned buffer in low memory */ + if(!buffer[1]) { + /* allocate a buffer in low memory that doesn't cross 64k boundaries */ if(!(seg = dpmi_alloc(BUFSIZE * 2 / 16, &pmsel))) { fprintf(stderr, "sb_start: failed to allocate DMA buffer\n"); return; @@ -203,18 +202,34 @@ void sb_start(int rate, int bits, int nchan) printf("DBG allocated seg: %x, addr: %lx\n", (unsigned int)seg, (unsigned long)seg << 4); - addr = ((uint32_t)(seg << 4) + 0xffff) & 0xffff0000; - printf("DBG aligned: %lx\n", (unsigned long)addr); + addr = (uint32_t)seg << 4; + next64k = (addr + 0x10000) & 0xffff0000; + if(next64k - addr < BUFSIZE) { + addr = next64k; + } + + printf("DBG aligned: %lx (mid: %lx)\n", (unsigned long)addr, (unsigned long)(addr + BUFSIZE / 2)); buffer[0] = (void*)addr; buffer[1] = (void*)(addr + BUFSIZE / 2); wrbuf = 0; } - if(!(size = audio_callback(buffer[wrbuf], BUFSIZE / 2))) { + /* Auto-init playback mode: + * fill the whole buffer with data, program the DMA for BUFSIZE transfer, + * and program the DSP for BUFSIZE/2 transfer. We'll get an interrupt in the + * middle, while the DSP uses the upper half, and we'll refill the bottom half. + * Then continue ping-ponging the two halves of the buffer until we run out of + * data. + */ + auto_init = 1; + + /* TODO: if size <= BUFSIZE, do a single transfer instead */ + wrbuf = 0; + if(!(size = audio_callback(buffer[wrbuf], BUFSIZE))) { return; } addr = (uint32_t)buffer[wrbuf]; - wrbuf ^= 1; + num_samples = bits == 8 ? size : size / 2; _disable(); if(!prev_intr_handler) { @@ -233,18 +248,16 @@ void sb_start(int rate, int bits, int nchan) } write_dsp(DSP_ENABLE_OUTPUT); - dma_out(bits == 8 ? dma_chan : dma16_chan, addr, size, DMA_SINGLE); + dma_out(cur_bits == 8 ? dma_chan : dma16_chan, addr, BUFSIZE, DMA_SINGLE | DMA_AUTO); sb_set_output_rate(rate); - start_dsp4(cur_bits, cur_mode, bits == 8 ? size : size / 2); + start_dsp4(cur_bits, cur_mode, num_samples / 2); isplaying = 1; } static void start_dsp4(int bits, unsigned int mode, int num_samples) { unsigned char cmd = bits == 8 ? DSP4_START_DMA8 : DSP4_START_DMA16; - assert(bits == 8 || bits == 16); - - /*cmd |= DSP4_AUTO | DSP4_FIFO;*/ + cmd |= DSP4_AUTO | DSP4_FIFO; /* program the DSP to start the DMA transfer */ write_dsp(cmd); @@ -280,10 +293,7 @@ void sb_stop(void) _dos_setvect(IRQ_TO_INTR(irq), prev_intr_handler); _enable(); - /* no need to stop anything if we're in single-cycle mode */ - if(cur_mode & DSP4_AUTO) { - write_dsp(cur_bits == 8 ? DSP_END_DMA8 : DSP_END_DMA16); - } + write_dsp(cur_bits == 8 ? DSP_END_DMA8 : DSP_END_DMA16); isplaying = 0; } @@ -308,21 +318,20 @@ static void INTERRUPT intr_handler() /* ask for more data */ if(!(size = audio_callback(bptr, BUFSIZE / 2))) { sb_stop(); - } else { - if(cur_bits == 8) { - dma_out(dma_chan, addr, size, DMA_SINGLE); - start_dsp4(cur_bits, cur_mode, size); - } else { - dma_out(dma16_chan, addr, size, DMA_SINGLE); - start_dsp4(cur_bits, cur_mode, size / 2); - } } /* acknowledge the interrupt */ if(cur_bits == 8) { inp(REG_INTACK); } else { - inp(REG_INT16ACK); + /* + unsigned char istat; + outp(REG_MIXPORT, 0x82); + istat = inp(REG_MIXDATA); + if(istat & 2) { + */ + inp(REG_INT16ACK); + //} } if(irq > 7) { diff --git a/src/audio.c b/src/audio.c index 88b8400..51a3521 100644 --- a/src/audio.c +++ b/src/audio.c @@ -17,7 +17,7 @@ static struct audrv drv; static audio_callback_func cbfunc; static void *cbcls; -void audio_init(void) +int audio_init(void) { if(sb_detect()) { drv.get_buffer = sb_buffer; @@ -27,10 +27,11 @@ void audio_init(void) drv.stop = sb_stop; drv.volume = sb_volume; drv.isplaying = sb_isplaying; - return; + return 0; } - printf("No supported audio device detected\n"); + fprintf(stderr, "No supported audio device detected\n"); + return -1; } void audio_set_callback(audio_callback_func func, void *cls) @@ -49,6 +50,7 @@ int audio_callback(void *buf, int sz) void audio_play(int rate, int bits, int nchan) { + printf("play %d samples/s, %d bits, %s\n", rate, bits, nchan == 1 ? "mono" : "stereo"); drv.start(rate, bits, nchan); } diff --git a/src/audio.h b/src/audio.h index c522134..9268627 100644 --- a/src/audio.h +++ b/src/audio.h @@ -3,7 +3,7 @@ typedef int (*audio_callback_func)(void *buffer, int size, void *cls); -void audio_init(void); +int audio_init(void); void audio_set_callback(audio_callback_func func, void *cls); int audio_callback(void *buf, int sz); diff --git a/src/aufile.h b/src/aufile.h index faca4c8..d5ef5e4 100644 --- a/src/aufile.h +++ b/src/aufile.h @@ -4,6 +4,7 @@ struct au_file { int rate, bits, chan; void *data; + unsigned long size; FILE *fp; void (*close)(struct au_file*); diff --git a/src/auwav.c b/src/auwav.c index eca5a76..6e1afc1 100644 --- a/src/auwav.c +++ b/src/auwav.c @@ -66,6 +66,7 @@ int au_open_wav(struct au_file *au) au->rate = fmt.rate; au->bits = fmt.sample_bytes * 8; au->chan = fmt.nchan; + au->size = pb->size; au->data = pb; au->close = close_wav; diff --git a/src/main.c b/src/main.c index 9a1b262..4395af6 100644 --- a/src/main.c +++ b/src/main.c @@ -1,16 +1,22 @@ #include +#include #include #include "aufile.h" #include "audio.h" +#define DBG_PRELOAD + static int play_file(const char *fname); +static int cbfunc(void *buf, int size, void *cls); static void print_usage(const char *argv0); int main(int argc, char **argv) { int i; - play_file("namarie.wav"); /* TODO remove */ + if(audio_init() == -1) { + return 1; + } for(i=1; isize))) { + perror("failed to preload samples into memory"); + return -1; + } + dbg_cur_offs = 0; + if(au_read(au, dbg_samples, au->size) < au->size) { + perror("failed to preload samples into memory"); + return -1; + } +#endif + audio_play(au->rate, au->bits, au->chan); while(audio_isplaying()); au_close(au); +#ifdef DBG_PRELOAD + free(dbg_samples); +#endif return 0; } +#ifdef DBG_PRELOAD +static int cbfunc(void *buf, int size, void *cls) +{ + struct au_file *au = cls; + + if(dbg_cur_offs + size > au->size) { + size = au->size - dbg_cur_offs; + } + if(size <= 0) return 0; + + memcpy(buf, dbg_samples + dbg_cur_offs, size); + dbg_cur_offs += size; + return size; +} +#else +static int cbfunc(void *buf, int size, void *cls) +{ + int rd; + + if((rd = au_read(cls, buf, size)) <= 0) { + return 0; + } + return rd; +} +#endif + static void print_usage(const char *argv0) { printf("Usage: %s [options] ... \n", argv0);