GBAHawk start audio

This commit is contained in:
alyosha-tas 2017-11-14 11:59:32 -05:00
parent c18298c8a5
commit ff815dec65
1 changed files with 359 additions and 48 deletions

View File

@ -44,6 +44,52 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
public byte[] Wave_RAM = new byte [16];
struct AUD_Object
{
// channel controls
public byte swp_period;
public bool negate;
public byte shift;
public byte duty;
public byte length;
public byte st_vol;
public bool env_add;
public byte per;
public ushort frq;
public bool trigger;
public bool len_en;
public bool DAC_pow;
public byte vol_code;
public byte clk_shft;
public bool wdth_md;
public byte div_code;
// channel states
public byte length_counter;
}
struct CTRL_Object
{
public bool vin_L_en;
public bool vin_R_en;
public byte vol_L;
public byte vol_R;
public bool sq1_L_en;
public bool sq2_L_en;
public bool wave_L_en;
public bool noise_L_en;
public bool sq1_R_en;
public bool sq2_R_en;
public bool wave_R_en;
public bool noise_R_en;
public bool power;
}
AUD_Object SQ1, SQ2, WAVE, NOISE;
CTRL_Object AUD_CTRL;
public int sequencer_len, sequencer_vol, sequencer_swp, sequencer_tick;
public byte ReadReg(int addr)
{
@ -65,13 +111,13 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
case 0xFF1C: ret = (byte)(Audio_Regs[NR32] | unused_bits[NR32]); break; // NR32 (level output)
case 0xFF1D: ret = (byte)(Audio_Regs[NR33] | unused_bits[NR33]); break; // NR33 (freq low)
case 0xFF1E: ret = (byte)(Audio_Regs[NR34] | unused_bits[NR34]); break; // NR34 (freq hi)
case 0xFF20: ret = (byte)(Audio_Regs[NR41] | unused_bits[NR41]); break; // NR41 (sweep)
case 0xFF21: ret = (byte)(Audio_Regs[NR42] | unused_bits[NR42]); break; // NR42 (sweep)
case 0xFF22: ret = (byte)(Audio_Regs[NR43] | unused_bits[NR43]); break; // NR43 (sweep)
case 0xFF23: ret = (byte)(Audio_Regs[NR44] | unused_bits[NR44]); break; // NR44 (sweep)
case 0xFF24: ret = (byte)(Audio_Regs[NR50] | unused_bits[NR50]); break; // NR50 (sweep)
case 0xFF25: ret = (byte)(Audio_Regs[NR51] | unused_bits[NR51]); break; // NR51 (sweep)
case 0xFF26: ret = (byte)(Audio_Regs[NR52] | unused_bits[NR52]); break; // NR52 (sweep)
case 0xFF20: ret = (byte)(Audio_Regs[NR41] | unused_bits[NR41]); break; // NR41 (length)
case 0xFF21: ret = (byte)(Audio_Regs[NR42] | unused_bits[NR42]); break; // NR42 (envelope)
case 0xFF22: ret = (byte)(Audio_Regs[NR43] | unused_bits[NR43]); break; // NR43 (shift)
case 0xFF23: ret = (byte)(Audio_Regs[NR44] | unused_bits[NR44]); break; // NR44 (trigger)
case 0xFF24: ret = (byte)(Audio_Regs[NR50] | unused_bits[NR50]); break; // NR50 (ctrl)
case 0xFF25: ret = (byte)(Audio_Regs[NR51] | unused_bits[NR51]); break; // NR51 (ctrl)
case 0xFF26: ret = (byte)(Audio_Regs[NR52] | unused_bits[NR52]); break; // NR52 (ctrl)
// wave ram table
case 0xFF30:
@ -100,50 +146,201 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
public void WriteReg(int addr, byte value)
{
switch (addr)
// while power is on, everything is writable
if (AUD_CTRL.power)
{
case 0xFF10: Audio_Regs[NR10] = value; break; // NR10 (sweep)
case 0xFF11: Audio_Regs[NR11] = value; break; // NR11 (sound length / wave pattern duty %)
case 0xFF12: Audio_Regs[NR12] = value; break; // NR12 (envelope)
case 0xFF13: Audio_Regs[NR13] = value; break; // NR13 (freq low)
case 0xFF14: Audio_Regs[NR14] = value; break; // NR14 (freq hi)
case 0xFF16: Audio_Regs[NR21] = value; break; // NR21 (sound length / wave pattern duty %)
case 0xFF17: Audio_Regs[NR22] = value; break; // NR22 (envelope)
case 0xFF18: Audio_Regs[NR23] = value; break; // NR23 (freq low)
case 0xFF19: Audio_Regs[NR24] = value; break; // NR24 (freq hi)
case 0xFF1A: Audio_Regs[NR30] = value; break; // NR30 (on/off)
case 0xFF1B: Audio_Regs[NR31] = value; break; // NR31 (length)
case 0xFF1C: Audio_Regs[NR32] = value; break; // NR32 (level output)
case 0xFF1D: Audio_Regs[NR33] = value; break; // NR33 (freq low)
case 0xFF1E: Audio_Regs[NR34] = value; break; // NR34 (freq hi)
case 0xFF20: Audio_Regs[NR41] = value; break; // NR41 (sweep)
case 0xFF21: Audio_Regs[NR42] = value; break; // NR42 (sweep)
case 0xFF22: Audio_Regs[NR43] = value; break; // NR43 (sweep)
case 0xFF23: Audio_Regs[NR44] = value; break; // NR44 (sweep)
case 0xFF24: Audio_Regs[NR50] = value; break; // NR50 (sweep)
case 0xFF25: Audio_Regs[NR51] = value; break; // NR51 (sweep)
case 0xFF26: Audio_Regs[NR52] = value; break; // NR52 (sweep)
switch (addr)
{
case 0xFF10: // NR10 (sweep)
Audio_Regs[NR10] = value;
SQ1.swp_period = (byte)((value & 0x70) >> 4);
SQ1.negate = (value & 8) > 0;
SQ1.shift = (byte)(value & 7);
break;
case 0xFF11: // NR11 (sound length / wave pattern duty %)
Audio_Regs[NR11] = value;
SQ1.duty = (byte)((value & 0xC0) >> 6);
SQ1.length = (byte)(64 - value & 0x3F);
break;
case 0xFF12: // NR12 (envelope)
Audio_Regs[NR12] = value;
SQ1.st_vol = (byte)((value & 0xF0) >> 4);
SQ1.env_add = (value & 8) > 0;
SQ1.per = (byte)(value & 7);
break;
case 0xFF13: // NR13 (freq low)
Audio_Regs[NR13] = value;
SQ1.frq &= 0x700;
SQ1.frq |= value;
break;
case 0xFF14: // NR14 (freq hi)
Audio_Regs[NR14] = value;
SQ1.trigger = (value & 0x80) > 0;
SQ1.len_en = (value & 0x40) > 0;
SQ1.frq &= 0xFF;
SQ1.frq |= (ushort)((value & 7) << 8);
break;
case 0xFF16: // NR21 (sound length / wave pattern duty %)
Audio_Regs[NR21] = value;
SQ2.duty = (byte)((value & 0xC0) >> 6);
SQ2.length = (byte)(64 - value & 0x3F);
break;
case 0xFF17: // NR22 (envelope)
Audio_Regs[NR22] = value;
SQ2.st_vol = (byte)((value & 0xF0) >> 4);
SQ2.env_add = (value & 8) > 0;
SQ2.per = (byte)(value & 7);
break;
case 0xFF18: // NR23 (freq low)
Audio_Regs[NR23] = value;
SQ2.frq &= 0x700;
SQ2.frq |= value;
break;
case 0xFF19: // NR24 (freq hi)
Audio_Regs[NR24] = value;
SQ2.trigger = (value & 0x80) > 0;
SQ2.len_en = (value & 0x40) > 0;
SQ2.frq &= 0xFF;
SQ2.frq |= (ushort)((value & 7) << 8);
break;
case 0xFF1A: // NR30 (on/off)
Audio_Regs[NR30] = value;
WAVE.DAC_pow = (value & 0x80) > 0;
break;
case 0xFF1B: // NR31 (length)
Audio_Regs[NR31] = value;
WAVE.length = (byte)(256 - value);
break;
case 0xFF1C: // NR32 (level output)
Audio_Regs[NR32] = value;
WAVE.vol_code = (byte)((value & 0x60) >> 5);
break;
case 0xFF1D: // NR33 (freq low)
Audio_Regs[NR33] = value;
WAVE.frq &= 0x700;
WAVE.frq |= value;
break;
case 0xFF1E: // NR34 (freq hi)
Audio_Regs[NR34] = value;
WAVE.trigger = (value & 0x80) > 0;
WAVE.len_en = (value & 0x40) > 0;
WAVE.frq &= 0xFF;
WAVE.frq |= (ushort)((value & 7) << 8);
break;
case 0xFF20: // NR41 (length)
Audio_Regs[NR41] = value;
NOISE.length = (byte)(64 - value & 0x3F);
break;
case 0xFF21: // NR42 (envelope)
Audio_Regs[NR42] = value;
NOISE.st_vol = (byte)((value & 0xF0) >> 4);
NOISE.env_add = (value & 8) > 0;
NOISE.per = (byte)(value & 7);
break;
case 0xFF22: // NR43 (shift)
Audio_Regs[NR43] = value;
NOISE.clk_shft = (byte)((value & 0xF0) >> 4);
NOISE.wdth_md = (value & 8) > 0;
NOISE.div_code = (byte)(value & 7);
break;
case 0xFF23: // NR44 (trigger)
Audio_Regs[NR44] = value;
WAVE.trigger = (value & 0x80) > 0;
WAVE.len_en = (value & 0x40) > 0;
break;
case 0xFF24: // NR50 (ctrl)
Audio_Regs[NR50] = value;
AUD_CTRL.vin_L_en = (value & 0x80) > 0;
AUD_CTRL.vol_L = (byte)((value & 0x70) >> 4);
AUD_CTRL.vin_R_en = (value & 8) > 0;
AUD_CTRL.vol_R = (byte)(value & 7);
break;
case 0xFF25: // NR51 (ctrl)
Audio_Regs[NR51] = value;
AUD_CTRL.noise_L_en = (value & 0x80) > 0;
AUD_CTRL.wave_L_en = (value & 0x40) > 0;
AUD_CTRL.sq2_L_en = (value & 0x20) > 0;
AUD_CTRL.sq1_L_en = (value & 0x10) > 0;
AUD_CTRL.noise_R_en = (value & 8) > 0;
AUD_CTRL.wave_R_en = (value & 4) > 0;
AUD_CTRL.sq2_R_en = (value & 2) > 0;
AUD_CTRL.sq1_R_en = (value & 1) > 0;
break;
case 0xFF26: // NR52 (ctrl)
Audio_Regs[NR52] &= 0x7F;
Audio_Regs[NR52] |= (byte)(value & 0x80);
AUD_CTRL.power = (value & 0x80) > 0;
// wave ram table
case 0xFF30:
case 0xFF31:
case 0xFF32:
case 0xFF33:
case 0xFF34:
case 0xFF35:
case 0xFF36:
case 0xFF37:
case 0xFF38:
case 0xFF39:
case 0xFF3A:
case 0xFF3B:
case 0xFF3C:
case 0xFF3D:
case 0xFF3E:
case 0xFF3F:
Wave_RAM[addr & 0x0F] = value;
break;
if (!AUD_CTRL.power)
{
power_off();
}
break;
// wave ram table
case 0xFF30:
case 0xFF31:
case 0xFF32:
case 0xFF33:
case 0xFF34:
case 0xFF35:
case 0xFF36:
case 0xFF37:
case 0xFF38:
case 0xFF39:
case 0xFF3A:
case 0xFF3B:
case 0xFF3C:
case 0xFF3D:
case 0xFF3E:
case 0xFF3F:
Wave_RAM[addr & 0x0F] = value;
break;
}
}
// when power is off, only length counters and waveRAM are effected by writes
else
{
switch (addr)
{
case 0xFF11: // NR11 (sound length / wave pattern duty %)
SQ1.length = (byte)(64 - value & 0x3F);
break;
case 0xFF16: // NR21 (sound length / wave pattern duty %)
SQ2.length = (byte)(64 - value & 0x3F);
break;
case 0xFF1B: // NR31 (length)
WAVE.length = (byte)(256 - value);
break;
case 0xFF20: // NR41 (length)
NOISE.length = (byte)(64 - value & 0x3F);
break;
case 0xFF26: // NR52 (ctrl)
Audio_Regs[NR52] &= 0x7F;
Audio_Regs[NR52] |= (byte)(value & 0x80);
AUD_CTRL.power = (value & 0x80) > 0;
break;
// wave ram table
case 0xFF30:
case 0xFF31:
case 0xFF32:
case 0xFF33:
case 0xFF34:
case 0xFF35:
case 0xFF36:
case 0xFF37:
case 0xFF38:
case 0xFF39:
case 0xFF3A:
case 0xFF3B:
case 0xFF3C:
case 0xFF3D:
case 0xFF3E:
case 0xFF3F:
Wave_RAM[addr & 0x0F] = value;
break;
}
}
}
@ -152,11 +349,30 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
}
public void power_off()
{
for (int i = 0; i < 20; i++)
{
Audio_Regs[i] = 0;
}
sequencer_len = 0;
sequencer_vol = 0;
sequencer_swp = 0;
sequencer_tick = 0;
}
public void reset()
{
Wave_RAM = new byte[16];
Audio_Regs = new byte[21];
SQ1 = new AUD_Object();
SQ2 = new AUD_Object();
WAVE = new AUD_Object();
NOISE = new AUD_Object();
AUD_CTRL = new CTRL_Object();
}
public void SyncState(Serializer ser)
@ -164,6 +380,101 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
ser.Sync("Audio_Regs", ref Audio_Regs, false);
ser.Sync("Wave_Ram", ref Wave_RAM, false);
// some aspecta of the channel states are not derived from the Regs
ser.Sync("SQ1.length_counter", ref SQ1.length_counter);
ser.Sync("SQ2.length_counter", ref SQ2.length_counter);
ser.Sync("WAVE.length_counter", ref WAVE.length_counter);
ser.Sync("NOISE.length_counter", ref NOISE.length_counter);
// get derived state
if (ser.IsReader)
{
sync_channels();
}
}
public void sync_channels()
{
SQ1.swp_period = (byte)((Audio_Regs[NR10] & 0x70) >> 4);
SQ1.negate = (Audio_Regs[NR10] & 8) > 0;
SQ1.shift = (byte)(Audio_Regs[NR10] & 7);
SQ1.duty = (byte)((Audio_Regs[NR11] & 0xC0) >> 6);
SQ1.length = (byte)(64 - Audio_Regs[NR11] & 0x3F);
SQ1.st_vol = (byte)((Audio_Regs[NR12] & 0xF0) >> 4);
SQ1.env_add = (Audio_Regs[NR12] & 8) > 0;
SQ1.per = (byte)(Audio_Regs[NR12] & 7);
SQ1.frq &= 0x700;
SQ1.frq |= Audio_Regs[NR13];
SQ1.trigger = (Audio_Regs[NR14] & 0x80) > 0;
SQ1.len_en = (Audio_Regs[NR14] & 0x40) > 0;
SQ1.frq &= 0xFF;
SQ1.frq |= (ushort)((Audio_Regs[NR14] & 7) << 8);
SQ2.duty = (byte)((Audio_Regs[NR21] & 0xC0) >> 6);
SQ2.length = (byte)(64 - Audio_Regs[NR21] & 0x3F);
SQ2.st_vol = (byte)((Audio_Regs[NR22] & 0xF0) >> 4);
SQ2.env_add = (Audio_Regs[NR22] & 8) > 0;
SQ2.per = (byte)(Audio_Regs[NR22] & 7);
SQ2.frq &= 0x700;
SQ2.frq |= Audio_Regs[NR23];
SQ2.trigger = (Audio_Regs[NR24] & 0x80) > 0;
SQ2.len_en = (Audio_Regs[NR24] & 0x40) > 0;
SQ2.frq &= 0xFF;
SQ2.frq |= (ushort)((Audio_Regs[NR24] & 7) << 8);
WAVE.DAC_pow = (Audio_Regs[NR30] & 0x80) > 0;
WAVE.length = (byte)(256 - Audio_Regs[NR31]);
WAVE.vol_code = (byte)((Audio_Regs[NR32] & 0x60) >> 5);
WAVE.frq &= 0x700;
WAVE.frq |= Audio_Regs[NR33];
WAVE.trigger = (Audio_Regs[NR34] & 0x80) > 0;
WAVE.len_en = (Audio_Regs[NR34] & 0x40) > 0;
WAVE.frq &= 0xFF;
WAVE.frq |= (ushort)((Audio_Regs[NR34] & 7) << 8);
NOISE.length = (byte)(64 - Audio_Regs[NR41] & 0x3F);
NOISE.st_vol = (byte)((Audio_Regs[NR42] & 0xF0) >> 4);
NOISE.env_add = (Audio_Regs[NR42] & 8) > 0;
NOISE.per = (byte)(Audio_Regs[NR42] & 7);
NOISE.clk_shft = (byte)((Audio_Regs[NR43] & 0xF0) >> 4);
NOISE.wdth_md = (Audio_Regs[NR43] & 8) > 0;
NOISE.div_code = (byte)(Audio_Regs[NR43] & 7);
WAVE.trigger = (Audio_Regs[NR44] & 0x80) > 0;
WAVE.len_en = (Audio_Regs[NR44] & 0x40) > 0;
AUD_CTRL.vin_L_en = (Audio_Regs[NR50] & 0x80) > 0;
AUD_CTRL.vol_L = (byte)((Audio_Regs[NR50] & 0x70) >> 4);
AUD_CTRL.vin_R_en = (Audio_Regs[NR50] & 8) > 0;
AUD_CTRL.vol_R = (byte)(Audio_Regs[NR50] & 7);
AUD_CTRL.noise_L_en = (Audio_Regs[NR51] & 0x80) > 0;
AUD_CTRL.wave_L_en = (Audio_Regs[NR51] & 0x40) > 0;
AUD_CTRL.sq2_L_en = (Audio_Regs[NR51] & 0x20) > 0;
AUD_CTRL.sq1_L_en = (Audio_Regs[NR51] & 0x10) > 0;
AUD_CTRL.noise_R_en = (Audio_Regs[NR51] & 8) > 0;
AUD_CTRL.wave_R_en = (Audio_Regs[NR51] & 4) > 0;
AUD_CTRL.sq2_R_en = (Audio_Regs[NR51] & 2) > 0;
AUD_CTRL.sq1_R_en = (Audio_Regs[NR51] & 1) > 0;
AUD_CTRL.power = (Audio_Regs[NR51] & 0x80) > 0;
}
#region audio