rolled my own downsampler

This commit is contained in:
Alex Janka 2023-03-06 21:10:52 +11:00
parent 0459390d78
commit 28240c80c3
5 changed files with 53 additions and 35 deletions

View file

@ -132,15 +132,15 @@ fn create_audio_output() -> (AudioOutput, Stream) {
let sample_rate = config.sample_rate().0;
let (output, mut rx) = AudioOutput::new(sample_rate);
let (output, mut rx) = AudioOutput::new(sample_rate as f32);
let stream = device
.build_output_stream(
&config.config(),
move |data: &mut [f32], _info: &cpal::OutputCallbackInfo| {
for v in data {
for v in data.chunks_exact_mut(2) {
match executor::block_on(rx.pop()) {
Some(a) => *v = a,
Some(a) => v.copy_from_slice(&a),
None => panic!("Audio queue disconnected!"),
}
}

View file

@ -7,7 +7,6 @@ edition = "2021"
[dependencies]
rand = "0.8.5"
samplerate = "0.2.4"
async-ringbuf = "0.1.2"
futures = "0.3.26"
once_cell = "1.17.1"

View file

@ -24,18 +24,18 @@ pub trait Renderer {
}
pub struct AudioOutput {
pub sample_rate: u32,
pub send_rb: AsyncHeapProducer<f32>,
pub sample_rate: f32,
pub send_rb: AsyncHeapProducer<[f32; 2]>,
}
impl AudioOutput {
pub fn new(sample_rate: u32) -> (Self, AsyncHeapConsumer<f32>) {
let rb_len = sample_rate as usize / 60;
pub fn new(sample_rate: f32) -> (Self, AsyncHeapConsumer<[f32; 2]>) {
let rb_len = sample_rate as usize / (60 * 2);
let rb = AsyncHeapRb::<f32>::new(rb_len);
let rb = AsyncHeapRb::<[f32; 2]>::new(rb_len);
let (mut send_rb, rx) = rb.split();
executor::block_on(send_rb.push_iter(vec![0.; rb_len - 1].into_iter())).unwrap();
executor::block_on(send_rb.push_iter(vec![[0.; 2]; rb_len - 1].into_iter())).unwrap();
(
Self {

View file

@ -1,19 +1,21 @@
use self::types::{Channels, DacSample, Mixer, VinEnable, Volume};
use self::{
downsampler::Downsampler,
types::{Channels, DacSample, Mixer, VinEnable, Volume},
};
use crate::{
connect::AudioOutput,
constants::CLOCK_SPEED,
processor::memory::Address,
util::{get_bit, set_or_clear_bit},
};
use futures::executor;
use itertools::izip;
use samplerate::{ConverterType, Samplerate};
mod channels;
mod downsampler;
mod types;
impl DacSample {
fn mixed(&self, mixer: &Mixer) -> Vec<f32> {
fn mixed(&self, mixer: &Mixer) -> [f32; 2] {
let left = (self.one * mixer.ch1.left.scale())
+ (self.two * mixer.ch2.left.scale())
+ (self.three * mixer.ch3.left.scale())
@ -22,7 +24,7 @@ impl DacSample {
+ (self.two * mixer.ch2.right.scale())
+ (self.three * mixer.ch3.right.scale())
+ (self.four * mixer.ch4.right.scale());
vec![
[
self.mix_channel(left, mixer.vol_left),
self.mix_channel(right, mixer.vol_right),
]
@ -40,7 +42,7 @@ pub struct Apu {
mixer: Mixer,
div_apu: u8,
buffer: Vec<DacSample>,
converter: Samplerate,
converter: Downsampler,
output: AudioOutput,
}
@ -48,14 +50,6 @@ const CYCLES_PER_FRAME: usize = 70224;
impl Apu {
pub fn new(output: AudioOutput) -> Self {
let converter = Samplerate::new(
ConverterType::ZeroOrderHold,
CLOCK_SPEED as u32,
output.sample_rate,
2,
)
.unwrap();
Self {
apu_enable: true,
channels: Channels::default(),
@ -63,7 +57,7 @@ impl Apu {
mixer: Mixer::default(),
div_apu: 0,
buffer: vec![],
converter,
converter: Downsampler::new(output.sample_rate),
output,
}
}
@ -111,16 +105,12 @@ impl Apu {
}
fn next_audio(&mut self) {
let converted = self
.converter
.process(
&self
.buffer
let converted = self.converter.process(
self.buffer
.drain(..)
.flat_map(|v| v.mixed(&self.mixer))
.collect::<Vec<f32>>(),
)
.unwrap();
.map(|v| v.mixed(&self.mixer))
.collect::<Vec<[f32; 2]>>(),
);
executor::block_on(self.output.send_rb.push_slice(&converted)).unwrap();
}

View file

@ -0,0 +1,29 @@
use crate::constants::CLOCK_SPEED;
const TIME_PER_CYCLE: f32 = 1. / CLOCK_SPEED as f32;
pub(super) struct Downsampler {
ratio: f32,
time_accum: f32,
}
impl Downsampler {
pub fn new(sample_rate: f32) -> Self {
Self {
ratio: 1. / sample_rate,
time_accum: 0.,
}
}
pub fn process(&mut self, signal: Vec<[f32; 2]>) -> Vec<[f32; 2]> {
let mut output = vec![];
for val in signal {
self.time_accum += TIME_PER_CYCLE;
if self.time_accum >= self.ratio {
self.time_accum = 0.;
output.push(val);
}
}
output
}
}