Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve audio #46

Merged
merged 4 commits into from
Dec 28, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
74 changes: 74 additions & 0 deletions plastic_core/src/apu2a03/channel.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
use serde::{Deserialize, Serialize};
use std::{
collections::VecDeque,
ops::{Deref, DerefMut},
};

pub trait APUChannel: Serialize + for<'de> Deserialize<'de> {
fn get_output(&mut self) -> f32;
}

pub trait TimedAPUChannel: APUChannel {
fn timer_clock(&mut self);
}

#[derive(Serialize, Deserialize)]
pub struct BufferedChannel {
buffer: VecDeque<f32>,
}

impl BufferedChannel {
pub fn new() -> Self {
Self {
buffer: VecDeque::new(),
}
}

pub fn recored_sample(&mut self, sample: f32) {
self.buffer.push_back(sample);
self.buffer.push_back(sample);
}

pub fn take_buffer(&mut self) -> Vec<f32> {
self.buffer.drain(..).collect()
}

Check warning on line 34 in plastic_core/src/apu2a03/channel.rs

View check run for this annotation

Codecov / codecov/patch

plastic_core/src/apu2a03/channel.rs#L32-L34

Added lines #L32 - L34 were not covered by tests
}

#[derive(Serialize, Deserialize)]
#[serde(bound = "C: APUChannel")]
pub struct Dac<C: APUChannel> {
capacitor: f32,
channel: C,
}

impl<C: APUChannel> Dac<C> {
pub fn new(channel: C) -> Self {
Self {
capacitor: 0.,
channel,
}
}

pub fn dac_output(&mut self) -> f32 {
let dac_in = self.channel.get_output() / 2.2;
let dac_out = dac_in - self.capacitor;

self.capacitor = dac_in - dac_out * 0.996;

dac_out
}
}

impl<C: APUChannel> Deref for Dac<C> {
type Target = C;

fn deref(&self) -> &Self::Target {
&self.channel
}
}

impl<C: APUChannel> DerefMut for Dac<C> {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.channel
}
}
2 changes: 1 addition & 1 deletion plastic_core/src/apu2a03/channels/dmc.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use super::super::tone_source::{APUChannel, TimedAPUChannel};
use super::super::channel::{APUChannel, TimedAPUChannel};
use serde::{Deserialize, Serialize};

