1
0
Fork 0
nih-plug/src/wrapper/clap/plugin.rs

205 lines
6.7 KiB
Rust
Raw Normal View History

2022-03-01 04:27:57 +11:00
use clap_sys::host::clap_host;
use clap_sys::plugin::clap_plugin;
2022-03-01 04:55:33 +11:00
use clap_sys::process::{clap_process, clap_process_status};
2022-03-01 05:16:03 +11:00
use crossbeam::atomic::AtomicCell;
2022-03-01 04:27:57 +11:00
use parking_lot::RwLock;
use std::collections::VecDeque;
2022-03-01 04:55:33 +11:00
use std::ffi::c_void;
use std::os::raw::c_char;
use std::ptr;
use std::sync::atomic::AtomicU32;
2022-03-01 04:27:57 +11:00
use super::context::WrapperProcessContext;
2022-03-01 04:55:33 +11:00
use super::descriptor::PluginDescriptor;
use crate::event_loop::{EventLoop, MainThreadExecutor};
2022-03-01 05:16:03 +11:00
use crate::plugin::{BufferConfig, BusConfig, ClapPlugin};
use crate::NoteEvent;
2022-03-01 04:27:57 +11:00
#[repr(C)]
pub struct Plugin<P: ClapPlugin> {
// Keep the vtable as the first field so we can do a simple pointer cast
pub clap_plugin: clap_plugin,
/// The wrapped plugin instance.
plugin: RwLock<P>,
2022-03-01 05:16:03 +11:00
/// The current IO configuration, modified through the `clap_plugin_audio_ports_config`
/// extension.
current_bus_config: AtomicCell<BusConfig>,
/// The current buffer configuration, containing the sample rate and the maximum block size.
/// Will be set in `clap_plugin::activate()`.
current_buffer_config: AtomicCell<Option<BufferConfig>>,
/// The incoming events for the plugin, if `P::ACCEPTS_MIDI` is set.
///
/// TODO: Maybe load these lazily at some point instead of needing to spool them all to this
/// queue first
/// TODO: Read these in the process call.
input_events: RwLock<VecDeque<NoteEvent>>,
/// The current latency in samples, as set by the plugin through the [ProcessContext]. uses the
/// latency extnesion
///
/// TODO: Implement the latency extension.
pub current_latency: AtomicU32,
host_callback: HostCallback,
2022-03-01 04:55:33 +11:00
/// Needs to be boxed because the plugin object is supposed to contain a static reference to
/// this.
plugin_descriptor: Box<PluginDescriptor<P>>,
2022-03-01 04:27:57 +11:00
}
/// Send+Sync wrapper around clap_host.
struct HostCallback(*const clap_host);
/// Tasks that can be sent from the plugin to be executed on the main thread in a non-blocking
/// realtime safe way. Instead of using a random thread or the OS' event loop like in the Linux
/// implementation, this uses [clap_host::request_callback()] instead.
#[derive(Debug, Clone)]
pub enum Task {
/// Inform the host that the latency has changed.
LatencyChanged,
}
/// Because CLAP has this [clap_host::request_host_callback()] function, we don't need to use
/// `OsEventLoop` and can instead just request a main thread callback directly.
impl<P: ClapPlugin> EventLoop<Task, Plugin<P>> for Plugin<P> {
fn new_and_spawn(executor: std::sync::Weak<Self>) -> Self {
panic!("What are you doing");
}
fn do_maybe_async(&self, task: Task) -> bool {
todo!()
}
fn is_main_thread(&self) -> bool {
todo!()
}
}
impl<P: ClapPlugin> MainThreadExecutor<Task> for Plugin<P> {
unsafe fn execute(&self, task: Task) {
todo!()
}
}
unsafe impl Send for HostCallback {}
unsafe impl Sync for HostCallback {}
2022-03-01 04:27:57 +11:00
impl<P: ClapPlugin> Plugin<P> {
pub fn new(host_callback: *const clap_host) -> Self {
2022-03-01 04:55:33 +11:00
let plugin_descriptor = Box::new(PluginDescriptor::default());
2022-03-01 04:27:57 +11:00
Self {
clap_plugin: clap_plugin {
2022-03-01 04:55:33 +11:00
// This needs to live on the heap because the plugin object contains a direct
// reference to the manifest as a value. We could share this between instances of
// the plugin using an `Arc`, but this doesn't consume a lot of memory so it's not a
// huge deal.
desc: plugin_descriptor.clap_plugin_descriptor(),
// We already need to use pointer casts in the factory, so might as well continue
// doing that here
plugin_data: ptr::null_mut(),
init: Self::init,
destroy: Self::destroy,
activate: Self::activate,
deactivate: Self::deactivate,
start_processing: Self::start_processing,
stop_processing: Self::stop_processing,
process: Self::process,
get_extension: Self::get_extension,
on_main_thread: Self::on_main_thread,
2022-03-01 04:27:57 +11:00
},
2022-03-01 04:55:33 +11:00
2022-03-01 04:27:57 +11:00
plugin: RwLock::new(P::default()),
2022-03-01 05:16:03 +11:00
current_bus_config: AtomicCell::new(BusConfig {
num_input_channels: P::DEFAULT_NUM_INPUTS,
num_output_channels: P::DEFAULT_NUM_OUTPUTS,
}),
current_buffer_config: AtomicCell::new(None),
input_events: RwLock::new(VecDeque::with_capacity(512)),
current_latency: AtomicU32::new(0),
2022-03-01 04:55:33 +11:00
host_callback: HostCallback(host_callback),
2022-03-01 04:55:33 +11:00
plugin_descriptor,
2022-03-01 04:27:57 +11:00
}
}
2022-03-01 04:55:33 +11:00
fn make_process_context(&self) -> WrapperProcessContext<'_, P> {
WrapperProcessContext {
plugin: self,
input_events_guard: self.input_events.write(),
}
}
2022-03-01 05:16:03 +11:00
unsafe extern "C" fn init(_plugin: *const clap_plugin) -> bool {
// We don't need any special initialization
true
2022-03-01 04:55:33 +11:00
}
2022-03-01 05:16:03 +11:00
2022-03-01 04:55:33 +11:00
unsafe extern "C" fn destroy(plugin: *const clap_plugin) {
2022-03-01 05:16:03 +11:00
Box::from_raw(plugin as *mut Self);
2022-03-01 04:55:33 +11:00
}
2022-03-01 05:16:03 +11:00
2022-03-01 04:55:33 +11:00
unsafe extern "C" fn activate(
plugin: *const clap_plugin,
sample_rate: f64,
min_frames_count: u32,
max_frames_count: u32,
) -> bool {
2022-03-01 05:16:03 +11:00
let plugin = &*(plugin as *const Self);
let bus_config = plugin.current_bus_config.load();
let buffer_config = BufferConfig {
sample_rate: sample_rate as f32,
max_buffer_size: max_frames_count,
};
// TODO: Reset smoothers
if plugin.plugin.write().initialize(
&bus_config,
&buffer_config,
&mut plugin.make_process_context(),
) {
// TODO: Allocate buffer slices
// Also store this for later, so we can reinitialize the plugin after restoring state
plugin.current_buffer_config.store(Some(buffer_config));
true
} else {
false
}
2022-03-01 04:55:33 +11:00
}
2022-03-01 05:16:03 +11:00
unsafe extern "C" fn deactivate(_plugin: *const clap_plugin) {
// We currently don't do anything here
2022-03-01 04:55:33 +11:00
}
2022-03-01 05:16:03 +11:00
unsafe extern "C" fn start_processing(_plugin: *const clap_plugin) -> bool {
// We currently don't do anything here
true
2022-03-01 04:55:33 +11:00
}
2022-03-01 05:16:03 +11:00
unsafe extern "C" fn stop_processing(_plugin: *const clap_plugin) {
// We currently don't do anything here
2022-03-01 04:55:33 +11:00
}
2022-03-01 05:16:03 +11:00
2022-03-01 04:55:33 +11:00
unsafe extern "C" fn process(
plugin: *const clap_plugin,
process: *const clap_process,
) -> clap_process_status {
todo!();
}
2022-03-01 05:16:03 +11:00
2022-03-01 04:55:33 +11:00
unsafe extern "C" fn get_extension(
plugin: *const clap_plugin,
id: *const c_char,
) -> *const c_void {
todo!();
}
2022-03-01 05:16:03 +11:00
2022-03-01 04:55:33 +11:00
unsafe extern "C" fn on_main_thread(plugin: *const clap_plugin) {
todo!();
}
}