Switching filter implementation to use SB16 filters; fixing CD audio volume

This commit is contained in:
OBattler
2024-03-12 10:10:00 -03:00
committed by Kagamiin~
parent 7c99887293
commit 7ad48f8d29
2 changed files with 75 additions and 24 deletions

View File

@@ -150,7 +150,7 @@ ess_mixer_write(uint16_t addr, uint8_t val, void *priv)
/* Initialize ESS regs. */ /* Initialize ESS regs. */
mixer->regs[0x14] = mixer->regs[0x32] = 0x88; mixer->regs[0x14] = mixer->regs[0x32] = 0x88;
mixer->regs[0x36] = 0x88; mixer->regs[0x36] = 0x88;
mixer->regs[0x38] = 0x00; mixer->regs[0x38] = 0x88;
mixer->regs[0x3a] = 0x00; mixer->regs[0x3a] = 0x00;
mixer->regs[0x3e] = 0x00; mixer->regs[0x3e] = 0x00;
@@ -384,8 +384,8 @@ ess_get_buffer_sbpro(int32_t *buffer, int len, void *priv)
/* TODO: Implement the stereo switch on the mixer instead of on the dsp? */ /* TODO: Implement the stereo switch on the mixer instead of on the dsp? */
if (mixer->output_filter) { if (mixer->output_filter) {
out_l += (sb_iir(0, 0, (double) ess->dsp.buffer[c]) * mixer->voice_l) / 3.9; out_l += (low_fir_sb16(0, 0, (double) ess->dsp.buffer[c]) * mixer->voice_l) / 3.0;
out_r += (sb_iir(0, 1, (double) ess->dsp.buffer[c + 1]) * mixer->voice_r) / 3.9; out_r += (low_fir_sb16(0, 1, (double) ess->dsp.buffer[c + 1]) * mixer->voice_r) / 3.0;
} else { } else {
out_l += (ess->dsp.buffer[c] * mixer->voice_l) / 3.0; out_l += (ess->dsp.buffer[c] * mixer->voice_l) / 3.0;
out_r += (ess->dsp.buffer[c + 1] * mixer->voice_r) / 3.0; out_r += (ess->dsp.buffer[c + 1] * mixer->voice_r) / 3.0;
@@ -446,10 +446,7 @@ ess_filter_cd_audio(int channel, double *buffer, void *priv)
double cd = channel ? mixer->cd_r : mixer->cd_l; double cd = channel ? mixer->cd_r : mixer->cd_l;
double master = channel ? mixer->master_r : mixer->master_l; double master = channel ? mixer->master_r : mixer->master_l;
if (mixer->output_filter) c = (*buffer * cd) / 3.0;
c = (sb_iir(2, channel, *buffer) * cd) / 3.9;
else
c = (*buffer * cd) / 3.0;
*buffer = c * master; *buffer = c * master;
} }

View File

