Skip to content
Snippets Groups Projects
Verified Commit 5cdf85d4 authored by João Magalhães's avatar João Magalhães :rocket:
Browse files

fix: overflow of the audio buffer with large values

Using a dequeue it's possible to control the size of the queue and outdate old elements.
parent 906bd93c
No related branches found
No related tags found
No related merge requests found
Pipeline #2315 failed
use std::collections::VecDeque;
use crate::warnln; use crate::warnln;
const DUTY_TABLE: [[u8; 8]; 4] = [ const DUTY_TABLE: [[u8; 8]; 4] = [
...@@ -59,15 +61,16 @@ pub struct Apu { ...@@ -59,15 +61,16 @@ pub struct Apu {
wave_ram: [u8; 16], wave_ram: [u8; 16],
sampling_frequency: u16, sampling_rate: u16,
sequencer: u16, sequencer: u16,
sequencer_step: u8, sequencer_step: u8,
output_timer: u16, output_timer: u16,
audio_buffer: Vec<u8>, audio_buffer: VecDeque<u8>,
audio_buffer_max: usize,
} }
impl Apu { impl Apu {
pub fn new() -> Self { pub fn new(sampling_rate: u16) -> Self {
Self { Self {
ch1_timer: 0, ch1_timer: 0,
ch1_sequence: 0, ch1_sequence: 0,
...@@ -113,14 +116,15 @@ impl Apu { ...@@ -113,14 +116,15 @@ impl Apu {
wave_ram: [0u8; 16], wave_ram: [0u8; 16],
sampling_frequency: 44100, sampling_rate: sampling_rate,
/// Internal sequencer counter that runs at 512Hz /// Internal sequencer counter that runs at 512Hz
/// used for the activation of the tick actions. /// used for the activation of the tick actions.
sequencer: 0, sequencer: 0,
sequencer_step: 0, sequencer_step: 0,
output_timer: 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 { ...@@ -232,11 +236,11 @@ impl Apu {
self.ch1_output + self.ch2_output + self.ch3_output 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 &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 &mut self.audio_buffer
} }
...@@ -282,10 +286,18 @@ impl Apu { ...@@ -282,10 +286,18 @@ impl Apu {
self.output_timer = self.output_timer.saturating_sub(1); self.output_timer = self.output_timer.saturating_sub(1);
if self.output_timer == 0 { 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 // @TODO the CPU clock is hardcoded here, we must handle situations
// where there's some kind of overclock // 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 { ...@@ -480,6 +492,6 @@ impl Apu {
impl Default for Apu { impl Default for Apu {
fn default() -> Self { fn default() -> Self {
Self::new() Self::new(44100)
} }
} }
...@@ -11,6 +11,8 @@ use crate::{ ...@@ -11,6 +11,8 @@ use crate::{
util::read_file, util::read_file,
}; };
use std::collections::VecDeque;
#[cfg(feature = "wasm")] #[cfg(feature = "wasm")]
use wasm_bindgen::prelude::*; use wasm_bindgen::prelude::*;
...@@ -55,7 +57,7 @@ pub struct Registers { ...@@ -55,7 +57,7 @@ pub struct Registers {
pub trait AudioProvider { pub trait AudioProvider {
fn audio_output(&self) -> u8; fn audio_output(&self) -> u8;
fn audio_buffer(&self) -> &Vec<u8>; fn audio_buffer(&self) -> &VecDeque<u8>;
fn clear_audio_buffer(&mut self); fn clear_audio_buffer(&mut self);
} }
...@@ -63,10 +65,10 @@ pub trait AudioProvider { ...@@ -63,10 +65,10 @@ pub trait AudioProvider {
impl GameBoy { impl GameBoy {
#[cfg_attr(feature = "wasm", wasm_bindgen(constructor))] #[cfg_attr(feature = "wasm", wasm_bindgen(constructor))]
pub fn new() -> Self { pub fn new() -> Self {
let ppu = Ppu::new(); let ppu = Ppu::default();
let apu = Apu::new(); let apu = Apu::default();
let pad = Pad::new(); let pad = Pad::default();
let timer = Timer::new(); let timer = Timer::default();
let mmu = Mmu::new(ppu, apu, pad, timer); let mmu = Mmu::new(ppu, apu, pad, timer);
let cpu = Cpu::new(mmu); let cpu = Cpu::new(mmu);
Self { cpu } Self { cpu }
...@@ -165,7 +167,7 @@ impl GameBoy { ...@@ -165,7 +167,7 @@ impl GameBoy {
} }
pub fn audio_buffer_eager(&mut self, clear: bool) -> Vec<u8> { 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 { if clear {
self.clear_audio_buffer(); self.clear_audio_buffer();
} }
...@@ -287,7 +289,7 @@ impl GameBoy { ...@@ -287,7 +289,7 @@ impl GameBoy {
&(self.ppu().frame_buffer) &(self.ppu().frame_buffer)
} }
pub fn audio_buffer(&mut self) -> &Vec<u8> { pub fn audio_buffer(&mut self) -> &VecDeque<u8> {
self.apu().audio_buffer() self.apu().audio_buffer()
} }
...@@ -399,7 +401,7 @@ impl AudioProvider for GameBoy { ...@@ -399,7 +401,7 @@ impl AudioProvider for GameBoy {
self.apu_i().output() self.apu_i().output()
} }
fn audio_buffer(&self) -> &Vec<u8> { fn audio_buffer(&self) -> &VecDeque<u8> {
self.apu_i().audio_buffer() self.apu_i().audio_buffer()
} }
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment