Skip to content

Commit

Permalink
Merge pull request #46 from Amjad50/improve_audio
Browse files Browse the repository at this point in the history
Improve audio
  • Loading branch information
Amjad50 authored Dec 28, 2024
2 parents a89b8dc + cc786f2 commit ef0cc31
Show file tree
Hide file tree
Showing 11 changed files with 123 additions and 175 deletions.
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()
}
}

#[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 @@ pub const SAMPLE_RATE: u32 = 44100;
// 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 @@ pub struct APU2A03 {

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 @@ impl APU2A03 {
}

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 @@ impl APU2A03 {
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 @@ impl APU2A03 {

// 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 @@ impl APU2A03 {
}
}

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()
}
}

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

This file was deleted.

Loading

0 comments on commit ef0cc31

Please sign in to comment.