From 0c843b9ca93caa86b3382e2cc8c38a005c366832 Mon Sep 17 00:00:00 2001 From: Rekai Musuka Date: Wed, 23 Jun 2021 21:49:10 -0500 Subject: [PATCH] feat(snd): implement volume envelope in ch1, 2 and 4 --- src/bus.rs | 14 ++-- src/sound.rs | 216 ++++++++++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 214 insertions(+), 16 deletions(-) diff --git a/src/bus.rs b/src/bus.rs index 57f035f..8206865 100644 --- a/src/bus.rs +++ b/src/bus.rs @@ -69,7 +69,7 @@ impl Bus { pub(crate) fn clock(&mut self) { self.ppu.clock(); self.timer.clock(); - self.snd.clock(); + self.snd.clock(self.timer.divider); self.clock_dma(); } @@ -223,10 +223,10 @@ impl BusIo for Bus { 0x10 => self.snd.ch1.sweep.into(), 0x11 => self.snd.ch1.duty.into(), 0x12 => self.snd.ch1.envelope.into(), - 0x14 => self.snd.ch1.freq_hi.into(), + 0x14 => self.snd.ch1.freq_hi(), 0x16 => self.snd.ch2.duty.into(), 0x17 => self.snd.ch2.envelope.into(), - 0x19 => self.snd.ch2.freq_hi.into(), + 0x19 => self.snd.ch2.freq_hi(), 0x1A => self.snd.ch3.enabled(), 0x1B => self.snd.ch3.len, 0x1C => self.snd.ch3.volume(), @@ -234,7 +234,7 @@ impl BusIo for Bus { 0x20 => self.snd.ch4.len(), 0x21 => self.snd.ch4.envelope.into(), 0x22 => self.snd.ch4.poly.into(), - 0x23 => self.snd.ch4.freq_data.into(), + 0x23 => self.snd.ch4.freq_data(), 0x24 => self.snd.ctrl.channel.into(), 0x25 => self.snd.ctrl.output.into(), 0x26 => self.snd.ctrl.status.into(), @@ -338,11 +338,11 @@ impl BusIo for Bus { 0x11 => self.snd.ch1.duty = byte.into(), 0x12 => self.snd.ch1.envelope = byte.into(), 0x13 => self.snd.ch1.freq_lo = byte, - 0x14 => self.snd.ch1.freq_hi = byte.into(), + 0x14 => self.snd.ch1.set_freq_hi(byte), 0x16 => self.snd.ch2.duty = byte.into(), 0x17 => self.snd.ch2.envelope = byte.into(), 0x18 => self.snd.ch2.freq_lo = byte, - 0x19 => self.snd.ch2.freq_hi = byte.into(), + 0x19 => self.snd.ch2.set_freq_hi(byte), 0x1A => self.snd.ch3.set_enabled(byte), 0x1B => self.snd.ch3.len = byte, 0x1C => self.snd.ch3.set_volume(byte), @@ -351,7 +351,7 @@ impl BusIo for Bus { 0x20 => self.snd.ch4.set_len(byte), 0x21 => self.snd.ch4.envelope = byte.into(), 0x22 => self.snd.ch4.poly = byte.into(), - 0x23 => self.snd.ch4.freq_data = byte.into(), + 0x23 => self.snd.ch4.set_freq_data(byte), 0x24 => self.snd.ctrl.channel = byte.into(), 0x25 => self.snd.ctrl.output = byte.into(), 0x26 => self.snd.ctrl.status = byte.into(), // FIXME: Should we control which bytes are written to here? diff --git a/src/sound.rs b/src/sound.rs index 9290f56..0fab7fe 100644 --- a/src/sound.rs +++ b/src/sound.rs @@ -13,11 +13,134 @@ pub(crate) struct Sound { pub(crate) ch3: Channel3, /// Noise pub(crate) ch4: Channel4, + + // Frame Sequencer + frame_seq_state: FrameSequencerState, + div_prev: Option, } impl Sound { - pub(crate) fn clock(&mut self) { - // + pub(crate) fn clock(&mut self, div: u16) { + use FrameSequencerState::*; + + // the 5th bit of the high byte + let bit_5 = (div >> 13 & 0x01) as u8; + + if let Some(0x01) = self.div_prev { + if bit_5 == 0x00 { + // Falling Edge, step the Frame Sequencer + self.frame_seq_state.step(); + + match self.frame_seq_state { + Step0Length => todo!(), + Step2LengthAndSweep => todo!(), + Step4Length => todo!(), + Step6LengthAndSweep => todo!(), + Step7VolumeEnvelope => { + use EnvelopeDirection::*; + // Channels 1, 2 and 4 have Volume Envelopes + + if self.ch1.envelope.sweep_count() != 0 { + if self.ch1.period_timer > 0 { + self.ch1.period_timer -= 1; + } + + if self.ch1.period_timer == 0 { + self.ch1.period_timer = self.ch1.envelope.sweep_count(); + + match self.ch1.envelope.direction() { + Decrease if self.ch1.current_volume > 0x00 => { + self.ch1.current_volume -= 1 + } + Increase if self.ch1.current_volume < 0x0F => { + self.ch1.current_volume += 1 + } + _ => {} + } + } + } + + if self.ch2.envelope.sweep_count() != 0 { + if self.ch2.period_timer > 0 { + self.ch2.period_timer -= 1; + } + + if self.ch2.period_timer == 0 { + self.ch2.period_timer = self.ch2.envelope.sweep_count(); + + match self.ch2.envelope.direction() { + Decrease if self.ch2.current_volume > 0x00 => { + self.ch2.current_volume -= 1 + } + Increase if self.ch2.current_volume < 0x0F => { + self.ch2.current_volume += 1 + } + _ => {} + } + } + } + + if self.ch4.envelope.sweep_count() != 0 { + if self.ch4.period_timer > 0 { + self.ch4.period_timer -= 1; + } + + if self.ch4.period_timer == 0 { + self.ch4.period_timer = self.ch4.envelope.sweep_count(); + + match self.ch4.envelope.direction() { + Decrease if self.ch4.current_volume > 0x00 => { + self.ch4.current_volume -= 1 + } + Increase if self.ch4.current_volume < 0x0F => { + self.ch4.current_volume += 1 + } + _ => {} + } + } + } + } + Step1Nothing | Step3Nothing | Step5Nothing => {} + }; + } + } + + self.div_prev = Some(bit_5); + } +} + +#[derive(Debug, Clone, Copy)] +enum FrameSequencerState { + Step0Length, + Step1Nothing, + Step2LengthAndSweep, + Step3Nothing, + Step4Length, + Step5Nothing, + Step6LengthAndSweep, + Step7VolumeEnvelope, +} + +impl FrameSequencerState { + pub fn step(&mut self) { + use FrameSequencerState::*; + + *self = match *self { + Step0Length => Step1Nothing, + Step1Nothing => Step2LengthAndSweep, + Step2LengthAndSweep => Step3Nothing, + Step3Nothing => Step4Length, + Step4Length => Step5Nothing, + Step5Nothing => Step6LengthAndSweep, + Step6LengthAndSweep => Step7VolumeEnvelope, + Step7VolumeEnvelope => Step0Length, + }; + } +} + +impl Default for FrameSequencerState { + fn default() -> Self { + Self::Step0Length } } @@ -36,11 +159,17 @@ pub(crate) struct SoundControl { bitfield! { pub struct FrequencyHigh(u8); impl Debug; - pub _, set_initial: 7; + initial, _set_initial: 7; pub from into FrequencyType, get_freq_type, set_freq_type: 6; pub _, set_freq_bits: 2, 0; } +impl FrequencyHigh { + pub(crate) fn set_initial(&mut self, value: bool, ch1: &mut Channel1) { + self._set_initial(value); + } +} + impl Copy for FrequencyHigh {} impl Clone for FrequencyHigh { fn clone(&self) -> Self { @@ -140,7 +269,28 @@ pub(crate) struct Channel1 { /// 0xFF13 | NR13 - Channel 1 Frequency low (lower 8 bits only) pub(crate) freq_lo: u8, /// 0xFF14 | NR14 - Channel 1 Frequency high - pub(crate) freq_hi: FrequencyHigh, + freq_hi: FrequencyHigh, + + // Envelope Functionality + period_timer: u8, + current_volume: u8, +} + +impl Channel1 { + /// 0xFF14 | NR14 - Channel 1 Frequency high + pub(crate) fn freq_hi(&self) -> u8 { + self.freq_hi.into() + } + + /// 0xFF14 | NR14 - Channel 1 Frequency high + pub(crate) fn set_freq_hi(&mut self, byte: u8) { + self.freq_hi = byte.into(); + + if self.freq_hi.initial() { + self.period_timer = self.envelope.sweep_count(); + self.current_volume = self.envelope.init_vol(); + } + } } bitfield! { @@ -207,14 +357,35 @@ pub(crate) struct Channel2 { /// 0xFF18 | NR23 - Channel 2 Frequency low (lower 8 bits only) pub(crate) freq_lo: u8, /// 0xFF19 | NR24 - Channel 2 Frequency high - pub(crate) freq_hi: FrequencyHigh, + freq_hi: FrequencyHigh, + + // Envelope Functionality + period_timer: u8, + current_volume: u8, +} + +impl Channel2 { + /// 0xFF19 | NR24 - Channel 2 Frequency high + pub(crate) fn freq_hi(&self) -> u8 { + self.freq_hi.into() + } + + /// 0xFF19 | NR24 - Channel 2 Frequency high + pub(crate) fn set_freq_hi(&mut self, byte: u8) { + self.freq_hi = byte.into(); + + if self.freq_hi.initial() { + self.period_timer = self.envelope.sweep_count(); + self.current_volume = self.envelope.init_vol(); + } + } } bitfield! { pub struct VolumeEnvelope(u8); impl Debug; pub init_vol, set_init_vol: 7, 4; - pub from into EnvelopeDirection, direction, set_direction: 3; + pub from into EnvelopeDirection, direction, set_direction: 3, 3; pub sweep_count, set_sweep_count: 2, 0; } @@ -244,7 +415,7 @@ impl From for u8 { } #[derive(Debug, Clone, Copy)] -enum EnvelopeDirection { +pub enum EnvelopeDirection { Decrease = 0, Increase = 1, } @@ -259,6 +430,12 @@ impl From for EnvelopeDirection { } } +impl From for u8 { + fn from(direction: EnvelopeDirection) -> Self { + direction as u8 + } +} + impl Default for EnvelopeDirection { fn default() -> Self { Self::Decrease @@ -393,7 +570,28 @@ pub(crate) struct Channel4 { /// 0xFF22 | NR43 - Chanel 4 Polynomial Counter pub(crate) poly: PolynomialCounter, /// 0xFF23 | NR44 - Channel 4 Counter / Consecutive Selector and Restart - pub(crate) freq_data: Channel4Frequency, + freq_data: Channel4Frequency, + + // Envelope Functionality + period_timer: u8, + current_volume: u8, +} + +impl Channel4 { + /// 0xFF23 | NR44 - Channel 4 Counter / Consecutive Selector and Restart + pub(crate) fn freq_data(&self) -> u8 { + self.freq_data.into() + } + + /// 0xFF23 | NR44 - Channel 4 Counter / Consecutive Selector and Restart + pub(crate) fn set_freq_data(&mut self, byte: u8) { + self.freq_data = byte.into(); + + if self.freq_data.initial() { + self.period_timer = self.envelope.sweep_count(); + self.current_volume = self.envelope.init_vol(); + } + } } impl Channel4 { @@ -464,7 +662,7 @@ impl From for u8 { bitfield! { pub struct Channel4Frequency(u8); impl Debug; - _, set_initial: 7; + initial, set_initial: 7; from into FrequencyType, freq_type, set_freq_type: 6, 6; }