diff --git a/src/apu.rs b/src/apu.rs index 550a17b..254542e 100644 --- a/src/apu.rs +++ b/src/apu.rs @@ -11,28 +11,94 @@ pub struct WaveChannel { } pub struct SquareChannel { - pub counter: u16, - pub enabled: bool, + pub wave_channel: WaveChannel, pub envelope_pos: u8, pub envelope_period: u8, - pub freq_pos: u32, pub incr_vol: bool, - pub volume: u8, pub wave_pos: usize, pub duty_table: [u8; 32], } pub struct NoiseChannel { - pub counter: u16, - pub enabled: bool, + pub wave_channel: WaveChannel, pub envelope_pos: u8, - pub volume: u8, pub lfsr: u16, - pub freq_pos: u32, pub incr_vol: bool, pub envelope_period: u8, } +pub trait HasWaveChannel { + fn wave_channel(&mut self) -> &mut WaveChannel; + + fn counter(&mut self) -> &mut u16 { + &mut self.wave_channel().counter + } + + fn enabled(&mut self) -> &mut bool { + &mut self.wave_channel().enabled + } + + fn freq_pos(&mut self) -> &mut u32 { + &mut self.wave_channel().freq_pos + } + + fn volume(&mut self) -> &mut u8 { + &mut self.wave_channel().volume + } +} + +impl HasWaveChannel for WaveChannel { + fn wave_channel(&mut self) -> &mut WaveChannel { + self + } +} + +impl HasWaveChannel for SquareChannel { + fn wave_channel(&mut self) -> &mut WaveChannel { + &mut self.wave_channel + } +} + +impl HasWaveChannel for NoiseChannel { + fn wave_channel(&mut self) -> &mut WaveChannel { + &mut self.wave_channel + } +} + +trait HasEnvelope { + fn envelope_pos(&mut self) -> &mut u8; + fn envelope_period(&mut self) -> &mut u8; + fn incr_vol(&mut self) -> &mut bool; +} + +impl HasEnvelope for SquareChannel { + fn envelope_pos(&mut self) -> &mut u8 { + &mut self.envelope_pos + } + + fn envelope_period(&mut self) -> &mut u8 { + &mut self.envelope_period + } + + fn incr_vol(&mut self) -> &mut bool { + &mut self.incr_vol + } +} + +impl HasEnvelope for NoiseChannel { + fn envelope_pos(&mut self) -> &mut u8 { + &mut self.envelope_pos + } + + fn envelope_period(&mut self) -> &mut u8 { + &mut self.envelope_period + } + + fn incr_vol(&mut self) -> &mut bool { + &mut self.incr_vol + } +} + pub struct Apu { pub master_clock: u32, pub length_clock: u32, @@ -60,11 +126,8 @@ pub struct Apu { impl Default for NoiseChannel { fn default() -> NoiseChannel { NoiseChannel { - counter: 0, - enabled: false, + wave_channel: Default::default(), envelope_pos: 0, - volume: 0, - freq_pos: 0, lfsr: 0x7FFF, incr_vol: false, envelope_period: 0, @@ -75,11 +138,8 @@ impl Default for NoiseChannel { impl Default for SquareChannel { fn default() -> SquareChannel { SquareChannel { - counter: 0, - enabled: false, + wave_channel: Default::default(), envelope_pos: 0, - freq_pos: 0, - volume: 0, incr_vol: false, envelope_period: 0, wave_pos: 0, @@ -139,13 +199,13 @@ impl Apu { pub fn gen_samples(sample_len: u8, cpu: &mut Cpu) { let mut result = vec![0; sample_len as usize]; let nr51 = cpu.memory[0xFF25]; - if cpu.apu.channel_1.enabled { + if *cpu.apu.channel_1.enabled() { let registers = read_channel_1_addresses(cpu); let mut channel = &mut cpu.apu.channel_1; let sound = ((nr51 >> 4) & 1, nr51 & 1); mix_channel_square(&mut result, channel, registers, sound); } - if cpu.apu.channel_2.enabled { + if *cpu.apu.channel_2.enabled() { let registers = read_channel_2_addresses(cpu); let mut channel = &mut cpu.apu.channel_2; let sound = ((nr51 >> 5) & 1, (nr51 >> 1) & 1); @@ -162,7 +222,7 @@ pub fn gen_samples(sample_len: u8, cpu: &mut Cpu) { channel_3_registers, sound); } - if cpu.apu.channel_4.enabled { + if *cpu.apu.channel_4.enabled() { let channel_4_registers = cpu.memory[0xFF22]; let mut channel_4 = &mut cpu.apu.channel_4; mix_channel_4(&mut result, &mut channel_4, channel_4_registers, nr51); @@ -187,32 +247,19 @@ pub fn step_length(cpu: &mut Cpu) { let channel_2_length_enable = read_address(0xFF19, cpu) & 0x40 != 0; let channel_3_length_enable = read_address(0xFF1E, cpu) & 0x40 != 0; let channel_4_length_enable = read_address(0xFF23, cpu) & 0x40 != 0; - if cpu.apu.channel_1.enabled && channel_1_length_enable { - if cpu.apu.channel_1.counter == 0 { - cpu.apu.channel_1.enabled = false; - } - cpu.apu.channel_1.counter -= 1; - } - if cpu.apu.channel_2.enabled && channel_2_length_enable { - if cpu.apu.channel_2.counter == 0 { - cpu.apu.channel_2.enabled = false; - } - cpu.apu.channel_2.counter -= 1; - } - if cpu.apu.channel_3.enabled && channel_3_length_enable { - if cpu.apu.channel_3.counter == 0 { - cpu.apu.channel_3.enabled = false; - } - cpu.apu.channel_3.counter -= 1; - } - - if cpu.apu.channel_4.enabled && channel_4_length_enable { - if cpu.apu.channel_4.counter == 0 { - cpu.apu.channel_4.enabled = false; + fn go(channel: &mut WaveChannel, length_enable: bool) { + if channel.enabled && length_enable { + if channel.counter == 0 { + channel.enabled = false; + } + channel.counter -= 1; } - cpu.apu.channel_4.counter -= 1; } + go(&mut cpu.apu.channel_1.wave_channel, channel_1_length_enable); + go(&mut cpu.apu.channel_2.wave_channel, channel_2_length_enable); + go(&mut cpu.apu.channel_3, channel_3_length_enable); + go(&mut cpu.apu.channel_4.wave_channel, channel_4_length_enable); } #[allow(non_snake_case)] @@ -223,18 +270,18 @@ pub fn mix_channel_square(result: &mut Vec, let time_freq = (freq_hi as u16 & 0b111) << 8 | freq_lo as u16; let duty = (duty_reg >> 6) as usize; let not_time_freq = 4 * (2048 - time_freq as u32); - let init_volume = channel.volume as i16; + let init_volume = *channel.volume() as i16; let volume = match left_out + right_out { 2 => (1 << 9) * init_volume, 1 => (1 << 8) * init_volume, 0 => 0, _ => unreachable!(), }; + let init_freq = *channel.freq_pos(); + let init_wave = channel.wave_pos; let duty_start = duty * 8; let duty_table = &channel.duty_table[duty_start..]; let downsample = 1 + 8192 / result.len(); - let init_freq = channel.freq_pos; - let init_wave = channel.wave_pos; let volume_on = volume != 0; if volume_on { for x in 0..result.len() { @@ -253,9 +300,9 @@ pub fn mix_channel_square(result: &mut Vec, (init_wave + ((8191 + not_time_freq as usize - init_freq as usize) / not_time_freq as usize) as usize) % 8); - channel.freq_pos = cond!(init_freq < 8192, - (not_time_freq - (8192 - init_freq) % not_time_freq) % not_time_freq, - init_freq - 8192); + channel.wave_channel.freq_pos = cond!(init_freq < 8192, + (not_time_freq - (8192 - init_freq) % not_time_freq) % not_time_freq, + init_freq - 8192); } #[allow(non_snake_case)] @@ -319,12 +366,12 @@ pub fn mix_channel_4(result: &mut Vec, channel: &mut NoiseChannel, nr43: u8 0 => 0, _ => unreachable!(), } as i16; - let volume_init = channel.volume as i16; + let volume_init = *channel.volume() as i16; let volume = volume_step * volume_init; let half_width = nr43 & 0x08 != 0; // whether the shift register is 15bits of 7 bits if shift_clock_freq < 14 && timer_freq as u32 != 0 { let downsample = 1 + 8192 / result.len(); - let mut freq = channel.freq_pos; + let mut freq = *channel.freq_pos(); let mut sample_idx = 0; for x in 0..8192 { // cycles @@ -347,7 +394,7 @@ pub fn mix_channel_4(result: &mut Vec, channel: &mut NoiseChannel, nr43: u8 sample_idx += 1; } } - channel.freq_pos = freq; + *channel.freq_pos() = freq; } } @@ -368,7 +415,7 @@ pub fn step_sweep(cpu: &mut Cpu) { // check again let sweep_check = cpu.apu.freq_sweep(shift, negate); if sweep_check > 2047 { - cpu.apu.channel_1.enabled = false; + *cpu.apu.channel_1.enabled() = false; } } } else { @@ -378,57 +425,28 @@ pub fn step_sweep(cpu: &mut Cpu) { } pub fn step_envelope(cpu: &mut Cpu) { - if cpu.apu.channel_1.enabled && cpu.apu.channel_1.envelope_period != 0 { - if cpu.apu.channel_1.incr_vol && cpu.apu.channel_1.volume < 15 { - if cpu.apu.channel_1.envelope_pos == 0 { - cpu.apu.channel_1.volume += 1; - cpu.apu.channel_1.envelope_pos = cpu.apu.channel_1.envelope_period; - } else { - cpu.apu.channel_1.envelope_pos -= 1; - } - } else if !cpu.apu.channel_1.incr_vol && cpu.apu.channel_1.volume > 0 { - if cpu.apu.channel_1.envelope_pos == 0 { - cpu.apu.channel_1.volume -= 1; - cpu.apu.channel_1.envelope_pos = cpu.apu.channel_1.envelope_period; - } else { - cpu.apu.channel_1.envelope_pos -= 1; - } - } - } - if cpu.apu.channel_2.enabled && cpu.apu.channel_2.envelope_period != 0 { - if cpu.apu.channel_2.incr_vol && cpu.apu.channel_2.volume < 15 { - if cpu.apu.channel_2.envelope_pos == 0 { - cpu.apu.channel_2.volume += 1; - cpu.apu.channel_2.envelope_pos = cpu.apu.channel_2.envelope_period; - } else { - cpu.apu.channel_2.envelope_pos -= 1; - } - } else if !cpu.apu.channel_2.incr_vol && cpu.apu.channel_2.volume > 0 { - if cpu.apu.channel_2.envelope_pos == 0 { - cpu.apu.channel_2.volume -= 1; - cpu.apu.channel_2.envelope_pos = cpu.apu.channel_2.envelope_period; - } else { - cpu.apu.channel_2.envelope_pos -= 1; - } - } - } - if cpu.apu.channel_4.enabled && cpu.apu.channel_4.envelope_period != 0 { - if cpu.apu.channel_4.incr_vol && cpu.apu.channel_4.volume < 15 { - if cpu.apu.channel_4.envelope_pos == 0 { - cpu.apu.channel_4.volume += 1; - cpu.apu.channel_4.envelope_pos = cpu.apu.channel_4.envelope_period; - } else { - cpu.apu.channel_4.envelope_pos -= 1; - } - } else if !cpu.apu.channel_4.incr_vol && cpu.apu.channel_4.volume > 0 { - if cpu.apu.channel_4.envelope_pos == 0 { - cpu.apu.channel_4.volume -= 1; - cpu.apu.channel_4.envelope_pos = cpu.apu.channel_4.envelope_period; - } else { - cpu.apu.channel_4.envelope_pos -= 1; + fn go(channel: &mut T) { + if *channel.enabled() && *channel.envelope_period() != 0 { + if *channel.incr_vol() && *channel.volume() < 15 { + if *channel.envelope_pos() == 0 { + *channel.volume() += 1; + *channel.envelope_pos() = *channel.envelope_period(); + } else { + *channel.envelope_pos() -= 1; + } + } else if !*channel.incr_vol() && *channel.volume() > 0 { + if *channel.envelope_pos() == 0 { + *channel.volume() -= 1; + *channel.envelope_pos() = *channel.envelope_period(); + } else { + *channel.envelope_pos() -= 1; + } } } } + go(&mut cpu.apu.channel_1); + go(&mut cpu.apu.channel_2); + go(&mut cpu.apu.channel_4); } pub fn step(cpu: &mut Cpu) { diff --git a/src/cpu.rs b/src/cpu.rs index 2f7c0b3..d6a4ce4 100644 --- a/src/cpu.rs +++ b/src/cpu.rs @@ -198,22 +198,22 @@ pub fn write_nx4_address(address: usize, val: u8, cpu: &mut Cpu) -> () { let nr14 = read_address(0xFF14, cpu); let time_freq = (nr14 as u16 & 0b111) << 8 | nr13 as u16; let not_time_freq = 4 * (2048 - time_freq as u32); - cpu.apu.channel_1.enabled = true; - if cpu.apu.channel_1.counter == 0 { - cpu.apu.channel_1.counter = 64; + *cpu.apu.channel_1.enabled() = true; + if *cpu.apu.channel_1.counter() == 0 { + *cpu.apu.channel_1.counter() = 64; } cpu.apu.channel_1.envelope_pos = nr12 & 7; - cpu.apu.channel_1.freq_pos = not_time_freq; + *cpu.apu.channel_1.freq_pos() = not_time_freq; cpu.apu.channel_1_shadow_freq = not_time_freq; cpu.apu.sweep_period = (nr10 >> 4) & 7; cpu.apu.sweep_clock = cpu.apu.sweep_period; let shift = nr10 & 7; cpu.apu.sweeping = cpu.apu.sweep_clock != 0 || shift != 0; cpu.apu.sweep_negate = (nr10 & 8) != 0; - cpu.apu.channel_1.volume = (nr12 & 0xF0) >> 4; - cpu.apu.channel_1.enabled = nr12 & 0xF8 != 0; + *cpu.apu.channel_1.volume() = (nr12 & 0xF0) >> 4; + *cpu.apu.channel_1.enabled() = nr12 & 0xF8 != 0; if cpu.apu.sweeping && cpu.apu.freq_sweep(shift, cpu.apu.sweep_negate) > 2047 { - cpu.apu.channel_1.enabled = false; + *cpu.apu.channel_1.enabled() = false; } } @@ -223,20 +223,20 @@ pub fn write_nx4_address(address: usize, val: u8, cpu: &mut Cpu) -> () { let nr24 = read_address(0xFF19, cpu); let time_freq = (nr24 as u16 & 0b111) << 8 | nr23 as u16; let not_time_freq = 4 * (2048 - time_freq as u32); - cpu.apu.channel_2.enabled = true; - if cpu.apu.channel_2.counter == 0 { - cpu.apu.channel_2.counter = 64; + *cpu.apu.channel_2.enabled() = true; + if *cpu.apu.channel_2.counter() == 0 { + *cpu.apu.channel_2.counter() = 64; } cpu.apu.channel_2.envelope_pos = nr22 & 7; - cpu.apu.channel_2.freq_pos = not_time_freq; - cpu.apu.channel_2.volume = (nr22 & 0xF0) >> 4; - cpu.apu.channel_2.enabled = nr22 & 0xF8 != 0; + *cpu.apu.channel_2.freq_pos() = not_time_freq; + *cpu.apu.channel_2.volume() = (nr22 & 0xF0) >> 4; + *cpu.apu.channel_2.enabled() = nr22 & 0xF8 != 0; // println!("Wrote {:4>0X} to NR24", val); } 0xFF1E => { - cpu.apu.channel_3.enabled = true; - if cpu.apu.channel_3.counter == 0 { - cpu.apu.channel_3.counter = 256; + *cpu.apu.channel_3.enabled() = true; + if *cpu.apu.channel_3.counter() == 0 { + *cpu.apu.channel_3.counter() = 256; } cpu.apu.channel_3_wave_pos = 0; let nr32 = read_address(0xFF1C, cpu); @@ -245,8 +245,8 @@ pub fn write_nx4_address(address: usize, val: u8, cpu: &mut Cpu) -> () { (read_address(0xFF1D, cpu) as u32 | (read_address(0xFF1E, cpu) as u32) << 8) & 0x7F); - cpu.apu.channel_3.volume = (nr32 & 0x60) >> 5; - cpu.apu.channel_3.enabled = (read_address(0xFF1A, cpu) & 0x80) != 0; + *cpu.apu.channel_3.volume() = (nr32 & 0x60) >> 5; + *cpu.apu.channel_3.enabled() = (read_address(0xFF1A, cpu) & 0x80) != 0; } 0xFF23 => { let nr42 = read_address(0xFF21, cpu); @@ -255,15 +255,15 @@ pub fn write_nx4_address(address: usize, val: u8, cpu: &mut Cpu) -> () { let dividing_ratio = divisors[(nr43 & 0x7) as usize]; let shift_clock_freq = nr43 >> 4 as u32; let timer_freq = dividing_ratio << shift_clock_freq; - cpu.apu.channel_4.enabled = true; - if cpu.apu.channel_4.counter == 0 { - cpu.apu.channel_4.counter = 64; + *cpu.apu.channel_4.enabled() = true; + if *cpu.apu.channel_4.counter() == 0 { + *cpu.apu.channel_4.counter() = 64; } cpu.apu.channel_4.lfsr = 0x7FFF; - cpu.apu.channel_4.freq_pos = timer_freq; + *cpu.apu.channel_4.freq_pos() = timer_freq; cpu.apu.channel_4.envelope_pos = nr42 & 7; - cpu.apu.channel_4.volume = nr42 >> 4; - cpu.apu.channel_4.enabled = nr42 & 0xF8 != 0; + *cpu.apu.channel_4.volume() = nr42 >> 4; + *cpu.apu.channel_4.enabled() = nr42 & 0xF8 != 0; // println!("Wrote {:4>0X} to NR44", val); } _ => {} @@ -316,12 +316,12 @@ pub fn safe_write_address(address: usize, val: u8, cpu: &mut Cpu) -> () { 0xFF04 => write_address(address, 0, cpu), 0xFF10 => write_address(address, val, cpu), //NR 10 Sound Mode 1 Sweep Register 0xFF11 => { - cpu.apu.channel_1.counter = 64 - (val & 0x3F) as u16; + *cpu.apu.channel_1.counter() = 64 - (val & 0x3F) as u16; write_address(address, val, cpu); } //NR 11 Sound Mode 1 Duty/Sound length 0xFF12 => { let (vol_init, vol_add, vol_period) = (val >> 4, val & 8 != 0, val & 7); - cpu.apu.channel_1.volume = vol_init; + *cpu.apu.channel_1.volume() = vol_init; cpu.apu.channel_1.incr_vol = vol_add; cpu.apu.channel_1.envelope_period = vol_period; write_address(address, val, cpu) @@ -329,12 +329,12 @@ pub fn safe_write_address(address: usize, val: u8, cpu: &mut Cpu) -> () { 0xFF13 => write_address(address, val, cpu), //NR 13 Sound Mode 1 Frequency lo 0xFF14 => write_nx4_address(address, val, cpu), //NR 14 Sound Mode 1 Frequency hi 0xFF16 => { - cpu.apu.channel_2.counter = 64 - (val & 0x3F) as u16; + *cpu.apu.channel_2.counter() = 64 - (val & 0x3F) as u16; write_address(address, val, cpu); } //NR 21 Sound Mode 2 Duty/Sound length 0xFF17 => { let (vol_init, vol_add, vol_period) = (val >> 4, val & 8 != 0, val & 7); - cpu.apu.channel_2.volume = vol_init; + *cpu.apu.channel_2.volume() = vol_init; cpu.apu.channel_2.incr_vol = vol_add; cpu.apu.channel_2.envelope_period = vol_period; write_address(address, val, cpu) @@ -343,19 +343,19 @@ pub fn safe_write_address(address: usize, val: u8, cpu: &mut Cpu) -> () { 0xFF19 => write_nx4_address(address, val, cpu), //NR 24 Sound Mode 2 Frequency hi 0xFF1A => write_address(address, val, cpu), //NR 30 Sound Mode 3 On/Off 0xFF1B => { - cpu.apu.channel_3.counter = 256 - val as u16; + *cpu.apu.channel_3.counter() = 256 - val as u16; write_address(address, val, cpu); } //NR 31 Sound Mode 3 Sound length 0xFF1C => write_address(address, val, cpu), //NR 32 Sound Mode 3 Select Output Level 0xFF1D => write_address(address, val, cpu), //NR 33 Sound Mode 3 Frequency lo 0xFF1E => write_nx4_address(address, val, cpu), //NR 34 Sound Mode 3 Frequency hi 0xFF20 => { - cpu.apu.channel_4.counter = 64 - (val & 0x3F) as u16; + *cpu.apu.channel_4.counter() = 64 - (val & 0x3F) as u16; write_address(address, val, cpu); } //NR 41 Sound Mode 4 Sound length 0xFF21 => { let (vol_init, vol_add, vol_period) = (val >> 4, val & 8 != 0, val & 7); - cpu.apu.channel_4.volume = vol_init; + *cpu.apu.channel_4.volume() = vol_init; cpu.apu.channel_4.incr_vol = vol_add; cpu.apu.channel_4.envelope_period = vol_period; write_address(address, val, cpu); @@ -609,4 +609,4 @@ pub fn stack_pop(cpu: &mut Cpu) -> u16 { cpu.sp = cpu.sp.wrapping_add(2); let res = (l_byte << 8) + r_byte; res -} \ No newline at end of file +}