use crate::extensions::wrapper::HostWrapper;
use crate::extensions::wrapper::descriptor::RawHostDescriptor;
use crate::prelude::*;
use clack_common::factory::plugin::PluginFactory;
use clap_sys::host::clap_host;
use clap_sys::plugin::clap_plugin;
use std::ffi::CStr;
use std::pin::Pin;
use std::ptr::NonNull;
use std::sync::Arc;
use std::sync::atomic::{AtomicBool, Ordering};
pub(crate) struct PluginInstanceInner<H: HostHandlers> {
host_wrapper: Pin<Arc<HostWrapper<H>>>,
host_descriptor: Pin<Box<RawHostDescriptor>>,
plugin_ptr: Option<NonNull<clap_plugin>>,
is_started: AtomicBool,
plugin_entry: PluginEntry, }
impl<H: HostHandlers> PluginInstanceInner<H> {
pub(crate) fn instantiate<FH, FS>(
shared: FS,
main_thread: FH,
plugin_entry: &PluginEntry,
plugin_id: &CStr,
host_info: HostInfo,
) -> Result<Arc<Self>, PluginInstanceError>
where
FS: for<'s> FnOnce(&'s ()) -> <H as HostHandlers>::Shared<'s>,
FH: for<'s> FnOnce(
&'s <H as HostHandlers>::Shared<'s>,
) -> <H as HostHandlers>::MainThread<'s>,
{
let plugin_factory = plugin_entry
.get_plugin_factory()
.ok_or(PluginInstanceError::MissingPluginFactory)?;
let host_wrapper = HostWrapper::new(shared, main_thread);
let host_descriptor = Box::pin(RawHostDescriptor::new::<H>(host_info));
let mut instance = Arc::new(Self {
host_wrapper,
host_descriptor,
plugin_ptr: None,
plugin_entry: plugin_entry.clone(),
is_started: AtomicBool::new(false),
});
{
let instance = Arc::get_mut(&mut instance).unwrap();
instance.host_descriptor.set_wrapper(&instance.host_wrapper);
let raw_descriptor = instance.host_descriptor.raw();
let plugin_instance_ptr =
unsafe { create_plugin(plugin_factory, raw_descriptor, plugin_id)? };
unsafe {
instance.host_wrapper.created(plugin_instance_ptr);
}
unsafe {
if let Some(init) = plugin_instance_ptr.as_ref().init {
if !init(plugin_instance_ptr.as_ptr()) {
instance.host_wrapper.start_instance_destroy();
if let Some(destroy) = plugin_instance_ptr.as_ref().destroy {
destroy(plugin_instance_ptr.as_ptr());
}
return Err(PluginInstanceError::InstantiationFailed);
}
}
}
unsafe { instance.host_wrapper.instantiated() };
instance.plugin_ptr = Some(plugin_instance_ptr);
}
Ok(instance)
}
#[inline]
pub fn wrapper(&self) -> &HostWrapper<H> {
&self.host_wrapper
}
#[inline]
pub fn entry(&self) -> &PluginEntry {
&self.plugin_entry
}
#[inline]
pub fn raw_instance(&self) -> &clap_plugin {
unsafe { self.plugin_ptr.unwrap_unchecked().as_ref() }
}
#[inline]
pub fn plugin_shared(&self) -> PluginSharedHandle<'_> {
unsafe { PluginSharedHandle::new(self.raw_instance().into()) }
}
pub fn activate<FA>(
&mut self,
audio_processor: FA,
configuration: PluginAudioConfiguration,
) -> Result<(), PluginInstanceError>
where
FA: for<'a> FnOnce(
&'a <H as HostHandlers>::Shared<'a>,
&<H as HostHandlers>::MainThread<'a>,
) -> <H as HostHandlers>::AudioProcessor<'a>,
{
let activate = self
.raw_instance()
.activate
.ok_or(PluginInstanceError::NullActivateFunction)?;
unsafe {
self.host_wrapper.setup_audio_processor(audio_processor)?;
}
let success = unsafe {
activate(
self.raw_instance(),
configuration.sample_rate,
configuration.min_frames_count,
configuration.max_frames_count,
)
};
if !success {
let _ = unsafe { self.host_wrapper.teardown_audio_processor(|_, _| ()) };
return Err(PluginInstanceError::ActivationFailed);
}
Ok(())
}
#[inline]
pub fn is_active(&self) -> bool {
self.wrapper().is_active()
}
#[inline]
pub fn deactivate_with<T>(
&mut self,
drop: impl for<'s> FnOnce(
<H as HostHandlers>::AudioProcessor<'s>,
&<H as HostHandlers>::MainThread<'s>,
) -> T,
) -> Result<T, PluginInstanceError> {
if !self.is_active() {
return Err(PluginInstanceError::DeactivatedPlugin);
}
if self.is_started.load(Ordering::Acquire) {
unsafe { self.stop_processing() }
}
if let Some(deactivate) = self.raw_instance().deactivate {
unsafe { deactivate(self.raw_instance()) };
}
unsafe { self.host_wrapper.teardown_audio_processor(drop) }
}
#[inline]
pub unsafe fn start_processing(&self) -> Result<(), PluginInstanceError> {
if let Some(start_processing) = self.raw_instance().start_processing {
if start_processing(self.raw_instance()) {
self.is_started.store(true, Ordering::Release);
return Ok(());
}
Err(PluginInstanceError::StartProcessingFailed)
} else {
Ok(())
}
}
#[inline]
pub unsafe fn reset(&self) {
if let Some(reset) = self.raw_instance().reset {
reset(self.raw_instance())
}
}
#[inline]
pub unsafe fn stop_processing(&self) {
if let Some(stop_processing) = self.raw_instance().stop_processing {
stop_processing(self.raw_instance());
self.is_started.store(false, Ordering::Release);
}
}
#[inline]
pub unsafe fn on_main_thread(&self) {
if let Some(on_main_thread) = self.raw_instance().on_main_thread {
on_main_thread(self.raw_instance())
}
}
}
impl<H: HostHandlers> Drop for PluginInstanceInner<H> {
#[inline]
fn drop(&mut self) {
let Some(plugin_ptr) = self.plugin_ptr else {
return;
};
if self.is_active() {
let _ = self.deactivate_with(|_, _| ());
}
self.host_wrapper.start_instance_destroy();
unsafe {
if let Some(destroy) = plugin_ptr.as_ref().destroy {
destroy(plugin_ptr.as_ptr())
}
}
}
}
unsafe impl<H: HostHandlers> Send for PluginInstanceInner<H> {}
unsafe impl<H: HostHandlers> Sync for PluginInstanceInner<H> {}
pub(crate) unsafe fn create_plugin(
plugin_factory: PluginFactory<'_>,
host: *const clap_host,
plugin_id: &CStr,
) -> Result<NonNull<clap_plugin>, PluginInstanceError> {
let Some(create_plugin) = plugin_factory.raw().get().create_plugin else {
return Err(PluginInstanceError::NullFactoryCreatePluginFunction);
};
let plugin_instance_ptr =
unsafe { create_plugin(plugin_factory.raw().as_ptr(), host, plugin_id.as_ptr()) };
NonNull::new(plugin_instance_ptr.cast_mut()).ok_or(PluginInstanceError::PluginNotFound)
}