14个版本 (5个重大变更)
0.6.1 | 2024年7月18日 |
---|---|
0.6.0 | 2024年7月18日 |
0.5.4 | 2024年6月5日 |
0.5.3 | 2024年5月17日 |
0.0.0 | 2020年2月5日 |
#29 in 音频
每月下载量 284次
505KB
14K SLoC
🎹 MIDI2 🎹
人体工程学设计,功能强大,类型安全地包装MIDI 2.0消息数据。
此MIDI 2.0实现基于规范的第1.1版。有关数据协议标准的更多详细信息,请参阅官方MIDI 2.0规范。
⚠️ 注意! ⚠️
该crate仍处于alpha阶段,不建议用于生产。
我们欢迎贡献!请参阅CONTRIBUTOR.md
强类型消息包装器
为MIDI 2.0规范中的每个消息提供强类型消息包装器。
use midi2::prelude::*;
// Messages have a simple setter / getter interface
let mut note_on = channel_voice2::NoteOn::<[u32; 4]>::new();
note_on.set_group(u4::new(0x8));
note_on.set_channel(u4::new(0xA));
note_on.set_note_number(u7::new(0x5E));
note_on.set_velocity(0x6A14);
assert_eq!(note_on.group(), u4::new(0x8));
assert_eq!(note_on.channel(), u4::new(0xA));
assert_eq!(note_on.note_number(), u7::new(0x5E));
assert_eq!(note_on.velocity(), 0x6A14);
// Messages wrap an underlying buffer of data which can be read as an
// ordinary slice.
let mut composer_name = flex_data::ComposerName::<Vec<u32>>::new();
composer_name.set_name("Pinch b2b Peverelist");
assert_eq!(
composer_name.data(),
&[
0xD050_0105,
0x5069_6E63,
0x6820_6232,
0x6220_5065,
0xD0D0_0105,
0x7665_7265,
0x6C69_7374,
0x0000_0000,
]);
聚合消息类型
所有消息包装器都分组到聚合枚举类型中。有一个顶级枚举类型可以表示所有消息,还有子枚举类型用于MIDI 2.0规范中指定的每个不同的UMP类型。
fn handle_message(buffer: &[u32]) {
use midi2::prelude::*;
match UmpMessage::try_from(buffer) {
Ok(UmpMessage::ChannelVoice2(m)) => {
println!("Channel Voice2: channel: {}", m.channel());
match m {
channel_voice2::ChannelVoice2::NoteOn(m) => {
println!("Note On! note: {}, velocity: {}", m.note_number(), m.velocity());
}
channel_voice2::ChannelVoice2::NoteOff(m) => {
println!("Note Off! note: {}, velocity: {}", m.note_number(), m.velocity());
}
_ => {}
}
}
Ok(UmpMessage::Sysex7(m)) => {
println!(
"Sysex 7bit: payload: {:?}",
m.payload().collect::<Vec<u7>>()
);
}
Ok(UmpMessage::FlexData(m)) => {
use midi2::flex_data::FlexDataMessage;
println!("FlexData: bank: {:?}", m.bank());
match m {
_ => {}, // further matching on different flex data types
}
}
// further matching on other message types
Err(e) => {
println!("Error parsing ump buffer: {:?}", e);
}
_ => {}
}
}
全面支持Sysex
可以使用MIDI 2.0通用消息包表示Sysex消息。
use midi2::prelude::*;
let mut message = sysex7::Sysex7::<Vec<u32>>::new();
message.set_payload((0u8..30u8).map(u7::new));
message.set_group(u4::new(0xA));
assert_eq!(
message.data(),
&[
0x3A16_0001,
0x0203_0405,
0x3A26_0607,
0x0809_0A0B,
0x3A26_0C0D,
0x0E0F_1011,
0x3A26_1213,
0x1415_1617,
0x3A36_1819,
0x1A1B_1C1D,
],
);
或使用经典的MIDI 2.0字节流。
use midi2::prelude::*;
let mut message = sysex7::Sysex7::<Vec<u8>>::new();
message.set_payload((0u8..30u8).map(u7::new));
assert_eq!(
message.data(),
&[
0xF0, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C,
0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A,
0x1B, 0x1C, 0x1D, 0xF7,
],
);
几乎完全兼容#![no_std]
#![no_std]
是midi2中的首选用法。所有消息类型都可以无分配读取和写入,即使像sysex或flex-data这样的任意长度消息。
您需要设置midi2,不使用默认功能,以便不使用std
功能进行编译。
midi2 = { version = "0.6.1", default-features = false, features = ["channel-voice2", "sysex7"], }
泛型表示
所有消息在其表示上是泛型的。例如,一个简单的非分配用例是在固定大小的数组中表示消息。
use midi2::prelude::*;
let mut message = sysex8::Sysex8::<[u32; 16]>::new();
// in this mode methods which would require a
// buffer resize are fallible
assert_eq!(message.try_set_payload(0..50), Ok(()));
// if there's not enough room in the buffer to
// accommodate the resize then an overflow error is returned.
assert_eq!(message.try_set_payload(0..60), Err(midi2::error::BufferOverflow));
更高级的用例可能涉及创建一个自定义缓冲区,该缓冲区使用区域分配器来支持您的消息。有关更多信息,请参阅[buffe]文档。
借用消息
当从现有缓冲区读取消息时,消息包装器拥有对数据的借用引用,因此不会发生复制或分配。在这种情况下,通用消息缓冲区类型是&[u32]
。
use midi2::prelude::*;
let buffer = [
0xD050_0100_u32,
0x4469_6769,
0x7461_6C20,
0x4175_6469,
0xD090_0100,
0x6F20_576F,
0x726B_7374,
0x6174_696F,
0xD0D0_0100,
0x6E20_2D20,
0x4441_5733,
0x362D_3136,
];
let message = UmpMessage::try_from(&buffer[..]).expect("Valid data");
当然,这意味着此类借用消息是不可变的,并且它们的生存期与原始缓冲区相关联。
为了解决这个问题,可以将消息rebuffered
到不同的通用后置缓冲区类型。
use midi2::{
prelude::*,
channel_voice2::NoteOn,
};
let mut owned: NoteOn::<[u32; 4]> = {
let buffer = [0x4898_5E03_u32, 0x6A14_E98A];
// the borrowed message is immutable and cannot outlive `buffer`
let borrowed = NoteOn::try_from(&buffer[..]).expect("Data is valid");
borrowed.rebuffer_into()
};
// the owned message is mutable and liberated from the buffer lifetime.
owned.set_channel(u4::new(0x9));
assert_eq!(owned.data(), &[0x4899_5E03, 0x6A14_E98A])
支持经典MIDI字节流消息
可以表示为经典MIDI字节流格式的消息也受到支持。为此,只需使用覆盖u8
而不是u32
的底层缓冲区即可!✨🎩
use midi2::prelude::*;
let mut message = channel_voice1::ChannelPressure::<[u8; 3]>::new();
message.set_channel(u4::new(0x6));
message.set_pressure(u7::new(0x09));
assert_eq!(message.data(), &[0xD6, 0x09]);
以字节表示的消息可以使用转换特征转换为ump,反之亦然。
use midi2::{
prelude::*,
channel_voice1::ChannelPressure,
};
let message = ChannelPressure::<[u8; 3]>::new();
let message: ChannelPressure<[u32; 4]> = message.into_ump();
assert_eq!(message.data(), &[0x20D0_0000]);
Cargo功能
提供了几个编译时功能,您可以根据需要启用或禁用以自定义功能。
以下是可用功能的列表
-
默认
:- std - 包含[buffer]集成以支持
std::vec::Vec
,并启用为返回std::string::String
值的值分配获取器。 - channel-voice2 - 包含MIDI 2.0通道声音消息类型的消息包装器。
- sysex7 - 包含MIDI 7位系统专用消息类型的消息包装器。
- ci - 🚧 WIP 🚧
- std - 包含[buffer]集成以支持
-
optional
:这些功能默认未启用,您可以通过将它们添加到您的Cargo.toml
中来包含它们。- flex-data - 包含MIDI 2.0 Flex Data消息类型的消息包装器。
- channel-voice1 - 包含经典MIDI通道声音消息类型的消息包装器。
- sysex8 - 包含MIDI 2.0 System Exclusive 8位消息类型的消息包装器。
- system-common - 包含MIDI 2.0 System Common / System Real Time消息类型的消息包装器。
- ump-stream - 包含MIDI 2.0 Ump Stream消息类型的消息包装器。
依赖项
~3MB
~64K SLoC