X-Git-Url: http://git.mutantstargoat.com/user/nuclear/?p=dos_auplay;a=blobdiff_plain;f=src%2Fau_sb.c;h=0daa7c0d57d12171dc9c474af8f7dbd5a5e8fcc4;hp=d733f20b71bc910403ba4d0396adb035e69f1fbe;hb=49ef4e243def029b7e68bf92141acbeac600e1e8;hpb=87ef5613bb9baae3903237321c15133066139f7c diff --git a/src/au_sb.c b/src/au_sb.c index d733f20..0daa7c0 100644 --- a/src/au_sb.c +++ b/src/au_sb.c @@ -9,6 +9,8 @@ #include "dma.h" #include "intr.h" +#define BUFSIZE 16384 + #define REG_MIXPORT (base_port + 0x4) #define REG_MIXDATA (base_port + 0x5) #define REG_RESET (base_port + 0x6) @@ -84,12 +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 void *buffer; -static int xfer_mode; -static int isplaying; -static int cur_bits, cur_mode; -static int curblk; +static void *buffer[2]; +static volatile int wrbuf; + +static volatile int isplaying; +static int cur_bits, cur_mode, auto_init; static void (INTERRUPT *prev_intr_handler)(); @@ -180,19 +182,19 @@ void sb_set_output_rate(int rate) void *sb_buffer(int *size) { - *size = 32768; - return (char*)buffer + curblk * 32768; + *size = BUFSIZE / 2; + return buffer[wrbuf]; } 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) { - /* allocate a 64k-aligned 64k buffer in low memory */ - if(!(seg = dpmi_alloc(65536 * 2 / 16, &pmsel))) { + 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; } @@ -200,17 +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); - buffer = (void*)addr; - } else { - addr = (uint32_t)buffer; + 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, 32768))) { + /* 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; } - curblk = 1; + addr = (uint32_t)buffer[wrbuf]; + num_samples = bits == 8 ? size : size / 2; _disable(); if(!prev_intr_handler) { @@ -223,24 +242,22 @@ void sb_start(int rate, int bits, int nchan) unmask_irq(irq); cur_bits = bits; - cur_mode = 0; /* TODO */ + cur_mode = bits == 8 ? 0 : DSP4_MODE_SIGNED; if(nchan > 1) { cur_mode |= DSP4_MODE_STEREO; } write_dsp(DSP_ENABLE_OUTPUT); - dma_out(dma_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, size); + 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); @@ -276,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; } @@ -296,20 +310,29 @@ void sb_volume(int vol) static void INTERRUPT intr_handler() { int size; - void *bptr = (unsigned char*)buffer + curblk * 32768; + void *bptr = buffer[wrbuf]; + uint32_t addr = (uint32_t)bptr; - curblk = (curblk + 1) & 1; + wrbuf ^= 1; /* ask for more data */ - if(!(size = audio_callback(bptr, 32768))) { + if(!(size = audio_callback(bptr, BUFSIZE / 2))) { sb_stop(); - } else { - dma_out(dma_chan, (uint32_t)bptr, size, DMA_SINGLE); - start_dsp4(cur_bits, cur_mode, size); } /* acknowledge the interrupt */ - inp(REG_INTACK); + if(cur_bits == 8) { + inp(REG_INTACK); + } else { + /* + unsigned char istat; + outp(REG_MIXPORT, 0x82); + istat = inp(REG_MIXDATA); + if(istat & 2) { + */ + inp(REG_INT16ACK); + //} + } if(irq > 7) { outp(PIC2_CMD, OCW2_EOI);