2022-03-04 07:18:57 +11:00
|
|
|
use atomic_refcell::AtomicRefMut;
|
2022-03-01 05:45:41 +11:00
|
|
|
use std::collections::VecDeque;
|
|
|
|
use std::sync::atomic::Ordering;
|
2022-03-04 03:47:41 +11:00
|
|
|
use std::sync::Arc;
|
2022-03-01 05:45:41 +11:00
|
|
|
|
2022-03-16 04:47:29 +11:00
|
|
|
use super::wrapper::{OutputParamEvent, Task, Wrapper};
|
2022-03-05 01:05:00 +11:00
|
|
|
use crate::context::{GuiContext, ProcessContext, Transport};
|
2022-03-01 05:45:41 +11:00
|
|
|
use crate::event_loop::EventLoop;
|
2022-04-08 07:28:31 +10:00
|
|
|
use crate::midi::NoteEvent;
|
2022-03-04 03:47:41 +11:00
|
|
|
use crate::param::internals::ParamPtr;
|
2022-04-08 07:28:31 +10:00
|
|
|
use crate::plugin::ClapPlugin;
|
2022-03-04 03:47:41 +11:00
|
|
|
|
2022-03-04 09:05:01 +11:00
|
|
|
/// A [`GuiContext`] implementation for the wrapper. This is passed to the plugin in
|
2022-03-04 09:30:29 +11:00
|
|
|
/// [`Editor::spawn()`][crate::prelude::Editor::spawn()] so it can interact with the rest of the plugin and
|
2022-03-04 09:05:01 +11:00
|
|
|
/// with the host for things like setting parameters.
|
2022-03-04 03:47:41 +11:00
|
|
|
pub(crate) struct WrapperGuiContext<P: ClapPlugin> {
|
|
|
|
pub(super) wrapper: Arc<Wrapper<P>>,
|
|
|
|
}
|
2022-03-01 05:45:41 +11:00
|
|
|
|
2022-03-04 09:05:01 +11:00
|
|
|
/// A [`ProcessContext`] implementation for the wrapper. This is a separate object so it can hold on
|
2022-03-01 05:45:41 +11:00
|
|
|
/// to lock guards for event queues. Otherwise reading these events would require constant
|
|
|
|
/// unnecessary atomic operations to lock the uncontested RwLocks.
|
|
|
|
pub(crate) struct WrapperProcessContext<'a, P: ClapPlugin> {
|
2022-03-04 03:47:41 +11:00
|
|
|
pub(super) wrapper: &'a Wrapper<P>,
|
2022-03-04 07:18:57 +11:00
|
|
|
pub(super) input_events_guard: AtomicRefMut<'a, VecDeque<NoteEvent>>,
|
2022-04-12 03:52:51 +10:00
|
|
|
pub(super) output_events_guard: AtomicRefMut<'a, VecDeque<NoteEvent>>,
|
2022-03-05 01:05:00 +11:00
|
|
|
pub(super) transport: Transport,
|
2022-03-01 05:45:41 +11:00
|
|
|
}
|
|
|
|
|
2022-03-04 03:47:41 +11:00
|
|
|
impl<P: ClapPlugin> GuiContext for WrapperGuiContext<P> {
|
2022-03-28 04:23:34 +11:00
|
|
|
fn request_resize(&self) -> bool {
|
2022-04-06 00:32:00 +10:00
|
|
|
self.wrapper.request_resize()
|
2022-03-28 04:23:34 +11:00
|
|
|
}
|
|
|
|
|
2022-03-04 03:47:41 +11:00
|
|
|
// All of these functions are supposed to be called from the main thread, so we'll put some
|
|
|
|
// trust in the caller and assume that this is indeed the case
|
2022-03-11 10:14:39 +11:00
|
|
|
unsafe fn raw_begin_set_parameter(&self, param: ParamPtr) {
|
|
|
|
match self.wrapper.param_ptr_to_hash.get(¶m) {
|
|
|
|
Some(hash) => {
|
2022-03-16 04:47:29 +11:00
|
|
|
let success = self
|
|
|
|
.wrapper
|
|
|
|
.queue_parameter_event(OutputParamEvent::BeginGesture { param_hash: *hash });
|
2022-03-11 10:14:39 +11:00
|
|
|
|
2022-03-16 04:47:29 +11:00
|
|
|
nih_debug_assert!(success, "Parameter output event queue was full, parameter change will not be sent to the host");
|
2022-03-11 10:14:39 +11:00
|
|
|
}
|
|
|
|
None => nih_debug_assert_failure!("Unknown parameter: {:?}", param),
|
|
|
|
}
|
2022-03-04 03:47:41 +11:00
|
|
|
}
|
|
|
|
|
|
|
|
unsafe fn raw_set_parameter_normalized(&self, param: ParamPtr, normalized: f32) {
|
|
|
|
match self.wrapper.param_ptr_to_hash.get(¶m) {
|
|
|
|
Some(hash) => {
|
|
|
|
// We queue the parameter change event here, and it will be sent to the host either
|
|
|
|
// at the end of the current processing cycle or after requesting an explicit flush
|
|
|
|
// (when the plugin isn't processing audio). The parameter's actual value will only
|
|
|
|
// 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;
|
2022-03-16 04:47:29 +11:00
|
|
|
let success = self
|
|
|
|
.wrapper
|
|
|
|
.queue_parameter_event(OutputParamEvent::SetValue {
|
|
|
|
param_hash: *hash,
|
|
|
|
clap_plain_value,
|
|
|
|
});
|
2022-03-04 03:47:41 +11:00
|
|
|
|
2022-03-16 04:47:29 +11:00
|
|
|
nih_debug_assert!(success, "Parameter output event queue was full, parameter change will not be sent to the host");
|
2022-03-04 03:47:41 +11:00
|
|
|
}
|
|
|
|
None => nih_debug_assert_failure!("Unknown parameter: {:?}", param),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-03-11 10:14:39 +11:00
|
|
|
unsafe fn raw_end_set_parameter(&self, param: ParamPtr) {
|
|
|
|
match self.wrapper.param_ptr_to_hash.get(¶m) {
|
|
|
|
Some(hash) => {
|
2022-03-16 04:47:29 +11:00
|
|
|
let success = self
|
|
|
|
.wrapper
|
|
|
|
.queue_parameter_event(OutputParamEvent::EndGesture { param_hash: *hash });
|
2022-03-11 10:14:39 +11:00
|
|
|
|
2022-03-16 04:47:29 +11:00
|
|
|
nih_debug_assert!(success, "Parameter output event queue was full, parameter change will not be sent to the host");
|
2022-03-11 10:14:39 +11:00
|
|
|
}
|
|
|
|
None => nih_debug_assert_failure!("Unknown parameter: {:?}", param),
|
|
|
|
}
|
2022-03-04 03:47:41 +11:00
|
|
|
}
|
2022-04-08 01:12:08 +10:00
|
|
|
|
2022-04-08 01:39:34 +10:00
|
|
|
fn get_state(&self) -> crate::wrapper::state::PluginState {
|
2022-04-08 01:12:08 +10:00
|
|
|
self.wrapper.get_state_object()
|
|
|
|
}
|
|
|
|
|
2022-04-08 01:39:34 +10:00
|
|
|
fn set_state(&self, state: crate::wrapper::state::PluginState) {
|
2022-04-08 01:12:08 +10:00
|
|
|
self.wrapper.set_state_object(state)
|
|
|
|
}
|
2022-03-04 03:47:41 +11:00
|
|
|
}
|
|
|
|
|
2022-03-01 05:45:41 +11:00
|
|
|
impl<P: ClapPlugin> ProcessContext for WrapperProcessContext<'_, P> {
|
2022-03-05 01:05:00 +11:00
|
|
|
fn transport(&self) -> &Transport {
|
|
|
|
&self.transport
|
|
|
|
}
|
|
|
|
|
2022-04-12 02:14:25 +10:00
|
|
|
fn next_event(&mut self) -> Option<NoteEvent> {
|
2022-03-04 23:22:58 +11:00
|
|
|
self.input_events_guard.pop_front()
|
|
|
|
}
|
|
|
|
|
2022-04-12 03:52:51 +10:00
|
|
|
fn send_event(&mut self, event: NoteEvent) {
|
|
|
|
self.output_events_guard.push_back(event);
|
|
|
|
}
|
|
|
|
|
2022-03-01 05:45:41 +11:00
|
|
|
fn set_latency_samples(&self, samples: u32) {
|
|
|
|
// Only make a callback if it's actually needed
|
|
|
|
// XXX: For CLAP we could move this handling to the Plugin struct, but it may be worthwhile
|
|
|
|
// to keep doing it this way to stay consistent with VST3.
|
2022-03-04 03:47:41 +11:00
|
|
|
let old_latency = self.wrapper.current_latency.swap(samples, Ordering::SeqCst);
|
2022-03-01 05:45:41 +11:00
|
|
|
if old_latency != samples {
|
2022-03-04 03:47:41 +11:00
|
|
|
let task_posted = self.wrapper.do_maybe_async(Task::LatencyChanged);
|
2022-03-01 05:45:41 +11:00
|
|
|
nih_debug_assert!(task_posted, "The task queue is full, dropping task...");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|