use serde::{Deserialize, Serialize};
use super::MidiTrigger;
#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
pub struct MidiControl {
pub name: String,
pub trigger: MidiTrigger,
}
impl MidiTrigger {
pub fn matches(&self, status: u8, data1: u8) -> bool {
self.status == status && (!self.match_data1 || self.data1 == data1)
}
pub fn releases(&self, press: &MidiTrigger) -> bool {
let note_on = press.status & 0xF0 == 0x90;
let same_channel = self.status & 0x0F == press.status & 0x0F;
note_on && same_channel && self.status & 0xF0 == 0x80 && self.data1 == press.data1
}
}
#[cfg(test)]
mod tests {
use super::*;
fn trigger(status: u8, data1: u8, match_data1: bool) -> MidiTrigger {
MidiTrigger {
status,
data1,
match_data1,
}
}
#[test]
fn a_trigger_matches_its_message() {
assert!(trigger(0x90, 24, true).matches(0x90, 24));
assert!(!trigger(0x90, 24, true).matches(0x90, 25));
assert!(!trigger(0x90, 24, true).matches(0x91, 24));
}
#[test]
fn a_pitch_bend_trigger_matches_any_data1() {
assert!(trigger(0xE2, 0, false).matches(0xE2, 93));
}
#[test]
fn a_note_off_releases_the_note_on_of_its_note() {
let press = trigger(0x90, 8, true);
assert!(trigger(0x80, 8, true).releases(&press));
assert!(!trigger(0x80, 9, true).releases(&press));
assert!(!trigger(0x81, 8, true).releases(&press));
assert!(!trigger(0x80, 8, true).releases(&trigger(0xB0, 8, true)));
}
}