fix(apu): clock frame sequencer at correct Hz
continuous-integration/drone/push Build is passing
Details
continuous-integration/drone/push Build is passing
Details
This commit is contained in:
parent
c2f2e2194b
commit
a77d0a0f62
56
src/apu.rs
56
src/apu.rs
|
@ -5,7 +5,7 @@ use types::ch1::{Sweep, SweepDirection};
|
|||
use types::ch3::Volume as Ch3Volume;
|
||||
use types::ch4::{CounterWidth, Frequency as Ch4Frequency, PolynomialCounter};
|
||||
use types::common::{EnvelopeDirection, FrequencyHigh, SoundDuty, VolumeEnvelope};
|
||||
use types::{ChannelControl, FrameSequencerState, SoundOutput};
|
||||
use types::{ChannelControl, SoundOutput};
|
||||
|
||||
pub mod gen;
|
||||
mod types;
|
||||
|
@ -26,8 +26,7 @@ pub struct Apu {
|
|||
ch4: Channel4,
|
||||
|
||||
// Frame Sequencer
|
||||
frame_seq_state: FrameSequencerState,
|
||||
div_prev: Option<u8>,
|
||||
div_prev: Option<u16>,
|
||||
|
||||
prod: Option<SampleProducer<f32>>,
|
||||
sample_counter: u64,
|
||||
|
@ -95,41 +94,30 @@ impl BusIo for Apu {
|
|||
|
||||
impl Apu {
|
||||
pub(crate) fn tick(&mut self, div: u16) {
|
||||
use FrameSequencerState::*;
|
||||
self.sample_counter += SAMPLE_INCREMENT;
|
||||
|
||||
// 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 => self.handle_length(),
|
||||
Step2LengthAndSweep => {
|
||||
self.handle_length();
|
||||
self.handle_sweep();
|
||||
}
|
||||
Step4Length => self.handle_length(),
|
||||
Step6LengthAndSweep => {
|
||||
self.handle_length();
|
||||
self.handle_sweep();
|
||||
}
|
||||
Step7VolumeEnvelope => self.handle_volume(),
|
||||
Step1Nothing | Step3Nothing | Step5Nothing => {}
|
||||
};
|
||||
}
|
||||
// Length Control (256Hz)
|
||||
if self.falling_edge(13, div) {
|
||||
self.handle_length();
|
||||
}
|
||||
|
||||
// Sweep (128Hz)
|
||||
if self.falling_edge(14, div) {
|
||||
self.handle_sweep();
|
||||
}
|
||||
|
||||
// Volume Envelope (64Hz)
|
||||
if self.falling_edge(15, div) {
|
||||
self.handle_volume();
|
||||
}
|
||||
|
||||
self.div_prev = Some(div);
|
||||
|
||||
self.ch1.clock();
|
||||
self.ch2.clock();
|
||||
self.ch3.clock();
|
||||
self.ch4.clock();
|
||||
|
||||
self.div_prev = Some(bit_5);
|
||||
|
||||
if self.sample_counter >= SM83_CLOCK_SPEED {
|
||||
self.sample_counter %= SM83_CLOCK_SPEED;
|
||||
|
||||
|
@ -176,7 +164,8 @@ impl Apu {
|
|||
|
||||
if self.ctrl.enabled {
|
||||
// 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
|
||||
self.ch1.duty_pos = 0;
|
||||
|
@ -338,6 +327,13 @@ impl Apu {
|
|||
&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)]
|
||||
|
|
|
@ -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! {
|
||||
pub struct SoundOutput(u8);
|
||||
impl Debug;
|
||||
|
|
Loading…
Reference in New Issue