--- /dev/null
+*.obj
+*.swp
+*.map
+*.lnk
+*.exe
--- /dev/null
+src = $(wildcard src/*.c)\r
+\r
+ifeq ($(findstring COMMAND.COM, $(SHELL)), COMMAND.COM)\r
+ hostsys = dos\r
+ obj = $(subst /,\,$(src:.c=.obj))\r
+ RM = del\r
+else\r
+ hostsys = unix\r
+ obj = $(src:.c=.obj)\r
+endif\r
+bin = auplay.exe\r
+\r
+opt = -5\r
+dbg = -d1\r
+def = -dLITTLEENDIAN\r
+\r
+incpath = -Isrc\r
+\r
+AS = nasm\r
+CC = wcc386\r
+ASFLAGS = -fobj\r
+CFLAGS = $(dbg) $(opt) $(def) -zq -bt=dos $(incpath)\r
+LDFLAGS = option map\r
+LD = wlink\r
+\r
+$(bin): $(obj)\r
+ $(file >objlist.lnk,$(obj))\r
+ $(LD) debug all name $@ system dos4g file { @objlist } $(LDFLAGS)\r
+\r
+%.obj: %.c\r
+ $(CC) -fo=$@ $(CFLAGS) $<\r
+\r
+%.obj: %.asm\r
+ $(AS) $(ASFLAGS) -o $@ $<\r
+\r
+clean:\r
+ $(RM) $(obj)\r
+ $(RM) *.obj\r
+ $(RM) src\*.obj\r
+ $(RM) $(bin)\r
+ $(RM) objlist.lnk\r
+ $(RM) auplay.map\r
--- /dev/null
+obj = main.obj audio.obj aufile.obj auwav.obj dma.obj au_sb.obj dpmi.obj
+bin = auplay.exe
+
+opt = -5
+dbg = -d1
+def = -dLITTLEENDIAN
+
+incpath = -Isrc
+
+!ifdef __UNIX__
+RM = rm -f
+!else
+RM = del
+!endif
+
+AS = nasm
+CC = wcc386
+ASFLAGS = -fobj
+CFLAGS = $(dbg) $(opt) $(def) -zq -bt=dos $(incpath)
+LDFLAGS = option map
+LD = wlink
+
+$(bin): $(obj)
+ %write objlist.lnk $(obj)
+ $(LD) debug all name $@ system dos4g file { @objlist } $(LDFLAGS)
+
+.c: src
+.asm: src
+
+.c.obj: .autodepend
+ $(CC) -fo=$@ $(CFLAGS) $[*
+
+.asm.obj:
+ $(AS) $(ASFLAGS) -o $@ $[*.asm
+
+clean: .symbolic
+ $(RM) *.obj
+ $(RM) *.lnk
+ $(RM) *.map
+ $(RM) $(bin)
--- /dev/null
+#include <stdio.h>\r
+#include <stdlib.h>\r
+#include <assert.h>\r
+#include <dos.h>\r
+#include <conio.h>\r
+#include "audio.h"\r
+#include "au_sb.h"\r
+#include "dpmi.h"\r
+#include "dma.h"\r
+#include "intr.h"\r
+\r
+#define REG_MIXPORT (base_port + 0x4)\r
+#define REG_MIXDATA (base_port + 0x5)\r
+#define REG_RESET (base_port + 0x6)\r
+#define REG_RDATA (base_port + 0xa)\r
+#define REG_WDATA (base_port + 0xc)\r
+#define REG_WSTAT (base_port + 0xc)\r
+#define REG_RSTAT (base_port + 0xe)\r
+#define REG_INTACK (base_port + 0xe)\r
+#define REG_INT16ACK (base_port + 0xf)\r
+\r
+#define WSTAT_BUSY 0x80\r
+#define RSTAT_RDY 0x80\r
+\r
+#define DSP_RATE 0x40\r
+#define DSP4_OUT_RATE 0x41\r
+#define DSP4_IN_RATE 0x42\r
+#define DSP_GET_VER 0xe1\r
+\r
+/* start DMA playback/recording. combine with fifo/auto/input flags */\r
+#define DSP4_START_DMA8 0xc0\r
+#define DSP4_START_DMA16 0xb0\r
+#define DSP4_FIFO 0x02\r
+#define DSP4_AUTO 0x04\r
+#define DSP4_INPUT 0x08\r
+\r
+/* transfer mode commands */\r
+#define DSP4_MODE_SIGNED 0x10\r
+#define DSP4_MODE_STEREO 0x20\r
+\r
+/* immediately pause/continue */\r
+#define DSP_PAUSE_DMA8 0xd0\r
+#define DSP_ENABLE_OUTPUT 0xd1\r
+#define DSP_DISABLE_OUTPUT 0xd3\r
+#define DSP_CONT_DMA8 0xd4\r
+#define DSP_PAUSE_DMA16 0xd5\r
+#define DSP_CONT_DMA16 0xd6\r
+\r
+/* end the playback at the end of the current buffer */\r
+#define DSP_END_DMA16 0xd9\r
+#define DSP_END_DMA8 0xda\r
+\r
+/* mixer registers */\r
+#define MIX_MASTER 0x02\r
+#define MIX_VOICE 0x0a\r
+#define MIX_SBPRO_VOICE 0x04\r
+#define MIX_SBPRO_MASTER 0x22\r
+#define MIX_SB16_MASTER_L 0x30\r
+#define MIX_SB16_MASTER_R 0x31\r
+#define MIX_SB16_VOICE_L 0x32\r
+#define MIX_SB16_VOICE_R 0x33\r
+#define MIX_SB16_IRQ_SEL 0x80\r
+#define MIX_SB16_DMA_SEL 0x81\r
+\r
+#define VER_MAJOR(x) ((x) >> 8)\r
+#define VER_MINOR(x) ((x) & 0xff)\r
+\r
+/* delay for about 1us */\r
+#define iodelay() outp(0x80, 0)\r
+\r
+static void INTERRUPT intr_handler();\r
+static void start_dsp4(int bits, unsigned int mode, int num_samples);\r
+static void start_dsp(int nchan, int num_samples);\r
+static void write_dsp(unsigned char val);\r
+static unsigned char read_dsp(void);\r
+static void write_mix(unsigned char val, int reg);\r
+static unsigned char read_mix(int reg);\r
+static int get_dsp_version(void);\r
+static int dsp4_detect_irq(void);\r
+static int dsp4_detect_dma(void);\r
+static void print_dsp_info(void);\r
+static const char *sbname(int ver);\r
+\r
+static int base_port;\r
+static int irq, dma_chan, dma16_chan, dsp_ver;\r
+static int dsp4;\r
+static void *buffer;\r
+static int xfer_mode;\r
+\r
+static int isplaying;\r
+static int cur_bits, cur_mode;\r
+static int curblk;\r
+\r
+static void (INTERRUPT *prev_intr_handler)();\r
+\r
+\r
+int sb_detect(void)\r
+{\r
+ int i;\r
+ char *env;\r
+\r
+ if((env = getenv("BLASTER"))) {\r
+ dma16_chan = -1;\r
+ if(sscanf(env, "A%x I%d D%d H%d", &base_port, &irq, &dma_chan, &dma16_chan) >= 3) {\r
+ if(sb_reset_dsp() == 0) {\r
+ dsp_ver = get_dsp_version();\r
+ dsp4 = VER_MAJOR(dsp_ver) >= 4 ? 1 : 0;\r
+ print_dsp_info();\r
+ return 1;\r
+ }\r
+ } else {\r
+ printf("sb_detect: malformed BLASTER environment variable. Fallback to probing.\n");\r
+ }\r
+ }\r
+\r
+ for(i=0; i<6; i++) {\r
+ base_port = 0x200 + ((i + 1) << 4);\r
+ if(sb_reset_dsp() == 0) {\r
+ dsp_ver = get_dsp_version();\r
+ dsp4 = VER_MAJOR(dsp_ver) >= 4 ? 1 : 0;\r
+\r
+ if(dsp4) {\r
+ if(dsp4_detect_irq() == -1) {\r
+ printf("sb_detect: failed to configure IRQ\n");\r
+ return 0;\r
+ }\r
+ if(dsp4_detect_dma() == -1) {\r
+ printf("sb_detect: failed to configure DMA\n");\r
+ return 0;\r
+ }\r
+\r
+ } else {\r
+ /* XXX for old sound blasters, hard-code to IRQ 5 DMA 1 for now */\r
+ irq = 5;\r
+ dma_chan = 1;\r
+ dma16_chan = -1;\r
+\r
+ printf("sb_detect: old sound blaster dsp. assuming: irq 5, dma 1\n");\r
+ }\r
+ print_dsp_info();\r
+\r
+ return 1;\r
+ }\r
+ }\r
+\r
+ return 0;\r
+}\r
+\r
+int sb_reset_dsp(void)\r
+{\r
+ int i;\r
+\r
+ outp(REG_RESET, 1);\r
+ for(i=0; i<3; i++) iodelay();\r
+ outp(REG_RESET, 0);\r
+\r
+ for(i=0; i<128; i++) {\r
+ if(inp(REG_RSTAT) & RSTAT_RDY) {\r
+ if(inp(REG_RDATA) == 0xaa) {\r
+ return 0;\r
+ }\r
+ }\r
+ }\r
+\r
+ return -1;\r
+}\r
+\r
+void sb_set_output_rate(int rate)\r
+{\r
+ if(dsp4) {\r
+ write_dsp(DSP4_OUT_RATE);\r
+ write_dsp(rate >> 8);\r
+ write_dsp(rate & 0xff);\r
+ } else {\r
+ int tcon = 256 - 1000000 / rate;\r
+ write_dsp(DSP_RATE);\r
+ write_dsp(tcon);\r
+ }\r
+}\r
+\r
+void *sb_buffer(int *size)\r
+{\r
+ *size = 32768;\r
+ return (char*)buffer + curblk * 32768;\r
+}\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
+\r
+ if(!buffer) {\r
+ /* allocate a 64k-aligned 64k buffer in low memory */\r
+ if(!(seg = dpmi_alloc(65536 * 2 / 16, &pmsel))) {\r
+ fprintf(stderr, "sb_start: failed to allocate DMA buffer\n");\r
+ return;\r
+ }\r
+\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
+ buffer = (void*)addr;\r
+ } else {\r
+ addr = (uint32_t)buffer;\r
+ }\r
+\r
+ if(!(size = audio_callback(buffer, 32768))) {\r
+ return;\r
+ }\r
+ curblk = 1;\r
+\r
+ _disable();\r
+ if(!prev_intr_handler) {\r
+ prev_intr_handler = _dos_getvect(IRQ_TO_INTR(irq));\r
+ }\r
+ printf("setting interrupt vector: %d\n", IRQ_TO_INTR(irq));\r
+ _dos_setvect(IRQ_TO_INTR(irq), intr_handler);\r
+ _enable();\r
+\r
+ unmask_irq(irq);\r
+\r
+ cur_bits = bits;\r
+ cur_mode = 0; /* TODO */\r
+ if(nchan > 1) {\r
+ cur_mode |= DSP4_MODE_STEREO;\r
+ }\r
+\r
+ write_dsp(DSP_ENABLE_OUTPUT);\r
+ dma_out(dma_chan, addr, size, DMA_SINGLE);\r
+ sb_set_output_rate(rate);\r
+ start_dsp4(cur_bits, cur_mode, size);\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
+\r
+ /* program the DSP to start the DMA transfer */\r
+ write_dsp(cmd);\r
+ write_dsp(mode);\r
+ num_samples--;\r
+ write_dsp(num_samples & 0xff);\r
+ write_dsp((num_samples >> 8) & 0xff);\r
+}\r
+\r
+static void start_dsp(int nchan, int num_samples)\r
+{\r
+ /* program the DSP to start the DMA transfer */\r
+ /* TODO */\r
+}\r
+\r
+void sb_pause(void)\r
+{\r
+ write_dsp(cur_bits == 8 ? DSP_PAUSE_DMA8 : DSP_PAUSE_DMA16);\r
+}\r
+\r
+void sb_continue(void)\r
+{\r
+ write_dsp(cur_bits == 8 ? DSP_CONT_DMA8 : DSP_CONT_DMA16);\r
+}\r
+\r
+void sb_stop(void)\r
+{\r
+ write_dsp(DSP_DISABLE_OUTPUT);\r
+\r
+ mask_irq(irq);\r
+ /* TODO: don't _enable, restore state */\r
+ _disable();\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
+ isplaying = 0;\r
+}\r
+\r
+int sb_isplaying(void)\r
+{\r
+ return isplaying;\r
+}\r
+\r
+void sb_volume(int vol)\r
+{\r
+ /* TODO */\r
+}\r
+\r
+static void INTERRUPT intr_handler()\r
+{\r
+ int size;\r
+ void *bptr = (unsigned char*)buffer + curblk * 32768;\r
+\r
+ curblk = (curblk + 1) & 1;\r
+\r
+ /* ask for more data */\r
+ if(!(size = audio_callback(bptr, 32768))) {\r
+ sb_stop();\r
+ } else {\r
+ dma_out(dma_chan, (uint32_t)bptr, size, DMA_SINGLE);\r
+ start_dsp4(cur_bits, cur_mode, size);\r
+ }\r
+\r
+ /* acknowledge the interrupt */\r
+ inp(REG_INTACK);\r
+\r
+ if(irq > 7) {\r
+ outp(PIC2_CMD, OCW2_EOI);\r
+ }\r
+ outp(PIC1_CMD, OCW2_EOI);\r
+}\r
+\r
+static void write_dsp(unsigned char val)\r
+{\r
+ while(inp(REG_WSTAT) & WSTAT_BUSY);\r
+ outp(REG_WDATA, val);\r
+}\r
+\r
+static unsigned char read_dsp(void)\r
+{\r
+ while((inp(REG_RSTAT) & RSTAT_RDY) == 0);\r
+ return inp(REG_RDATA);\r
+}\r
+\r
+static void write_mix(unsigned char val, int reg)\r
+{\r
+ outp(REG_MIXPORT, reg);\r
+ outp(REG_MIXDATA, val);\r
+}\r
+\r
+static unsigned char read_mix(int reg)\r
+{\r
+ outp(REG_MIXPORT, reg);\r
+ return inp(REG_MIXDATA);\r
+}\r
+\r
+static int get_dsp_version(void)\r
+{\r
+ int major, minor;\r
+\r
+ write_dsp(DSP_GET_VER);\r
+ major = read_dsp();\r
+ minor = read_dsp();\r
+\r
+ return (major << 8) | minor;\r
+}\r
+\r
+static int dsp4_detect_irq(void)\r
+{\r
+ int i, irqsel;\r
+ static int irqtab[] = {2, 5, 7, 10};\r
+\r
+ irq = 0;\r
+ irqsel = read_mix(MIX_SB16_IRQ_SEL);\r
+ for(i=0; i<4; i++) {\r
+ if(irqsel & (1 << i)) {\r
+ irq = irqtab[i];\r
+ break;\r
+ }\r
+ }\r
+ if(!irq) {\r
+ /* try to force IRQ 5 */\r
+ write_mix(2, MIX_SB16_IRQ_SEL); /* bit1 selects irq 5 */\r
+\r
+ /* re-read to verify */\r
+ irqsel = read_mix(MIX_SB16_IRQ_SEL);\r
+ if(irqsel != 2) {\r
+ return -1;\r
+ }\r
+ irq = 5;\r
+ }\r
+\r
+ return irq;\r
+}\r
+\r
+static int dsp4_detect_dma(void)\r
+{\r
+ int i, dmasel, tmp;\r
+ static int dmatab[] = {0, 1, -1, 3, -1, 5, 6, 7};\r
+\r
+ dma_chan = -1;\r
+ dma16_chan = -1;\r
+ dmasel = read_mix(MIX_SB16_DMA_SEL);\r
+ for(i=0; i<4; i++) {\r
+ if(dmasel & (1 << i)) {\r
+ dma_chan = dmatab[i];\r
+ break;\r
+ }\r
+ }\r
+ for(i=5; i<8; i++) {\r
+ if(dmasel & (1 << i)) {\r
+ dma16_chan = dmatab[i];\r
+ break;\r
+ }\r
+ }\r
+ if(dma_chan == -1) {\r
+ /* try to force DMA 1 */\r
+ dmasel |= 2;\r
+ }\r
+ if(dma16_chan == -1) {\r
+ /* try to force 16bit DMA 5 */\r
+ dmasel |= 0x20;\r
+ }\r
+\r
+ if(dma_chan == -1 || dma16_chan == -1) {\r
+ write_mix(dmasel, MIX_SB16_DMA_SEL);\r
+\r
+ /* re-read to verify */\r
+ tmp = read_mix(MIX_SB16_DMA_SEL);\r
+ if(tmp != dmasel) {\r
+ return -1;\r
+ }\r
+ dma_chan = 1;\r
+ dma16_chan = 5;\r
+ }\r
+\r
+ return dma_chan;\r
+}\r
+\r
+static void print_dsp_info(void)\r
+{\r
+ int master[2], voice[2];\r
+ int val;\r
+\r
+ printf("sb_detect: %s (DSP v%d.%02d) port %xh, irq %d", sbname(dsp_ver),\r
+ VER_MAJOR(dsp_ver), VER_MINOR(dsp_ver), base_port, irq);\r
+ if(VER_MAJOR(dsp_ver) >= 4) {\r
+ printf(" dma %d/%d\n", dma_chan, dma16_chan);\r
+ } else {\r
+ printf(" dma %d\n", dma_chan);\r
+ }\r
+\r
+ if(VER_MAJOR(dsp_ver) >= 4) {\r
+ master[0] = 100 * (int)(read_mix(MIX_SB16_MASTER_L) >> 3) / 31;\r
+ master[1] = 100 * (int)(read_mix(MIX_SB16_MASTER_R) >> 3) / 31;\r
+ voice[0] = 100 * (int)(read_mix(MIX_SB16_VOICE_L) >> 3) / 31;\r
+ voice[1] = 100 * (int)(read_mix(MIX_SB16_VOICE_R) >> 3) / 31;\r
+ } else if(VER_MAJOR(dsp_ver) >= 3) {\r
+ val = read_mix(MIX_SBPRO_MASTER);\r
+ master[0] = 100 * (val >> 5) / 7;\r
+ master[1] = 100 * ((val >> 1) & 7) / 7;\r
+ val = read_mix(MIX_SBPRO_VOICE);\r
+ voice[0] = 100 * (val >> 5) / 7;\r
+ voice[1] = 100 * ((val >> 1) & 7) / 7;\r
+ } else {\r
+ val = read_mix(MIX_MASTER);\r
+ master[0] = master[1] = 100 * ((val >> 1) & 7) / 7;\r
+ val = read_mix(MIX_VOICE);\r
+ voice[0] = voice[1] = 100 * ((val >> 1) & 3) / 3;\r
+ }\r
+ printf(" mixer: master(%d|%d) voice(%d|%d)\n", master[0], master[1],\r
+ voice[0], voice[1]);\r
+}\r
+\r
+#define V(maj, min) (((maj) << 8) | (min))\r
+\r
+static const char *sbname(int ver)\r
+{\r
+ int major = VER_MAJOR(ver);\r
+ int minor = VER_MINOR(ver);\r
+\r
+ switch(major) {\r
+ case 1:\r
+ if(minor == 5) {\r
+ return "Sound Blaster 1.5";\r
+ }\r
+ return "Sound Blaster 1.0";\r
+\r
+ case 2:\r
+ if(minor == 1 || minor == 2) {\r
+ return "Sound Blaster 2.0";\r
+ }\r
+ break;\r
+\r
+ case 3:\r
+ switch(minor) {\r
+ case 0:\r
+ return "Sound Blaster Pro";\r
+ case 1:\r
+ case 2:\r
+ return "Sound Blaster Pro 2";\r
+ case 5:\r
+ return "Gallant SC-6000";\r
+ default:\r
+ break;\r
+ }\r
+ break;\r
+\r
+ case 4:\r
+ switch(minor) {\r
+ case 4:\r
+ case 5:\r
+ return "Sound Blaster 16";\r
+ case 11:\r
+ return "Sound Blaster 16 SCSI-2";\r
+ case 12:\r
+ return "Sound Blaster AWE 32";\r
+ case 13:\r
+ return "Sound Blaster ViBRA16C";\r
+ case 16:\r
+ return "Sound Blaster AWE 64";\r
+ default:\r
+ break;\r
+ }\r
+ break;\r
+ }\r
+\r
+ return "Unknown Sound Blaster";\r
+}\r
--- /dev/null
+#ifndef AU_SB_H_\r
+#define AU_SB_H_\r
+\r
+/* returns true (nonzero) if a sound blaster DSP is detected in the ISA bus\r
+ * and sets the internal base_port so that subsequent calls can find it\r
+ */\r
+int sb_detect(void);\r
+\r
+/* returns 0 for success, non-zero if the DSP isn't responding at the currently\r
+ * selected base port\r
+ */\r
+int sb_reset_dsp(void);\r
+\r
+void *sb_buffer(int *size);\r
+\r
+void sb_set_output_rate(int rate);\r
+\r
+void sb_start(int rate, int bits, int nchan);\r
+void sb_pause(void);\r
+void sb_continue(void);\r
+void sb_stop(void);\r
+int sb_isplaying(void);\r
+\r
+void sb_volume(int vol);\r
+\r
+#endif /* AU_SB_H_ */\r
--- /dev/null
+#include <stdio.h>\r
+#include "audio.h"\r
+#include "au_sb.h"\r
+\r
+struct audrv {\r
+ void *(*get_buffer)(int *size);\r
+ void (*start)(int rate, int bits, int nchan);\r
+ void (*pause)(void);\r
+ void (*cont)(void);\r
+ void (*stop)(void);\r
+ void (*volume)(int vol);\r
+ int (*isplaying)(void);\r
+};\r
+\r
+static struct audrv drv;\r
+\r
+static audio_callback_func cbfunc;\r
+static void *cbcls;\r
+\r
+void audio_init(void)\r
+{\r
+ if(sb_detect()) {\r
+ drv.get_buffer = sb_buffer;\r
+ drv.start = sb_start;\r
+ drv.pause = sb_pause;\r
+ drv.cont = sb_continue;\r
+ drv.stop = sb_stop;\r
+ drv.volume = sb_volume;\r
+ drv.isplaying = sb_isplaying;\r
+ return;\r
+ }\r
+\r
+ printf("No supported audio device detected\n");\r
+}\r
+\r
+void audio_set_callback(audio_callback_func func, void *cls)\r
+{\r
+ cbfunc = func;\r
+ cbcls = cls;\r
+}\r
+\r
+int audio_callback(void *buf, int sz)\r
+{\r
+ if(!cbfunc) {\r
+ return 0;\r
+ }\r
+ return cbfunc(buf, sz, cbcls);\r
+}\r
+\r
+void audio_play(int rate, int bits, int nchan)\r
+{\r
+ drv.start(rate, bits, nchan);\r
+}\r
+\r
+void audio_pause(void)\r
+{\r
+ drv.pause();\r
+}\r
+\r
+void audio_resume(void)\r
+{\r
+ drv.cont();\r
+}\r
+\r
+void audio_stop(void)\r
+{\r
+ drv.stop();\r
+}\r
+\r
+void audio_volume(int vol)\r
+{\r
+ drv.volume(vol);\r
+}\r
+\r
+int audio_isplaying(void)\r
+{\r
+ return drv.isplaying();\r
+}\r
--- /dev/null
+#ifndef AUDIO_H_\r
+#define AUDIO_H_\r
+\r
+typedef int (*audio_callback_func)(void *buffer, int size, void *cls);\r
+\r
+void audio_init(void);\r
+\r
+void audio_set_callback(audio_callback_func func, void *cls);\r
+int audio_callback(void *buf, int sz);\r
+\r
+void audio_play(int rate, int bits, int nchan);\r
+void audio_pause(void);\r
+void audio_resume(void);\r
+void audio_stop(void);\r
+int audio_isplaying(void);\r
+\r
+void audio_volume(int vol);\r
+\r
+#endif /* AUDIO_H_ */\r
--- /dev/null
+#include <stdio.h>\r
+#include <stdlib.h>\r
+#include <string.h>\r
+#include <errno.h>\r
+#include "aufile.h"\r
+\r
+int au_open_wav(struct au_file *au);\r
+\r
+struct au_file *au_open(const char *fname)\r
+{\r
+ FILE *fp;\r
+ struct au_file *au;\r
+\r
+ if(!(fp = fopen(fname, "rb"))) {\r
+ fprintf(stderr, "au_open: failed to open file: %s: %s\n", fname, strerror(errno));\r
+ return 0;\r
+ }\r
+\r
+ if(!(au = malloc(sizeof *au))) {\r
+ fclose(fp);\r
+ fprintf(stderr, "au_open: failed to allocate file structure: %s\n", strerror(errno));\r
+ return 0;\r
+ }\r
+ au->fp = fp;\r
+\r
+ if(au_open_wav(au) != -1) {\r
+ return au;\r
+ }\r
+\r
+ fprintf(stderr, "au_open: invalid file: %s\n", fname);\r
+ fclose(fp);\r
+ free(au);\r
+ return 0;\r
+}\r
+\r
+void au_close(struct au_file *au)\r
+{\r
+ au->close(au);\r
+ fclose(au->fp);\r
+ free(au);\r
+}\r
+\r
+void au_reset(struct au_file *au)\r
+{\r
+ au->reset(au);\r
+}\r
+\r
+int au_read(struct au_file *au, void *buf, int size)\r
+{\r
+ return au->read(au, buf, size);\r
+}\r
--- /dev/null
+#ifndef AUFILE_H_\r
+#define AUFILE_H_\r
+\r
+struct au_file {\r
+ int rate, bits, chan;\r
+ void *data;\r
+\r
+ FILE *fp;\r
+ void (*close)(struct au_file*);\r
+ void (*reset)(struct au_file*);\r
+ int (*read)(struct au_file*, void*, int);\r
+};\r
+\r
+struct au_file *au_open(const char *fname);\r
+void au_close(struct au_file *au);\r
+\r
+void au_reset(struct au_file *au);\r
+int au_read(struct au_file *au, void *buf, int size);\r
+\r
+#endif /* AUFILE_H_ */\r
--- /dev/null
+#include <stdio.h>\r
+#include <stdlib.h>\r
+#include "aufile.h"\r
+#include "inttypes.h"\r
+\r
+struct format {\r
+ uint16_t fmt;\r
+ uint16_t nchan;\r
+ uint32_t rate;\r
+ uint16_t avgbaud;\r
+ uint16_t block_align;\r
+ uint16_t sample_bytes;\r
+};\r
+\r
+struct playback_data {\r
+ uint32_t start, size;\r
+ uint32_t bytes_left;\r
+};\r
+\r
+#define FOURCC(a, b, c, d) \\r
+ ((uint32_t)(a) | ((uint32_t)(b) << 8) | ((uint32_t)(c) << 16) | ((uint32_t)(d) << 24))\r
+\r
+enum {\r
+ ID_RIFF = FOURCC('R', 'I', 'F', 'F'),\r
+ ID_WAVE = FOURCC('W', 'A', 'V', 'E'),\r
+ ID_FMT = FOURCC('f', 'm', 't', ' '),\r
+ ID_DATA = FOURCC('d', 'a', 't', 'a')\r
+};\r
+\r
+static void close_wav(struct au_file *au);\r
+static void reset_wav(struct au_file *au);\r
+static int read_wav(struct au_file *au, void *buf, int size);\r
+static int read_uint32(uint32_t *res, FILE *fp);\r
+static int read_format(struct format *fmt, int fmtsize, FILE *fp);\r
+\r
+\r
+int au_open_wav(struct au_file *au)\r
+{\r
+ uint32_t id, len;\r
+ struct format fmt;\r
+ struct playback_data *pb;\r
+\r
+ if(read_uint32(&id, au->fp) == -1 || id != ID_RIFF)\r
+ return -1;\r
+ fseek(au->fp, 4, SEEK_CUR);\r
+ if(read_uint32(&id, au->fp) == -1 || id != ID_WAVE)\r
+ return -1;\r
+ if(read_uint32(&id, au->fp) == -1 || id != ID_FMT)\r
+ return -1;\r
+ if(read_uint32(&len, au->fp) == -1)\r
+ return -1;\r
+ if(read_format(&fmt, len, au->fp) == -1)\r
+ return -1;\r
+ if(read_uint32(&id, au->fp) == -1 || id != ID_DATA)\r
+ return -1;\r
+ if(read_uint32(&len, au->fp) == -1)\r
+ return -1;\r
+\r
+ if(!(pb = malloc(sizeof *pb))) {\r
+ fprintf(stderr, "failed to allocate wav playback data block\n");\r
+ return -1;\r
+ }\r
+ pb->start = ftell(au->fp);\r
+ pb->size = pb->bytes_left = len;\r
+\r
+ au->rate = fmt.rate;\r
+ au->bits = fmt.sample_bytes * 8;\r
+ au->chan = fmt.nchan;\r
+ au->data = pb;\r
+\r
+ au->close = close_wav;\r
+ au->reset = reset_wav;\r
+ au->read = read_wav;\r
+ return 0;\r
+}\r
+\r
+static void close_wav(struct au_file *au)\r
+{\r
+ free(au->data);\r
+}\r
+\r
+static void reset_wav(struct au_file *au)\r
+{\r
+ struct playback_data *pb = au->data;\r
+ pb->bytes_left = pb->size;\r
+ fseek(au->fp, pb->start, SEEK_SET);\r
+}\r
+\r
+static int read_wav(struct au_file *au, void *buf, int size)\r
+{\r
+ struct playback_data *pb = au->data;\r
+ size_t rd;\r
+\r
+ if(size > pb->bytes_left) {\r
+ size = pb->bytes_left;\r
+ }\r
+ if(size <= 0) {\r
+ return 0;\r
+ }\r
+ if((rd = fread(buf, 1, size, au->fp)) == -1) {\r
+ pb->bytes_left = 0;\r
+ return -1;\r
+ }\r
+ pb->bytes_left -= rd;\r
+ return rd;\r
+}\r
+\r
+#ifdef BIGENDIAN\r
+static void swap_uint32(uint32_t *val)\r
+{\r
+ uint32_t x = *val;\r
+ *val = (x << 24) | ((x & 0xff00) << 8) | ((x & 0xff0000) >> 8) | (x >> 24);\r
+}\r
+\r
+static void swap_uint16(uint16_t *val)\r
+{\r
+ uint16_t x = *val;\r
+ *val = (x << 8) | (x >> 8);\r
+}\r
+#endif\r
+\r
+static int read_uint32(uint32_t *res, FILE *fp)\r
+{\r
+ if(fread(res, 4, 1, fp) < 1) {\r
+ return -1;\r
+ }\r
+#ifdef BIGENDIAN\r
+ swap_uint32(res);\r
+#endif\r
+ return 0;\r
+}\r
+\r
+static int read_format(struct format *fmt, int fmtsize, FILE *fp)\r
+{\r
+ if(fread(fmt, 1, fmtsize, fp) < fmtsize) {\r
+ return -1;\r
+ }\r
+#ifdef BIGENDIAN\r
+ swap_uint16(&fmt->fmt);\r
+ swap_uint16(&fmt->nchan);\r
+ swap_uint32(&fmt->rate);\r
+ swap_uint16(&fmt->avgbaud);\r
+ swap_uint16(&fmt->block_align);\r
+#endif\r
+ return 0;\r
+}\r
--- /dev/null
+#include <conio.h>\r
+#include "dma.h"\r
+\r
+/* 8bit DMA ports */\r
+#define DMA_0_ADDR 0x00\r
+#define DMA_0_COUNT 0x01\r
+#define DMA_1_ADDR 0x02\r
+#define DMA_1_COUNT 0x03\r
+#define DMA_2_ADDR 0x04\r
+#define DMA_2_COUNT 0x05\r
+#define DMA_3_ADDR 0x06\r
+#define DMA_3_COUNT 0x07\r
+/* 16bit DMA ports */\r
+#define DMA_4_ADDR 0xc0\r
+#define DMA_4_COUNT 0xc2\r
+#define DMA_5_ADDR 0xc4\r
+#define DMA_5_COUNT 0xc6\r
+#define DMA_6_ADDR 0xc8\r
+#define DMA_6_COUNT 0xca\r
+#define DMA_7_ADDR 0xcc\r
+#define DMA_7_COUNT 0xce\r
+\r
+#define DMA_ADDR(c) \\r
+ ((c < 4) ? DMA_0_ADDR + ((c) << 1) : (DMA_4_ADDR + ((c) << 2)))\r
+#define DMA_COUNT(c) \\r
+ ((c < 4) ? DMA_0_COUNT + ((c) << 1) : (DMA_4_COUNT + ((c) << 2)))\r
+\r
+#define DMA8_MASK 0x0a\r
+#define DMA8_MODE 0x0b\r
+#define DMA8_CLR_FLIPFLOP 0x0c\r
+#define DMA8_RESET 0x0d\r
+#define DMA8_MASK_RST 0x0e\r
+#define DMA8_RMASK 0x0f\r
+#define DMA16_MASK 0xd4\r
+#define DMA16_MODE 0xd6\r
+#define DMA16_CLR_FLIPFLOP 0xd8\r
+#define DMA16_RESET 0xda\r
+#define DMA16_MASK_RST 0xdc\r
+#define DMA16_RMASK 0xde\r
+\r
+#define DMA_MASK(c) ((c) < 4 ? DMA8_MASK : DMA16_MASK)\r
+#define DMA_MODE(c) ((c) < 4 ? DMA8_MODE : DMA16_MODE)\r
+#define DMA_CLR_FLIPFLOP(c) ((c) < 4 ? DMA8_CLR_FLIPFLOP : DMA16_CLR_FLIPFLOP)\r
+#define DMA_RESET(c) ((c) < 4 ? DMA8_RESET : DMA16_RESET)\r
+#define DMA_MASK_RST(c) ((c) < 4 ? DMA8_MASK_RST : DMA16_MASK_RST)\r
+#define DMA_RMASK(c) ((c) < 4 ? DMA8_RMASK : DMA16_RMASK)\r
+\r
+#define DMA_0_PAGE 0x87\r
+#define DMA_1_PAGE 0x83\r
+#define DMA_2_PAGE 0x81\r
+#define DMA_3_PAGE 0x82\r
+#define DMA_4_PAGE 0x8f\r
+#define DMA_5_PAGE 0x8b\r
+#define DMA_6_PAGE 0x89\r
+#define DMA_7_PAGE 0x8a\r
+\r
+#define MODE_CHAN(x) ((x) & 3)\r
+#define MODE_WRITE 0x04\r
+#define MODE_READ 0x08\r
+#define MODE_AUTO 0x10\r
+#define MODE_DECR 0x20\r
+#define MODE_SINGLE 0x40\r
+#define MODE_BLOCK 0x80\r
+#define MODE_CASCADE 0xc0\r
+\r
+#define MASK_CHAN(x) ((x) & 3)\r
+#define MASK_DISABLE 0x04\r
+\r
+#define RMASK_CHAN(x) (1 << ((x) & 3))\r
+\r
+#define IS_16BIT(c) ((c) >= 4)\r
+\r
+static void dma_io(int chan, uint32_t phyaddr, int size, unsigned int flags, unsigned int dir);\r
+static __inline void mask(int chan);\r
+static __inline void unmask(int chan);\r
+\r
+static int page_port[] = {\r
+ DMA_0_PAGE, DMA_1_PAGE, DMA_2_PAGE, DMA_3_PAGE,\r
+ DMA_4_PAGE, DMA_5_PAGE, DMA_6_PAGE, DMA_7_PAGE\r
+};\r
+\r
+void dma_out(int chan, uint32_t phyaddr, int size, unsigned int flags)\r
+{\r
+ dma_io(chan, phyaddr, size, flags, MODE_READ);\r
+}\r
+\r
+void dma_in(int chan, uint32_t phyaddr, int size, unsigned int flags)\r
+{\r
+ dma_io(chan, phyaddr, size, flags, MODE_WRITE);\r
+}\r
+\r
+static void dma_io(int chan, uint32_t phyaddr, int size, unsigned int flags, unsigned int dir)\r
+{\r
+ unsigned int mode;\r
+ int addr_port, count_port;\r
+\r
+ addr_port = DMA_ADDR(chan);\r
+ count_port = DMA_COUNT(chan);\r
+\r
+ mask(chan);\r
+ outp(DMA_CLR_FLIPFLOP(chan), 0);\r
+\r
+ /* first 2 bits of flags correspond to the mode bits 6,7 */\r
+ mode = ((flags & 3) << 6) | dir | MODE_CHAN(chan);\r
+ if(flags & DMA_DECR) mode |= MODE_DECR;\r
+ if(flags & DMA_AUTO) mode |= MODE_AUTO;\r
+ outp(DMA_MODE(chan), mode);\r
+\r
+ if(IS_16BIT(chan)) {\r
+ phyaddr >>= 1;\r
+ size >>= 1;\r
+ }\r
+\r
+ outp(addr_port, phyaddr & 0xff);\r
+ outp(addr_port, (phyaddr >> 8) & 0xff);\r
+ outp(page_port[chan], (phyaddr >> 16) & 0xff);\r
+\r
+ size--;\r
+ outp(count_port, size & 0xff);\r
+ outp(count_port, (size >> 8) & 0xff);\r
+\r
+ unmask(chan);\r
+}\r
+\r
+static __inline void mask(int chan)\r
+{\r
+ outp(DMA_MASK(chan), MASK_CHAN(chan) | MASK_DISABLE);\r
+}\r
+\r
+static __inline void unmask(int chan)\r
+{\r
+ outp(DMA_MASK(chan), MASK_CHAN(chan));\r
+}\r
--- /dev/null
+#ifndef DMA_H_\r
+#define DMA_H_\r
+\r
+#include <inttypes.h>\r
+\r
+enum {\r
+ DMA_SINGLE = 0x01,\r
+ DMA_BLOCK = 0x02,\r
+ DMA_CASCADE = DMA_SINGLE | DMA_BLOCK,\r
+ DMA_DECR = 0x08,\r
+ DMA_AUTO = 0x10\r
+};\r
+\r
+void dma_out(int chan, uint32_t phyaddr, int size, unsigned int flags);\r
+void dma_in(int chan, uint32_t phyaddr, int size, unsigned int flags);\r
+\r
+#endif /* DMA_H_ */\r
--- /dev/null
+#include "dpmi.h"
+
+void dpmi_real_int(int inum, struct dpmi_real_regs *regs)
+{
+ unsigned char int_num = (unsigned char)inum;
+ __asm {
+ mov eax, 0x300
+ mov edi, regs
+ mov bl, int_num
+ mov bh, 0
+ xor ecx, ecx
+ int 0x31
+ }
+}
+
+void *dpmi_mmap(uint32_t phys_addr, unsigned int size)
+{
+ uint16_t mem_high, mem_low;
+ uint16_t phys_high = phys_addr >> 16;
+ uint16_t phys_low = phys_addr & 0xffff;
+ uint16_t size_high = size >> 16;
+ uint16_t size_low = size & 0xffff;
+ unsigned int err, res = 0;
+
+ __asm {
+ mov eax, 0x800
+ mov bx, phys_high
+ mov cx, phys_low
+ mov si, size_high
+ mov di, size_low
+ int 0x31
+ add res, 1
+ mov err, eax
+ mov mem_high, bx
+ mov mem_low, cx
+ }
+
+ if(res == 2) {
+ return 0;
+ }
+ return (void*)(((uint32_t)mem_high << 16) | ((uint32_t)mem_low));
+}
+
+void dpmi_munmap(void *addr)
+{
+ uint16_t mem_high = (uint32_t)addr >> 16;
+ uint16_t mem_low = (uint16_t)addr;
+
+ __asm {
+ mov eax, 0x801
+ mov bx, mem_high
+ mov cx, mem_low
+ int 0x31
+ }
+}
--- /dev/null
+#ifndef DPMI_H_
+#define DPMI_H_
+
+#include "inttypes.h"
+
+struct dpmi_real_regs {
+ uint32_t edi, esi, ebp;
+ uint32_t reserved;
+ uint32_t ebx, edx, ecx, eax;
+ uint16_t flags;
+ uint16_t es, ds, fs, gs;
+ uint16_t ip, cs, sp, ss;
+};
+
+uint16_t dpmi_alloc(unsigned int par, uint16_t *sel);
+void dpmi_free(uint16_t sel);
+
+#pragma aux dpmi_alloc = \
+ "mov eax, 0x100" \
+ "int 0x31" \
+ "mov [edi], dx" \
+ value[ax] parm[ebx][edi];
+
+#pragma aux dpmi_free = \
+ "mov eax, 0x101" \
+ "int 0x31" \
+ parm[dx];
+
+void dpmi_real_int(int inum, struct dpmi_real_regs *regs);
+
+void *dpmi_mmap(uint32_t phys_addr, unsigned int size);
+void dpmi_munmap(void *addr);
+
+#endif /* DPMI_H_ */
--- /dev/null
+#ifndef INTR_H_\r
+#define INTR_H_\r
+\r
+#define INTERRUPT __interrupt __far\r
+\r
+#define IRQ_TO_INTR(x) ((x) + 8)\r
+\r
+/* PIC command and data ports */\r
+#define PIC1_CMD 0x20\r
+#define PIC1_DATA 0x21\r
+#define PIC2_CMD 0xa0\r
+#define PIC2_DATA 0xa1\r
+/* PIC operation command word 2 bits */\r
+#define OCW2_EOI (1 << 5)\r
+\r
+unsigned char get_irq_mask(int pic);\r
+#pragma aux get_irq_mask = \\r
+ "cmp bx, 0" \\r
+ "jnz getpic2" \\r
+ "in al, 0x21" \\r
+ "jmp getend" \\r
+ "getpic2:" \\r
+ "in al, 0xa1" \\r
+ "getend:" \\r
+ value[al] parm[ebx];\r
+\r
+void mask_irq(int irq);\r
+#pragma aux mask_irq = \\r
+ "mov dx, 0x21" \\r
+ "cmp ax, 8" \\r
+ "jb skip_mask_pic2" \\r
+ "mov dx, 0xa1" \\r
+ "sub ax, 8" \\r
+ "skip_mask_pic2:" \\r
+ "mov cl, al" \\r
+ "mov ah, 1" \\r
+ "shl ah, cl" \\r
+ "in al, dx" \\r
+ "or al, ah" \\r
+ "out dx, al" \\r
+ parm[eax] modify[cl dx];\r
+\r
+void unmask_irq(int irq);\r
+#pragma aux unmask_irq = \\r
+ "mov dx, 0x21" \\r
+ "cmp ax, 8" \\r
+ "jb skip_unmask_pic2" \\r
+ "mov dx, 0xa1" \\r
+ "sub ax, 8" \\r
+ "skip_unmask_pic2:" \\r
+ "mov cl, al" \\r
+ "mov ah, 1" \\r
+ "shl ah, cl" \\r
+ "not ah" \\r
+ "in al, dx" \\r
+ "and al, ah" \\r
+ "out dx, al" \\r
+ parm[eax] modify[cl dx];\r
+\r
+#endif /* INTR_H_ */\r
--- /dev/null
+#ifndef INT_TYPES_H_
+#define INT_TYPES_H_
+
+#if defined(__DOS__) || defined(WIN32)
+typedef char int8_t;
+typedef short int16_t;
+typedef long int32_t;
+
+typedef unsigned char uint8_t;
+typedef unsigned short uint16_t;
+typedef unsigned long uint32_t;
+
+typedef unsigned long intptr_t;
+#else
+#include <stdint.h>
+#endif
+
+#endif /* INT_TYPES_H_ */
--- /dev/null
+#include <stdio.h>\r
+#include <string.h>\r
+#include "aufile.h"\r
+\r
+static int play_file(const char *fname);\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
+\r
+ for(i=1; i<argc; i++) {\r
+ if(argv[i][0] == '-') {\r
+ if(strcmp(argv[i], "-h") == 0 || strcmp(argv[i], "-help") == 0) {\r
+ print_usage(argv[0]);\r
+ return 0;\r
+ } else {\r
+ fprintf(stderr, "invalid option: %s\n", argv[i]);\r
+ return 1;\r
+ }\r
+ } else {\r
+ play_file(argv[i]);\r
+ }\r
+ }\r
+ return 0;\r
+}\r
+\r
+static int play_file(const char *fname)\r
+{\r
+ struct au_file *au;\r
+\r
+ if(!(au = au_open(fname))) {\r
+ return -1;\r
+ }\r
+ /* TODO: cont */\r
+ au_close(au);\r
+ return 0;\r
+}\r
+\r
+static void print_usage(const char *argv0)\r
+{\r
+ printf("Usage: %s [options] <file1> <file2> ... <filen>\n", argv0);\r
+ printf("options:\n");\r
+ printf(" -h,-help: print usage and exit\n");\r
+}\r