@@ -175,6 +175,37 @@ recalc_sb16_filter(int c, int playback_freq)
low_fir_sb16_coef[c][n] /= gain; low_fir_sb16_coef[c][n] /= gain;
} }
static void
recalc_opl_filter(int c, int playback_freq)
{
/* Cutoff frequency = playback / 2 */
int n;
double w;
double h;
double fC = ((double) playback_freq) / (double) (FREQ_49716 * 2);
double gain;
for (n = 0; n < SB16_NCoef; n++) {
/* Blackman window */
w = 0.42 - (0.5 * cos((2.0 * n * M_PI) / (double) (SB16_NCoef - 1))) + (0.08 * cos((4.0 * n * M_PI) / (double) (SB16_NCoef - 1)));
/* Sinc filter */
h = sinc(2.0 * fC * ((double) n - ((double) (SB16_NCoef - 1) / 2.0)));
/* Create windowed-sinc filter */
low_fir_sb16_coef[c][n] = w * h;
}
low_fir_sb16_coef[c][(SB16_NCoef - 1) / 2] = 1.0;
gain = 0.0;
for (n = 0; n < SB16_NCoef; n++)
gain += low_fir_sb16_coef[c][n];
/* Normalise filter, to produce unity gain */
for (n = 0; n < SB16_NCoef; n++)
low_fir_sb16_coef[c][n] /= gain;
}
static void static void
sb_irq_update_pic(void *priv, int set) sb_irq_update_pic(void *priv, int set)
{ {
@@ -678,17 +709,29 @@ sb_dsp_setdma16_translate(sb_dsp_t *dsp, int translate)
dsp->sb_16_dma_translate = translate; dsp->sb_16_dma_translate = translate;
} }
static void sb_ess_update_reg_a2(sb_dsp_t *dsp, uint8_t val)
{
double freq = (7160000.0 / (256.0 - ((double) val))) * 41.0;
int temp = (int) freq;
ESSreg(0xA2) = val;
if (dsp->sb_freq != temp)
recalc_sb16_filter(0, temp);
dsp->sb_freq = temp;
}
/* TODO: Investigate ESS cards' filtering on real hardware as well. /* TODO: Investigate ESS cards' filtering on real hardware as well.
(DOSBox-X did it purely off some laptop's ESS chip, which isn't a good look.) */ (DOSBox-X did it purely off some laptop's ESS chip, which isn't a good look.) */
static void sb_ess_update_filter_freq(sb_dsp_t *dsp) static void sb_ess_update_filter_freq(sb_dsp_t *dsp)
{ {
double temp = (7160000.0 / (((((double) dsp->sb_freq) / 2.0) * 0.80) * 82.0)) - 256.0;
if (dsp->sb_freq >= 22050) if (dsp->sb_freq >= 22050)
ESSreg(0xA1) = 256 - (795500UL / dsp->sb_freq); ESSreg(0xA1) = 256 - (795500UL / dsp->sb_freq);
else else
ESSreg(0xA1) = 128 - (397700UL / dsp->sb_freq); ESSreg(0xA1) = 128 - (397700UL / dsp->sb_freq);
unsigned int freq = ((dsp->sb_freq * 4) / (5 * 2)); /* 80% of 1/2 the sample rate */ sb_ess_update_reg_a2(dsp, (uint8_t) temp);
ESSreg(0xA2) = 256 - (7160000 / (freq * 82));
} }
static uint8_t sb_ess_read_reg(sb_dsp_t *dsp, uint8_t reg) static uint8_t sb_ess_read_reg(sb_dsp_t *dsp, uint8_t reg)
@@ -720,20 +763,14 @@ static void sb_ess_write_reg(sb_dsp_t *dsp, uint8_t reg, uint8_t data)
dsp->sb_freq = 795500UL / (256ul - data); dsp->sb_freq = 795500UL / (256ul - data);
else else
dsp->sb_freq = 397700UL / (128ul - data); dsp->sb_freq = 397700UL / (128ul - data);
// TODO: check if this command updates the filter or not
sb_ess_update_filter_freq(dsp);
ESSreg(reg) = data; /* HACK: sb_ess_update_filter_freq updates 0xA1.
* I'm not sure if that could cause an off by one
* error, so this is just to be safe. */
temp = 1000000.0 / dsp->sb_freq; temp = 1000000.0 / dsp->sb_freq;
dsp->sblatchi = dsp->sblatcho = TIMER_USEC * temp; dsp->sblatchi = dsp->sblatcho = TIMER_USEC * temp;
dsp->sb_timei = dsp->sb_timeo; dsp->sb_timei = dsp->sb_timeo;
pclog("ess: Sample rate - %ihz (%f)\n", dsp->sb_freq, dsp->sblatcho); pclog("ess: Sample rate - %ihz (%f)\n", dsp->sb_freq, dsp->sblatcho);
break; break;
} }
case 0xA2: /* Filter divider (effectively, a hardware lowpass filter under S/W control) */ case 0xA2: /* Filter divider (effectively, a hardware lowpass filter under S/W control) */
ESSreg(reg) = data; sb_ess_update_reg_a2(dsp, data);
break; break;
case 0xA4: /* DMA Transfer Count Reload (low) */ case 0xA4: /* DMA Transfer Count Reload (low) */
@@ -1147,6 +1184,7 @@ sb_exec_command(sb_dsp_t *dsp)
temp = 1000000 / temp; temp = 1000000 / temp;
sb_dsp_log("Sample rate - %ihz (%f)\n", temp, dsp->sblatcho); sb_dsp_log("Sample rate - %ihz (%f)\n", temp, dsp->sblatcho);
pclog("Sample rate - %ihz (%f)\n", temp, dsp->sblatcho); pclog("Sample rate - %ihz (%f)\n", temp, dsp->sblatcho);
// if ((dsp->sb_freq != temp) && (IS_ESS(dsp) || (dsp->sb_type >= SB16)))
if ((dsp->sb_freq != temp) && (dsp->sb_type >= SB16)) if ((dsp->sb_freq != temp) && (dsp->sb_type >= SB16))
recalc_sb16_filter(0, temp); recalc_sb16_filter(0, temp);
dsp->sb_freq = temp; dsp->sb_freq = temp;
@@ -1165,7 +1203,7 @@ sb_exec_command(sb_dsp_t *dsp)
dsp->sb_timeo = 256LL + dsp->sb_freq; dsp->sb_timeo = 256LL + dsp->sb_freq;
dsp->sblatchi = dsp->sblatcho; dsp->sblatchi = dsp->sblatcho;
dsp->sb_timei = dsp->sb_timeo; dsp->sb_timei = dsp->sb_timeo;
if (dsp->sb_freq != temp && dsp->sb_type >= SB16) if ((dsp->sb_freq != temp) && (dsp->sb_type >= SB16))
recalc_sb16_filter(0, dsp->sb_freq); recalc_sb16_filter(0, dsp->sb_freq);
dsp->sb_8051_ram[0x13] = dsp->sb_freq & 0xff; dsp->sb_8051_ram[0x13] = dsp->sb_freq & 0xff;
dsp->sb_8051_ram[0x14] = (dsp->sb_freq >> 8) & 0xff; dsp->sb_8051_ram[0x14] = (dsp->sb_freq >> 8) & 0xff;
@@ -1731,14 +1769,30 @@ sb_dsp_init(sb_dsp_t *dsp, int type, int subtype, void *parent)
timer_add(&dsp->wb_timer, NULL, dsp, 0); timer_add(&dsp->wb_timer, NULL, dsp, 0);
timer_add(&dsp->irq_timer, sb_dsp_irq_poll, dsp, 0); timer_add(&dsp->irq_timer, sb_dsp_irq_poll, dsp, 0);
/* Initialise SB16 filter to same cutoff as 8-bit SBs (3.2 kHz). This will be recalculated when if (IS_ESS(dsp))
a set frequency command is sent. */ /* Initialize ESS filter to 8 kHz. This will be recalculated when a set frequency command is
recalc_sb16_filter(0, 3200 * 2); sent. */
if (dsp->sb_has_real_opl) recalc_sb16_filter(0, 8000 * 2);
recalc_sb16_filter(1, FREQ_49716);
else else
recalc_sb16_filter(1, FREQ_48000); /* Initialise SB16 filter to same cutoff as 8-bit SBs (3.2 kHz). This will be recalculated when
recalc_sb16_filter(2, FREQ_44100); a set frequency command is sent. */
recalc_sb16_filter(0, 3200 * 2);
if (IS_ESS(dsp) || (dsp->sb_type >= SBPRO2)) {
/* OPL3 or dual OPL2 is stereo. */
if (dsp->sb_has_real_opl)
recalc_opl_filter(1, FREQ_49716 * 2);
else
recalc_sb16_filter(1, FREQ_48000 * 2);
} else {
/* OPL2 is mono. */
if (dsp->sb_has_real_opl)
recalc_opl_filter(1, FREQ_49716);
else
recalc_sb16_filter(1, FREQ_48000);
}
/* CD Audio is stereo. */
recalc_sb16_filter(2, FREQ_44100 * 2);
/* PC speaker is mono. */
recalc_sb16_filter(3, 18939); recalc_sb16_filter(3, 18939);
/* Initialize SB16 8051 RAM and ASP internal RAM */ /* Initialize SB16 8051 RAM and ASP internal RAM */