aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAstatin <[email protected]>2025-07-22 13:18:50 +0200
committerAstatin <[email protected]>2025-07-22 13:18:50 +0200
commitd630494d65129393645a414cf0ea1adbe9c401c4 (patch)
tree42dbbac277bd5ff96a1905752083eb5403be0b31
parentc6972abff6c81565a41df8731509435274a80c1f (diff)
Make audio time accurate using audio buffers
-rw-r--r--src/audio.rs10
-rw-r--r--src/desktop/audio.rs45
-rw-r--r--src/io.rs11
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<Mutex<Option<Wave>>>,
wave_ch2: Arc<Mutex<Option<Wave>>>,
wave_ch3: Arc<Mutex<Option<Wave>>>,
@@ -583,7 +583,7 @@ impl AudioNoiseChannel {
}
pub struct Channels<A: Audio> {
- _audio: A,
+ audio: A,
pub ch1: AudioSquareChannel,
pub ch2: AudioSquareChannel,
@@ -606,11 +606,15 @@ impl<A: Audio> Channels<A> {
));
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<MutableWave>,
+ buffer: Box<[f32; BUFFER_SIZE]>,
+ buffer_i: usize,
}
struct RodioWave<W: Wave + Send + 'static>(W, usize);
@@ -24,7 +30,17 @@ impl<W: Wave + Send + 'static> Iterator for RodioWave<W>
}
}
-impl<W: Wave + Send + 'static> Source for RodioWave<W>
+struct RodioBuffer<I: Iterator<Item = f32>>(I);
+
+impl<I: Iterator<Item = f32>> Iterator for RodioBuffer<I> {
+ type Item = f32;
+
+ fn next(&mut self) -> Option<Self::Item> {
+ self.0.next()
+ }
+}
+
+impl<I: Iterator<Item = f32>> Source for RodioBuffer<I>
{
fn current_frame_len(&self) -> Option<usize> {
None
@@ -44,15 +60,32 @@ impl<W: Wave + Send + 'static> Source for RodioWave<W>
}
impl Audio for RodioAudio {
- fn new<S: Wave + Send + 'static>(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<S: Wave + Send + 'static>(wave: S) -> Self;
+ fn new(wave: MutableWave) -> Self;
+ fn next(&mut self);
}
pub trait LoadSave
@@ -147,6 +149,7 @@ impl<I: Input, W: Window, S: Serial, A: Audio, LS: LoadSave> Gameboy<I, W, S, A,
let mut total_cycle_counter: u128 = 0;
let mut nanos_sleep: f64 = 0.0;
let mut halt_time = 0;
+ let mut audio_counter = 0;
let mut was_previously_halted = false;
let mut last_ram_bank_enabled = false;
@@ -168,6 +171,12 @@ impl<I: Input, W: Window, S: Serial, A: Audio, LS: LoadSave> Gameboy<I, W, S, A,
state.cpu.dbg_cycle_counter += c;
total_cycle_counter += c as u128;
+ audio_counter += c;
+
+ if audio_counter >= 32 {
+ audio_counter -= 32;
+ state.mem.audio.next();
+ }
state.div_timer(c);
state.tima_timer(c);