diff --git a/src/format/clap/gui.rs b/src/format/clap/gui.rs index 3d9df10..28dbbc7 100644 --- a/src/format/clap/gui.rs +++ b/src/format/clap/gui.rs @@ -1,20 +1,48 @@ +use std::collections::HashMap; use std::ffi::{c_char, CStr}; use std::rc::Rc; +use std::sync::Arc; -use clap_sys::ext::gui::*; -use clap_sys::plugin::*; +use clap_sys::ext::{gui::*, params::*}; +use clap_sys::{host::*, plugin::*}; use super::instance::Instance; use crate::editor::{Editor, EditorHost, EditorHostInner, ParentWindow, RawParent}; use crate::params::{ParamId, ParamValue}; use crate::plugin::Plugin; +use crate::sync::param_gestures::ParamGestures; -struct ClapEditorHost {} +struct ClapEditorHost { + host: *const clap_host, + host_params: Option<*const clap_host_params>, + param_map: Arc>, + param_gestures: Arc, +} impl EditorHostInner for ClapEditorHost { - fn begin_gesture(&self, _id: ParamId) {} - fn end_gesture(&self, _id: ParamId) {} - fn set_param(&self, _id: ParamId, _value: ParamValue) {} + fn begin_gesture(&self, id: ParamId) { + self.param_gestures.begin_gesture(self.param_map[&id]); + + if let Some(host_params) = self.host_params { + unsafe { (*host_params).request_flush.unwrap()(self.host) }; + } + } + + fn end_gesture(&self, id: ParamId) { + self.param_gestures.end_gesture(self.param_map[&id]); + + if let Some(host_params) = self.host_params { + unsafe { (*host_params).request_flush.unwrap()(self.host) }; + } + } + + fn set_param(&self, id: ParamId, value: ParamValue) { + self.param_gestures.set_value(self.param_map[&id], value); + + if let Some(host_params) = self.host_params { + unsafe { (*host_params).request_flush.unwrap()(self.host) }; + } + } } impl Instance

