From 5f03914e523a716a895c10da220e797b3973e5d7 Mon Sep 17 00:00:00 2001 From: Benjamin Klum Date: Sat, 2 Apr 2022 15:33:32 +0200 Subject: [PATCH 1/3] #184 Support the min/max and step parts of GetParamInfo --- src/api.rs | 88 ++++++++++++++++++++++++++++++++++++++++ src/interfaces.rs | 11 ++++- src/plugin.rs | 101 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 199 insertions(+), 1 deletion(-) diff --git a/src/api.rs b/src/api.rs index 44a1a78a..8aa69780 100644 --- a/src/api.rs +++ b/src/api.rs @@ -738,6 +738,72 @@ impl Default for SmpteFrameRate { } } +/// Parameter properties. +#[repr(C)] +pub struct VstParameterProperties { + /// Float step. + pub step_float: f32, + /// Small float step. + pub small_step_float: f32, + /// Large float step. + pub large_step_float: f32, + /// Parameter label. + pub label: [u8; 64], + /// Flags found in `VstParameterFlags`. + pub flags: i32, + /// Integer minimum. + pub min_integer: i32, + /// Integer maximum. + pub max_integer: i32, + /// Integer step. + pub step_integer: i32, + /// Large integer step. + pub large_step_integer: i32, + /// Short label. + /// + /// Recommended: 6 characters + delimiter. + pub short_label: [u8; 8], + /// Index where this parameter should be displayed (starting with 0). + /// + /// Requires flag `SUPPORTS_DISPLAY_INDEX`. + pub display_index: i16, + /// Parameter category. + /// + /// 0 means no category, else category index + 1. + pub category: i16, + /// Number of parameters in category. + pub num_parameters_in_category: i16, + /// Reserved for future use (please zero). + pub reserved: i16, + /// Category label. + pub category_label: [u8; 24], + /// Reserved for future use (please zero). + pub future: [u8; 16], +} + +impl Default for VstParameterProperties { + fn default() -> Self { + Self { + step_float: 0.0, + small_step_float: 0.0, + large_step_float: 0.0, + label: [0; 64], + flags: 0, + min_integer: 0, + max_integer: 0, + step_integer: 0, + large_step_integer: 0, + short_label: [0; 8], + display_index: 0, + category: 0, + num_parameters_in_category: 0, + reserved: 0, + category_label: [0; 24], + future: [0; 16], + } + } +} + bitflags! { /// Flags for VST channels. pub struct ChannelFlags: i32 { @@ -828,6 +894,28 @@ bitflags! { } } +bitflags! { + /// Flags for VST parameters. + /// + /// Used in `VstParameterProperties`. + pub struct VstParameterFlags: i32 { + /// Parameter is a switch (on or off). + const IS_SWITCH = 1; + /// Indicates that `min_integer` and `max_integer` are valid. + const USES_INTEGER_MIN_MAX = 1 << 1; + /// Indicates that `step_float`, `small_step_float` and `large_step_float` are valid. + const USES_FLOAT_STEP = 1 << 2; + /// Indicates that `step_integer` and `large_step_integer` are valid. + const USES_INT_STEP = 1 << 3; + /// Indicates that `display_index` is valid. + const SUPPORTS_DISPLAY_INDEX = 1 << 4; + /// Indicates that `category`, `num_parameters_in_category` and `category_label` are valid. + const SUPPORTS_DISPLAY_CATEGORY = 1 << 5; + /// If the parameter value can ramp up or down. + const CAN_RAMP = 1 << 6; + } +} + #[cfg(test)] mod tests { use super::super::event; diff --git a/src/interfaces.rs b/src/interfaces.rs index 6b5261e7..99cd9ed8 100644 --- a/src/interfaces.rs +++ b/src/interfaces.rs @@ -244,7 +244,16 @@ pub extern "C" fn dispatch( } } - //OpCode::GetParamInfo => { /*TODO*/ } + Ok(OpCode::GetParamInfo) => { + if let Some(info) = get_plugin().get_parameter_info(index) { + let ptr = ptr as *mut api::VstParameterProperties; + unsafe { + *ptr = info.into(); + } + return 1; + } + } + Ok(OpCode::GetApiVersion) => return 2400, Ok(OpCode::EditorKeyDown) => { diff --git a/src/plugin.rs b/src/plugin.rs index 8c9be409..5c0b8c0f 100644 --- a/src/plugin.rs +++ b/src/plugin.rs @@ -383,6 +383,102 @@ impl Default for Info { } } +/// A structure representing information about a specific plug-in parameter. +#[derive(Clone, Debug)] +#[non_exhaustive] +pub struct PluginParameterInfo { + /// Defines the parameter character. + pub character: PluginParameterCharacter, + /// If the parameter value can ramp up or down. + pub can_ramp: bool, +} + +impl Default for PluginParameterInfo { + fn default() -> Self { + Self { + character: PluginParameterCharacter::Continuous { steps: None }, + can_ramp: false, + } + } +} + +/// Character of a plug-in parameter. +#[derive(Clone, Debug)] +#[non_exhaustive] +pub enum PluginParameterCharacter { + /// Parameter is a switch (on or off). + Switch, + /// Parameter has a continuous value range (floating point numbers). + Continuous { + /// Step sizes. + steps: Option, + }, + /// Parameter has a discrete value range (integers). + Discrete { + /// Minimum value. + min: i32, + /// Maximum value. + max: i32, + /// Step sizes. + steps: Option, + }, +} + +/// Custom step sizes for continuous parameters. +#[derive(Clone, Debug)] +pub struct FloatSteps { + /// Normal step. + pub step: f32, + /// Small step. + pub small_step: f32, + /// Large step. + pub large_step: f32, +} + +/// Custom step sizes for discrete parameters. +#[derive(Clone, Debug)] +pub struct IntegerSteps { + /// Normal step. + pub step: i32, + /// Large step. + pub large_step: i32, +} + +impl From for api::VstParameterProperties { + fn from(info: PluginParameterInfo) -> api::VstParameterProperties { + let mut props = api::VstParameterProperties::default(); + let mut flags = api::VstParameterFlags::empty(); + if info.can_ramp { + flags |= api::VstParameterFlags::CAN_RAMP; + } + match info.character { + PluginParameterCharacter::Switch => { + flags |= api::VstParameterFlags::IS_SWITCH; + } + PluginParameterCharacter::Continuous { steps } => { + if let Some(steps) = steps { + flags |= api::VstParameterFlags::USES_FLOAT_STEP; + props.small_step_float = steps.small_step; + props.step_float = steps.step; + props.large_step_float = steps.large_step; + } + } + PluginParameterCharacter::Discrete { min, max, steps } => { + flags |= api::VstParameterFlags::USES_INTEGER_MIN_MAX; + props.min_integer = min; + props.max_integer = max; + if let Some(steps) = steps { + flags |= api::VstParameterFlags::USES_INT_STEP; + props.step_integer = steps.step; + props.large_step_integer = steps.large_step; + } + } + } + props.flags = flags.bits(); + props + } +} + /// Features which are optionally supported by a plugin. These are queried by the host at run time. #[derive(Debug)] #[allow(missing_docs)] @@ -676,6 +772,11 @@ pub trait Plugin: Send { ) } + /// Returns additional information about the parameter at the given index. + fn get_parameter_info(&self, index: i32) -> Option { + None + } + /// Called one time before the start of process call. /// /// This indicates that the process call will be interrupted (due to Host reconfiguration From 6f827426bca5be7fa5f3b93c276a591a040e13fd Mon Sep 17 00:00:00 2001 From: Benjamin Klum Date: Sat, 2 Apr 2022 15:41:08 +0200 Subject: [PATCH 2/3] #184 Add example how to create a PluginParameterInfo value --- src/plugin.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/plugin.rs b/src/plugin.rs index 5c0b8c0f..5dd6f521 100644 --- a/src/plugin.rs +++ b/src/plugin.rs @@ -384,6 +384,14 @@ impl Default for Info { } /// A structure representing information about a specific plug-in parameter. +/// +/// # Example +/// +/// ```no_run +/// # use vst::plugin::{PluginParameterCharacter, PluginParameterInfo}; +/// let mut info = PluginParameterInfo::default(); +/// info.character = PluginParameterCharacter::Switch; +/// ``` #[derive(Clone, Debug)] #[non_exhaustive] pub struct PluginParameterInfo { From 679613bc17c39817ba92284c61065d7ae7dc3761 Mon Sep 17 00:00:00 2001 From: Benjamin Klum Date: Sat, 10 Jun 2023 13:48:15 +0200 Subject: [PATCH 3/3] #196 Fix garbage characters when returning long names/labels --- src/interfaces.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/interfaces.rs b/src/interfaces.rs index 99cd9ed8..d6c8f7d4 100644 --- a/src/interfaces.rs +++ b/src/interfaces.rs @@ -73,7 +73,7 @@ fn copy_string(dst: *mut c_void, src: &str, max: usize) -> isize { let dst = dst as *mut c_void; memset(dst, 0, max); - memcpy(dst, src.as_ptr() as *const c_void, min(max, src.as_bytes().len())); + memcpy(dst, src.as_ptr() as *const c_void, min(max - 1, src.as_bytes().len())); } 1 // Success