1
0
Fork 0

Update for CLAP 0.23

This commit is contained in:
Robbert van der Helm 2022-03-15 18:47:29 +01:00
parent 62a7994877
commit ccc8088218
3 changed files with 109 additions and 106 deletions

4
Cargo.lock generated
View file

@ -449,8 +449,8 @@ dependencies = [
[[package]]
name = "clap-sys"
version = "0.1.0"
source = "git+https://github.com/robbert-vdh/clap-sys?branch=update/clap-0.20#0c68b124fc9aa723b5c3aa61f132ddcc0d9f06ab"
version = "0.23.0"
source = "git+https://github.com/robbert-vdh/clap-sys?branch=update/clap-0.20#d15507000cb0ddd64606362fe1aec0e638e54748"
[[package]]
name = "clipboard-win"

View file

@ -3,12 +3,11 @@ use std::collections::VecDeque;
use std::sync::atomic::Ordering;
use std::sync::Arc;
use super::wrapper::{OutputParamChange, Task, Wrapper};
use super::wrapper::{OutputParamEvent, Task, Wrapper};
use crate::context::{GuiContext, ProcessContext, Transport};
use crate::event_loop::EventLoop;
use crate::param::internals::ParamPtr;
use crate::plugin::{ClapPlugin, NoteEvent};
use crate::wrapper::clap::wrapper::OutputParamChangeType;
/// A [`GuiContext`] implementation for the wrapper. This is passed to the plugin in
/// [`Editor::spawn()`][crate::prelude::Editor::spawn()] so it can interact with the rest of the plugin and
@ -32,17 +31,11 @@ impl<P: ClapPlugin> GuiContext for WrapperGuiContext<P> {
unsafe fn raw_begin_set_parameter(&self, param: ParamPtr) {
match self.wrapper.param_ptr_to_hash.get(&param) {
Some(hash) => {
// Apparently you're supposed to resend old values for the automation begin and end
// gestures
let clap_plain_value =
param.normalized_value() as f64 * param.step_count().unwrap_or(1) as f64;
let success = self.wrapper.queue_parameter_change(OutputParamChange {
param_hash: *hash,
clap_plain_value,
change_type: OutputParamChangeType::BeginGesture,
});
let success = self
.wrapper
.queue_parameter_event(OutputParamEvent::BeginGesture { param_hash: *hash });
nih_debug_assert!(success, "Parameter output queue was full, parameter change will not be sent to the host");
nih_debug_assert!(success, "Parameter output event queue was full, parameter change will not be sent to the host");
}
None => nih_debug_assert_failure!("Unknown parameter: {:?}", param),
}
@ -57,13 +50,14 @@ impl<P: ClapPlugin> GuiContext for WrapperGuiContext<P> {
// be changed when the output event is written to prevent changing parameter values
// in the middle of processing audio.
let clap_plain_value = normalized as f64 * param.step_count().unwrap_or(1) as f64;
let success = self.wrapper.queue_parameter_change(OutputParamChange {
param_hash: *hash,
clap_plain_value,
change_type: OutputParamChangeType::Normal,
});
let success = self
.wrapper
.queue_parameter_event(OutputParamEvent::SetValue {
param_hash: *hash,
clap_plain_value,
});
nih_debug_assert!(success, "Parameter output queue was full, parameter change will not be sent to the host");
nih_debug_assert!(success, "Parameter output event queue was full, parameter change will not be sent to the host");
}
None => nih_debug_assert_failure!("Unknown parameter: {:?}", param),
}
@ -72,21 +66,11 @@ impl<P: ClapPlugin> GuiContext for WrapperGuiContext<P> {
unsafe fn raw_end_set_parameter(&self, param: ParamPtr) {
match self.wrapper.param_ptr_to_hash.get(&param) {
Some(hash) => {
// Apparently you're supposed to resend old values for the automation begin and end
// gestures
// FIXME: This will result in a race condition if the parameter is modified in the
// same cycle! (same for the gesture begin, but it's less likely to cause
// problems there) This will be fixed in a next version of CLAP by splitting
// the gestures up into their own events so it's not a huge deal right now.
let clap_plain_value =
param.normalized_value() as f64 * param.step_count().unwrap_or(1) as f64;
let success = self.wrapper.queue_parameter_change(OutputParamChange {
param_hash: *hash,
clap_plain_value,
change_type: OutputParamChangeType::EndGesture,
});
let success = self
.wrapper
.queue_parameter_event(OutputParamEvent::EndGesture { param_hash: *hash });
nih_debug_assert!(success, "Parameter output queue was full, parameter change will not be sent to the host");
nih_debug_assert!(success, "Parameter output event queue was full, parameter change will not be sent to the host");
}
None => nih_debug_assert_failure!("Unknown parameter: {:?}", param),
}

View file

@ -5,11 +5,11 @@
use atomic_float::AtomicF32;
use atomic_refcell::{AtomicRefCell, AtomicRefMut};
use clap_sys::events::{
clap_event_header, clap_event_note, clap_event_param_mod, clap_event_param_value,
clap_input_events, clap_output_events, CLAP_CORE_EVENT_SPACE_ID, CLAP_EVENT_BEGIN_ADJUST,
CLAP_EVENT_END_ADJUST, CLAP_EVENT_IS_LIVE, CLAP_EVENT_MIDI, CLAP_EVENT_NOTE_EXPRESSION,
CLAP_EVENT_NOTE_OFF, CLAP_EVENT_NOTE_ON, CLAP_EVENT_PARAM_MOD, CLAP_EVENT_PARAM_VALUE,
CLAP_EVENT_SHOULD_RECORD, CLAP_TRANSPORT_HAS_BEATS_TIMELINE,
clap_event_header, clap_event_note, clap_event_param_gesture, clap_event_param_mod,
clap_event_param_value, clap_input_events, clap_output_events, CLAP_CORE_EVENT_SPACE_ID,
CLAP_EVENT_IS_LIVE, CLAP_EVENT_MIDI, CLAP_EVENT_NOTE_EXPRESSION, CLAP_EVENT_NOTE_OFF,
CLAP_EVENT_NOTE_ON, CLAP_EVENT_PARAM_GESTURE_BEGIN, CLAP_EVENT_PARAM_GESTURE_END,
CLAP_EVENT_PARAM_MOD, CLAP_EVENT_PARAM_VALUE, CLAP_TRANSPORT_HAS_BEATS_TIMELINE,
CLAP_TRANSPORT_HAS_SECONDS_TIMELINE, CLAP_TRANSPORT_HAS_TEMPO,
CLAP_TRANSPORT_HAS_TIME_SIGNATURE, CLAP_TRANSPORT_IS_LOOP_ACTIVE, CLAP_TRANSPORT_IS_PLAYING,
CLAP_TRANSPORT_IS_RECORDING, CLAP_TRANSPORT_IS_WITHIN_PRE_ROLL,
@ -176,13 +176,13 @@ pub struct Wrapper<P: ClapPlugin> {
/// having to add a setter function to the parameter (or even worse, have it be completely
/// untyped).
pub param_ptr_to_hash: HashMap<ParamPtr, u32>,
/// A queue of parameter changes that should be output in either the next process call or in the
/// next parameter flush.
/// A queue of parameter changes and gestures that should be output in either the next process
/// call or in the next parameter flush.
///
/// XXX: There's no guarentee that a single parmaeter doesn't occur twice in this queue, but
/// even if it does then that should still not be a problem because the host also reads it
/// in the same order, right?
output_parameter_changes: ArrayQueue<OutputParamChange>,
output_parameter_events: ArrayQueue<OutputParamEvent>,
host_thread_check: AtomicRefCell<Option<ClapPtr<clap_host_thread_check>>>,
@ -219,27 +219,23 @@ pub enum ClapParamUpdate {
PlainValueMod(f64),
}
/// A parameter change that should be output by the plugin, stored in a queue on the wrapper and
/// A parameter event that should be output by the plugin, stored in a queue on the wrapper and
/// written to the host either at the end of the process function or during a flush.
pub struct OutputParamChange {
/// The internal hash for the parameter.
pub param_hash: u32,
/// The 'plain' value as reported to CLAP. This is the normalized value multiplied by
/// [`Param::step_size()`][crate::Param::step_size()].
pub clap_plain_value: f64,
/// The kind of parameter change event, since CLAP wants you to resend an old value to handle
/// automation start and end gestures.
pub change_type: OutputParamChangeType,
}
/// The type of an [`OutputParamChange`].
pub enum OutputParamChangeType {
/// A regular parameter change, sending a new value for a parameter.
Normal,
/// Tell the host that the automation gesture begins. The event may resend an old value.
BeginGesture,
/// Tell the host that the automation gesture has ended. This event may resend an old value.
EndGesture,
pub enum OutputParamEvent {
/// Begin an automation gesture. This must always be sent before sending [`SetValue`].
BeginGesture { param_hash: u32 },
/// Change the value of a parmaeter using a plain CLAP value, aka the normalized value
/// multiplied by the number of steps.
SetValue {
/// The internal hash for the parameter.
param_hash: u32,
/// The 'plain' value as reported to CLAP. This is the normalized value multiplied by
/// [`Param::step_size()`][crate::Param::step_size()].
clap_plain_value: f64,
},
/// Begin an automation gesture. This must always be sent after sending one or more [`SetValue`]
/// events.
EndGesture { param_hash: u32 },
}
/// Because CLAP has this [`clap_host::request_host_callback()`] function, we don't need to use
@ -402,7 +398,7 @@ impl<P: ClapPlugin> Wrapper<P> {
param_defaults_normalized: HashMap::new(),
param_id_to_hash: HashMap::new(),
param_ptr_to_hash: HashMap::new(),
output_parameter_changes: ArrayQueue::new(OUTPUT_EVENT_QUEUE_CAPACITY),
output_parameter_events: ArrayQueue::new(OUTPUT_EVENT_QUEUE_CAPACITY),
host_thread_check: AtomicRefCell::new(None),
@ -503,15 +499,15 @@ impl<P: ClapPlugin> Wrapper<P> {
}
}
/// Queue a parmeter change to be sent to the host at the end of the audio processing cycle, and
/// request a parameter flush from the host if the plugin is not currently processing audio. The
/// parameter's actual value will only be updated at that point so the value won't change in the
/// middle of a processing call.
/// Queue a parmeter output event to be sent to the host at the end of the audio processing
/// cycle, and request a parameter flush from the host if the plugin is not currently processing
/// audio. The parameter's actual value will only be updated at that point so the value won't
/// change in the middle of a processing call.
///
/// Returns `false` if the parameter value queue was full and the update will not be sent to the
/// host (it will still be set on the plugin either way).
pub fn queue_parameter_change(&self, change: OutputParamChange) -> bool {
let result = self.output_parameter_changes.push(change).is_ok();
pub fn queue_parameter_event(&self, event: OutputParamEvent) -> bool {
let result = self.output_parameter_events.push(event).is_ok();
match &*self.host_params.borrow() {
Some(host_params) if !self.is_processing.load(Ordering::SeqCst) => {
unsafe { (host_params.request_flush)(&*self.host_callback) };
@ -678,44 +674,67 @@ impl<P: ClapPlugin> Wrapper<P> {
// shouldn't have to think about interleaving events here
let sample_rate = self.current_buffer_config.load().map(|c| c.sample_rate);
let mut parameter_values_changed = false;
while let Some(change) = self.output_parameter_changes.pop() {
self.update_plain_value_by_hash(
change.param_hash,
ClapParamUpdate::PlainValueSet(change.clap_plain_value),
sample_rate,
);
parameter_values_changed = true;
while let Some(change) = self.output_parameter_events.pop() {
let push_succesful = match change {
OutputParamEvent::BeginGesture { param_hash } => {
let event = clap_event_param_gesture {
header: clap_event_header {
size: mem::size_of::<clap_event_param_gesture>() as u32,
time: current_sample_idx as u32,
space_id: CLAP_CORE_EVENT_SPACE_ID,
type_: CLAP_EVENT_PARAM_GESTURE_BEGIN,
flags: CLAP_EVENT_IS_LIVE,
},
param_id: param_hash,
};
let event = clap_event_param_value {
header: clap_event_header {
size: mem::size_of::<clap_event_param_value>() as u32,
time: current_sample_idx as u32,
space_id: CLAP_CORE_EVENT_SPACE_ID,
type_: CLAP_EVENT_PARAM_VALUE,
flags: match change.change_type {
OutputParamChangeType::Normal => {
CLAP_EVENT_IS_LIVE | CLAP_EVENT_SHOULD_RECORD
}
// XXX: Apparently you should have `CLAP_EVENT_SHOULD_RECORD` here, even if
// we're repeating old values. This parameter gesture handling in CLAP
// is currently a bit weird and error prone.
OutputParamChangeType::BeginGesture => {
CLAP_EVENT_IS_LIVE | CLAP_EVENT_SHOULD_RECORD | CLAP_EVENT_BEGIN_ADJUST
}
OutputParamChangeType::EndGesture => {
CLAP_EVENT_IS_LIVE | CLAP_EVENT_SHOULD_RECORD | CLAP_EVENT_END_ADJUST
}
},
},
param_id: change.param_hash,
cookie: ptr::null_mut(),
port_index: -1,
key: -1,
channel: -1,
value: change.clap_plain_value,
(out.try_push)(out, &event.header)
}
OutputParamEvent::SetValue {
param_hash,
clap_plain_value,
} => {
self.update_plain_value_by_hash(
param_hash,
ClapParamUpdate::PlainValueSet(clap_plain_value),
sample_rate,
);
parameter_values_changed = true;
let event = clap_event_param_value {
header: clap_event_header {
size: mem::size_of::<clap_event_param_value>() as u32,
time: current_sample_idx as u32,
space_id: CLAP_CORE_EVENT_SPACE_ID,
type_: CLAP_EVENT_PARAM_VALUE,
flags: CLAP_EVENT_IS_LIVE,
},
param_id: param_hash,
cookie: ptr::null_mut(),
port_index: -1,
key: -1,
channel: -1,
value: clap_plain_value,
};
(out.try_push)(out, &event.header)
}
OutputParamEvent::EndGesture { param_hash } => {
let event = clap_event_param_gesture {
header: clap_event_header {
size: mem::size_of::<clap_event_param_gesture>() as u32,
time: current_sample_idx as u32,
space_id: CLAP_CORE_EVENT_SPACE_ID,
type_: CLAP_EVENT_PARAM_GESTURE_END,
flags: CLAP_EVENT_IS_LIVE,
},
param_id: param_hash,
};
(out.try_push)(out, &event.header)
}
};
let push_succesful = (out.try_push)(out, &event.header);
nih_debug_assert!(push_succesful);
}
@ -1767,7 +1786,7 @@ impl<P: ClapPlugin> Wrapper<P> {
unsafe extern "C" fn ext_state_save(
plugin: *const clap_plugin,
stream: *mut clap_ostream,
stream: *const clap_ostream,
) -> bool {
check_null_ptr!(false, plugin, stream);
let wrapper = &*(plugin as *const Self);
@ -1808,7 +1827,7 @@ impl<P: ClapPlugin> Wrapper<P> {
unsafe extern "C" fn ext_state_load(
plugin: *const clap_plugin,
stream: *mut clap_istream,
stream: *const clap_istream,
) -> bool {
check_null_ptr!(false, plugin, stream);
let wrapper = &*(plugin as *const Self);