1
0
Fork 0

Implement the CLAP latency extension

This commit is contained in:
Robbert van der Helm 2022-03-03 00:46:49 +01:00
parent c3efc81957
commit 4eb35ed585

View file

@ -15,6 +15,7 @@ use clap_sys::ext::audio_ports::{
use clap_sys::ext::audio_ports_config::{ use clap_sys::ext::audio_ports_config::{
clap_audio_ports_config, clap_plugin_audio_ports_config, CLAP_EXT_AUDIO_PORTS_CONFIG, clap_audio_ports_config, clap_plugin_audio_ports_config, CLAP_EXT_AUDIO_PORTS_CONFIG,
}; };
use clap_sys::ext::latency::{clap_host_latency, clap_plugin_latency, CLAP_EXT_LATENCY};
use clap_sys::ext::params::{ use clap_sys::ext::params::{
clap_param_info, clap_plugin_params, CLAP_EXT_PARAMS, CLAP_PARAM_IS_BYPASS, clap_param_info, clap_plugin_params, CLAP_EXT_PARAMS, CLAP_PARAM_IS_BYPASS,
CLAP_PARAM_IS_STEPPED, CLAP_PARAM_IS_STEPPED,
@ -92,14 +93,13 @@ pub struct Wrapper<P: ClapPlugin> {
/// a mutable reference to the data contained in this mutex. /// a mutable reference to the data contained in this mutex.
pub output_buffer: RwLock<Buffer<'static>>, pub output_buffer: RwLock<Buffer<'static>>,
// We'll query all of the host's extensions upfront
host_callback: ClapPtr<clap_host>,
thread_check: Option<ClapPtr<clap_host_thread_check>>,
/// Needs to be boxed because the plugin object is supposed to contain a static reference to /// Needs to be boxed because the plugin object is supposed to contain a static reference to
/// this. /// this.
plugin_descriptor: Box<PluginDescriptor<P>>, plugin_descriptor: Box<PluginDescriptor<P>>,
// We'll query all of the host's extensions upfront
host_callback: ClapPtr<clap_host>,
clap_plugin_audio_ports_config: clap_plugin_audio_ports_config, clap_plugin_audio_ports_config: clap_plugin_audio_ports_config,
/// During initialization we'll ask `P` which bus configurations it supports. The host can then /// During initialization we'll ask `P` which bus configurations it supports. The host can then
/// use the audio ports config extension to choose a configuration. Right now we only query mono /// use the audio ports config extension to choose a configuration. Right now we only query mono
@ -112,6 +112,9 @@ pub struct Wrapper<P: ClapPlugin> {
clap_plugin_audio_ports: clap_plugin_audio_ports, clap_plugin_audio_ports: clap_plugin_audio_ports,
clap_plugin_latency: clap_plugin_latency,
host_latency: Option<ClapPtr<clap_host_latency>>,
clap_plugin_params: clap_plugin_params, clap_plugin_params: clap_plugin_params,
// These fiels are exactly the same as their VST3 wrapper counterparts. // These fiels are exactly the same as their VST3 wrapper counterparts.
// //
@ -133,6 +136,8 @@ pub struct Wrapper<P: ClapPlugin> {
/// add a setter function to the parameter (or even worse, have it be completely untyped). /// add a setter function to the parameter (or even worse, have it be completely untyped).
param_ptr_to_hash: HashMap<ParamPtr, u32>, param_ptr_to_hash: HashMap<ParamPtr, u32>,
host_thread_check: Option<ClapPtr<clap_host_thread_check>>,
clap_plugin_state: clap_plugin_state, clap_plugin_state: clap_plugin_state,
/// A queue of tasks that still need to be performed. Because CLAP lets the plugin request a /// A queue of tasks that still need to be performed. Because CLAP lets the plugin request a
@ -191,7 +196,7 @@ impl<P: ClapPlugin> EventLoop<Task, Wrapper<P>> for Wrapper<P> {
fn is_main_thread(&self) -> bool { fn is_main_thread(&self) -> bool {
// If the host supports the thread check interface then we'll use that, otherwise we'll // If the host supports the thread check interface then we'll use that, otherwise we'll
// check if this is the same thread as the one that created the plugin instance. // check if this is the same thread as the one that created the plugin instance.
match &self.thread_check { match &self.host_thread_check {
Some(thread_check) => unsafe { (thread_check.is_main_thread)(&*self.host_callback) }, Some(thread_check) => unsafe { (thread_check.is_main_thread)(&*self.host_callback) },
None => thread::current().id() == self.main_thread_id, None => thread::current().id() == self.main_thread_id,
} }
@ -200,7 +205,13 @@ impl<P: ClapPlugin> EventLoop<Task, Wrapper<P>> for Wrapper<P> {
impl<P: ClapPlugin> MainThreadExecutor<Task> for Wrapper<P> { impl<P: ClapPlugin> MainThreadExecutor<Task> for Wrapper<P> {
unsafe fn execute(&self, task: Task) { unsafe fn execute(&self, task: Task) {
todo!("Implement latency changes for CLAP") // This function is always called from the main thread, from [Self::on_main_thread].
match task {
Task::LatencyChanged => match &self.host_latency {
Some(host_latency) => (host_latency.changed)(&*self.host_callback),
None => nih_debug_assert_failure!("Host does not support the latency extension"),
},
};
} }
} }
@ -210,7 +221,9 @@ impl<P: ClapPlugin> Wrapper<P> {
assert!(!host_callback.is_null()); assert!(!host_callback.is_null());
let host_callback = unsafe { ClapPtr::new(host_callback) }; let host_callback = unsafe { ClapPtr::new(host_callback) };
let thread_check = unsafe { let host_latency =
unsafe { query_host_extension::<clap_host_latency>(&host_callback, CLAP_EXT_LATENCY) };
let host_thread_check = unsafe {
query_host_extension::<clap_host_thread_check>(&host_callback, CLAP_EXT_THREAD_CHECK) query_host_extension::<clap_host_thread_check>(&host_callback, CLAP_EXT_THREAD_CHECK)
}; };
@ -246,11 +259,10 @@ impl<P: ClapPlugin> Wrapper<P> {
current_latency: AtomicU32::new(0), current_latency: AtomicU32::new(0),
output_buffer: RwLock::new(Buffer::default()), output_buffer: RwLock::new(Buffer::default()),
host_callback,
thread_check,
plugin_descriptor, plugin_descriptor,
host_callback,
clap_plugin_audio_ports_config: clap_plugin_audio_ports_config { clap_plugin_audio_ports_config: clap_plugin_audio_ports_config {
count: Self::ext_audio_ports_config_count, count: Self::ext_audio_ports_config_count,
get: Self::ext_audio_ports_config_get, get: Self::ext_audio_ports_config_get,
@ -263,6 +275,11 @@ impl<P: ClapPlugin> Wrapper<P> {
get: Self::ext_audio_ports_get, get: Self::ext_audio_ports_get,
}, },
clap_plugin_latency: clap_plugin_latency {
get: Self::ext_latency_get,
},
host_latency,
clap_plugin_params: clap_plugin_params { clap_plugin_params: clap_plugin_params {
count: Self::ext_params_count, count: Self::ext_params_count,
get_info: Self::ext_params_get_info, get_info: Self::ext_params_get_info,
@ -277,6 +294,8 @@ impl<P: ClapPlugin> Wrapper<P> {
param_id_to_hash: HashMap::new(), param_id_to_hash: HashMap::new(),
param_ptr_to_hash: HashMap::new(), param_ptr_to_hash: HashMap::new(),
host_thread_check,
clap_plugin_state: clap_plugin_state { clap_plugin_state: clap_plugin_state {
save: Self::ext_state_save, save: Self::ext_state_save,
load: Self::ext_state_load, load: Self::ext_state_load,
@ -679,12 +698,13 @@ impl<P: ClapPlugin> Wrapper<P> {
// TODO: Implement the following extensions: // TODO: Implement the following extensions:
// - gui // - gui
// - the non-freestanding GUI extensions depending on the platform // - the non-freestanding GUI extensions depending on the platform
// - latency
let id = CStr::from_ptr(id); let id = CStr::from_ptr(id);
if id == CStr::from_ptr(CLAP_EXT_AUDIO_PORTS_CONFIG) { if id == CStr::from_ptr(CLAP_EXT_AUDIO_PORTS_CONFIG) {
&wrapper.clap_plugin_audio_ports_config as *const _ as *const c_void &wrapper.clap_plugin_audio_ports_config as *const _ as *const c_void
} else if id == CStr::from_ptr(CLAP_EXT_AUDIO_PORTS) { } else if id == CStr::from_ptr(CLAP_EXT_AUDIO_PORTS) {
&wrapper.clap_plugin_audio_ports as *const _ as *const c_void &wrapper.clap_plugin_audio_ports as *const _ as *const c_void
} else if id == CStr::from_ptr(CLAP_EXT_LATENCY) {
&wrapper.clap_plugin_latency as *const _ as *const c_void
} else if id == CStr::from_ptr(CLAP_EXT_PARAMS) { } else if id == CStr::from_ptr(CLAP_EXT_PARAMS) {
&wrapper.clap_plugin_params as *const _ as *const c_void &wrapper.clap_plugin_params as *const _ as *const c_void
} else if id == CStr::from_ptr(CLAP_EXT_STATE) { } else if id == CStr::from_ptr(CLAP_EXT_STATE) {
@ -882,6 +902,13 @@ impl<P: ClapPlugin> Wrapper<P> {
} }
} }
unsafe extern "C" fn ext_latency_get(plugin: *const clap_plugin) -> u32 {
check_null_ptr!(0, plugin);
let wrapper = &*(plugin as *const Self);
wrapper.current_latency.load(Ordering::SeqCst)
}
unsafe extern "C" fn ext_params_count(plugin: *const clap_plugin) -> u32 { unsafe extern "C" fn ext_params_count(plugin: *const clap_plugin) -> u32 {
check_null_ptr!(0, plugin); check_null_ptr!(0, plugin);
let wrapper = &*(plugin as *const Self); let wrapper = &*(plugin as *const Self);