1use {
2 crate::{
3 os::{OsMidiOutput,OsMidiInput},
4 makepad_live_id::{LiveId, FromLiveId},
5 }
6};
7
8#[derive(Clone, Debug)]
9pub struct MidiPortsEvent {
10 pub descs: Vec<MidiPortDesc>,
11}
12
13impl MidiPortsEvent {
14 pub fn all_inputs(&self) -> Vec<MidiPortId> {
15 let mut out = Vec::new();
16 for d in &self.descs {
17 if d.port_type.is_input() {
18 out.push(d.port_id);
19 }
20 }
21 out
22 }
23 pub fn all_outputs(&self) -> Vec<MidiPortId> {
24 let mut out = Vec::new();
25 for d in &self.descs {
26 if d.port_type.is_output() {
27 out.push(d.port_id);
28 }
29 }
30 out
31 }
32}
33
34impl std::fmt::Display for MidiPortsEvent {
35 fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result {
36 write!(f, "MIDI ports:\n").unwrap();
37 for desc in &self.descs {
38 if desc.port_type.is_input() {
39 write!(f, "[Input] {}\n", desc.name).unwrap()
40 }
41 else {
42 write!(f, "[Output] {}\n", desc.name).unwrap()
43 }
44 }
45 Ok(())
46 }
47}
48
49impl std::fmt::Debug for MidiPortDesc {
50 fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result {
51 f.debug_tuple("name").field(&self.name).finish()
52 }
53}
54
55#[derive(Default)]
56pub struct MidiInput(pub (crate) Option<OsMidiInput>);
57unsafe impl Send for MidiInput {}
58
59impl MidiInput {
60 pub fn receive(&mut self) -> Option<(MidiPortId, MidiData)> {
61 self.0.as_mut().unwrap().receive()
62 }
63}
64
65#[derive(Default)]
66pub struct MidiOutput(pub (crate) Option<OsMidiOutput>);
67unsafe impl Send for MidiOutput {}
68
69impl MidiOutput {
70 pub fn send(&self, port: Option<MidiPortId>, data: MidiData) {
71 let output = self.0.as_ref().unwrap();
72 output.send(port, data);
73 }
74}
75
76#[derive(Clone, Copy, Debug, PartialEq)]
77pub struct MidiData {
78 pub data: [u8; 3],
79}
80
81impl std::convert::From<u32> for MidiData {
82 fn from(data: u32) -> Self {
83 MidiData {
84 data: [((data >> 16) & 0xff) as u8, ((data >> 8) & 0xff) as u8, ((data >> 0) & 0xff) as u8]
85 }
86 }
87}
88
89#[derive(Clone, Copy, Debug, PartialEq)]
90pub enum MidiPortType {
91 Input,
92 Output,
93}
94
95impl MidiPortType {
96 pub fn is_input(&self) -> bool {
97 match self {
98 Self::Input => true,
99 _ => false
100 }
101 }
102 pub fn is_output(&self) -> bool {
103 match self {
104 Self::Output => true,
105 _ => false
106 }
107 }
108}
109
110#[derive(Clone, Debug, Default, Eq, Hash, Copy, PartialEq, FromLiveId)]
111pub struct MidiPortId(pub LiveId);
112
113#[derive(Clone, PartialEq)]
114pub struct MidiPortDesc {
115 pub name: String,
116 pub port_id: MidiPortId,
117 pub port_type: MidiPortType,
118}
119
120
121#[derive(Clone, Copy, Debug)]
122pub struct MidiNote {
123 pub is_on: bool,
124 pub channel: u8,
125 pub note_number: u8,
126 pub velocity: u8,
127}
128
129impl Into<MidiData> for MidiNote {
130 fn into(self) -> MidiData {
131 MidiData {
132 data: [
133 (if self.is_on {0x9}else {0x8} << 4) | self.channel,
134 self.note_number,
135 self.velocity
136 ]
137 }
138 }
139}
140
141
142#[derive(Clone, Copy, Debug)]
143pub struct MidiAftertouch {
144 pub channel: u8,
145 pub note_number: u8,
146 pub velocity: u8
147}
148
149impl Into<MidiData> for MidiAftertouch {
150 fn into(self) -> MidiData {
151 MidiData {
152 data: [
153 0xA0 | self.channel,
154 self.note_number,
155 self.velocity
156 ]
157 }
158 }
159}
160
161#[derive(Clone, Copy, Debug)]
162pub struct MidiControlChange {
163 pub channel: u8,
164 pub param: u8,
165 pub value: u8,
166}
167
168impl Into<MidiData> for MidiControlChange {
169 fn into(self) -> MidiData {
170 MidiData {
171 data: [
172 0xB0 | self.channel,
173 self.param,
174 self.value
175 ]
176 }
177 }
178}
179
180
181#[derive(Clone, Copy, Debug)]
182pub struct MidiProgramChange {
183 pub channel: u8,
184 pub hi: u8,
185 pub lo: u8
186}
187
188impl Into<MidiData> for MidiProgramChange {
189 fn into(self) -> MidiData {
190 MidiData {
191 data: [
192 0xC0 | self.channel,
193 self.hi,
194 self.lo
195 ]
196 }
197 }
198}
199
200
201#[derive(Clone, Copy, Debug)]
202pub struct MidiChannelAftertouch {
203 pub channel: u8,
204 pub value: u16
205}
206
207impl Into<MidiData> for MidiChannelAftertouch {
208 fn into(self) -> MidiData {
209 MidiData {
210 data: [
211 0xD0 | self.channel,
212 (((self.value as u32)>>7)&0x7f) as u8,
213 ((self.value as u32)&0x7f) as u8,
214 ]
215 }
216 }
217}
218
219
220#[derive(Clone, Copy, Debug)]
221pub struct MidiPitchBend {
222 pub channel: u8,
223 pub bend: u16,
224}
225
226impl Into<MidiData> for MidiPitchBend {
227 fn into(self) -> MidiData {
228 MidiData {
229 data: [
230 0xE0 | self.channel,
231 (((self.bend as u32)>>7)&0x7f) as u8,
232 ((self.bend as u32)&0x7f) as u8,
233 ]
234 }
235 }
236}
237
238#[derive(Clone, Copy, Debug)]
239pub struct MidiSystem {
240 pub channel: u8,
241 pub hi: u8,
242 pub lo: u8
243}
244
245impl Into<MidiData> for MidiSystem {
246 fn into(self) -> MidiData {
247 MidiData {
248 data: [
249 0xF0 | self.channel,
250 self.hi,
251 self.lo
252 ]
253 }
254 }
255}
256
257#[derive(Clone, Copy, Debug)]
258pub enum MidiEvent {
259 Note(MidiNote),
260 Aftertouch(MidiAftertouch),
261 ControlChange(MidiControlChange),
262 ProgramChange(MidiProgramChange),
263 PitchBend(MidiPitchBend),
264 ChannelAftertouch(MidiChannelAftertouch),
265 System(MidiSystem),
266 Unknown(MidiData)
267}
268
269impl MidiEvent {
270 pub fn on_note(&self) -> Option<MidiNote> {
271 match self {
272 Self::Note(note) => Some(*note),
273 _ => None
274 }
275 }
276}
277
278impl MidiData {
279 pub fn status(&self) -> u8 {
280 self.data[0] >> 4
281 }
282 pub fn channel(&self) -> u8 {
283 self.data[0] & 0xf
284 }
285
286 pub fn decode(&self) -> MidiEvent {
287 let status = self.status();
288 let channel = self.channel();
289 match status {
290 0x8 | 0x9 => {
291 let velocity = self.data[2];
292 let is_on = if status == 0x8 || velocity == 0 {
293 false
294 } else {
295 true
296 };
297 MidiEvent::Note(MidiNote {
298 is_on,
299 channel,
300 note_number: self.data[1],
301 velocity,
302 })
303 },
304 0xA => MidiEvent::Aftertouch(MidiAftertouch {
305 channel,
306 note_number: self.data[1],
307 velocity: self.data[2],
308 }),
309 0xB => MidiEvent::ControlChange(MidiControlChange {
310 channel,
311 param: self.data[1],
312 value: self.data[2]
313 }),
314 0xC => MidiEvent::ProgramChange(MidiProgramChange {
315 channel,
316 hi: self.data[1],
317 lo: self.data[2]
318 }),
319 0xD => MidiEvent::ChannelAftertouch(MidiChannelAftertouch {
320 channel,
321 value: ((self.data[1] as u16) << 7) | self.data[2] as u16,
322 }),
323 0xE => MidiEvent::PitchBend(MidiPitchBend {
324 channel,
325 bend: ((self.data[1] as u16) << 7) | self.data[2] as u16,
326 }),
327 0xF => MidiEvent::System(MidiSystem {
328 channel,
329 hi: self.data[1],
330 lo: self.data[2]
331 }),
332 _ => MidiEvent::Unknown(*self)
333 }
334 }
335}