implemented volume control, and restructured slightly
authorJohn Tsiombikas <nuclear@member.fsf.org>
Sat, 2 Feb 2019 03:37:55 +0000 (05:37 +0200)
committerJohn Tsiombikas <nuclear@member.fsf.org>
Sat, 2 Feb 2019 03:37:55 +0000 (05:37 +0200)
src/au_sb.c
src/au_sb.h [deleted file]
src/audio.c
src/audio.h
src/audrv.h [new file with mode: 0644]
src/main.c

index 0daa7c0..06f862a 100644 (file)
@@ -4,7 +4,7 @@
 #include <dos.h>\r
 #include <conio.h>\r
 #include "audio.h"\r
-#include "au_sb.h"\r
+#include "audrv.h"\r
 #include "dpmi.h"\r
 #include "dma.h"\r
 #include "intr.h"\r
 /* delay for about 1us */\r
 #define iodelay()      outp(0x80, 0)\r
 \r
+\r
+static int reset_dsp(void);\r
+static void *sb_buffer(int *size);\r
+static void set_output_rate(int rate);\r
+static void start(int rate, int bits, int nchan);\r
+static void pause(void);\r
+static void cont(void);\r
+static void stop(void);\r
+static int isplaying(void);\r
+static void setvolume(int ctl, int vol);\r
+static int getvolume(int ctl);\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
@@ -83,6 +95,18 @@ static int dsp4_detect_dma(void);
 static void print_dsp_info(void);\r
 static const char *sbname(int ver);\r
 \r
+\r
+static const struct audrv sbdrv = {\r
+       start,\r
+       pause,\r
+       cont,\r
+       stop,\r
+       setvolume,\r
+       getvolume,\r
+       isplaying\r
+};\r
+\r
+\r
 static int base_port;\r
 static int irq, dma_chan, dma16_chan, dsp_ver;\r
 static int dsp4;\r
@@ -90,13 +114,13 @@ static int dsp4;
 static void *buffer[2];\r
 static volatile int wrbuf;\r
 \r
-static volatile int isplaying;\r
+static volatile int playing;\r
 static int cur_bits, cur_mode, auto_init;\r
 \r
 static void (INTERRUPT *prev_intr_handler)();\r
 \r
 \r
-int sb_detect(void)\r
+int sb_detect(struct audrv *drv)\r
 {\r
        int i;\r
        char *env;\r
@@ -104,10 +128,11 @@ int sb_detect(void)
        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
+                       if(reset_dsp() == 0) {\r
                                dsp_ver = get_dsp_version();\r
                                dsp4 = VER_MAJOR(dsp_ver) >= 4 ? 1 : 0;\r
                                print_dsp_info();\r
+                               *drv = sbdrv;\r
                                return 1;\r
                        }\r
                } else {\r
@@ -117,7 +142,7 @@ int sb_detect(void)
 \r
        for(i=0; i<6; i++) {\r
                base_port = 0x200 + ((i + 1) << 4);\r
-               if(sb_reset_dsp() == 0) {\r
+               if(reset_dsp() == 0) {\r
                        dsp_ver = get_dsp_version();\r
                        dsp4 = VER_MAJOR(dsp_ver) >= 4 ? 1 : 0;\r
 \r
@@ -140,6 +165,7 @@ int sb_detect(void)
                                printf("sb_detect: old sound blaster dsp. assuming: irq 5, dma 1\n");\r
                        }\r
                        print_dsp_info();\r
+                       *drv = sbdrv;\r
 \r
                        return 1;\r
                }\r
@@ -148,7 +174,7 @@ int sb_detect(void)
        return 0;\r
 }\r
 \r
-int sb_reset_dsp(void)\r
+static int reset_dsp(void)\r
 {\r
        int i;\r
 \r
@@ -167,7 +193,7 @@ int sb_reset_dsp(void)
        return -1;\r
 }\r
 \r
-void sb_set_output_rate(int rate)\r
+static void set_output_rate(int rate)\r
 {\r
        if(dsp4) {\r
                write_dsp(DSP4_OUT_RATE);\r
@@ -180,13 +206,7 @@ void sb_set_output_rate(int rate)
        }\r
 }\r
 \r
-void *sb_buffer(int *size)\r
-{\r
-       *size = BUFSIZE / 2;\r
-       return buffer[wrbuf];\r
-}\r
-\r
-void sb_start(int rate, int bits, int nchan)\r
+static void start(int rate, int bits, int nchan)\r
 {\r
        uint16_t seg, pmsel;\r
        uint32_t addr, next64k;\r
@@ -195,7 +215,7 @@ void sb_start(int rate, int bits, int nchan)
        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
+                       fprintf(stderr, "SB start: failed to allocate DMA buffer\n");\r
                        return;\r
                }\r
 \r
@@ -235,7 +255,6 @@ void sb_start(int rate, int bits, int nchan)
        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
@@ -249,9 +268,9 @@ void sb_start(int rate, int bits, int nchan)
 \r
        write_dsp(DSP_ENABLE_OUTPUT);\r
        dma_out(cur_bits == 8 ? dma_chan : dma16_chan, addr, BUFSIZE, DMA_SINGLE | DMA_AUTO);\r
-       sb_set_output_rate(rate);\r
+       set_output_rate(rate);\r
        start_dsp4(cur_bits, cur_mode, num_samples / 2);\r
-       isplaying = 1;\r
+       playing = 1;\r
 }\r
 \r
 static void start_dsp4(int bits, unsigned int mode, int num_samples)\r
