use std::os::raw::c_void;
use crate::plugin::PluginAdapter;
use crate::{intptr_t, AsRawPtr, FlMessage, ValuePtr};
crate::implement_tag!();
pub trait ReceiveVoiceHandler: Send + Sync {
fn trigger(&mut self, params: Params, tag: Tag) -> &mut dyn Voice;
fn release(&mut self, tag: Tag);
fn kill(&mut self, tag: Tag);
fn on_event(&mut self, _tag: Tag, _event: Event) -> Box<dyn AsRawPtr> {
Box::new(0)
}
fn out_handler(&mut self) -> Option<&mut dyn SendVoiceHandler> {
None
}
}
pub trait Voice: Send + Sync {
fn tag(&self) -> Tag;
}
#[derive(Clone, Debug)]
#[repr(C)]
pub struct Params {
pub init_levels: LevelParams,
pub final_levels: LevelParams,
}
#[derive(Clone, Debug)]
#[repr(C)]
pub struct LevelParams {
pub pan: f32,
pub vol: f32,
pub pitch: f32,
pub mod_x: f32,
pub mod_y: f32,
}
#[derive(Debug)]
pub enum Event {
Retrigger,
GetLength,
GetColor,
GetVelocity,
GetRelVelocity,
GetRelTime,
SetLinkVelocity(bool),
Unknown,
}
impl From<FlMessage> for Event {
fn from(message: FlMessage) -> Self {
match message.id {
0 => Event::Retrigger,
1 => Event::GetLength,
2 => Event::GetColor,
3 => Event::GetVelocity,
4 => Event::GetRelVelocity,
5 => Event::GetRelTime,
6 => Event::SetLinkVelocity(message.index != 0),
_ => Event::Unknown,
}
}
}
impl From<Event> for Option<FlMessage> {
fn from(event: Event) -> Self {
match event {
Event::Retrigger => Some(FlMessage {
id: 0,
index: 0,
value: 0,
}),
Event::GetLength => Some(FlMessage {
id: 1,
index: 0,
value: 0,
}),
Event::GetColor => Some(FlMessage {
id: 2,
index: 0,
value: 0,
}),
Event::GetVelocity => Some(FlMessage {
id: 3,
index: 0,
value: 0,
}),
Event::GetRelVelocity => Some(FlMessage {
id: 4,
index: 0,
value: 0,
}),
Event::GetRelTime => Some(FlMessage {
id: 5,
index: 0,
value: 0,
}),
Event::SetLinkVelocity(value) => Some(FlMessage {
id: 6,
index: value as isize,
value: 0,
}),
Event::Unknown => None,
}
}
}
pub trait SendVoiceHandler: Send + Sync {
fn trigger(&mut self, _params: Params, _index: usize, _tag: Tag) -> Option<&mut dyn Voice> {
None
}
fn release(&mut self, _tag: Tag) {}
fn kill(&mut self, tag: Tag);
fn on_event(&mut self, _tag: Tag, _event: Event) -> Option<ValuePtr> {
None
}
}
#[doc(hidden)]
#[no_mangle]
unsafe extern "C" fn voice_handler_trigger(
adapter: *mut PluginAdapter,
params: Params,
tag: intptr_t,
) -> intptr_t {
(*adapter)
.0
.voice_handler()
.map(|handler| {
let voice_ptr: *mut &mut dyn Voice =
Box::leak(Box::new(handler.trigger(params, Tag(tag))));
voice_ptr as *mut c_void as intptr_t
})
.unwrap_or(-1)
}
#[doc(hidden)]
#[no_mangle]
unsafe extern "C" fn voice_handler_release(
adapter: *mut PluginAdapter,
voice: *mut &mut dyn Voice,
) {
if let Some(handler) = (*adapter).0.voice_handler() {
handler.release((*voice).tag())
}
}
#[doc(hidden)]
#[no_mangle]
unsafe extern "C" fn voice_handler_kill(adapter: *mut PluginAdapter, voice: *mut &mut dyn Voice) {
let r_voice = Box::from_raw(voice);
if let Some(handler) = (*adapter).0.voice_handler() {
handler.kill(r_voice.tag())
}
}
#[doc(hidden)]
#[no_mangle]
unsafe extern "C" fn out_voice_handler_kill(adapter: *mut PluginAdapter, tag: intptr_t) {
(*adapter).0.voice_handler().and_then(|handler| {
handler.out_handler().map(|out_handler| {
out_handler.kill(Tag(tag));
})
});
}
#[doc(hidden)]
#[no_mangle]
unsafe extern "C" fn voice_handler_on_event(
adapter: *mut PluginAdapter,
voice: *mut &mut dyn Voice,
message: FlMessage,
) -> intptr_t {
(*adapter)
.0
.voice_handler()
.map(|handler| {
handler
.on_event((*voice).tag(), message.into())
.as_raw_ptr()
})
.unwrap_or(-1)
}
#[doc(hidden)]
#[no_mangle]
unsafe extern "C" fn out_voice_handler_on_event(
adapter: *mut PluginAdapter,
tag: intptr_t,
message: FlMessage,
) -> intptr_t {
(*adapter)
.0
.voice_handler()
.and_then(|handler| handler.out_handler())
.and_then(|out_handler| out_handler.on_event(Tag(tag), message.into()))
.map(|result| result.0)
.unwrap_or(-1)
}
pub fn vol_to_vel(vol: f32) -> f32 {
inv_log_vol(vol * 10.0, 2610.0 / 127.0)
}
pub fn vol_to_midi_vel(vol: f32) -> f32 {
inv_log_vol(vol * 10.0, 2610.0 / 127.0) * 127.0
}
fn inv_log_vol(value: f32, max_value: f32) -> f32 {
(value + 1.0).ln() / (max_value + 1.0).ln()
}