fixed by preloading samples. the audio callback is being called from the
[dos_auplay] / src / au_sb.c
index a1ea830..0daa7c0 100644 (file)
@@ -86,13 +86,12 @@ static const char *sbname(int ver);
 static int base_port;\r
 static int irq, dma_chan, dma16_chan, dsp_ver;\r
 static int dsp4;\r
-static int xfer_mode;\r
 \r
 static void *buffer[2];\r
-static int wrbuf;\r
+static volatile int wrbuf;\r
 \r
-static int isplaying;\r
-static int cur_bits, cur_mode;\r
+static volatile int isplaying;\r
+static int cur_bits, cur_mode, auto_init;\r
 \r
 static void (INTERRUPT *prev_intr_handler)();\r
 \r
@@ -190,11 +189,11 @@ void *sb_buffer(int *size)
 void sb_start(int rate, int bits, int nchan)\r
 {\r
        uint16_t seg, pmsel;\r
-       uint32_t addr;\r
-       int size;\r
+       uint32_t addr, next64k;\r
+       int size, num_samples;\r
 \r
-       if(!buffer[0]) {\r
-               /* allocate a 64k-aligned buffer in low memory */\r
+       if(!buffer[1]) {\r
+               /* allocate a buffer in low memory that doesn't cross 64k boundaries */\r
                if(!(seg = dpmi_alloc(BUFSIZE * 2 / 16, &pmsel))) {\r
                        fprintf(stderr, "sb_start: failed to allocate DMA buffer\n");\r
                        return;\r
@@ -203,18 +202,34 @@ void sb_start(int rate, int bits, int nchan)
                printf("DBG allocated seg: %x, addr: %lx\n", (unsigned int)seg,\r
                                (unsigned long)seg << 4);\r
 \r
-               addr = ((uint32_t)(seg << 4) + 0xffff) & 0xffff0000;\r
-               printf("DBG aligned: %lx\n", (unsigned long)addr);\r
+               addr = (uint32_t)seg << 4;\r
+               next64k = (addr + 0x10000) & 0xffff0000;\r
+               if(next64k - addr < BUFSIZE) {\r
+                       addr = next64k;\r
+               }\r
+\r
+               printf("DBG aligned: %lx (mid: %lx)\n", (unsigned long)addr, (unsigned long)(addr + BUFSIZE / 2));\r
                buffer[0] = (void*)addr;\r
                buffer[1] = (void*)(addr + BUFSIZE / 2);\r
                wrbuf = 0;\r
        }\r
 \r
-       if(!(size = audio_callback(buffer[wrbuf], BUFSIZE / 2))) {\r
+       /* Auto-init playback mode:\r
+        * fill the whole buffer with data, program the DMA for BUFSIZE transfer,\r
+        * and program the DSP for BUFSIZE/2 transfer. We'll get an interrupt in the\r
+        * middle, while the DSP uses the upper half, and we'll refill the bottom half.\r
+        * Then continue ping-ponging the two halves of the buffer until we run out of\r
+        * data.\r
+        */\r
+       auto_init = 1;\r
+\r
+       /* TODO: if size <= BUFSIZE, do a single transfer instead */\r
+       wrbuf = 0;\r
+       if(!(size = audio_callback(buffer[wrbuf], BUFSIZE))) {\r
                return;\r
        }\r
        addr = (uint32_t)buffer[wrbuf];\r
-       wrbuf ^= 1;\r
+       num_samples = bits == 8 ? size : size / 2;\r
 \r
        _disable();\r
        if(!prev_intr_handler) {\r
@@ -233,18 +248,16 @@ void sb_start(int rate, int bits, int nchan)
        }\r
 \r
        write_dsp(DSP_ENABLE_OUTPUT);\r
-       dma_out(bits == 8 ? dma_chan : dma16_chan, addr, size, DMA_SINGLE);\r
+       dma_out(cur_bits == 8 ? dma_chan : dma16_chan, addr, BUFSIZE, DMA_SINGLE | DMA_AUTO);\r
        sb_set_output_rate(rate);\r
-       start_dsp4(cur_bits, cur_mode, bits == 8 ? size : size / 2);\r
+       start_dsp4(cur_bits, cur_mode, num_samples / 2);\r
        isplaying = 1;\r
 }\r
 \r
 static void start_dsp4(int bits, unsigned int mode, int num_samples)\r
 {\r
        unsigned char cmd = bits == 8 ? DSP4_START_DMA8 : DSP4_START_DMA16;\r
-       assert(bits == 8 || bits == 16);\r
-\r
-       /*cmd |= DSP4_AUTO | DSP4_FIFO;*/\r
+       cmd |= DSP4_AUTO | DSP4_FIFO;\r
 \r
        /* program the DSP to start the DMA transfer */\r
        write_dsp(cmd);\r
@@ -280,10 +293,7 @@ void sb_stop(void)
        _dos_setvect(IRQ_TO_INTR(irq), prev_intr_handler);\r
        _enable();\r
 \r
-       /* no need to stop anything if we're in single-cycle mode */\r
-       if(cur_mode & DSP4_AUTO) {\r
-               write_dsp(cur_bits == 8 ? DSP_END_DMA8 : DSP_END_DMA16);\r
-       }\r
+       write_dsp(cur_bits == 8 ? DSP_END_DMA8 : DSP_END_DMA16);\r
        isplaying = 0;\r
 }\r
 \r
@@ -308,21 +318,20 @@ static void INTERRUPT intr_handler()
        /* ask for more data */\r
        if(!(size = audio_callback(bptr, BUFSIZE / 2))) {\r
                sb_stop();\r
-       } else {\r
-               if(cur_bits == 8) {\r
-                       dma_out(dma_chan, addr, size, DMA_SINGLE);\r
-                       start_dsp4(cur_bits, cur_mode, size);\r
-               } else {\r
-                       dma_out(dma16_chan, addr, size, DMA_SINGLE);\r
-                       start_dsp4(cur_bits, cur_mode, size / 2);\r
-               }\r
        }\r
 \r
        /* acknowledge the interrupt */\r
        if(cur_bits == 8) {\r
                inp(REG_INTACK);\r
        } else {\r
-               inp(REG_INT16ACK);\r
+               /*\r
+               unsigned char istat;\r
+               outp(REG_MIXPORT, 0x82);\r
+               istat = inp(REG_MIXDATA);\r
+               if(istat & 2) {\r
+               */\r
+                       inp(REG_INT16ACK);\r
+               //}\r
        }\r
 \r
        if(irq > 7) {\r