use crate::ReceiverContext;
use super::parse_error::*;
use super::util::*;
use alloc::vec;
use alloc::vec::Vec;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ChannelVoiceMsg {
NoteOn {
note: u8,
velocity: u8,
},
NoteOff {
note: u8,
velocity: u8,
},
ControlChange { control: ControlChange },
HighResNoteOn { note: u8, velocity: u16 },
HighResNoteOff { note: u8, velocity: u16 },
PolyPressure {
note: u8,
pressure: u8,
},
ChannelPressure { pressure: u8 },
ProgramChange { program: u8 },
PitchBend { bend: u16 },
}
impl ChannelVoiceMsg {
pub(crate) fn extend_midi(&self, v: &mut Vec<u8>) {
match self {
ChannelVoiceMsg::NoteOff { .. } => v.push(0x80),
ChannelVoiceMsg::NoteOn { .. } => v.push(0x90),
ChannelVoiceMsg::HighResNoteOff { .. } => v.push(0x80),
ChannelVoiceMsg::HighResNoteOn { .. } => v.push(0x90),
ChannelVoiceMsg::PolyPressure { .. } => v.push(0xA0),
ChannelVoiceMsg::ControlChange { .. } => v.push(0xB0),
ChannelVoiceMsg::ProgramChange { .. } => v.push(0xC0),
ChannelVoiceMsg::ChannelPressure { .. } => v.push(0xD0),
ChannelVoiceMsg::PitchBend { .. } => v.push(0xE0),
}
self.extend_midi_running(v);
}
pub(crate) fn is_extensible(&self) -> bool {
match self {
Self::NoteOff { .. }
| Self::NoteOn { .. }
| Self::HighResNoteOff { .. }
| Self::HighResNoteOn { .. } => true,
Self::ControlChange {
control: ControlChange::Parameter(_),
} => true,
Self::ControlChange { control } => control.is_lsb() || control.is_msb(),
_ => false,
}
}
pub(crate) fn is_extension(&self) -> bool {
match self {
Self::ControlChange { control } => match control {
ControlChange::HighResVelocity(_) => true,
control => control.is_lsb() || control.is_msb(),
},
_ => false,
}
}
pub(crate) fn maybe_extend(&self, other: &Self) -> Result<Self, ()> {
match (self, other) {
(
Self::NoteOff { note, velocity },
Self::ControlChange {
control: ControlChange::HighResVelocity(v),
},
) => Ok(Self::HighResNoteOff {
note: *note,
velocity: u14_from_u7s(*velocity, *v),
}),
(
Self::NoteOn { note, velocity },
Self::ControlChange {
control: ControlChange::HighResVelocity(v),
},
) => Ok(Self::HighResNoteOn {
note: *note,
velocity: u14_from_u7s(*velocity, *v),
}),
(
Self::HighResNoteOff { note, velocity },
Self::ControlChange {
control: ControlChange::HighResVelocity(v),
},
) => Ok(Self::HighResNoteOff {
note: *note,
velocity: replace_u14_lsb(*velocity, *v),
}),
(
Self::HighResNoteOn { note, velocity },
Self::ControlChange {
control: ControlChange::HighResVelocity(v),
},
) => Ok(Self::HighResNoteOn {
note: *note,
velocity: replace_u14_lsb(*velocity, *v),
}),
(Self::ControlChange { control: ctrl1 }, Self::ControlChange { control: ctrl2 }) => {
match ctrl1.maybe_extend(ctrl2) {
Ok(control) => Ok(Self::ControlChange { control }),
Err(()) => Err(()),
}
}
_ => Err(()),
}
}
pub(crate) fn extend_midi_running(&self, v: &mut Vec<u8>) {
match *self {
ChannelVoiceMsg::NoteOff { note, velocity } => {
v.push(to_u7(note));
v.push(to_u7(velocity));
}
ChannelVoiceMsg::NoteOn { note, velocity } => {
v.push(to_u7(note));
v.push(to_u7(velocity));
}
ChannelVoiceMsg::HighResNoteOff { note, velocity } => {
let [msb, lsb] = to_u14(velocity);
push_u7(note, v);
v.push(msb);
v.push(0xB0);
v.push(0x58);
v.push(lsb);
}
ChannelVoiceMsg::HighResNoteOn { note, velocity } => {
let [msb, lsb] = to_u14(velocity);
push_u7(note, v);
v.push(msb);
v.push(0xB0);
v.push(0x58);
v.push(lsb);
}
ChannelVoiceMsg::PolyPressure { note, pressure } => {
v.push(to_u7(note));
v.push(to_u7(pressure));
}
ChannelVoiceMsg::ControlChange { control } => control.extend_midi_running(v),
ChannelVoiceMsg::ProgramChange { program } => v.push(to_u7(program)),
ChannelVoiceMsg::ChannelPressure { pressure } => v.push(to_u7(pressure)),
ChannelVoiceMsg::PitchBend { bend } => {
push_u14(bend, v);
}
}
}
pub(crate) fn from_midi(m: &[u8], ctx: &ReceiverContext) -> Result<(Self, usize), ParseError> {
let status = match m.first() {
Some(b) => match b >> 4 {
0x8 => Self::NoteOff {
note: 0,
velocity: 0,
},
0x9 => Self::NoteOn {
note: 0,
velocity: 0,
},
0xA => Self::PolyPressure {
note: 0,
pressure: 0,
},
0xB => Self::ControlChange {
control: ControlChange::BankSelect(0),
},
0xC => Self::ProgramChange { program: 0 },
0xD => Self::ChannelPressure { pressure: 0 },
0xE => Self::PitchBend { bend: 0 },
_ => return Err(ParseError::Invalid("This shouldn't be possible")),
},
None => return Err(ParseError::UnexpectedEnd),
};
let (msg, len) = Self::from_midi_running(&m[1..], &status, ctx)?;
Ok((msg, len + 1))
}
pub(crate) fn from_midi_running(
m: &[u8],
msg: &Self,
ctx: &ReceiverContext,
) -> Result<(Self, usize), ParseError> {
match msg {
Self::NoteOff { .. } => Ok((
Self::NoteOff {
note: u7_from_midi(m)?,
velocity: u7_from_midi(&m[1..])?,
},
2,
)),
Self::NoteOn { .. } => Ok((
Self::NoteOn {
note: u7_from_midi(m)?,
velocity: u7_from_midi(&m[1..])?,
},
2,
)),
Self::PolyPressure { .. } => Ok((
Self::PolyPressure {
note: u7_from_midi(m)?,
pressure: u7_from_midi(&m[1..])?,
},
2,
)),
Self::ControlChange { .. } => Ok((
Self::ControlChange {
control: ControlChange::from_midi(m, ctx)?,
},
2,
)),
Self::ProgramChange { .. } => Ok((
Self::ProgramChange {
program: u7_from_midi(m)?,
},
1,
)),
Self::ChannelPressure { .. } => Ok((
Self::ChannelPressure {
pressure: u7_from_midi(m)?,
},
1,
)),
Self::PitchBend { .. } => Ok((
Self::PitchBend {
bend: u14_from_midi(m)?,
},
2,
)),
Self::HighResNoteOn { .. } | Self::HighResNoteOff { .. } => {
Ok((
Self::ControlChange {
control: ControlChange::from_midi(m, ctx)?,
},
2,
))
}
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ControlNumber {
BankSelect = 0,
BankSelectLSB = 32,
ModWheel = 1,
ModWheelLSB = 33,
Breath = 2,
BreathLSB = 34,
Foot = 4,
FootLSB = 36,
Portamento = 5,
PortamentoLSB = 37,
DataEntry = 6,
DataEntryLSB = 38,
Volume = 7,
VolumeLSB = 39,
Balance = 8,
BalanceLSB = 40,
Pan = 10,
PanLSB = 42,
Expression = 11,
ExpressionLSB = 43,
Effect1 = 12,
Effect1LSB = 44,
Effect2 = 13,
Effect2LSB = 45,
GeneralPurpose1 = 16,
GeneralPurpose1LSB = 48,
GeneralPurpose2 = 17,
GeneralPurpose2LSB = 49,
GeneralPurpose3 = 18,
GeneralPurpose3LSB = 50,
GeneralPurpose4 = 19,
GeneralPurpose4LSB = 51,
Hold = 64,
TogglePortamento = 65,
Sostenuto = 66,
SoftPedal = 67,
ToggleLegato = 68,
Hold2 = 69,
SoundControl1 = 70,
SoundControl2 = 71,
SoundControl3 = 72,
SoundControl4 = 73,
SoundControl5 = 74,
SoundControl6 = 75,
SoundControl7 = 76,
SoundControl8 = 77,
SoundControl9 = 78,
SoundControl10 = 79,
GeneralPurpose5 = 80,
GeneralPurpose6 = 81,
GeneralPurpose7 = 82,
GeneralPurpose8 = 83,
PortamentoControl = 84,
HighResVelocity = 88,
Effects1Depth = 91,
Effects2Depth = 92,
Effects3Depth = 93,
Effects4Depth = 94,
Effects5Depth = 95,
DataIncrement = 96,
DataDecrement = 97,
NonRegisteredParameterLSB = 98,
NonRegisteredParameter = 99,
RegisteredParameterLSB = 100,
RegisteredParameter = 101,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ControlChange {
CC {
control: u8,
value: u8,
},
CCHighRes {
control1: u8,
control2: u8,
value: u16,
},
BankSelect(u16),
ModWheel(u16),
Breath(u16),
Foot(u16),
Portamento(u16),
Volume(u16),
Balance(u16),
Pan(u16),
Expression(u16),
Effect1(u16),
Effect2(u16),
GeneralPurpose1(u16),
GeneralPurpose2(u16),
GeneralPurpose3(u16),
GeneralPurpose4(u16),
GeneralPurpose5(u8),
GeneralPurpose6(u8),
GeneralPurpose7(u8),
GeneralPurpose8(u8),
Hold(u8),
Hold2(u8),
TogglePortamento(bool),
Sostenuto(u8),
SoftPedal(u8),
ToggleLegato(bool),
SoundVariation(u8),
Timbre(u8),
ReleaseTime(u8),
AttackTime(u8),
Brightness(u8),
DecayTime(u8),
VibratoRate(u8),
VibratoDepth(u8),
VibratoDelay(u8),
SoundControl1(u8),
SoundControl2(u8),
SoundControl3(u8),
SoundControl4(u8),
SoundControl5(u8),
SoundControl6(u8),
SoundControl7(u8),
SoundControl8(u8),
SoundControl9(u8),
SoundControl10(u8),
HighResVelocity(u8),
PortamentoControl(u8),
Effects1Depth(u8),
Effects2Depth(u8),
Effects3Depth(u8),
Effects4Depth(u8),
Effects5Depth(u8),
ReverbSendLevel(u8),
TremoloDepth(u8),
ChorusSendLevel(u8),
CelesteDepth(u8),
PhaserDepth(u8),
Parameter(Parameter),
DataEntry(u16),
DataEntry2(u8, u8),
DataIncrement(u8),
DataDecrement(u8),
}
impl ControlChange {
pub fn to_complex(&self) -> Self {
match *self {
Self::CC { control, value } => {
match control {
0 => Self::BankSelect((value as u16) << 7),
1 => Self::ModWheel((value as u16) << 7),
2 => Self::Breath((value as u16) << 7),
4 => Self::Foot((value as u16) << 7),
5 => Self::Portamento((value as u16) << 7),
6 => Self::DataEntry((value as u16) << 7),
7 => Self::Volume((value as u16) << 7),
8 => Self::Balance((value as u16) << 7),
10 => Self::Pan((value as u16) << 7),
11 => Self::Expression((value as u16) << 7),
12 => Self::Effect1((value as u16) << 7),
13 => Self::Effect2((value as u16) << 7),
16 => Self::GeneralPurpose1((value as u16) << 7),
17 => Self::GeneralPurpose2((value as u16) << 7),
18 => Self::GeneralPurpose3((value as u16) << 7),
19 => Self::GeneralPurpose4((value as u16) << 7),
64 => Self::Hold(value),
65 => Self::TogglePortamento(value >= 0x40),
66 => Self::Sostenuto(value),
67 => Self::SoftPedal(value),
68 => Self::ToggleLegato(value >= 0x40),
69 => Self::Hold2(value),
70 => Self::SoundControl1(value),
71 => Self::SoundControl2(value),
72 => Self::SoundControl3(value),
73 => Self::SoundControl4(value),
74 => Self::SoundControl5(value),
75 => Self::SoundControl6(value),
76 => Self::SoundControl7(value),
77 => Self::SoundControl8(value),
78 => Self::SoundControl9(value),
79 => Self::SoundControl10(value),
80 => Self::GeneralPurpose5(value),
81 => Self::GeneralPurpose6(value),
82 => Self::GeneralPurpose7(value),
83 => Self::GeneralPurpose8(value),
84 => Self::PortamentoControl(value),
88 => Self::HighResVelocity(value),
91 => Self::Effects1Depth(value),
92 => Self::Effects2Depth(value),
93 => Self::Effects3Depth(value),
94 => Self::Effects4Depth(value),
95 => Self::Effects5Depth(value),
96 => Self::DataIncrement(value),
97 => Self::DataDecrement(value),
3 | 9 | 14 | 15 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 => {
Self::CCHighRes {
control1: control,
control2: control + 32,
value: (value as u16) << 7,
}
}
control => Self::CC { control, value },
}
}
Self::CCHighRes {
control1, value, ..
} => {
match control1 {
0 => Self::BankSelect(value),
1 => Self::ModWheel(value),
2 => Self::Breath(value),
4 => Self::Foot(value),
5 => Self::Portamento(value),
6 => Self::DataEntry(value),
7 => Self::Volume(value),
8 => Self::Balance(value),
10 => Self::Pan(value),
11 => Self::Expression(value),
12 => Self::Effect1(value),
13 => Self::Effect2(value),
16 => Self::GeneralPurpose1(value),
17 => Self::GeneralPurpose2(value),
18 => Self::GeneralPurpose3(value),
19 => Self::GeneralPurpose4(value),
_ => Self::CC {
control: control1,
value: (value >> 7) as u8,
}
.to_complex(),
}
}
rest => rest,
}
}
pub fn to_simple(&self) -> Self {
Self::CC {
control: self.control(),
value: self.value(),
}
}
pub fn to_simple_high_res(&self) -> Self {
match self {
Self::CCHighRes { .. } => *self,
_ => {
let cc = self.control();
Self::CCHighRes {
control1: cc,
control2: cc + 32,
value: self.value_high_res(),
}
}
}
}
pub fn control(&self) -> u8 {
match self {
Self::CC { control, .. } => *control,
Self::CCHighRes { control1, .. } => *control1,
Self::BankSelect(_) => ControlNumber::BankSelect as u8,
Self::ModWheel(_) => ControlNumber::ModWheel as u8,
Self::Breath(_) => ControlNumber::Breath as u8,
Self::Foot(_) => ControlNumber::Foot as u8,
Self::Portamento(_) => ControlNumber::Portamento as u8,
Self::Volume(_) => ControlNumber::Volume as u8,
Self::Balance(_) => ControlNumber::Balance as u8,
Self::Pan(_) => ControlNumber::Pan as u8,
Self::Expression(_) => ControlNumber::Expression as u8,
Self::Effect1(_) => ControlNumber::Effect1 as u8,
Self::Effect2(_) => ControlNumber::Effect2 as u8,
Self::GeneralPurpose1(_) => ControlNumber::GeneralPurpose1 as u8,
Self::GeneralPurpose2(_) => ControlNumber::GeneralPurpose2 as u8,
Self::GeneralPurpose3(_) => ControlNumber::GeneralPurpose3 as u8,
Self::GeneralPurpose4(_) => ControlNumber::GeneralPurpose4 as u8,
Self::GeneralPurpose5(_) => ControlNumber::GeneralPurpose5 as u8,
Self::GeneralPurpose6(_) => ControlNumber::GeneralPurpose6 as u8,
Self::GeneralPurpose7(_) => ControlNumber::GeneralPurpose7 as u8,
Self::GeneralPurpose8(_) => ControlNumber::GeneralPurpose8 as u8,
Self::Hold(_) => ControlNumber::Hold as u8,
Self::Hold2(_) => ControlNumber::Hold2 as u8,
Self::TogglePortamento(_) => ControlNumber::TogglePortamento as u8,
Self::Sostenuto(_) => ControlNumber::Sostenuto as u8,
Self::SoftPedal(_) => ControlNumber::SoftPedal as u8,
Self::ToggleLegato(_) => ControlNumber::ToggleLegato as u8,
Self::SoundVariation(_) => ControlNumber::SoundControl1 as u8,
Self::Timbre(_) => ControlNumber::SoundControl2 as u8,
Self::ReleaseTime(_) => ControlNumber::SoundControl3 as u8,
Self::AttackTime(_) => ControlNumber::SoundControl4 as u8,
Self::Brightness(_) => ControlNumber::SoundControl5 as u8,
Self::DecayTime(_) => ControlNumber::SoundControl6 as u8,
Self::VibratoRate(_) => ControlNumber::SoundControl7 as u8,
Self::VibratoDepth(_) => ControlNumber::SoundControl8 as u8,
Self::VibratoDelay(_) => ControlNumber::SoundControl9 as u8,
Self::SoundControl1(_) => ControlNumber::SoundControl1 as u8,
Self::SoundControl2(_) => ControlNumber::SoundControl2 as u8,
Self::SoundControl3(_) => ControlNumber::SoundControl3 as u8,
Self::SoundControl4(_) => ControlNumber::SoundControl4 as u8,
Self::SoundControl5(_) => ControlNumber::SoundControl5 as u8,
Self::SoundControl6(_) => ControlNumber::SoundControl6 as u8,
Self::SoundControl7(_) => ControlNumber::SoundControl7 as u8,
Self::SoundControl8(_) => ControlNumber::SoundControl8 as u8,
Self::SoundControl9(_) => ControlNumber::SoundControl9 as u8,
Self::SoundControl10(_) => ControlNumber::SoundControl10 as u8,
Self::HighResVelocity(_) => ControlNumber::HighResVelocity as u8,
Self::PortamentoControl(_) => ControlNumber::PortamentoControl as u8,
Self::Effects1Depth(_) => ControlNumber::Effects1Depth as u8,
Self::Effects2Depth(_) => ControlNumber::Effects2Depth as u8,
Self::Effects3Depth(_) => ControlNumber::Effects3Depth as u8,
Self::Effects4Depth(_) => ControlNumber::Effects4Depth as u8,
Self::Effects5Depth(_) => ControlNumber::Effects5Depth as u8,
Self::ReverbSendLevel(_) => ControlNumber::Effects1Depth as u8,
Self::TremoloDepth(_) => ControlNumber::Effects2Depth as u8,
Self::ChorusSendLevel(_) => ControlNumber::Effects3Depth as u8,
Self::CelesteDepth(_) => ControlNumber::Effects4Depth as u8,
Self::PhaserDepth(_) => ControlNumber::Effects5Depth as u8,
Self::Parameter(Parameter::Unregistered(..)) => {
ControlNumber::NonRegisteredParameter as u8
}
Self::Parameter(_) => ControlNumber::RegisteredParameter as u8,
Self::DataEntry(_) => ControlNumber::DataEntry as u8,
Self::DataEntry2(_, _) => ControlNumber::DataEntry as u8,
Self::DataIncrement(_) => ControlNumber::DataIncrement as u8,
Self::DataDecrement(_) => ControlNumber::DataDecrement as u8,
}
}
pub fn value(&self) -> u8 {
match self {
Self::CC { value, .. } => *value,
Self::CCHighRes { value, .. } => (*value >> 7) as u8,
Self::BankSelect(x)
| Self::ModWheel(x)
| Self::Breath(x)
| Self::Foot(x)
| Self::Portamento(x)
| Self::Volume(x)
| Self::Balance(x)
| Self::Pan(x)
| Self::Expression(x)
| Self::Effect1(x)
| Self::Effect2(x)
| Self::GeneralPurpose1(x)
| Self::GeneralPurpose2(x)
| Self::GeneralPurpose3(x)
| Self::GeneralPurpose4(x)
| Self::DataEntry(x) => (x >> 7) as u8,
Self::Hold(x)
| Self::Hold2(x)
| Self::Sostenuto(x)
| Self::SoftPedal(x)
| Self::SoundVariation(x)
| Self::Timbre(x)
| Self::ReleaseTime(x)
| Self::AttackTime(x)
| Self::Brightness(x)
| Self::DecayTime(x)
| Self::VibratoRate(x)
| Self::VibratoDepth(x)
| Self::VibratoDelay(x)
| Self::SoundControl1(x)
| Self::SoundControl2(x)
| Self::SoundControl3(x)
| Self::SoundControl4(x)
| Self::SoundControl5(x)
| Self::SoundControl6(x)
| Self::SoundControl7(x)
| Self::SoundControl8(x)
| Self::SoundControl9(x)
| Self::SoundControl10(x)
| Self::GeneralPurpose5(x)
| Self::GeneralPurpose6(x)
| Self::GeneralPurpose7(x)
| Self::GeneralPurpose8(x)
| Self::PortamentoControl(x)
| Self::Effects1Depth(x)
| Self::Effects2Depth(x)
| Self::Effects3Depth(x)
| Self::Effects4Depth(x)
| Self::Effects5Depth(x)
| Self::ReverbSendLevel(x)
| Self::TremoloDepth(x)
| Self::ChorusSendLevel(x)
| Self::CelesteDepth(x)
| Self::PhaserDepth(x)
| Self::HighResVelocity(x)
| Self::DataDecrement(x)
| Self::DataIncrement(x) => *x,
Self::DataEntry2(msb, _) => *msb,
Self::ToggleLegato(x) | Self::TogglePortamento(x) => {
if *x {
127
} else {
0
}
}
Self::Parameter(_) => 0,
}
}
pub fn value_high_res(&self) -> u16 {
match self {
Self::CC { value, .. } => (*value as u16) << 7,
Self::CCHighRes { value, .. } => *value,
Self::BankSelect(x)
| Self::ModWheel(x)
| Self::Breath(x)
| Self::Foot(x)
| Self::Portamento(x)
| Self::Volume(x)
| Self::Balance(x)
| Self::Pan(x)
| Self::Expression(x)
| Self::Effect1(x)
| Self::Effect2(x)
| Self::GeneralPurpose1(x)
| Self::GeneralPurpose2(x)
| Self::GeneralPurpose3(x)
| Self::GeneralPurpose4(x)
| Self::DataEntry(x) => *x,
Self::Hold(x)
| Self::Hold2(x)
| Self::Sostenuto(x)
| Self::SoftPedal(x)
| Self::SoundVariation(x)
| Self::Timbre(x)
| Self::ReleaseTime(x)
| Self::AttackTime(x)
| Self::Brightness(x)
| Self::DecayTime(x)
| Self::VibratoRate(x)
| Self::VibratoDepth(x)
| Self::VibratoDelay(x)
| Self::SoundControl1(x)
| Self::SoundControl2(x)
| Self::SoundControl3(x)
| Self::SoundControl4(x)
| Self::SoundControl5(x)
| Self::SoundControl6(x)
| Self::SoundControl7(x)
| Self::SoundControl8(x)
| Self::SoundControl9(x)
| Self::SoundControl10(x)
| Self::GeneralPurpose5(x)
| Self::GeneralPurpose6(x)
| Self::GeneralPurpose7(x)
| Self::GeneralPurpose8(x)
| Self::PortamentoControl(x)
| Self::Effects1Depth(x)
| Self::Effects2Depth(x)
| Self::Effects3Depth(x)
| Self::Effects4Depth(x)
| Self::Effects5Depth(x)
| Self::ReverbSendLevel(x)
| Self::TremoloDepth(x)
| Self::ChorusSendLevel(x)
| Self::CelesteDepth(x)
| Self::PhaserDepth(x)
| Self::HighResVelocity(x)
| Self::DataDecrement(x)
| Self::DataIncrement(x) => (*x as u16) << 7,
Self::DataEntry2(msb, lsb) => (*msb as u16) << 7 | *lsb as u16,
Self::ToggleLegato(x) | Self::TogglePortamento(x) => {
if *x {
127 << 7
} else {
0
}
}
Self::Parameter(_) => 0,
}
}
fn high_res_cc(v: &mut Vec<u8>, control: u8, value: u16) {
let [msb, lsb] = to_u14(value);
v.push(control);
v.push(msb);
v.push(control + 32);
v.push(lsb);
}
fn undefined(v: &mut Vec<u8>, control: u8, value: u8) {
v.push(control.min(119));
v.push(to_u7(value));
}
fn undefined_high_res(v: &mut Vec<u8>, control1: u8, control2: u8, value: u16) {
let [msb, lsb] = to_u14(value);
v.push(control1.min(119));
v.push(msb);
v.push(control2.min(119));
v.push(lsb);
}
fn is_msb(&self) -> bool {
match self {
Self::BankSelect(_)
| Self::ModWheel(_)
| Self::Breath(_)
| Self::DataEntry(_)
| Self::CCHighRes { .. }
| Self::Foot(_)
| Self::Portamento(_)
| Self::Volume(_)
| Self::Balance(_)
| Self::Pan(_)
| Self::Expression(_)
| Self::Effect1(_)
| Self::Effect2(_)
| Self::GeneralPurpose1(_)
| Self::GeneralPurpose2(_)
| Self::GeneralPurpose3(_)
| Self::GeneralPurpose4(_) => true,
Self::CC { control, .. } if control < &32 || control == &99 || control == &101 => true,
_ => false,
}
}
fn is_lsb(&self) -> bool {
match self {
Self::CC { control, .. }
if control >= &32 && control < &64 || control == &98 || control == &100 =>
{
true
}
_ => false,
}
}
pub fn to_midi_running(&self) -> Vec<u8> {
let mut r: Vec<u8> = vec![];
self.extend_midi_running(&mut r);
r
}
pub fn extend_midi_running(&self, v: &mut Vec<u8>) {
match *self {
ControlChange::BankSelect(x) => ControlChange::high_res_cc(v, 0, x),
ControlChange::ModWheel(x) => ControlChange::high_res_cc(v, 1, x),
ControlChange::Breath(x) => ControlChange::high_res_cc(v, 2, x),
ControlChange::CC { control, value } => ControlChange::undefined(v, control, value),
ControlChange::CCHighRes {
control1,
control2,
value,
} => ControlChange::undefined_high_res(v, control1, control2, value),
ControlChange::Foot(x) => ControlChange::high_res_cc(v, 4, x),
ControlChange::Portamento(x) => ControlChange::high_res_cc(v, 5, x),
ControlChange::Volume(x) => ControlChange::high_res_cc(v, 7, x),
ControlChange::Balance(x) => ControlChange::high_res_cc(v, 8, x),
ControlChange::Pan(x) => ControlChange::high_res_cc(v, 10, x),
ControlChange::Expression(x) => ControlChange::high_res_cc(v, 11, x),
ControlChange::Effect1(x) => ControlChange::high_res_cc(v, 12, x),
ControlChange::Effect2(x) => ControlChange::high_res_cc(v, 13, x),
ControlChange::GeneralPurpose1(x) => ControlChange::high_res_cc(v, 16, x),
ControlChange::GeneralPurpose2(x) => ControlChange::high_res_cc(v, 17, x),
ControlChange::GeneralPurpose3(x) => ControlChange::high_res_cc(v, 18, x),
ControlChange::GeneralPurpose4(x) => ControlChange::high_res_cc(v, 19, x),
ControlChange::GeneralPurpose5(x) => {
v.push(80);
v.push(to_u7(x));
}
ControlChange::GeneralPurpose6(x) => {
v.push(82);
v.push(to_u7(x));
}
ControlChange::GeneralPurpose7(x) => {
v.push(83);
v.push(to_u7(x));
}
ControlChange::GeneralPurpose8(x) => {
v.push(84);
v.push(to_u7(x));
}
ControlChange::Hold(x) => {
v.push(64);
v.push(to_u7(x));
}
ControlChange::Hold2(x) => {
v.push(69);
v.push(to_u7(x));
}
ControlChange::TogglePortamento(on) => {
v.push(65);
v.push(if on { 127 } else { 0 });
}
ControlChange::Sostenuto(x) => {
v.push(66);
v.push(to_u7(x));
}
ControlChange::SoftPedal(x) => {
v.push(67);
v.push(to_u7(x));
}
ControlChange::ToggleLegato(on) => {
v.push(68);
v.push(if on { 127 } else { 0 });
}
ControlChange::SoundVariation(x) | ControlChange::SoundControl1(x) => {
v.push(70);
v.push(to_u7(x));
}
ControlChange::Timbre(x) | ControlChange::SoundControl2(x) => {
v.push(71);
v.push(to_u7(x));
}
ControlChange::ReleaseTime(x) | ControlChange::SoundControl3(x) => {
v.push(72);
v.push(to_u7(x));
}
ControlChange::AttackTime(x) | ControlChange::SoundControl4(x) => {
v.push(73);
v.push(to_u7(x));
}
ControlChange::Brightness(x) | ControlChange::SoundControl5(x) => {
v.push(74);
v.push(to_u7(x));
}
ControlChange::DecayTime(x) | ControlChange::SoundControl6(x) => {
v.push(75);
v.push(to_u7(x));
}
ControlChange::VibratoRate(x) | ControlChange::SoundControl7(x) => {
v.push(76);
v.push(to_u7(x));
}
ControlChange::VibratoDepth(x) | ControlChange::SoundControl8(x) => {
v.push(77);
v.push(to_u7(x));
}
ControlChange::VibratoDelay(x) | ControlChange::SoundControl9(x) => {
v.push(78);
v.push(to_u7(x));
}
ControlChange::SoundControl10(x) => {
v.push(79);
v.push(to_u7(x));
}
ControlChange::PortamentoControl(x) => {
v.push(84);
v.push(to_u7(x));
}
ControlChange::HighResVelocity(x) => {
v.push(88);
v.push(to_u7(x));
}
ControlChange::Effects1Depth(x) | ControlChange::ReverbSendLevel(x) => {
v.push(91);
v.push(to_u7(x));
}
ControlChange::Effects2Depth(x) | ControlChange::TremoloDepth(x) => {
v.push(92);
v.push(to_u7(x));
}
ControlChange::Effects3Depth(x) | ControlChange::ChorusSendLevel(x) => {
v.push(93);
v.push(to_u7(x));
}
ControlChange::Effects4Depth(x) | ControlChange::CelesteDepth(x) => {
v.push(94);
v.push(to_u7(x));
}
ControlChange::Effects5Depth(x) | ControlChange::PhaserDepth(x) => {
v.push(95);
v.push(to_u7(x));
}
ControlChange::Parameter(p) => p.extend_midi_running(v),
ControlChange::DataEntry(x) => ControlChange::high_res_cc(v, 6, x),
ControlChange::DataEntry2(msb, lsb) => {
v.push(6);
v.push(msb);
v.push(6 + 32);
v.push(lsb);
}
ControlChange::DataIncrement(x) => {
v.push(96);
v.push(to_u7(x));
}
ControlChange::DataDecrement(x) => {
v.push(97);
v.push(to_u7(x));
}
}
}
pub(crate) fn from_midi(m: &[u8], ctx: &ReceiverContext) -> Result<Self, ParseError> {
if m.len() < 2 {
return Err(crate::ParseError::UnexpectedEnd);
}
if m[0] > 119 {
return Err(ParseError::Invalid(
"Tried to parse a control change message, but it looks like a channel mode message",
));
}
let value = u8_from_u7(m[1])?;
if !ctx.complex_cc {
return Ok(ControlChange::CC {
control: m[0],
value,
});
}
Ok(match m[0] {
0 => Self::BankSelect((value as u16) << 7),
1 => Self::ModWheel((value as u16) << 7),
2 => Self::Breath((value as u16) << 7),
4 => Self::Foot((value as u16) << 7),
5 => Self::Portamento((value as u16) << 7),
6 => Self::DataEntry((value as u16) << 7),
7 => Self::Volume((value as u16) << 7),
8 => Self::Balance((value as u16) << 7),
10 => Self::Pan((value as u16) << 7),
11 => Self::Expression((value as u16) << 7),
12 => Self::Effect1((value as u16) << 7),
13 => Self::Effect2((value as u16) << 7),
16 => Self::GeneralPurpose1((value as u16) << 7),
17 => Self::GeneralPurpose2((value as u16) << 7),
18 => Self::GeneralPurpose3((value as u16) << 7),
19 => Self::GeneralPurpose4((value as u16) << 7),
64 => Self::Hold(value),
65 => Self::TogglePortamento(bool_from_u7(m[1])?),
66 => Self::Sostenuto(value),
67 => Self::SoftPedal(value),
68 => Self::ToggleLegato(bool_from_u7(m[1])?),
69 => Self::Hold2(value),
70 => Self::SoundControl1(value),
71 => Self::SoundControl2(value),
72 => Self::SoundControl3(value),
73 => Self::SoundControl4(value),
74 => Self::SoundControl5(value),
75 => Self::SoundControl6(value),
76 => Self::SoundControl7(value),
77 => Self::SoundControl8(value),
78 => Self::SoundControl9(value),
79 => Self::SoundControl10(value),
80 => Self::GeneralPurpose5(value),
81 => Self::GeneralPurpose6(value),
82 => Self::GeneralPurpose7(value),
83 => Self::GeneralPurpose8(value),
84 => Self::PortamentoControl(value),
88 => Self::HighResVelocity(value),
91 => Self::Effects1Depth(value),
92 => Self::Effects2Depth(value),
93 => Self::Effects3Depth(value),
94 => Self::Effects4Depth(value),
95 => Self::Effects5Depth(value),
96 => Self::DataIncrement(value),
97 => Self::DataDecrement(value),
3 | 9 | 14 | 15 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 => {
Self::CCHighRes {
control1: m[0],
control2: m[0] + 32,
value: (value as u16) << 7,
}
}
control => Self::CC { control, value },
})
}
fn maybe_extend(&self, other: &Self) -> Result<Self, ()> {
match (self, other) {
(Self::BankSelect(msb), Self::CC { control, value })
| (Self::CC { control, value }, Self::BankSelect(msb))
if *control == ControlNumber::BankSelectLSB as u8 =>
{
Ok(Self::BankSelect(replace_u14_lsb(*msb, *value)))
}
(Self::ModWheel(msb), Self::CC { control, value })
| (Self::CC { control, value }, Self::ModWheel(msb))
if *control == ControlNumber::ModWheelLSB as u8 =>
{
Ok(Self::ModWheel(replace_u14_lsb(*msb, *value)))
}
(Self::Breath(msb), Self::CC { control, value })
| (Self::CC { control, value }, Self::Breath(msb))
if *control == ControlNumber::BreathLSB as u8 =>
{
Ok(Self::Breath(replace_u14_lsb(*msb, *value)))
}
(Self::Foot(msb), Self::CC { control, value })
| (Self::CC { control, value }, Self::Foot(msb))
if *control == ControlNumber::FootLSB as u8 =>
{
Ok(Self::Foot(replace_u14_lsb(*msb, *value)))
}
(Self::Portamento(msb), Self::CC { control, value })
| (Self::CC { control, value }, Self::Portamento(msb))
if *control == ControlNumber::PortamentoLSB as u8 =>
{
Ok(Self::Portamento(replace_u14_lsb(*msb, *value)))
}
(Self::DataEntry(msb), Self::CC { control, value })
| (Self::CC { control, value }, Self::DataEntry(msb))
if *control == ControlNumber::DataEntryLSB as u8 =>
{
Ok(Self::DataEntry(replace_u14_lsb(*msb, *value)))
}
(Self::Volume(msb), Self::CC { control, value })
| (Self::CC { control, value }, Self::Volume(msb))
if *control == ControlNumber::VolumeLSB as u8 =>
{
Ok(Self::Volume(replace_u14_lsb(*msb, *value)))
}
(Self::Balance(msb), Self::CC { control, value })
| (Self::CC { control, value }, Self::Balance(msb))
if *control == ControlNumber::BalanceLSB as u8 =>
{
Ok(Self::Balance(replace_u14_lsb(*msb, *value)))
}
(Self::Pan(msb), Self::CC { control, value })
| (Self::CC { control, value }, Self::Pan(msb))
if *control == ControlNumber::PanLSB as u8 =>
{
Ok(Self::Pan(replace_u14_lsb(*msb, *value)))
}
(Self::Expression(msb), Self::CC { control, value })
| (Self::CC { control, value }, Self::Expression(msb))
if *control == ControlNumber::ExpressionLSB as u8 =>
{
Ok(Self::Expression(replace_u14_lsb(*msb, *value)))
}
(Self::Effect1(msb), Self::CC { control, value })
| (Self::CC { control, value }, Self::Effect1(msb))
if *control == ControlNumber::Effect1LSB as u8 =>
{
Ok(Self::Effect1(replace_u14_lsb(*msb, *value)))
}
(Self::Effect2(msb), Self::CC { control, value })
| (Self::CC { control, value }, Self::Effect2(msb))
if *control == ControlNumber::Effect2LSB as u8 =>
{
Ok(Self::Effect2(replace_u14_lsb(*msb, *value)))
}
(Self::GeneralPurpose1(msb), Self::CC { control, value })
| (Self::CC { control, value }, Self::GeneralPurpose1(msb))
if *control == ControlNumber::GeneralPurpose1LSB as u8 =>
{
Ok(Self::GeneralPurpose1(replace_u14_lsb(*msb, *value)))
}
(Self::GeneralPurpose2(msb), Self::CC { control, value })
| (Self::CC { control, value }, Self::GeneralPurpose2(msb))
if *control == ControlNumber::GeneralPurpose2LSB as u8 =>
{
Ok(Self::GeneralPurpose2(replace_u14_lsb(*msb, *value)))
}
(Self::GeneralPurpose3(msb), Self::CC { control, value })
| (Self::CC { control, value }, Self::GeneralPurpose3(msb))
if *control == ControlNumber::GeneralPurpose3LSB as u8 =>
{
Ok(Self::GeneralPurpose3(replace_u14_lsb(*msb, *value)))
}
(Self::GeneralPurpose4(msb), Self::CC { control, value })
| (Self::CC { control, value }, Self::GeneralPurpose4(msb))
if *control == ControlNumber::GeneralPurpose4LSB as u8 =>
{
Ok(Self::GeneralPurpose4(replace_u14_lsb(*msb, *value)))
}
(
Self::CCHighRes {
control1,
control2,
value: msb,
},
Self::CC { control, value },
)
| (
Self::CC { control, value },
Self::CCHighRes {
control1,
control2,
value: msb,
},
) if control == control2 => Ok(Self::CCHighRes {
control1: *control1,
control2: *control2,
value: replace_u14_lsb(*msb, *value),
}),
(
Self::CC {
control: ctrl1,
value: val1,
},
Self::CC {
control: ctrl2,
value: val2,
},
) => {
let ((ctrl_lsb, ctrl_msb), (val_lsb, val_msb)) = if ctrl1 < ctrl2 {
((*ctrl1, *ctrl2), (*val1, *val2))
} else {
((*ctrl2, *ctrl1), (*val2, *val1))
};
if ctrl_lsb == ControlNumber::NonRegisteredParameterLSB as u8
&& ctrl_msb == ControlNumber::NonRegisteredParameter as u8
{
Ok(Self::Parameter(Parameter::Unregistered(u14_from_u7s(
val_msb, val_lsb,
))))
} else if ctrl_lsb == ControlNumber::RegisteredParameterLSB as u8
&& ctrl_msb == ControlNumber::RegisteredParameter as u8
{
Ok(Self::Parameter(Parameter::maybe_extend_cc(
val_msb, val_lsb,
)?))
} else {
Err(())
}
}
(Self::Parameter(param), Self::CC { control, value })
| (Self::CC { control, value }, Self::Parameter(param))
if *control == ControlNumber::DataEntryLSB as u8 =>
{
Ok(Self::Parameter(param.maybe_extend(None, Some(*value))?))
}
(Self::Parameter(param), Self::DataEntry(value))
| (Self::DataEntry(value), Self::Parameter(param)) => {
Ok(Self::Parameter(param.maybe_extend(Some(*value), None)?))
}
_ => Err(()),
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Parameter {
Unregistered(u16),
Null,
PitchBendSensitivity,
PitchBendSensitivityEntry(u8, u8),
FineTuning,
FineTuningEntry(i16),
CoarseTuning,
CoarseTuningEntry(i8),
TuningProgramSelect,
TuningProgramSelectEntry(u8),
TuningBankSelect,
TuningBankSelectEntry(u8),
ModulationDepthRange,
ModulationDepthRangeEntry(u16),
PolyphonicExpression,
PolyphonicExpressionEntry(u8),
AzimuthAngle3DSound,
AzimuthAngle3DSoundEntry(u16),
ElevationAngle3DSound,
ElevationAngle3DSoundEntry(u16),
Gain3DSound,
Gain3DSoundEntry(u16),
DistanceRatio3DSound,
DistanceRatio3DSoundEntry(u16),
MaxiumumDistance3DSound,
MaxiumumDistance3DSoundEntry(u16),
GainAtMaxiumumDistance3DSound,
GainAtMaxiumumDistance3DSoundEntry(u16),
ReferenceDistanceRatio3DSound,
ReferenceDistanceRatio3DSoundEntry(u16),
PanSpreadAngle3DSound,
PanSpreadAngle3DSoundEntry(u16),
RollAngle3DSound,
RollAngle3DSoundEntry(u16),
}
impl Parameter {
fn extend_midi_running(&self, v: &mut Vec<u8>) {
match self {
Self::Null => {
v.push(100);
v.push(0x7F);
v.push(101);
v.push(0x7F);
}
Self::PitchBendSensitivity => {
v.push(100);
v.push(0);
v.push(101);
v.push(0);
}
Self::PitchBendSensitivityEntry(c, f) => {
Self::PitchBendSensitivity.extend_midi_running(v);
v.push(6);
v.push(*c);
v.push(6 + 32);
v.push((*f).min(100));
}
Self::FineTuning => {
v.push(100);
v.push(1);
v.push(101);
v.push(0);
}
Self::FineTuningEntry(x) => {
Self::FineTuning.extend_midi_running(v);
let [msb, lsb] = i_to_u14(*x);
v.push(6);
v.push(msb);
v.push(6 + 32);
v.push(lsb);
}
Self::CoarseTuning => {
v.push(100);
v.push(2);
v.push(101);
v.push(0);
}
Self::CoarseTuningEntry(x) => {
Self::CoarseTuning.extend_midi_running(v);
let msb = i_to_u7(*x);
v.push(6);
v.push(msb);
v.push(6 + 32);
v.push(0);
}
Self::TuningProgramSelect => {
v.push(100);
v.push(3);
v.push(101);
v.push(0);
}
Self::TuningProgramSelectEntry(x) => {
Self::TuningProgramSelect.extend_midi_running(v);
v.push(6);
v.push(*x);
}
Self::TuningBankSelect => {
v.push(100);
v.push(4);
v.push(101);
v.push(0);
}
Self::TuningBankSelectEntry(x) => {
Self::TuningBankSelect.extend_midi_running(v);
v.push(6);
v.push(*x);
}
Self::ModulationDepthRange => {
v.push(100);
v.push(5);
v.push(101);
v.push(0);
}
Self::ModulationDepthRangeEntry(x) => {
Self::ModulationDepthRange.extend_midi_running(v);
ControlChange::high_res_cc(v, 6, *x);
}
Self::PolyphonicExpression => {
v.push(100);
v.push(6);
v.push(101);
v.push(0);
}
Self::PolyphonicExpressionEntry(x) => {
Self::PolyphonicExpression.extend_midi_running(v);
v.push(6);
v.push((*x).min(16));
}
Self::AzimuthAngle3DSound => {
v.push(100);
v.push(0);
v.push(101);
v.push(61); }
Self::AzimuthAngle3DSoundEntry(x) => {
Self::AzimuthAngle3DSound.extend_midi_running(v);
ControlChange::high_res_cc(v, 6, *x);
}
Self::ElevationAngle3DSound => {
v.push(100);
v.push(1);
v.push(101);
v.push(61); }
Self::ElevationAngle3DSoundEntry(x) => {
Self::ElevationAngle3DSound.extend_midi_running(v);
ControlChange::high_res_cc(v, 6, *x);
}
Self::Gain3DSound => {
v.push(100);
v.push(2);
v.push(101);
v.push(61); }
Self::Gain3DSoundEntry(x) => {
Self::Gain3DSound.extend_midi_running(v);
ControlChange::high_res_cc(v, 6, *x);
}
Self::DistanceRatio3DSound => {
v.push(100);
v.push(3);
v.push(101);
v.push(61); }
Self::DistanceRatio3DSoundEntry(x) => {
Self::DistanceRatio3DSound.extend_midi_running(v);
ControlChange::high_res_cc(v, 6, *x);
}
Self::MaxiumumDistance3DSound => {
v.push(100);
v.push(4);
v.push(101);
v.push(61); }
Self::MaxiumumDistance3DSoundEntry(x) => {
Self::MaxiumumDistance3DSound.extend_midi_running(v);
ControlChange::high_res_cc(v, 6, *x);
}
Self::GainAtMaxiumumDistance3DSound => {
v.push(100);
v.push(5);
v.push(101);
v.push(61); }
Self::GainAtMaxiumumDistance3DSoundEntry(x) => {
Self::GainAtMaxiumumDistance3DSound.extend_midi_running(v);
ControlChange::high_res_cc(v, 6, *x);
}
Self::ReferenceDistanceRatio3DSound => {
v.push(100);
v.push(6);
v.push(101);
v.push(61); }
Self::ReferenceDistanceRatio3DSoundEntry(x) => {
Self::ReferenceDistanceRatio3DSound.extend_midi_running(v);
ControlChange::high_res_cc(v, 6, *x);
}
Self::PanSpreadAngle3DSound => {
v.push(100);
v.push(7);
v.push(101);
v.push(61); }
Self::PanSpreadAngle3DSoundEntry(x) => {
Self::PanSpreadAngle3DSound.extend_midi_running(v);
ControlChange::high_res_cc(v, 6, *x);
}
Self::RollAngle3DSound => {
v.push(100);
v.push(8);
v.push(101);
v.push(61); }
Self::RollAngle3DSoundEntry(x) => {
Self::RollAngle3DSound.extend_midi_running(v);
ControlChange::high_res_cc(v, 6, *x);
}
Self::Unregistered(x) => {
let [msb, lsb] = to_u14(*x);
v.push(98);
v.push(lsb);
v.push(99);
v.push(msb);
}
}
}
fn maybe_extend_cc(msb: u8, lsb: u8) -> Result<Self, ()> {
match (msb, lsb) {
(0x7F, 0x7F) => Ok(Self::Null),
(0, 0) => Ok(Self::PitchBendSensitivity),
(0, 1) => Ok(Self::FineTuning),
(0, 2) => Ok(Self::CoarseTuning),
(0, 3) => Ok(Self::TuningProgramSelect),
(0, 4) => Ok(Self::TuningBankSelect),
(0, 5) => Ok(Self::ModulationDepthRange),
(0, 6) => Ok(Self::PolyphonicExpression),
(61, 0) => Ok(Self::AzimuthAngle3DSound),
(61, 1) => Ok(Self::ElevationAngle3DSound),
(61, 2) => Ok(Self::Gain3DSound),
(61, 3) => Ok(Self::DistanceRatio3DSound),
(61, 4) => Ok(Self::MaxiumumDistance3DSound),
(61, 5) => Ok(Self::GainAtMaxiumumDistance3DSound),
(61, 6) => Ok(Self::ReferenceDistanceRatio3DSound),
(61, 7) => Ok(Self::PanSpreadAngle3DSound),
(61, 8) => Ok(Self::RollAngle3DSound),
_ => Err(()),
}
}
fn maybe_extend(&self, msb: Option<u16>, lsb: Option<u8>) -> Result<Self, ()> {
match self {
Self::PitchBendSensitivity => Ok(Self::PitchBendSensitivityEntry(
msb.map_or(0, |v| (v >> 7) as u8),
lsb.unwrap_or(0),
)),
Self::PitchBendSensitivityEntry(v1, v2) => Ok(Self::PitchBendSensitivityEntry(
msb.map_or(*v1, |v| v as u8),
lsb.unwrap_or(*v2),
)),
Self::FineTuning => Ok(Self::FineTuningEntry(i14_from_u7s(
msb.map_or(0, |v| (v >> 7) as u8),
lsb.unwrap_or(0),
))),
Self::FineTuningEntry(v) => Ok(Self::FineTuningEntry(i14_from_u7s(
msb.map_or(i_to_u14(*v)[0], |v| v as u8),
lsb.unwrap_or(i_to_u14(*v)[1]),
))),
Self::CoarseTuning => Ok(Self::CoarseTuningEntry(msb.map_or(0, |v| u7_to_i(v as u8)))),
Self::CoarseTuningEntry(v) => Ok(Self::CoarseTuningEntry(
msb.map_or(*v, |v| u7_to_i(v as u8)),
)),
Self::TuningProgramSelect => {
Ok(Self::TuningProgramSelectEntry(msb.map_or(0, |v| v as u8)))
}
Self::TuningProgramSelectEntry(v) => {
Ok(Self::TuningProgramSelectEntry(msb.map_or(*v, |v| v as u8)))
}
Self::TuningBankSelect => Ok(Self::TuningBankSelectEntry(msb.map_or(0, |v| v as u8))),
Self::TuningBankSelectEntry(v) => {
Ok(Self::TuningBankSelectEntry(msb.map_or(*v, |v| v as u8)))
}
Self::ModulationDepthRange => Ok(Self::ModulationDepthRangeEntry(replace_u14_lsb(
msb.unwrap_or(0),
lsb.unwrap_or(0),
))),
Self::ModulationDepthRangeEntry(v) => Ok(Self::ModulationDepthRangeEntry(
replace_u14_lsb(msb.unwrap_or(*v), lsb.unwrap_or((*v as u8) & 0b01111111)),
)),
Self::PolyphonicExpression => {
Ok(Self::PolyphonicExpressionEntry(msb.map_or(0, |v| v as u8)))
}
Self::PolyphonicExpressionEntry(v) => {
Ok(Self::PolyphonicExpressionEntry(msb.map_or(*v, |v| v as u8)))
}
Self::AzimuthAngle3DSound => Ok(Self::AzimuthAngle3DSoundEntry(replace_u14_lsb(
msb.unwrap_or(0),
lsb.unwrap_or(0),
))),
Self::AzimuthAngle3DSoundEntry(v) => Ok(Self::AzimuthAngle3DSoundEntry(
replace_u14_lsb(msb.unwrap_or(*v), lsb.unwrap_or((*v as u8) & 0b01111111)),
)),
Self::ElevationAngle3DSound => Ok(Self::ElevationAngle3DSoundEntry(replace_u14_lsb(
msb.unwrap_or(0),
lsb.unwrap_or(0),
))),
Self::ElevationAngle3DSoundEntry(v) => Ok(Self::ElevationAngle3DSoundEntry(
replace_u14_lsb(msb.unwrap_or(*v), lsb.unwrap_or((*v as u8) & 0b01111111)),
)),
Self::Gain3DSound => Ok(Self::Gain3DSoundEntry(replace_u14_lsb(
msb.unwrap_or(0),
lsb.unwrap_or(0),
))),
Self::Gain3DSoundEntry(v) => Ok(Self::Gain3DSoundEntry(replace_u14_lsb(
msb.unwrap_or(*v),
lsb.unwrap_or((*v as u8) & 0b01111111),
))),
Self::DistanceRatio3DSound => Ok(Self::DistanceRatio3DSoundEntry(replace_u14_lsb(
msb.unwrap_or(0),
lsb.unwrap_or(0),
))),
Self::DistanceRatio3DSoundEntry(v) => Ok(Self::DistanceRatio3DSoundEntry(
replace_u14_lsb(msb.unwrap_or(*v), lsb.unwrap_or((*v as u8) & 0b01111111)),
)),
Self::MaxiumumDistance3DSound => Ok(Self::MaxiumumDistance3DSoundEntry(
replace_u14_lsb(msb.unwrap_or(0), lsb.unwrap_or(0)),
)),
Self::MaxiumumDistance3DSoundEntry(v) => Ok(Self::MaxiumumDistance3DSoundEntry(
replace_u14_lsb(msb.unwrap_or(*v), lsb.unwrap_or((*v as u8) & 0b01111111)),
)),
Self::GainAtMaxiumumDistance3DSound => Ok(Self::GainAtMaxiumumDistance3DSoundEntry(
replace_u14_lsb(msb.unwrap_or(0), lsb.unwrap_or(0)),
)),
Self::GainAtMaxiumumDistance3DSoundEntry(v) => {
Ok(Self::GainAtMaxiumumDistance3DSoundEntry(replace_u14_lsb(
msb.unwrap_or(*v),
lsb.unwrap_or((*v as u8) & 0b01111111),
)))
}
Self::ReferenceDistanceRatio3DSound => Ok(Self::ReferenceDistanceRatio3DSoundEntry(
replace_u14_lsb(msb.unwrap_or(0), lsb.unwrap_or(0)),
)),
Self::ReferenceDistanceRatio3DSoundEntry(v) => {
Ok(Self::ReferenceDistanceRatio3DSoundEntry(replace_u14_lsb(
msb.unwrap_or(*v),
lsb.unwrap_or((*v as u8) & 0b01111111),
)))
}
Self::PanSpreadAngle3DSound => Ok(Self::PanSpreadAngle3DSoundEntry(replace_u14_lsb(
msb.unwrap_or(0),
lsb.unwrap_or(0),
))),
Self::PanSpreadAngle3DSoundEntry(v) => Ok(Self::PanSpreadAngle3DSoundEntry(
replace_u14_lsb(msb.unwrap_or(*v), lsb.unwrap_or((*v as u8) & 0b01111111)),
)),
Self::RollAngle3DSound => Ok(Self::RollAngle3DSoundEntry(replace_u14_lsb(
msb.unwrap_or(0),
lsb.unwrap_or(0),
))),
Self::RollAngle3DSoundEntry(v) => Ok(Self::RollAngle3DSoundEntry(replace_u14_lsb(
msb.unwrap_or(*v),
lsb.unwrap_or((*v as u8) & 0b01111111),
))),
_ => Err(()),
}
}
}
#[cfg(test)]
mod tests {
use crate::*;
use alloc::vec;
#[test]
fn serialize_channel_voice_msg() {
assert_eq!(
MidiMsg::ChannelVoice {
channel: Channel::Ch1,
msg: ChannelVoiceMsg::NoteOn {
note: 0x88,
velocity: 0xff
}
}
.to_midi(),
vec![0x90, 0x7f, 127]
);
assert_eq!(
MidiMsg::RunningChannelVoice {
channel: Channel::Ch10,
msg: ChannelVoiceMsg::PitchBend { bend: 0xff44 }
}
.to_midi(),
vec![0x7f, 0x7f]
);
assert_eq!(
MidiMsg::ChannelVoice {
channel: Channel::Ch10,
msg: ChannelVoiceMsg::PitchBend { bend: 1000 }
}
.to_midi(),
vec![0xE9, 0x68, 0x07]
);
assert_eq!(
MidiMsg::ChannelVoice {
channel: Channel::Ch2,
msg: ChannelVoiceMsg::ControlChange {
control: ControlChange::Volume(1000)
}
}
.to_midi(),
vec![0xB1, 7, 0x07, 39, 0x68]
);
assert_eq!(
MidiMsg::ChannelVoice {
channel: Channel::Ch4,
msg: ChannelVoiceMsg::ControlChange {
control: ControlChange::CC {
control: 85,
value: 77
}
}
}
.to_midi(),
vec![0xB3, 85, 77]
);
assert_eq!(
MidiMsg::ChannelVoice {
channel: Channel::Ch2,
msg: ChannelVoiceMsg::ControlChange {
control: ControlChange::CCHighRes {
control1: 3,
control2: 35,
value: 1000
}
}
}
.to_midi(),
vec![0xB1, 3, 0x07, 35, 0x68]
);
assert_eq!(
MidiMsg::ChannelVoice {
channel: Channel::Ch3,
msg: ChannelVoiceMsg::ControlChange {
control: ControlChange::TogglePortamento(true)
}
}
.to_midi(),
vec![0xB2, 65, 0x7f]
);
assert_eq!(
MidiMsg::ChannelVoice {
channel: Channel::Ch2,
msg: ChannelVoiceMsg::ControlChange {
control: ControlChange::Parameter(Parameter::FineTuning)
}
}
.to_midi(),
vec![0xB1, 100, 0x01, 101, 0x00]
);
assert_eq!(
MidiMsg::ChannelVoice {
channel: Channel::Ch2,
msg: ChannelVoiceMsg::ControlChange {
control: ControlChange::Parameter(Parameter::Unregistered(1000))
}
}
.to_midi(),
vec![0xB1, 98, 0x68, 99, 0x07]
);
}
#[test]
fn deserialize_channel_voice_msg() {
let mut ctx = ReceiverContext::new().complex_cc();
test_serialization(
MidiMsg::ChannelVoice {
channel: Channel::Ch1,
msg: ChannelVoiceMsg::NoteOn {
note: 0x7f,
velocity: 0x7f,
},
},
&mut ctx,
);
test_serialization(
MidiMsg::ChannelVoice {
channel: Channel::Ch10,
msg: ChannelVoiceMsg::PitchBend { bend: 1000 },
},
&mut ctx,
);
test_serialization(
MidiMsg::ChannelVoice {
channel: Channel::Ch2,
msg: ChannelVoiceMsg::ControlChange {
control: ControlChange::Volume(1000),
},
},
&mut ctx,
);
test_serialization(
MidiMsg::ChannelVoice {
channel: Channel::Ch4,
msg: ChannelVoiceMsg::ControlChange {
control: ControlChange::CC {
control: 85,
value: 77,
},
},
},
&mut ctx,
);
test_serialization(
MidiMsg::ChannelVoice {
channel: Channel::Ch2,
msg: ChannelVoiceMsg::ControlChange {
control: ControlChange::CCHighRes {
control1: 3,
control2: 35,
value: 1000,
},
},
},
&mut ctx,
);
test_serialization(
MidiMsg::ChannelVoice {
channel: Channel::Ch3,
msg: ChannelVoiceMsg::ControlChange {
control: ControlChange::TogglePortamento(true),
},
},
&mut ctx,
);
test_serialization(
MidiMsg::ChannelVoice {
channel: Channel::Ch2,
msg: ChannelVoiceMsg::ControlChange {
control: ControlChange::Parameter(Parameter::FineTuning),
},
},
&mut ctx,
);
test_serialization(
MidiMsg::ChannelVoice {
channel: Channel::Ch2,
msg: ChannelVoiceMsg::ControlChange {
control: ControlChange::Parameter(Parameter::Unregistered(1000)),
},
},
&mut ctx,
);
test_serialization(
MidiMsg::ChannelVoice {
channel: Channel::Ch3,
msg: ChannelVoiceMsg::HighResNoteOn {
note: 77,
velocity: 1000,
},
},
&mut ctx,
);
test_serialization(
MidiMsg::ChannelVoice {
channel: Channel::Ch2,
msg: ChannelVoiceMsg::ControlChange {
control: ControlChange::Parameter(Parameter::FineTuningEntry(-30)),
},
},
&mut ctx,
);
test_serialization(
MidiMsg::ChannelVoice {
channel: Channel::Ch2,
msg: ChannelVoiceMsg::ControlChange {
control: ControlChange::Parameter(Parameter::Gain3DSoundEntry(1001)),
},
},
&mut ctx,
);
test_serialization(
MidiMsg::ChannelVoice {
channel: Channel::Ch2,
msg: ChannelVoiceMsg::ControlChange {
control: ControlChange::Parameter(Parameter::PitchBendSensitivityEntry(4, 78)),
},
},
&mut ctx,
);
test_serialization(
MidiMsg::ChannelVoice {
channel: Channel::Ch2,
msg: ChannelVoiceMsg::ControlChange {
control: ControlChange::GeneralPurpose1(50),
},
},
&mut ctx,
);
}
#[test]
fn test_cc_control_and_value() {
assert_eq!(
ControlChange::CC {
control: 20,
value: 40
}
.control(),
20
);
assert_eq!(
ControlChange::CC {
control: 20,
value: 40
}
.value(),
40
);
assert_eq!(
ControlChange::CC {
control: 20,
value: 40
}
.value_high_res(),
40 << 7
);
assert_eq!(ControlChange::Breath(40 << 7).control(), 2);
assert_eq!(ControlChange::Breath(40 << 7).value(), 40);
assert_eq!(ControlChange::Breath(40 << 7).value_high_res(), 40 << 7);
}
#[test]
fn test_cc_to_complex_and_to_simple() {
assert_eq!(
ControlChange::CC {
control: 2,
value: 40
}
.to_complex(),
ControlChange::Breath(40 << 7)
);
assert_eq!(
ControlChange::Breath(40 << 7).to_simple(),
ControlChange::CC {
control: 2,
value: 40
}
);
assert_eq!(
ControlChange::Breath(40 << 7).to_simple_high_res(),
ControlChange::CCHighRes {
control1: 2,
control2: 34,
value: 40 << 7
}
);
assert_eq!(
ControlChange::CC {
control: 20,
value: 40
}
.to_complex(),
ControlChange::CCHighRes {
control1: 20,
control2: 52,
value: 40 << 7,
}
);
assert_eq!(
ControlChange::CCHighRes {
control1: 20,
control2: 52,
value: 40 << 7,
}
.to_simple(),
ControlChange::CC {
control: 20,
value: 40,
},
);
assert_eq!(
ControlChange::CCHighRes {
control1: 20,
control2: 52,
value: 40 << 7,
}
.to_simple_high_res(),
ControlChange::CCHighRes {
control1: 20,
control2: 52,
value: 40 << 7,
}
);
}
}