#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
pub enum MidiNoteKind {
Frequency,
#[default]
Amplitude,
Gate,
}
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum MidiTransportKind {
Start,
Stop,
Continue,
}
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub enum EventPattern {
AnyButton,
ButtonId(u32),
AnyKnob,
KnobId(u32),
AnyFader,
FaderId(u32),
AnyMidi,
MidiControl {
channel: Option<u8>,
controller: u8,
},
MidiNote {
channel: Option<u8>,
note: Option<u8>,
#[cfg_attr(feature = "serde", serde(default))]
kind: MidiNoteKind,
},
MidiClock,
MidiTransport {
kind: Option<MidiTransportKind>,
},
OscAddress(String),
OscPattern(String),
}
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[derive(Debug, Clone, PartialEq)]
pub enum ControlEvent {
Button {
id: u32,
pressed: bool,
},
Knob {
id: u32,
value: f32,
normalized: f32,
},
Fader {
id: u32,
value: f32,
normalized: f32,
},
MidiControl {
channel: u8,
controller: u8,
value: u8,
normalized: f32,
},
MidiNote {
channel: u8,
note: u8,
velocity: u8,
on: bool,
},
Osc {
address: String,
args: Vec<f32>,
},
MidiClock,
MidiTransport {
kind: MidiTransportKind,
},
}
impl EventPattern {
pub fn matches(&self, event: &ControlEvent) -> bool {
match (self, event) {
(EventPattern::AnyButton, ControlEvent::Button { .. }) => true,
(EventPattern::ButtonId(id), ControlEvent::Button { id: eid, .. }) => *id == *eid,
(EventPattern::AnyKnob, ControlEvent::Knob { .. }) => true,
(EventPattern::KnobId(id), ControlEvent::Knob { id: eid, .. }) => *id == *eid,
(EventPattern::AnyFader, ControlEvent::Fader { .. }) => true,
(EventPattern::FaderId(id), ControlEvent::Fader { id: eid, .. }) => *id == *eid,
(
EventPattern::MidiControl {
channel,
controller,
},
ControlEvent::MidiControl {
channel: ech,
controller: ectr,
..
},
) => (channel.is_none() || channel.unwrap() == *ech) && *controller == *ectr,
(
EventPattern::MidiNote { channel, note, .. },
ControlEvent::MidiNote {
channel: ech,
note: en,
..
},
) => {
(channel.is_none() || channel.unwrap() == *ech)
&& (note.is_none() || note.unwrap() == *en)
}
(EventPattern::AnyMidi, ControlEvent::MidiControl { .. })
| (EventPattern::AnyMidi, ControlEvent::MidiNote { .. })
| (EventPattern::AnyMidi, ControlEvent::MidiClock)
| (EventPattern::AnyMidi, ControlEvent::MidiTransport { .. }) => true,
(EventPattern::MidiClock, ControlEvent::MidiClock) => true,
(
EventPattern::MidiTransport { kind },
ControlEvent::MidiTransport { kind: ek, .. },
) => kind.is_none_or(|k| k == *ek),
(EventPattern::OscAddress(addr), ControlEvent::Osc { address, .. }) => addr == address,
(EventPattern::OscPattern(pat), ControlEvent::Osc { address, .. }) => {
address.contains(pat)
}
_ => false,
}
}
}
impl ControlEvent {
pub fn normalized_value(&self) -> Option<f32> {
match self {
ControlEvent::Knob { normalized, .. } => Some(*normalized),
ControlEvent::Fader { normalized, .. } => Some(*normalized),
ControlEvent::MidiControl { normalized, .. } => Some(*normalized),
ControlEvent::Button { pressed, .. } => Some(if *pressed { 1.0 } else { 0.0 }),
_ => None,
}
}
pub fn id(&self) -> Option<u32> {
match self {
ControlEvent::Button { id, .. } => Some(*id),
ControlEvent::Knob { id, .. } => Some(*id),
ControlEvent::Fader { id, .. } => Some(*id),
_ => None,
}
}
}