Compare commits

..

No commits in common. "db421c58f84f41a6bd0096f57fde733a3ee1734a" and "367eb60238930022081e18632352ad39c5cd3f50" have entirely different histories.

6 changed files with 131 additions and 326 deletions

4
Cargo.lock generated
View File

@ -71,9 +71,9 @@ dependencies = [
[[package]] [[package]]
name = "anyhow" name = "anyhow"
version = "1.0.42" version = "1.0.41"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "595d3cfa7a60d4555cb5067b99f07142a08ea778de5cf993f7b75c7d8fabc486" checksum = "15af2628f6890fe2609a3b91bef4c83450512802e59489f9c1cb1fa5df064a61"
[[package]] [[package]]
name = "arrayvec" name = "arrayvec"

View File

@ -338,16 +338,16 @@ impl BusIo for Bus {
0x10 => self.snd.ch1.sweep = byte.into(), 0x10 => self.snd.ch1.sweep = byte.into(),
0x11 => self.snd.ch1.set_duty(byte), 0x11 => self.snd.ch1.set_duty(byte),
0x12 => self.snd.ch1.envelope = byte.into(), 0x12 => self.snd.ch1.envelope = byte.into(),
0x13 => self.snd.ch1.set_freq_lo(byte), 0x13 => self.snd.ch1.freq_lo = byte,
0x14 => self.snd.ch1.set_freq_hi(byte), 0x14 => self.snd.ch1.set_freq_hi(byte),
0x16 => self.snd.ch2.set_duty(byte), 0x16 => self.snd.ch2.set_duty(byte),
0x17 => self.snd.ch2.envelope = byte.into(), 0x17 => self.snd.ch2.envelope = byte.into(),
0x18 => self.snd.ch2.set_freq_lo(byte), 0x18 => self.snd.ch2.freq_lo = byte,
0x19 => self.snd.ch2.set_freq_hi(byte), 0x19 => self.snd.ch2.set_freq_hi(byte),
0x1A => self.snd.ch3.set_enabled(byte), 0x1A => self.snd.ch3.set_enabled(byte),
0x1B => self.snd.ch3.set_len(byte), 0x1B => self.snd.ch3.set_len(byte),
0x1C => self.snd.ch3.set_volume(byte), 0x1C => self.snd.ch3.set_volume(byte),
0x1D => self.snd.ch3.set_freq_lo(byte), 0x1D => self.snd.ch3.freq_lo = byte,
0x1E => self.snd.ch3.set_freq_hi(byte), 0x1E => self.snd.ch3.set_freq_hi(byte),
0x20 => self.snd.ch4.set_len(byte), 0x20 => self.snd.ch4.set_len(byte),
0x21 => self.snd.ch4.envelope = byte.into(), 0x21 => self.snd.ch4.envelope = byte.into(),

View File

@ -4,8 +4,8 @@ use crate::joypad;
use crate::ppu::Ppu; use crate::ppu::Ppu;
use anyhow::Result; use anyhow::Result;
use gilrs::Gilrs; use gilrs::Gilrs;
use rodio::OutputStreamHandle;
use std::time::Duration; use std::time::Duration;
use winit_input_helper::WinitInputHelper;
pub const SM83_CYCLE_TIME: Duration = Duration::from_nanos(1_000_000_000 / SM83_CLOCK_SPEED); pub const SM83_CYCLE_TIME: Duration = Duration::from_nanos(1_000_000_000 / SM83_CLOCK_SPEED);
pub const CYCLES_IN_FRAME: Cycle = Cycle::new(456 * 154); // 456 Cycles times 154 scanlines pub const CYCLES_IN_FRAME: Cycle = Cycle::new(456 * 154); // 456 Cycles times 154 scanlines
@ -28,26 +28,19 @@ pub fn rom_title(game_boy: &SM83) -> &str {
game_boy.rom_title().unwrap_or(DEFAULT_TITLE) game_boy.rom_title().unwrap_or(DEFAULT_TITLE)
} }
pub fn run( pub fn run(game_boy: &mut SM83, gamepad: &mut Gilrs, pending: Cycle) -> Cycle {
game_boy: &mut SM83,
gamepad: &mut Gilrs,
input: &WinitInputHelper,
pending: Cycle,
) -> Cycle {
let mut elapsed = Cycle::new(0); let mut elapsed = Cycle::new(0);
while elapsed < pending { while elapsed < pending {
elapsed += run_unsynced(game_boy, gamepad, input); elapsed += run_unsynced(game_boy, gamepad);
} }
elapsed elapsed
} }
pub fn run_unsynced(game_boy: &mut SM83, gamepad: &mut Gilrs, input: &WinitInputHelper) -> Cycle { pub fn run_unsynced(game_boy: &mut SM83, gamepad: &mut Gilrs) -> Cycle {
if let Some(event) = gamepad.next_event() { if let Some(event) = gamepad.next_event() {
joypad::handle_gamepad_input(game_boy.joypad_mut(), event); joypad::handle_gamepad_input(&mut game_boy.joypad_mut(), event);
} else {
joypad::handle_keyboard_input(game_boy.joypad_mut(), input);
} }
game_boy.step() game_boy.step()

View File

@ -1,5 +1,4 @@
use gilrs::{Button, Event as GamepadEvent, EventType as GamepadEventType}; use gilrs::{Button, Event as GamepadEvent, EventType as GamepadEventType};
use winit_input_helper::WinitInputHelper;
#[derive(Debug, Clone, Copy)] #[derive(Debug, Clone, Copy)]
pub struct Joypad { pub struct Joypad {
@ -110,63 +109,6 @@ impl ButtonEvent {
} }
} }
pub fn handle_keyboard_input(pad: &mut Joypad, input: &WinitInputHelper) {
use winit::event::VirtualKeyCode;
// TODO: What do I have to do to get a match statement here?
let state = &mut pad.ext;
let irq = &mut pad.interrupt;
if input.key_pressed(VirtualKeyCode::Down) {
state.dpad_down.update(true, irq);
} else if input.key_released(VirtualKeyCode::Down) {
state.dpad_down.update(false, irq);
}
if input.key_pressed(VirtualKeyCode::Up) {
state.dpad_up.update(true, irq);
} else if input.key_released(VirtualKeyCode::Up) {
state.dpad_up.update(false, irq);
}
if input.key_pressed(VirtualKeyCode::Left) {
state.dpad_left.update(true, irq);
} else if input.key_released(VirtualKeyCode::Left) {
state.dpad_left.update(false, irq);
}
if input.key_pressed(VirtualKeyCode::Right) {
state.dpad_right.update(true, irq);
} else if input.key_released(VirtualKeyCode::Right) {
state.dpad_right.update(false, irq);
}
if input.key_pressed(VirtualKeyCode::T) {
state.start.update(true, irq);
} else if input.key_released(VirtualKeyCode::T) {
state.start.update(false, irq);
}
if input.key_pressed(VirtualKeyCode::Y) {
state.select.update(true, irq);
} else if input.key_released(VirtualKeyCode::Y) {
state.select.update(false, irq);
}
if input.key_pressed(VirtualKeyCode::Z) {
state.south.update(true, irq);
} else if input.key_released(VirtualKeyCode::Z) {
state.south.update(false, irq);
}
if input.key_pressed(VirtualKeyCode::X) {
state.east.update(true, irq);
} else if input.key_released(VirtualKeyCode::X) {
state.east.update(false, irq);
}
}
pub fn handle_gamepad_input(pad: &mut Joypad, event: GamepadEvent) { pub fn handle_gamepad_input(pad: &mut Joypad, event: GamepadEvent) {
use Button::*; use Button::*;
use GamepadEventType::*; use GamepadEventType::*;

View File

@ -8,10 +8,11 @@ use std::time::Instant;
use winit::dpi::LogicalSize; use winit::dpi::LogicalSize;
use winit::event::{Event, VirtualKeyCode}; use winit::event::{Event, VirtualKeyCode};
use winit::event_loop::{ControlFlow, EventLoop}; use winit::event_loop::{ControlFlow, EventLoop};
use winit::platform::windows::WindowBuilderExtWindows;
use winit::window::{Window, WindowBuilder}; use winit::window::{Window, WindowBuilder};
use winit_input_helper::WinitInputHelper; use winit_input_helper::WinitInputHelper;
const SCALE: f64 = 2.0; const SCALE: f64 = 5.0;
fn main() -> Result<()> { fn main() -> Result<()> {
let app = App::new(crate_name!()) let app = App::new(crate_name!())
@ -127,7 +128,7 @@ fn main() -> Result<()> {
now = Instant::now(); now = Instant::now();
let pending = Cycle::new(delta / gb::emu::SM83_CYCLE_TIME.subsec_nanos()); let pending = Cycle::new(delta / gb::emu::SM83_CYCLE_TIME.subsec_nanos());
cycle_count += gb::emu::run(&mut game_boy, &mut gamepad, &input, pending); cycle_count += gb::emu::run(&mut game_boy, &mut gamepad, pending);
if cycle_count >= gb::emu::CYCLES_IN_FRAME { if cycle_count >= gb::emu::CYCLES_IN_FRAME {
// Draw Frame // Draw Frame
@ -149,6 +150,6 @@ fn create_window(event_loop: &EventLoop<()>, title: &str) -> Result<Window> {
.with_resizable(true) .with_resizable(true)
.with_decorations(true) .with_decorations(true)
.with_transparent(false) .with_transparent(false)
// .with_drag_and_drop(false) // OleInitialize failed error if this is set to true .with_drag_and_drop(false) // OleInitialize failed error if this is set to true
.build(event_loop)?) .build(event_loop)?)
} }

View File

@ -3,10 +3,11 @@ use crossbeam_channel::{Receiver, Sender};
use rodio::Source; use rodio::Source;
use crate::emu::SM83_CLOCK_SPEED; use crate::emu::SM83_CLOCK_SPEED;
use crate::Cycle;
const WAVE_PATTERN_RAM_LEN: usize = 0x10; const WAVE_PATTERN_RAM_LEN: usize = 0x10;
const SAMPLE_RATE: u32 = 48000; // Hz const SAMPLE_RATE: u32 = 4800; // Hz
const SAMPLE_INCREMENT: u64 = SAMPLE_RATE as u64; const SAMPLE_RATE_IN_CYCLES: Cycle = Cycle::new((SM83_CLOCK_SPEED / SAMPLE_RATE as u64) as u32);
#[derive(Debug, Clone, Default)] #[derive(Debug, Clone, Default)]
pub(crate) struct Sound { pub(crate) struct Sound {
@ -25,13 +26,13 @@ pub(crate) struct Sound {
div_prev: Option<u8>, div_prev: Option<u8>,
sender: Option<SampleSender>, sender: Option<SampleSender>,
sample_counter: u64, cycle: Cycle,
} }
impl Sound { impl Sound {
pub(crate) fn clock(&mut self, div: u16) { pub(crate) fn clock(&mut self, div: u16) {
use FrameSequencerState::*; use FrameSequencerState::*;
self.sample_counter += SAMPLE_INCREMENT; self.cycle += 1;
// the 5th bit of the high byte // the 5th bit of the high byte
let bit_5 = (div >> 13 & 0x01) as u8; let bit_5 = (div >> 13 & 0x01) as u8;
@ -58,38 +59,19 @@ impl Sound {
} }
} }
self.ch1.clock();
self.ch2.clock();
self.ch3.clock();
self.ch4.clock();
self.div_prev = Some(bit_5); self.div_prev = Some(bit_5);
if self.sample_counter >= SM83_CLOCK_SPEED { // TODO: Should the FrameSequencer be run first?
self.sample_counter %= SM83_CLOCK_SPEED; if self.cycle > SAMPLE_RATE_IN_CYCLES {
// Sample the APU // Sample the APU
self.cycle %= SAMPLE_RATE_IN_CYCLES;
let ch1_amplitude = self.ch1.amplitude(); let left_sample = self.ch2.clock();
let ch1_left = self.ctrl.output.ch1_left() as u8 as f32 * ch1_amplitude; let right_sample = self.ch2.clock();
let ch1_right = self.ctrl.output.ch1_right() as u8 as f32 * ch1_amplitude;
let ch2_amplitude = self.ch2.amplitude();
let ch2_left = self.ctrl.output.ch2_left() as u8 as f32 * ch2_amplitude;
let ch2_right = self.ctrl.output.ch2_right() as u8 as f32 * ch2_amplitude;
let ch3_amplitude = self.ch3.amplitude();
let ch3_left = self.ctrl.output.ch3_left() as u8 as f32 * ch3_amplitude;
let ch3_right = self.ctrl.output.ch3_right() as u8 as f32 * ch3_amplitude;
let ch4_amplitude = self.ch4.amplitude();
let ch4_left = self.ctrl.output.ch4_left() as u8 as f32 * ch4_amplitude;
let ch4_right = self.ctrl.output.ch4_right() as u8 as f32 * ch4_amplitude;
let left_sample = (ch1_left + ch2_left + ch3_left + ch4_left) / 4.0;
let right_sample = (ch1_right + ch2_right + ch3_right + ch4_right) / 4.0;
if let Some(send) = self.sender.as_ref() { if let Some(send) = self.sender.as_ref() {
send.add_sample(left_sample, right_sample); send.add_sample(left_sample);
send.add_sample(right_sample);
} }
} }
} }
@ -98,54 +80,46 @@ impl Sound {
self.sender = Some(sender); self.sender = Some(sender);
} }
fn clock_length(freq_hi: &FrequencyHigh, length_timer: &mut u16, enabled: &mut bool) {
if freq_hi.idk() && *length_timer > 0 {
*length_timer -= 1;
// Check in this scope ensures (only) the above subtraction
// made length_timer 0
if *length_timer == 0 {
*enabled = false;
}
}
}
fn clock_length_ch4(freq_data: &Channel4Frequency, length_timer: &mut u16, enabled: &mut bool) {
if freq_data.idk() && *length_timer > 0 {
*length_timer -= 1;
// Check in this scope ensures (only) the above subtraction
// made length_timer 0
if *length_timer == 0 {
*enabled = false;
}
}
}
fn handle_length(&mut self) { fn handle_length(&mut self) {
Self::clock_length( if self.ch1.freq_hi.idk() && self.ch1.length_timer > 0 {
&self.ch1.freq_hi, self.ch1.length_timer -= 1;
&mut self.ch1.length_timer,
&mut self.ch1.enabled,
);
Self::clock_length( // Check in this scope ensures (only) the above subtraction
&self.ch2.freq_hi, // made length_timer 0
&mut self.ch2.length_timer, if self.ch1.length_timer == 0 {
&mut self.ch2.enabled, self.ch1.enabled = false;
); }
}
Self::clock_length( if self.ch2.freq_hi.idk() && self.ch2.length_timer > 0 {
&self.ch3.freq_hi, self.ch2.length_timer -= 1;
&mut self.ch3.length_timer,
&mut self.ch3.enabled,
);
Self::clock_length_ch4( // Check in this scope ensures (only) the above subtraction
&self.ch4.freq_data, // made length_timer 0
&mut self.ch4.length_timer, if self.ch2.length_timer == 0 {
&mut self.ch4.enabled, self.ch2.enabled = false;
); }
}
if self.ch3.freq_hi.idk() && self.ch3.length_timer > 0 {
self.ch3.length_timer -= 1;
// Check in this scope ensures (only) the above subtraction
// made length_timer 0
if self.ch3.length_timer == 0 {
self.ch3.enabled = false;
}
}
if self.ch4.freq_data.idk() && self.ch4.length_timer > 0 {
self.ch4.length_timer -= 1;
// Check in this scope ensures (only) the above subtraction
// made length_timer 0
if self.ch4.length_timer == 0 {
self.ch4.enabled = false;
}
}
} }
fn handle_sweep(&mut self) { fn handle_sweep(&mut self) {
@ -173,46 +147,57 @@ impl Sound {
} }
} }
fn clock_envelope(envelope: &VolumeEnvelope, period_timer: &mut u8, current_volume: &mut u8) { fn handle_volume(&mut self) {
use EnvelopeDirection::*; use EnvelopeDirection::*;
// Channels 1, 2 and 4 have Volume Envelopes
if envelope.period() != 0 { if self.ch1.envelope.period() != 0 {
if *period_timer != 0 { if self.ch1.period_timer > 0 {
*period_timer -= 1; self.ch1.period_timer -= 1;
} }
if *period_timer == 0 { if self.ch1.period_timer == 0 {
*period_timer = envelope.period(); self.ch1.period_timer = self.ch1.envelope.period();
match envelope.direction() { match self.ch1.envelope.direction() {
Decrease if *current_volume > 0x00 => *current_volume -= 1, Decrease if self.ch1.current_volume > 0x00 => self.ch1.current_volume -= 1,
Increase if *current_volume < 0x0F => *current_volume += 1, Increase if self.ch1.current_volume < 0x0F => self.ch1.current_volume += 1,
_ => {} _ => {}
} }
} }
} }
if self.ch2.envelope.period() != 0 {
if self.ch2.period_timer > 0 {
self.ch2.period_timer -= 1;
} }
fn handle_volume(&mut self) { if self.ch2.period_timer == 0 {
// Channels 1, 2 and 4 have Volume Envelopes self.ch2.period_timer = self.ch2.envelope.period();
Self::clock_envelope( match self.ch2.envelope.direction() {
&self.ch1.envelope, Decrease if self.ch2.current_volume > 0x00 => self.ch2.current_volume -= 1,
&mut self.ch1.period_timer, Increase if self.ch2.current_volume < 0x0F => self.ch2.current_volume += 1,
&mut self.ch1.current_volume, _ => {}
); }
}
}
Self::clock_envelope( if self.ch4.envelope.period() != 0 {
&self.ch2.envelope, if self.ch4.period_timer > 0 {
&mut self.ch2.period_timer, self.ch4.period_timer -= 1;
&mut self.ch2.current_volume, }
);
Self::clock_envelope( if self.ch4.period_timer == 0 {
&self.ch4.envelope, self.ch4.period_timer = self.ch4.envelope.period();
&mut self.ch4.period_timer,
&mut self.ch4.current_volume, 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,
_ => {}
}
}
}
} }
} }
@ -357,7 +342,7 @@ pub(crate) struct Channel1 {
/// 0xFF12 | NR12 - Channel 1 Volume Envelope /// 0xFF12 | NR12 - Channel 1 Volume Envelope
pub(crate) envelope: VolumeEnvelope, pub(crate) envelope: VolumeEnvelope,
/// 0xFF13 | NR13 - Channel 1 Frequency low (lower 8 bits only) /// 0xFF13 | NR13 - Channel 1 Frequency low (lower 8 bits only)
freq_lo: u8, pub(crate) freq_lo: u8,
/// 0xFF14 | NR14 - Channel 1 Frequency high /// 0xFF14 | NR14 - Channel 1 Frequency high
freq_hi: FrequencyHigh, freq_hi: FrequencyHigh,
@ -373,34 +358,13 @@ pub(crate) struct Channel1 {
// Length Functionality // Length Functionality
length_timer: u16, length_timer: u16,
freq_timer: u16,
duty_pos: u8,
enabled: bool, enabled: bool,
} }
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 {
// TODO: Why is this 2048?
self.freq_timer = (2048 - self.frequency()) * 4;
self.duty_pos = (self.duty_pos + 1) % 8;
}
}
/// 0xFF11 | NR11 - Channel 1 Sound length / Wave pattern duty /// 0xFF11 | NR11 - Channel 1 Sound length / Wave pattern duty
pub(crate) fn duty(&self) -> u8 { pub(crate) fn duty(&self) -> u8 {
u8::from(self.duty) & 0xC0 // Only bits 7 and 6 can be read self.duty.into()
} }
/// 0xFF11 | NR11 - Channel 1 Sound length / Wave pattern duty /// 0xFF11 | NR11 - Channel 1 Sound length / Wave pattern duty
@ -409,14 +373,9 @@ impl Channel1 {
self.length_timer = 64 - self.duty.sound_length() as u16; self.length_timer = 64 - self.duty.sound_length() as u16;
} }
/// 0xFF13 | NR13 - Channel 1 Frequency low (lower 8 bits only)
pub(crate) fn set_freq_lo(&mut self, byte: u8) {
self.freq_lo = byte;
}
/// 0xFF14 | NR14 - Channel 1 Frequency high /// 0xFF14 | NR14 - Channel 1 Frequency high
pub(crate) fn freq_hi(&self) -> u8 { pub(crate) fn freq_hi(&self) -> u8 {
u8::from(self.freq_hi) & 0x40 // Only bit 6 is readable self.freq_hi.into()
} }
/// 0xFF14 | NR14 - Channel 1 Frequency high /// 0xFF14 | NR14 - Channel 1 Frequency high
@ -543,7 +502,7 @@ pub(crate) struct Channel2 {
/// 0xFF17 | NR22 - Channel 2 Volume ENvelope /// 0xFF17 | NR22 - Channel 2 Volume ENvelope
pub(crate) envelope: VolumeEnvelope, pub(crate) envelope: VolumeEnvelope,
/// 0xFF18 | NR23 - Channel 2 Frequency low (lower 8 bits only) /// 0xFF18 | NR23 - Channel 2 Frequency low (lower 8 bits only)
freq_lo: u8, pub(crate) freq_lo: u8,
/// 0xFF19 | NR24 - Channel 2 Frequency high /// 0xFF19 | NR24 - Channel 2 Frequency high
freq_hi: FrequencyHigh, freq_hi: FrequencyHigh,
@ -561,27 +520,21 @@ pub(crate) struct Channel2 {
} }
impl Channel2 { impl Channel2 {
fn amplitude(&self) -> f32 { fn clock(&mut self) -> u8 {
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; self.freq_timer -= 1;
}
if self.freq_timer == 0 { if self.freq_timer == 0 {
// TODO: Why is this 2048? // TODO: Why is this 2048?
self.freq_timer = (2048 - self.frequency()) * 4; self.freq_timer = (2048 - self.frequency()) * 4;
self.duty_pos = (self.duty_pos + 1) % 8; self.duty_pos = (self.duty_pos + 1) % 8;
} }
self.duty.wave_pattern().amplitude(self.duty_pos)
} }
/// 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) & 0xC0 // Only bits 7 & 6 are readable self.duty.into()
} }
/// 0xFF16 | NR21 - Channel 2 Sound length / Wave Pattern Duty /// 0xFF16 | NR21 - Channel 2 Sound length / Wave Pattern Duty
@ -590,14 +543,9 @@ impl Channel2 {
self.length_timer = 64 - self.duty.sound_length() as u16; self.length_timer = 64 - self.duty.sound_length() as u16;
} }
/// 0xFF18 | NR23 - Channel 2 Frequency low (lower 8 bits only)
pub(crate) fn set_freq_lo(&mut self, byte: u8) {
self.freq_lo = byte;
}
/// 0xFF19 | NR24 - Channel 2 Frequency high /// 0xFF19 | NR24 - Channel 2 Frequency high
pub(crate) fn freq_hi(&self) -> u8 { pub(crate) fn freq_hi(&self) -> u8 {
u8::from(self.freq_hi) & 0x40 // only bit 6 is readable self.freq_hi.into()
} }
/// 0xFF19 | NR24 - Channel 2 Frequency high /// 0xFF19 | NR24 - Channel 2 Frequency high
@ -769,16 +717,13 @@ pub(crate) struct Channel3 {
/// 0xFF1C | NR32 - Channel 3 Volume /// 0xFF1C | NR32 - Channel 3 Volume
volume: Channel3Volume, volume: Channel3Volume,
/// 0xFF1D | NR33 - Channel 3 Frequency low (lower 8 bits) /// 0xFF1D | NR33 - Channel 3 Frequency low (lower 8 bits)
freq_lo: u8, pub(crate) freq_lo: u8,
/// 0xFF1E | NR34 - Channel 3 Frequency high /// 0xFF1E | NR34 - Channel 3 Frequency high
freq_hi: FrequencyHigh, freq_hi: FrequencyHigh,
pub(crate) wave_ram: [u8; WAVE_PATTERN_RAM_LEN], pub(crate) wave_ram: [u8; WAVE_PATTERN_RAM_LEN],
// Length Functionality // Length Functionality
length_timer: u16, length_timer: u16,
freq_timer: u16,
offset: u8,
} }
impl Channel3 { impl Channel3 {
@ -793,14 +738,9 @@ impl Channel3 {
self.length_timer = 256 - self.len as u16; self.length_timer = 256 - self.len as u16;
} }
/// 0xFF1D | NR33 - Channel 3 Frequency low (lower 8 bits)
pub(crate) fn set_freq_lo(&mut self, byte: u8) {
self.freq_lo = byte;
}
/// 0xFF1E | NR34 - Channel 3 Frequency high /// 0xFF1E | NR34 - Channel 3 Frequency high
pub(crate) fn freq_hi(&self) -> u8 { pub(crate) fn freq_hi(&self) -> u8 {
u8::from(self.freq_hi) & 0x40 // Only bit 6 readable self.freq_hi.into()
} }
/// 0xFF1E | NR34 - Channel 3 Frequency high /// 0xFF1E | NR34 - Channel 3 Frequency high
@ -816,7 +756,7 @@ impl Channel3 {
} }
pub(crate) fn enabled(&self) -> u8 { pub(crate) fn enabled(&self) -> u8 {
(self.enabled as u8) << 7 self.enabled as u8
} }
pub(crate) fn set_enabled(&mut self, byte: u8) { pub(crate) fn set_enabled(&mut self, byte: u8) {
@ -838,39 +778,6 @@ impl Channel3 {
_ => unreachable!("{:#04X} is not a valid value for Channel3Volume", byte), _ => unreachable!("{:#04X} is not a valid value for Channel3Volume", byte),
}; };
} }
fn amplitude(&self) -> f32 {
let dac_input = self.read_sample(self.offset) >> self.volume.shift_count();
(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.offset = (self.offset + 1) % 8;
}
}
fn read_sample(&self, index: u8) -> u8 {
let i = index as usize / 2;
if index % 2 == 0 {
// We grab the high nibble on even indexes
self.wave_ram[i] >> 4
} else {
// We grab the low nibble on odd indexes
self.wave_ram[i] & 0x0F
}
}
fn frequency(&self) -> u16 {
(self.freq_hi.freq_bits() as u16) << 8 | self.freq_lo as u16
}
} }
#[derive(Debug, Clone, Copy)] #[derive(Debug, Clone, Copy)]
@ -919,9 +826,7 @@ pub(crate) struct Channel4 {
length_timer: u16, length_timer: u16,
/// Linear Feedback Shift Register (15-bit) /// Linear Feedback Shift Register (15-bit)
lf_shift: u16, shift_register: u16,
freq_timer: u16,
enabled: bool, enabled: bool,
} }
@ -940,7 +845,7 @@ impl Channel4 {
/// 0xFF23 | NR44 - Channel 4 Counter / Consecutive Selector and Restart /// 0xFF23 | NR44 - Channel 4 Counter / Consecutive Selector and Restart
pub(crate) fn freq_data(&self) -> u8 { pub(crate) fn freq_data(&self) -> u8 {
u8::from(self.freq_data) & 0x40 // only bit 6 readable self.freq_data.into()
} }
/// 0xFF23 | NR44 - Channel 4 Counter / Consecutive Selector and Restart /// 0xFF23 | NR44 - Channel 4 Counter / Consecutive Selector and Restart
@ -958,49 +863,17 @@ impl Channel4 {
} }
// LFSR behaviour during trigger event // LFSR behaviour during trigger event
self.lf_shift = 0x7FFF; self.shift_register = 0x7FFF;
} }
} }
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 {
self.freq_timer -= 1;
}
if self.freq_timer == 0 {
let divisor = Self::divisor(self.poly.divisor_code()) as u16;
self.freq_timer = divisor << self.poly.shift_count();
let xor_result = (self.lf_shift & 0x01) ^ ((self.lf_shift & 0x02) >> 1);
self.lf_shift = (self.lf_shift >> 1) | xor_result << 14;
if let CounterWidth::Long = self.poly.counter_width() {
self.lf_shift = (self.lf_shift & !(0x01 << 6)) | xor_result << 6;
}
}
}
fn divisor(code: u8) -> u8 {
if code == 0 {
return 8;
}
code << 4
}
} }
bitfield! { bitfield! {
pub struct PolynomialCounter(u8); pub struct PolynomialCounter(u8);
impl Debug; impl Debug;
shift_count, set_shift_count: 7, 4; freq, set_freq: 7, 4;
from into CounterWidth, counter_width, set_counter_width: 3, 3; from into CounterWidth, counter_width, set_counter_width: 3, 3;
divisor_code, set_divisor_code: 2, 0; div_ratio, set_div_ratio: 2, 0;
} }
impl Copy for PolynomialCounter {} impl Copy for PolynomialCounter {}
@ -1085,14 +958,14 @@ impl From<Channel4Frequency> for u8 {
bitfield! { bitfield! {
pub struct SoundOutput(u8); pub struct SoundOutput(u8);
impl Debug; impl Debug;
pub ch4_left, set_ch4_left: 7; pub snd4_so2, set_snd4_so2: 7;
pub ch3_left, set_ch3_left: 6; pub snd3_so2, set_snd3_so2: 6;
pub ch2_left, set_ch2_left: 5; pub snd2_so2, set_snd2_so2: 5;
pub ch1_left, set_ch1_left: 4; pub snd1_so2, set_snd1_so2: 4;
pub ch4_right, set_ch4_right: 3; pub snd4_so1, set_snd4_so1: 3;
pub ch3_right, set_ch3_right: 2; pub snd3_so1, set_snd3_so1: 2;
pub ch2_right, set_ch2_right: 1; pub snd2_so1, set_snd2_so1: 1;
pub ch1_right, set_ch1_right: 0; pub snd1_so1, set_snd1_so1: 0;
} }
impl Copy for SoundOutput {} impl Copy for SoundOutput {}
@ -1166,23 +1039,19 @@ impl AudioSenderReceiver {
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct SampleSender { pub struct SampleSender {
send: Sender<f32>, send: Sender<u8>,
} }
impl SampleSender { impl SampleSender {
fn add_sample(&self, left: f32, right: f32) { fn add_sample(&self, sample: u8) {
self.send self.send
.send(left) .send(sample)
.expect("Send audio sample across threads");
self.send
.send(right)
.expect("Send audio sample across threads"); .expect("Send audio sample across threads");
} }
} }
pub struct SampleReceiver { pub struct SampleReceiver {
recv: Receiver<f32>, recv: Receiver<u8>,
} }
impl Iterator for SampleReceiver { impl Iterator for SampleReceiver {
@ -1190,7 +1059,7 @@ impl Iterator for SampleReceiver {
fn next(&mut self) -> Option<Self::Item> { fn next(&mut self) -> Option<Self::Item> {
// TODO: Should this never return none? // TODO: Should this never return none?
self.recv.recv().ok() self.recv.recv().ok().map(|num| num as f32)
} }
} }