From d630494d65129393645a414cf0ea1adbe9c401c4 Mon Sep 17 00:00:00 2001 From: Astatin Date: Tue, 22 Jul 2025 13:18:50 +0200 Subject: Make audio time accurate using audio buffers --- src/audio.rs | 10 +++++++--- src/desktop/audio.rs | 45 +++++++++++++++++++++++++++++++++++++++------ src/io.rs | 11 ++++++++++- 3 files changed, 56 insertions(+), 10 deletions(-) diff --git a/src/audio.rs b/src/audio.rs index b8f6aa9..427ca26 100644 --- a/src/audio.rs +++ b/src/audio.rs @@ -293,7 +293,7 @@ impl io::Wave for NoiseWave { } #[derive(Clone, Debug)] -struct MutableWave { +pub struct MutableWave { wave_ch1: Arc>>, wave_ch2: Arc>>, wave_ch3: Arc>>, @@ -583,7 +583,7 @@ impl AudioNoiseChannel { } pub struct Channels { - _audio: A, + audio: A, pub ch1: AudioSquareChannel, pub ch2: AudioSquareChannel, @@ -606,11 +606,15 @@ impl Channels { )); Self { - _audio: audio, + audio: audio, ch1: AudioSquareChannel::new(wave_ch1), ch2: AudioSquareChannel::new(wave_ch2), ch3: AudioCustomChannel::new(wave_ch3), ch4: AudioNoiseChannel::new(wave_ch4), } } + + pub fn next(&mut self) { + self.audio.next(); + } } diff --git a/src/desktop/audio.rs b/src/desktop/audio.rs index 2438d01..486b41c 100644 --- a/src/desktop/audio.rs +++ b/src/desktop/audio.rs @@ -1,12 +1,18 @@ use rodio::{OutputStream, Sink, Source}; -use crate::audio::SAMPLE_RATE; +use crate::audio::{SAMPLE_RATE, MutableWave}; use crate::io::{Wave, Audio}; use std::time::Duration; +use std::mem; + +const BUFFER_SIZE: usize = 1024; pub struct RodioAudio { _stream: OutputStream, - _sink: Sink, + sink: Sink, + wave: RodioWave, + buffer: Box<[f32; BUFFER_SIZE]>, + buffer_i: usize, } struct RodioWave(W, usize); @@ -24,7 +30,17 @@ impl Iterator for RodioWave } } -impl Source for RodioWave +struct RodioBuffer>(I); + +impl> Iterator for RodioBuffer { + type Item = f32; + + fn next(&mut self) -> Option { + self.0.next() + } +} + +impl> Source for RodioBuffer { fn current_frame_len(&self) -> Option { None @@ -44,15 +60,32 @@ impl Source for RodioWave } impl Audio for RodioAudio { - fn new(wave: S) -> Self { + fn new(wave: MutableWave) -> Self { let (stream, stream_handle) = OutputStream::try_default().unwrap(); let sink = Sink::try_new(&stream_handle).unwrap(); - sink.append(RodioWave(wave, 0)); + let wave = RodioWave(wave, 0); RodioAudio { _stream: stream, - _sink: sink, + sink: sink, + wave, + buffer: Box::new([0.0; BUFFER_SIZE]), + buffer_i: 0, + } + } + + fn next(&mut self) { + if let Some(v) = self.wave.next() { + self.buffer[self.buffer_i] = v; + self.buffer_i += 1; + + if self.buffer_i == BUFFER_SIZE { + self.buffer_i = 0; + let mut buffer = Box::new([0.0; BUFFER_SIZE]); + mem::swap(&mut self.buffer, &mut buffer); + self.sink.append(RodioBuffer(buffer.into_iter())); + } } } } diff --git a/src/io.rs b/src/io.rs index 92e5984..06775a2 100644 --- a/src/io.rs +++ b/src/io.rs @@ -1,6 +1,7 @@ use std::time::SystemTime; use std::{thread, time}; +use crate::audio::MutableWave; use crate::consts; use crate::state::GBState; @@ -65,7 +66,8 @@ pub trait Wave { } pub trait Audio { - fn new(wave: S) -> Self; + fn new(wave: MutableWave) -> Self; + fn next(&mut self); } pub trait LoadSave @@ -147,6 +149,7 @@ impl Gameboy Gameboy= 32 { + audio_counter -= 32; + state.mem.audio.next(); + } state.div_timer(c); state.tima_timer(c); -- cgit v1.2.3-70-g09d2