From 8c30647fc19fb821707e8c23d723be40888a31f5 Mon Sep 17 00:00:00 2001 From: YushiOMOTE Date: Sun, 4 Aug 2024 19:46:28 +0900 Subject: [PATCH] Use buffer for sound --- core/src/apu/buffer.rs | 454 +++++++++++++++++++++++++++++++++++++++++ core/src/apu/mixer.rs | 295 +++++--------------------- core/src/apu/mod.rs | 57 +++--- core/src/apu/stream.rs | 104 ++++++++++ 4 files changed, 638 insertions(+), 272 deletions(-) create mode 100644 core/src/apu/buffer.rs create mode 100644 core/src/apu/stream.rs diff --git a/core/src/apu/buffer.rs b/core/src/apu/buffer.rs new file mode 100644 index 0000000..4e51c31 --- /dev/null +++ b/core/src/apu/buffer.rs @@ -0,0 +1,454 @@ +use alloc::{sync::Arc, vec, vec::Vec}; +use log::*; +use spin::Mutex; + +struct RingBuffer { + events: Vec, + reader: usize, + writer: usize, +} + +impl RingBuffer { + fn new(size: usize) -> Self { + Self { + events: vec![T::default(); size], + reader: 0, + writer: 0, + } + } + + fn push(&mut self, event: T) -> bool { + self.events[self.writer] = event; + let next_writer = (self.writer + 1) % self.events.len(); + if next_writer == self.reader { + return false; + } + self.writer = next_writer; + + true + } + + fn pop(&mut self) -> Option { + if self.reader == self.writer { + None + } else { + let event = self.events[self.reader]; + self.reader = (self.reader + 1) % self.events.len(); + Some(event) + } + } +} + +#[test] +fn test_ring_buffer() { + let mut b = RingBuffer::::new(10); + + assert!(b.pop().is_none()); + assert!(b.push(Frame::new(1, 0))); + assert_eq!(b.pop().unwrap().cycles, 1); + assert!(b.pop().is_none()); + assert!(b.push(Frame::new(2, 0))); + assert!(b.push(Frame::new(3, 0))); + assert_eq!(b.pop().unwrap().cycles, 2); + assert_eq!(b.pop().unwrap().cycles, 3); + assert!(b.pop().is_none()); + assert!(b.push(Frame::new(4, 0))); + assert_eq!(b.pop().unwrap().cycles, 4); + assert!(b.pop().is_none()); +} + +#[test] +fn test_ring_buffer_overflow() { + let mut b = RingBuffer::::new(10); + + for i in 0..9 { + assert!(b.push(Frame::new(i, 0))); + } + + assert!(!b.push(Frame::new(9, 0))); + + for i in 0..9 { + assert_eq!(b.pop().unwrap().cycles, i); + } + + assert!(b.pop().is_none()); +} + +#[derive(Clone)] +pub struct SharedRingBuffer { + inner: Arc>>, +} + +impl SharedRingBuffer { + fn new(size: usize) -> Self { + Self { + inner: Arc::new(Mutex::new(RingBuffer::new(size))), + } + } + + fn push(&self, event: T) -> bool { + self.inner.lock().push(event) + } + + fn pop(&self) -> Option { + self.inner.lock().pop() + } +} + +#[derive(Debug, Clone, Copy, Default)] +struct Frame { + cycles: usize, + diff: isize, +} + +impl Frame { + fn new(cycles: usize, diff: isize) -> Self { + Self { cycles, diff } + } +} + +pub struct Producer { + cycles: usize, + amp: isize, + buf: SharedRingBuffer, + max_frame_size: usize, +} + +impl Producer { + fn new(buf: SharedRingBuffer, max_frame_size: usize) -> Self { + Self { + amp: 0, + cycles: 0, + buf, + max_frame_size, + } + } + + pub fn add_sample(&mut self, cycles: usize, amp: isize) { + assert!(cycles > 0); + + self.cycles = self.cycles.saturating_add(cycles); + + if self.amp != amp || self.cycles >= self.max_frame_size { + if self.buf.push(Frame::new(self.cycles, amp - self.amp)) { + self.cycles = 0; + self.amp = amp; + } else { + warn!("Ring buffer overflow. Skip a sample"); + } + } + } +} + +#[derive(Clone)] +pub struct Consumer { + amp: isize, + cycles: usize, + next: Option, + buf: SharedRingBuffer, +} + +impl Consumer { + fn new(buf: SharedRingBuffer) -> Self { + Self { + amp: 0, + cycles: 0, + next: None, + buf, + } + } + + pub fn get_sample(&mut self, cycles: usize) -> isize { + assert!(cycles > 0); + + if self.next.is_none() { + self.next = self.buf.pop(); + + if self.next.is_none() { + // No new frame. Wait for a new frame arrival. + // Keep the last amp until the new frame arrives. + return self.amp; + } + } + + self.cycles += cycles; + + while self.next.is_some() { + match self.next.as_mut() { + Some(e) if self.cycles >= e.cycles => { + self.cycles -= e.cycles; + self.amp += e.diff; + self.next = self.buf.pop(); + } + Some(e) => { + e.cycles -= self.cycles; + self.cycles = 0; + break; + } + None => break, + } + } + + self.amp + } +} + +pub fn open_buffer(buf_size: usize, max_frame_size: usize) -> (Producer, Consumer) { + let buf = SharedRingBuffer::new(buf_size); + + ( + Producer::new(buf.clone(), max_frame_size), + Consumer::new(buf), + ) +} + +#[test] +fn test_stream() { + let (mut p, mut c) = open_buffer(10, 10); + + p.add_sample(1, 5); + p.add_sample(1, 6); + p.add_sample(1, 7); + p.add_sample(1, 8); + p.add_sample(1, 7); + p.add_sample(1, 6); + + assert_eq!(c.get_sample(1), 5); + assert_eq!(c.get_sample(1), 6); + assert_eq!(c.get_sample(1), 7); + assert_eq!(c.get_sample(1), 8); + assert_eq!(c.get_sample(1), 7); + assert_eq!(c.get_sample(1), 6); +} + +#[test] +fn test_stream_consume_by_2() { + let (mut p, mut c) = open_buffer(10, 10); + + p.add_sample(1, 5); + p.add_sample(1, 6); + p.add_sample(1, 7); + p.add_sample(1, 8); + p.add_sample(1, 7); + p.add_sample(1, 6); + + assert_eq!(c.get_sample(2), 6); + assert_eq!(c.get_sample(2), 8); + assert_eq!(c.get_sample(2), 6); +} + +#[test] +fn test_stream_consume_by_3() { + let (mut p, mut c) = open_buffer(10, 10); + + p.add_sample(1, 5); + p.add_sample(1, 6); + p.add_sample(1, 7); + p.add_sample(1, 8); + p.add_sample(1, 7); + p.add_sample(1, 6); + + assert_eq!(c.get_sample(3), 7); + assert_eq!(c.get_sample(3), 6); +} + +#[test] +fn test_stream_produce_4_consume_1() { + let (mut p, mut c) = open_buffer(50, 50); + + p.add_sample(4, 5); + p.add_sample(4, 6); + p.add_sample(4, 7); + p.add_sample(4, 8); + p.add_sample(4, 7); + p.add_sample(4, 6); + + assert_eq!(c.get_sample(1), 0); + assert_eq!(c.get_sample(1), 0); + assert_eq!(c.get_sample(1), 0); + assert_eq!(c.get_sample(1), 5); + assert_eq!(c.get_sample(1), 5); + assert_eq!(c.get_sample(1), 5); + assert_eq!(c.get_sample(1), 5); + assert_eq!(c.get_sample(1), 6); + assert_eq!(c.get_sample(1), 6); + assert_eq!(c.get_sample(1), 6); + assert_eq!(c.get_sample(1), 6); + assert_eq!(c.get_sample(1), 7); + assert_eq!(c.get_sample(1), 7); + assert_eq!(c.get_sample(1), 7); + assert_eq!(c.get_sample(1), 7); + assert_eq!(c.get_sample(1), 8); + assert_eq!(c.get_sample(1), 8); + assert_eq!(c.get_sample(1), 8); + assert_eq!(c.get_sample(1), 8); + assert_eq!(c.get_sample(1), 7); + assert_eq!(c.get_sample(1), 7); + assert_eq!(c.get_sample(1), 7); + assert_eq!(c.get_sample(1), 7); + assert_eq!(c.get_sample(1), 6); + assert_eq!(c.get_sample(1), 6); + assert_eq!(c.get_sample(1), 6); + assert_eq!(c.get_sample(1), 6); +} + +#[test] +fn test_stream_produce_4_consume_2() { + let (mut p, mut c) = open_buffer(50, 50); + + p.add_sample(4, 5); + p.add_sample(4, 6); + p.add_sample(4, 7); + p.add_sample(4, 8); + p.add_sample(4, 7); + p.add_sample(4, 6); + + assert_eq!(c.get_sample(2), 0); + assert_eq!(c.get_sample(2), 5); + assert_eq!(c.get_sample(2), 5); + assert_eq!(c.get_sample(2), 6); + assert_eq!(c.get_sample(2), 6); + assert_eq!(c.get_sample(2), 7); + assert_eq!(c.get_sample(2), 7); + assert_eq!(c.get_sample(2), 8); + assert_eq!(c.get_sample(2), 8); + assert_eq!(c.get_sample(2), 7); + assert_eq!(c.get_sample(2), 7); + assert_eq!(c.get_sample(2), 6); + assert_eq!(c.get_sample(2), 6); +} + +#[test] +fn test_stream_underrun() { + let (mut p, mut c) = open_buffer(10, 10); + + assert_eq!(c.get_sample(1), 0); + assert_eq!(c.get_sample(1), 0); + assert_eq!(c.get_sample(1), 0); + + p.add_sample(1, 5); + p.add_sample(1, 6); + p.add_sample(1, 7); + p.add_sample(1, 8); + p.add_sample(1, 7); + p.add_sample(1, 6); + + assert_eq!(c.get_sample(1), 5); + assert_eq!(c.get_sample(1), 6); + assert_eq!(c.get_sample(1), 7); + assert_eq!(c.get_sample(1), 8); + assert_eq!(c.get_sample(1), 7); + assert_eq!(c.get_sample(1), 6); +} + +#[test] +fn test_stream_underrun_in_middle() { + let (mut p, mut c) = open_buffer(10, 10); + + p.add_sample(1, 5); + p.add_sample(1, 6); + p.add_sample(1, 7); + + assert_eq!(c.get_sample(1), 5); + assert_eq!(c.get_sample(1), 6); + assert_eq!(c.get_sample(1), 7); + assert_eq!(c.get_sample(1), 7); + + p.add_sample(1, 8); + p.add_sample(1, 7); + p.add_sample(1, 6); + + assert_eq!(c.get_sample(1), 8); + assert_eq!(c.get_sample(1), 7); + assert_eq!(c.get_sample(1), 6); +} + +#[test] +fn test_stream_empty() { + let (_, mut c) = open_buffer(10, 10); + + assert_eq!(c.get_sample(1), 0); + assert_eq!(c.get_sample(1), 0); + assert_eq!(c.get_sample(1), 0); + assert_eq!(c.get_sample(1), 0); + assert_eq!(c.get_sample(1), 0); + assert_eq!(c.get_sample(1), 0); +} + +#[test] +fn test_stream_same_sound() { + let (mut p, mut c) = open_buffer(10, 10); + + p.add_sample(1, 5); + p.add_sample(1, 5); + p.add_sample(1, 6); + p.add_sample(1, 6); + p.add_sample(1, 6); + p.add_sample(1, 6); + p.add_sample(1, 7); + p.add_sample(1, 7); + p.add_sample(1, 7); + p.add_sample(1, 7); + p.add_sample(1, 7); + p.add_sample(1, 7); + p.add_sample(1, 8); + p.add_sample(1, 7); + p.add_sample(1, 6); + p.add_sample(1, 6); + + assert_eq!(c.get_sample(1), 5); + assert_eq!(c.get_sample(1), 5); + assert_eq!(c.get_sample(1), 6); + assert_eq!(c.get_sample(1), 6); + assert_eq!(c.get_sample(1), 6); + assert_eq!(c.get_sample(1), 6); + assert_eq!(c.get_sample(1), 7); + assert_eq!(c.get_sample(1), 7); + assert_eq!(c.get_sample(1), 7); + assert_eq!(c.get_sample(1), 7); + assert_eq!(c.get_sample(1), 7); + assert_eq!(c.get_sample(1), 7); + assert_eq!(c.get_sample(1), 8); + assert_eq!(c.get_sample(1), 7); + assert_eq!(c.get_sample(1), 6); + assert_eq!(c.get_sample(1), 6); +} + +#[test] +fn test_stream_same_sound_small_max_frame_size() { + let (mut p, mut c) = open_buffer(10, 2); + + p.add_sample(1, 5); + p.add_sample(1, 5); + p.add_sample(1, 6); + p.add_sample(1, 6); + p.add_sample(1, 6); + p.add_sample(1, 6); + p.add_sample(1, 7); + p.add_sample(1, 7); + p.add_sample(1, 7); + p.add_sample(1, 7); + p.add_sample(1, 7); + p.add_sample(1, 7); + p.add_sample(1, 8); + p.add_sample(1, 7); + p.add_sample(1, 6); + p.add_sample(1, 6); + + assert_eq!(c.get_sample(1), 5); + assert_eq!(c.get_sample(1), 5); + assert_eq!(c.get_sample(1), 6); + assert_eq!(c.get_sample(1), 6); + assert_eq!(c.get_sample(1), 6); + assert_eq!(c.get_sample(1), 6); + assert_eq!(c.get_sample(1), 7); + assert_eq!(c.get_sample(1), 7); + assert_eq!(c.get_sample(1), 7); + assert_eq!(c.get_sample(1), 7); + assert_eq!(c.get_sample(1), 7); + assert_eq!(c.get_sample(1), 7); + assert_eq!(c.get_sample(1), 8); + assert_eq!(c.get_sample(1), 7); + assert_eq!(c.get_sample(1), 6); + assert_eq!(c.get_sample(1), 6); +} diff --git a/core/src/apu/mixer.rs b/core/src/apu/mixer.rs index 5638e5d..e3bc186 100644 --- a/core/src/apu/mixer.rs +++ b/core/src/apu/mixer.rs @@ -1,20 +1,9 @@ -use super::{ - frame_sequencer::{Frame, FrameSequencer}, - noise::Noise, - tone::Tone, - wave::Wave, -}; -use crate::{cpu::CPU_FREQ_HZ, divider::Divider, hardware::Stream}; -use alloc::sync::Arc; use bitfield_struct::bitfield; -use core::sync::atomic::{AtomicIsize, Ordering}; -use spin::Mutex; pub struct Mixer { power: bool, nr50: Nr50, nr51: Nr51, - state: SharedState, } #[bitfield(u8)] @@ -29,14 +18,22 @@ struct Nr50 { #[bitfield(u8)] struct Nr51 { - ch1_right: bool, - ch2_right: bool, - ch3_right: bool, - ch4_right: bool, - ch1_left: bool, - ch2_left: bool, - ch3_left: bool, - ch4_left: bool, + #[bits(1)] + ch1_right: isize, + #[bits(1)] + ch2_right: isize, + #[bits(1)] + ch3_right: isize, + #[bits(1)] + ch4_right: isize, + #[bits(1)] + ch1_left: isize, + #[bits(1)] + ch2_left: isize, + #[bits(1)] + ch3_left: isize, + #[bits(1)] + ch4_left: isize, } impl Mixer { @@ -45,7 +42,6 @@ impl Mixer { power: false, nr50: Nr50::default(), nr51: Nr51::default(), - state: SharedState::new(), } } @@ -61,8 +57,6 @@ impl Mixer { } self.nr50 = Nr50::from_bits(value); - - self.sync_volume(); } /// Read NR51 register (0xff25) @@ -77,54 +71,19 @@ impl Mixer { } self.nr51 = Nr51::from_bits(value); - - self.sync_volume(); - } - - pub fn sync_tone(&mut self, index: usize, tone: Tone) { - self.state.tones[index].sync_channel(tone); - } - - pub fn sync_wave(&mut self, wave: Wave) { - self.state.wave.sync_channel(wave); - } - - pub fn sync_noise(&mut self, noise: Noise) { - self.state.noise.sync_channel(noise); - } - - fn sync_volume(&mut self) { - self.state - .sync_volume(0, (self.nr50.left_volume() + 1) as isize); - self.state - .sync_volume(1, (self.nr50.right_volume() + 1) as isize); - - self.state.tones[0].sync_volume(0, self.nr51.ch1_left() as isize); - self.state.tones[0].sync_volume(1, self.nr51.ch1_right() as isize); - self.state.tones[1].sync_volume(0, self.nr51.ch2_left() as isize); - self.state.tones[1].sync_volume(1, self.nr51.ch2_right() as isize); - self.state - .wave - .sync_volume(0, self.nr51.ch3_left() as isize); - self.state - .wave - .sync_volume(1, self.nr51.ch3_right() as isize); - self.state - .noise - .sync_volume(0, self.nr51.ch4_left() as isize); - self.state - .noise - .sync_volume(1, self.nr51.ch4_right() as isize); } - pub fn create_stream(&self) -> MixerStream { - MixerStream::new(self.state.clone()) + pub fn builder(&self) -> AmpBuilder { + AmpBuilder { + left: 0, + right: 0, + nr50: self.nr50.clone(), + nr51: self.nr51.clone(), + } } pub fn power_on(&mut self) { self.power = true; - - self.sync_volume(); } pub fn power_off(&mut self) { @@ -132,199 +91,45 @@ impl Mixer { self.nr50 = Nr50::default(); self.nr51 = Nr51::default(); - - self.sync_volume(); } } -#[derive(Debug, Clone)] -struct Shared { - channel: Arc>, - volumes: [Arc; 2], -} - -impl Shared { - fn new(channel: T) -> Self { - Self { - channel: Arc::new(Mutex::new(channel)), - volumes: [Arc::new(AtomicIsize::new(0)), Arc::new(AtomicIsize::new(0))], - } - } - - fn step(&mut self, cycles: usize, frame: Frame) { - self.channel.lock().step(cycles, frame); - } - - fn sync_channel(&self, channel: T) { - *self.channel.lock() = channel; - } - - fn sync_volume(&self, index: usize, volume: isize) { - self.volumes[index].store(volume, Ordering::Relaxed); - } - - fn volume(&mut self, index: usize) -> isize { - self.volumes[index].load(Ordering::Relaxed) * self.channel.lock().amp() - } -} - -trait VolumeUnit { - fn amp(&self) -> isize; - - fn step(&mut self, rate: usize, frame: Frame); -} - -impl VolumeUnit for Tone { - fn amp(&self) -> isize { - self.amp() - } - - fn step(&mut self, cycles: usize, frame: Frame) { - self.step(cycles, frame); - } -} - -impl VolumeUnit for Wave { - fn amp(&self) -> isize { - self.amp() - } - - fn step(&mut self, cycles: usize, frame: Frame) { - self.step(cycles, frame); - } -} - -impl VolumeUnit for Noise { - fn amp(&self) -> isize { - self.amp() - } - - fn step(&mut self, cycles: usize, frame: Frame) { - self.step(cycles, frame); - } -} - -#[derive(Clone)] -pub struct SharedState { - tones: [Shared; 2], - wave: Shared, - noise: Shared, - volumes: [Arc; 2], -} - -impl SharedState { - fn new() -> Self { - Self { - tones: [Shared::new(Tone::new(true)), Shared::new(Tone::new(false))], - wave: Shared::new(Wave::new()), - noise: Shared::new(Noise::new()), - volumes: [Arc::new(AtomicIsize::new(0)), Arc::new(AtomicIsize::new(0))], - } - } - - fn sync_volume(&self, index: usize, volume: isize) { - self.volumes[index].store(volume, Ordering::Relaxed); - } - - fn volume(&self, index: usize) -> isize { - self.volumes[index].load(Ordering::Relaxed) - } -} - -pub struct MixerStream { - state: SharedState, - upscaler: UpScaler, - divider: Divider, - frame_sequencer: FrameSequencer, -} - -impl MixerStream { - fn new(state: SharedState) -> Self { - Self { - state, - upscaler: UpScaler::new(CPU_FREQ_HZ), - divider: Divider::new(), - frame_sequencer: FrameSequencer::new(), - } - } - - fn step(&mut self, rate: usize) { - let mut cycles = self.upscaler.compute_cycles(rate); - - while cycles > 0 { - let sub_cycles = cycles.max(4); - - let div = self.divider.step(sub_cycles); - let step = self.frame_sequencer.step(cycles, div); - - self.state.tones[0].step(sub_cycles, step); - self.state.tones[1].step(sub_cycles, step); - self.state.wave.step(sub_cycles, step); - self.state.noise.step(sub_cycles, step); - - cycles -= sub_cycles; - } - } -} - -#[derive(Clone)] -struct UpScaler { - target_rate: usize, - count: usize, +pub struct AmpBuilder { + left: isize, + right: isize, + nr50: Nr50, + nr51: Nr51, } -impl UpScaler { - fn new(target_rate: usize) -> Self { - Self { - target_rate, - count: 0, - } - } - - fn compute_cycles(&mut self, rate: usize) -> usize { - let mut cycles = 0; - - while self.count < self.target_rate { - self.count += rate; - cycles += 1; - } - self.count -= self.target_rate; - - cycles +impl AmpBuilder { + pub fn tone1(mut self, amp: isize) -> Self { + self.left += amp * self.nr51.ch1_left(); + self.right += amp * self.nr51.ch1_right(); + self } -} -impl Stream for MixerStream { - fn max(&self) -> u16 { - // Master volume max is 8, we have left and right: 8 * 2 - // Each channel max is 15, 4 channels, left and right: 15 * 4 * 2 - 8 * 2 * 15 * 4 * 2 + pub fn tone2(mut self, amp: isize) -> Self { + self.left += amp * self.nr51.ch2_left(); + self.right += amp * self.nr51.ch2_right(); + self } - fn next(&mut self, rate: u32) -> u16 { - let (left, right) = self.next_dual(rate); - (left + right) / 2 + pub fn wave(mut self, amp: isize) -> Self { + self.left += amp * self.nr51.ch3_left(); + self.right += amp * self.nr51.ch3_right(); + self } - fn next_dual(&mut self, rate: u32) -> (u16, u16) { - let center = (self.max() / 2) as isize; - - self.step(rate as usize); - - let mut values = (0..2).map(|i| { - let mut vol = 0; - vol += self.state.tones[0].volume(i); - vol += self.state.tones[1].volume(i); - vol += self.state.wave.volume(i); - vol += self.state.noise.volume(i); - vol *= self.state.volume(i); - (vol + center) as u16 * 2 - }); - - (values.next().unwrap(), values.next().unwrap()) + pub fn noise(mut self, amp: isize) -> Self { + self.left += amp * self.nr51.ch4_left(); + self.right += amp * self.nr51.ch4_right(); + self } - fn on(&self) -> bool { - true + pub fn build(self) -> (isize, isize) { + ( + self.left * (self.nr50.left_volume() + 1) as isize, + self.right * (self.nr50.right_volume() + 1) as isize, + ) } } diff --git a/core/src/apu/mod.rs b/core/src/apu/mod.rs index ffca195..eb8e4d7 100644 --- a/core/src/apu/mod.rs +++ b/core/src/apu/mod.rs @@ -4,16 +4,25 @@ use log::*; use crate::hardware::HardwareHandle; -use self::{frame_sequencer::FrameSequencer, mixer::Mixer, noise::Noise, tone::Tone, wave::Wave}; +use self::{ + frame_sequencer::FrameSequencer, + mixer::Mixer, + noise::Noise, + stream::{open_stream, SoundSink}, + tone::Tone, + wave::Wave, +}; use bitfield_struct::bitfield; +mod buffer; mod dac; mod envelope; mod frame_sequencer; mod length_counter; mod mixer; mod noise; +mod stream; mod sweep; mod tone; mod wave; @@ -25,6 +34,7 @@ pub struct Apu { mixer: Mixer, nr52: Nr52, frame_sequencer: FrameSequencer, + sink: SoundSink, } #[bitfield(u8)] @@ -50,9 +60,9 @@ impl Apu { pub fn new(hw: HardwareHandle) -> Self { let mixer = Mixer::new(); - hw.get() - .borrow_mut() - .sound_play(Box::new(mixer.create_stream())); + let (sink, stream) = open_stream(); + + hw.get().borrow_mut().sound_play(Box::new(stream)); Self { tones: [Tone::new(true), Tone::new(false)], @@ -61,6 +71,7 @@ impl Apu { mixer, nr52: Nr52::default(), frame_sequencer: FrameSequencer::new(), + sink, } } @@ -101,7 +112,7 @@ impl Apu { /// Write NR13/NR23 register (0xff13/0xff18) pub fn write_tone_freq_low(&mut self, tone: usize, value: u8) { - self.tones[tone].write_freq_low(value) + self.tones[tone].write_freq_low(value); } /// Read NR14/NR24 register (0xff14/0xff19) @@ -111,9 +122,7 @@ impl Apu { /// Write NR14/NR24 register (0xff14/0xff19) pub fn write_tone_freq_high(&mut self, tone: usize, value: u8) { - if self.tones[tone].write_freq_high(value) { - self.mixer.sync_tone(tone, self.tones[tone].clone()); - } + self.tones[tone].write_freq_high(value); } /// Read NR30 register (0xff1a) @@ -124,7 +133,6 @@ impl Apu { /// Write NR30 register (0xff1a) pub fn write_wave_enable(&mut self, value: u8) { self.wave.write_enable(value); - self.mixer.sync_wave(self.wave.clone()); } /// Read NR31 register (0xff1b) @@ -164,9 +172,7 @@ impl Apu { /// Write NR34 register (0xff1e) pub fn write_wave_freq_high(&mut self, value: u8) { - if self.wave.write_freq_high(value) { - self.mixer.sync_wave(self.wave.clone()); - } + self.wave.write_freq_high(value); } /// Read wave pattern buffer @@ -216,9 +222,7 @@ impl Apu { /// Write NR44 register (0xff23) pub fn write_noise_select(&mut self, value: u8) { - if self.noise.write_select(value) { - self.mixer.sync_noise(self.noise.clone()); - } + self.noise.write_select(value); } /// Read NR50 register (0xff24) @@ -276,8 +280,6 @@ impl Apu { self.wave.power_on(); self.noise.power_on(); self.mixer.power_on(); - - self.sync_all(); } else if before && !after { info!("Sound master disabled"); @@ -287,8 +289,6 @@ impl Apu { self.wave.power_off(); self.noise.power_off(); self.mixer.power_off(); - - self.sync_all(); } } @@ -309,14 +309,6 @@ impl Apu { pcm.into_bits() } - fn sync_all(&mut self) { - for (i, tone) in self.tones.iter().enumerate() { - self.mixer.sync_tone(i, tone.clone()); - } - self.mixer.sync_wave(self.wave.clone()); - self.mixer.sync_noise(self.noise.clone()); - } - pub fn step(&mut self, cycles: usize, div: usize) { let frame = self.frame_sequencer.step(cycles, div); @@ -325,5 +317,16 @@ impl Apu { } self.wave.step(cycles, frame); self.noise.step(cycles, frame); + + let amp = self + .mixer + .builder() + .tone1(self.tones[0].amp()) + .tone2(self.tones[1].amp()) + .wave(self.wave.amp()) + .noise(self.noise.amp()) + .build(); + + self.sink.send(cycles, amp); } } diff --git a/core/src/apu/stream.rs b/core/src/apu/stream.rs new file mode 100644 index 0000000..6424261 --- /dev/null +++ b/core/src/apu/stream.rs @@ -0,0 +1,104 @@ +use crate::{cpu::CPU_FREQ_HZ, Stream}; + +use super::buffer::{open_buffer, Consumer, Producer}; + +pub struct SoundSink { + left: Producer, + right: Producer, +} + +const BUF_SIZE: usize = 16384; +const MAX_FRAME_SIZE: usize = 1024; + +pub fn open_stream() -> (SoundSink, SoundStream) { + let left = open_buffer(BUF_SIZE, MAX_FRAME_SIZE); + let right = open_buffer(BUF_SIZE, MAX_FRAME_SIZE); + + ( + SoundSink::new(left.0, right.0), + SoundStream::new(left.1, right.1), + ) +} + +impl SoundSink { + fn new(left: Producer, right: Producer) -> Self { + Self { left, right } + } + + pub fn send(&mut self, cycles: usize, amp: (isize, isize)) { + self.left.add_sample(cycles, amp.0); + self.right.add_sample(cycles, amp.1); + } +} + +pub struct SoundStream { + left: Consumer, + right: Consumer, + upscaler: UpScaler, +} + +impl SoundStream { + fn new(left: Consumer, right: Consumer) -> Self { + Self { + left, + right, + upscaler: UpScaler::new(CPU_FREQ_HZ), + } + } +} + +#[derive(Clone)] +struct UpScaler { + target_rate: usize, + count: usize, +} + +impl UpScaler { + fn new(target_rate: usize) -> Self { + Self { + target_rate, + count: 0, + } + } + + fn compute_cycles(&mut self, rate: usize) -> usize { + let mut cycles = 0; + + while self.count < self.target_rate { + self.count += rate; + cycles += 1; + } + self.count -= self.target_rate; + + cycles + } +} + +impl Stream for SoundStream { + fn max(&self) -> u16 { + // Master volume max is 8, we have left and right: 8 * 2 + // Each channel max is 15, 4 channels, left and right: 15 * 4 * 2 + 8 * 2 * 15 * 4 * 2 + } + + fn next(&mut self, rate: u32) -> u16 { + let (left, right) = self.next_dual(rate); + (left + right) / 2 + } + + fn next_dual(&mut self, rate: u32) -> (u16, u16) { + let cycles = self.upscaler.compute_cycles(rate as usize); + + let left = self.left.get_sample(cycles); + + let right = self.right.get_sample(cycles); + + let center = (self.max() / 2) as isize; + + ((left + center) as u16 * 2, (right + center) as u16 * 2) + } + + fn on(&self) -> bool { + true + } +}