@@ -273,17 +292,17 @@ static void start_dsp(int nchan, int num_samples)
        /* TODO */\r
 }\r
 \r
-void sb_pause(void)\r
+static void pause(void)\r
 {\r
        write_dsp(cur_bits == 8 ? DSP_PAUSE_DMA8 : DSP_PAUSE_DMA16);\r
 }\r
 \r
-void sb_continue(void)\r
+static void cont(void)\r
 {\r
        write_dsp(cur_bits == 8 ? DSP_CONT_DMA8 : DSP_CONT_DMA16);\r
 }\r
 \r
-void sb_stop(void)\r
+static void stop(void)\r
 {\r
        write_dsp(DSP_DISABLE_OUTPUT);\r
 \r
@@ -294,17 +313,99 @@ void sb_stop(void)
        _enable();\r
 \r
        write_dsp(cur_bits == 8 ? DSP_END_DMA8 : DSP_END_DMA16);\r
-       isplaying = 0;\r
+       playing = 0;\r
 }\r
 \r
-int sb_isplaying(void)\r
+static int isplaying(void)\r
 {\r
-       return isplaying;\r
+       return playing;\r
 }\r
 \r
-void sb_volume(int vol)\r
+static void setvolume(int ctl, int vol)\r
 {\r
-       /* TODO */\r
+       unsigned char val;\r
+\r
+       if(VER_MAJOR(dsp_ver) >= 4) {\r
+               /* DSP 4.x - SB16 */\r
+               val = vol & 0xf8;\r
+               if(ctl == AUDIO_PCM) {\r
+                       write_mix(MIX_SB16_VOICE_L, vol);\r
+                       write_mix(MIX_SB16_VOICE_R, vol);\r
+               } else {\r
+                       write_mix(MIX_SB16_MASTER_L, vol);\r
+                       write_mix(MIX_SB16_MASTER_R, vol);\r
+               }\r
+\r
+       } else if(VER_MAJOR(dsp_ver) >= 3) {\r
+               /* DSP 3.x - SBPro */\r
+               val = vol & 0xe0;\r
+               val |= val >> 4;\r
+\r
+               if(ctl == AUDIO_PCM) {\r
+                       write_mix(MIX_SBPRO_VOICE, val);\r
+               } else {\r
+                       write_mix(MIX_SBPRO_MASTER, val);\r
+               }\r
+\r
+       } else {\r
+               /* DSP 2.x - SB 2.0 */\r
+               if(ctl == AUDIO_PCM) {\r
+                       val = (vol >> 5) & 6;\r
+                       write_mix(MIX_VOICE, val);\r
+               } else {\r
+                       val = (vol >> 4) & 0xe;\r
+                       write_mix(MIX_MASTER, val);\r
+               }\r
+       }\r
+}\r
+\r
+static int getvolume(int ctl)\r
+{\r
+       int left, right;\r
+       unsigned char val;\r
+\r
+       if(VER_MAJOR(dsp_ver) >= 4) {\r
+               /* DSP 4.x - SB16 */\r
+               int lreg, rreg;\r
+               if(ctl == AUDIO_PCM) {\r
+                       lreg = MIX_SB16_VOICE_L;\r
+                       rreg = MIX_SB16_VOICE_R;\r
+               } else {        /* MASTER or DEFAULT */\r
+                       lreg = MIX_SB16_MASTER_L;\r
+                       rreg = MIX_SB16_MASTER_R;\r
+               }\r
+\r
+               val = read_mix(lreg);\r
+               left = (val & 0xf8) | ((val >> 3) & 7); /* duplicate last 3 bits */\r
+               val = read_mix(rreg);\r
+               right = (val & 0xf8) | ((val >> 3) & 7);\r
+\r
+       } else if(VER_MAJOR(dsp_ver) >= 3) {\r
+               /* DSP 3.x - SBPro */\r
+               val = read_mix(ctl == AUDIO_PCM ? MIX_SBPRO_VOICE : MIX_SBPRO_MASTER);\r
+\r
+               /* left is top 3 bits, duplicate twice(-ish) */\r
+               left = (val & 0xe0) | ((val >> 3) & 0x1c) | (val >> 6);\r
+               /* right is top 3 bits of the lower nibble */\r
+               right = (val << 4) | ((val << 1) & 0x1c) | ((val >> 2) & 3);\r
+\r
+       } else {\r
+               int volume;\r
+\r
+               /* DSP 2.x - SB 2.0 */\r
+               if(ctl == AUDIO_PCM) {\r
+                       /* voice is in bits 1 and 2 */\r
+                       val = read_mix(MIX_VOICE);\r
+                       volume = (val << 5) | ((val << 3) & 0x30) | ((val << 1) & 0xc) | ((val >> 1) & 3);\r
+               } else {\r
+                       /* master is in the 3 top bits of the lower nibble */\r
+                       val = read_mix(MIX_MASTER);\r
+                       volume = (val << 4) | ((val << 1) & 0x1c) | ((val >> 2) & 3);\r
+               }\r
+               return volume;\r
+       }\r
+\r
+       return (left + right) >> 1;\r
 }\r
 \r
 static void INTERRUPT intr_handler()\r
