diff --git a/src/apu/mod.rs b/src/apu/mod.rs index 0332dd5..c2ab8e2 100644 --- a/src/apu/mod.rs +++ b/src/apu/mod.rs @@ -30,7 +30,8 @@ use dmc::DMC; // TODO: organize APU structs const FRAME_COUNTER_STEPS: [usize; 5] = [3728, 7456, 11185, 14914, 18640]; -const CYCLES_PER_SAMPLE: f32 = 894_886.5/44_100.0; // APU frequency over sample frequency. May need to turn this down slightly as it's outputting less than 44_100Hz. +// const CYCLES_PER_SAMPLE: f32 = 894_886.5/44_100.0; // APU frequency over sample frequency. May need to turn this down slightly as it's outputting less than 44_100Hz. +const CYCLES_PER_SAMPLE: f32 = 19.65; const LENGTH_COUNTER_TABLE: [u8; 32] = [ 10, 254, 20, 2, 40, 4, 80, 6, 160, 8, 60, 10, 14, 12, 26, 14, 12, 16, 24, 18, 48, 20, 96, 22, 192, 24, 72, 26, 16, 28, 32, 30, @@ -111,6 +112,7 @@ impl Apu { } pub fn write_reg(&mut self, address: usize, value: u8) { + // println!("writing 0b{:08b} to 0x{:X}", value, address); match address { 0x4000 => self.square1.write_duty(value), 0x4001 => self.square1.write_sweep(value), diff --git a/src/apu/square.rs b/src/apu/square.rs index 0063ce0..1ccfe81 100644 --- a/src/apu/square.rs +++ b/src/apu/square.rs @@ -75,7 +75,7 @@ impl Square { } // Update volume for this channel // The mixer receives the current envelope volume except when - self.sample = if self.duty_cycle[self.duty_counter] == 0 // The sequencer output is zero, or + self.sample = if self.duty_cycle[self.duty_counter] == 0 // the sequencer output is zero, or || self.sweep_divider > 0x7FF // overflow from the sweep unit's adder is silencing the channel, || self.length_counter == 0 // the length counter is zero, or || self.timer < 8 { // the timer has a value less than eight. @@ -83,7 +83,6 @@ impl Square { } else { self.decay_counter }; - println!("{}", self.sample); } pub fn clock_envelope(&mut self) { @@ -101,7 +100,7 @@ impl Square { pub fn clock_length_counter(&mut self) { if !(self.length_counter == 0 || self.length_counter_halt) { self.length_counter -= 1; - } + } } fn clock_envelope_divider(&mut self) { @@ -136,7 +135,7 @@ impl Square { } // If the divider's counter is zero, the sweep is enabled, and the sweep unit is not muting the channel: The pulse's period is adjusted. if self.sweep_counter == 0 && self.sweep_enabled && !(self.timer < 8 || self.sweep_divider > 0x7FF) { - self.adjust_sweep(); + self.timer_period = self.sweep_divider; } // If the divider's counter is zero or the reload flag is true: The counter is set to P and the reload flag is cleared. Otherwise, the counter is decremented. if self.sweep_counter == 0 || self.sweep_reload { @@ -147,13 +146,9 @@ impl Square { } } - fn adjust_sweep(&mut self) { - self.timer_period = self.sweep_divider; - } - // $4000/$4004 pub fn write_duty(&mut self, value: u8) { - // TODO: The duty cycle is changed (see table below), but the sequencer's current position isn't affected. + // The duty cycle is changed (see table below), but the sequencer's current position isn't affected. self.duty_cycle = DUTY_CYCLE_SEQUENCES[(value >> 6) as usize]; self.length_counter_halt = value & (1<<5) != 0; self.constant_volume_flag = value & (1<<4) != 0; @@ -175,8 +170,8 @@ impl Square { // $4002/$4006 pub fn write_timer_low(&mut self, value: u8) { - self.timer &= 0b00000111_00000000; // mask off everything but high 3 bits of 11-bit timer - self.timer |= value as u16; // apply low 8 bits + self.timer_period &= 0b00000111_00000000; // mask off everything but high 3 bits of 11-bit timer + self.timer_period |= value as u16; // apply low 8 bits } // $4003/$4007 @@ -186,8 +181,8 @@ impl Square { self.length_counter = super::LENGTH_COUNTER_TABLE[value as usize >> 3]; } let timer_high = value as u16 & 0b0000_0111; - self.timer &= 0b11111000_11111111; // mask off high 3 bits of 11-bit timer - self.timer |= timer_high << 8; // apply high timer bits in their place + self.timer_period &= 0b11111000_11111111; // mask off high 3 bits of 11-bit timer + self.timer_period |= timer_high << 8; // apply high timer bits in their place // The sequencer is immediately restarted at the first value of the current sequence. The envelope is also restarted. The period divider is not reset. self.duty_counter = 0; self.start = true; diff --git a/src/audio.rs b/src/audio.rs index 236734a..1fde837 100644 --- a/src/audio.rs +++ b/src/audio.rs @@ -2,28 +2,6 @@ extern crate sdl2; use sdl2::audio::{AudioCallback, AudioSpecDesired}; -// pub struct Speaker { -// buffer: [f32; 4096*4], -// head: usize, -// } - -// impl AudioCallback for Speaker { -// type Channel = f32; -// fn callback(&mut self, out: &mut [f32]) { -// for (i, x) in out.iter_mut().enumerate() { -// *x = self.buffer[i+self.head]; // get data from apu -// } -// self.head = (self.head + 4096) % (4096*4) -// } -// } - -// impl Speaker { -// pub fn append(&mut self, sample: f32) { -// self.buffer[self.head] = sample; -// self.head = (self.head + 1) % (4096*4); -// } -// } - pub fn initialize(context: &sdl2::Sdl) -> Result, String> { let audio_subsystem = context.audio()?; @@ -35,5 +13,3 @@ pub fn initialize(context: &sdl2::Sdl) -> Result, S audio_subsystem.open_queue(None, &desired_spec) } - -// problem is: how to get data into callback from outside? can't change its signature. can't sneak it in through struct as struct is consumed by the audio device diff --git a/src/main.rs b/src/main.rs index a70b7e8..342f6a5 100644 --- a/src/main.rs +++ b/src/main.rs @@ -37,7 +37,6 @@ fn main() -> Result<(), String> { // Set up audio let mut audio_device = audio::initialize(&sdl_context).expect("Could not create audio device"); let mut half_cycle = false; - let mut audio_buffer = Vec::::new(); audio_device.resume(); // Initialize hardware components @@ -70,19 +69,11 @@ fn main() -> Result<(), String> { match cpu.apu.clock() { Some(sample) => { sps += 1; - // if sample != 0.0 { - // println!("sample {}", sample); - // } - audio_buffer.push(sample) + audio_device.queue(&vec![sample]); }, None => (), }; } - if audio_buffer.len() == 44_100 { - // println!("queueing: {:?}", &audio_buffer[..32]); - audio_device.queue(&audio_buffer); - audio_buffer = vec![]; - } // clock PPU three times for every CPU cycle for _ in 0..cpu_cycles * 3 { let (pixel, end_of_frame) = cpu.ppu.clock(); @@ -130,5 +121,13 @@ fn main() -> Result<(), String> { Ok(()) } -// TODO: reset function? -// TODO: save/load functionality +/* +TODO: +- remaining APU channels +- common mappers +- battery-backed RAM solution +- GUI? drag and drop ROMs? +- reset function +- save/load/pause functionality + +*/