Skip to main content

nice_plug_core/midi/
sysex.rs

1//! Traits for working with MIDI SysEx data.
2
3use std::borrow::{Borrow, BorrowMut};
4use std::fmt::Debug;
5
6/// A type that can be converted to and from byte buffers containing MIDI SysEx messages.
7///
8/// # SysEx buffers
9///
10/// For maximum flexibility this trait works with RAW MIDI messages. This means that status bytes
11/// and end of SysEx (EOX) bytes are included in the input, and should also be included in the
12/// output. A consequence of this is that it is also possible to support system common and system
13/// real time messages as needed, as long as the plugin API supports those.
14///
15/// For example, the message to turn general MIDI mode on is `[0xf0, 0x7e, 0x7f, 0x09, 0x01, 0xf7]`,
16/// and has a length of 6 bytes. Note that this includes the `0xf0` start byte and `0xf7` end byte.
17pub trait SysExMessage: Debug + Clone + PartialEq + Send + Sync {
18    /// The byte array buffer the messages are read from and serialized to. Should be a `[u8; N]`,
19    /// where `N` is the maximum supported message length in bytes. This covers the full message,
20    /// see the trait's docstring for more information.
21    ///
22    /// Ideally this could just be a const generic but Rust doesn't let you use those as array
23    /// lengths just yet.
24    ///
25    /// <https://github.com/rust-lang/rust/issues/60551>
26    type Buffer: Borrow<[u8]> + BorrowMut<[u8]>;
27
28    /// Read a SysEx message from `buffer` and convert it to this message type if supported. This
29    /// covers the full message, see the trait's docstring for more information. `buffer`'s length
30    /// matches the received message. It is not padded to match [`Buffer`][Self::Buffer].
31    fn from_buffer(buffer: &[u8]) -> Option<Self>;
32
33    /// Serialize this message object as a SysEx message in a byte buffer. This returns a buffer
34    /// alongside the message's length in bytes. The buffer may contain padding at the end. This
35    /// should contain the full message including headers and the EOX byte, see the trait's
36    /// docstring for more information.
37    fn to_buffer(self) -> (Self::Buffer, usize);
38}
39
40/// A default implementation plugins that don't need SysEx support can use.
41impl SysExMessage for () {
42    type Buffer = [u8; 0];
43
44    fn from_buffer(_buffer: &[u8]) -> Option<Self> {
45        None
46    }
47
48    fn to_buffer(self) -> (Self::Buffer, usize) {
49        ([], 0)
50    }
51}