GBHawk: upgrade audio to use blip buffer (avoids some high frequency aliasing)

This commit is contained in:
alyosha-tas 2018-04-28 14:50:58 -04:00
parent ca0ae3d971
commit 2fbdc00183
2 changed files with 71 additions and 30 deletions

View File

@ -12,6 +12,9 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
{ {
public GBHawk Core { get; set; } public GBHawk Core { get; set; }
private readonly BlipBuffer _blip_L = new BlipBuffer(15000);
private readonly BlipBuffer _blip_R = new BlipBuffer(15000);
public static int[] DUTY_CYCLES = new int[] {0, 0, 0, 0, 0, 0, 0, 1, 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, 0, 0, 1,
1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1,
@ -106,8 +109,12 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
public int sequencer_len, sequencer_vol, sequencer_swp, sequencer_tick; public int sequencer_len, sequencer_vol, sequencer_swp, sequencer_tick;
public byte sample;
public int master_audio_clock; public int master_audio_clock;
public int latched_sample_L, latched_sample_R;
public byte ReadReg(int addr) public byte ReadReg(int addr)
{ {
byte ret = 0; byte ret = 0;
@ -502,7 +509,10 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
{ {
if (WAVE_can_get || Core.is_GBC) { Wave_RAM[WAVE_wave_cntr >> 1] = value; } if (WAVE_can_get || Core.is_GBC) { Wave_RAM[WAVE_wave_cntr >> 1] = value; }
} }
else { Wave_RAM[addr & 0xF] = value; } else
{
Wave_RAM[addr & 0xF] = value;
}
break; break;
} }
@ -620,13 +630,9 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
if (WAVE_intl_cntr == 0) if (WAVE_intl_cntr == 0)
{ {
WAVE_intl_cntr = (2048 - WAVE_frq) * 2;
WAVE_wave_cntr++;
WAVE_wave_cntr &= 0x1F;
WAVE_can_get = true; WAVE_can_get = true;
byte sample = Wave_RAM[WAVE_wave_cntr >> 1]; WAVE_intl_cntr = (2048 - WAVE_frq) * 2;
if ((WAVE_wave_cntr & 1) == 0) if ((WAVE_wave_cntr & 1) == 0)
{ {
@ -652,6 +658,11 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
WAVE_output = sample; WAVE_output = sample;
// NOTE: The sample buffer is only reloaded after the current sample is played, even if just triggered
WAVE_wave_cntr++;
WAVE_wave_cntr &= 0x1F;
sample = Wave_RAM[WAVE_wave_cntr >> 1];
if (!WAVE_DAC_pow) { WAVE_output = 0; } if (!WAVE_DAC_pow) { WAVE_output = 0; }
// avoid aliasing at high frequenices // avoid aliasing at high frequenices
@ -697,23 +708,23 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
if (AUD_CTRL_wave_R_en) { R_final += WAVE_output; } if (AUD_CTRL_wave_R_en) { R_final += WAVE_output; }
if (AUD_CTRL_noise_R_en) { R_final += NOISE_output; } if (AUD_CTRL_noise_R_en) { R_final += NOISE_output; }
L_final *= (AUD_CTRL_vol_L + 1); L_final *= (AUD_CTRL_vol_L + 1) * 40;
R_final *= (AUD_CTRL_vol_R + 1); R_final *= (AUD_CTRL_vol_R + 1) * 40;
// send out an actual sample every 94 cycles if (L_final != latched_sample_L)
master_audio_clock++;
if (master_audio_clock == 94)
{ {
master_audio_clock = 0; _blip_L.AddDelta((uint)master_audio_clock, L_final - latched_sample_L);
if (AudioClocks < 1500) latched_sample_L = L_final;
{
AudioSamples[AudioClocks] = (short)(L_final * 20);
AudioClocks++;
AudioSamples[AudioClocks] = (short)(R_final * 20);
AudioClocks++;
}
} }
if (R_final != latched_sample_R)
{
_blip_R.AddDelta((uint)master_audio_clock, R_final - latched_sample_R);
latched_sample_R = R_final;
}
master_audio_clock++;
// frame sequencer ticks at a rate of 512 hz (or every time a 13 bit counter rolls over) // frame sequencer ticks at a rate of 512 hz (or every time a 13 bit counter rolls over)
sequencer_tick++; sequencer_tick++;
@ -905,9 +916,17 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
public void Reset() public void Reset()
{ {
Wave_RAM = new byte[] { 0x84, 0x40, 0x43, 0xAA, 0x2D, 0x78, 0x92, 0x3C, if (Core.is_GBC)
{
Wave_RAM = new byte[] { 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF,
0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF };
}
else
{
Wave_RAM = new byte[] { 0x84, 0x40, 0x43, 0xAA, 0x2D, 0x78, 0x92, 0x3C,
0x60, 0x59, 0x59, 0xB0, 0x34, 0xB8, 0x2E, 0xDA }; 0x60, 0x59, 0x59, 0xB0, 0x34, 0xB8, 0x2E, 0xDA };
}
Audio_Regs = new byte[21]; Audio_Regs = new byte[21];
AudioClocks = 0; AudioClocks = 0;
@ -917,6 +936,11 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
sequencer_swp = 0; sequencer_swp = 0;
sequencer_vol = 0; sequencer_vol = 0;
sequencer_tick = 0; sequencer_tick = 0;
sample = 0;
_blip_L.SetRates(4194304, 44100);
_blip_R.SetRates(4194304, 44100);
} }
public void SyncState(Serializer ser) public void SyncState(Serializer ser)
@ -1007,6 +1031,10 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
ser.Sync("master_audio_clock", ref master_audio_clock); ser.Sync("master_audio_clock", ref master_audio_clock);
ser.Sync("sample", ref sample);
ser.Sync("latched_sample_L", ref latched_sample_L);
ser.Sync("latched_sample_R", ref latched_sample_R);
ser.Sync("AUD_CTRL_vin_L_en", ref AUD_CTRL_vin_L_en); ser.Sync("AUD_CTRL_vin_L_en", ref AUD_CTRL_vin_L_en);
ser.Sync("AUD_CTRL_vin_R_en", ref AUD_CTRL_vin_R_en); ser.Sync("AUD_CTRL_vin_R_en", ref AUD_CTRL_vin_R_en);
ser.Sync("AUD_CTRL_sq1_L_en", ref AUD_CTRL_sq1_L_en); ser.Sync("AUD_CTRL_sq1_L_en", ref AUD_CTRL_sq1_L_en);
@ -1037,7 +1065,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
public bool CanProvideAsync => false; public bool CanProvideAsync => false;
public int AudioClocks; public int AudioClocks;
public short[] AudioSamples = new short[1500]; public short[] AudioSamples = new short[150000];
public void SetSyncMode(SyncSoundMode mode) public void SetSyncMode(SyncSoundMode mode)
{ {
@ -1051,17 +1079,19 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
public void GetSamplesSync(out short[] samples, out int nsamp) public void GetSamplesSync(out short[] samples, out int nsamp)
{ {
nsamp = AudioClocks / 2; _blip_L.EndFrame((uint)master_audio_clock);
short[] temp_samp = new short[AudioClocks]; _blip_R.EndFrame((uint)master_audio_clock);
nsamp = _blip_R.SamplesAvailable();
for (int i = 0; i < AudioClocks; i++) samples = new short[nsamp * 2];
{
temp_samp[i] = AudioSamples[i];
}
samples = temp_samp; _blip_L.ReadSamplesLeft(samples, nsamp);
_blip_R.ReadSamplesRight(samples, nsamp);
AudioClocks = 0; AudioClocks = 0;
master_audio_clock = 0;
} }
public void GetSamplesAsync(short[] samples) public void GetSamplesAsync(short[] samples)
@ -1072,6 +1102,9 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
public void DiscardSamples() public void DiscardSamples()
{ {
AudioClocks = 0; AudioClocks = 0;
_blip_L.Clear();
_blip_R.Clear();
master_audio_clock = 0;
} }
private void GetSamples(short[] samples) private void GetSamples(short[] samples)
@ -1080,5 +1113,11 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
} }
#endregion #endregion
public void DisposeSound()
{
_blip_L.Dispose();
_blip_R.Dispose();
}
} }
} }

View File

@ -156,7 +156,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
} }
ticker++; ticker++;
if (ticker > 10000000) { vblank_rise = true; }//throw new Exception("ERROR: Unable to Resolve Frame"); } //if (ticker > 10000000) { vblank_rise = true; }//throw new Exception("ERROR: Unable to Resolve Frame"); }
in_vblank_old = in_vblank; in_vblank_old = in_vblank;
} }
@ -216,6 +216,8 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
Marshal.FreeHGlobal(iptr1); Marshal.FreeHGlobal(iptr1);
Marshal.FreeHGlobal(iptr2); Marshal.FreeHGlobal(iptr2);
Marshal.FreeHGlobal(iptr3); Marshal.FreeHGlobal(iptr3);
audio.DisposeSound();
} }
#region Video provider #region Video provider