fix(apu): clock frame sequencer at correct Hz
continuous-integration/drone/push Build is passing Details

This commit is contained in:
Rekai Nyangadzayi Musuka 2021-08-15 02:46:20 -05:00
parent c2f2e2194b
commit a77d0a0f62
2 changed files with 26 additions and 65 deletions

View File

@ -5,7 +5,7 @@ use types::ch1::{Sweep, SweepDirection};
use types::ch3::Volume as Ch3Volume; use types::ch3::Volume as Ch3Volume;
use types::ch4::{CounterWidth, Frequency as Ch4Frequency, PolynomialCounter}; use types::ch4::{CounterWidth, Frequency as Ch4Frequency, PolynomialCounter};
use types::common::{EnvelopeDirection, FrequencyHigh, SoundDuty, VolumeEnvelope}; use types::common::{EnvelopeDirection, FrequencyHigh, SoundDuty, VolumeEnvelope};
use types::{ChannelControl, FrameSequencerState, SoundOutput}; use types::{ChannelControl, SoundOutput};
pub mod gen; pub mod gen;
mod types; mod types;
@ -26,8 +26,7 @@ pub struct Apu {
ch4: Channel4, ch4: Channel4,
// Frame Sequencer // Frame Sequencer
frame_seq_state: FrameSequencerState, div_prev: Option<u16>,
div_prev: Option<u8>,
prod: Option<SampleProducer<f32>>, prod: Option<SampleProducer<f32>>,
sample_counter: u64, sample_counter: u64,
@ -95,41 +94,30 @@ impl BusIo for Apu {
impl Apu { impl Apu {
pub(crate) fn tick(&mut self, div: u16) { pub(crate) fn tick(&mut self, div: u16) {
use FrameSequencerState::*;
self.sample_counter += SAMPLE_INCREMENT; self.sample_counter += SAMPLE_INCREMENT;
// the 5th bit of the high byte // Length Control (256Hz)
let bit_5 = (div >> 13 & 0x01) as u8; if self.falling_edge(13, div) {
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 => self.handle_length(),
Step2LengthAndSweep => {
self.handle_length(); self.handle_length();
}
// Sweep (128Hz)
if self.falling_edge(14, div) {
self.handle_sweep(); self.handle_sweep();
} }
Step4Length => self.handle_length(),
Step6LengthAndSweep => { // Volume Envelope (64Hz)
self.handle_length(); if self.falling_edge(15, div) {
self.handle_sweep(); self.handle_volume();
}
Step7VolumeEnvelope => self.handle_volume(),
Step1Nothing | Step3Nothing | Step5Nothing => {}
};
}
} }
self.div_prev = Some(div);
self.ch1.clock(); self.ch1.clock();
self.ch2.clock(); self.ch2.clock();
self.ch3.clock(); self.ch3.clock();
self.ch4.clock(); self.ch4.clock();
self.div_prev = Some(bit_5);
if self.sample_counter >= SM83_CLOCK_SPEED { if self.sample_counter >= SM83_CLOCK_SPEED {
self.sample_counter %= SM83_CLOCK_SPEED; self.sample_counter %= SM83_CLOCK_SPEED;
@ -176,7 +164,8 @@ impl Apu {
if self.ctrl.enabled { if self.ctrl.enabled {
// Frame Sequencer reset to Step 0 // Frame Sequencer reset to Step 0
self.frame_seq_state = Default::default(); // TODO: With the current implementation of the frame sequencer,
// what does this even mean?
// Square Duty units are reset to first step // Square Duty units are reset to first step
self.ch1.duty_pos = 0; self.ch1.duty_pos = 0;
@ -338,6 +327,13 @@ impl Apu {
&mut self.ch4.current_volume, &mut self.ch4.current_volume,
); );
} }
fn falling_edge(&self, bit: u8, div: u16) -> bool {
match self.div_prev {
Some(p) => (p >> bit & 0x01) == 0x01 && (div >> bit & 0x01) == 0x00,
None => false,
}
}
} }
#[derive(Debug, Default)] #[derive(Debug, Default)]

View File

@ -427,41 +427,6 @@ pub(crate) mod common {
} }
} }
#[derive(Debug, Clone, Copy)]
pub(crate) enum FrameSequencerState {
Step0Length,
Step1Nothing,
Step2LengthAndSweep,
Step3Nothing,
Step4Length,
Step5Nothing,
Step6LengthAndSweep,
Step7VolumeEnvelope,
}
impl FrameSequencerState {
pub(crate) 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
}
}
bitfield! { bitfield! {
pub struct SoundOutput(u8); pub struct SoundOutput(u8);
impl Debug; impl Debug;