#message #midi #data #byte #versatile #wrapping #strong

no-std midi2

人体工程学设计,功能强大,类型安全地包装MIDI 2.0消息数据

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 音频

Download history 575/week @ 2024-05-06 361/week @ 2024-05-13 71/week @ 2024-05-20 150/week @ 2024-06-03 10/week @ 2024-06-10 1/week @ 2024-06-17 40/week @ 2024-07-01 190/week @ 2024-07-15 94/week @ 2024-07-29

每月下载量 284次

MIT/Apache

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 🚧
  • 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