use crate::Hz;
use reaper_low::raw::audio_hook_register_t;
use reaper_low::{firewall, raw};
use std::any::Any;
use std::os::raw::{c_int, c_void};
use std::ptr::{null_mut, NonNull};
pub trait MediumOnAudioBuffer {
fn call(&mut self, args: OnAudioBufferArgs);
}
#[derive(PartialEq, Debug)]
pub struct OnAudioBufferArgs<'a> {
pub is_post: bool,
pub len: u32,
pub srate: Hz,
pub reg: &'a AudioHookRegister,
}
#[derive(Eq, PartialEq, Hash, Debug)]
pub struct AudioHookRegister(pub(crate) NonNull<raw::audio_hook_register_t>);
impl AudioHookRegister {
pub(crate) fn new(ptr: NonNull<raw::audio_hook_register_t>) -> AudioHookRegister {
AudioHookRegister(ptr)
}
pub fn get(&self) -> NonNull<raw::audio_hook_register_t> {
self.0
}
pub fn input_nch(&self) -> u32 {
unsafe { self.0.as_ref() }.input_nch as u32
}
pub fn output_nch(&self) -> u32 {
unsafe { self.0.as_ref() }.input_nch as u32
}
}
pub(crate) extern "C" fn delegating_on_audio_buffer<T: MediumOnAudioBuffer>(
is_post: bool,
len: c_int,
srate: f64,
reg: *mut audio_hook_register_t,
) {
firewall(|| {
let reg = unsafe { NonNull::new_unchecked(reg) };
let callback_struct: &mut T = decode_user_data(unsafe { reg.as_ref() }.userdata1);
callback_struct.call(OnAudioBufferArgs {
is_post,
len: len as u32,
srate: unsafe { Hz::new_unchecked(srate) },
reg: &AudioHookRegister::new(reg),
});
});
}
fn encode_user_data<U>(data: &Box<U>) -> *mut c_void {
data.as_ref() as *const _ as *mut c_void
}
fn decode_user_data<'a, U>(data: *mut c_void) -> &'a mut U {
assert!(!data.is_null());
let data = data as *mut U;
unsafe { &mut *data }
}
#[derive(Debug)]
pub(crate) struct MediumAudioHookRegister {
inner: raw::audio_hook_register_t,
owned_user_data_1: Option<Box<dyn Any>>,
owned_user_data_2: Option<Box<dyn Any>>,
}
impl MediumAudioHookRegister {
pub(crate) fn new<T: MediumOnAudioBuffer + 'static>(callback: T) -> MediumAudioHookRegister {
let callback = Box::new(callback);
MediumAudioHookRegister {
inner: audio_hook_register_t {
OnAudioBuffer: Some(delegating_on_audio_buffer::<T>),
userdata1: encode_user_data(&callback),
userdata2: null_mut(),
input_nch: 0,
output_nch: 0,
GetBuffer: None,
},
owned_user_data_1: Some(callback),
owned_user_data_2: None,
}
}
}
impl AsRef<raw::audio_hook_register_t> for MediumAudioHookRegister {
fn as_ref(&self) -> &audio_hook_register_t {
&self.inner
}
}