Implement the CLAP latency extension
This commit is contained in:
parent
c3efc81957
commit
4eb35ed585
|
@ -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);
|
||||||
|
|
Loading…
Reference in a new issue