use super::glide::Glide; use super::value::integer_control; use crate::parameter::bin_enum; use mfctl_derive::author; #[author] #[serde(default, rename_all = "camelCase", deny_unknown_fields)] pub struct Keyboard { /// Choose glideTimeMs, glideDivision or glideMsPerOctave. Omission defaults to Time, Off. #[serde(flatten, deserialize_with = "Glide::deserialize_or_default")] #[schemars(with = "Option")] pub glide: Glide, /// Keyboard octave transpose. pub octave: Octave, /// Aftertouch uses pressure held on a key; Velocity uses the strength of the initial touch. This selects the Pressure matrix source. pub pressure_mode: PressureMode, /// Amount of key velocity sent to amplitude. pub velocity_amp: VelocityAmp, /// Keyboard scale. Global uses the instrument's global scale; OFF leaves pitches unquantized. pub scale: Scale, /// Root note for the selected keyboard scale. pub root: Note, } impl Default for Keyboard { fn default() -> Self { Self { glide: Glide::default(), octave: Octave(0), pressure_mode: PressureMode::default(), velocity_amp: VelocityAmp(0), scale: Scale::default(), root: Note::default(), } } } bin_enum! { pub enum PressureMode { #[default] Aftertouch, Velocity, } } bin_enum! { pub enum Scale { #[default] Global, OFF, Major, Minor, HarmoMinor, Dorian, Mixolydian, Blues, Penta, } } bin_enum! { pub enum Note { #[default] C, #[serde(rename = "C#")] CSharp, D, #[serde(rename = "D#")] DSharp, E, F, #[serde(rename = "F#")] FSharp, G, #[serde(rename = "G#")] GSharp, A, #[serde(rename = "A#")] ASharp, B, } } integer_control!(Octave, i8, -3, 3); integer_control!(VelocityAmp, u8, 0, 10); #[cfg(test)] mod tests { use super::*; use crate::parameter::{RegisterCodec, StoredValue}; use crate::patch::value::tests::check_integer_controls; use garde::Validate; #[test] fn integer_controls_round_trip_their_entire_author_ranges() { check_integer_controls!(Octave: -3 => 3, VelocityAmp: 0 => 10); } }