@@ -317,7 +418,7 @@ static void INTERRUPT intr_handler()
 \r
        /* ask for more data */\r
        if(!(size = audio_callback(bptr, BUFSIZE / 2))) {\r
-               sb_stop();\r
+               stop();\r
        }\r
 \r
        /* acknowledge the interrupt */\r
@@ -449,9 +550,6 @@ static int dsp4_detect_dma(void)
 \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
@@ -459,27 +557,6 @@ static void print_dsp_info(void)
        } 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
diff --git a/src/au_sb.h b/src/au_sb.h
deleted file mode 100644 (file)
index 4766b44..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-#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
index 51a3521..0e16101 100644 (file)
@@ -1,32 +1,19 @@
 #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
+#include "audrv.h"\r
 \r
 static struct audrv drv;\r
 \r
 static audio_callback_func cbfunc;\r
 static void *cbcls;\r
 \r
+/* driver detect/init functions are defined in their respective source files */\r
+int sb_detect(struct audrv *drv);\r
+\r
+\r
 int 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
+       if(sb_detect(&drv)) {\r
                return 0;\r
        }\r
 \r
@@ -69,9 +56,14 @@ void audio_stop(void)
        drv.stop();\r
 }\r
 \r
-void audio_volume(int vol)\r
+void audio_setvolume(int ctl, int vol)\r
+{\r
+       drv.setvolume(ctl, vol);\r
+}\r
+\r
+int audio_getvolume(int ctl)\r
 {\r
-       drv.volume(vol);\r
+       return drv.getvolume(ctl);\r
 }\r
 \r
 int audio_isplaying(void)\r
