Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
153 changes: 153 additions & 0 deletions midi2/src/channel_voice2/note_on.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,59 @@ struct NoteOn {
attribute: Option<Attribute>,
}

/// Converts a CV2 Note On message to CV1 Note On message,
/// storing the result in a pre-instantiated CV1 Note On.
///
/// Note: Due to 0 velocity Note On messages being considered
/// a Note Off in CV1 but not in CV2, a 0 velocity CV2 message
/// will be converted to a 1 velocity CV1 message.
#[cfg(feature = "channel-voice1")]
impl<
A: crate::buffer::Buffer<Unit = u32>,
B: crate::buffer::Buffer<Unit = u32> + crate::buffer::BufferMut,
> Into<crate::channel_voice1::NoteOn<B>> for (NoteOn<A>, crate::channel_voice1::NoteOn<B>)
{
fn into(self) -> crate::channel_voice1::NoteOn<B> {
use crate::traits::{Channeled, Grouped};

let (src, mut dest) = self;
dest.set_group(src.group());
dest.set_channel(src.channel());
dest.set_note_number(src.note_number());
match src.velocity() {
// Since 0 velocity doesn't trigger a note off in CV2 like in CV1,
// we need to convert 0 velocity in CV2 to 1 velocity in CV1.
// See MIDI 2.0 spec 7.4.2: MIDI 2.0 Note On Message -> Velocity
// for details.
0 => dest.set_velocity(u7::new(0x01)),
_ => dest.set_velocity(u7::new((src.velocity() >> 9) as u8)),
}
dest
}
}

/// Converts a CV2 Note On message to a CV1 Note On message.
/// This is only infallible for resizable buffers.
/// For fixed size buffers, see the Into impl for (CV2, CV1).
///
/// Note: Due to 0 velocity Note On messages being considered
/// a Note Off in CV1 but not in CV2, a 0 velocity CV2 message
/// will be converted to a 1 velocity CV1 message.
#[cfg(feature = "channel-voice1")]
impl<
A: crate::buffer::Buffer<Unit = u32>,
B: crate::buffer::Buffer<Unit = u32>
+ crate::buffer::BufferMut
+ crate::buffer::BufferDefault
+ crate::buffer::BufferResize,
> Into<crate::channel_voice1::NoteOn<B>> for NoteOn<A>
{
fn into(self) -> crate::channel_voice1::NoteOn<B> {
let dest = crate::channel_voice1::NoteOn::<B>::new();
(self, dest).into()
}
}

#[cfg(test)]
mod tests {
use super::*;
Expand Down Expand Up @@ -96,4 +149,104 @@ mod tests {
Some(Attribute::Pitch7_9(Fixed7_9::from_bits(0b1110100110001010))),
);
}

#[test]
fn into_midi_1() {
use crate::channel_voice1;
use crate::traits::{Channeled, Grouped};
use std::vec::Vec;

let mut message2 = NoteOn::<[u32; 4]>::new();
message2.set_group(u4::new(0x8));
message2.set_channel(u4::new(0x8));
message2.set_note_number(u7::new(0x5E));
message2.set_velocity(0x8000);

assert_eq!(message2, NoteOn([0x4898_5E00, 0x8000_0000, 0x0, 0x0]),);

let mut message1 = channel_voice1::NoteOn::<Vec<u32>>::new();
message1.set_group(u4::new(0x8));
message1.set_channel(u4::new(0x8));
message1.set_note_number(u7::new(0x5E));
message1.set_velocity(u7::new(0x40));

let message21: channel_voice1::NoteOn<Vec<u32>> = message2.into();

assert_eq!(message21, message1);
}

#[test]
fn into_midi_1_zero_velocity() {
use crate::channel_voice1;
use crate::traits::{Channeled, Grouped};
use std::vec::Vec;

let mut message2 = NoteOn::<[u32; 4]>::new();
message2.set_group(u4::new(0x8));
message2.set_channel(u4::new(0x8));
message2.set_note_number(u7::new(0x5E));
message2.set_velocity(0x0000);

assert_eq!(message2, NoteOn([0x4898_5E00, 0x0000_0000, 0x0, 0x0]),);

let mut message1 = channel_voice1::NoteOn::<Vec<u32>>::new();
message1.set_group(u4::new(0x8));
message1.set_channel(u4::new(0x8));
message1.set_note_number(u7::new(0x5E));
message1.set_velocity(u7::new(0x01));

let message21: channel_voice1::NoteOn<Vec<u32>> = message2.into();

assert_eq!(message21, message1);
}

#[test]
fn into_midi_1_with_dest() {
use crate::channel_voice1;
use crate::traits::{Channeled, Grouped};

let mut message2 = NoteOn::<[u32; 4]>::new();
message2.set_group(u4::new(0x8));
message2.set_channel(u4::new(0x8));
message2.set_note_number(u7::new(0x5E));
message2.set_velocity(0x8000);

assert_eq!(message2, NoteOn([0x4898_5E00, 0x8000_0000, 0x0, 0x0]),);

let mut message1 = channel_voice1::NoteOn::<[u32; 4]>::new();
message1.set_group(u4::new(0x8));
message1.set_channel(u4::new(0x8));
message1.set_note_number(u7::new(0x5E));
message1.set_velocity(u7::new(0x40));

let message21 = channel_voice1::NoteOn::<[u32; 4]>::new();
let message21: channel_voice1::NoteOn<[u32; 4]> = (message2, message21).into();

assert_eq!(message21, message1);
}

#[test]
fn into_midi_1_zero_velocity_with_dest() {
use crate::channel_voice1;
use crate::traits::{Channeled, Grouped};

let mut message2 = NoteOn::<[u32; 4]>::new();
message2.set_group(u4::new(0x8));
message2.set_channel(u4::new(0x8));
message2.set_note_number(u7::new(0x5E));
message2.set_velocity(0x0000);

assert_eq!(message2, NoteOn([0x4898_5E00, 0x0000_0000, 0x0, 0x0]),);

let mut message1 = channel_voice1::NoteOn::<[u32; 4]>::new();
message1.set_group(u4::new(0x8));
message1.set_channel(u4::new(0x8));
message1.set_note_number(u7::new(0x5E));
message1.set_velocity(u7::new(0x01));

let message21 = channel_voice1::NoteOn::<[u32; 4]>::new();
let message21: channel_voice1::NoteOn<[u32; 4]> = (message2, message21).into();

assert_eq!(message21, message1);
}
}
Loading
Loading