From 2d88f46f02a28c30af2f4d3fd151cd0e7bb7e892 Mon Sep 17 00:00:00 2001 From: NetterSilver <133535268+Silvertree2010@users.noreply.github.com> Date: Sat, 31 Oct 2026 10:16:46 +0000 Subject: [PATCH] Keep plugin parameter id case in AutoParam::parse Found while testing crates/model/src/automation.rs:86-103 (AutoParam::parse) Co-Authored-By: Claude Haiku 5.5 Co-Authored-By: Claude Sonnet 5.5 --- crates/model/src/automation.rs | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/crates/model/src/automation.rs b/crates/model/src/automation.rs index 26bbcae3..8ee9e7fb 100644 --- a/crates/model/src/automation.rs +++ b/crates/model/src/automation.rs @@ -80,7 +80,8 @@ impl AutoParam { } /// Parse ids like `volume`, `pan`, `pan2`, `mute`, `send_a_level`, `plugin:a:threshold`. pub fn parse(s: &str) -> Option { - let s = s.trim().to_ascii_lowercase(); + let orig = s.trim(); + let s = orig.to_ascii_lowercase(); match s.as_str() { "volume" | "vol" => return Some(AutoParam::Volume), "pan" | "pan1" => return Some(AutoParam::Pan(0)), @@ -100,6 +101,8 @@ impl AutoParam { } if let Some(rest) = s.strip_prefix("plugin:") { let (slot, param) = rest.split_once(':')?; + // ASCII lowercasing keeps byte offsets, so take the param from the original. + let param = orig.get(orig.len() - param.len()..)?; return Some(AutoParam::Plugin { slot: letter_slot(slot)?, param: param.to_string() }); } None @@ -255,6 +258,15 @@ impl AutomationLane { mod tests { use super::*; + #[test] + fn parse_keeps_plugin_param_case() { + let p = AutoParam::Plugin { slot: 0, param: "Cutoff".into() }; + assert_eq!(AutoParam::parse("plugin:a:Cutoff"), Some(p)); + assert_eq!(AutoParam::parse("Plugin:B:Mix"), Some(AutoParam::Plugin { slot: 1, param: "Mix".into() })); + assert_eq!(AutoParam::parse("Volume"), Some(AutoParam::Volume)); + assert_eq!(AutoParam::parse("SEND_B_LEVEL"), Some(AutoParam::SendLevel(1))); + } + #[test] fn pan_label_max_does_not_overflow() { assert_eq!(AutoParam::Pan(255).label(), "pan 256");