From a64b0dec1c8853194da7c794b65d73935c4229e5 Mon Sep 17 00:00:00 2001 From: Peter Smith Date: Tue, 18 Feb 2025 12:08:56 +0000 Subject: [PATCH] run buffer sample conversion in-place --- examples/src/bin/parameters.rs | 17 ++-- src/program_vector/audio.rs | 138 +++++++++++++-------------------- src/sample_buffer.rs | 7 +- 3 files changed, 68 insertions(+), 94 deletions(-) diff --git a/examples/src/bin/parameters.rs b/examples/src/bin/parameters.rs index 5c0b28d..50f1aa6 100644 --- a/examples/src/bin/parameters.rs +++ b/examples/src/bin/parameters.rs @@ -38,17 +38,18 @@ fn run(mut pv: ProgramVector) -> ! { // For correct reporting, this should be called after all heap allocations are done with. pv.meta().set_heap_bytes_used(heap_bytes_used()); - // Main audio loop - pv.audio().run(|input, output| { + loop { let volume = parameters.get(PatchParameterId::PARAMETER_A); parameters.set(PatchParameterId::PARAMETER_F, volume); - buffer.convert_from(input); + pv.audio().process(|input, output| { + buffer.convert_from(input); - for mut channel in buffer.channels_mut() { - channel *= volume; - } + for mut channel in buffer.channels_mut() { + channel *= volume; + } - buffer.convert_to(output); - }); + buffer.convert_to(output); + }) + } } diff --git a/src/program_vector/audio.rs b/src/program_vector/audio.rs index ad92418..a624bfb 100644 --- a/src/program_vector/audio.rs +++ b/src/program_vector/audio.rs @@ -1,8 +1,6 @@ use core::slice; -use alloc::boxed::Box; - -use crate::sample_buffer::{Buffer, ConvertFrom, Interleaved}; +use crate::sample_buffer::{Buffer, Interleaved}; use super::{ AUDIO_FORMAT_24B16, AUDIO_FORMAT_24B32, AUDIO_FORMAT_CHANNEL_MASK, AUDIO_FORMAT_FORMAT_MASK, @@ -44,42 +42,6 @@ impl AudioFormat { } } -#[derive(Clone, Copy, Default)] -#[repr(transparent)] -struct Samplew16(i32); - -// The C code for 24B16 reads two 16 bit words and swaps them over to create a 32 bit value. I *think* that the codec is -// actually operating in 16 bit mode though, so here we're just doing a 16 bit shift instead. -// The C code for 24B32 does an 8 bit shift, I'm fairly certain it is actually 24 bit. - -impl ConvertFrom for Samplew16 { - fn convert_from(&mut self, value: i32) { - self.0 = value >> 16 - } -} - -impl ConvertFrom for i32 { - fn convert_from(&mut self, value: Samplew16) { - *self = value.0 << 16; - } -} - -#[derive(Clone, Copy, Default)] -#[repr(transparent)] -struct Samplei32(i32); - -impl ConvertFrom for Samplei32 { - fn convert_from(&mut self, value: i32) { - self.0 = value >> 8; - } -} - -impl ConvertFrom for i32 { - fn convert_from(&mut self, value: Samplei32) { - *self = value.0 << 8; - } -} - /// Container for the input and output audio buffers /// /// Use [ProgramVector::audio()] to access the audio buffers @@ -91,28 +53,20 @@ pub struct AudioBuffers { /// Current audio settings (set by the os / device) pub settings: AudioSettings, program_ready: Option, - input_buffer: Buffer>, - output_buffer: Buffer>, } impl AudioBuffers { pub(crate) fn new( input: &'static *mut i32, output: &'static *mut i32, - settings: AudioSettings, program_ready: Option, ) -> Self { - let input_buffer = Buffer::::new(settings.channels, settings.blocksize); - let output_buffer = Buffer::::new(settings.channels, settings.blocksize); - Self { input, output, settings, program_ready, - input_buffer, - output_buffer, } } @@ -127,53 +81,67 @@ impl AudioBuffers { /// [self.settings.channels]: AudioSettings pub fn run( &mut self, - f: impl FnMut(&Buffer>, &mut Buffer>), + mut f: impl FnMut(&Buffer, &mut Buffer), ) -> ! { match self.settings.format { - AudioFormat::Format24B16 => self.run_with_format::(f), - AudioFormat::Format24B32 => self.run_with_format::(f), + AudioFormat::Format24B16 => loop { + self.process_shifted::<16>(&mut f); + }, + AudioFormat::Format24B32 => loop { + self.process_shifted::<8>(&mut f); + }, + } + } + + /// Process the next audio buffer + pub fn process( + &mut self, + f: impl FnMut(&Buffer, &mut Buffer), + ) { + match self.settings.format { + AudioFormat::Format24B16 => self.process_shifted::<16>(f), + AudioFormat::Format24B32 => self.process_shifted::<8>(f), } } - fn run_with_format( + fn process_shifted( &mut self, - mut f: impl FnMut(&Buffer>, &mut Buffer>), - ) -> ! - where - i32: ConvertFrom, - F: ConvertFrom + Copy, - { + mut f: impl FnMut(&Buffer, &mut Buffer), + ) { let Some(program_ready) = self.program_ready else { panic!("no audio available") }; - loop { - // Safety: Trusting the OS that the provided function is safe to call - // Note: any callbacks are invoked during this call - unsafe { program_ready() }; - - // Safety: The OS provides a valid buffer of the appropriate length. - // The buffers remain valid until the next call to program_ready() - let input = unsafe { - slice::from_raw_parts( - (*self.input) as *const F, - self.settings.blocksize * self.settings.channels, - ) - }; - - self.input_buffer.convert_from(input); - - f(&self.input_buffer, &mut self.output_buffer); - - // Safety: The OS provides a valid buffer of the appropriate length - let mut output = unsafe { - slice::from_raw_parts_mut( - (*self.output) as *mut F, - self.settings.blocksize * self.settings.channels, - ) - }; - - output.convert_from(&self.output_buffer); - } + // Safety: Trusting the OS that the provided function is safe to call + // Note: any callbacks are invoked during this call + unsafe { program_ready() }; + + // Safety: The OS provides a valid buffer of the appropriate length. + // The buffers remain valid until the next call to program_ready() + let input = unsafe { + slice::from_raw_parts_mut( + *self.input, + self.settings.blocksize * self.settings.channels, + ) + }; + + // Safety: The OS provides a valid buffer of the appropriate length + let output = unsafe { + slice::from_raw_parts_mut( + *self.output, + self.settings.blocksize * self.settings.channels, + ) + }; + + let mut input_buffer: Buffer = + Buffer::new_mut(self.settings.channels, self.settings.blocksize, input); + input_buffer <<= SHIFT; + + let mut output_buffer: Buffer = + Buffer::new_mut(self.settings.channels, self.settings.blocksize, output); + + f(&input_buffer, &mut output_buffer); + + output_buffer >>= SHIFT; } } diff --git a/src/sample_buffer.rs b/src/sample_buffer.rs index fceda11..f684ca4 100644 --- a/src/sample_buffer.rs +++ b/src/sample_buffer.rs @@ -4,7 +4,10 @@ extern crate alloc; use core::{ marker::PhantomData, - ops::{AddAssign, Deref, DerefMut, DivAssign, MulAssign, Neg, RemAssign, SubAssign}, + ops::{ + AddAssign, Deref, DerefMut, DivAssign, MulAssign, Neg, RemAssign, ShlAssign, ShrAssign, + SubAssign, + }, }; use alloc::vec; @@ -729,6 +732,8 @@ impl_op!(SubAssign, sub_assign); impl_op!(MulAssign, mul_assign); impl_op!(DivAssign, div_assign); impl_op!(RemAssign, rem_assign); +impl_op!(ShlAssign, shl_assign); +impl_op!(ShrAssign, shr_assign); impl MulAddAssign for Buffer where