Compare commits
No commits in common. "360a9a7b65fabb3377b96a83e3f6594846b6542f" and "aa22e93049a9c77cf5442738fee6c5a89d886b4d" have entirely different histories.
360a9a7b65
...
aa22e93049
256
src/apu.rs
256
src/apu.rs
|
@ -5,7 +5,6 @@ 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::fs::{FrameSequencer, State as FrameSequencerState};
|
|
||||||
use types::{ChannelControl, SoundOutput};
|
use types::{ChannelControl, SoundOutput};
|
||||||
|
|
||||||
pub mod gen;
|
pub mod gen;
|
||||||
|
@ -26,7 +25,7 @@ pub struct Apu {
|
||||||
/// Noise
|
/// Noise
|
||||||
ch4: Channel4,
|
ch4: Channel4,
|
||||||
|
|
||||||
sequencer: FrameSequencer,
|
// Frame Sequencer
|
||||||
div_prev: Option<u16>,
|
div_prev: Option<u16>,
|
||||||
|
|
||||||
prod: Option<SampleProducer<f32>>,
|
prod: Option<SampleProducer<f32>>,
|
||||||
|
@ -43,7 +42,7 @@ impl BusIo for Apu {
|
||||||
0x16 => self.ch2.duty(),
|
0x16 => self.ch2.duty(),
|
||||||
0x17 => self.ch2.envelope(),
|
0x17 => self.ch2.envelope(),
|
||||||
0x19 => self.ch2.freq_hi(),
|
0x19 => self.ch2.freq_hi(),
|
||||||
0x1A => self.ch3.dac_enabled(),
|
0x1A => self.ch3.enabled(),
|
||||||
0x1C => self.ch3.volume(),
|
0x1C => self.ch3.volume(),
|
||||||
0x1E => self.ch3.freq_hi(),
|
0x1E => self.ch3.freq_hi(),
|
||||||
0x21 => self.ch4.envelope(),
|
0x21 => self.ch4.envelope(),
|
||||||
|
@ -71,7 +70,7 @@ impl BusIo for Apu {
|
||||||
0x17 if self.ctrl.enabled => self.ch2.set_envelope(byte),
|
0x17 if self.ctrl.enabled => self.ch2.set_envelope(byte),
|
||||||
0x18 if self.ctrl.enabled => self.ch2.set_freq_lo(byte),
|
0x18 if self.ctrl.enabled => self.ch2.set_freq_lo(byte),
|
||||||
0x19 if self.ctrl.enabled => self.ch2.set_freq_hi(byte),
|
0x19 if self.ctrl.enabled => self.ch2.set_freq_hi(byte),
|
||||||
0x1A if self.ctrl.enabled => self.ch3.set_dac_enabled(byte),
|
0x1A if self.ctrl.enabled => self.ch3.set_enabled(byte),
|
||||||
0x1B if self.ctrl.enabled => self.ch3.set_len(byte),
|
0x1B if self.ctrl.enabled => self.ch3.set_len(byte),
|
||||||
0x1C if self.ctrl.enabled => self.ch3.set_volume(byte),
|
0x1C if self.ctrl.enabled => self.ch3.set_volume(byte),
|
||||||
0x1D if self.ctrl.enabled => self.ch3.set_freq_lo(byte),
|
0x1D if self.ctrl.enabled => self.ch3.set_freq_lo(byte),
|
||||||
|
@ -97,35 +96,33 @@ impl Apu {
|
||||||
pub(crate) fn tick(&mut self, div: u16) {
|
pub(crate) fn tick(&mut self, div: u16) {
|
||||||
self.sample_counter += SAMPLE_INCREMENT;
|
self.sample_counter += SAMPLE_INCREMENT;
|
||||||
|
|
||||||
// Frame Sequencer (512Hz)
|
// Length Control (256Hz)
|
||||||
if self.is_falling_edge(12, div) {
|
if self.falling_edge(13, div) {
|
||||||
use FrameSequencerState::*;
|
self.handle_length();
|
||||||
|
}
|
||||||
|
|
||||||
match self.sequencer.state() {
|
// Sweep (128Hz)
|
||||||
Length => self.clock_length(),
|
if self.falling_edge(14, div) {
|
||||||
LengthAndSweep => {
|
self.handle_sweep();
|
||||||
self.clock_length();
|
}
|
||||||
self.clock_sweep();
|
|
||||||
}
|
|
||||||
Envelope => self.clock_envelope(),
|
|
||||||
Nothing => {}
|
|
||||||
}
|
|
||||||
|
|
||||||
self.sequencer.next();
|
// Volume Envelope (64Hz)
|
||||||
|
if self.falling_edge(15, div) {
|
||||||
|
self.handle_volume();
|
||||||
}
|
}
|
||||||
|
|
||||||
self.div_prev = Some(div);
|
self.div_prev = Some(div);
|
||||||
|
|
||||||
self.ch1.tick();
|
self.ch1.clock();
|
||||||
self.ch2.tick();
|
self.ch2.clock();
|
||||||
self.ch3.tick();
|
self.ch3.clock();
|
||||||
self.ch4.tick();
|
self.ch4.clock();
|
||||||
|
|
||||||
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;
|
||||||
|
|
||||||
if let Some(ref mut prod) = self.prod {
|
if let Some(ref mut prod) = self.prod {
|
||||||
if prod.available_blocking() {
|
if prod.available_block() {
|
||||||
// Sample the APU
|
// Sample the APU
|
||||||
let ch1_amplitude = self.ch1.amplitude();
|
let ch1_amplitude = self.ch1.amplitude();
|
||||||
let ch1_left = self.ctrl.output.ch1_left() as u8 as f32 * ch1_amplitude;
|
let ch1_left = self.ctrl.output.ch1_left() as u8 as f32 * ch1_amplitude;
|
||||||
|
@ -157,20 +154,23 @@ impl Apu {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn set_producer(&mut self, prod: SampleProducer<f32>) {
|
||||||
|
self.prod = Some(prod);
|
||||||
|
}
|
||||||
|
|
||||||
/// 0xFF26 | NR52 - Sound On/Off
|
/// 0xFF26 | NR52 - Sound On/Off
|
||||||
pub(crate) fn set_status(&mut self, byte: u8) {
|
pub(crate) fn set_status(&mut self, byte: u8) {
|
||||||
self.ctrl.enabled = (byte >> 7) & 0x01 == 0x01;
|
self.ctrl.enabled = (byte >> 7) & 0x01 == 0x01;
|
||||||
|
|
||||||
if self.ctrl.enabled {
|
if self.ctrl.enabled {
|
||||||
// Frame Sequencer reset to Step 0
|
// Frame Sequencer reset to Step 0
|
||||||
self.sequencer.reset();
|
// 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;
|
||||||
self.ch2.duty_pos = 0;
|
self.ch2.duty_pos = 0;
|
||||||
|
|
||||||
// Wave Channel's sample buffer reset to 0
|
// Wave Channel's sample buffer reset to 0
|
||||||
self.ch3.offset = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if !self.ctrl.enabled {
|
if !self.ctrl.enabled {
|
||||||
|
@ -179,10 +179,6 @@ impl Apu {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn attach_producer(&mut self, prod: SampleProducer<f32>) {
|
|
||||||
self.prod = Some(prod);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn reset(&mut self) {
|
fn reset(&mut self) {
|
||||||
self.ch1.sweep = Default::default();
|
self.ch1.sweep = Default::default();
|
||||||
self.ch1.duty = Default::default();
|
self.ch1.duty = Default::default();
|
||||||
|
@ -195,7 +191,7 @@ impl Apu {
|
||||||
self.ch2.freq_lo = Default::default();
|
self.ch2.freq_lo = Default::default();
|
||||||
self.ch2.freq_hi = Default::default();
|
self.ch2.freq_hi = Default::default();
|
||||||
|
|
||||||
self.ch3.dac_enabled = Default::default();
|
self.ch3.enabled = Default::default();
|
||||||
self.ch3.len = Default::default();
|
self.ch3.len = Default::default();
|
||||||
self.ch3.volume = Default::default();
|
self.ch3.volume = Default::default();
|
||||||
self.ch3.freq_lo = Default::default();
|
self.ch3.freq_lo = Default::default();
|
||||||
|
@ -209,14 +205,13 @@ impl Apu {
|
||||||
self.ctrl.channel = Default::default();
|
self.ctrl.channel = Default::default();
|
||||||
self.ctrl.output = Default::default();
|
self.ctrl.output = Default::default();
|
||||||
|
|
||||||
// Disable the Channels
|
// Disable the rest of the channels
|
||||||
self.ch1.enabled = Default::default();
|
self.ch1.enabled = Default::default();
|
||||||
self.ch2.enabled = Default::default();
|
self.ch2.enabled = Default::default();
|
||||||
self.ch3.enabled = Default::default();
|
|
||||||
self.ch4.enabled = Default::default();
|
self.ch4.enabled = Default::default();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn process_length(freq_hi: &FrequencyHigh, length_timer: &mut u16, enabled: &mut bool) {
|
fn clock_length(freq_hi: &FrequencyHigh, length_timer: &mut u16, enabled: &mut bool) {
|
||||||
if freq_hi.length_disable() && *length_timer > 0 {
|
if freq_hi.length_disable() && *length_timer > 0 {
|
||||||
*length_timer -= 1;
|
*length_timer -= 1;
|
||||||
|
|
||||||
|
@ -228,7 +223,7 @@ impl Apu {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn ch4_process_length(freq: &Ch4Frequency, length_timer: &mut u16, enabled: &mut bool) {
|
fn clock_length_ch4(freq: &Ch4Frequency, length_timer: &mut u16, enabled: &mut bool) {
|
||||||
if freq.length_disable() && *length_timer > 0 {
|
if freq.length_disable() && *length_timer > 0 {
|
||||||
*length_timer -= 1;
|
*length_timer -= 1;
|
||||||
|
|
||||||
|
@ -240,33 +235,33 @@ impl Apu {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn clock_length(&mut self) {
|
fn handle_length(&mut self) {
|
||||||
Self::process_length(
|
Self::clock_length(
|
||||||
&self.ch1.freq_hi,
|
&self.ch1.freq_hi,
|
||||||
&mut self.ch1.length_timer,
|
&mut self.ch1.length_timer,
|
||||||
&mut self.ch1.enabled,
|
&mut self.ch1.enabled,
|
||||||
);
|
);
|
||||||
|
|
||||||
Self::process_length(
|
Self::clock_length(
|
||||||
&self.ch2.freq_hi,
|
&self.ch2.freq_hi,
|
||||||
&mut self.ch2.length_timer,
|
&mut self.ch2.length_timer,
|
||||||
&mut self.ch2.enabled,
|
&mut self.ch2.enabled,
|
||||||
);
|
);
|
||||||
|
|
||||||
Self::process_length(
|
Self::clock_length(
|
||||||
&self.ch3.freq_hi,
|
&self.ch3.freq_hi,
|
||||||
&mut self.ch3.length_timer,
|
&mut self.ch3.length_timer,
|
||||||
&mut self.ch3.enabled,
|
&mut self.ch3.enabled,
|
||||||
);
|
);
|
||||||
|
|
||||||
Self::ch4_process_length(
|
Self::clock_length_ch4(
|
||||||
&self.ch4.freq,
|
&self.ch4.freq,
|
||||||
&mut self.ch4.length_timer,
|
&mut self.ch4.length_timer,
|
||||||
&mut self.ch4.enabled,
|
&mut self.ch4.enabled,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn clock_sweep(&mut self) {
|
fn handle_sweep(&mut self) {
|
||||||
if self.ch1.sweep_timer != 0 {
|
if self.ch1.sweep_timer != 0 {
|
||||||
self.ch1.sweep_timer -= 1;
|
self.ch1.sweep_timer -= 1;
|
||||||
}
|
}
|
||||||
|
@ -288,7 +283,7 @@ impl Apu {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn process_envelope(envelope: &VolumeEnvelope, period_timer: &mut u8, current_volume: &mut u8) {
|
fn clock_envelope(envelope: &VolumeEnvelope, period_timer: &mut u8, current_volume: &mut u8) {
|
||||||
use EnvelopeDirection::*;
|
use EnvelopeDirection::*;
|
||||||
|
|
||||||
if envelope.period() != 0 {
|
if envelope.period() != 0 {
|
||||||
|
@ -308,29 +303,29 @@ impl Apu {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn clock_envelope(&mut self) {
|
fn handle_volume(&mut self) {
|
||||||
// Channels 1, 2 and 4 have Volume Envelopes
|
// Channels 1, 2 and 4 have Volume Envelopes
|
||||||
|
|
||||||
Self::process_envelope(
|
Self::clock_envelope(
|
||||||
&self.ch1.envelope,
|
&self.ch1.envelope,
|
||||||
&mut self.ch1.period_timer,
|
&mut self.ch1.period_timer,
|
||||||
&mut self.ch1.current_volume,
|
&mut self.ch1.current_volume,
|
||||||
);
|
);
|
||||||
|
|
||||||
Self::process_envelope(
|
Self::clock_envelope(
|
||||||
&self.ch2.envelope,
|
&self.ch2.envelope,
|
||||||
&mut self.ch2.period_timer,
|
&mut self.ch2.period_timer,
|
||||||
&mut self.ch2.current_volume,
|
&mut self.ch2.current_volume,
|
||||||
);
|
);
|
||||||
|
|
||||||
Self::process_envelope(
|
Self::clock_envelope(
|
||||||
&self.ch4.envelope,
|
&self.ch4.envelope,
|
||||||
&mut self.ch4.period_timer,
|
&mut self.ch4.period_timer,
|
||||||
&mut self.ch4.current_volume,
|
&mut self.ch4.current_volume,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_falling_edge(&self, bit: u8, div: u16) -> bool {
|
fn falling_edge(&self, bit: u8, div: u16) -> bool {
|
||||||
match self.div_prev {
|
match self.div_prev {
|
||||||
Some(p) => (p >> bit & 0x01) == 0x01 && (div >> bit & 0x01) == 0x00,
|
Some(p) => (p >> bit & 0x01) == 0x01 && (div >> bit & 0x01) == 0x00,
|
||||||
None => false,
|
None => false,
|
||||||
|
@ -416,6 +411,23 @@ pub(crate) struct Channel1 {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Channel1 {
|
impl Channel1 {
|
||||||
|
fn amplitude(&self) -> f32 {
|
||||||
|
let dac_input = self.duty.wave_pattern().amplitude(self.duty_pos) * self.current_volume;
|
||||||
|
|
||||||
|
(dac_input as f32 / 7.5) - 1.0
|
||||||
|
}
|
||||||
|
|
||||||
|
fn clock(&mut self) {
|
||||||
|
if self.freq_timer != 0 {
|
||||||
|
self.freq_timer -= 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if self.freq_timer == 0 {
|
||||||
|
self.freq_timer = (2048 - self.frequency()) * 4;
|
||||||
|
self.duty_pos = (self.duty_pos + 1) % 8;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// 0xFF10 | NR10 - Channel 1 Sweep Register
|
/// 0xFF10 | NR10 - Channel 1 Sweep Register
|
||||||
pub(crate) fn sweep(&self) -> u8 {
|
pub(crate) fn sweep(&self) -> u8 {
|
||||||
u8::from(self.sweep) | 0x80
|
u8::from(self.sweep) | 0x80
|
||||||
|
@ -444,11 +456,7 @@ impl Channel1 {
|
||||||
|
|
||||||
/// 0xFF12 | NR12 - Channel 1 Volume Envelope
|
/// 0xFF12 | NR12 - Channel 1 Volume Envelope
|
||||||
pub(crate) fn set_envelope(&mut self, byte: u8) {
|
pub(crate) fn set_envelope(&mut self, byte: u8) {
|
||||||
self.envelope = byte.into();
|
self.envelope = byte.into()
|
||||||
|
|
||||||
if !self.is_dac_enabled() {
|
|
||||||
self.enabled = false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 0xFF13 | NR13 - Channel 1 Frequency low (lower 8 bits only)
|
/// 0xFF13 | NR13 - Channel 1 Frequency low (lower 8 bits only)
|
||||||
|
@ -490,29 +498,7 @@ impl Channel1 {
|
||||||
self.length_timer = 64;
|
self.length_timer = 64;
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.is_dac_enabled() {
|
self.enabled = true;
|
||||||
self.enabled = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn tick(&mut self) {
|
|
||||||
if self.freq_timer != 0 {
|
|
||||||
self.freq_timer -= 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if self.freq_timer == 0 {
|
|
||||||
self.freq_timer = (2048 - self.frequency()) * 4;
|
|
||||||
self.duty_pos = (self.duty_pos + 1) % 8;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn amplitude(&self) -> f32 {
|
|
||||||
if self.is_dac_enabled() && self.enabled {
|
|
||||||
let input = self.duty.wave_pattern().amplitude(self.duty_pos) * self.current_volume;
|
|
||||||
(input as f32 / 7.5) - 1.0
|
|
||||||
} else {
|
|
||||||
0.0
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -543,10 +529,6 @@ impl Channel1 {
|
||||||
fn frequency(&self) -> u16 {
|
fn frequency(&self) -> u16 {
|
||||||
(self.freq_hi.freq_bits() as u16) << 8 | self.freq_lo as u16
|
(self.freq_hi.freq_bits() as u16) << 8 | self.freq_lo as u16
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_dac_enabled(&self) -> bool {
|
|
||||||
self.envelope.0 & 0xF8 != 0x00
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Default)]
|
#[derive(Debug, Default)]
|
||||||
|
@ -574,6 +556,23 @@ pub(crate) struct Channel2 {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Channel2 {
|
impl Channel2 {
|
||||||
|
fn amplitude(&self) -> f32 {
|
||||||
|
let dac_input = self.duty.wave_pattern().amplitude(self.duty_pos) * self.current_volume;
|
||||||
|
|
||||||
|
(dac_input as f32 / 7.5) - 1.0
|
||||||
|
}
|
||||||
|
|
||||||
|
fn clock(&mut self) {
|
||||||
|
if self.freq_timer != 0 {
|
||||||
|
self.freq_timer -= 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if self.freq_timer == 0 {
|
||||||
|
self.freq_timer = (2048 - self.frequency()) * 4;
|
||||||
|
self.duty_pos = (self.duty_pos + 1) % 8;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// 0xFF16 | NR21 - Channel 2 Sound length / Wave Pattern Duty
|
/// 0xFF16 | NR21 - Channel 2 Sound length / Wave Pattern Duty
|
||||||
pub(crate) fn duty(&self) -> u8 {
|
pub(crate) fn duty(&self) -> u8 {
|
||||||
u8::from(self.duty) | 0x3F
|
u8::from(self.duty) | 0x3F
|
||||||
|
@ -592,11 +591,7 @@ impl Channel2 {
|
||||||
|
|
||||||
/// 0xFF17 | NR22 - Channel 2 Volume ENvelope
|
/// 0xFF17 | NR22 - Channel 2 Volume ENvelope
|
||||||
pub(crate) fn set_envelope(&mut self, byte: u8) {
|
pub(crate) fn set_envelope(&mut self, byte: u8) {
|
||||||
self.envelope = byte.into();
|
self.envelope = byte.into()
|
||||||
|
|
||||||
if !self.is_dac_enabled() {
|
|
||||||
self.enabled = false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 0xFF18 | NR23 - Channel 2 Frequency low (lower 8 bits only)
|
/// 0xFF18 | NR23 - Channel 2 Frequency low (lower 8 bits only)
|
||||||
|
@ -623,45 +618,19 @@ impl Channel2 {
|
||||||
self.length_timer = 64;
|
self.length_timer = 64;
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.is_dac_enabled() {
|
self.enabled = true;
|
||||||
self.enabled = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn amplitude(&self) -> f32 {
|
|
||||||
if self.is_dac_enabled() && self.enabled {
|
|
||||||
let input = self.duty.wave_pattern().amplitude(self.duty_pos) * self.current_volume;
|
|
||||||
(input as f32 / 7.5) - 1.0
|
|
||||||
} else {
|
|
||||||
0.0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn tick(&mut self) {
|
|
||||||
if self.freq_timer != 0 {
|
|
||||||
self.freq_timer -= 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if self.freq_timer == 0 {
|
|
||||||
self.freq_timer = (2048 - self.frequency()) * 4;
|
|
||||||
self.duty_pos = (self.duty_pos + 1) % 8;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn frequency(&self) -> u16 {
|
fn frequency(&self) -> u16 {
|
||||||
(self.freq_hi.freq_bits() as u16) << 8 | self.freq_lo as u16
|
(self.freq_hi.freq_bits() as u16) << 8 | self.freq_lo as u16
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_dac_enabled(&self) -> bool {
|
|
||||||
self.envelope.0 & 0xF8 != 0x00
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Default)]
|
#[derive(Debug, Default)]
|
||||||
pub(crate) struct Channel3 {
|
pub(crate) struct Channel3 {
|
||||||
/// 0xFF1A | NR30 - Channel 3 Sound on/off
|
/// 0xFF1A | NR30 - Channel 3 Sound on/off
|
||||||
dac_enabled: bool,
|
enabled: bool,
|
||||||
/// 0xFF1B | NR31 - Sound Length
|
/// 0xFF1B | NR31 - Sound Length
|
||||||
len: u8,
|
len: u8,
|
||||||
/// 0xFF1C | NR32 - Channel 3 Volume
|
/// 0xFF1C | NR32 - Channel 3 Volume
|
||||||
|
@ -678,8 +647,6 @@ pub(crate) struct Channel3 {
|
||||||
|
|
||||||
freq_timer: u16,
|
freq_timer: u16,
|
||||||
offset: u8,
|
offset: u8,
|
||||||
|
|
||||||
enabled: bool,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl BusIo for Channel3 {
|
impl BusIo for Channel3 {
|
||||||
|
@ -704,17 +671,13 @@ impl Channel3 {
|
||||||
const WAVE_RAM_START_ADDR: u16 = 0xFF30;
|
const WAVE_RAM_START_ADDR: u16 = 0xFF30;
|
||||||
|
|
||||||
/// 0xFF1A | NR30 - Channel 3 Sound on/off
|
/// 0xFF1A | NR30 - Channel 3 Sound on/off
|
||||||
pub(crate) fn dac_enabled(&self) -> u8 {
|
pub(crate) fn enabled(&self) -> u8 {
|
||||||
((self.dac_enabled as u8) << 7) | 0x7F
|
((self.enabled as u8) << 7) | 0x7F
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 0xFF1A | NR30 - Channel 3 Sound on/off
|
/// 0xFF1A | NR30 - Channel 3 Sound on/off
|
||||||
pub(crate) fn set_dac_enabled(&mut self, byte: u8) {
|
pub(crate) fn set_enabled(&mut self, byte: u8) {
|
||||||
self.dac_enabled = (byte >> 7) & 0x01 == 0x01;
|
self.enabled = (byte >> 7) & 0x01 == 0x01;
|
||||||
|
|
||||||
if !self.dac_enabled {
|
|
||||||
self.enabled = false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 0xFF1B | NR31 - Sound Length
|
/// 0xFF1B | NR31 - Sound Length
|
||||||
|
@ -761,13 +724,18 @@ impl Channel3 {
|
||||||
self.length_timer = 256;
|
self.length_timer = 256;
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.dac_enabled {
|
self.enabled = true;
|
||||||
self.enabled = true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn tick(&mut self) {
|
fn amplitude(&self) -> f32 {
|
||||||
|
let dac_input =
|
||||||
|
(self.read_sample(self.offset) >> self.volume.shift_count()) * self.enabled as u8;
|
||||||
|
|
||||||
|
(dac_input as f32 / 7.5) - 1.0
|
||||||
|
}
|
||||||
|
|
||||||
|
fn clock(&mut self) {
|
||||||
if self.freq_timer != 0 {
|
if self.freq_timer != 0 {
|
||||||
self.freq_timer -= 1;
|
self.freq_timer -= 1;
|
||||||
}
|
}
|
||||||
|
@ -778,15 +746,6 @@ impl Channel3 {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn amplitude(&self) -> f32 {
|
|
||||||
if self.dac_enabled && self.enabled {
|
|
||||||
let input = self.read_sample(self.offset) >> self.volume.shift_count();
|
|
||||||
(input as f32 / 7.5) - 1.0
|
|
||||||
} else {
|
|
||||||
0.0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn read_sample(&self, index: u8) -> u8 {
|
fn read_sample(&self, index: u8) -> u8 {
|
||||||
let i = (index / 2) as usize;
|
let i = (index / 2) as usize;
|
||||||
|
|
||||||
|
@ -844,11 +803,7 @@ impl Channel4 {
|
||||||
|
|
||||||
/// 0xFF21 | NR42 - Channel 4 Volume Envelope
|
/// 0xFF21 | NR42 - Channel 4 Volume Envelope
|
||||||
pub(crate) fn set_envelope(&mut self, byte: u8) {
|
pub(crate) fn set_envelope(&mut self, byte: u8) {
|
||||||
self.envelope = byte.into();
|
self.envelope = byte.into()
|
||||||
|
|
||||||
if !self.is_dac_enabled() {
|
|
||||||
self.enabled = false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 0xFF22 | NR43 - Chanel 4 Polynomial Counter
|
/// 0xFF22 | NR43 - Chanel 4 Polynomial Counter
|
||||||
|
@ -883,13 +838,17 @@ impl Channel4 {
|
||||||
// LFSR behaviour during trigger event
|
// LFSR behaviour during trigger event
|
||||||
self.lf_shift = 0x7FFF;
|
self.lf_shift = 0x7FFF;
|
||||||
|
|
||||||
if self.is_dac_enabled() {
|
self.enabled = true;
|
||||||
self.enabled = true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn tick(&mut self) {
|
fn amplitude(&self) -> f32 {
|
||||||
|
let dac_input = (!self.lf_shift & 0x01) as u8 * self.current_volume;
|
||||||
|
|
||||||
|
(dac_input as f32 / 7.5) - 1.0
|
||||||
|
}
|
||||||
|
|
||||||
|
fn clock(&mut self) {
|
||||||
if self.freq_timer != 0 {
|
if self.freq_timer != 0 {
|
||||||
self.freq_timer -= 1;
|
self.freq_timer -= 1;
|
||||||
}
|
}
|
||||||
|
@ -907,19 +866,6 @@ impl Channel4 {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn amplitude(&self) -> f32 {
|
|
||||||
if self.is_dac_enabled() && self.enabled {
|
|
||||||
let input = (!self.lf_shift & 0x01) as u8 * self.current_volume;
|
|
||||||
(input as f32 / 7.5) - 1.0
|
|
||||||
} else {
|
|
||||||
0.0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn is_dac_enabled(&self) -> bool {
|
|
||||||
self.envelope.0 & 0xF8 != 0x00
|
|
||||||
}
|
|
||||||
|
|
||||||
fn divisor(code: u8) -> u8 {
|
fn divisor(code: u8) -> u8 {
|
||||||
if code == 0 {
|
if code == 0 {
|
||||||
return 8;
|
return 8;
|
||||||
|
|
|
@ -48,7 +48,7 @@ impl<T> SampleProducer<T> {
|
||||||
self.inner.slots() > 2
|
self.inner.slots() > 2
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn available_blocking(&self) -> bool {
|
pub(crate) fn available_block(&self) -> bool {
|
||||||
loop {
|
loop {
|
||||||
if self.inner.slots() > 2 {
|
if self.inner.slots() > 2 {
|
||||||
break true;
|
break true;
|
||||||
|
|
|
@ -73,7 +73,7 @@ pub(crate) mod ch1 {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) mod ch3 {
|
pub(crate) mod ch3 {
|
||||||
#[derive(Debug, Clone, Copy)]
|
#[derive(Debug, Clone, Copy)]
|
||||||
pub(crate) enum Volume {
|
pub(crate) enum Volume {
|
||||||
Mute = 0,
|
Mute = 0,
|
||||||
|
@ -102,7 +102,7 @@ pub(super) mod ch3 {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) mod ch4 {
|
pub(crate) mod ch4 {
|
||||||
use super::bitfield;
|
use super::bitfield;
|
||||||
|
|
||||||
bitfield! {
|
bitfield! {
|
||||||
|
@ -217,7 +217,7 @@ pub(super) mod ch4 {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) mod common {
|
pub(crate) mod common {
|
||||||
use super::bitfield;
|
use super::bitfield;
|
||||||
|
|
||||||
bitfield! {
|
bitfield! {
|
||||||
|
@ -508,52 +508,3 @@ impl From<ChannelControl> for u8 {
|
||||||
ctrl.0
|
ctrl.0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) mod fs {
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub(crate) struct FrameSequencer {
|
|
||||||
step: u8,
|
|
||||||
state: State,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Default for FrameSequencer {
|
|
||||||
fn default() -> Self {
|
|
||||||
Self {
|
|
||||||
step: Default::default(),
|
|
||||||
state: State::Length,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl FrameSequencer {
|
|
||||||
pub(crate) fn next(&mut self) {
|
|
||||||
use State::*;
|
|
||||||
|
|
||||||
self.step = (self.step + 1) % 8;
|
|
||||||
self.state = match self.step {
|
|
||||||
1 | 3 | 5 => Nothing,
|
|
||||||
0 | 4 => Length,
|
|
||||||
2 | 6 => LengthAndSweep,
|
|
||||||
7 => Envelope,
|
|
||||||
_ => unreachable!("Step {} is invalid for the Frame Sequencer", self.step),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn state(&self) -> State {
|
|
||||||
self.state
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn reset(&mut self) {
|
|
||||||
self.step = Default::default();
|
|
||||||
self.state = State::Length;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy)]
|
|
||||||
pub(crate) enum State {
|
|
||||||
Length,
|
|
||||||
Nothing,
|
|
||||||
LengthAndSweep,
|
|
||||||
Envelope,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
18
src/main.rs
18
src/main.rs
|
@ -63,16 +63,16 @@ fn main() -> Result<()> {
|
||||||
};
|
};
|
||||||
|
|
||||||
// Initialize Audio
|
// Initialize Audio
|
||||||
let spsc: AudioSPSC<f32> = Default::default();
|
// let spsc: AudioSPSC<f32> = Default::default();
|
||||||
let (prod, cons) = spsc.init();
|
// let (prod, cons) = spsc.init();
|
||||||
let (_stream, stream_handle) = OutputStream::try_default().expect("Initialized Audio");
|
// let (_stream, stream_handle) = OutputStream::try_default().expect("Initialized Audio");
|
||||||
let sink = Sink::try_new(&stream_handle)?;
|
// let sink = Sink::try_new(&stream_handle)?;
|
||||||
sink.append(cons);
|
// sink.append(cons);
|
||||||
game_boy.apu_mut().attach_producer(prod);
|
// game_boy.apu_mut().set_producer(prod);
|
||||||
|
|
||||||
std::thread::spawn(move || {
|
// std::thread::spawn(move || {
|
||||||
sink.sleep_until_end();
|
// sink.sleep_until_end();
|
||||||
});
|
// });
|
||||||
|
|
||||||
let mut start = Instant::now();
|
let mut start = Instant::now();
|
||||||
let frame_time = Duration::from_secs_f64(1.0 / 59.73); // 59.73 Hz on Host
|
let frame_time = Duration::from_secs_f64(1.0 / 59.73); // 59.73 Hz on Host
|
||||||
|
|
Loading…
Reference in New Issue