Skip to content

Commit

Permalink
ParamInfo redesign
Browse files Browse the repository at this point in the history
Replace the Range enum in ParamInfo with a `steps` value, and switch to using
only normalized values in the [0.0, 1.0] range for parameters. Replace the
Display trait with two separate Box<dyn Fn> fields called `parse` and
`display`.
  • Loading branch information
micahrj committed Jan 14, 2024
1 parent 2e63ac2 commit 6e9a605
Show file tree
Hide file tree
Showing 4 changed files with 76 additions and 101 deletions.
7 changes: 5 additions & 2 deletions examples/gain/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}),
}],
}
}
Expand Down
76 changes: 49 additions & 27 deletions src/format/clap/instance.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -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<P: Plugin> {
pub layout_index: usize,
pub plugin: P,
Expand Down Expand Up @@ -275,16 +291,18 @@ impl<P: Plugin> Instance<P> {
{
let event = &*(event as *const clap_event_param_value);

if let Some(&param_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);
}
}
}
Expand Down Expand Up @@ -507,18 +525,15 @@ impl<P: Plugin> Instance<P> {
param_info.cookie = ptr::null_mut();
copy_cstring(&param.name, &mut param_info.name);
copy_cstring("", &mut param_info.module);
match &param.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(&param, param.default);

return true;
}
Expand All @@ -534,9 +549,11 @@ impl<P: Plugin> Instance<P> {
let instance = &*(plugin as *const Self);
let main_thread_state = &mut *instance.main_thread_state.get();

if instance.param_map.contains_key(&param_id) {
if let Some(&index) = instance.param_map.get(&param_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;
}

Expand All @@ -553,8 +570,10 @@ impl<P: Plugin> Instance<P> {
let instance = &*(plugin as *const Self);

if let Some(&index) = instance.param_map.get(&param_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);
Expand All @@ -575,8 +594,9 @@ impl<P: Plugin> Instance<P> {

if let Some(&index) = instance.param_map.get(&param_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;
}
}
Expand Down Expand Up @@ -608,9 +628,10 @@ impl<P: Plugin> Instance<P> {
{
let event = &*(event as *const clap_event_param_value);

if let Some(&param_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);
}
}
}
Expand All @@ -630,9 +651,10 @@ impl<P: Plugin> Instance<P> {
{
let event = &*(event as *const clap_event_param_value);

if let Some(&param_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);
}
}
}
Expand Down
64 changes: 16 additions & 48 deletions src/format/vst3/component.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};
Expand All @@ -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<P: Plugin> {
pub config: Config,
pub plugin: P,
Expand Down Expand Up @@ -512,19 +497,16 @@ impl<P: Plugin> IAudioProcessorTrait for Component<P> {
let Some(&param_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 },
Expand Down Expand Up @@ -577,11 +559,12 @@ impl<P: Plugin> IEditControllerTrait for Component<P> {
copy_wstring(&param.name, &mut info.title);
copy_wstring(&param.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;

Expand All @@ -601,8 +584,7 @@ impl<P: Plugin> IEditControllerTrait for Component<P> {
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;
Expand All @@ -621,8 +603,8 @@ impl<P: Plugin> IEditControllerTrait for Component<P> {
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;
}
}
Expand All @@ -633,33 +615,21 @@ impl<P: Plugin> IEditControllerTrait for Component<P> {

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
Expand All @@ -669,9 +639,7 @@ impl<P: Plugin> IEditControllerTrait for Component<P> {
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;
}
Expand Down
30 changes: 6 additions & 24 deletions src/param.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,32 +2,14 @@ use std::fmt::Write;

use crate::{ParamId, ParamValue};

type ParseFn = dyn Fn(&str) -> Option<ParamValue> + 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<dyn Display + Send + Sync>,
}

pub enum Range {
Continuous { min: f64, max: f64 },
Discrete { min: i32, max: i32 },
}

pub trait Display {
fn parse(&self, string: &str) -> Option<ParamValue>;
fn display(&self, value: ParamValue, output: &mut dyn Write);
}

pub struct Float;

impl Display for Float {
fn parse(&self, string: &str) -> Option<ParamValue> {
string.parse().ok()
}

fn display(&self, value: ParamValue, output: &mut dyn Write) {
let _ = write!(output, "{:.2}", value);
}
pub steps: Option<u32>,
pub parse: Box<ParseFn>,
pub display: Box<DisplayFn>,
}

0 comments on commit 6e9a605

Please sign in to comment.