pub(crate) mod info;
pub use info::PluginInfo;
pub use lv2_core_derive::*;
use crate::feature::*;
use crate::port::*;
use std::any::Any;
use std::ffi::c_void;
use std::os::raw::c_char;
use sys::LV2_Handle;
use urid::{Uri, UriBound};
pub trait Plugin: UriBound + Sized + Send + Sync + 'static {
type Ports: PortCollection;
type InitFeatures: FeatureCollection<'static>;
type AudioFeatures: FeatureCollection<'static>;
fn new(plugin_info: &PluginInfo, features: &mut Self::InitFeatures) -> Option<Self>;
fn run(
&mut self,
ports: &mut Self::Ports,
features: &mut Self::AudioFeatures,
sample_count: u32,
);
fn activate(&mut self, _features: &mut Self::InitFeatures) {}
fn deactivate(&mut self, _features: &mut Self::InitFeatures) {}
fn extension_data(_uri: &Uri) -> Option<&'static dyn Any> {
None
}
}
#[repr(C)]
pub struct PluginInstance<T: Plugin> {
instance: T,
connections: <T::Ports as PortCollection>::Cache,
init_features: T::InitFeatures,
audio_features: T::AudioFeatures,
}
impl<T: Plugin> PluginInstance<T> {
pub unsafe fn ports(&self, sample_count: u32) -> Option<T::Ports> {
<T::Ports as PortCollection>::from_connections(&self.connections, sample_count)
}
pub unsafe extern "C" fn instantiate(
descriptor: *const sys::LV2_Descriptor,
sample_rate: f64,
bundle_path: *const c_char,
features: *const *const sys::LV2_Feature,
) -> LV2_Handle {
let descriptor = match descriptor.as_ref() {
Some(descriptor) => descriptor,
None => {
eprintln!("Failed to initialize plugin: Descriptor points to null");
return std::ptr::null_mut();
}
};
let plugin_info = match PluginInfo::from_raw(descriptor, bundle_path, sample_rate) {
Ok(info) => info,
Err(e) => {
eprintln!(
"Failed to initialize plugin: Illegal info from host: {:?}",
e
);
return std::ptr::null_mut();
}
};
let mut init_features_cache = FeatureCache::from_raw(features);
let mut audio_features_cache = init_features_cache.clone();
let mut init_features = match T::InitFeatures::from_cache(
&mut init_features_cache,
ThreadingClass::Instantiation,
) {
Ok(f) => f,
Err(e) => {
eprintln!("{}", e);
return std::ptr::null_mut();
}
};
let audio_features =
match T::AudioFeatures::from_cache(&mut audio_features_cache, ThreadingClass::Audio) {
Ok(f) => f,
Err(e) => {
eprintln!("{}", e);
return std::ptr::null_mut();
}
};
match T::new(&plugin_info, &mut init_features) {
Some(instance) => {
let instance = Box::new(Self {
instance,
connections: <<T::Ports as PortCollection>::Cache as Default>::default(),
init_features,
audio_features,
});
Box::leak(instance) as *mut Self as LV2_Handle
}
None => std::ptr::null_mut(),
}
}
pub unsafe extern "C" fn cleanup(instance: *mut c_void) {
let instance = instance as *mut Self;
Box::from_raw(instance);
}
pub unsafe extern "C" fn activate(instance: *mut c_void) {
let instance = &mut *(instance as *mut Self);
instance.instance.activate(&mut instance.init_features)
}
pub unsafe extern "C" fn deactivate(instance: *mut c_void) {
let instance = &mut *(instance as *mut Self);
instance.instance.deactivate(&mut instance.init_features)
}
pub unsafe extern "C" fn connect_port(instance: *mut c_void, port: u32, data: *mut c_void) {
let instance = instance as *mut Self;
(*instance).connections.connect(port, data)
}
pub unsafe extern "C" fn run(instance: *mut c_void, sample_count: u32) {
let instance = &mut *(instance as *mut Self);
if let Some(mut ports) = instance.ports(sample_count) {
instance
.instance
.run(&mut ports, &mut instance.audio_features, sample_count);
}
}
pub unsafe extern "C" fn extension_data(uri: *const c_char) -> *const c_void {
let uri = Uri::from_ptr(uri);
if let Some(data) = T::extension_data(uri) {
data as *const _ as *const c_void
} else {
std::ptr::null()
}
}
pub fn plugin_handle(&mut self) -> &mut T {
&mut self.instance
}
pub fn init_class_handle(&mut self) -> (&mut T, &mut T::InitFeatures) {
(&mut self.instance, &mut self.init_features)
}
pub fn audio_class_handle(&mut self) -> (&mut T, &mut T::AudioFeatures) {
(&mut self.instance, &mut self.audio_features)
}
}
#[doc(hidden)]
pub unsafe trait PluginInstanceDescriptor: Plugin {
const DESCRIPTOR: sys::LV2_Descriptor;
}