From 4389231cc058d52196ebf35a4b62ddf6a8410326 Mon Sep 17 00:00:00 2001 From: win2kgamer <47463859+win2kgamer@users.noreply.github.com> Date: Tue, 27 Jan 2026 22:14:42 -0600 Subject: [PATCH] Sensation audio: Implement the mixer --- src/sound/snd_sensation.c | 143 ++++++++++++++++++++++++++++++++------ 1 file changed, 123 insertions(+), 20 deletions(-) diff --git a/src/sound/snd_sensation.c b/src/sound/snd_sensation.c index e135d9435..88866f563 100644 --- a/src/sound/snd_sensation.c +++ b/src/sound/snd_sensation.c @@ -64,6 +64,8 @@ sensation_log(void *priv, const char *fmt, ...) # define sensation_log(fmt, ...) #endif +static int visdac_vols_6bits[64]; + typedef struct sensation_t { int mma_irq; int mma_dma; @@ -148,12 +150,30 @@ typedef struct sensation_t { int visdac_count; + double cd_vol_l; + double cd_vol_r; + int fm_vol_l; + int fm_vol_r; + int wave_vol_l; + int wave_vol_r; + void * log; /* New logging system */ } sensation_t; void sensation_mma_timer_poll(void *priv); void sensation_mma_update(sensation_t *dev); +void +sensation_filter_cd_audio(int channel, double *buffer, void *priv) +{ + sensation_t *dev = (sensation_t *) priv; + + const double cd_vol = channel ? dev->cd_vol_r : dev->cd_vol_l; + double c = ((*buffer * cd_vol / 4.0)) / 65536.0; + + *buffer = c; +} + void sensation_visdac_update(sensation_t *dev) { @@ -286,6 +306,14 @@ sensation_visdac_poll(void *priv) default: break; } + if (dev->wave_vol_l == 0) + dev->visdac_out_l = 0; + else + dev->visdac_out_l = (int16_t) ((dev->visdac_out_l * dev->wave_vol_l) >> 16); + if (dev->wave_vol_r == 0) + dev->visdac_out_r = 0; + else + dev->visdac_out_r = (int16_t) ((dev->visdac_out_r * dev->wave_vol_r) >> 16); //if (!(dev->visdac_playback_pos & 0x03)) // dev->visdac_count--; if (dev->visdac_count < 0) { @@ -389,21 +417,6 @@ sensation_visdac_write(uint16_t port, uint8_t val, void *priv) sensation_log(visdac->log, "[%04X:%08X] Sensation VISDAC Write: port = %02X, val = %02X\n", CS, cpu_state.pc, port, val); - /* TODO: Implement volume controls: - * 222/223 reg 0 = CD L Mute - * 222/223 reg 1 = CD R Mute - * 222/223 reg 2 = MIDI L Mute - * 222/223 reg 3 = MIDI R Mute - * 222/223 reg 4 = CD L Volume - * 222/223 reg 5 = CD R Volume - * 222/223 reg 6 = MIDI L Volume - * 222/223 reg 7 = MIDI R Volume - * 224/225 reg 0 = Wave L Mute - * 224/225 reg 1 = Wave R Mute - * 224/225 reg 4 = Wave L Volume - * 224/225 reg 5 = Wave R Volume - */ - uint8_t oldmode = visdac->visdac_mode; switch (port & 0xF) { case 0x00: /* Mode/Enable register */ @@ -429,6 +442,46 @@ sensation_visdac_write(uint16_t port, uint8_t val, void *priv) case 0x02: /* Indirect register set 0 data */ visdac->visdac_regs[0x02] = val; visdac->visdac_iregs0[visdac->visdac_regs[0x03] & 0x0f] = val; + switch (visdac->visdac_regs[0x03]) { + case 0: /* CD L Mute */ + visdac->cd_vol_l = 0; + break; + case 1: /* CD R Mute */ + visdac->cd_vol_r = 0; + break; + case 2: /* MIDI L Mute */ + visdac->fm_vol_l = 0; + break; + case 3: /* MIDI R Mute */ + visdac->fm_vol_r = 0; + break; + case 4: /* CD L Volume */ + if (visdac->visdac_iregs0[0x04] == 0x00) + visdac->cd_vol_l = 0; + else + visdac->cd_vol_l = visdac_vols_6bits[(visdac->visdac_iregs0[0x04] & 0x3f)]; + break; + case 5: /* CD R Volume */ + if (visdac->visdac_iregs0[0x05] == 0x00) + visdac->cd_vol_r = 0; + else + visdac->cd_vol_r = visdac_vols_6bits[(visdac->visdac_iregs0[0x05] & 0x3f)]; + break; + case 6: /* MIDI L Volume */ + if (visdac->visdac_iregs0[0x06] == 0x00) + visdac->fm_vol_l = 0; + else + visdac->fm_vol_l = visdac_vols_6bits[(visdac->visdac_iregs0[0x06] & 0x3f)]; + break; + case 7: /* MIDI R Volume */ + if (visdac->visdac_iregs0[0x07] == 0x00) + visdac->fm_vol_r = 0; + else + visdac->fm_vol_r = visdac_vols_6bits[(visdac->visdac_iregs0[0x07] & 0x3f)]; + break; + default: + break; + } break; case 0x03: /* Indirect register set 0 index */ visdac->visdac_regs[0x03] = val; @@ -436,6 +489,30 @@ sensation_visdac_write(uint16_t port, uint8_t val, void *priv) case 0x04: /* Indirect register set 1 data */ visdac->visdac_regs[0x04] = val; visdac->visdac_iregs1[visdac->visdac_regs[0x05] & 0x0f] = val; + switch (visdac->visdac_regs[0x05]) { + case 0: /* Wave L Mute */ + visdac->wave_vol_l = 0; + break; + case 1: /* Wave R Mute */ + visdac->wave_vol_r = 0; + break; + case 2: /* Mic/Line/Phone L Mute */ + break; + case 3: /* Mic/Line/Phone R Mute */ + break; + case 4: /* Wave L Volume */ + visdac->wave_vol_l = visdac_vols_6bits[(visdac->visdac_iregs1[0x04] & 0x3f)]; + break; + case 5: /* Wave R Volume */ + visdac->wave_vol_r = visdac_vols_6bits[(visdac->visdac_iregs1[0x05] & 0x3f)]; + break; + case 6: /* Mic/Line/Phone L Volume */ + break; + case 7: /* Mic/Line/Phone R Volume */ + break; + default: + break; + } break; case 0x05: /* Indirect register set 1 index */ visdac->visdac_regs[0x05] = val; @@ -443,10 +520,10 @@ sensation_visdac_write(uint16_t port, uint8_t val, void *priv) case 0x06: visdac->visdac_regs[0x06] = val; break; - case 0x07: + case 0x07: /* Mixer Source Select */ visdac->visdac_regs[0x07] = val; break; - case 0x08: + case 0x08: /* Mixer Crossover Control */ visdac->visdac_regs[0x08] = val; break; case 0x09: /* Control register */ @@ -1008,11 +1085,10 @@ sensation_get_buffer(int32_t *buffer, int len, void *priv) sensation_mma_update(dev); sensation_visdac_update(dev); - /* TODO: Volume controls */ for (c = 0; c < len * 2; c += 2) { - mma_buffer[c] = opl_buf[c]; + mma_buffer[c] = (opl_buf[c] * dev->fm_vol_l) / 65536.0; mma_buffer[c] += dev->mma_buffer[0][c >> 1]; - mma_buffer[c + 1] = opl_buf[c + 1]; + mma_buffer[c + 1] = (opl_buf[c + 1] * dev->fm_vol_r) / 65536.0; mma_buffer[c + 1] += dev->mma_buffer[1][c >> 1]; buffer[c] += mma_buffer[c]; @@ -1103,6 +1179,33 @@ sensation_init(const device_t *info) if (device_get_config_int("receive_input")) midi_in_handler(1, sensation_input_msg, sensation_input_sysex, dev); + /* Calculate attenuation values for the 6-bit volume control */ + int c; + double attenuation; + for (c = 0; c < 64; c++) { + attenuation = -31.5; + if (c & 0x01) + attenuation += 0.5; + if (c & 0x02) + attenuation += 1.0; + if (c & 0x04) + attenuation += 2.0; + if (c & 0x08) + attenuation += 4.0; + if (c & 0x10) + attenuation += 8.0; + if (c & 0x20) + attenuation += 16.0; + + attenuation = pow(10, attenuation / 10); + + visdac_vols_6bits[c] = (int) (attenuation * 65536); + } + + /* Set up audio filters */ + sound_set_cd_audio_filter(NULL, NULL); + sound_set_cd_audio_filter(sensation_filter_cd_audio, dev); + return dev; }