diff --git a/src/bus.rs b/src/bus.rs index f43975b..607abe5 100644 --- a/src/bus.rs +++ b/src/bus.rs @@ -227,9 +227,14 @@ impl BusIo for Bus { 0x16 => self.sound.ch2.duty.into(), 0x17 => self.sound.ch2.envelope.into(), 0x19 => self.sound.ch2.freq_hi.into(), + 0x1A => self.sound.ch3.enabled(), + 0x1B => self.sound.ch3.len, + 0x1C => self.sound.ch3.volume(), + 0x1E => self.sound.ch3.freq_hi.into(), 0x24 => self.sound.ctrl.channel.into(), 0x25 => self.sound.ctrl.output.into(), 0x26 => self.sound.ctrl.status.into(), + 0x30..=0x3F => self.sound.ch3.ram[addr as usize - 0xFF30], 0x40 => self.ppu.ctrl.into(), 0x41 => self.ppu.stat.into(), 0x42 => self.ppu.pos.scroll_y, @@ -328,15 +333,21 @@ impl BusIo for Bus { 0x10 => self.sound.ch1.sweep = byte.into(), 0x11 => self.sound.ch1.duty = byte.into(), 0x12 => self.sound.ch1.envelope = byte.into(), - 0x13 => self.sound.ch1.freq_lo = byte.into(), + 0x13 => self.sound.ch1.freq_lo = byte, 0x14 => self.sound.ch1.freq_hi = byte.into(), 0x16 => self.sound.ch2.duty = byte.into(), 0x17 => self.sound.ch2.envelope = byte.into(), - 0x18 => self.sound.ch2.freq_lo = byte.into(), + 0x18 => self.sound.ch2.freq_lo = byte, 0x19 => self.sound.ch2.freq_hi = byte.into(), + 0x1A => self.sound.ch3.set_enabled(byte), + 0x1B => self.sound.ch3.len = byte, + 0x1C => self.sound.ch3.set_volume(byte), + 0x1D => self.sound.ch3.freq_lo = byte, + 0x1E => self.sound.ch3.freq_hi = byte.into(), 0x24 => self.sound.ctrl.channel = byte.into(), 0x25 => self.sound.ctrl.output = byte.into(), 0x26 => self.sound.ctrl.status = byte.into(), // FIXME: Should we control which bytes are written to here? + 0x30..=0x3F => self.sound.ch3.ram[addr as usize - 0xFF30] = byte, 0x40 => self.ppu.ctrl = byte.into(), 0x41 => self.ppu.stat.update(byte), 0x42 => self.ppu.pos.scroll_y = byte, diff --git a/src/sound.rs b/src/sound.rs index 81de381..9f4f700 100644 --- a/src/sound.rs +++ b/src/sound.rs @@ -1,9 +1,17 @@ use bitfield::bitfield; + +const WAVE_PATTERN_RAM_LEN: usize = 0x10; + #[derive(Debug, Clone, Copy, Default)] pub(crate) struct Sound { pub(crate) ctrl: SoundControl, + /// Tone & Sweep pub(crate) ch1: Channel1, + /// Tone pub(crate) ch2: Channel2, + /// Wave + pub(crate) ch3: Channel3, + // pub(crate) ch4: Channel4, } impl Sound { @@ -57,31 +65,6 @@ impl From for u8 { } } -bitfield! { - pub struct FrequencyLow(u8); - impl Debug; - pub _, set_freq_bits: 7, 0; -} - -impl Copy for FrequencyLow {} -impl Clone for FrequencyLow { - fn clone(&self) -> Self { - *self - } -} - -impl Default for FrequencyLow { - fn default() -> Self { - Self(0) - } -} - -impl From for FrequencyLow { - fn from(byte: u8) -> Self { - Self(byte) - } -} - #[derive(Debug, Clone, Copy)] enum FrequencyType { Counter = 0, @@ -148,7 +131,7 @@ pub(crate) struct Channel1 { /// 0xFF12 | NR12 - Channel 1 Volume Envelope pub(crate) envelope: VolumeEnvelope, /// 0xFF13 | NR13 - Channel 1 Frequency low (lower 8 bits only) - pub(crate) freq_lo: FrequencyLow, + pub(crate) freq_lo: u8, /// 0xFF14 | NR14 - Channel 1 Frequency high pub(crate) freq_hi: FrequencyHigh, } @@ -215,7 +198,7 @@ pub(crate) struct Channel2 { /// 0xFF17 | NR22 - Channel 2 Volume ENvelope pub(crate) envelope: VolumeEnvelope, /// 0xFF18 | NR23 - Channel 2 Frequency low (lower 8 bits only) - pub(crate) freq_lo: FrequencyLow, + pub(crate) freq_lo: u8, /// 0xFF19 | NR24 - Channel 2 Frequency high pub(crate) freq_hi: FrequencyHigh, } @@ -339,6 +322,61 @@ impl From for WavePattern { } } +#[derive(Debug, Clone, Copy, Default)] +pub(crate) struct Channel3 { + /// 0xFF1A | NR30 - Channel 3 Sound on/off + enabled: bool, + /// 0xFF1B | NR31 - Sound Length + pub(crate) len: u8, + /// 0xFF1C | NR32 - Channel 3 Volume + volume: Channel3Volume, + /// 0xFF1D | NR33 - Channel 3 Frequency low (lower 8 bits) + pub(crate) freq_lo: u8, + /// 0xFF1E | NR34 - Channel 3 Frequency high + pub(crate) freq_hi: FrequencyHigh, + pub(crate) ram: [u8; WAVE_PATTERN_RAM_LEN], +} + +impl Channel3 { + pub fn enabled(&self) -> u8 { + self.enabled as u8 + } + + pub fn set_enabled(&mut self, byte: u8) { + self.enabled = (byte >> 7) & 0x01 == 0x01; + } + + pub fn volume(&self) -> u8 { + (self.volume as u8) << 5 + } + + pub fn set_volume(&mut self, byte: u8) { + use Channel3Volume::*; + + self.volume = match (byte >> 5) & 0x03 { + 0b00 => Mute, + 0b01 => Full, + 0b10 => Half, + 0b11 => Quarter, + _ => unreachable!("{:#04X} is not a valid value for Channel3Volume", byte), + }; + } +} + +#[derive(Debug, Clone, Copy)] +enum Channel3Volume { + Mute = 0, + Full = 1, + Half = 2, + Quarter = 3, +} + +impl Default for Channel3Volume { + fn default() -> Self { + Self::Mute + } +} + bitfield! { pub struct SoundOutput(u8); impl Debug;