From ce858743403582148a3d0f6ce9cb6fd9897162cc Mon Sep 17 00:00:00 2001 From: Robbert van der Helm Date: Tue, 15 Mar 2022 22:28:26 +0100 Subject: [PATCH] Implement the CLAP tail extension --- src/wrapper/clap/wrapper.rs | 32 ++++++++++++++++++++++++++++---- 1 file changed, 28 insertions(+), 4 deletions(-) diff --git a/src/wrapper/clap/wrapper.rs b/src/wrapper/clap/wrapper.rs index 306a6abf..9dab778f 100644 --- a/src/wrapper/clap/wrapper.rs +++ b/src/wrapper/clap/wrapper.rs @@ -34,6 +34,7 @@ use clap_sys::ext::params::{ CLAP_PARAM_IS_AUTOMATABLE, CLAP_PARAM_IS_BYPASS, CLAP_PARAM_IS_STEPPED, }; use clap_sys::ext::state::{clap_plugin_state, CLAP_EXT_STATE}; +use clap_sys::ext::tail::{clap_plugin_tail, CLAP_EXT_TAIL}; use clap_sys::ext::thread_check::{clap_host_thread_check, CLAP_EXT_THREAD_CHECK}; use clap_sys::fixedpoint::{CLAP_BEATTIME_FACTOR, CLAP_SECTIME_FACTOR}; use clap_sys::host::clap_host; @@ -124,6 +125,8 @@ pub struct Wrapper { /// TODO: Maybe load these lazily at some point instead of needing to spool them all to this /// queue first input_events: AtomicRefCell>, + /// The last process status returned by the plugin. This is used for tail handling. + last_process_status: AtomicCell, /// The current latency in samples, as set by the plugin through the [`ProcessContext`]. uses /// the latency extnesion pub current_latency: AtomicU32, @@ -195,6 +198,8 @@ pub struct Wrapper { clap_plugin_state: clap_plugin_state, + clap_plugin_tail: clap_plugin_tail, + /// A queue of tasks that still need to be performed. Because CLAP lets the plugin request a /// host callback directly, we don't need to use the OsEventLoop we use in our other plugin /// implementations. Instead, we'll post tasks to this queue, ask the host to call @@ -354,6 +359,7 @@ impl Wrapper

{ current_buffer_config: AtomicCell::new(None), bypass_state: AtomicBool::new(false), input_events: AtomicRefCell::new(VecDeque::with_capacity(512)), + last_process_status: AtomicCell::new(ProcessStatus::Normal), current_latency: AtomicU32::new(0), output_buffer: AtomicRefCell::new(Buffer::default()), @@ -426,6 +432,10 @@ impl Wrapper

{ load: Self::ext_state_load, }, + clap_plugin_tail: clap_plugin_tail { + get: Self::ext_tail_get, + }, + tasks: ArrayQueue::new(TASK_QUEUE_CAPACITY), main_thread_id: thread::current().id(), }; @@ -1148,7 +1158,10 @@ impl Wrapper

{ let mut plugin = wrapper.plugin.write(); let mut context = wrapper.make_process_context(transport); - let result = match plugin.process(&mut output_buffer, &mut context) { + let result = plugin.process(&mut output_buffer, &mut context); + wrapper.last_process_status.store(result); + + let clap_result = match result { ProcessStatus::Error(err) => { nih_debug_assert_failure!("Process error: {}", err); @@ -1168,7 +1181,7 @@ impl Wrapper

{ // unprocessed (parameter) events. If there are more events, we'll just keep going // through this process until we've processed the entire buffer. if block_end as u32 == process.frames_count { - break result; + break clap_result; } else { block_start = block_end; } @@ -1185,8 +1198,6 @@ impl Wrapper

{ let id = CStr::from_ptr(id); - // TODO: Implement: - // - tail if id == CStr::from_ptr(CLAP_EXT_AUDIO_PORTS_CONFIG) { &wrapper.clap_plugin_audio_ports_config as *const _ as *const c_void } else if id == CStr::from_ptr(CLAP_EXT_AUDIO_PORTS) { @@ -1204,6 +1215,8 @@ impl Wrapper

{ &wrapper.clap_plugin_params as *const _ as *const c_void } else if id == CStr::from_ptr(CLAP_EXT_STATE) { &wrapper.clap_plugin_state as *const _ as *const c_void + } else if id == CStr::from_ptr(CLAP_EXT_TAIL) { + &wrapper.clap_plugin_tail as *const _ as *const c_void } else { nih_log!("Host tried to query unknown extension {:?}", id); ptr::null() @@ -1948,6 +1961,17 @@ impl Wrapper

{ true } + + unsafe extern "C" fn ext_tail_get(plugin: *const clap_plugin) -> u32 { + check_null_ptr!(0, plugin); + let wrapper = &*(plugin as *const Self); + + match wrapper.last_process_status.load() { + ProcessStatus::Tail(samples) => samples, + ProcessStatus::KeepAlive => u32::MAX, + _ => 0, + } + } } /// Convenience function to query an extennsion from the host.