const DMC_PERIOD_RATES_NTSC: [u16; 0x10] = [
Expand Down
2 changes: 1 addition & 1 deletion plastic_core/src/apu2a03/channels/noise.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use super::super::channel::{APUChannel, TimedAPUChannel};
use super::super::envelope::{EnvelopeGenerator, EnvelopedChannel};
use super::super::tone_source::{APUChannel, TimedAPUChannel};
use serde::{Deserialize, Serialize};

/// Table for NTSC only
Expand Down
2 changes: 1 addition & 1 deletion plastic_core/src/apu2a03/channels/square.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use super::super::channel::{APUChannel, TimedAPUChannel};
use super::super::envelope::{EnvelopeGenerator, EnvelopedChannel};
use super::super::sequencer::Sequencer;
use super::super::tone_source::{APUChannel, TimedAPUChannel};
use serde::{Deserialize, Serialize};

#[derive(Serialize, Deserialize)]
Expand Down
2 changes: 1 addition & 1 deletion plastic_core/src/apu2a03/channels/triangle.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use super::super::channel::{APUChannel, TimedAPUChannel};
use super::super::sequencer::Sequencer;
use super::super::tone_source::{APUChannel, TimedAPUChannel};
use serde::{Deserialize, Serialize};

#[derive(Serialize, Deserialize)]
Expand Down
2 changes: 1 addition & 1 deletion plastic_core/src/apu2a03/envelope.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use super::tone_source::APUChannel;
use super::channel::APUChannel;
use serde::{Deserialize, Serialize};

#[derive(Serialize, Deserialize)]
Expand Down
3 changes: 2 additions & 1 deletion plastic_core/src/apu2a03/length_counter.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use super::channel::{APUChannel, TimedAPUChannel};
use super::envelope::{EnvelopeGenerator, EnvelopedChannel};
use super::tone_source::{APUChannel, TimedAPUChannel};
use serde::{Deserialize, Serialize};

const LEGNTH_COUNTER_TABLE: [u8; 0x20] = [
Expand Down Expand Up @@ -67,6 +67,7 @@ impl LengthCounter {
}

#[derive(Serialize, Deserialize)]
#[serde(bound = "C: APUChannel")]
pub struct LengthCountedChannel<C>
where
C: APUChannel,
Expand Down
99 changes: 27 additions & 72 deletions plastic_core/src/apu2a03/mod.rs
Original file line number Diff line number Diff line change
@@ -1,23 +1,22 @@
mod apu2a03_registers;
mod channel;
mod channels;
mod envelope;
mod length_counter;
mod sequencer;
mod tone_source;

use crate::common::{
interconnection::{APUCPUConnection, CPUIrqProvider},
save_state::{Savable, SaveError},
CPU_FREQ,
};
use apu2a03_registers::Register;
use channel::{BufferedChannel, Dac, TimedAPUChannel};
use channels::{Dmc, NoiseWave, SquarePulse, TriangleWave};
use envelope::EnvelopedChannel;
use length_counter::LengthCountedChannel;
use serde::{Deserialize, Serialize};
use std::cell::Cell;
use std::sync::{Arc, Mutex};
use tone_source::{APUChannel, BufferedChannel, TimedAPUChannel};

// for performance
/// The sample rate expected to get from [`NES::audio_buffer`](crate::NES::audio_buffer)
Expand All @@ -28,43 +27,15 @@
// APU, is clocked on every CPU clock
const SAMPLES_EVERY_N_APU_CLOCK: f64 = CPU_FREQ / (SAMPLE_RATE as f64);

mod buffered_channel_serde {
use super::BufferedChannel;
use serde::{ser::Error, Deserialize, Deserializer, Serialize, Serializer};
use std::sync::{Arc, Mutex};

pub fn serialize<S>(
value: &Arc<Mutex<BufferedChannel>>,
serializer: S,
) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
if let Ok(value) = value.lock() {
value.serialize(serializer)
} else {
Err(S::Error::custom(""))
}
}

pub fn deserialize<'de, D>(deserializer: D) -> Result<Arc<Mutex<BufferedChannel>>, D::Error>
where
D: Deserializer<'de>,
{
BufferedChannel::deserialize(deserializer).map(|channel| Arc::new(Mutex::new(channel)))
}
}

#[derive(Serialize, Deserialize)]
pub struct APU2A03 {
square_pulse_1: LengthCountedChannel<SquarePulse>,
square_pulse_2: LengthCountedChannel<SquarePulse>,
triangle: LengthCountedChannel<TriangleWave>,
noise: LengthCountedChannel<NoiseWave>,
dmc: Dmc,
square_pulse_1: Dac<LengthCountedChannel<SquarePulse>>,
square_pulse_2: Dac<LengthCountedChannel<SquarePulse>>,
triangle: Dac<LengthCountedChannel<TriangleWave>>,
noise: Dac<LengthCountedChannel<NoiseWave>>,
dmc: Dac<Dmc>,

#[serde(with = "buffered_channel_serde")]
buffered_channel: Arc<Mutex<BufferedChannel>>,
buffered_channel: BufferedChannel,

is_4_step_squence_mode_hold_value: bool,
is_4_step_squence_mode: bool,
Expand All @@ -84,19 +55,19 @@

impl APU2A03 {
pub fn new() -> Self {
let buffered_channel = Arc::new(Mutex::new(BufferedChannel::new()));
let buffered_channel = BufferedChannel::new();

Self {
square_pulse_1: LengthCountedChannel::new(SquarePulse::new(true)),
square_pulse_2: LengthCountedChannel::new(SquarePulse::new(false)),
square_pulse_1: Dac::new(LengthCountedChannel::new(SquarePulse::new(true))),
square_pulse_2: Dac::new(LengthCountedChannel::new(SquarePulse::new(false))),

triangle: LengthCountedChannel::new(TriangleWave::new()),
triangle: Dac::new(LengthCountedChannel::new(TriangleWave::new())),

noise: LengthCountedChannel::new(NoiseWave::new()),
noise: Dac::new(LengthCountedChannel::new(NoiseWave::new())),

dmc: Dmc::new(),
dmc: Dac::new(Dmc::new()),

buffered_channel: buffered_channel.clone(),
buffered_channel,

is_4_step_squence_mode_hold_value: false,
is_4_step_squence_mode: false,
Expand Down Expand Up @@ -414,11 +385,11 @@
}

fn get_mixer_output(&mut self) -> f32 {
let square_pulse_1 = self.square_pulse_1.get_output();
let square_pulse_2 = self.square_pulse_2.get_output();
let triangle = self.triangle.get_output();
let noise = self.noise.get_output();
let dmc = self.dmc.get_output();
let square_pulse_1 = self.square_pulse_1.dac_output();
let square_pulse_2 = self.square_pulse_2.dac_output();
let triangle = self.triangle.dac_output();
let noise = self.noise.dac_output();
let dmc = self.dmc.dac_output();

let pulse_out = if square_pulse_1 == 0. && square_pulse_2 == 0. {
0.
Expand Down Expand Up @@ -454,30 +425,13 @@
std::cmp::Ordering::Greater => self.wait_reset -= 1,
}

// after how many apu clocks a sample should be recorded
let samples_every_n_apu_clock = SAMPLES_EVERY_N_APU_CLOCK + self.offset;

self.sample_counter += 1.;
if self.sample_counter >= samples_every_n_apu_clock {
if self.sample_counter >= SAMPLES_EVERY_N_APU_CLOCK {
let output = self.get_mixer_output();

if let Ok(mut buffered_channel) = self.buffered_channel.lock() {
buffered_channel.recored_sample(output);

// check for needed change in offset
let change = if buffered_channel.get_is_overusing() {
-0.001
} else if buffered_channel.get_is_underusing() {
0.001
} else {
0.
};

self.offset += change;
buffered_channel.clear_using_flags();
}
self.buffered_channel.recored_sample(output);

self.sample_counter -= samples_every_n_apu_clock;
self.sample_counter -= SAMPLES_EVERY_N_APU_CLOCK;
}

// clocked on every CPU cycle
Expand All @@ -494,7 +448,7 @@

// this is clocked in every CPU cycle, so the numbers are multiplied by 2
match self.cycle {
7455 => {
7457 => {
self.generate_quarter_frame_clock();
}
14913 => {
Expand Down Expand Up @@ -531,8 +485,9 @@
}
}

pub fn take_audio_buffer(&self) -> Vec<f32> {
self.buffered_channel.lock().unwrap().take_buffer()
/// Take and return the audio buffer as f32 format stereo (2 channels)
pub fn take_audio_buffer(&mut self) -> Vec<f32> {
self.buffered_channel.take_buffer()

Check warning on line 490 in plastic_core/src/apu2a03/mod.rs

View check run for this annotation

Codecov / codecov/patch

plastic_core/src/apu2a03/mod.rs#L489-L490

Added lines #L489 - L490 were not covered by tests
}
}

Expand Down
88 changes: 0 additions & 88 deletions plastic_core/src/apu2a03/tone_source.rs

This file was deleted.

Loading
Loading