feat(snd): implement channel 3
This commit is contained in:
		
							
								
								
									
										15
									
								
								src/bus.rs
									
									
									
									
									
								
							
							
						
						
									
										15
									
								
								src/bus.rs
									
									
									
									
									
								
							@@ -227,9 +227,14 @@ impl BusIo for Bus {
 | 
				
			|||||||
                    0x16 => self.sound.ch2.duty.into(),
 | 
					                    0x16 => self.sound.ch2.duty.into(),
 | 
				
			||||||
                    0x17 => self.sound.ch2.envelope.into(),
 | 
					                    0x17 => self.sound.ch2.envelope.into(),
 | 
				
			||||||
                    0x19 => self.sound.ch2.freq_hi.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(),
 | 
					                    0x24 => self.sound.ctrl.channel.into(),
 | 
				
			||||||
                    0x25 => self.sound.ctrl.output.into(),
 | 
					                    0x25 => self.sound.ctrl.output.into(),
 | 
				
			||||||
                    0x26 => self.sound.ctrl.status.into(),
 | 
					                    0x26 => self.sound.ctrl.status.into(),
 | 
				
			||||||
 | 
					                    0x30..=0x3F => self.sound.ch3.ram[addr as usize - 0xFF30],
 | 
				
			||||||
                    0x40 => self.ppu.ctrl.into(),
 | 
					                    0x40 => self.ppu.ctrl.into(),
 | 
				
			||||||
                    0x41 => self.ppu.stat.into(),
 | 
					                    0x41 => self.ppu.stat.into(),
 | 
				
			||||||
                    0x42 => self.ppu.pos.scroll_y,
 | 
					                    0x42 => self.ppu.pos.scroll_y,
 | 
				
			||||||
@@ -328,15 +333,21 @@ impl BusIo for Bus {
 | 
				
			|||||||
                    0x10 => self.sound.ch1.sweep = byte.into(),
 | 
					                    0x10 => self.sound.ch1.sweep = byte.into(),
 | 
				
			||||||
                    0x11 => self.sound.ch1.duty = byte.into(),
 | 
					                    0x11 => self.sound.ch1.duty = byte.into(),
 | 
				
			||||||
                    0x12 => self.sound.ch1.envelope = 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(),
 | 
					                    0x14 => self.sound.ch1.freq_hi = byte.into(),
 | 
				
			||||||
                    0x16 => self.sound.ch2.duty = byte.into(),
 | 
					                    0x16 => self.sound.ch2.duty = byte.into(),
 | 
				
			||||||
                    0x17 => self.sound.ch2.envelope = 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(),
 | 
					                    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(),
 | 
					                    0x24 => self.sound.ctrl.channel = byte.into(),
 | 
				
			||||||
                    0x25 => self.sound.ctrl.output = 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?
 | 
					                    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(),
 | 
					                    0x40 => self.ppu.ctrl = byte.into(),
 | 
				
			||||||
                    0x41 => self.ppu.stat.update(byte),
 | 
					                    0x41 => self.ppu.stat.update(byte),
 | 
				
			||||||
                    0x42 => self.ppu.pos.scroll_y = byte,
 | 
					                    0x42 => self.ppu.pos.scroll_y = byte,
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										92
									
								
								src/sound.rs
									
									
									
									
									
								
							
							
						
						
									
										92
									
								
								src/sound.rs
									
									
									
									
									
								
							@@ -1,9 +1,17 @@
 | 
				
			|||||||
use bitfield::bitfield;
 | 
					use bitfield::bitfield;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const WAVE_PATTERN_RAM_LEN: usize = 0x10;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[derive(Debug, Clone, Copy, Default)]
 | 
					#[derive(Debug, Clone, Copy, Default)]
 | 
				
			||||||
pub(crate) struct Sound {
 | 
					pub(crate) struct Sound {
 | 
				
			||||||
    pub(crate) ctrl: SoundControl,
 | 
					    pub(crate) ctrl: SoundControl,
 | 
				
			||||||
 | 
					    /// Tone & Sweep
 | 
				
			||||||
    pub(crate) ch1: Channel1,
 | 
					    pub(crate) ch1: Channel1,
 | 
				
			||||||
 | 
					    /// Tone
 | 
				
			||||||
    pub(crate) ch2: Channel2,
 | 
					    pub(crate) ch2: Channel2,
 | 
				
			||||||
 | 
					    /// Wave
 | 
				
			||||||
 | 
					    pub(crate) ch3: Channel3,
 | 
				
			||||||
 | 
					    // pub(crate) ch4: Channel4,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl Sound {
 | 
					impl Sound {
 | 
				
			||||||
@@ -57,31 +65,6 @@ impl From<FrequencyHigh> 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<u8> for FrequencyLow {
 | 
					 | 
				
			||||||
    fn from(byte: u8) -> Self {
 | 
					 | 
				
			||||||
        Self(byte)
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#[derive(Debug, Clone, Copy)]
 | 
					#[derive(Debug, Clone, Copy)]
 | 
				
			||||||
enum FrequencyType {
 | 
					enum FrequencyType {
 | 
				
			||||||
    Counter = 0,
 | 
					    Counter = 0,
 | 
				
			||||||
@@ -148,7 +131,7 @@ pub(crate) struct Channel1 {
 | 
				
			|||||||
    /// 0xFF12 | NR12 - Channel 1 Volume Envelope
 | 
					    /// 0xFF12 | NR12 - Channel 1 Volume Envelope
 | 
				
			||||||
    pub(crate) envelope: VolumeEnvelope,
 | 
					    pub(crate) envelope: VolumeEnvelope,
 | 
				
			||||||
    /// 0xFF13 | NR13 - Channel 1 Frequency low (lower 8 bits only)
 | 
					    /// 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
 | 
					    /// 0xFF14 | NR14 - Channel 1 Frequency high
 | 
				
			||||||
    pub(crate) freq_hi: FrequencyHigh,
 | 
					    pub(crate) freq_hi: FrequencyHigh,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -215,7 +198,7 @@ pub(crate) struct Channel2 {
 | 
				
			|||||||
    /// 0xFF17 | NR22 - Channel 2 Volume ENvelope
 | 
					    /// 0xFF17 | NR22 - Channel 2 Volume ENvelope
 | 
				
			||||||
    pub(crate) envelope: VolumeEnvelope,
 | 
					    pub(crate) envelope: VolumeEnvelope,
 | 
				
			||||||
    /// 0xFF18 | NR23 - Channel 2 Frequency low (lower 8 bits only)
 | 
					    /// 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
 | 
					    /// 0xFF19 | NR24 - Channel 2 Frequency high
 | 
				
			||||||
    pub(crate) freq_hi: FrequencyHigh,
 | 
					    pub(crate) freq_hi: FrequencyHigh,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -339,6 +322,61 @@ impl From<u8> 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! {
 | 
					bitfield! {
 | 
				
			||||||
    pub struct SoundOutput(u8);
 | 
					    pub struct SoundOutput(u8);
 | 
				
			||||||
    impl Debug;
 | 
					    impl Debug;
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user