1
0
Fork 0

Update clap-sys with optional function pointers

None of these function pointers are allowed to be null, yet even the
official `clap-helpers` do this. This new `clap_call!()` macro asserts
that a pointer is non-null before calling it.
This commit is contained in:
Robbert van der Helm 2022-07-04 00:07:06 +02:00
parent 24d499e716
commit 5cbd8827e9
7 changed files with 153 additions and 117 deletions

5
Cargo.lock generated
View file

@ -502,9 +502,8 @@ dependencies = [
[[package]] [[package]]
name = "clap-sys" name = "clap-sys"
version = "0.1.0" version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "git+https://github.com/glowcoil/clap-sys.git?rev=efc0940651c3a57a3f9402bf3798cda9a7f7fc87#efc0940651c3a57a3f9402bf3798cda9a7f7fc87"
checksum = "4a8aa914ef6a42441b5ef7884eef20c6d38bd5b24c3c9eba865b08bf3353bc11"
[[package]] [[package]]
name = "clap_derive" name = "clap_derive"

View file

@ -67,7 +67,8 @@ atomic_refcell = "0.1"
backtrace = "0.3.65" backtrace = "0.3.65"
bitflags = "1.3" bitflags = "1.3"
cfg-if = "1.0" cfg-if = "1.0"
clap-sys = "0.1" # TODO: Switch back to the crates.rs version once the debug prints are in a released version
clap-sys = { git = "https://github.com/glowcoil/clap-sys.git", rev = "efc0940651c3a57a3f9402bf3798cda9a7f7fc87" }
crossbeam = "0.8" crossbeam = "0.8"
lazy_static = "1.4" lazy_static = "1.4"
log = { version = "0.4", features = ["std", "release_max_level_info"] } log = { version = "0.4", features = ["std", "release_max_level_info"] }

View file

@ -42,11 +42,7 @@ macro_rules! nih_export_clap {
) -> *const ::std::ffi::c_void { ) -> *const ::std::ffi::c_void {
if !factory_id.is_null() if !factory_id.is_null()
&& unsafe { ::std::ffi::CStr::from_ptr(factory_id) } && unsafe { ::std::ffi::CStr::from_ptr(factory_id) }
== unsafe { == ::nih_plug::wrapper::clap::CLAP_PLUGIN_FACTORY_ID
::std::ffi::CStr::from_ptr(
::nih_plug::wrapper::clap::CLAP_PLUGIN_FACTORY_ID,
)
}
{ {
&(*FACTORY).clap_plugin_factory as *const _ as *const ::std::ffi::c_void &(*FACTORY).clap_plugin_factory as *const _ as *const ::std::ffi::c_void
} else { } else {
@ -60,9 +56,9 @@ macro_rules! nih_export_clap {
pub static clap_entry: ::nih_plug::wrapper::clap::clap_plugin_entry = pub static clap_entry: ::nih_plug::wrapper::clap::clap_plugin_entry =
::nih_plug::wrapper::clap::clap_plugin_entry { ::nih_plug::wrapper::clap::clap_plugin_entry {
clap_version: ::nih_plug::wrapper::clap::CLAP_VERSION, clap_version: ::nih_plug::wrapper::clap::CLAP_VERSION,
init: self::clap::init, init: Some(self::clap::init),
deinit: self::clap::deinit, deinit: Some(self::clap::deinit),
get_factory: self::clap::get_factory, get_factory: Some(self::clap::get_factory),
}; };
}; };
} }

View file

@ -25,9 +25,9 @@ impl<P: ClapPlugin> Default for Factory<P> {
fn default() -> Self { fn default() -> Self {
Self { Self {
clap_plugin_factory: clap_plugin_factory { clap_plugin_factory: clap_plugin_factory {
get_plugin_count: Self::get_plugin_count, get_plugin_count: Some(Self::get_plugin_count),
get_plugin_descriptor: Self::get_plugin_descriptor, get_plugin_descriptor: Some(Self::get_plugin_descriptor),
create_plugin: Self::create_plugin, create_plugin: Some(Self::create_plugin),
}, },
plugin_descriptor: PluginDescriptor::default(), plugin_descriptor: PluginDescriptor::default(),
} }

View file

@ -7,7 +7,7 @@ use std::os::raw::c_void;
/// null. /// null.
macro_rules! check_null_ptr { macro_rules! check_null_ptr {
($ret:expr, $ptr:expr $(, $ptrs:expr)* $(, )?) => { ($ret:expr, $ptr:expr $(, $ptrs:expr)* $(, )?) => {
check_null_ptr_msg!("Null pointer passed to function", $ret, $ptr $(, $ptrs)*) $crate::wrapper::clap::util::check_null_ptr_msg!("Null pointer passed to function", $ret, $ptr $(, $ptrs)*)
}; };
} }
@ -24,6 +24,40 @@ macro_rules! check_null_ptr_msg {
}; };
} }
/// Call a CLAP function. This is needed because even though none of CLAP's functions are allowed to
/// be null pointers, people will still use null pointers for some of the function arguments. This
/// also happens in the official `clap-helpers`. As such, these functions are now `Option<fn(...)>`
/// optional function pointers in `clap-sys`. This macro asserts that the pointer is not null, and
/// prints a nicely formatted error message containing the struct and funciton name if it is. It
/// also emulates C's syntax for accessing fields struct through a pointer. Except that it uses `=>`
/// instead of `->`. Because that sounds like it would be hilarious.
macro_rules! clap_call {
{ $obj_ptr:expr=>$function_name:ident($($args:expr),* $(, )?) } => {
match (*$obj_ptr).$function_name {
Some(function_ptr) => function_ptr($($args),*),
None => panic!("'{}::{}' is a null pointer, but this is not allowed", $crate::wrapper::clap::util::type_name_of_ptr($obj_ptr), stringify!($function_name)),
}
}
}
/// [`clap_call!()`], wrapped in an unsafe block.
macro_rules! unsafe_clap_call {
{ $($args:tt)* } => {
unsafe { $crate::wrapper::clap::util::clap_call! { $($args)* } }
}
}
/// Similar to, [`std::any::type_name_of_val()`], but on stable Rust, and stripping away the pointer
/// part.
#[must_use]
pub fn type_name_of_ptr<T: ?Sized>(_ptr: *const T) -> &'static str {
std::any::type_name::<T>()
}
pub(crate) use check_null_ptr_msg;
pub(crate) use clap_call;
pub(crate) use unsafe_clap_call;
/// Send+Sync wrapper around CLAP host extension pointers. /// Send+Sync wrapper around CLAP host extension pointers.
pub struct ClapPtr<T> { pub struct ClapPtr<T> {
inner: *const T, inner: *const T,
@ -92,8 +126,8 @@ unsafe impl ByteReadBuffer for &mut [MaybeUninit<u8>] {
pub fn read_stream(stream: &clap_istream, mut slice: impl ByteReadBuffer) -> bool { pub fn read_stream(stream: &clap_istream, mut slice: impl ByteReadBuffer) -> bool {
let mut read_pos = 0; let mut read_pos = 0;
while read_pos < slice.len() { while read_pos < slice.len() {
let bytes_read = unsafe { let bytes_read = unsafe_clap_call! {
(stream.read)( stream=>read(
stream, stream,
slice.as_mut_ptr().add(read_pos) as *mut c_void, slice.as_mut_ptr().add(read_pos) as *mut c_void,
(slice.len() - read_pos) as u64, (slice.len() - read_pos) as u64,
@ -115,8 +149,8 @@ pub fn read_stream(stream: &clap_istream, mut slice: impl ByteReadBuffer) -> boo
pub fn write_stream(stream: &clap_ostream, slice: &[u8]) -> bool { pub fn write_stream(stream: &clap_ostream, slice: &[u8]) -> bool {
let mut write_pos = 0; let mut write_pos = 0;
while write_pos < slice.len() { while write_pos < slice.len() {
let bytes_written = unsafe { let bytes_written = unsafe_clap_call! {
(stream.write)( stream=>write(
stream, stream,
slice.as_ptr().add(write_pos) as *const c_void, slice.as_ptr().add(write_pos) as *const c_void,
(slice.len() - write_pos) as u64, (slice.len() - write_pos) as u64,

View file

@ -305,7 +305,7 @@ impl<P: ClapPlugin> EventLoop<Task, Wrapper<P>> for Wrapper<P> {
if success { if success {
// CLAP lets us use the host's event loop instead of having to implement our own // CLAP lets us use the host's event loop instead of having to implement our own
let host = &self.host_callback; let host = &self.host_callback;
unsafe { (host.request_callback)(&**host) }; unsafe_clap_call! { host=>request_callback(&**host) };
} }
success success
@ -316,7 +316,9 @@ impl<P: ClapPlugin> EventLoop<Task, Wrapper<P>> for Wrapper<P> {
// 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.host_thread_check.borrow() { match &*self.host_thread_check.borrow() {
Some(thread_check) => unsafe { (thread_check.is_main_thread)(&*self.host_callback) }, Some(thread_check) => {
unsafe_clap_call! { thread_check=>is_main_thread(&*self.host_callback) }
}
// FIXME: `thread::current()` may allocate the first time it's called, is there a safe // FIXME: `thread::current()` may allocate the first time it's called, is there a safe
// nonallocating version of this without using huge OS-specific libraries? // nonallocating version of this without using huge OS-specific libraries?
None => permit_alloc(|| thread::current().id() == self.main_thread_id), None => permit_alloc(|| thread::current().id() == self.main_thread_id),
@ -335,16 +337,16 @@ impl<P: ClapPlugin> MainThreadExecutor<Task> for Wrapper<P> {
// is processing, but we'll treat it as the same thing). In practice just // is processing, but we'll treat it as the same thing). In practice just
// calling the latency changed function also seems to work just fine. // calling the latency changed function also seems to work just fine.
if self.is_processing.load(Ordering::SeqCst) { if self.is_processing.load(Ordering::SeqCst) {
(self.host_callback.request_restart)(&*self.host_callback) clap_call! { &*self.host_callback=>request_restart(&*self.host_callback) };
} else { } else {
(host_latency.changed)(&*self.host_callback) clap_call! { host_latency=>changed(&*self.host_callback) };
} }
} }
None => nih_debug_assert_failure!("Host does not support the latency extension"), None => nih_debug_assert_failure!("Host does not support the latency extension"),
}, },
Task::RescanParamValues => match &*self.host_params.borrow() { Task::RescanParamValues => match &*self.host_params.borrow() {
Some(host_params) => { Some(host_params) => {
(host_params.rescan)(&*self.host_callback, CLAP_PARAM_RESCAN_VALUES); clap_call! { host_params=>rescan(&*self.host_callback, CLAP_PARAM_RESCAN_VALUES) };
} }
None => nih_debug_assert_failure!("The host does not support parameters? What?"), None => nih_debug_assert_failure!("The host does not support parameters? What?"),
}, },
@ -487,16 +489,16 @@ impl<P: ClapPlugin> Wrapper<P> {
// We already need to use pointer casts in the factory, so might as well continue // We already need to use pointer casts in the factory, so might as well continue
// doing that here // doing that here
plugin_data: ptr::null_mut(), plugin_data: ptr::null_mut(),
init: Self::init, init: Some(Self::init),
destroy: Self::destroy, destroy: Some(Self::destroy),
activate: Self::activate, activate: Some(Self::activate),
deactivate: Self::deactivate, deactivate: Some(Self::deactivate),
start_processing: Self::start_processing, start_processing: Some(Self::start_processing),
stop_processing: Self::stop_processing, stop_processing: Some(Self::stop_processing),
reset: Self::reset, reset: Some(Self::reset),
process: Self::process, process: Some(Self::process),
get_extension: Self::get_extension, get_extension: Some(Self::get_extension),
on_main_thread: Self::on_main_thread, on_main_thread: Some(Self::on_main_thread),
}, },
this: AtomicRefCell::new(Weak::new()), this: AtomicRefCell::new(Weak::new()),
@ -532,53 +534,53 @@ impl<P: ClapPlugin> Wrapper<P> {
host_callback, 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: Some(Self::ext_audio_ports_config_count),
get: Self::ext_audio_ports_config_get, get: Some(Self::ext_audio_ports_config_get),
select: Self::ext_audio_ports_config_select, select: Some(Self::ext_audio_ports_config_select),
}, },
supported_bus_configs, supported_bus_configs,
clap_plugin_audio_ports: clap_plugin_audio_ports { clap_plugin_audio_ports: clap_plugin_audio_ports {
count: Self::ext_audio_ports_count, count: Some(Self::ext_audio_ports_count),
get: Self::ext_audio_ports_get, get: Some(Self::ext_audio_ports_get),
}, },
clap_plugin_gui: clap_plugin_gui { clap_plugin_gui: clap_plugin_gui {
is_api_supported: Self::ext_gui_is_api_supported, is_api_supported: Some(Self::ext_gui_is_api_supported),
get_preferred_api: Self::ext_gui_get_preferred_api, get_preferred_api: Some(Self::ext_gui_get_preferred_api),
create: Self::ext_gui_create, create: Some(Self::ext_gui_create),
destroy: Self::ext_gui_destroy, destroy: Some(Self::ext_gui_destroy),
set_scale: Self::ext_gui_set_scale, set_scale: Some(Self::ext_gui_set_scale),
get_size: Self::ext_gui_get_size, get_size: Some(Self::ext_gui_get_size),
can_resize: Self::ext_gui_can_resize, can_resize: Some(Self::ext_gui_can_resize),
get_resize_hints: Self::ext_gui_get_resize_hints, get_resize_hints: Some(Self::ext_gui_get_resize_hints),
adjust_size: Self::ext_gui_adjust_size, adjust_size: Some(Self::ext_gui_adjust_size),
set_size: Self::ext_gui_set_size, set_size: Some(Self::ext_gui_set_size),
set_parent: Self::ext_gui_set_parent, set_parent: Some(Self::ext_gui_set_parent),
set_transient: Self::ext_gui_set_transient, set_transient: Some(Self::ext_gui_set_transient),
suggest_title: Self::ext_gui_suggest_title, suggest_title: Some(Self::ext_gui_suggest_title),
show: Self::ext_gui_show, show: Some(Self::ext_gui_show),
hide: Self::ext_gui_hide, hide: Some(Self::ext_gui_hide),
}, },
host_gui: AtomicRefCell::new(None), host_gui: AtomicRefCell::new(None),
clap_plugin_latency: clap_plugin_latency { clap_plugin_latency: clap_plugin_latency {
get: Self::ext_latency_get, get: Some(Self::ext_latency_get),
}, },
host_latency: AtomicRefCell::new(None), host_latency: AtomicRefCell::new(None),
clap_plugin_note_ports: clap_plugin_note_ports { clap_plugin_note_ports: clap_plugin_note_ports {
count: Self::ext_note_ports_count, count: Some(Self::ext_note_ports_count),
get: Self::ext_note_ports_get, get: Some(Self::ext_note_ports_get),
}, },
clap_plugin_params: clap_plugin_params { clap_plugin_params: clap_plugin_params {
count: Self::ext_params_count, count: Some(Self::ext_params_count),
get_info: Self::ext_params_get_info, get_info: Some(Self::ext_params_get_info),
get_value: Self::ext_params_get_value, get_value: Some(Self::ext_params_get_value),
value_to_text: Self::ext_params_value_to_text, value_to_text: Some(Self::ext_params_value_to_text),
text_to_value: Self::ext_params_text_to_value, text_to_value: Some(Self::ext_params_text_to_value),
flush: Self::ext_params_flush, flush: Some(Self::ext_params_flush),
}, },
host_params: AtomicRefCell::new(None), host_params: AtomicRefCell::new(None),
param_hashes, param_hashes,
@ -591,17 +593,17 @@ impl<P: ClapPlugin> Wrapper<P> {
host_thread_check: AtomicRefCell::new(None), host_thread_check: AtomicRefCell::new(None),
clap_plugin_render: clap_plugin_render { clap_plugin_render: clap_plugin_render {
has_hard_realtime_requirement: Self::ext_render_has_hard_realtime_requirement, has_hard_realtime_requirement: Some(Self::ext_render_has_hard_realtime_requirement),
set: Self::ext_render_set, set: Some(Self::ext_render_set),
}, },
clap_plugin_state: clap_plugin_state { clap_plugin_state: clap_plugin_state {
save: Self::ext_state_save, save: Some(Self::ext_state_save),
load: Self::ext_state_load, load: Some(Self::ext_state_load),
}, },
clap_plugin_tail: clap_plugin_tail { clap_plugin_tail: clap_plugin_tail {
get: Self::ext_tail_get, get: Some(Self::ext_tail_get),
}, },
tasks: ArrayQueue::new(TASK_QUEUE_CAPACITY), tasks: ArrayQueue::new(TASK_QUEUE_CAPACITY),
@ -645,7 +647,9 @@ impl<P: ClapPlugin> Wrapper<P> {
// Requesting a flush is fine even during audio processing. This avoids a race condition. // Requesting a flush is fine even during audio processing. This avoids a race condition.
match &*self.host_params.borrow() { match &*self.host_params.borrow() {
Some(host_params) => unsafe { (host_params.request_flush)(&*self.host_callback) }, Some(host_params) => {
unsafe_clap_call! { host_params=>request_flush(&*self.host_callback) }
}
None => nih_debug_assert_failure!("The host does not support parameters? What?"), None => nih_debug_assert_failure!("The host does not support parameters? What?"),
} }
@ -670,8 +674,8 @@ impl<P: ClapPlugin> Wrapper<P> {
let (unscaled_width, unscaled_height) = editor.size(); let (unscaled_width, unscaled_height) = editor.size();
let scaling_factor = self.editor_scaling_factor.load(Ordering::Relaxed); let scaling_factor = self.editor_scaling_factor.load(Ordering::Relaxed);
unsafe { unsafe_clap_call! {
(host_gui.request_resize)( host_gui=>request_resize(
&*self.host_callback, &*self.host_callback,
(unscaled_width as f32 * scaling_factor).round() as u32, (unscaled_width as f32 * scaling_factor).round() as u32,
(unscaled_height as f32 * scaling_factor).round() as u32, (unscaled_height as f32 * scaling_factor).round() as u32,
@ -738,10 +742,10 @@ impl<P: ClapPlugin> Wrapper<P> {
let mut input_events = self.input_events.borrow_mut(); let mut input_events = self.input_events.borrow_mut();
input_events.clear(); input_events.clear();
let num_events = ((*in_).size)(in_); let num_events = clap_call! { in_=>size(in_) };
let mut parameter_values_changed = false; let mut parameter_values_changed = false;
for event_idx in 0..num_events { for event_idx in 0..num_events {
let event = ((*in_).get)(in_, event_idx); let event = clap_call! { in_=>get(in_, event_idx) };
parameter_values_changed |= parameter_values_changed |=
self.handle_in_event(event, &mut input_events, None, current_sample_idx); self.handle_in_event(event, &mut input_events, None, current_sample_idx);
} }
@ -773,13 +777,13 @@ impl<P: ClapPlugin> Wrapper<P> {
input_events.clear(); input_events.clear();
// To achive this, we'll always read one event ahead // To achive this, we'll always read one event ahead
let num_events = ((*in_).size)(in_); let num_events = clap_call! { in_=>size(in_) };
if num_events == 0 { if num_events == 0 {
return None; return None;
} }
let start_idx = resume_from_event_idx as u32; let start_idx = resume_from_event_idx as u32;
let mut event: *const clap_event_header = ((*in_).get)(in_, start_idx); let mut event: *const clap_event_header = clap_call! { in_=>get(in_, start_idx) };
let mut parameter_values_changed = false; let mut parameter_values_changed = false;
for next_event_idx in (start_idx + 1)..num_events { for next_event_idx in (start_idx + 1)..num_events {
parameter_values_changed |= self.handle_in_event( parameter_values_changed |= self.handle_in_event(
@ -791,7 +795,7 @@ impl<P: ClapPlugin> Wrapper<P> {
// Stop just before the next parameter change or transport information event at a sample // Stop just before the next parameter change or transport information event at a sample
// after the current sample // after the current sample
let next_event: *const clap_event_header = ((*in_).get)(in_, next_event_idx); let next_event: *const clap_event_header = clap_call! { in_=>get(in_, next_event_idx) };
if (*next_event).time > current_sample_idx as u32 && stop_predicate(next_event) { if (*next_event).time > current_sample_idx as u32 && stop_predicate(next_event) {
return Some(((*next_event).time as usize, next_event_idx as usize)); return Some(((*next_event).time as usize, next_event_idx as usize));
} }
@ -840,7 +844,7 @@ impl<P: ClapPlugin> Wrapper<P> {
param_id: param_hash, param_id: param_hash,
}; };
(out.try_push)(out, &event.header) clap_call! { out=>try_push(out, &event.header) }
} }
OutputParamEvent::SetValue { OutputParamEvent::SetValue {
param_hash, param_hash,
@ -870,7 +874,7 @@ impl<P: ClapPlugin> Wrapper<P> {
value: clap_plain_value, value: clap_plain_value,
}; };
(out.try_push)(out, &event.header) clap_call! { out=>try_push(out, &event.header) }
} }
OutputParamEvent::EndGesture { param_hash } => { OutputParamEvent::EndGesture { param_hash } => {
let event = clap_event_param_gesture { let event = clap_event_param_gesture {
@ -884,7 +888,7 @@ impl<P: ClapPlugin> Wrapper<P> {
param_id: param_hash, param_id: param_hash,
}; };
(out.try_push)(out, &event.header) clap_call! { out=>try_push(out, &event.header) }
} }
}; };
@ -925,7 +929,7 @@ impl<P: ClapPlugin> Wrapper<P> {
velocity: velocity as f64, velocity: velocity as f64,
}; };
(out.try_push)(out, &event.header) clap_call! { out=>try_push(out, &event.header) }
} }
NoteEvent::NoteOff { NoteEvent::NoteOff {
timing: _, timing: _,
@ -948,7 +952,7 @@ impl<P: ClapPlugin> Wrapper<P> {
velocity: velocity as f64, velocity: velocity as f64,
}; };
(out.try_push)(out, &event.header) clap_call! { out=>try_push(out, &event.header) }
} }
NoteEvent::PolyPressure { NoteEvent::PolyPressure {
timing: _, timing: _,
@ -972,7 +976,7 @@ impl<P: ClapPlugin> Wrapper<P> {
value: pressure as f64, value: pressure as f64,
}; };
(out.try_push)(out, &event.header) clap_call! { out=>try_push(out, &event.header) }
} }
NoteEvent::PolyVolume { NoteEvent::PolyVolume {
timing: _, timing: _,
@ -996,7 +1000,7 @@ impl<P: ClapPlugin> Wrapper<P> {
value: gain as f64, value: gain as f64,
}; };
(out.try_push)(out, &event.header) clap_call! { out=>try_push(out, &event.header) }
} }
NoteEvent::PolyPan { NoteEvent::PolyPan {
timing: _, timing: _,
@ -1020,7 +1024,7 @@ impl<P: ClapPlugin> Wrapper<P> {
value: (pan as f64 + 1.0) / 2.0, value: (pan as f64 + 1.0) / 2.0,
}; };
(out.try_push)(out, &event.header) clap_call! { out=>try_push(out, &event.header) }
} }
NoteEvent::PolyTuning { NoteEvent::PolyTuning {
timing: _, timing: _,
@ -1044,7 +1048,7 @@ impl<P: ClapPlugin> Wrapper<P> {
value: tuning as f64, value: tuning as f64,
}; };
(out.try_push)(out, &event.header) clap_call! { out=>try_push(out, &event.header) }
} }
NoteEvent::PolyVibrato { NoteEvent::PolyVibrato {
timing: _, timing: _,
@ -1068,7 +1072,7 @@ impl<P: ClapPlugin> Wrapper<P> {
value: vibrato as f64, value: vibrato as f64,
}; };
(out.try_push)(out, &event.header) clap_call! { out=>try_push(out, &event.header) }
} }
NoteEvent::PolyExpression { NoteEvent::PolyExpression {
timing: _, timing: _,
@ -1092,7 +1096,7 @@ impl<P: ClapPlugin> Wrapper<P> {
value: expression as f64, value: expression as f64,
}; };
(out.try_push)(out, &event.header) clap_call! { out=>try_push(out, &event.header) }
} }
NoteEvent::PolyBrightness { NoteEvent::PolyBrightness {
timing: _, timing: _,
@ -1116,7 +1120,7 @@ impl<P: ClapPlugin> Wrapper<P> {
value: brightness as f64, value: brightness as f64,
}; };
(out.try_push)(out, &event.header) clap_call! { out=>try_push(out, &event.header) }
} }
NoteEvent::MidiChannelPressure { NoteEvent::MidiChannelPressure {
timing: _, timing: _,
@ -1139,7 +1143,7 @@ impl<P: ClapPlugin> Wrapper<P> {
], ],
}; };
(out.try_push)(out, &event.header) clap_call! { out=>try_push(out, &event.header) }
} }
NoteEvent::MidiPitchBend { NoteEvent::MidiPitchBend {
timing: _, timing: _,
@ -1164,7 +1168,7 @@ impl<P: ClapPlugin> Wrapper<P> {
], ],
}; };
(out.try_push)(out, &event.header) clap_call! { out=>try_push(out, &event.header) }
} }
NoteEvent::MidiCC { NoteEvent::MidiCC {
timing: _, timing: _,
@ -1188,7 +1192,7 @@ impl<P: ClapPlugin> Wrapper<P> {
], ],
}; };
(out.try_push)(out, &event.header) clap_call! { out=>try_push(out, &event.header) }
} }
_ => { _ => {
nih_debug_assert_failure!( nih_debug_assert_failure!(
@ -2081,24 +2085,24 @@ impl<P: ClapPlugin> Wrapper<P> {
let id = CStr::from_ptr(id); let id = CStr::from_ptr(id);
if id == CStr::from_ptr(CLAP_EXT_AUDIO_PORTS_CONFIG) { if id == 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 == 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_GUI) && wrapper.editor.is_some() { } else if id == CLAP_EXT_GUI && wrapper.editor.is_some() {
// Only report that we support this extension if the plugin has an editor // Only report that we support this extension if the plugin has an editor
&wrapper.clap_plugin_gui as *const _ as *const c_void &wrapper.clap_plugin_gui as *const _ as *const c_void
} else if id == CStr::from_ptr(CLAP_EXT_LATENCY) { } else if id == CLAP_EXT_LATENCY {
&wrapper.clap_plugin_latency as *const _ as *const c_void &wrapper.clap_plugin_latency as *const _ as *const c_void
} else if id == CStr::from_ptr(CLAP_EXT_NOTE_PORTS) } else if id == CLAP_EXT_NOTE_PORTS
&& (P::MIDI_INPUT >= MidiConfig::Basic || P::MIDI_OUTPUT >= MidiConfig::Basic) && (P::MIDI_INPUT >= MidiConfig::Basic || P::MIDI_OUTPUT >= MidiConfig::Basic)
{ {
&wrapper.clap_plugin_note_ports as *const _ as *const c_void &wrapper.clap_plugin_note_ports as *const _ as *const c_void
} else if id == CStr::from_ptr(CLAP_EXT_PARAMS) { } else if id == 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 == CLAP_EXT_STATE {
&wrapper.clap_plugin_state as *const _ as *const c_void &wrapper.clap_plugin_state as *const _ as *const c_void
} else if id == CStr::from_ptr(CLAP_EXT_TAIL) { } else if id == CLAP_EXT_TAIL {
&wrapper.clap_plugin_tail as *const _ as *const c_void &wrapper.clap_plugin_tail as *const _ as *const c_void
} else { } else {
nih_trace!("Host tried to query unknown extension {:?}", id); nih_trace!("Host tried to query unknown extension {:?}", id);
@ -2154,13 +2158,13 @@ impl<P: ClapPlugin> Wrapper<P> {
} => format!("{num_input_channels} inputs, {num_output_channels} outputs"), } => format!("{num_input_channels} inputs, {num_output_channels} outputs"),
}; };
let input_port_type = match bus_config.num_input_channels { let input_port_type = match bus_config.num_input_channels {
1 => CLAP_PORT_MONO, 1 => CLAP_PORT_MONO.as_ptr(),
2 => CLAP_PORT_STEREO, 2 => CLAP_PORT_STEREO.as_ptr(),
_ => ptr::null(), _ => ptr::null(),
}; };
let output_port_type = match bus_config.num_output_channels { let output_port_type = match bus_config.num_output_channels {
1 => CLAP_PORT_MONO, 1 => CLAP_PORT_MONO.as_ptr(),
2 => CLAP_PORT_STEREO, 2 => CLAP_PORT_STEREO.as_ptr(),
_ => ptr::null(), _ => ptr::null(),
}; };
@ -2302,8 +2306,8 @@ impl<P: ClapPlugin> Wrapper<P> {
}; };
let port_type = match channel_count { let port_type = match channel_count {
1 => CLAP_PORT_MONO, 1 => CLAP_PORT_MONO.as_ptr(),
2 => CLAP_PORT_STEREO, 2 => CLAP_PORT_STEREO.as_ptr(),
_ => ptr::null(), _ => ptr::null(),
}; };
@ -2377,15 +2381,15 @@ impl<P: ClapPlugin> Wrapper<P> {
} }
#[cfg(all(target_family = "unix", not(target_os = "macos")))] #[cfg(all(target_family = "unix", not(target_os = "macos")))]
if CStr::from_ptr(api) == CStr::from_ptr(CLAP_WINDOW_API_X11) { if CStr::from_ptr(api) == CLAP_WINDOW_API_X11 {
return true; return true;
} }
#[cfg(target_os = "macos")] #[cfg(target_os = "macos")]
if CStr::from_ptr(api) == CStr::from_ptr(CLAP_WINDOW_API_COCOA) { if CStr::from_ptr(api) == CLAP_WINDOW_API_COCOA {
return true; return true;
} }
#[cfg(target_os = "windows")] #[cfg(target_os = "windows")]
if CStr::from_ptr(api) == CStr::from_ptr(CLAP_WINDOW_API_WIN32) { if CStr::from_ptr(api) == CLAP_WINDOW_API_WIN32 {
return true; return true;
} }
@ -2401,15 +2405,15 @@ impl<P: ClapPlugin> Wrapper<P> {
#[cfg(all(target_family = "unix", not(target_os = "macos")))] #[cfg(all(target_family = "unix", not(target_os = "macos")))]
{ {
*api = CLAP_WINDOW_API_X11; *api = CLAP_WINDOW_API_X11.as_ptr();
} }
#[cfg(target_os = "macos")] #[cfg(target_os = "macos")]
{ {
*api = CLAP_WINDOW_API_COCOA; *api = CLAP_WINDOW_API_COCOA.as_ptr();
} }
#[cfg(target_os = "windows")] #[cfg(target_os = "windows")]
{ {
*api = CLAP_WINDOW_API_WIN32; *api = CLAP_WINDOW_API_WIN32.as_ptr();
} }
// We don't do standalone floating windows yet // We don't do standalone floating windows yet
@ -2555,15 +2559,15 @@ impl<P: ClapPlugin> Wrapper<P> {
let mut editor_handle = wrapper.editor_handle.write(); let mut editor_handle = wrapper.editor_handle.write();
if editor_handle.is_none() { if editor_handle.is_none() {
let api = CStr::from_ptr(window.api); let api = CStr::from_ptr(window.api);
let handle = if api == CStr::from_ptr(CLAP_WINDOW_API_X11) { let handle = if api == CLAP_WINDOW_API_X11 {
let mut handle = raw_window_handle::XcbHandle::empty(); let mut handle = raw_window_handle::XcbHandle::empty();
handle.window = window.specific.x11 as u32; handle.window = window.specific.x11 as u32;
RawWindowHandle::Xcb(handle) RawWindowHandle::Xcb(handle)
} else if api == CStr::from_ptr(CLAP_WINDOW_API_COCOA) { } else if api == CLAP_WINDOW_API_COCOA {
let mut handle = raw_window_handle::AppKitHandle::empty(); let mut handle = raw_window_handle::AppKitHandle::empty();
handle.ns_view = window.specific.cocoa; handle.ns_view = window.specific.cocoa;
RawWindowHandle::AppKit(handle) RawWindowHandle::AppKit(handle)
} else if api == CStr::from_ptr(CLAP_WINDOW_API_WIN32) { } else if api == CLAP_WINDOW_API_WIN32 {
let mut handle = raw_window_handle::Win32Handle::empty(); let mut handle = raw_window_handle::Win32Handle::empty();
handle.hwnd = window.specific.win32; handle.hwnd = window.specific.win32;
RawWindowHandle::Win32(handle) RawWindowHandle::Win32(handle)
@ -2971,9 +2975,10 @@ impl<P: ClapPlugin> Wrapper<P> {
/// The extension type `T` must match the extension's name `name`. /// The extension type `T` must match the extension's name `name`.
unsafe fn query_host_extension<T>( unsafe fn query_host_extension<T>(
host_callback: &ClapPtr<clap_host>, host_callback: &ClapPtr<clap_host>,
name: *const c_char, name: &CStr,
) -> Option<ClapPtr<T>> { ) -> Option<ClapPtr<T>> {
let extension_ptr = (host_callback.get_extension)(&**host_callback, name); let extension_ptr =
clap_call! { host_callback=>get_extension(&**host_callback, name.as_ptr()) };
if !extension_ptr.is_null() { if !extension_ptr.is_null() {
Some(ClapPtr::new(extension_ptr as *const T)) Some(ClapPtr::new(extension_ptr as *const T))
} else { } else {

View file

@ -74,6 +74,7 @@ impl<P: Vst3Plugin> GuiContext for WrapperGuiContext<P> {
// FIXME: So this doesn't work for REAPER, because they just silently stop // FIXME: So this doesn't work for REAPER, because they just silently stop
// processing audio when you bypass the plugin. Great. We can add a time // processing audio when you bypass the plugin. Great. We can add a time
// based heuristic to work aorund this in the meantime. // based heuristic to work aorund this in the meantime.
concat!("asfd", "dsaf", stringify!(34));
if !self.inner.is_processing.load(Ordering::SeqCst) { if !self.inner.is_processing.load(Ordering::SeqCst) {
self.inner.set_normalized_value_by_hash( self.inner.set_normalized_value_by_hash(
*hash, *hash,