mod buffer_abstraction;
pub use buffer_abstraction::{input, main, output, DeviceBuffer};
use std::ptr::NonNull;
use crate::types::{ChannelIndex, Device, VoicemeeterApplication};
pub type AudioInfo = crate::bindings::VBVMR_T_AUDIOINFO;
pub type AudioBuffer = crate::bindings::VBVMR_T_AUDIOBUFFER;
impl AudioBuffer {
pub(crate) fn read_write_buffer(&self) -> (&[*mut f32], &[*mut f32]) {
let first_ptr_r = self.audiobuffer_r[0];
let first_ptr_w = self.audiobuffer_w[0];
for (idx, ptr) in self
.audiobuffer_r
.iter()
.enumerate()
.take(self.audiobuffer_nbi as usize)
{
debug_assert!(!ptr.is_null(), "ptr: {:?} was null at idx: {}", ptr, idx);
}
for (idx, ptr) in self
.audiobuffer_w
.iter()
.enumerate()
.take(self.audiobuffer_nbo as usize)
{
debug_assert!(!ptr.is_null(), "ptr: {:?} was null at idx: {}", ptr, idx);
}
let k = (
&self.audiobuffer_r[..self.audiobuffer_nbi as usize],
&self.audiobuffer_w[..self.audiobuffer_nbo as usize],
);
debug_assert_eq!(first_ptr_r, k.0[0]);
debug_assert_eq!(first_ptr_w, k.1[0]);
k
}
}
#[repr(transparent)]
pub struct RawCallbackData(NonNull<std::ffi::c_void>);
impl std::fmt::Debug for RawCallbackData {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{:p}", self.0)
}
}
impl RawCallbackData {
pub fn from_ptr(ptr: *mut std::ffi::c_void) -> Self {
RawCallbackData(NonNull::new(ptr).unwrap())
}
pub unsafe fn as_audio_info<'a>(&self) -> &'a mut AudioInfo {
unsafe { self.0.cast().as_mut() }
}
pub unsafe fn as_audio_buffer<'a>(&self) -> &'a mut AudioBuffer {
unsafe { self.0.cast().as_mut() }
}
}
trait BufferDataExt<'a> {
fn data<'b>(&'b self) -> (&'a [*mut f32], &'a [*mut f32]);
fn channel_index_write(&self, device: &Device) -> Option<ChannelIndex>;
fn channel_index_read(&self, device: &Device) -> Option<ChannelIndex>;
fn samples_per_frame(&self) -> usize;
#[inline]
unsafe fn device_write<'b, const N: usize>(
&'a self,
device: &Device,
) -> DeviceBuffer<[&'b mut [f32]; N]> {
let idx = if let Some(idx) = self.channel_index_write(device) {
idx
} else {
return DeviceBuffer::None;
};
assert_eq!(N, idx.size);
let data = self.data().1;
let mut array = [(); N].map(|_| Default::default());
for i in 0..N {
let ptr = data[idx.start + i];
array[i] = unsafe { std::slice::from_raw_parts_mut(ptr, self.samples_per_frame()) };
}
DeviceBuffer::Buffer(array)
}
#[inline]
unsafe fn device_read<'b, const N: usize>(
&'a self,
device: &Device,
) -> DeviceBuffer<[&'b [f32]; N]> {
let idx = if let Some(idx) = self.channel_index_read(device) {
idx
} else {
return DeviceBuffer::None;
};
assert_eq!(N, idx.size, "on device: {device:?}");
let data = self.data().0;
let mut array = [(); N].map(|_| Default::default());
for i in 0..N {
let ptr = data[idx.start + i];
array[i] = unsafe { std::slice::from_raw_parts(ptr, self.samples_per_frame()) };
}
DeviceBuffer::Buffer(array)
}
}
pub struct BufferMainData<'a> {
pub read: main::ReadDevices<'a, 'a>,
pub write: main::WriteDevices<'a, 'a>,
}
pub(crate) struct Main<'a> {
program: VoicemeeterApplication,
samples_per_frame: usize,
data: (&'a [*mut f32], &'a [*mut f32]),
}
impl<'a> BufferDataExt<'a> for Main<'a> {
#[inline]
fn data<'b>(&'b self) -> (&'a [*mut f32], &'a [*mut f32]) {
self.data
}
#[inline]
fn channel_index_read(&self, device: &Device) -> Option<ChannelIndex> {
device.main(&self.program).0
}
#[inline]
fn channel_index_write(&self, device: &Device) -> Option<ChannelIndex> {
device.main(&self.program).1
}
#[inline]
fn samples_per_frame(&self) -> usize {
self.samples_per_frame
}
}
impl<'a> BufferMainData<'a> {
pub(crate) fn new<'b: 'a>(
program: VoicemeeterApplication,
data: &'b AudioBuffer,
samples_per_frame: usize,
) -> Self {
let mut data = Main {
data: data.read_write_buffer(),
samples_per_frame,
program,
};
unsafe {
Self {
read: main::ReadDevices::new(&mut data),
write: main::WriteDevices::new(&mut data),
}
}
}
pub fn get_buffers(self) -> (main::ReadDevices<'a, 'a>, main::WriteDevices<'a, 'a>) {
(self.read, self.write)
}
}
pub struct BufferOutData<'a> {
pub read: output::ReadDevices<'a, 'a>,
pub write: output::WriteDevices<'a, 'a>,
}
pub(crate) struct Output<'a> {
program: VoicemeeterApplication,
samples_per_frame: usize,
data: (&'a [*mut f32], &'a [*mut f32]),
}
impl<'a> BufferDataExt<'a> for Output<'a> {
#[inline]
fn data<'b>(&'b self) -> (&'a [*mut f32], &'a [*mut f32]) {
self.data
}
#[inline]
fn channel_index_read(&self, device: &Device) -> Option<ChannelIndex> {
device.output(&self.program)
}
#[inline]
fn channel_index_write(&self, device: &Device) -> Option<ChannelIndex> {
device.output(&self.program)
}
#[inline]
fn samples_per_frame(&self) -> usize {
self.samples_per_frame
}
}
impl<'a> BufferOutData<'a> {
pub(crate) fn new(
program: VoicemeeterApplication,
data: &'a mut AudioBuffer,
samples_per_frame: usize,
) -> Self {
let mut data = Output {
data: data.read_write_buffer(),
samples_per_frame,
program,
};
unsafe {
Self {
read: output::ReadDevices::new(&mut data),
write: output::WriteDevices::new(&mut data),
}
}
}
pub fn get_buffers(self) -> (output::ReadDevices<'a, 'a>, output::WriteDevices<'a, 'a>) {
(self.read, self.write)
}
}
pub struct BufferInData<'a> {
pub read: input::ReadDevices<'a, 'a>,
pub write: input::WriteDevices<'a, 'a>,
}
pub(crate) struct Input<'a> {
program: VoicemeeterApplication,
samples_per_frame: usize,
data: (&'a [*mut f32], &'a [*mut f32]),
}
impl<'a> BufferDataExt<'a> for Input<'a> {
#[inline]
fn data<'b>(&'b self) -> (&'a [*mut f32], &'a [*mut f32]) {
self.data
}
#[inline]
fn channel_index_read(&self, device: &Device) -> Option<ChannelIndex> {
device.input(&self.program)
}
#[inline]
fn channel_index_write(&self, device: &Device) -> Option<ChannelIndex> {
device.input(&self.program)
}
#[inline]
fn samples_per_frame(&self) -> usize {
self.samples_per_frame
}
}
impl<'a> BufferInData<'a> {
pub(crate) fn new(
program: VoicemeeterApplication,
data: &'a mut AudioBuffer,
samples_per_frame: usize,
) -> Self {
let mut data = Input {
data: data.read_write_buffer(),
samples_per_frame,
program,
};
unsafe {
Self {
read: input::ReadDevices::new(&mut data),
write: input::WriteDevices::new(&mut data),
}
}
}
pub fn get_buffers(self) -> (input::ReadDevices<'a, 'a>, input::WriteDevices<'a, 'a>) {
(self.read, self.write)
}
}