diff --git a/src/processor/memory/mmio/apu.rs b/src/processor/memory/mmio/apu.rs index aa4f892..1ef6d17 100644 --- a/src/processor/memory/mmio/apu.rs +++ b/src/processor/memory/mmio/apu.rs @@ -19,10 +19,12 @@ impl DacSample { fn mixed(&self, mixer: &Mixer) -> Vec { let left = (self.one * mixer.ch1.left.scale()) + (self.two * mixer.ch2.left.scale()) - + (self.three * mixer.ch3.left.scale()); + + (self.three * mixer.ch3.left.scale()) + + (self.four * mixer.ch4.left.scale()); let right = (self.one * mixer.ch1.right.scale()) + (self.two * mixer.ch2.right.scale()) - + (self.three * mixer.ch3.right.scale()); + + (self.three * mixer.ch3.right.scale()) + + (self.four * mixer.ch4.right.scale()); vec![ self.mix_channel(left, mixer.vol_left), self.mix_channel(right, mixer.vol_right), @@ -133,6 +135,7 @@ impl Apu { // envelope sweep self.channels.one.envelope_tick(); self.channels.two.envelope_tick(); + self.channels.four.envelope_tick(); } if self.div_apu % 4 == 0 { // ch1 frequency sweep @@ -143,6 +146,7 @@ impl Apu { self.channels.one.length_tick(); self.channels.two.length_tick(); self.channels.three.length_tick(); + self.channels.four.length_tick(); } } @@ -151,9 +155,15 @@ impl Apu { &mut izip!( self.channels.one.tick(steps).into_iter(), self.channels.two.tick(steps).into_iter(), - self.channels.three.tick(steps).into_iter() + self.channels.three.tick(steps).into_iter(), + self.channels.four.tick(steps).into_iter() ) - .map(|(one, two, three)| DacSample { one, two, three }) + .map(|(one, two, three, four)| DacSample { + one, + two, + three, + four, + }) .collect(), ); if self.buffer.len() >= CYCLES_PER_FRAME { diff --git a/src/processor/memory/mmio/apu/channels.rs b/src/processor/memory/mmio/apu/channels.rs index 56efdc7..41f5166 100644 --- a/src/processor/memory/mmio/apu/channels.rs +++ b/src/processor/memory/mmio/apu/channels.rs @@ -451,6 +451,43 @@ struct Lfsr { clock_shift: u8, width: LfsrWidth, clock_divider: u8, + interval: u16, + timer: u16, + current_value: u8, + register: u16, +} + +impl Lfsr { + fn update(&mut self) { + self.interval = + (1 << (self.clock_shift as u16)) * (1 + (2 * self.clock_divider as u16)) * 8; + } + + fn tick(&mut self) { + self.timer += 1; + if self.timer > self.interval { + self.timer = 0; + self.next_value(); + } + } + + fn next_value(&mut self) { + let next = if (self.register & 0b1) == ((self.register >> 1) & 0b1) { + 1 + } else { + 0 + }; + self.register = (self.register & !(0b1 << 15)) | (next << 15); + if self.width == LfsrWidth::SevenBit { + self.register = (self.register & !(0b1 << 7)) | (next << 7); + } + self.register >>= 1; + self.current_value = if (self.register & 0b1) == 0b1 { + 0x1 + } else { + 0x0 + }; + } } impl Default for Lfsr { @@ -459,6 +496,10 @@ impl Default for Lfsr { clock_shift: Default::default(), width: LfsrWidth::FifteenBit, clock_divider: Default::default(), + interval: 0, + timer: 0, + current_value: 0, + register: 0, } } } @@ -489,6 +530,38 @@ impl NoiseChannel { self.envelope = self.queued_envelope; } + pub fn tick(&mut self, steps: usize) -> Vec { + if self.enabled { + (0..steps) + .map(|_| { + self.lfsr.tick(); + self.dac(self.lfsr.current_value) + }) + .collect() + } else { + vec![0.; steps] + } + } + + fn dac(&self, digital: u8) -> f32 { + (((digital as f32) * (-2.)) + 1.) * ((self.envelope.current_volume as f32) / 15.) + } + + pub(super) fn envelope_tick(&mut self) { + if self.enabled { + self.envelope.tick(); + } + } + + pub(super) fn length_tick(&mut self) { + if self.length_enable && self.enabled { + self.length_timer += 1; + if self.length_timer >= 64 { + self.enabled = false; + } + } + } + pub(super) fn update_length_timer(&mut self, data: u8) { self.length_timer = data & 0b111111; } @@ -522,6 +595,7 @@ impl NoiseChannel { LfsrWidth::FifteenBit }; self.lfsr.clock_divider = data & 0b111; + self.lfsr.update(); } pub(super) fn get_frequency_and_randomness(&self) -> u8 { diff --git a/src/processor/memory/mmio/apu/types.rs b/src/processor/memory/mmio/apu/types.rs index ad3b5e4..1e71038 100644 --- a/src/processor/memory/mmio/apu/types.rs +++ b/src/processor/memory/mmio/apu/types.rs @@ -94,6 +94,7 @@ pub(super) struct DacSample { pub(super) one: f32, pub(super) two: f32, pub(super) three: f32, + pub(super) four: f32, } impl Default for DacSample { @@ -102,6 +103,7 @@ impl Default for DacSample { one: 0., two: 0., three: 0., + four: 0., } } }