diff --git a/src-tauri/src/audio/plugins/au_host.rs b/src-tauri/src/audio/plugins/au_host.rs index 2074f2a..3faecfd 100644 --- a/src-tauri/src/audio/plugins/au_host.rs +++ b/src-tauri/src/audio/plugins/au_host.rs @@ -727,10 +727,14 @@ fn param_info(unit: AudioUnit, id: u32) -> Option { max: info.maxValue as f64, default: info.defaultValue as f64, value: value as f64, - stepped: matches!( + step: if matches!( info.unit, AudioUnitParameterUnit::Indexed | AudioUnitParameterUnit::Boolean - ), + ) { + 1.0 + } else { + 0.0 + }, read_only: !info .flags .contains(AudioUnitParameterOptions::Flag_IsWritable), @@ -1271,7 +1275,7 @@ mod tests { assert_eq!((gain.min, gain.max), (-96.0, 24.0)); assert!(!gain.read_only); assert!( - params.iter().any(|p| p.stepped), + params.iter().any(|p| p.step > 0.0), "no stepped parameter found" ); diff --git a/src-tauri/src/audio/plugins/clap_host.rs b/src-tauri/src/audio/plugins/clap_host.rs index 2016aa3..8f80c73 100644 --- a/src-tauri/src/audio/plugins/clap_host.rs +++ b/src-tauri/src/audio/plugins/clap_host.rs @@ -368,7 +368,11 @@ impl ClapInstance { max: info.max_value, default: info.default_value, value, - stepped: info.flags.contains(ParamInfoFlags::IS_STEPPED), + step: if info.flags.contains(ParamInfoFlags::IS_STEPPED) { + 1.0 + } else { + 0.0 + }, read_only: info.flags.contains(ParamInfoFlags::IS_READONLY), }); } diff --git a/src-tauri/src/audio/plugins/host_api.rs b/src-tauri/src/audio/plugins/host_api.rs index b7cf159..abfc7be 100644 --- a/src-tauri/src/audio/plugins/host_api.rs +++ b/src-tauri/src/audio/plugins/host_api.rs @@ -34,8 +34,9 @@ pub struct PluginParamInfo { pub max: f64, pub default: f64, pub value: f64, - /// Stepped params (int/enum/toggle) render as discrete steps, not a slider. - pub stepped: bool, + /// One step in the `min..max` units for stepped params (int/enum/toggle), + /// 0 for continuous ones. + pub step: f64, /// Read-only params are shown but not editable. pub read_only: bool, } diff --git a/src-tauri/src/audio/plugins/vst3_host.rs b/src-tauri/src/audio/plugins/vst3_host.rs index a21a933..cdaf4be 100644 --- a/src-tauri/src/audio/plugins/vst3_host.rs +++ b/src-tauri/src/audio/plugins/vst3_host.rs @@ -205,7 +205,7 @@ impl Vst3Instance { pub fn params(&self) -> Vec { use vst3::Steinberg::Vst::ParameterInfo; use vst3::Steinberg::Vst::ParameterInfo_::ParameterFlags_::{ - kIsHidden, kIsList, kIsProgramChange, kIsReadOnly, + kIsHidden, kIsProgramChange, kIsReadOnly, }; let mut out = Vec::new(); @@ -228,7 +228,11 @@ impl Vst3Instance { max: 1.0, default: info.defaultNormalizedValue, value: self.controller.getParamNormalized(info.id), - stepped: info.stepCount > 0 || info.flags & kIsList != 0, + step: if info.stepCount > 0 { + 1.0 / info.stepCount as f64 + } else { + 0.0 + }, read_only: info.flags & kIsReadOnly != 0, }); } @@ -584,7 +588,7 @@ mod tests { let Some(param) = instance .params() .into_iter() - .find(|p| !p.read_only && !p.stepped) + .find(|p| !p.read_only && p.step == 0.0) else { panic!("{name} has no continuous writable parameter"); }; @@ -650,7 +654,7 @@ mod tests { let param = before .params() .into_iter() - .find(|p| !p.read_only && !p.stepped) + .find(|p| !p.read_only && p.step == 0.0) .expect("a continuous parameter"); let target = if param.value > 0.5 { 0.25 } else { 0.75 }; before.set_param(param.id, target); diff --git a/src/lib/modules/audio/types.ts b/src/lib/modules/audio/types.ts index 80d21cc..009739a 100644 --- a/src/lib/modules/audio/types.ts +++ b/src/lib/modules/audio/types.ts @@ -38,7 +38,7 @@ export interface PluginParam { max: number; default: number; value: number; - stepped: boolean; + step: number; readOnly: boolean; } diff --git a/src/lib/modules/flow/ui/effect/plugin.svelte b/src/lib/modules/flow/ui/effect/plugin.svelte index 5ae8aad..e1f89f6 100644 --- a/src/lib/modules/flow/ui/effect/plugin.svelte +++ b/src/lib/modules/flow/ui/effect/plugin.svelte @@ -242,7 +242,7 @@ value={p.value} min={p.min} max={p.max} - step={p.stepped ? 1 : p.max > p.min ? (p.max - p.min) / 100 : 0.01} + step={p.step || (p.max > p.min ? (p.max - p.min) / 100 : 0.01)} defaultValue={p.default} onChange={(v) => setParam(p, v)} /> {/each}