makepad_platform/
midi.rs

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
65pub struct MidiOutput(pub (crate) Option<OsMidiOutput>);
66unsafe impl Send for MidiOutput {}
67
68impl MidiOutput {
69    pub fn send(&self, port: Option<MidiPortId>, data: MidiData) {
70        let output = self.0.as_ref().unwrap();
71        output.send(port, data);
72    } 
73}
74
75#[derive(Clone, Copy, Debug, PartialEq)] 
76pub struct MidiData {
77    pub data: [u8; 3],
78}
79
80impl std::convert::From<u32> for MidiData {
81    fn from(data: u32) -> Self {
82        MidiData {
83            data: [((data >> 16) & 0xff) as u8, ((data >> 8) & 0xff) as u8, ((data >> 0) & 0xff) as u8]
84        }
85    } 
86}  
87
88#[derive(Clone, Copy, Debug, PartialEq)]
89pub enum MidiPortType {
90    Input,
91    Output,
92}
93
94impl MidiPortType {
95    pub fn is_input(&self) -> bool {
96        match self {
97            Self::Input => true,
98            _ => false
99        }
100    }
101    pub fn is_output(&self) -> bool {
102        match self {
103            Self::Output => true,
104            _ => false
105        }
106    }
107}
108
109#[derive(Clone, Debug, Default, Eq, Hash, Copy, PartialEq, FromLiveId)]
110pub struct MidiPortId(pub LiveId);
111
112#[derive(Clone, PartialEq)]
113pub struct MidiPortDesc {
114    pub name: String,
115    pub port_id: MidiPortId,
116    pub port_type: MidiPortType,
117}
118
119
120#[derive(Clone, Copy, Debug)]
121pub struct MidiNote {
122    pub is_on: bool,
123    pub channel: u8,
124    pub note_number: u8,
125    pub velocity: u8,
126}
127
128impl Into<MidiData> for MidiNote {
129    fn into(self) -> MidiData {
130        MidiData {
131            data: [
132                (if self.is_on {0x9}else {0x8} << 4) | self.channel,
133                self.note_number,
134                self.velocity
135            ]
136        }
137    }
138}
139
140
141#[derive(Clone, Copy, Debug)]
142pub struct MidiAftertouch {
143    pub channel: u8,
144    pub note_number: u8,
145    pub velocity: u8
146}
147
148impl Into<MidiData> for MidiAftertouch {
149    fn into(self) -> MidiData {
150        MidiData {
151            data: [
152                0xA0 | self.channel,
153                self.note_number,
154                self.velocity
155            ]
156        }
157    }
158}
159
160#[derive(Clone, Copy, Debug)]
161pub struct MidiControlChange {
162    pub channel: u8,
163    pub param: u8,
164    pub value: u8,
165}
166
167impl Into<MidiData> for MidiControlChange {
168    fn into(self) -> MidiData {
169        MidiData {
170            data: [
171                0xB0 | self.channel,
172                self.param,
173                self.value
174            ]
175        }
176    }
177}
178
179
180#[derive(Clone, Copy, Debug)]
181pub struct MidiProgramChange {
182    pub channel: u8,
183    pub hi: u8,
184    pub lo: u8
185}
186
187impl Into<MidiData> for MidiProgramChange {
188    fn into(self) -> MidiData {
189        MidiData {
190            data: [
191                0xC0 | self.channel,
192                self.hi,
193                self.lo
194            ]
195        }
196    }
197}
198
199
200#[derive(Clone, Copy, Debug)]
201pub struct MidiChannelAftertouch {
202    pub channel: u8,
203    pub value: u16
204}
205
206impl Into<MidiData> for MidiChannelAftertouch {
207    fn into(self) -> MidiData {
208        MidiData {
209            data: [
210                0xD0 | self.channel,
211                (((self.value as u32)>>7)&0x7f) as u8,
212                ((self.value as u32)&0x7f) as u8,
213            ]
214        }
215    }
216}
217
218
219#[derive(Clone, Copy, Debug)]
220pub struct MidiPitchBend {
221    pub channel: u8,
222    pub bend: u16,
223}
224
225impl Into<MidiData> for MidiPitchBend {
226    fn into(self) -> MidiData {
227        MidiData {
228            data: [
229                0xE0 | self.channel,
230                (((self.bend as u32)>>7)&0x7f) as u8,
231                ((self.bend as u32)&0x7f) as u8,
232            ]
233        }
234    }
235}
236
237#[derive(Clone, Copy, Debug)]
238pub struct MidiSystem {
239    pub channel: u8,
240    pub hi: u8,
241    pub lo: u8
242}
243
244impl Into<MidiData> for MidiSystem {
245    fn into(self) -> MidiData {
246        MidiData {
247            data: [
248                0xF0 | self.channel,
249                self.hi,
250                self.lo
251            ]
252        }
253    }
254}
255
256#[derive(Clone, Copy, Debug)]
257pub enum MidiEvent {
258    Note(MidiNote),
259    Aftertouch(MidiAftertouch),
260    ControlChange(MidiControlChange),
261    ProgramChange(MidiProgramChange),
262    PitchBend(MidiPitchBend),
263    ChannelAftertouch(MidiChannelAftertouch),
264    System(MidiSystem),
265    Unknown(MidiData)
266}
267
268impl MidiEvent {
269    pub fn on_note(&self) -> Option<MidiNote> {
270        match self {
271            Self::Note(note) => Some(*note),
272            _ => None
273        }
274    }
275}
276
277impl MidiData {
278    pub fn status(&self) -> u8 {
279        self.data[0] >> 4
280    }
281    pub fn channel(&self) -> u8 {
282        self.data[0] & 0xf
283    }
284    
285    pub fn decode(&self) -> MidiEvent {
286        let status = self.status();
287        let channel = self.channel();
288        match status {
289            0x8 | 0x9 => MidiEvent::Note(MidiNote {
290                is_on: status == 0x9,
291                channel,
292                note_number: self.data[1],
293                velocity: self.data[2]
294            }),
295            0xA => MidiEvent::Aftertouch(MidiAftertouch {
296                channel,
297                note_number: self.data[1],
298                velocity: self.data[2],
299            }),
300            0xB => MidiEvent::ControlChange(MidiControlChange {
301                channel,
302                param: self.data[1],
303                value: self.data[2]
304            }),
305            0xC => MidiEvent::ProgramChange(MidiProgramChange {
306                channel,
307                hi: self.data[1],
308                lo: self.data[2]
309            }),
310            0xD => MidiEvent::ChannelAftertouch(MidiChannelAftertouch {
311                channel,
312                value: ((self.data[1] as u16) << 7) | self.data[2] as u16,
313            }),
314            0xE => MidiEvent::PitchBend(MidiPitchBend {
315                channel,
316                bend: ((self.data[1] as u16) << 7) | self.data[2] as u16,
317            }),
318            0xF => MidiEvent::System(MidiSystem {
319                channel,
320                hi: self.data[1],
321                lo: self.data[2]
322            }),
323            _ => MidiEvent::Unknown(*self)
324        }
325    }
326}