extern crate alloc;
use core::slice;
use crate::sample_buffer::{Buffer, Interleaved, InterleavedBufferMut};
use super::{
AUDIO_FORMAT_24B16, AUDIO_FORMAT_24B32, AUDIO_FORMAT_CHANNEL_MASK, AUDIO_FORMAT_FORMAT_MASK,
};
#[derive(Clone, Copy)]
pub struct AudioSettings {
pub sample_rate: usize,
pub blocksize: usize,
pub channels: usize,
pub format: AudioFormat,
}
#[derive(Clone, Copy)]
pub enum AudioFormat {
Format24B16,
Format24B32,
}
impl AudioFormat {
pub fn parse(value: u8) -> (Self, usize) {
let mut channels = value & AUDIO_FORMAT_CHANNEL_MASK;
if channels == 0 {
channels = 2;
}
let format = match value & AUDIO_FORMAT_FORMAT_MASK {
AUDIO_FORMAT_24B16 => Self::Format24B16,
AUDIO_FORMAT_24B32 => Self::Format24B32,
_ => panic!("bad audio format"),
};
(format, channels as usize)
}
}
pub struct AudioBuffers {
input: &'static *mut i32,
output: &'static *mut i32,
pub settings: AudioSettings,
program_ready: Option<unsafe extern "C" fn()>,
}
impl AudioBuffers {
pub(crate) fn new(
input: &'static *mut i32,
output: &'static *mut i32,
settings: AudioSettings,
program_ready: Option<unsafe extern "C" fn()>,
) -> Self {
Self {
input,
output,
settings,
program_ready,
}
}
pub fn run(
&mut self,
mut f: impl FnMut(&Buffer<Interleaved<&[i32]>>, &mut Buffer<Interleaved<&mut [i32]>>),
) -> ! {
match self.settings.format {
AudioFormat::Format24B16 => loop {
self.process_shifted::<16>(&mut f);
},
AudioFormat::Format24B32 => loop {
self.process_shifted::<8>(&mut f);
},
}
}
pub fn process(
&mut self,
f: impl FnMut(&Buffer<Interleaved<&[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 process_shifted<const SHIFT: i32>(
&mut self,
mut f: impl FnMut(&Buffer<Interleaved<&[i32]>>, &mut Buffer<Interleaved<&mut [i32]>>),
) {
let Some(program_ready) = self.program_ready else {
panic!("no audio available")
};
unsafe { program_ready() };
let input = unsafe {
slice::from_raw_parts_mut(
*self.input,
self.settings.blocksize * self.settings.channels,
)
};
let output = unsafe {
slice::from_raw_parts_mut(
*self.output,
self.settings.blocksize * self.settings.channels,
)
};
let mut input_buffer = InterleavedBufferMut::new(input, self.settings.channels);
input_buffer <<= SHIFT;
let mut output_buffer = InterleavedBufferMut::new(output, self.settings.channels);
f(&input_buffer.into_ref(), &mut output_buffer);
output_buffer >>= SHIFT;
}
}