#[macro_export]
macro_rules! export_plugin {
($name:ident, $impl_fn:expr) => {
#[unsafe(no_mangle)]
pub extern "C" fn $name(
out_ptr: *mut f32,
out_len: i32,
freq: f32,
amp: f32,
duration_ms: i32,
sample_rate: i32,
channels: i32,
) {
if out_ptr.is_null() {
return;
}
let out_len_usize = out_len.max(0) as usize;
if out_len_usize == 0 {
return;
}
let channels_val = channels.max(1) as u32;
let sample_rate_val = sample_rate.max(1) as u32;
let frames = (out_len_usize / channels_val as usize) as u32;
let params = $crate::engine::plugin::bindings::types::BufferParams {
sample_rate: sample_rate_val,
channels: channels_val,
frames,
};
let note = $crate::engine::plugin::bindings::types::Note {
pitch: 60,
velocity: 100,
duration_ms: duration_ms.max(1) as u32,
};
unsafe {
let out = core::slice::from_raw_parts_mut(out_ptr, out_len_usize);
let implementation: fn(
&mut [f32],
$crate::engine::plugin::bindings::types::BufferParams,
$crate::engine::plugin::bindings::types::Note,
f32,
f32,
) = $impl_fn;
implementation(out, params, note, freq, amp);
}
}
};
}
#[macro_export]
macro_rules! export_plugin_with_state {
(
$name:ident,
$state_struct:item,
$default_state:expr,
$render:expr,
{ $($param:ident: $setter:expr),* $(,)? }
) => {
use std::sync::Mutex;
use once_cell::sync::Lazy;
$state_struct
static STATE: Lazy<Mutex<std::collections::HashMap<String, Box<dyn std::any::Any + Send>>>> =
Lazy::new(|| Mutex::new(std::collections::HashMap::new()));
#[unsafe(no_mangle)]
pub extern "C" fn $name(
out_ptr: *mut f32,
out_len: i32,
freq: f32,
amp: f32,
duration_ms: i32,
sample_rate: i32,
channels: i32,
) {
if out_ptr.is_null() {
return;
}
let out_len_usize = out_len.max(0) as usize;
if out_len_usize == 0 {
return;
}
let channels_val = channels.max(1) as u32;
let sample_rate_val = sample_rate.max(1) as u32;
let frames = (out_len_usize / channels_val as usize) as u32;
let params = $crate::engine::plugin::bindings::types::BufferParams {
sample_rate: sample_rate_val,
channels: channels_val,
frames,
};
let note = $crate::engine::plugin::bindings::types::Note {
pitch: 60,
velocity: 100,
duration_ms: duration_ms.max(1) as u32,
};
unsafe {
let out = core::slice::from_raw_parts_mut(out_ptr, out_len_usize);
let instance_key = "default".to_string(); let mut states = STATE.lock().unwrap();
let state = states.entry(instance_key)
.or_insert_with(|| Box::new($default_state))
.downcast_mut()
.unwrap();
let render_fn: fn(&mut _, &mut [f32], $crate::engine::plugin::bindings::types::BufferParams, $crate::engine::plugin::bindings::types::Note, f32, f32) = $render;
render_fn(state, out, params, note, freq, amp);
}
}
$(
paste::paste! {
#[unsafe(no_mangle)]
pub extern "C" fn [<set $param:camel>](value: f32) {
let instance_key = "default".to_string();
let mut states = STATE.lock().unwrap();
if let Some(state_any) = states.get_mut(&instance_key) {
if let Some(state) = state_any.downcast_mut() {
let setter: fn(&mut _, f32) = $setter;
setter(state, value);
}
}
}
}
)*
};
}
#[macro_export]
macro_rules! simple_oscillator_plugin {
($name:ident, $waveform:expr) => {
$crate::export_plugin!($name, |out, params, _note, freq, amp| {
use $crate::oscillators::Oscillator;
let mut osc = Oscillator::new($waveform);
osc.set_frequency(freq);
osc.set_amplitude(amp);
osc.render(out, params);
});
};
}