1#![no_std]
4#[warn(missing_debug_implementations, missing_docs)]
5mod parser;
6
7use core::fmt::Debug;
8use embedded_hal::serial;
9pub use midi_types::{Channel, Control, MidiMessage, Note, Program};
10use nb::block;
11pub use parser::MidiParser;
12
13pub struct MidiIn<RX> {
14 rx: RX,
15 parser: MidiParser,
16}
17
18impl<RX, E> MidiIn<RX>
19where
20 RX: serial::Read<u8, Error = E>,
21 E: Debug,
22{
23 pub fn new(rx: RX) -> Self {
24 MidiIn {
25 rx,
26 parser: MidiParser::new(),
27 }
28 }
29
30 pub fn read(&mut self) -> nb::Result<MidiMessage, E> {
31 let byte = self.rx.read()?;
32
33 match self.parser.parse_byte(byte) {
34 Some(event) => Ok(event),
35 None => Err(nb::Error::WouldBlock),
36 }
37 }
38}
39
40pub struct MidiOut<TX> {
41 tx: TX,
42 last_status: Option<u8>,
43}
44
45impl<TX, E> MidiOut<TX>
46where
47 TX: serial::Write<u8, Error = E>,
48 E: Debug,
49{
50 pub fn new(tx: TX) -> Self {
51 MidiOut {
52 tx,
53 last_status: None,
54 }
55 }
56
57 pub fn release(self) -> TX {
58 self.tx
59 }
60
61 pub fn write(&mut self, message: &MidiMessage) -> Result<(), E> {
62 match message {
63 &MidiMessage::NoteOn(channel, note, velocity) => {
64 self.write_channel_message(0x90, channel.into(), &[note.into(), velocity.into()])?;
65 }
66 &MidiMessage::NoteOff(channel, note, velocity) => {
67 self.write_channel_message(0x80, channel.into(), &[note.into(), velocity.into()])?;
68 }
69 &MidiMessage::KeyPressure(channel, note, value) => {
70 self.write_channel_message(0xA0, channel.into(), &[note.into(), value.into()])?;
71 }
72 &MidiMessage::ControlChange(channel, control, value) => {
73 self.write_channel_message(0xB0, channel.into(), &[control.into(), value.into()])?;
74 }
75 &MidiMessage::ProgramChange(channel, program) => {
76 self.write_channel_message(0xC0, channel.into(), &[program.into()])?;
77 }
78 &MidiMessage::ChannelPressure(channel, value) => {
79 self.write_channel_message(0xD0, channel.into(), &[value.into()])?;
80 }
81 &MidiMessage::PitchBendChange(channel, value) => {
82 let (value_lsb, value_msb) = value.into();
83 self.write_channel_message(0xE0, channel.into(), &[value_lsb, value_msb])?;
84 }
85 &MidiMessage::QuarterFrame(value) => {
86 block!(self.tx.write(0xF1))?;
87 block!(self.tx.write(value.into()))?;
88 self.last_status = None;
89 }
90 &MidiMessage::SongPositionPointer(value) => {
91 let (value_lsb, value_msb) = value.into();
92 block!(self.tx.write(0xF2))?;
93 block!(self.tx.write(value_lsb))?;
94 block!(self.tx.write(value_msb))?;
95 self.last_status = None;
96 }
97 &MidiMessage::SongSelect(value) => {
98 block!(self.tx.write(0xF3))?;
99 block!(self.tx.write(value.into()))?;
100 self.last_status = None;
101 }
102 &MidiMessage::TuneRequest => {
103 block!(self.tx.write(0xF6))?;
104 self.last_status = None;
105 }
106 &MidiMessage::TimingClock => {
107 block!(self.tx.write(0xF8))?;
108 }
109 &MidiMessage::Start => {
110 block!(self.tx.write(0xFA))?;
111 }
112 &MidiMessage::Continue => {
113 block!(self.tx.write(0xFB))?;
114 }
115 &MidiMessage::Stop => {
116 block!(self.tx.write(0xFC))?;
117 }
118 &MidiMessage::ActiveSensing => {
119 block!(self.tx.write(0xFE))?;
120 }
121 &MidiMessage::Reset => {
122 block!(self.tx.write(0xFF))?;
123 }
124 }
125
126 Ok(())
127 }
128
129 fn write_channel_message(&mut self, status_msb: u8, channel: u8, data: &[u8]) -> Result<(), E> {
130 let status = status_msb + channel;
131 if self.last_status != Some(status) {
134 block!(self.tx.write(status))?;
135 }
136 for byte in data {
137 block!(self.tx.write(*byte))?;
138 }
139 self.last_status = Some(status);
140
141 Ok(())
142 }
143}
144
145#[cfg(test)]
146mod tests {
147 extern crate std;
148 use super::*;
149 use embedded_hal_mock::serial;
150 use std::vec::Vec;
151
152 fn verify_writes(messages: &[MidiMessage], bytes: &[u8]) {
153 let expectations: Vec<serial::Transaction<u8>> = bytes
154 .into_iter()
155 .map(|byte| serial::Transaction::write(*byte))
156 .collect();
157 let serial = serial::Mock::new(&expectations);
158 let mut midi_out = MidiOut::new(serial);
159 for message in messages {
160 midi_out.write(&message).unwrap();
161 }
162 let mut serial = midi_out.release();
163 serial.done();
164 }
165
166 #[test]
167 fn note_on_should_write_successfully() {
168 verify_writes(
169 &[MidiMessage::NoteOn(0x02.into(), 0x76.into(), 0x34.into())],
170 &[0x92, 0x76, 0x34],
171 );
172 }
173
174 #[test]
175 fn note_on_second_note_should_skip_status() {
176 verify_writes(
177 &[
178 MidiMessage::NoteOn(0x02.into(), 0x76.into(), 0x34.into()),
179 MidiMessage::NoteOn(0x02.into(), 0x33.into(), 0x65.into()),
180 ],
181 &[0x92, 0x76, 0x34, 0x33, 0x65],
182 );
183 }
184 #[test]
185 fn note_on_second_note_different_channel_should_not_skip_status() {
186 verify_writes(
187 &[
188 MidiMessage::NoteOn(0x02.into(), 0x76.into(), 0x34.into()),
189 MidiMessage::NoteOn(0x03.into(), 0x33.into(), 0x65.into()),
190 ],
191 &[0x92, 0x76, 0x34, 0x93, 0x33, 0x65],
192 );
193 }
194 #[test]
195 fn note_on_note_off_should_not_skip_status() {
196 verify_writes(
197 &[
198 MidiMessage::NoteOn(0x02.into(), 0x76.into(), 0x34.into()),
199 MidiMessage::NoteOff(0x02.into(), 0x33.into(), 0x65.into()),
200 ],
201 &[0x92, 0x76, 0x34, 0x82, 0x33, 0x65],
202 );
203 }
204 #[test]
205 fn note_off_should_write_successfully() {
206 verify_writes(
207 &[MidiMessage::NoteOff(0x02.into(), 0x76.into(), 0x34.into())],
208 &[0x82, 0x76, 0x34],
209 );
210 }
211 #[test]
212 fn key_pressure_should_write_successfully() {
213 verify_writes(
214 &[MidiMessage::KeyPressure(
215 0x02.into(),
216 0x76.into(),
217 0x34.into(),
218 )],
219 &[0xA2, 0x76, 0x34],
220 );
221 }
222 #[test]
223 fn control_change_should_write_successfully() {
224 verify_writes(
225 &[MidiMessage::ControlChange(
226 0x02.into(),
227 0x76.into(),
228 0x34.into(),
229 )],
230 &[0xB2, 0x76, 0x34],
231 );
232 }
233 #[test]
234 fn program_change_should_write_successfully() {
235 verify_writes(
236 &[MidiMessage::ProgramChange(0x02.into(), 0x76.into())],
237 &[0xC2, 0x76],
238 );
239 }
240 #[test]
241 fn channel_pressure_should_write_successfully() {
242 verify_writes(
243 &[MidiMessage::ChannelPressure(0x02.into(), 0x76.into())],
244 &[0xD2, 0x76],
245 );
246 }
247 #[test]
248 fn pitch_bend_should_write_successfully() {
249 verify_writes(
250 &[MidiMessage::PitchBendChange(
251 0x02.into(),
252 (0x76, 0x34).into(),
253 )],
254 &[0xE2, 0x76, 0x34],
255 );
256 }
257 #[test]
258 fn quarter_frame_should_write_successfully() {
259 verify_writes(&[MidiMessage::QuarterFrame(0x76.into())], &[0xF1, 0x76]);
260 }
261 #[test]
262 fn song_position_pointer_should_write_successfully() {
263 verify_writes(
264 &[MidiMessage::SongPositionPointer((0x76, 0x34).into())],
265 &[0xF2, 0x76, 0x34],
266 );
267 }
268 #[test]
269 fn song_select_should_write_successfully() {
270 verify_writes(&[MidiMessage::SongSelect(0x76.into())], &[0xF3, 0x76]);
271 }
272 #[test]
273 fn tune_request_should_write_successfully() {
274 verify_writes(&[MidiMessage::TuneRequest], &[0xF6]);
275 }
276 #[test]
277 fn timing_clock_should_write_successfully() {
278 verify_writes(&[MidiMessage::TimingClock], &[0xF8]);
279 }
280 #[test]
281 fn start_should_write_successfully() {
282 verify_writes(&[MidiMessage::Start], &[0xFA]);
283 }
284 #[test]
285 fn continue_should_write_successfully() {
286 verify_writes(&[MidiMessage::Continue], &[0xFB]);
287 }
288 #[test]
289 fn stop_should_write_successfully() {
290 verify_writes(&[MidiMessage::Stop], &[0xFC]);
291 }
292 #[test]
293 fn active_sensing_should_write_successfully() {
294 verify_writes(&[MidiMessage::ActiveSensing], &[0xFE]);
295 }
296 #[test]
297 fn reset_should_write_successfully() {
298 verify_writes(&[MidiMessage::Reset], &[0xFF]);
299 }
300}