index 961cb9e..fafcb7f 100644 (file)
@@ -1,6 +1,13 @@
 #ifndef AUDIO_H_\r
 #define AUDIO_H_\r
 \r
+/* mixer channels */\r
+enum {\r
+       AUDIO_DEFAULT,\r
+       AUDIO_MASTER,\r
+       AUDIO_PCM\r
+};\r
+\r
 typedef int (*audio_callback_func)(void *buffer, int size, void *cls);\r
 \r
 int audio_init(void);\r
@@ -15,6 +22,7 @@ void audio_stop(void);
 int audio_isplaying(void);\r
 \r
 /* audio volume: 0-255 */\r
-void audio_volume(int vol);\r
+void audio_setvolume(int ctl, int vol);\r
+int audio_getvolume(int ctl);\r
 \r
 #endif /* AUDIO_H_ */\r
diff --git a/src/audrv.h b/src/audrv.h
new file mode 100644 (file)
index 0000000..6fc99d6
--- /dev/null
@@ -0,0 +1,14 @@
+#ifndef AUDIO_DRIVER_H_
+#define AUDIO_DRIVER_H_
+
+struct audrv {
+       void (*start)(int rate, int bits, int nchan);
+       void (*pause)(void);
+       void (*cont)(void);
+       void (*stop)(void);
+       void (*setvolume)(int ctl, int vol);
+       int (*getvolume)(int ctl);
+       int (*isplaying)(void);
+};
+
+#endif /* AUDIO_DRIVER_H_ */
index f62fdac..c88aa3b 100644 (file)
@@ -22,7 +22,8 @@ int main(int argc, char **argv)
        if(audio_init() == -1) {\r
                return 1;\r
        }\r
-       audio_volume(vol);\r
+       audio_setvolume(AUDIO_MASTER, 255);\r
+       audio_setvolume(AUDIO_PCM, 255);\r
 \r
        for(i=1; i<argc; i++) {\r
                if(argv[i][0] == '-') {\r
@@ -47,7 +48,7 @@ static int dbg_cur_offs;
 static int play_file(const char *fname)\r
 {\r
        struct au_file *au;\r
-       int paused = 0;\r
+       int paused = 0, muted = 0;\r
        unsigned long prev;\r
 \r
        if(!(au = au_open(fname))) {\r
@@ -92,17 +93,26 @@ static int play_file(const char *fname)
                        case '=':\r
                                vol += 32;\r
                                if(vol > 255) vol = 255;\r
-                               audio_volume(vol);\r
+                               audio_setvolume(AUDIO_DEFAULT, vol);\r
                                printf("volume: %d%%\n", 101 * vol / 256);\r
                                break;\r
 \r
                        case '-':\r
                                vol -= 32;\r
                                if(vol < 0) vol = 0;\r
-                               audio_volume(vol);\r
+                               audio_setvolume(AUDIO_DEFAULT, vol);\r
                                printf("volume: %d%%\n", 101 * vol / 256);\r
                                break;\r
 \r
+                       case 'm':\r
+                               muted = !muted;\r
+                               if(muted) {\r
+                                       audio_setvolume(AUDIO_DEFAULT, 0);\r
+                               } else {\r
+                                       audio_setvolume(AUDIO_DEFAULT, vol);\r
+                               }\r
+                               break;\r
+\r
                        default:\r
                                break;\r
                        }\r