SB: finalize IRQ/DMA/options settings

This commit is contained in:
wbcbz7 committed 2026-03-22 00:56:38 +07:00
1 parent f54d9a5840
commit 4bf5631472
11 files changed
+284 -108

No files matched your search

+2 -2
View File
@@ -68,10 +68,10 @@ static const char *modenames[8] = {
#define CMD_MPUFAKE 0x22 // MPU fake all notes off
#define CMD_OPLWAIT 0x30 // Adlib speed sensitive fix
#define CMD_SBOPTS 0x30 // SB options (mixer lock, time constant fix, etc.) - aliased to CMD_OPLWAIT
#define CMD_SBDSPVER 0x31 // SB DSP version
#define CMD_SBTYPE 0x31 // SB type
#define CMD_SBIRQ 0x32 // SB IRQ
#define CMD_SBDMA 0x33 // SB DMA
#define CMD_SBOPTS 0x34 // SB options (mixer lock, time constant fix, etc.)
#define CMD_MOUSEPORT 0x40 // Mouse Base port
#define CMD_MOUSEPROTO 0x41 // Mouse protocol
+19
View File
@@ -86,11 +86,30 @@ https://github.com/polpo/picogus/wiki/Compatibility-list
### Sound Blaster/AdLib options
Sound Blaster emulation requires the BLASTER variable to be set, in the format:
`set BLASTER=A220 I5 D1 H1 T6`, where 220 is the PicoGUS's SB emulation port,
5 is the IRQ, 1 is the DMA, 6 is the emulated SB type (see `/sbtype` option)
* `/sbport x` - sets the base port of the Sound Blaster. Defaults to 220.
* `/sbirq x` - sets the IRQ of the Sound Blaster. Must match jumper settings.
* `/sbdma x` - sets the DMA of the Sound Blaster. Must match jumper settings.
* `/sbtype x` - sets the Sound Blaster type: Allowed values are:
1 - SB 1.x, 2 - SB Pro 1 (dual OPL2), 3 - SB 2.0
4 - SB Pro 2 (OPL3), 6 - SB 16
* `/oplport x` - sets the base port of the OPL/AdLib. Defaults to 388.
* `/oplwait` - wait on OPL2 data write. Can fix speed-sensitive early AdLib
games on fast systems (example: 688 Attack Sub).
* `/sbvol x` - sets the volume of the SB PCM output to x percent.
* `/oplvol x` - sets the volume of the OPL2 output to x percent.
* `/sbfixtc 1|0 ` - fix SB time constant for 11/22/44 kHz sample rate. Can fix
PCM audio slightly pitched up or down in pre-SB16 games and applications.
Note than certain programs are already aware of SB time constant inaccuracy
and will sound wrong if this option is enabled. Default = 0 (disabled)
* `/sblockmixer n` - lock writes to SB mixer settings. Choices:
0 - write lock disabled (default)
1 - lock all but Voice Volume registers (for panning effects e.g. in Wolf3D)
2 - lock all registers
### MPU-401 options
+171 -38
View File
@@ -107,8 +107,16 @@ static void usage(card_mode_t mode, bool print_all)
if (mode == SB_MODE || print_all) {
// "...............................................................................\n"
pageprintf("Sound Blaster settings:\n");
pageprintf(" /sbport x - set the base port of the Sound Blaster. Default: 220\n");
pageprintf(" /sbvol x - set the Sound Blaster audio volume: 0 - 100%\n");
pageprintf(" /sbport x - set the base port of the Sound Blaster. Default: 220\n");
pageprintf(" /sbirq x - set the SB IRQ (must match jumper settings!). Default: 5\n");
pageprintf(" /sbdma x - set the SB DMA (must match jumper settings!). Default: 1\n");
pageprintf(" /sbtype x - set the Sound Blaster type. Default: 6 (SB 16)\n");
pageprintf(" 1 - SB 1.x, 2 - SB Pro 1 (dual OPL2), 3 - SB 2.0,\n");
pageprintf(" 4 - SB Pro 2 (OPL3), 6 - SB 16\n");
pageprintf(" /sbvol x - set the Sound Blaster audio volume: 0 - 100%\n");
pageprintf(" /sbfixtc 1|0 - fix SB time constant to match common rates. Default: 0\n");
pageprintf(" /sblockmixer n - lock SB mixer settings. Default: 0 (no lock)\n");
pageprintf(" 0 - no lock, 1 - lock all but Voice Volume, 2 - lock all\n");
}
if (mode == SB_MODE || mode == ADLIB_MODE || print_all) {
pageprintf("AdLib settings:\n");
@@ -176,11 +184,19 @@ static void err_blaster(void)
// "................................................................................\n"
fprintf(stderr, "ERROR: In SB mode but no BLASTER variable set or is malformed!\n");
fprintf(stderr, "The BLASTER environment variable must be set in the following format:\n");
fprintf(stderr, "\tset BLASTER=Axxx Iy Dz T3\n");
fprintf(stderr, "Where xxx = port, y = IRQ, z = DMA. T3 indicates an SB 2.0 compatible card.\n");
fprintf(stderr, "Port is set via /sbport xxx option; DMA and IRQ configued via jumper.\n");
fprintf(stderr, "\tset BLASTER=Axxx Iy Dz Hz Tw\n");
fprintf(stderr, "Where xxx = port, y = IRQ, z = DMA. w = SB type:\n");
fprintf(stderr, " 1 - SB 1.x, 2 - SB Pro 1 (dual OPL2), 3 - SB 2.0,\n");
fprintf(stderr, " 4 - SB Pro 2 (OPL3), 6 - SB 16\n");
fprintf(stderr, "Port is set via /sbport xxx option; DMA and IRQ configued via jumper then also\n");
fprintf(stderr, "set via /sbirq y and /sbdma y options.\n");
}
static void err_blaster16_dma_mismatch(void)
{
// "................................................................................\n"
fprintf(stderr, "ERROR: In SB 16 mode, low (Dx) and high (Hx) DMA in BLASTER variable must match!\n");
}
static void err_pigus(void)
{
@@ -247,17 +263,33 @@ static int init_gus(void)
static int init_sb(void)
{
// SB DSP version table
const uint16_t dspver[] = {0, 0x105, 0x300, 0x201, 0x301, 0, 0x405};
char* blaster = getenv("BLASTER");
if (blaster == NULL) {
err_blaster();
return 1;
}
char blasterTemp[256];
strncpy(blasterTemp, blaster, sizeof(blasterTemp));
// Parse BLASTER
uint16_t port;
int e;
e = sscanf(blaster, "A%hx I%*hhu D%*hhu T3", &port);
if (e != 1) {
char* p = strtok(blasterTemp, " ");
uint16_t port = -1, irq = -1, dma8 = -1, dma16 = -1, sbtype = 0;
while (p != NULL) {
switch (*p) {
case 'a': case 'A': port = strtol(p + 1, NULL, 16); break;
case 'i': case 'I': irq = strtol(p + 1, NULL, 10); break;
case 'd': case 'D': dma8 = strtol(p + 1, NULL, 10); break;
case 'h': case 'H': dma16 = strtol(p + 1, NULL, 10); break;
case 't': case 'T': sbtype = strtol(p + 1, NULL, 10); break;
default: break;
}
p = strtok(NULL, " ");
}
if ((port == -1) || (irq == -1) || (dma8 == -1) || (sbtype > 6) || (dspver[sbtype] == 0) || ((sbtype == 6) && (dma8 != dma16))) {
err_blaster();
return 2;
}
@@ -268,6 +300,28 @@ static int init_sb(void)
err_blaster();
return 2;
}
outp(CONTROL_PORT, CMD_SBIRQ); // Select IRQ register
uint8_t tmp_irq = inp(DATA_PORT_HIGH);
if (irq != tmp_irq) {
err_blaster();
return 2;
}
outp(CONTROL_PORT, CMD_SBDMA); // Select DMA register
uint8_t tmp_dma = inp(DATA_PORT_HIGH);
if (dma8 != tmp_dma) {
err_blaster();
return 2;
}
outp(CONTROL_PORT, CMD_SBTYPE); // Select SB type register
uint8_t tmp_type = inp(DATA_PORT_HIGH);
if (sbtype != tmp_type) {
err_blaster();
return 2;
}
return 0;
}
@@ -630,13 +684,13 @@ static void send_string(const uint8_t cmd, const char* str, const int16_t max_le
outp(DATA_PORT_HIGH, 0);
}
static bool cmdDisplayUsage(const char* arg, const int print_all)
static bool cmdDisplayUsage(const char* arg, const int print_all, const int cmd2, const int cmd3)
{
usage(gMode, print_all);
return true;
}
static bool cmdSendBool(const char* arg, const int cmd)
static bool cmdSendBool(const char* arg, const int cmd, const int cmd2, const int cmd3)
{
uint8_t value;
@@ -654,7 +708,27 @@ static bool cmdSendBool(const char* arg, const int cmd)
return true;
}
static bool cmdSetMode(const char* arg, const int cmd)
static bool cmdSendBoolMasked(const char* arg, const int cmd, const int mask, const int shift)
{
uint8_t value, oldvalue;
if (!strcmp(arg, "1") || !stricmp(arg, "true") || !stricmp(arg, "on")) {
value = 1;
} else if (!strcmp(arg, "0") || !stricmp(arg, "false") || !stricmp(arg, "off")) {
value = 0;
} else {
usage(gMode, false);
return false;
}
outp(CONTROL_PORT, cmd);
oldvalue = inp(DATA_PORT_HIGH);
outp(DATA_PORT_HIGH, (uint8_t)(oldvalue & ~mask) | ((value << shift) & mask));
return true;
}
static bool cmdSetMode(const char* arg, const int cmd, const int cmd2, const int cmd3)
{
if (!stricmp(arg, "TANDY") || !stricmp(arg, "CMS")) {
// Backwards compatibility for old tandy and cms modes
@@ -687,11 +761,47 @@ static bool ctrlSendUint8(const char *arg, int cmd, int min, int max)
return true;
}
static bool cmdSendUint8(const char* arg, const int cmd)
static bool ctrlSendUint8Masked(const char *arg, int cmd, int min, int max, int mask, int shift) {
char* endptr;
uint8_t val = (uint8_t)strtoul(arg, &endptr, 10);
uint8_t oldval = 0;
if (*endptr != '\0' || val < min || val > max) {
usage(gMode, false);
return false;
}
outp(CONTROL_PORT, cmd);
oldval = inp(DATA_PORT_HIGH);
outp(DATA_PORT_HIGH, (uint8_t)(oldval & ~mask) | ((val << shift) & mask));
return true;
}
static bool cmdSendUint8(const char* arg, const int cmd, const int cmd2, const int cmd3)
{
return ctrlSendUint8(arg, cmd, 0, 255);
}
static bool cmdSendSBType(const char* arg, const int cmd, const int cmd2, const int cmd3) {
char* endptr;
uint8_t val = (uint8_t)strtoul(arg, &endptr, 10);
if (*endptr != '\0' || val < 1 || val > 6 || val == 5) {
usage(gMode, false);
return false;
}
outp(CONTROL_PORT, cmd);
outp(DATA_PORT_HIGH, (uint8_t)val);
return true;
}
static bool cmdSendUint8Masked(const char* arg, const int cmd, const int cmd2, const int cmd3)
{
// cmd2 - mask, cmd3 - shift
return ctrlSendUint8Masked(arg, cmd, 0, 255, cmd2, cmd3);
}
static bool ctrlSendUint16(const char *arg, int cmd, long min, long max, int base)
{
char *endptr;
@@ -707,27 +817,27 @@ static bool ctrlSendUint16(const char *arg, int cmd, long min, long max, int bas
return true;
}
static bool cmdSendUint16(const char* arg, const int cmd)
static bool cmdSendUint16(const char* arg, const int cmd, const int cmd2, const int cmd3)
{
return ctrlSendUint16(arg, cmd, 0, 65535, 10);
}
static bool cmdSendPort(const char* arg, const int cmd)
static bool cmdSendPort(const char* arg, const int cmd, const int cmd2, const int cmd3)
{
return ctrlSendUint16(arg, cmd, 0, 0x3FF, 16);
}
static bool cmdDefaults(const char* arg, const int cmd)
static bool cmdDefaults(const char* arg, const int cmd, const int cmd2, const int cmd3)
{
return cmdSendUint8(CMD_DEFAULTS, 0xff);
return cmdSendUint8(CMD_DEFAULTS, 0xff, 0, 0);
}
static bool cmdSetVol(const char* arg, const int cmd)
static bool cmdSetVol(const char* arg, const int cmd, const int cmd2, const int cmd3)
{
return ctrlSendUint8(arg, cmd, 0, 100);
}
static bool cmdSendMousePort(const char *arg, const int cmd)
static bool cmdSendMousePort(const char *arg, const int cmd, const int cmd2, const int cmd3)
{
char* endptr;
uint8_t val = (uint8_t)strtoul(arg, &endptr, 10);
@@ -753,66 +863,71 @@ static bool cmdSendMousePort(const char *arg, const int cmd)
return true;
}
static bool cmdSendMouseSen(const char* arg, const int cmd)
static bool cmdSendMouseSen(const char* arg, const int cmd, const int cmd2, const int cmd3)
{
return ctrlSendUint16(arg, cmd, 0, 1024, 10);
}
static bool cmdSendMouseProto(const char* arg, const int cmd)
static bool cmdSendMouseProto(const char* arg, const int cmd, const int cmd2, const int cmd3)
{
return ctrlSendUint8(arg, cmd, 0, 3);
}
static bool cmdSendMouseRate(const char* arg, const int cmd)
static bool cmdSendMouseRate(const char* arg, const int cmd, const int cmd2, const int cmd3)
{
return ctrlSendUint8(arg, cmd, 20, 200);
}
static bool cmdWifiStatus(const char* arg, const int cmd)
static bool cmdSendSBLockMixer(const char* arg, const int cmd, const int cmd2, const int cmd3)
{
return ctrlSendUint8Masked(arg, cmd, 0, 2, (2 << 1), 1);
}
static bool cmdWifiStatus(const char* arg, const int cmd, const int cmd2, const int cmd3)
{
wifi_printStatus();
exit(0);
}
static bool cmdWifiSSID(const char* arg, const int cmd)
static bool cmdWifiSSID(const char* arg, const int cmd, const int cmd2, const int cmd3)
{
wifichg = true;
send_string(cmd, arg, 32);
return true;
}
static bool cmdWifiPass(const char* arg, const int cmd)
static bool cmdWifiPass(const char* arg, const int cmd, const int cmd2, const int cmd3)
{
wifichg = true;
send_string(cmd, arg, 63);
return true;
}
static bool cmdWifiNoPass(const char* arg, const int cmd)
static bool cmdWifiNoPass(const char* arg, const int cmd, const int cmd2, const int cmd3)
{
wifichg = true;
send_string(cmd, "", 1);
return true;
}
static bool cmdCDLoadName(const char* arg, const int cmd)
static bool cmdCDLoadName(const char* arg, const int cmd, const int cmd2, const int cmd3)
{
send_string(cmd, arg, 127);
exit(wait_for_cd_load());
}
static bool cmdCDList(const char* arg, const int cmd)
static bool cmdCDList(const char* arg, const int cmd, const int cmd2, const int cmd3)
{
exit(print_cdimage_list());
}
static bool cmdCDLoad(const char* arg, const int cmd)
static bool cmdCDLoad(const char* arg, const int cmd, const int cmd2, const int cmd3)
{
ctrlSendUint8(arg, cmd, 0, 255);
exit(wait_for_cd_load());
}
static bool cmdGUSBuffer(const char* arg, const int cmd)
static bool cmdGUSBuffer(const char* arg, const int cmd, const int cmd2, const int cmd3)
{
uint8_t tmp_uint8;
uint8_t e = sscanf(arg, "%hhu", &tmp_uint8);
@@ -826,7 +941,7 @@ static bool cmdGUSBuffer(const char* arg, const int cmd)
return true;
}
static bool cmdFlashPico(const char* arg, const int cmd)
static bool cmdFlashPico(const char* arg, const int cmd, const int cmd2, const int cmd3)
{
if (strlen(arg) > 255)
{
@@ -837,7 +952,7 @@ static bool cmdFlashPico(const char* arg, const int cmd)
return true;
}
static bool cmdSave(const char* arg, const int cmd)
static bool cmdSave(const char* arg, const int cmd, const int cmd2, const int cmd3)
{
permanent = true;
return true;
@@ -868,6 +983,11 @@ ParseCommand parseCommands[] = {
{"/gusdma", cmdSendUint8, CMD_GUSDMA, ARG_REQUIRE, "0"},
{"/gusport", cmdSendPort, CMD_GUSPORT, ARG_REQUIRE, "240"},
{"/sbport", cmdSendPort, CMD_SBPORT, ARG_REQUIRE, "220"},
{"/sbirq", cmdSendUint8, CMD_SBIRQ, ARG_REQUIRE, "5"},
{"/sbdma", cmdSendUint8, CMD_SBDMA, ARG_REQUIRE, "1"},
{"/sbtype", cmdSendSBType, CMD_SBTYPE, ARG_REQUIRE, "6"},
{"/sbfixtc", cmdSendBoolMasked, CMD_SBOPTS, ARG_REQUIRE, "0", (1 << 0), 0},
{"/sblockmixer", cmdSendSBLockMixer, CMD_SBOPTS, ARG_REQUIRE, "0"},
{"/oplport", cmdSendPort, CMD_OPLPORT, ARG_REQUIRE, "388"},
{"/oplwait", cmdSendBool, CMD_OPLWAIT, ARG_REQUIRE, "false"},
{"/mpuport", cmdSendPort, CMD_MPUPORT, ARG_REQUIRE, "330"},
@@ -941,7 +1061,7 @@ int parseCommand(int argc, char* argv[], int* i, ParseCommand commands[])
return retVal;
}
}
return command->routine(arg, command->cmd);
return command->routine(arg, command->cmd, command->cmd2, command->cmd3);
} else {
printf("Invalid command %s. Run pgusinit /? for usage help", argv[idx]);
}
@@ -1006,7 +1126,7 @@ static void printGUSMode()
static void printAdlibMode()
{
printf("Running in AdLib/OPL2 mode on port %x", ctrlGetUint16(CMD_OPLPORT));
printf("%s\n", ctrlGetUint8(CMD_OPLWAIT) ? ", wait on" : "");
printf("%s\n", ctrlGetUint8(CMD_OPLWAIT) & 1 ? ", wait on" : "");
}
static void printUSBMode()
@@ -1023,16 +1143,29 @@ static void printPSGMode()
static void printSBMode()
{
static char *strMode[] = {"(invalid)", "1.x", "Pro 1", "2.0", "Pro 2", "(invalid)", "16"};
static char *strLockMixerMode[] = {"unlocked", "locked except Voice Volume", "locked", "(invalid)"};
if (init_sb()) {
return;
}
printf("Running in Sound Blaster 2.0 mode on port %x ", ctrlGetUint16(CMD_SBPORT));
printf("Running in Sound Blaster %s mode on port %x, IRQ %d, DMA %d\n",
ctrlGetUint8(CMD_SBTYPE) > 6 ? "(invalid)" : strMode[ctrlGetUint8(CMD_SBTYPE)],
ctrlGetUint16(CMD_SBPORT),
ctrlGetUint8(CMD_SBIRQ),
ctrlGetUint8(CMD_SBDMA)
);
uint8_t tmp_uint8 = ctrlGetUint8(CMD_SBOPTS);
printf("SB Time Constant fix: %s, SB mixer: %s\n",
(tmp_uint8 >> 0) & 1 ? "enabled" : "disabled",
strLockMixerMode[(tmp_uint8 >> 1) & 3]
);
uint16_t tmp_uint16 = ctrlGetUint16(CMD_OPLPORT);
if (tmp_uint16) {
printf("(AdLib port %x", tmp_uint16);
printf("%s)\n", ctrlGetUint8(CMD_OPLWAIT) ? ", wait on" : "");
printf("AdLib port %x", tmp_uint16);
printf("%s\n", ctrlGetUint8(CMD_OPLWAIT) & 1 ? ", wait on" : "");
} else {
printf("(AdLib port disabled)\n");
printf("AdLib port disabled\n");
}
print_cdemu_status();
}
+3 -1
View File
@@ -34,9 +34,11 @@ enum CommandType
typedef struct {
char *name;
bool (*routine)(const char*, const int);
bool (*routine)(const char*, const int, const int, const int);
int cmd;
int type;
char *def;
int cmd2;
int cmd3;
} ParseCommand;
+1 -1
View File
@@ -19,7 +19,7 @@ set(PICO_COPY_TO_RAM 1)
include(pico_sdk_import.cmake)
project(picogus
VERSION "3.2.1"
VERSION "3.2.2"
LANGUAGES C CXX ASM
)
+22 -18
View File
@@ -244,13 +244,10 @@ __force_inline void select_picogus(uint8_t value) {
cur_read_idx = 0;
#endif
break;
#ifdef SOUND_SB
case CMD_SBDSPVER:
picogus_dataLatch_low = 0;
case CMD_SBTYPE:
case CMD_SBIRQ:
case CMD_SBDMA:
break;
#endif
case CMD_SBOPTS:
case CMD_CDSTATUS:
case CMD_CDLOAD:
case CMD_CDAUTOADV:
@@ -296,12 +293,6 @@ __force_inline void write_picogus_low(uint8_t value) {
case CMD_MOUSESEN: // USB Mouse Sensitivity (8.8 fixedpoint)
mouseSensitivity_low = value;
break;
#ifdef SOUND_SB
case CMD_SBDSPVER:
picogus_dataLatch_low = value;
break;
#endif
break;
}
}
@@ -372,25 +363,30 @@ __force_inline void write_picogus_high(uint8_t value) {
#endif
break;
case CMD_OPLWAIT: // Adlib speed sensitive fix
//case CMD_SBOPTS: // ... and SB emulation options
settings.SB.oplSpeedSensitive = value & 1; // HACK until settings struct resolved
#ifdef SOUND_SB
sbdsp_set_options(value);
#endif
settings.SB.oplSpeedSensitive = value;
break;
case CMD_SBDSPVER:
case CMD_SBTYPE:
settings.SB16.sbType = value;
#ifdef SOUND_SB
sbdsp_set_dsp_version((value << 8) | picogus_dataLatch_low);
sbdsp_set_type(value);
#endif
break;
case CMD_SBIRQ:
settings.SB16.irq = value;
#ifdef SOUND_SB
sbdsp_set_irq(value);
#endif
break;
case CMD_SBDMA:
settings.SB16.dma = value;
#ifdef SOUND_SB
sbdsp_set_dma(value);
#endif
case CMD_SBOPTS:
settings.SB16.options = value;
#ifdef SOUND_SB
sbdsp_set_options(value);
#endif
break;
case CMD_MOUSEPORT: // USB Mouse port (0 - disabled)
@@ -606,6 +602,14 @@ __force_inline uint8_t read_picogus_high(void) {
return settings.Mouse.sensitivity >> 8;
case CMD_NE2KPORT: // NE2000 Base port
return settings.NE2K.basePort == 0xFFFF ? 0 : (settings.NE2K.basePort >> 8);
case CMD_SBTYPE: // SB type
return settings.SB16.sbType;
case CMD_SBIRQ: // SB IRQ
return settings.SB16.irq;
case CMD_SBDMA: // SB DMA
return settings.SB16.dma;
case CMD_SBOPTS: // SB Options
return settings.SB16.options;
/*
case CMD_WIFISSID:
break;
+32 -19
View File
@@ -13,6 +13,7 @@ Author : Kevin Moonlight <me@yyzkevin.com>
Copyright (C) 2023 Kevin Moonlight
Copyright (C) 2024 Ian Scott
Copyright (C) 2026 Artem Vasilev
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
@@ -49,8 +50,12 @@ static irq_handler_t SBDSP_DMA_isr_pt;
static dma_inst_t dma_config;
#define DMA_PIO_SM 2
#define DSP_VERSION_MAJOR 4
#define DSP_VERSION_MINOR 5
#define SB_TYPE_SB1 0x1
#define SB_TYPE_SBPRO1 0x2
#define SB_TYPE_SB2 0x3
#define SB_TYPE_SBPRO2 0x4
#define SB_TYPE_SB2MCV 0x5
#define SB_TYPE_SB16 0x6
// Sound Blaster DSP I/O port offsets
#define DSP_RESET 0x6
@@ -138,8 +143,8 @@ static dma_inst_t dma_config;
// mixer locking settings
#define MIXER_LOCK_NONE 0 // none, all registers writeable
#define MIXER_LOCK_ALL_BUT_SBP_VOICE 14 // lock all but SBPro Voice (for stereo FX like in Wolf3D)
#define MIXER_LOCK_ALL 15 // lock all registers
#define MIXER_LOCK_ALL_BUT_SBP_VOICE 1 // lock all but SBPro Voice (for stereo FX like in Wolf3D)
#define MIXER_LOCK_ALL 2 // lock all registers
static char const copyright_string[] = "COPYRIGHT (C) CREATIVE TECHNOLOGY LTD, 1992.";
@@ -222,7 +227,7 @@ uint32_t sbdsp_generate_sample() {
}
static void sbdsp_handle_time_constant(uint8_t tc) {
if (sbdsp.options.fix_tc) {
if (sbdsp.options.fixTC) {
// round time constants to 11/22/44 KHz sample rates
switch (tc) {
case (256 - 62): // 16129 Hz
@@ -320,11 +325,31 @@ uint16_t sbdsp_sample_rate() {
return sbdsp.sample_rate;
}
void sbdsp_set_options(uint8_t options) {
sbdsp.options.b = options;
// TODO if any to apply
}
void sbdsp_set_type(uint8_t type) {
if ((type == 0) && (type > SB_TYPE_SB16)) type = SB_TYPE_SB16;
switch (type) {
default:
case SB_TYPE_SB1: sbdsp.dsp_version.major = 1; sbdsp.dsp_version.minor = 5; break;
case SB_TYPE_SB2:
case SB_TYPE_SB2MCV: sbdsp.dsp_version.major = 2; sbdsp.dsp_version.minor = 1; break;
case SB_TYPE_SBPRO1: sbdsp.dsp_version.major = 3; sbdsp.dsp_version.minor = 0; break;
case SB_TYPE_SBPRO2: sbdsp.dsp_version.major = 3; sbdsp.dsp_version.minor = 1; break;
case SB_TYPE_SB16: sbdsp.dsp_version.major = 4; sbdsp.dsp_version.minor = 5; break;
}
return;
}
void sbdsp_set_irq(uint8_t irq) {
sbdsp.resources.irq = irq;
int mixer_irq;
switch (irq) {
case 2: mixer_irq = 1; break;
case 2:
case 9: mixer_irq = 1; break;
case 7: mixer_irq = 4; break;
case 10: mixer_irq = 8; break;
case 5:
@@ -338,23 +363,11 @@ void sbdsp_set_dma(uint8_t dma) {
mixer_state[MIXER_DMA] = dma < 4 ? (1 << dma) : 0; // 8-bit DMA channel only
}
void sbdsp_set_options(uint8_t opts) {
sbdsp.options.b = opts;
// TODO apply them in runtime where applicable
}
static void sbmixer_reset(void);
void sbdsp_init() {
puts("Initing ISA DMA PIO...");
SBDSP_DMA_isr_pt = sbdsp_dma_isr;
sbdsp.options.mixer_lock = MIXER_LOCK_NONE;
sbdsp.options.fix_tc = 0;
sbdsp.dsp_version.major = DSP_VERSION_MAJOR;
sbdsp.dsp_version.minor = DSP_VERSION_MINOR;
sbdsp_set_irq(5);
sbdsp_set_dma(1);
sbdsp.outbox = 0xAA;
dma_config = DMA_multi_init(pio0, DMA_PIO_SM, SBDSP_DMA_isr_pt);
@@ -882,7 +895,7 @@ static __force_inline uint8_t sbmixer_read(void) {
static __force_inline void sbmixer_write(uint8_t value) {
// mixer locking
switch(sbdsp.options.mixer_lock) {
switch(sbdsp.options.lockMixer) {
case MIXER_LOCK_ALL_BUT_SBP_VOICE:
if (sbdsp.mixer_command != MIXER_VOL_VOICE)
// fallthrough
+4 -27
View File
@@ -84,12 +84,10 @@ typedef struct sbdsp_t {
uint8_t dma;
} resources;
// additional options
union {
struct {
uint8_t reserved : 3; // reserved for OPL speed sensitivity fix and future settings
uint8_t fix_tc : 1; // fix time constant for exact 11/22/44k Hz
uint8_t mixer_lock : 4; // mixer lock
uint8_t fixTC : 1;
uint8_t lockMixer : 2;
};
uint8_t b;
} options;
@@ -140,30 +138,9 @@ static inline uint32_t sbdsp_sample_stereo() {
// -------------------------
// PicoGUS configuration interface helpers
static inline uint16_t sbdsp_get_dsp_version() {
extern sbdsp_t sbdsp;
return sbdsp.dsp_version.w;
}
static inline void sbdsp_set_dsp_version(uint16_t dspver) {
extern sbdsp_t sbdsp;
sbdsp.dsp_version.w = dspver;
}
static inline uint8_t sbdsp_get_irq() {
extern sbdsp_t sbdsp;
return sbdsp.resources.irq;
}
static inline uint8_t sbdsp_get_dma() {
extern sbdsp_t sbdsp;
return sbdsp.resources.dma;
}
void sbdsp_set_type(uint8_t type);
void sbdsp_set_irq(uint8_t irq);
void sbdsp_set_dma(uint8_t dma);
static inline uint8_t sbdsp_get_options() {
extern sbdsp_t sbdsp;
return sbdsp.options.b;
}
void sbdsp_set_options(uint8_t opts);
void sbdsp_set_options(uint8_t options);
#endif // SBDSP_H
+5 -1
View File
@@ -66,7 +66,7 @@ extern cms_buffer_t opl_cmd_buffer;
#include "mouse/sermouse.h"
#endif
#ifdef SOUND_MPU
#if (defined(SOUND_MPU) || defined(SOUND_SB))
#include "system/flash_settings.h"
extern Settings settings;
#include "mpu401/export.h"
@@ -201,6 +201,10 @@ void play_adlib() {
ad1848_init();
#else
sbdsp_init();
sbdsp_set_type(settings.SB16.sbType);
sbdsp_set_irq(settings.SB16.irq);
sbdsp_set_dma(settings.SB16.dma);
sbdsp_set_options(settings.SB16.options);
#endif
#endif
init_audio();
+12
View File
@@ -85,6 +85,13 @@ static const Settings defaultSettings = {
.cdVol = 100,
.gusVol = 100,
.psgVol = 80
},
.SB16 = {
.irq = 5,
.dma = 1,
.sbType = 6,
.fixTC = 0,
.lockMixer = 0
}
};
@@ -126,6 +133,11 @@ static const VersionFields versionFieldsTable[] = {
{(const FieldInfo[]){
FIELD(Volume),
}, 1},
// version 5 - added SB16 settings
{(const FieldInfo[]){
FIELD(SB16),
}, 1},
};
// Apply default values only to fields introduced after the given version
+13 -1
View File
@@ -25,7 +25,7 @@ extern "C" {
#include <stdbool.h>
#define SETTINGS_MAGIC 0x70677573 // "pgus" in ascii
#define SETTINGS_VERSION 4
#define SETTINGS_VERSION 5
// When adding new fields to Settings struct:
// 1. Increment SETTINGS_VERSION
@@ -95,6 +95,18 @@ typedef struct Settings {
uint8_t gusVol;
uint8_t psgVol;
} Volume;
struct {
uint8_t irq;
uint8_t dma;
uint8_t sbType;
union {
struct {
uint8_t fixTC : 1;
uint8_t lockMixer : 2;
};
uint8_t options;
};
} SB16; // TEMPORARY - may be changed!
} Settings;