diff --git a/examples/gain/src/lib.rs b/examples/gain/src/lib.rs index e599054..666529e 100644 --- a/examples/gain/src/lib.rs +++ b/examples/gain/src/lib.rs @@ -37,8 +37,11 @@ impl Plugin for Gain { id: GAIN, name: "Gain".to_string(), default: 1.0, - range: Range::Continuous { min: 0.0, max: 1.0 }, - display: Box::new(Float), + steps: None, + parse: Box::new(|s| s.parse().ok()), + display: Box::new(|v, w| { + let _ = write!(w, "{:.2}", v); + }), }], } } diff --git a/src/format/clap/instance.rs b/src/format/clap/instance.rs index 589b379..700a505 100644 --- a/src/format/clap/instance.rs +++ b/src/format/clap/instance.rs @@ -12,10 +12,10 @@ use clap_sys::{events::*, id::*, plugin::*, process::*, stream::*}; use crate::buffers::{Buffers, BusData}; use crate::bus::{BusDir, Format}; use crate::events::{Data, Event, Events}; -use crate::param::Range; +use crate::param::ParamInfo; use crate::sync::params::ParamValues; use crate::util::{copy_cstring, slice_from_raw_parts_checked}; -use crate::{Config, Editor, Host, ParamId, Plugin, PluginInfo, Processor}; +use crate::{Config, Editor, Host, ParamId, ParamValue, Plugin, PluginInfo, Processor}; fn port_type_from_format(format: &Format) -> &'static CStr { match format { @@ -24,6 +24,22 @@ fn port_type_from_format(format: &Format) -> &'static CStr { } } +fn map_param_in(param: &ParamInfo, value: f64) -> ParamValue { + if let Some(steps) = param.steps { + (value + 0.5) / steps as f64 + } else { + value + } +} + +fn map_param_out(param: &ParamInfo, value: ParamValue) -> f64 { + if let Some(steps) = param.steps { + (value * steps as f64).floor() + } else { + value + } +} + pub struct MainThreadState { pub layout_index: usize, pub plugin: P, @@ -275,16 +291,18 @@ impl Instance

{ { let event = &*(event as *const clap_event_param_value); - if let Some(¶m_index) = instance.param_map.get(&event.param_id) { + if let Some(&index) = instance.param_map.get(&event.param_id) { + let value = map_param_in(&instance.info.params[index], event.value); + process_state.events.push(Event { time: event.header.time as i64, data: Data::ParamChange { id: event.param_id, - value: event.value, + value, }, }); - instance.plugin_params.set(param_index, event.value); + instance.plugin_params.set(index, value); } } } @@ -507,18 +525,15 @@ impl Instance

{ param_info.cookie = ptr::null_mut(); copy_cstring(¶m.name, &mut param_info.name); copy_cstring("", &mut param_info.module); - match ¶m.range { - Range::Continuous { min, max } => { - param_info.min_value = *min; - param_info.max_value = *max; - } - Range::Discrete { min, max } => { - param_info.flags |= CLAP_PARAM_IS_STEPPED; - param_info.min_value = *min as f64; - param_info.max_value = *max as f64; - } + if let Some(steps) = param.steps { + param_info.flags |= CLAP_PARAM_IS_STEPPED; + param_info.min_value = 0.0; + param_info.max_value = (steps.max(2) - 1) as f64; + } else { + param_info.min_value = 0.0; + param_info.max_value = 1.0; } - param_info.default_value = param.default; + param_info.default_value = map_param_out(¶m, param.default); return true; } @@ -534,9 +549,11 @@ impl Instance

{ let instance = &*(plugin as *const Self); let main_thread_state = &mut *instance.main_thread_state.get(); - if instance.param_map.contains_key(¶m_id) { + if let Some(&index) = instance.param_map.get(¶m_id) { instance.sync_plugin(&mut main_thread_state.plugin); - *value = main_thread_state.plugin.get_param(param_id); + + let param = &instance.info.params[index]; + *value = map_param_out(param, main_thread_state.plugin.get_param(param_id)); return true; } @@ -553,8 +570,10 @@ impl Instance

{ let instance = &*(plugin as *const Self); if let Some(&index) = instance.param_map.get(¶m_id) { + let param = &instance.info.params[index]; + let mut text = String::new(); - instance.info.params[index].display.display(value, &mut text); + (param.display)(map_param_in(param, value), &mut text); let dst = slice::from_raw_parts_mut(display, size as usize); copy_cstring(&text, dst); @@ -575,8 +594,9 @@ impl Instance

{ if let Some(&index) = instance.param_map.get(¶m_id) { if let Ok(text) = CStr::from_ptr(display).to_str() { - if let Some(out) = instance.info.params[index].display.parse(text) { - *value = out; + let param = &instance.info.params[index]; + if let Some(out) = (param.parse)(text) { + *value = map_param_out(param, out); return true; } } @@ -608,9 +628,10 @@ impl Instance

{ { let event = &*(event as *const clap_event_param_value); - if let Some(¶m_index) = instance.param_map.get(&event.param_id) { - processor.set_param(event.param_id, event.value); - instance.plugin_params.set(param_index, event.value); + if let Some(&index) = instance.param_map.get(&event.param_id) { + let value = map_param_in(&instance.info.params[index], event.value); + processor.set_param(event.param_id, value); + instance.plugin_params.set(index, value); } } } @@ -630,9 +651,10 @@ impl Instance

{ { let event = &*(event as *const clap_event_param_value); - if let Some(¶m_index) = instance.param_map.get(&event.param_id) { - main_thread_state.plugin.set_param(event.param_id, event.value); - instance.processor_params.set(param_index, event.value); + if let Some(&index) = instance.param_map.get(&event.param_id) { + let value = map_param_in(&instance.info.params[index], event.value); + main_thread_state.plugin.set_param(event.param_id, value); + instance.processor_params.set(index, value); } } } diff --git a/src/format/vst3/component.rs b/src/format/vst3/component.rs index b1fc183..ec6b156 100644 --- a/src/format/vst3/component.rs +++ b/src/format/vst3/component.rs @@ -11,7 +11,6 @@ use super::util::{copy_wstring, utf16_from_ptr}; use super::view::View; use crate::bus::{BusDir, Format, Layout}; use crate::events::{Data, Event, Events}; -use crate::param::{ParamInfo, Range}; use crate::sync::params::ParamValues; use crate::util::slice_from_raw_parts_checked; use crate::{Config, Editor, Host, ParamId, Plugin, PluginInfo, Processor}; @@ -31,20 +30,6 @@ fn speaker_arrangement_to_format(speaker_arrangement: SpeakerArrangement) -> Opt } } -fn map_param(param: &ParamInfo, value: ParamValue) -> ParamValue { - match param.range { - Range::Continuous { min, max } => (1.0 - value) * min + value * max, - Range::Discrete { min, max } => (1.0 - value) * min as f64 + value * max as f64, - } -} - -fn unmap_param(param: &ParamInfo, value: ParamValue) -> ParamValue { - match param.range { - Range::Continuous { min, max } => (value - min) / (max - min), - Range::Discrete { min, max } => (value - min as f64) / ((max - min) as f64), - } -} - pub struct MainThreadState { pub config: Config, pub plugin: P, @@ -512,19 +497,16 @@ impl IAudioProcessorTrait for Component

{ let Some(¶m_index) = self.param_map.get(&id) else { continue; }; - let param = &self.info.params[param_index]; for index in 0..point_count { let mut offset = 0; - let mut value_normalized = 0.0; - let result = param_data.getPoint(index, &mut offset, &mut value_normalized); + let mut value = 0.0; + let result = param_data.getPoint(index, &mut offset, &mut value); if result != kResultOk { continue; } - let value = map_param(param, value_normalized); - process_state.events.push(Event { time: offset as i64, data: Data::ParamChange { id, value }, @@ -577,11 +559,12 @@ impl IEditControllerTrait for Component

{ copy_wstring(¶m.name, &mut info.title); copy_wstring(¶m.name, &mut info.shortTitle); copy_wstring("", &mut info.units); - info.stepCount = match param.range { - Range::Continuous { .. } => 0, - Range::Discrete { min, max } => (max - min).max(1), + info.stepCount = if let Some(steps) = param.steps { + (steps.max(2) - 1) as int32 + } else { + 0 }; - info.defaultNormalizedValue = map_param(param, param.default); + info.defaultNormalizedValue = param.default; info.unitId = 0; info.flags = ParameterInfo_::ParameterFlags_::kCanAutomate as int32; @@ -601,8 +584,7 @@ impl IEditControllerTrait for Component

{ let param = &self.info.params[index]; let mut display = String::new(); - let value = map_param(param, valueNormalized); - param.display.display(value, &mut display); + (param.display)(valueNormalized, &mut display); copy_wstring(&display, &mut *string); return kResultOk; @@ -621,8 +603,8 @@ impl IEditControllerTrait for Component

{ let param = &self.info.params[index]; if let Ok(display) = String::from_utf16(utf16_from_ptr(string)) { - if let Some(value) = param.display.parse(&display) { - *valueNormalized = unmap_param(param, value); + if let Some(value) = (param.parse)(&display) { + *valueNormalized = value; return kResultOk; } } @@ -633,33 +615,21 @@ impl IEditControllerTrait for Component

{ unsafe fn normalizedParamToPlain( &self, - id: ParamID, + _id: ParamID, valueNormalized: ParamValue, ) -> ParamValue { - if let Some(&index) = self.param_map.get(&id) { - let param = &self.info.params[index]; - return map_param(param, valueNormalized); - } - - 0.0 + valueNormalized } - unsafe fn plainParamToNormalized(&self, id: ParamID, plainValue: ParamValue) -> ParamValue { - if let Some(&index) = self.param_map.get(&id) { - let param = &self.info.params[index]; - return unmap_param(param, plainValue); - } - - 0.0 + unsafe fn plainParamToNormalized(&self, _id: ParamID, plainValue: ParamValue) -> ParamValue { + plainValue } unsafe fn getParamNormalized(&self, id: ParamID) -> ParamValue { let main_thread_state = &*self.main_thread_state.get(); if let Some(&index) = self.param_map.get(&id) { - let param = &self.info.params[index]; - let value = main_thread_state.editor_params[index]; - return unmap_param(param, value); + return main_thread_state.editor_params[index]; } 0.0 @@ -669,9 +639,7 @@ impl IEditControllerTrait for Component

{ let main_thread_state = &mut *self.main_thread_state.get(); if let Some(&index) = self.param_map.get(&id) { - let param = &self.info.params[index]; - let mapped = map_param(param, value); - main_thread_state.editor_params[index] = mapped; + main_thread_state.editor_params[index] = value; return kResultOk; } diff --git a/src/param.rs b/src/param.rs index add2063..fff7db3 100644 --- a/src/param.rs +++ b/src/param.rs @@ -2,32 +2,14 @@ use std::fmt::Write; use crate::{ParamId, ParamValue}; +type ParseFn = dyn Fn(&str) -> Option + Send + Sync; +type DisplayFn = dyn Fn(ParamValue, &mut dyn Write) + Send + Sync; + pub struct ParamInfo { pub id: ParamId, pub name: String, pub default: ParamValue, - pub range: Range, - pub display: Box, -} - -pub enum Range { - Continuous { min: f64, max: f64 }, - Discrete { min: i32, max: i32 }, -} - -pub trait Display { - fn parse(&self, string: &str) -> Option; - fn display(&self, value: ParamValue, output: &mut dyn Write); -} - -pub struct Float; - -impl Display for Float { - fn parse(&self, string: &str) -> Option { - string.parse().ok() - } - - fn display(&self, value: ParamValue, output: &mut dyn Write) { - let _ = write!(output, "{:.2}", value); - } + pub steps: Option, + pub parse: Box, + pub display: Box, }