diff --git a/src/apu.rs b/src/apu.rs index 1c55c7befa146cefec123ea505c2a9023bcd18b3..66b6c4bb61966dbda8bb6299ec0a267b457fa6bf 100644 --- a/src/apu.rs +++ b/src/apu.rs @@ -1,3 +1,5 @@ +use std::collections::VecDeque; + use crate::warnln; const DUTY_TABLE: [[u8; 8]; 4] = [ @@ -59,15 +61,16 @@ pub struct Apu { wave_ram: [u8; 16], - sampling_frequency: u16, + sampling_rate: u16, sequencer: u16, sequencer_step: u8, output_timer: u16, - audio_buffer: Vec<u8>, + audio_buffer: VecDeque<u8>, + audio_buffer_max: usize, } impl Apu { - pub fn new() -> Self { + pub fn new(sampling_rate: u16) -> Self { Self { ch1_timer: 0, ch1_sequence: 0, @@ -113,14 +116,15 @@ impl Apu { wave_ram: [0u8; 16], - sampling_frequency: 44100, + sampling_rate: sampling_rate, /// Internal sequencer counter that runs at 512Hz /// used for the activation of the tick actions. sequencer: 0, sequencer_step: 0, output_timer: 0, - audio_buffer: Vec::new(), + audio_buffer: VecDeque::with_capacity(sampling_rate as usize), + audio_buffer_max: sampling_rate as usize, } } @@ -232,11 +236,11 @@ impl Apu { self.ch1_output + self.ch2_output + self.ch3_output } - pub fn audio_buffer(&self) -> &Vec<u8> { + pub fn audio_buffer(&self) -> &VecDeque<u8> { &self.audio_buffer } - pub fn audio_buffer_mut(&mut self) -> &mut Vec<u8> { + pub fn audio_buffer_mut(&mut self) -> &mut VecDeque<u8> { &mut self.audio_buffer } @@ -282,10 +286,18 @@ impl Apu { self.output_timer = self.output_timer.saturating_sub(1); if self.output_timer == 0 { - self.audio_buffer.push(self.output()); + // verifies if we've reached the maximum allowed size for the + // audio buffer and if that's the case an item is removed from + // the buffer (avoiding overflow) and then then the new audio + // volume item is added to the queue + if self.audio_buffer.len() >= self.audio_buffer_max { + self.audio_buffer.pop_front(); + } + self.audio_buffer.push_back(self.output()); + // @TODO the CPU clock is hardcoded here, we must handle situations // where there's some kind of overclock - self.output_timer = (4194304.0 / self.sampling_frequency as f32) as u16; + self.output_timer = (4194304.0 / self.sampling_rate as f32) as u16; } } @@ -480,6 +492,6 @@ impl Apu { impl Default for Apu { fn default() -> Self { - Self::new() + Self::new(44100) } } diff --git a/src/gb.rs b/src/gb.rs index 7cbafab922b5774fe8ab867124cf54966a23fd5d..26103de99295869fc0ffa15fa0468a31ad639496 100644 --- a/src/gb.rs +++ b/src/gb.rs @@ -11,6 +11,8 @@ use crate::{ util::read_file, }; +use std::collections::VecDeque; + #[cfg(feature = "wasm")] use wasm_bindgen::prelude::*; @@ -55,7 +57,7 @@ pub struct Registers { pub trait AudioProvider { fn audio_output(&self) -> u8; - fn audio_buffer(&self) -> &Vec<u8>; + fn audio_buffer(&self) -> &VecDeque<u8>; fn clear_audio_buffer(&mut self); } @@ -63,10 +65,10 @@ pub trait AudioProvider { impl GameBoy { #[cfg_attr(feature = "wasm", wasm_bindgen(constructor))] pub fn new() -> Self { - let ppu = Ppu::new(); - let apu = Apu::new(); - let pad = Pad::new(); - let timer = Timer::new(); + let ppu = Ppu::default(); + let apu = Apu::default(); + let pad = Pad::default(); + let timer = Timer::default(); let mmu = Mmu::new(ppu, apu, pad, timer); let cpu = Cpu::new(mmu); Self { cpu } @@ -165,7 +167,7 @@ impl GameBoy { } pub fn audio_buffer_eager(&mut self, clear: bool) -> Vec<u8> { - let buffer = self.audio_buffer().to_vec(); + let buffer = Vec::from(self.audio_buffer().clone()); if clear { self.clear_audio_buffer(); } @@ -287,7 +289,7 @@ impl GameBoy { &(self.ppu().frame_buffer) } - pub fn audio_buffer(&mut self) -> &Vec<u8> { + pub fn audio_buffer(&mut self) -> &VecDeque<u8> { self.apu().audio_buffer() } @@ -399,7 +401,7 @@ impl AudioProvider for GameBoy { self.apu_i().output() } - fn audio_buffer(&self) -> &Vec<u8> { + fn audio_buffer(&self) -> &VecDeque<u8> { self.apu_i().audio_buffer() }