midi_event/
write.rs

1use crate::types::*;
2use core::{i8, isize, ptr, slice};
3
4pub trait Write<Output: AsMut<[u8]> + ?Sized> {
5    /// If there is enough space, write to the Output and return the slice written to. Buffer
6    /// contents can be anything if None is returned, and can be anything outside the slice.
7    fn write(self, buffer: &mut Output) -> Option<&[u8]>;
8}
9
10impl Write<[u8]> for MidiEvent {
11    #[inline]
12    fn write(self, output: &mut [u8]) -> Option<&[u8]> {
13        use crate::MidiEventType::*;
14        debug_assert!(self.channel & 0x80 == 0);
15        let channel = self.channel & 0x0F;
16        match self.event {
17            NoteOff(note, velocity) => {
18                debug_assert!(velocity & 0x80 == 0);
19                unsafe {
20                    if output.len() < 3 {
21                        return None;
22                    }
23                    *output.get_unchecked_mut(0) = 0x80 | channel;
24                    *output.get_unchecked_mut(1) = note.into();
25                    *output.get_unchecked_mut(2) = velocity & 0x7F;
26                    Some(unsafe_slice(output, 0, 3))
27                }
28            }
29            NoteOn(note, velocity) => {
30                debug_assert!(velocity & 0x80 == 0);
31                unsafe {
32                    if output.len() < 3 {
33                        return None;
34                    }
35                    *output.get_unchecked_mut(0) = 0x90 | channel;
36                    *output.get_unchecked_mut(1) = note.into();
37                    *output.get_unchecked_mut(2) = velocity & 0x7F;
38                    Some(unsafe_slice(output, 0, 3))
39                }
40            }
41            PolyphonicPressure(note, amount) => {
42                debug_assert!(amount & 0x80 == 0);
43                unsafe {
44                    if output.len() < 3 {
45                        return None;
46                    }
47                    *output.get_unchecked_mut(0) = 0xA0 | channel;
48                    *output.get_unchecked_mut(1) = note.into();
49                    *output.get_unchecked_mut(2) = amount & 0x7F;
50                    Some(unsafe_slice(output, 0, 3))
51                }
52            }
53            Controller(controller, value) => {
54                debug_assert!(controller & 0x80 == 0);
55                debug_assert!(value & 0x80 == 0);
56                unsafe {
57                    if output.len() < 3 {
58                        return None;
59                    }
60                    *output.get_unchecked_mut(0) = 0xB0 | channel;
61                    *output.get_unchecked_mut(1) = controller & 0x7F;
62                    *output.get_unchecked_mut(2) = value & 0x7F;
63                    Some(unsafe_slice(output, 0, 3))
64                }
65            }
66            ProgramChange(program) => {
67                debug_assert!(program & 0x80 == 0);
68                unsafe {
69                    if output.len() < 2 {
70                        return None;
71                    }
72                    *output.get_unchecked_mut(0) = 0xC0 | channel;
73                    *output.get_unchecked_mut(1) = program & 0x7F;
74                    Some(unsafe_slice(output, 0, 2))
75                }
76            }
77            ChannelPressure(pressure) => {
78                debug_assert!(pressure & 0x80 == 0);
79                unsafe {
80                    if output.len() < 2 {
81                        return None;
82                    }
83                    *output.get_unchecked_mut(0) = 0xD0 | channel;
84                    *output.get_unchecked_mut(1) = pressure & 0x7F;
85                    Some(unsafe_slice(output, 0, 2))
86                }
87            }
88            PitchBend(lsb, msb) => {
89                debug_assert!(lsb & 0x80 == 0);
90                debug_assert!(msb & 0x80 == 0);
91                unsafe {
92                    if output.len() < 3 {
93                        return None;
94                    }
95                    *output.get_unchecked_mut(0) = 0xE0 | channel;
96                    *output.get_unchecked_mut(1) = lsb & 0x7F;
97                    *output.get_unchecked_mut(2) = msb & 0x7F;
98                    Some(unsafe_slice(output, 0, 3))
99                }
100            }
101        }
102    }
103}
104
105impl Write<[u8]> for Event<'_> {
106    #[inline]
107    fn write(self, output: &mut [u8]) -> Option<&[u8]> {
108        match self {
109            Event::Midi(evt) => evt.write(output),
110            Event::SysEx(msg) => unsafe {
111                if output.len() < msg.len() + 2 {
112                    return None;
113                }
114                *output.get_unchecked_mut(0) = 0xF0;
115                ptr::copy_nonoverlapping(msg.as_ptr(), output.as_mut_ptr().offset(1), msg.len());
116                *output.get_unchecked_mut(msg.len() + 1) = 0xF7;
117                Some(unsafe_slice(output, 0, msg.len() + 2))
118            },
119            // TODO support messages longer than 127 (using variable length quantities).
120            Event::Escape(msg) => unsafe {
121                if output.len() < msg.len() + 2 || msg.len() > i8::MAX as usize {
122                    return None;
123                }
124                *output.get_unchecked_mut(0) = 0xF7;
125                *output.get_unchecked_mut(1) = msg.len() as u8;
126                ptr::copy_nonoverlapping(msg.as_ptr(), output.as_mut_ptr().offset(2), msg.len());
127                Some(unsafe_slice(output, 0, msg.len() + 2))
128            },
129        }
130    }
131}
132
133#[inline(always)]
134unsafe fn unsafe_slice<T>(input: &[T], start: usize, end: usize) -> &[T] {
135    debug_assert!(input.len() >= end);
136    debug_assert!(start < end);
137    debug_assert!(end < isize::MAX as usize);
138    let pointer = input.as_ptr().offset(start as isize);
139    slice::from_raw_parts(pointer, end - start)
140}