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
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
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
}\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
_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
/* 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
#include <stdio.h>\r
+#include <stdlib.h>\r
#include <string.h>\r
#include "aufile.h"\r
#include "audio.h"\r
\r
+#define DBG_PRELOAD\r
+\r
static int play_file(const char *fname);\r
+static int cbfunc(void *buf, int size, void *cls);\r
static void print_usage(const char *argv0);\r
\r
int main(int argc, char **argv)\r
{\r
int i;\r
\r
- play_file("namarie.wav"); /* TODO remove */\r
+ if(audio_init() == -1) {\r
+ return 1;\r
+ }\r
\r
for(i=1; i<argc; i++) {\r
if(argv[i][0] == '-') {\r
return 0;\r
}\r
\r
+static unsigned char *dbg_samples;\r
+static int dbg_cur_offs;\r
+\r
static int play_file(const char *fname)\r
{\r
struct au_file *au;\r
return -1;\r
}\r
\r
+ audio_set_callback(cbfunc, au);\r
+\r
+#ifdef DBG_PRELOAD\r
+ if(!(dbg_samples = malloc(au->size))) {\r
+ perror("failed to preload samples into memory");\r
+ return -1;\r
+ }\r
+ dbg_cur_offs = 0;\r
+ if(au_read(au, dbg_samples, au->size) < au->size) {\r
+ perror("failed to preload samples into memory");\r
+ return -1;\r
+ }\r
+#endif\r
+\r
audio_play(au->rate, au->bits, au->chan);\r
while(audio_isplaying());\r
\r
au_close(au);\r
+#ifdef DBG_PRELOAD\r
+ free(dbg_samples);\r
+#endif\r
return 0;\r
}\r
\r
+#ifdef DBG_PRELOAD\r
+static int cbfunc(void *buf, int size, void *cls)\r
+{\r
+ struct au_file *au = cls;\r
+\r
+ if(dbg_cur_offs + size > au->size) {\r
+ size = au->size - dbg_cur_offs;\r
+ }\r
+ if(size <= 0) return 0;\r
+\r
+ memcpy(buf, dbg_samples + dbg_cur_offs, size);\r
+ dbg_cur_offs += size;\r
+ return size;\r
+}\r
+#else\r
+static int cbfunc(void *buf, int size, void *cls)\r
+{\r
+ int rd;\r
+\r
+ if((rd = au_read(cls, buf, size)) <= 0) {\r
+ return 0;\r
+ }\r
+ return rd;\r
+}\r
+#endif\r
+\r
static void print_usage(const char *argv0)\r
{\r
printf("Usage: %s [options] <file1> <file2> ... <filen>\n", argv0);\r