Switching filter implementation to use SB16 filters; fixing CD audio volume
This commit is contained in:
@@ -150,7 +150,7 @@ ess_mixer_write(uint16_t addr, uint8_t val, void *priv)
|
||||
/* Initialize ESS regs. */
|
||||
mixer->regs[0x14] = mixer->regs[0x32] = 0x88;
|
||||
mixer->regs[0x36] = 0x88;
|
||||
mixer->regs[0x38] = 0x00;
|
||||
mixer->regs[0x38] = 0x88;
|
||||
mixer->regs[0x3a] = 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? */
|
||||
if (mixer->output_filter) {
|
||||
out_l += (sb_iir(0, 0, (double) ess->dsp.buffer[c]) * mixer->voice_l) / 3.9;
|
||||
out_r += (sb_iir(0, 1, (double) ess->dsp.buffer[c + 1]) * mixer->voice_r) / 3.9;
|
||||
out_l += (low_fir_sb16(0, 0, (double) ess->dsp.buffer[c]) * mixer->voice_l) / 3.0;
|
||||
out_r += (low_fir_sb16(0, 1, (double) ess->dsp.buffer[c + 1]) * mixer->voice_r) / 3.0;
|
||||
} else {
|
||||
out_l += (ess->dsp.buffer[c] * mixer->voice_l) / 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 master = channel ? mixer->master_r : mixer->master_l;
|
||||
|
||||
if (mixer->output_filter)
|
||||
c = (sb_iir(2, channel, *buffer) * cd) / 3.9;
|
||||
else
|
||||
c = (*buffer * cd) / 3.0;
|
||||
c = (*buffer * cd) / 3.0;
|
||||
*buffer = c * master;
|
||||
}
|
||||
|
||||
|
@@ -175,6 +175,37 @@ recalc_sb16_filter(int c, int playback_freq)
|
||||
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
|
||||
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;
|
||||
}
|
||||
|
||||
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.
|
||||
(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)
|
||||
{
|
||||
double temp = (7160000.0 / (((((double) dsp->sb_freq) / 2.0) * 0.80) * 82.0)) - 256.0;
|
||||
|
||||
if (dsp->sb_freq >= 22050)
|
||||
ESSreg(0xA1) = 256 - (795500UL / dsp->sb_freq);
|
||||
else
|
||||
ESSreg(0xA1) = 128 - (397700UL / dsp->sb_freq);
|
||||
|
||||
unsigned int freq = ((dsp->sb_freq * 4) / (5 * 2)); /* 80% of 1/2 the sample rate */
|
||||
ESSreg(0xA2) = 256 - (7160000 / (freq * 82));
|
||||
sb_ess_update_reg_a2(dsp, (uint8_t) temp);
|
||||
}
|
||||
|
||||
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);
|
||||
else
|
||||
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;
|
||||
dsp->sblatchi = dsp->sblatcho = TIMER_USEC * temp;
|
||||
dsp->sb_timei = dsp->sb_timeo;
|
||||
pclog("ess: Sample rate - %ihz (%f)\n", dsp->sb_freq, dsp->sblatcho);
|
||||
|
||||
break;
|
||||
}
|
||||
case 0xA2: /* Filter divider (effectively, a hardware lowpass filter under S/W control) */
|
||||
ESSreg(reg) = data;
|
||||
sb_ess_update_reg_a2(dsp, data);
|
||||
break;
|
||||
|
||||
case 0xA4: /* DMA Transfer Count Reload (low) */
|
||||
@@ -1147,6 +1184,7 @@ sb_exec_command(sb_dsp_t *dsp)
|
||||
temp = 1000000 / temp;
|
||||
sb_dsp_log("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))
|
||||
recalc_sb16_filter(0, temp);
|
||||
dsp->sb_freq = temp;
|
||||
@@ -1165,7 +1203,7 @@ sb_exec_command(sb_dsp_t *dsp)
|
||||
dsp->sb_timeo = 256LL + dsp->sb_freq;
|
||||
dsp->sblatchi = dsp->sblatcho;
|
||||
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);
|
||||
dsp->sb_8051_ram[0x13] = dsp->sb_freq & 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->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
|
||||
a set frequency command is sent. */
|
||||
recalc_sb16_filter(0, 3200 * 2);
|
||||
if (dsp->sb_has_real_opl)
|
||||
recalc_sb16_filter(1, FREQ_49716);
|
||||
if (IS_ESS(dsp))
|
||||
/* Initialize ESS filter to 8 kHz. This will be recalculated when a set frequency command is
|
||||
sent. */
|
||||
recalc_sb16_filter(0, 8000 * 2);
|
||||
else
|
||||
recalc_sb16_filter(1, FREQ_48000);
|
||||
recalc_sb16_filter(2, FREQ_44100);
|
||||
/* Initialise SB16 filter to same cutoff as 8-bit SBs (3.2 kHz). This will be recalculated when
|
||||
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);
|
||||
|
||||
/* Initialize SB16 8051 RAM and ASP internal RAM */
|
||||
|
Reference in New Issue
Block a user