1use crate::types::*;
2use core::{i8, isize, ptr, slice};
3
4pub trait Write<Output: AsMut<[u8]> + ?Sized> {
5 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 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}