Read updated parmater values from the process data
This commit is contained in:
parent
59b1132d3b
commit
f5f143b4f0
|
@ -26,11 +26,13 @@ use std::ffi::c_void;
|
||||||
use std::marker::PhantomData;
|
use std::marker::PhantomData;
|
||||||
use std::mem;
|
use std::mem;
|
||||||
use std::ptr;
|
use std::ptr;
|
||||||
use vst3_com::base::kResultTrue;
|
use std::sync::atomic::{AtomicBool, Ordering};
|
||||||
use vst3_sys::base::{kInvalidArgument, kNoInterface, kResultFalse, kResultOk, tresult, TBool};
|
use vst3_sys::base::{kInvalidArgument, kNoInterface, kResultFalse, kResultOk, tresult, TBool};
|
||||||
use vst3_sys::base::{IPluginBase, IPluginFactory, IPluginFactory2, IPluginFactory3};
|
use vst3_sys::base::{IPluginBase, IPluginFactory, IPluginFactory2, IPluginFactory3};
|
||||||
use vst3_sys::vst::TChar;
|
use vst3_sys::vst::TChar;
|
||||||
use vst3_sys::vst::{IAudioProcessor, IComponent, IEditController};
|
use vst3_sys::vst::{
|
||||||
|
IAudioProcessor, IComponent, IEditController, IParamValueQueue, IParameterChanges,
|
||||||
|
};
|
||||||
use vst3_sys::VST3;
|
use vst3_sys::VST3;
|
||||||
use widestring::U16CStr;
|
use widestring::U16CStr;
|
||||||
|
|
||||||
|
@ -80,6 +82,7 @@ pub struct Wrapper<'a, P: Plugin> {
|
||||||
bypass_state: Cell<bool>,
|
bypass_state: Cell<bool>,
|
||||||
/// The last process status returned by the plugin. This is used for tail handling.
|
/// The last process status returned by the plugin. This is used for tail handling.
|
||||||
last_process_status: Cell<ProcessStatus>,
|
last_process_status: Cell<ProcessStatus>,
|
||||||
|
is_processing: AtomicBool,
|
||||||
|
|
||||||
/// Contains slices for the plugin's outputs. You can't directly create a nested slice form
|
/// Contains slices for the plugin's outputs. You can't directly create a nested slice form
|
||||||
/// apointer to pointers, so this needs to be preallocated in the setup call and kept around
|
/// apointer to pointers, so this needs to be preallocated in the setup call and kept around
|
||||||
|
@ -89,9 +92,6 @@ pub struct Wrapper<'a, P: Plugin> {
|
||||||
/// A mapping from parameter ID hashes (obtained from the string parameter IDs) to pointers to
|
/// A mapping from parameter ID hashes (obtained from the string parameter IDs) to pointers to
|
||||||
/// parameters belonging to the plugin. As long as `plugin` does not get recreated, these
|
/// parameters belonging to the plugin. As long as `plugin` does not get recreated, these
|
||||||
/// addresses will remain stable, as they are obtained from a pinned object.
|
/// addresses will remain stable, as they are obtained from a pinned object.
|
||||||
///
|
|
||||||
/// TODO: Wrap this in a mutex in case the host tries setting parameters from multiple threads
|
|
||||||
/// at the same time.
|
|
||||||
param_by_hash: HashMap<u32, ParamPtr>,
|
param_by_hash: HashMap<u32, ParamPtr>,
|
||||||
/// The keys from `param_map` in a stable order.
|
/// The keys from `param_map` in a stable order.
|
||||||
param_hashes: Vec<u32>,
|
param_hashes: Vec<u32>,
|
||||||
|
@ -112,6 +112,7 @@ impl<P: Plugin> Wrapper<'_, P> {
|
||||||
RefCell::new(P::default()), // plugin
|
RefCell::new(P::default()), // plugin
|
||||||
Cell::new(false), // bypass_state
|
Cell::new(false), // bypass_state
|
||||||
Cell::new(ProcessStatus::Normal), // last_process_status
|
Cell::new(ProcessStatus::Normal), // last_process_status
|
||||||
|
AtomicBool::new(false), // is_processing
|
||||||
RefCell::new(Vec::new()), // output_slices
|
RefCell::new(Vec::new()), // output_slices
|
||||||
HashMap::new(), // param_by_hash
|
HashMap::new(), // param_by_hash
|
||||||
Vec::new(), // param_hashes
|
Vec::new(), // param_hashes
|
||||||
|
@ -153,6 +154,20 @@ impl<P: Plugin> Wrapper<'_, P> {
|
||||||
|
|
||||||
wrapper
|
wrapper
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unsafe fn set_normalized_value_by_hash(&self, hash: u32, normalized_value: f64) -> tresult {
|
||||||
|
if hash == *BYPASS_PARAM_HASH {
|
||||||
|
self.bypass_state.set(normalized_value >= 0.5);
|
||||||
|
|
||||||
|
kResultOk
|
||||||
|
} else if let Some(param_ptr) = self.param_by_hash.get(&hash) {
|
||||||
|
param_ptr.set_normalized_value(normalized_value as f32);
|
||||||
|
|
||||||
|
kResultOk
|
||||||
|
} else {
|
||||||
|
kInvalidArgument
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<P: Plugin> IPluginBase for Wrapper<'_, P> {
|
impl<P: Plugin> IPluginBase for Wrapper<'_, P> {
|
||||||
|
@ -453,17 +468,13 @@ impl<P: Plugin> IEditController for Wrapper<'_, P> {
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe fn set_param_normalized(&self, id: u32, value: f64) -> tresult {
|
unsafe fn set_param_normalized(&self, id: u32, value: f64) -> tresult {
|
||||||
if id == *BYPASS_PARAM_HASH {
|
// If the plugin is currently processing audio, then this parameter change will also be sent
|
||||||
self.bypass_state.set(value >= 0.5);
|
// to the process function
|
||||||
|
if self.is_processing.load(Ordering::SeqCst) {
|
||||||
kResultOk
|
return kResultOk;
|
||||||
} else if let Some(param_ptr) = self.param_by_hash.get(&id) {
|
|
||||||
param_ptr.set_normalized_value(value as f32);
|
|
||||||
|
|
||||||
kResultOk
|
|
||||||
} else {
|
|
||||||
kInvalidArgument
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
self.set_normalized_value_by_hash(id, value)
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe fn set_component_handler(&self, _handler: *mut c_void) -> tresult {
|
unsafe fn set_component_handler(&self, _handler: *mut c_void) -> tresult {
|
||||||
|
@ -590,12 +601,13 @@ impl<P: Plugin> IAudioProcessor for Wrapper<'_, P> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe fn set_processing(&self, _state: TBool) -> tresult {
|
unsafe fn set_processing(&self, state: TBool) -> tresult {
|
||||||
// Always reset the processing status when the plugin gets activated or deactivated
|
// Always reset the processing status when the plugin gets activated or deactivated
|
||||||
self.last_process_status.set(ProcessStatus::Normal);
|
self.last_process_status.set(ProcessStatus::Normal);
|
||||||
|
self.is_processing.store(state != 0, Ordering::SeqCst);
|
||||||
|
|
||||||
// We don't have any special handling for suspending and resuming plugins, yet
|
// We don't have any special handling for suspending and resuming plugins, yet
|
||||||
kResultTrue
|
kResultOk
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe fn process(&self, data: *mut vst3_sys::vst::ProcessData) -> tresult {
|
unsafe fn process(&self, data: *mut vst3_sys::vst::ProcessData) -> tresult {
|
||||||
|
@ -664,7 +676,32 @@ impl<P: Plugin> IAudioProcessor for Wrapper<'_, P> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Handle incoming parameter changes
|
if let Some(param_changes) = data.input_param_changes.upgrade() {
|
||||||
|
let num_param_queues = param_changes.get_parameter_count();
|
||||||
|
for change_queue_idx in 0..num_param_queues {
|
||||||
|
if let Some(param_change_queue) =
|
||||||
|
param_changes.get_parameter_data(change_queue_idx).upgrade()
|
||||||
|
{
|
||||||
|
let param_hash = param_change_queue.get_parameter_id();
|
||||||
|
let num_changes = param_change_queue.get_point_count();
|
||||||
|
|
||||||
|
// TODO: Handle sample accurate parameter changes, possibly in a similar way to
|
||||||
|
// the smoothing
|
||||||
|
let mut sample_offset = 0i32;
|
||||||
|
let mut value = 0.0f64;
|
||||||
|
if num_changes > 0
|
||||||
|
&& param_change_queue.get_point(
|
||||||
|
num_changes - 1,
|
||||||
|
&mut sample_offset,
|
||||||
|
&mut value,
|
||||||
|
) == kResultOk
|
||||||
|
{
|
||||||
|
self.set_normalized_value_by_hash(param_hash, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
match self.plugin.borrow_mut().process(&mut output_slices) {
|
match self.plugin.borrow_mut().process(&mut output_slices) {
|
||||||
ProcessStatus::Error(err) => {
|
ProcessStatus::Error(err) => {
|
||||||
nih_debug_assert_failure!("Process error: {}", err);
|
nih_debug_assert_failure!("Process error: {}", err);
|
||||||
|
|
Loading…
Reference in a new issue