Skip to content
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
17 changes: 9 additions & 8 deletions examples/src/bin/parameters.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
})
}
}
138 changes: 53 additions & 85 deletions src/program_vector/audio.rs
Original file line number Diff line number Diff line change
@@ -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,
Expand Down Expand Up @@ -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<i32> for Samplew16 {
fn convert_from(&mut self, value: i32) {
self.0 = value >> 16
}
}

impl ConvertFrom<Samplew16> for i32 {
fn convert_from(&mut self, value: Samplew16) {
*self = value.0 << 16;
}
}

#[derive(Clone, Copy, Default)]
#[repr(transparent)]
struct Samplei32(i32);

impl ConvertFrom<i32> for Samplei32 {
fn convert_from(&mut self, value: i32) {
self.0 = value >> 8;
}
}

impl ConvertFrom<Samplei32> 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
Expand All @@ -91,28 +53,20 @@ pub struct AudioBuffers {
/// Current audio settings (set by the os / device)
pub settings: AudioSettings,
program_ready: Option<unsafe extern "C" fn()>,
input_buffer: Buffer<Interleaved, Box<[i32]>>,
output_buffer: Buffer<Interleaved, Box<[i32]>>,
}

impl AudioBuffers {
pub(crate) fn new(
input: &'static *mut i32,
output: &'static *mut i32,

settings: AudioSettings,
program_ready: Option<unsafe extern "C" fn()>,
) -> Self {
let input_buffer = Buffer::<Interleaved, _>::new(settings.channels, settings.blocksize);
let output_buffer = Buffer::<Interleaved, _>::new(settings.channels, settings.blocksize);

Self {
input,
output,
settings,
program_ready,
input_buffer,
output_buffer,
}
}

Expand All @@ -127,53 +81,67 @@ impl AudioBuffers {
/// [self.settings.channels]: AudioSettings
pub fn run(
&mut self,
f: impl FnMut(&Buffer<Interleaved, Box<[i32]>>, &mut Buffer<Interleaved, Box<[i32]>>),
mut f: impl FnMut(&Buffer<Interleaved, &mut [i32]>, &mut Buffer<Interleaved, &mut [i32]>),
) -> ! {
match self.settings.format {
AudioFormat::Format24B16 => self.run_with_format::<Samplew16>(f),
AudioFormat::Format24B32 => self.run_with_format::<Samplei32>(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<Interleaved, &mut [i32]>, &mut Buffer<Interleaved, &mut [i32]>),
) {
match self.settings.format {
AudioFormat::Format24B16 => self.process_shifted::<16>(f),
AudioFormat::Format24B32 => self.process_shifted::<8>(f),
}
}

fn run_with_format<F>(
fn process_shifted<const SHIFT: i32>(
&mut self,
mut f: impl FnMut(&Buffer<Interleaved, Box<[i32]>>, &mut Buffer<Interleaved, Box<[i32]>>),
) -> !
where
i32: ConvertFrom<F>,
F: ConvertFrom<i32> + Copy,
{
mut f: impl FnMut(&Buffer<Interleaved, &mut [i32]>, &mut Buffer<Interleaved, &mut [i32]>),
) {
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<Interleaved, &mut [i32]> =
Buffer::new_mut(self.settings.channels, self.settings.blocksize, input);
input_buffer <<= SHIFT;

let mut output_buffer: Buffer<Interleaved, &mut [i32]> =
Buffer::new_mut(self.settings.channels, self.settings.blocksize, output);

f(&input_buffer, &mut output_buffer);

output_buffer >>= SHIFT;
}
}
7 changes: 6 additions & 1 deletion src/sample_buffer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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<F, S, C> MulAddAssign<F, F> for Buffer<S, C>
where
Expand Down