GBHawk: proper bias emulation in audio, still needs some refinement but everything is in place.
This commit is contained in:
parent
4bfb4ab00d
commit
b1d17b0a57
|
@ -14,10 +14,10 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
|
|||
private BlipBuffer _blip_L = new BlipBuffer(15000);
|
||||
private BlipBuffer _blip_R = new BlipBuffer(15000);
|
||||
|
||||
public static int[] DUTY_CYCLES = new int[] {0, 0, 0, 0, 0, 0, 0, 1,
|
||||
1, 0, 0, 0, 0, 0, 0, 1,
|
||||
1, 0, 0, 0, 0, 1, 1, 1,
|
||||
0, 1, 1, 1, 1, 1, 1, 0};
|
||||
public static bool[] DUTY_CYCLES = new bool[] {false, false, false, false, false, false, false, true,
|
||||
true, false, false, false, false, false, false, true,
|
||||
true, false, false, false, false, true, true, true,
|
||||
false, true, true, true, true, true, true, false};
|
||||
|
||||
public static int[] DIVISOR = new int[] { 8, 16, 32, 48, 64, 80, 96, 112 };
|
||||
|
||||
|
@ -115,6 +115,8 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
|
|||
|
||||
public int latched_sample_L, latched_sample_R;
|
||||
|
||||
public int SQ1_bias_gain, SQ2_bias_gain, WAVE_bias_gain, NOISE_bias_gain;
|
||||
|
||||
public byte ReadReg(int addr)
|
||||
{
|
||||
byte ret = 0;
|
||||
|
@ -187,7 +189,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
|
|||
SQ1_negate = (value & 8) > 0;
|
||||
SQ1_shift = (byte)(value & 7);
|
||||
|
||||
if (!SQ1_negate && SQ1_calc_done) { SQ1_enable = false; SQ1_output = 0; }
|
||||
if (!SQ1_negate && SQ1_calc_done) { SQ1_enable = false; calculate_bias_gain_1(); }
|
||||
break;
|
||||
case 0xFF11: // NR11 (sound length / wave pattern duty %)
|
||||
Audio_Regs[NR11] = value;
|
||||
|
@ -208,9 +210,10 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
|
|||
|
||||
SQ1_vol_state &= 0xF;
|
||||
|
||||
if ((value & 0xF8) == 0) { SQ1_enable = SQ1_swp_enable = false; SQ1_output = 0; }
|
||||
if (!SQ1_enable && (SQ1_st_vol >= 8)) { SQ1_output = 8; }
|
||||
if ((value & 0xF8) == 0) { SQ1_enable = SQ1_swp_enable = false; }
|
||||
Audio_Regs[NR12] = value;
|
||||
|
||||
calculate_bias_gain_1();
|
||||
break;
|
||||
case 0xFF13: // NR13 (freq low)
|
||||
Audio_Regs[NR13] = value;
|
||||
|
@ -228,7 +231,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
|
|||
if (!SQ1_len_en && ((value & 0x40) > 0) && (SQ1_len_cntr > 0))
|
||||
{
|
||||
SQ1_len_cntr--;
|
||||
if ((SQ1_len_cntr == 0) && !SQ1_trigger) { SQ1_enable = SQ1_swp_enable = false; SQ1_output = 0; }
|
||||
if ((SQ1_len_cntr == 0) && !SQ1_trigger) { SQ1_enable = SQ1_swp_enable = false; }
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -268,17 +271,17 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
|
|||
// disable channel if overflow
|
||||
if ((uint)shadow_frq > 2047)
|
||||
{
|
||||
SQ1_enable = SQ1_swp_enable = false; SQ1_output = 0;
|
||||
SQ1_enable = SQ1_swp_enable = false;
|
||||
}
|
||||
|
||||
// set negate mode flag that disables channel is negate clerar
|
||||
if (SQ1_negate) { SQ1_calc_done = true; }
|
||||
}
|
||||
|
||||
if ((SQ1_vol_state == 0) && !SQ1_env_add) { SQ1_enable = SQ1_swp_enable = false; SQ1_output = 0; }
|
||||
//if ((SQ1_vol_state == 0) && (SQ1_per == 0) && SQ1_env_add) { SQ1_vol_state = 16; }
|
||||
if ((SQ1_vol_state == 0) && !SQ1_env_add) { SQ1_enable = SQ1_swp_enable = false; }
|
||||
}
|
||||
|
||||
calculate_bias_gain_1();
|
||||
SQ1_len_en = (value & 0x40) > 0;
|
||||
break;
|
||||
case 0xFF16: // NR21 (sound length / wave pattern duty %)
|
||||
|
@ -299,9 +302,10 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
|
|||
if (((Audio_Regs[NR22] ^ value) & 8) > 0) { SQ2_vol_state = (byte)(0x10 - SQ2_vol_state); }
|
||||
|
||||
SQ2_vol_state &= 0xF;
|
||||
if ((value & 0xF8) == 0) { SQ2_enable = false; SQ2_output = 0; }
|
||||
if (!SQ2_enable && (SQ2_st_vol >= 8)) { SQ2_output = 8; }
|
||||
if ((value & 0xF8) == 0) { SQ2_enable = false; }
|
||||
Audio_Regs[NR22] = value;
|
||||
|
||||
calculate_bias_gain_2();
|
||||
break;
|
||||
case 0xFF18: // NR23 (freq low)
|
||||
Audio_Regs[NR23] = value;
|
||||
|
@ -319,7 +323,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
|
|||
if (!SQ2_len_en && ((value & 0x40) > 0) && (SQ2_len_cntr > 0))
|
||||
{
|
||||
SQ2_len_cntr--;
|
||||
if ((SQ2_len_cntr == 0) && !SQ2_trigger) { SQ2_enable = false; SQ2_output = 0; }
|
||||
if ((SQ2_len_cntr == 0) && !SQ2_trigger) { SQ2_enable = false; }
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -336,16 +340,16 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
|
|||
SQ2_intl_cntr = (2048 - SQ2_frq) * 4;
|
||||
SQ2_vol_state = SQ2_st_vol;
|
||||
SQ2_vol_per = (SQ2_per > 0) ? SQ2_per : 8;
|
||||
if ((SQ2_vol_state == 0) && !SQ2_env_add) { SQ2_enable = false; SQ2_output = 0; }
|
||||
//if ((SQ2_vol_state == 0) && (SQ2_per == 0) && SQ2_env_add) { SQ2_vol_state = 16; }
|
||||
if ((SQ2_vol_state == 0) && !SQ2_env_add) { SQ2_enable = false; }
|
||||
}
|
||||
|
||||
calculate_bias_gain_2();
|
||||
SQ2_len_en = (value & 0x40) > 0;
|
||||
break;
|
||||
case 0xFF1A: // NR30 (on/off)
|
||||
Audio_Regs[NR30] = value;
|
||||
WAVE_DAC_pow = (value & 0x80) > 0;
|
||||
if (!WAVE_DAC_pow) { WAVE_enable = false; }
|
||||
//calculate_bias_gain_w();
|
||||
break;
|
||||
case 0xFF1B: // NR31 (length)
|
||||
Audio_Regs[NR31] = value;
|
||||
|
@ -405,11 +409,11 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
|
|||
}
|
||||
WAVE_intl_cntr = (2048 - WAVE_frq) * 2 + 6; // trigger delay for wave channel
|
||||
WAVE_wave_cntr = 0;
|
||||
if (!WAVE_DAC_pow) { WAVE_enable = false; /*WAVE_output = 0;*/ }
|
||||
if (!WAVE_DAC_pow) { WAVE_enable = false; }
|
||||
}
|
||||
|
||||
//calculate_bias_gain_w();
|
||||
WAVE_len_en = (value & 0x40) > 0;
|
||||
|
||||
break;
|
||||
case 0xFF20: // NR41 (length)
|
||||
Audio_Regs[NR41] = value;
|
||||
|
@ -428,9 +432,10 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
|
|||
if (((Audio_Regs[NR42] ^ value) & 8) > 0) { NOISE_vol_state = (byte)(0x10 - NOISE_vol_state); }
|
||||
|
||||
NOISE_vol_state &= 0xF;
|
||||
if ((value & 0xF8) == 0) { NOISE_enable = false; NOISE_output = 0; }
|
||||
if (!NOISE_enable && (NOISE_st_vol >= 8)) { NOISE_output = 8; }
|
||||
if ((value & 0xF8) == 0) { NOISE_enable = false; }
|
||||
Audio_Regs[NR42] = value;
|
||||
|
||||
calculate_bias_gain_n();
|
||||
break;
|
||||
case 0xFF22: // NR43 (shift)
|
||||
Audio_Regs[NR43] = value;
|
||||
|
@ -447,7 +452,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
|
|||
if (!NOISE_len_en && ((value & 0x40) > 0) && (NOISE_len_cntr > 0))
|
||||
{
|
||||
NOISE_len_cntr--;
|
||||
if ((NOISE_len_cntr == 0) && !NOISE_trigger) { NOISE_enable = false; NOISE_output = 0; }
|
||||
if ((NOISE_len_cntr == 0) && !NOISE_trigger) { NOISE_enable = false; }
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -465,9 +470,10 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
|
|||
NOISE_vol_state = NOISE_st_vol;
|
||||
NOISE_vol_per = (NOISE_per > 0) ? NOISE_per : 8;
|
||||
NOISE_LFSR = 0x7FFF;
|
||||
if ((NOISE_vol_state == 0) && !NOISE_env_add) { NOISE_enable = false; NOISE_output = 0; }
|
||||
if ((NOISE_vol_state == 0) && !NOISE_env_add) { NOISE_enable = false; }
|
||||
}
|
||||
|
||||
calculate_bias_gain_n();
|
||||
NOISE_len_en = (value & 0x40) > 0;
|
||||
break;
|
||||
case 0xFF24: // NR50 (ctrl)
|
||||
|
@ -476,6 +482,8 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
|
|||
AUD_CTRL_vol_L = (byte)((value & 0x70) >> 4);
|
||||
AUD_CTRL_vin_R_en = (value & 8) > 0;
|
||||
AUD_CTRL_vol_R = (byte)(value & 7);
|
||||
|
||||
calculate_bias_gain_a();
|
||||
break;
|
||||
case 0xFF25: // NR51 (ctrl)
|
||||
Audio_Regs[NR51] = value;
|
||||
|
@ -487,6 +495,8 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
|
|||
AUD_CTRL_wave_R_en = (value & 4) > 0;
|
||||
AUD_CTRL_sq2_R_en = (value & 2) > 0;
|
||||
AUD_CTRL_sq1_R_en = (value & 1) > 0;
|
||||
|
||||
calculate_bias_gain_a();
|
||||
break;
|
||||
case 0xFF26: // NR52 (ctrl)
|
||||
// NOTE: Make sure to do the power off first since it will call the write_reg function again
|
||||
|
@ -602,8 +612,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
|
|||
SQ1_duty_cntr++;
|
||||
SQ1_duty_cntr &= 7;
|
||||
|
||||
SQ1_output = DUTY_CYCLES[SQ1_duty * 8 + SQ1_duty_cntr];
|
||||
SQ1_output *= SQ1_vol_state;
|
||||
SQ1_output = DUTY_CYCLES[SQ1_duty * 8 + SQ1_duty_cntr] ? SQ1_vol_state : SQ1_bias_gain;
|
||||
|
||||
// avoid aliasing at high frequenices
|
||||
//if (SQ1_frq > 0x7F0) { SQ1_output = 0; }
|
||||
|
@ -620,8 +629,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
|
|||
SQ2_duty_cntr++;
|
||||
SQ2_duty_cntr &= 7;
|
||||
|
||||
SQ2_output = DUTY_CYCLES[SQ2_duty * 8 + SQ2_duty_cntr];
|
||||
SQ2_output *= SQ2_vol_state;
|
||||
SQ2_output = DUTY_CYCLES[SQ2_duty * 8 + SQ2_duty_cntr] ? SQ2_vol_state : SQ2_bias_gain;
|
||||
|
||||
// avoid aliasing at high frequenices
|
||||
//if (SQ2_frq > 0x7F0) { SQ2_output = 0; }
|
||||
|
@ -689,8 +697,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
|
|||
NOISE_LFSR |= (bit_lfsr << 6);
|
||||
}
|
||||
|
||||
NOISE_output = (NOISE_LFSR & 1) > 0 ? 0 : 1;
|
||||
NOISE_output *= NOISE_vol_state;
|
||||
NOISE_output = (NOISE_LFSR & 1) > 0 ? NOISE_bias_gain : NOISE_vol_state;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -742,22 +749,22 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
|
|||
if (SQ1_len_en && SQ1_len_cntr > 0)
|
||||
{
|
||||
SQ1_len_cntr--;
|
||||
if (SQ1_len_cntr == 0) { SQ1_enable = SQ1_swp_enable = false; SQ1_output = 0; }
|
||||
if (SQ1_len_cntr == 0) { SQ1_enable = SQ1_swp_enable = false; calculate_bias_gain_1(); }
|
||||
}
|
||||
if (SQ2_len_en && SQ2_len_cntr > 0)
|
||||
{
|
||||
SQ2_len_cntr--;
|
||||
if (SQ2_len_cntr == 0) { SQ2_enable = false; SQ2_output = 0; }
|
||||
if (SQ2_len_cntr == 0) { SQ2_enable = false; calculate_bias_gain_2(); }
|
||||
}
|
||||
if (WAVE_len_en && WAVE_len_cntr > 0)
|
||||
{
|
||||
WAVE_len_cntr--;
|
||||
if (WAVE_len_cntr == 0) { WAVE_enable = false; }
|
||||
if (WAVE_len_cntr == 0) { WAVE_enable = false; calculate_bias_gain_w(); }
|
||||
}
|
||||
if (NOISE_len_en && NOISE_len_cntr > 0)
|
||||
{
|
||||
NOISE_len_cntr--;
|
||||
if (NOISE_len_cntr == 0) { NOISE_enable = false; NOISE_output = 0; }
|
||||
if (NOISE_len_cntr == 0) { NOISE_enable = false; calculate_bias_gain_n(); }
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -782,7 +789,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
|
|||
// disable channel if overflow
|
||||
if ((uint)shadow_frq > 2047)
|
||||
{
|
||||
SQ1_enable = SQ1_swp_enable = false; SQ1_output = 0;
|
||||
SQ1_enable = SQ1_swp_enable = false; calculate_bias_gain_1();
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -805,7 +812,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
|
|||
|
||||
if ((uint)shadow_frq > 2047)
|
||||
{
|
||||
SQ1_enable = SQ1_swp_enable = false; SQ1_output = 0;
|
||||
SQ1_enable = SQ1_swp_enable = false; calculate_bias_gain_1();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -893,6 +900,8 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
|
|||
WriteReg(0xFF10 + i, 0);
|
||||
}
|
||||
|
||||
calculate_bias_gain_a();
|
||||
|
||||
// duty and length are reset
|
||||
SQ1_duty_cntr = SQ2_duty_cntr = 0;
|
||||
|
||||
|
@ -935,6 +944,8 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
|
|||
WriteReg(0xFF10 + i, 0);
|
||||
}
|
||||
|
||||
calculate_bias_gain_a();
|
||||
|
||||
SQ1_duty_cntr = SQ2_duty_cntr = 0;
|
||||
|
||||
SQ1_enable = SQ1_swp_enable = SQ2_enable = WAVE_enable = NOISE_enable = false;
|
||||
|
@ -958,6 +969,103 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
|
|||
_blip_R.SetRates(4194304, 44100);
|
||||
}
|
||||
|
||||
public void calculate_bias_gain_a()
|
||||
{
|
||||
if ((AUD_CTRL_sq1_R_en | AUD_CTRL_sq1_L_en) && ((Audio_Regs[NR12] & 0xF8) > 0))
|
||||
{
|
||||
SQ1_bias_gain = (AUD_CTRL_vol_R | AUD_CTRL_vol_L) >> 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
SQ1_bias_gain = 0;
|
||||
}
|
||||
if ((AUD_CTRL_sq2_R_en | AUD_CTRL_sq2_L_en) && ((Audio_Regs[NR22] & 0xF8) > 0))
|
||||
{
|
||||
SQ2_bias_gain = (AUD_CTRL_vol_R | AUD_CTRL_vol_L) >> 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
SQ2_bias_gain = 0;
|
||||
}
|
||||
if ((AUD_CTRL_wave_R_en | AUD_CTRL_wave_L_en) && WAVE_DAC_pow)
|
||||
{
|
||||
WAVE_bias_gain = (AUD_CTRL_vol_R | AUD_CTRL_vol_L) >> 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
WAVE_bias_gain = 0;
|
||||
}
|
||||
if ((AUD_CTRL_noise_R_en | AUD_CTRL_noise_L_en) && ((Audio_Regs[NR42] & 0xF8) > 0))
|
||||
{
|
||||
NOISE_bias_gain = (AUD_CTRL_vol_R | AUD_CTRL_vol_L) >> 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
NOISE_bias_gain = 0;
|
||||
}
|
||||
|
||||
if (!SQ1_enable) { SQ1_output = (AUD_CTRL_vol_R | AUD_CTRL_vol_L) >> 1; }
|
||||
if (!SQ2_enable) { SQ2_output = (AUD_CTRL_vol_R | AUD_CTRL_vol_L) >> 1; }
|
||||
//if (!WAVE_enable) { WAVE_output = (AUD_CTRL_vol_R | AUD_CTRL_vol_L) >> 1; }
|
||||
if (!NOISE_enable) { NOISE_output = (AUD_CTRL_vol_R | AUD_CTRL_vol_L) >> 2; }
|
||||
}
|
||||
|
||||
public void calculate_bias_gain_1()
|
||||
{
|
||||
if ((AUD_CTRL_sq1_R_en | AUD_CTRL_sq1_L_en) && ((Audio_Regs[NR12] & 0xF8) > 0))
|
||||
{
|
||||
SQ1_bias_gain = (AUD_CTRL_vol_R | AUD_CTRL_vol_L) >> 3;
|
||||
}
|
||||
else
|
||||
{
|
||||
SQ1_bias_gain = 0;
|
||||
}
|
||||
|
||||
if (!SQ1_enable) { SQ1_output = (AUD_CTRL_vol_R | AUD_CTRL_vol_L) >> 1; }
|
||||
}
|
||||
|
||||
public void calculate_bias_gain_2()
|
||||
{
|
||||
if ((AUD_CTRL_sq2_R_en | AUD_CTRL_sq2_L_en) && ((Audio_Regs[NR22] & 0xF8) > 0))
|
||||
{
|
||||
SQ2_bias_gain = (AUD_CTRL_vol_R | AUD_CTRL_vol_L) >> 3;
|
||||
}
|
||||
else
|
||||
{
|
||||
SQ2_bias_gain = 0;
|
||||
}
|
||||
|
||||
if (!SQ2_enable) { SQ2_output = (AUD_CTRL_vol_R | AUD_CTRL_vol_L) >> 1; }
|
||||
}
|
||||
|
||||
public void calculate_bias_gain_w()
|
||||
{
|
||||
if ((AUD_CTRL_wave_R_en | AUD_CTRL_wave_L_en) && WAVE_DAC_pow)
|
||||
{
|
||||
WAVE_bias_gain = (AUD_CTRL_vol_R | AUD_CTRL_vol_L) >> 3;
|
||||
}
|
||||
else
|
||||
{
|
||||
WAVE_bias_gain = 0;
|
||||
}
|
||||
|
||||
if (!WAVE_enable) { WAVE_output = (AUD_CTRL_vol_R | AUD_CTRL_vol_L) >> 1; }
|
||||
}
|
||||
|
||||
public void calculate_bias_gain_n()
|
||||
{
|
||||
if ((AUD_CTRL_noise_R_en | AUD_CTRL_noise_L_en) && ((Audio_Regs[NR42] & 0xF8) > 0))
|
||||
{
|
||||
NOISE_bias_gain = (AUD_CTRL_vol_R | AUD_CTRL_vol_L) >> 3;
|
||||
}
|
||||
else
|
||||
{
|
||||
NOISE_bias_gain = 0;
|
||||
}
|
||||
|
||||
if (!NOISE_enable) { NOISE_output = (AUD_CTRL_vol_R | AUD_CTRL_vol_L) >> 2; }
|
||||
}
|
||||
|
||||
public void SyncState(Serializer ser)
|
||||
{
|
||||
ser.Sync(nameof(Audio_Regs), ref Audio_Regs, false);
|
||||
|
@ -1059,6 +1167,11 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
|
|||
ser.Sync(nameof(AUD_CTRL_power), ref AUD_CTRL_power);
|
||||
ser.Sync(nameof(AUD_CTRL_vol_L), ref AUD_CTRL_vol_L);
|
||||
ser.Sync(nameof(AUD_CTRL_vol_R), ref AUD_CTRL_vol_R);
|
||||
|
||||
ser.Sync(nameof(SQ1_bias_gain), ref SQ1_bias_gain);
|
||||
ser.Sync(nameof(SQ2_bias_gain), ref SQ2_bias_gain);
|
||||
ser.Sync(nameof(WAVE_bias_gain), ref WAVE_bias_gain);
|
||||
ser.Sync(nameof(NOISE_bias_gain), ref NOISE_bias_gain);
|
||||
}
|
||||
|
||||
public byte Read_NR52()
|
||||
|
|
Loading…
Reference in New Issue