{ @@ -161,7 +189,12 @@ impl Instance

{ let instance = &*(plugin as *const Self); let main_thread_state = &mut *instance.main_thread_state.get(); - let host = EditorHost::from_inner(Rc::new(ClapEditorHost {})); + let host = EditorHost::from_inner(Rc::new(ClapEditorHost { + host: instance.host, + host_params: main_thread_state.host_params, + param_map: Arc::clone(&instance.param_map), + param_gestures: Arc::clone(&instance.param_gestures), + })); let parent = ParentWindow::from_raw(raw_parent); let editor = main_thread_state.plugin.editor(host, &parent); main_thread_state.editor = Some(editor); diff --git a/src/format/clap/instance.rs b/src/format/clap/instance.rs index 82efb64..dbe88a1 100644 --- a/src/format/clap/instance.rs +++ b/src/format/clap/instance.rs @@ -4,7 +4,7 @@ use std::ffi::{c_char, c_void, CStr}; use std::iter::zip; use std::ptr::NonNull; use std::sync::Arc; -use std::{io, ptr, slice}; +use std::{io, mem, ptr, slice}; use clap_sys::ext::{audio_ports::*, audio_ports_config::*, gui::*, params::*, state::*}; use clap_sys::{events::*, host::*, id::*, plugin::*, process::*, stream::*}; @@ -18,6 +18,7 @@ use crate::host::Host; use crate::params::{ParamId, ParamInfo, ParamValue}; use crate::plugin::{Plugin, PluginInfo}; use crate::process::{Config, Processor}; +use crate::sync::param_gestures::{GestureStates, GestureUpdate, ParamGestures}; use crate::sync::params::ParamValues; use crate::util::{copy_cstring, slice_from_raw_parts_checked, DisplayParam}; @@ -45,12 +46,14 @@ fn map_param_out(param: &ParamInfo, value: ParamValue) -> f64 { } pub struct MainThreadState { + pub host_params: Option<*const clap_host_params>, pub layout_index: usize, pub plugin: P, pub editor: Option, } pub struct ProcessState { + gesture_states: GestureStates, buffer_data: Vec, buffer_ptrs: Vec<*mut f32>, events: Vec, @@ -65,11 +68,12 @@ pub struct Instance { pub info: Arc, pub input_bus_map: Vec, pub output_bus_map: Vec, - pub param_map: HashMap, + pub param_map: Arc>, // Processor -> plugin parameter changes pub plugin_params: ParamValues, // Plugin -> processor parameter changes pub processor_params: ParamValues, + pub param_gestures: Arc, pub main_thread_state: UnsafeCell>, pub process_state: UnsafeCell>, } @@ -119,15 +123,18 @@ impl Instance

{ info: info.clone(), input_bus_map, output_bus_map, - param_map, + param_map: Arc::new(param_map), plugin_params: ParamValues::with_count(info.params.len()), processor_params: ParamValues::with_count(info.params.len()), + param_gestures: Arc::new(ParamGestures::with_count(info.params.len())), main_thread_state: UnsafeCell::new(MainThreadState { + host_params: None, layout_index: 0, plugin: P::new(Host::from_inner(Arc::new(ClapHost {}))), editor: None, }), process_state: UnsafeCell::new(ProcessState { + gesture_states: GestureStates::with_count(info.params.len()), buffer_data: Vec::new(), buffer_ptrs: Vec::new(), events: Vec::with_capacity(4096), @@ -197,10 +204,114 @@ impl Instance

{ (*self.host).request_callback.unwrap()(self.host); } } + + unsafe fn process_gestures( + &self, + gesture_states: &mut GestureStates, + events: &mut Vec, + out_events: *const clap_output_events, + time: u32, + ) { + for update in self.param_gestures.poll(gesture_states) { + let param = &self.info.params[update.index]; + + if let Some(value) = update.set_value { + events.push(Event { + time: time as i64, + data: Data::ParamChange { + id: param.id, + value, + }, + }); + + self.plugin_params.set(update.index, value); + } + + self.send_gesture_events(&update, out_events, time); + } + } + + unsafe fn send_gesture_events( + &self, + update: &GestureUpdate, + out_events: *const clap_output_events, + time: u32, + ) { + let param = &self.info.params[update.index]; + + if update.begin_gesture { + let event = clap_event_param_gesture { + header: clap_event_header { + size: mem::size_of::() as u32, + time, + space_id: CLAP_CORE_EVENT_SPACE_ID, + type_: CLAP_EVENT_PARAM_GESTURE_BEGIN, + flags: CLAP_EVENT_IS_LIVE, + }, + param_id: param.id, + }; + + (*out_events).try_push.unwrap()( + out_events, + &event as *const clap_event_param_gesture as *const clap_event_header, + ); + } + + if let Some(value) = update.set_value { + let event = clap_event_param_value { + header: clap_event_header { + size: mem::size_of::() as u32, + time, + space_id: CLAP_CORE_EVENT_SPACE_ID, + type_: CLAP_EVENT_PARAM_VALUE, + flags: CLAP_EVENT_IS_LIVE, + }, + param_id: param.id, + cookie: ptr::null_mut(), + note_id: -1, + port_index: -1, + channel: -1, + key: -1, + value: map_param_out(param, value), + }; + + (*out_events).try_push.unwrap()( + out_events, + &event as *const clap_event_param_value as *const clap_event_header, + ); + } + + if update.end_gesture { + let event = clap_event_param_gesture { + header: clap_event_header { + size: mem::size_of::() as u32, + time, + space_id: CLAP_CORE_EVENT_SPACE_ID, + type_: CLAP_EVENT_PARAM_GESTURE_END, + flags: CLAP_EVENT_IS_LIVE, + }, + param_id: param.id, + }; + + (*out_events).try_push.unwrap()( + out_events, + &event as *const clap_event_param_gesture as *const clap_event_header, + ); + } + } } impl Instance

{ - unsafe extern "C" fn init(_plugin: *const clap_plugin) -> bool { + unsafe extern "C" fn init(plugin: *const clap_plugin) -> bool { + let instance = &*(plugin as *const Self); + let main_thread_state = &mut *instance.main_thread_state.get(); + + let host_params = + (*instance.host).get_extension.unwrap()(instance.host, CLAP_EXT_PARAMS.as_ptr()); + if !host_params.is_null() { + main_thread_state.host_params = Some(host_params as *const clap_host_params); + } + true } @@ -372,6 +483,14 @@ impl Instance

{ instance.sync_processor(&mut process_state.events); instance.process_param_events(process.in_events, &mut process_state.events); + let last_sample = process.frames_count.saturating_sub(1); + instance.process_gestures( + &mut process_state.gesture_states, + &mut process_state.events, + process.out_events, + last_sample, + ); + processor.process( Buffers::from_raw_parts( &process_state.buffer_data, @@ -684,7 +803,7 @@ impl Instance

{ unsafe extern "C" fn params_flush( plugin: *const clap_plugin, in_: *const clap_input_events, - _out: *const clap_output_events, + out: *const clap_output_events, ) { let instance = &*(plugin as *const Self); let process_state = &mut *instance.process_state.get(); @@ -696,6 +815,12 @@ impl Instance

{ process_state.events.clear(); instance.sync_processor(&mut process_state.events); instance.process_param_events(in_, &mut process_state.events); + instance.process_gestures( + &mut process_state.gesture_states, + &mut process_state.events, + out, + 0, + ); processor.process( Buffers::from_raw_parts( @@ -730,6 +855,20 @@ impl Instance

{ } } } + + for update in instance.param_gestures.poll(&mut process_state.gesture_states) { + let param = &instance.info.params[update.index]; + + if let Some(value) = update.set_value { + main_thread_state.plugin.set_param(param.id, value); + + if let Some(editor) = &mut main_thread_state.editor { + editor.param_changed(param.id, value); + } + } + + instance.send_gesture_events(&update, out, 0); + } } } }