Skip to content

Commit

Permalink
APU: reduce allocation by re-using old audio buffers
Browse files Browse the repository at this point in the history
Only give reference to the user, as they don't need the actual Vec
  • Loading branch information
Amjad50 committed Mar 4, 2024
1 parent bd91a5f commit d2924db
Show file tree
Hide file tree
Showing 4 changed files with 60 additions and 24 deletions.
56 changes: 44 additions & 12 deletions mizu-core/src/apu.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,45 @@ use wave_channel::WaveChannel;
/// The main buffer `all` is the summation of all of the other buffers/channels.
/// If you want a combination of different channels, you can just add them together.
/// All volume control is done before pushing to the buffers.
pub struct AudioBuffers {
pub pulse1: Vec<f32>,
pub pulse2: Vec<f32>,
pub wave: Vec<f32>,
pub noise: Vec<f32>,
pub struct AudioBuffers<'a> {
pulse1: &'a mut Vec<f32>,
pulse2: &'a mut Vec<f32>,
wave: &'a mut Vec<f32>,
noise: &'a mut Vec<f32>,

pub all: Vec<f32>,
all: &'a mut Vec<f32>,
}

impl AudioBuffers<'_> {
pub fn pulse1(&self) -> &[f32] {
self.pulse1
}

pub fn pulse2(&self) -> &[f32] {
self.pulse2
}

pub fn wave(&self) -> &[f32] {
self.wave
}

pub fn noise(&self) -> &[f32] {
self.noise
}

pub fn all(&self) -> &[f32] {
self.all
}
}

impl Drop for AudioBuffers<'_> {
fn drop(&mut self) {
self.pulse1.clear();
self.pulse2.clear();
self.wave.clear();
self.noise.clear();
self.all.clear();
}
}

bitflags! {
Expand Down Expand Up @@ -353,14 +385,14 @@ impl Apu {
(p2 << 4) | p1
}

pub fn get_buffers(&mut self) -> AudioBuffers {
pub fn get_buffers(&mut self) -> AudioBuffers<'_> {
AudioBuffers {
pulse1: std::mem::take(&mut self.pulse1_buffers),
pulse2: std::mem::take(&mut self.pulse2_buffers),
wave: std::mem::take(&mut self.wave_buffers),
noise: std::mem::take(&mut self.noise_buffers),
pulse1: &mut self.pulse1_buffers,
pulse2: &mut self.pulse2_buffers,
wave: &mut self.wave_buffers,
noise: &mut self.noise_buffers,

all: std::mem::take(&mut self.buffer),
all: &mut self.buffer,
}
}

Expand Down
2 changes: 2 additions & 0 deletions mizu-core/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,8 @@ impl GameBoy {
}

/// Return the audio buffer of the APU at the current state.
///
/// We use `&mut` as it will also reset the buffers after using them
pub fn audio_buffers(&mut self) -> AudioBuffers {
self.bus.audio_buffers()
}
Expand Down
2 changes: 1 addition & 1 deletion mizu-core/src/memory.rs
Original file line number Diff line number Diff line change
Expand Up @@ -318,7 +318,7 @@ impl Bus {
self.ppu.raw_screen_buffer()
}

pub fn audio_buffers(&mut self) -> AudioBuffers {
pub fn audio_buffers(&mut self) -> AudioBuffers<'_> {
self.apu.get_buffers()
}

Expand Down
24 changes: 13 additions & 11 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -179,17 +179,19 @@ impl GameboyFront {

self.gameboy.clock_for_frame();

let buffers = self.gameboy.audio_buffers();

if let Some(audio_player) = self.audio_player.as_mut() {
let audio_buffer = match self.audio_output {
AudioBufferOutput::All => buffers.all,
AudioBufferOutput::Pulse1 => buffers.pulse1,
AudioBufferOutput::Pulse2 => buffers.pulse2,
AudioBufferOutput::Wave => buffers.wave,
AudioBufferOutput::Noise => buffers.noise,
};
audio_player.queue(&audio_buffer);
{
let buffers = self.gameboy.audio_buffers();

if let Some(audio_player) = self.audio_player.as_mut() {
let audio_buffer = match self.audio_output {
AudioBufferOutput::All => buffers.all(),
AudioBufferOutput::Pulse1 => buffers.pulse1(),
AudioBufferOutput::Pulse2 => buffers.pulse2(),
AudioBufferOutput::Wave => buffers.wave(),
AudioBufferOutput::Noise => buffers.noise(),
};
audio_player.queue(audio_buffer);
}
}

self.window.clear(Color::BLACK);
Expand Down

0 comments on commit d2924db

Please sign in to comment.