use crate::range::ParamRange;
#[derive(Clone, Copy, Debug)]
pub struct ParamInfo {
pub id: u32,
pub name: &'static str,
pub short_name: &'static str,
pub group: &'static str,
pub range: ParamRange,
pub default_plain: f64,
pub flags: ParamFlags,
pub unit: ParamUnit,
pub kind: ParamValueKind,
pub midi_map: Option<MidiSource>,
pub midi_channel: Option<u8>,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum MidiSource {
Cc(u8),
PitchBend,
ChannelPressure,
ProgramChange,
}
#[must_use]
pub fn map_source_to_param(infos: &[ParamInfo], channel: u8, source: MidiSource) -> Option<u32> {
infos
.iter()
.find(|p| p.midi_map == Some(source) && p.midi_channel.is_none_or(|ch| ch == channel))
.map(|p| p.id)
}
#[cfg(test)]
mod tests {
use super::*;
fn info(id: u32, map: Option<MidiSource>, channel: Option<u8>) -> ParamInfo {
ParamInfo {
id,
name: "p",
short_name: "p",
group: "",
range: ParamRange::Linear { min: 0.0, max: 1.0 },
default_plain: 0.0,
flags: ParamFlags::AUTOMATABLE,
unit: ParamUnit::None,
kind: ParamValueKind::Float,
midi_map: map,
midi_channel: channel,
}
}
#[test]
fn resolves_cc_any_and_scoped_channel() {
let infos = [
info(1, Some(MidiSource::Cc(74)), None), info(2, Some(MidiSource::Cc(71)), Some(0)), info(3, Some(MidiSource::PitchBend), None),
];
assert_eq!(map_source_to_param(&infos, 5, MidiSource::Cc(74)), Some(1));
assert_eq!(map_source_to_param(&infos, 0, MidiSource::Cc(71)), Some(2));
assert_eq!(map_source_to_param(&infos, 1, MidiSource::Cc(71)), None);
assert_eq!(
map_source_to_param(&infos, 9, MidiSource::PitchBend),
Some(3)
);
assert_eq!(map_source_to_param(&infos, 0, MidiSource::Cc(7)), None);
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum ParamValueKind {
Float,
Int,
Bool,
Enum,
}
bitflags::bitflags! {
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct ParamFlags: u32 {
const AUTOMATABLE = 0b0_0001;
const HIDDEN = 0b0_0010;
const READONLY = 0b0_0100;
const IS_BYPASS = 0b0_1000;
const CHUNKED = 0b1_0000;
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum ParamUnit {
None,
Db,
Hz,
Milliseconds,
Seconds,
Percent,
Semitones,
Pan,
Degrees,
}
impl ParamUnit {
#[must_use]
pub fn as_str(&self) -> &'static str {
match self {
Self::Db => "dB",
Self::Hz => "Hz",
Self::Milliseconds => "ms",
Self::Seconds => "s",
Self::Percent => "%",
Self::Semitones => "st",
Self::Degrees => "°",
Self::Pan | Self::None => "",
}
}
}