Skip to content

Commit 282e1f8

Browse files
committed
fix: midi2 crate has no readme
1 parent 8d1ef32 commit 282e1f8

File tree

3 files changed

+291
-292
lines changed

3 files changed

+291
-292
lines changed

README.md

Lines changed: 290 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,290 @@
1-
midi2/README.md
1+
# 🎹 MIDI2 🎹
2+
3+
[![crates.io](https://img.shields.io/crates/v/midi2.svg)](https://crates.io/crates/midi2)
4+
[![docs.rs](https://docs.rs/midi2/badge.svg)](https://docs.rs/midi2)
5+
[![pre-commit](https://img.shields.io/badge/pre--commit-enabled-brightgreen?logo=pre-commit)](https://github.com/pre-commit/pre-commit)
6+
[![Conventional Commits](https://img.shields.io/badge/Conventional%20Commits-1.0.0-%23FE5196?logo=conventionalcommits&logoColor=white)](https://conventionalcommits.org)
7+
![Contributions Welcome](https://img.shields.io/badge/contributions-welcome-brightgreen.svg)
8+
9+
Ergonomic, versatile, strong types wrapping MIDI 2.0 message data.
10+
11+
This implementation of MIDI 2.0 is based on the 1.1 revision of the specifications.
12+
See [the official MIDI 2.0 specification](https://midi.org/)
13+
for more details on the data protocol standard.
14+
15+
> [!CAUTION]
16+
>
17+
> This project is still in early development.
18+
> Expect breaking changes and bugs, and please report any issues you encounter.
19+
20+
We would welcome contributions!
21+
Please refer to the [CONTRIBUTOR.md](CONTRIBUTOR.md)
22+
23+
## Strongly Typed Message Wrappers
24+
25+
A strongly typed message wrapper is provided for every message in the MIDI 2.0 specification.
26+
27+
28+
```rust
29+
use midi2::prelude::*;
30+
31+
// Messages have a simple setter / getter interface
32+
let mut note_on = channel_voice2::NoteOn::<[u32; 4]>::new();
33+
note_on.set_group(u4::new(0x8));
34+
note_on.set_channel(u4::new(0xA));
35+
note_on.set_note_number(u7::new(0x5E));
36+
note_on.set_velocity(0x6A14);
37+
38+
assert_eq!(note_on.group(), u4::new(0x8));
39+
assert_eq!(note_on.channel(), u4::new(0xA));
40+
assert_eq!(note_on.note_number(), u7::new(0x5E));
41+
assert_eq!(note_on.velocity(), 0x6A14);
42+
assert_eq!(note_on.data(), &[0x489A_5E00, 0x6A14_0000]);
43+
44+
// Messages wrap an underlying buffer of data which can be read as an
45+
// ordinary slice.
46+
let mut composer_name = flex_data::ComposerName::<Vec<u32>>::new();
47+
composer_name.set_name("Pinch b2b Peverelist");
48+
assert_eq!(
49+
composer_name.data(),
50+
&[
51+
0xD050_0105,
52+
0x5069_6E63,
53+
0x6820_6232,
54+
0x6220_5065,
55+
0xD0D0_0105,
56+
0x7665_7265,
57+
0x6C69_7374,
58+
0x0000_0000,
59+
]
60+
);
61+
```
62+
63+
## Aggregate Message Types
64+
65+
All message wrappers are grouped into aggregate enum types.
66+
There's a top level enum type which can represent all messages,
67+
and there's sub enum types for each different UMP type specified
68+
by the MIDI 2.0 specification.
69+
70+
```rust
71+
fn handle_message(buffer: &[u32]) {
72+
use midi2::prelude::*;
73+
74+
match UmpMessage::try_from(buffer) {
75+
Ok(UmpMessage::ChannelVoice2(m)) => {
76+
println!("Channel Voice2: channel: {}", m.channel());
77+
match m {
78+
channel_voice2::ChannelVoice2::NoteOn(m) => {
79+
println!("Note On! note: {}, velocity: {}", m.note_number(), m.velocity());
80+
}
81+
channel_voice2::ChannelVoice2::NoteOff(m) => {
82+
println!("Note Off! note: {}, velocity: {}", m.note_number(), m.velocity());
83+
}
84+
_ => {}
85+
}
86+
}
87+
Ok(UmpMessage::Sysex7(m)) => {
88+
println!(
89+
"Sysex 7bit: payload: {:?}",
90+
m.payload().collect::<Vec<u7>>()
91+
);
92+
}
93+
Ok(UmpMessage::FlexData(m)) => {
94+
use midi2::flex_data::FlexDataMessage;
95+
96+
println!("FlexData: bank: {:?}", m.bank());
97+
match m {
98+
_ => {}, // further matching on different flex data types
99+
}
100+
}
101+
// further matching on other message types
102+
Err(e) => {
103+
println!("Error parsing ump buffer: {:?}", e);
104+
}
105+
_ => {}
106+
}
107+
}
108+
```
109+
110+
## Full Sysex Support
111+
112+
Sysex message can be represented with MIDI 2.0 Universal Message Packets.
113+
114+
```rust
115+
use midi2::prelude::*;
116+
117+
let mut message = sysex7::Sysex7::<Vec<u32>>::new();
118+
message.set_payload((0u8..30u8).map(u7::new));
119+
message.set_group(u4::new(0xA));
120+
121+
assert_eq!(
122+
message.data(),
123+
&[
124+
0x3A16_0001,
125+
0x0203_0405,
126+
0x3A26_0607,
127+
0x0809_0A0B,
128+
0x3A26_0C0D,
129+
0x0E0F_1011,
130+
0x3A26_1213,
131+
0x1415_1617,
132+
0x3A36_1819,
133+
0x1A1B_1C1D,
134+
],
135+
);
136+
```
137+
138+
Or with classical MIDI 2.0 byte streams.
139+
140+
```rust
141+
use midi2::prelude::*;
142+
143+
let mut message = sysex7::Sysex7::<Vec<u8>>::new();
144+
message.set_payload((0u8..30u8).map(u7::new));
145+
146+
assert_eq!(
147+
message.data(),
148+
&[
149+
0xF0, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C,
150+
0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A,
151+
0x1B, 0x1C, 0x1D, 0xF7,
152+
],
153+
);
154+
```
155+
156+
## Almost Entirely `#![no_std]` Friendly
157+
158+
`#![no_std]` is a first class use case in midi2.
159+
All message types can be read and written without allocation,
160+
even messages of arbitrary length, like sysex or flex-data.
161+
162+
You'll want to setup midi2 without default features to compile
163+
without the `std` feature.
164+
165+
```toml
166+
midi2 = { version = "0.8.0", default-features = false, features = ["channel-voice2", "sysex7"], }
167+
```
168+
169+
### Generic Representation
170+
171+
All messages are generic over their representation.
172+
For example, a simple non-allocating use case would be to
173+
represent messages within a fixed size array.
174+
175+
```rust
176+
use midi2::prelude::*;
177+
178+
let mut message = sysex8::Sysex8::<[u32; 16]>::new();
179+
180+
// in this mode methods which would require a
181+
// buffer resize are fallible
182+
assert_eq!(message.try_set_payload(0..50), Ok(()));
183+
184+
// if there's not enough room in the buffer to
185+
// accommodate the resize then an overflow error is returned.
186+
assert_eq!(message.try_set_payload(0..60), Err(midi2::error::BufferOverflow));
187+
```
188+
189+
A more advanced use case might be to make a custom buffer which
190+
uses an arena allocator to back your messages.
191+
See the [buffer] docs for more info.
192+
193+
### Borrowed Messages
194+
195+
When reading messages from an existing buffer, the message wrappers
196+
own a borrowed reference to the data, so no copying or allocation takes place.
197+
In this case the generic message buffer type is `&[u32]`.
198+
199+
```rust
200+
use midi2::prelude::*;
201+
202+
let buffer = [
203+
0xD050_0100_u32,
204+
0x4469_6769,
205+
0x7461_6C20,
206+
0x4175_6469,
207+
0xD090_0100,
208+
0x6F20_576F,
209+
0x726B_7374,
210+
0x6174_696F,
211+
0xD0D0_0100,
212+
0x6E20_2D20,
213+
0x4441_5733,
214+
0x362D_3136,
215+
];
216+
let message = UmpMessage::try_from(&buffer[..]).expect("Valid data");
217+
```
218+
219+
Of course this means that such borrowed messages are immutable
220+
and also have their lifetimes tied to the original buffer.
221+
222+
To remedy this messages can be `rebuffered` into a different
223+
generic backing buffer type.
224+
225+
```rust
226+
use midi2::{
227+
prelude::*,
228+
channel_voice2::NoteOn,
229+
};
230+
231+
let mut owned: NoteOn::<[u32; 4]> = {
232+
let buffer = [0x4898_5E03_u32, 0x6A14_E98A];
233+
// the borrowed message is immutable and cannot outlive `buffer`
234+
let borrowed = NoteOn::try_from(&buffer[..]).expect("Data is valid");
235+
borrowed.array_rebuffer_into()
236+
};
237+
238+
// the owned message is mutable and liberated from the buffer lifetime.
239+
owned.set_channel(u4::new(0x9));
240+
assert_eq!(owned.data(), &[0x4899_5E03, 0x6A14_E98A])
241+
```
242+
243+
## Support For Classical MIDI Byte Stream Messages
244+
245+
Messages which can be represented in classical MIDI byte stream format are also supported.
246+
To do this simply use a backing buffer over `u8` instead of `u32`! ✨🎩
247+
248+
```rust
249+
use midi2::prelude::*;
250+
251+
let mut message = channel_voice1::ChannelPressure::<[u8; 3]>::new();
252+
message.set_channel(u4::new(0x6));
253+
message.set_pressure(u7::new(0x09));
254+
255+
assert_eq!(message.data(), &[0xD6, 0x09]);
256+
```
257+
258+
Messages represented in bytes can be transformed to ump and back using conversion traits.
259+
260+
```rust
261+
use midi2::{
262+
prelude::*,
263+
channel_voice1::ChannelPressure,
264+
};
265+
266+
let message = ChannelPressure::<[u8; 3]>::new();
267+
let message: ChannelPressure<[u32; 4]> = message.into_ump();
268+
269+
assert_eq!(message.data(), &[0x20D0_0000]);
270+
```
271+
272+
## Cargo Features
273+
274+
Several compile-time features are provided that you can enable or disable to customize
275+
functionality according to your needs.
276+
277+
Here's a list of available features:
278+
279+
- `default`:
280+
- **std** - Include [buffer] integration for `std::vec::Vec` and enable allocating getters for values which return `std::string::String` values.
281+
- **channel-voice2** — Include message wrappers for the MIDI 2.0 channel voice message type.
282+
283+
- `optional`: These features are not enabled by default and can be included by adding them to your `Cargo.toml`.
284+
- **flex-data** - Include message wrappers for the MIDI 2.0 Flex Data message type.
285+
- **channel-voice1** - Include message wrappers for the classical MIDI channel voice message type.
286+
- **sysex7** — Include message wrappers for the MIDI 7bit system exclusive message type.
287+
- **sysex8** - Include message wrappers for the MIDI 2.0 System Exclusive 8bit message type.
288+
- **system-common** - Include message wrappers for the MIDI 2.0 System Common / System Real Time message type.
289+
- **ump-stream** - Include message wrappers for the MIDI 2.0 Ump Stream message type.
290+
- **ci** — 🚧 WIP 🚧

midi2/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ name = "midi2"
33
version = "0.8.0"
44
description = "Ergonomic, versatile, strong types wrapping MIDI 2.0 message data."
55
edition = "2021"
6-
readme = "README.md"
6+
readme = "../README.md"
77
license = "MIT OR Apache-2.0"
88
authors = [
99
"Ben Leadbetter <[email protected]>",

0 commit comments

Comments
 (0)