lv2rs_midi/
atom.rs

1/// Atom types for MIDI handling.
2use crate::message::*;
3use crate::prelude::*;
4use crate::status_bytes::*;
5use lv2rs_atom::prelude::*;
6use lv2rs_urid::CachedMap;
7use std::ffi::CStr;
8
9#[repr(C)]
10/// Raw representation of a "normal", non-system-exclusive message.
11///
12/// There are many different but similiar MIDI message types. Due to their similarities, all of them
13/// are represented by this type.
14///
15/// `RawMidiMessage` does not have a writer extension; You simply intitialize it with a value of
16/// the [`MidiMessage`](enum.MidiMessage.html) enum and that's it.
17///
18/// Reading is done by calling the [`interpret`](#method.interpret) method which tries to create
19/// a `MidiMessage` value from the raw message.
20pub struct RawMidiMessage([u8]);
21
22impl RawMidiMessage {
23    /// Try to create a `MidiMessage` from the raw message.
24    ///
25    /// This basically an alias for
26    /// [`MidiMessage::try_from`](enum.MidiMessage.html#method.try_from) and therefore,
27    /// errors are forwarded.
28    pub fn interpret(&self) -> Result<MidiMessage, TryFromError> {
29        MidiMessage::try_from(&self.0)
30    }
31}
32
33impl<'a> AtomBody for RawMidiMessage {
34    type InitializationParameter = MidiMessage;
35
36    fn get_uri() -> &'static CStr {
37        unsafe { CStr::from_bytes_with_nul_unchecked(crate::uris::EVENT_URI) }
38    }
39
40    unsafe fn initialize_body<'b, W>(
41        writer: &mut W,
42        message: &MidiMessage,
43        _urids: &mut CachedMap,
44    ) -> Result<(), ()>
45    where
46        W: WritingFrame<'b> + WritingFrameExt<'b, Self>,
47    {
48        match message {
49            MidiMessage::NoteOff {
50                channel,
51                note,
52                velocity,
53            } => {
54                write_channel_status(writer, NOTE_OFF_STATUS, *channel)?;
55                write_data(writer, *note)?;
56                write_data(writer, *velocity)?;
57            }
58            MidiMessage::NoteOn {
59                channel,
60                note,
61                velocity,
62            } => {
63                write_channel_status(writer, NOTE_ON_STATUS, *channel)?;
64                write_data(writer, *note)?;
65                write_data(writer, *velocity)?;
66            }
67            MidiMessage::PolyKeyPressure { channel, pressure } => {
68                write_channel_status(writer, POLY_KEY_PRESSURE_STATUS, *channel)?;
69                write_data(writer, *pressure)?;
70            }
71            MidiMessage::ControlChange {
72                channel,
73                control_number,
74                control_value,
75            } => {
76                write_channel_status(writer, CONTROL_CHANGE_STATUS, *channel)?;
77                write_data(writer, *control_number)?;
78                write_data(writer, *control_value)?;
79            }
80            MidiMessage::ProgramChange {
81                channel,
82                program_number,
83            } => {
84                write_channel_status(writer, PROGRAM_CHANGE_STATUS, *channel)?;
85                write_data(writer, *program_number)?;
86            }
87            MidiMessage::ChannelPressure { channel, pressure } => {
88                write_channel_status(writer, CHANNEL_PRESSURE_STATUS, *channel)?;
89                write_data(writer, *pressure)?;
90            }
91            MidiMessage::PitchBendChange { channel, value } => {
92                write_channel_status(writer, PITCH_BEND_CHANGE_STATUS, *channel)?;
93                write_u14_data(writer, *value)?;
94            }
95            MidiMessage::TimeCodeQuarterFrame {
96                message_type,
97                value,
98            } => {
99                writer.write_sized(&TIME_CODE_QUARTER_FRAME_STATUS)?;
100                let message_type: u8 = (*message_type).into();
101                let value: u8 = (*value).into();
102                let byte: u8 = value + (message_type << 4);
103                writer.write_sized(&byte)?;
104            }
105            MidiMessage::SongPositionPointer { position } => {
106                writer.write_sized(&SONG_POSITION_POINTER_STATUS)?;
107                write_u14_data(writer, *position)?;
108            }
109            MidiMessage::SongSelect { song } => {
110                writer.write_sized(&SONG_SELECT_STATUS)?;
111                write_data(writer, *song)?;
112            }
113            MidiMessage::TuneRequest => {
114                writer.write_sized(&TUNE_REQUEST_STATUS)?;
115            }
116            MidiMessage::TimingClock => {
117                writer.write_sized(&TIMING_CLOCK_STATUS)?;
118            }
119            MidiMessage::Start => {
120                writer.write_sized(&START_STATUS)?;
121            }
122            MidiMessage::Continue => {
123                writer.write_sized(&CONTINUE_STATUS)?;
124            }
125            MidiMessage::Stop => {
126                writer.write_sized(&STOP_STATUS)?;
127            }
128            MidiMessage::ActiveSensing => {
129                writer.write_sized(&ACTIVE_SENSING_STATUS)?;
130            }
131            MidiMessage::SystemReset => {
132                writer.write_sized(&SYSTEM_RESET_STATUS)?;
133            }
134        }
135        Ok(())
136    }
137
138    fn create_ref<'b>(raw_data: &'b [u8]) -> Result<&'b Self, ()> {
139        // A MIDI message may only have one, two or three bytes.
140        if (raw_data.len() > 3) | (raw_data.len() == 0) {
141            return Err(());
142        }
143        // The first byte must be a status byte.
144        if (raw_data[0] & 0b1000_0000) == 0 {
145            return Err(());
146        }
147        // The second byte must not be a status byte.
148        if (raw_data.len() >= 2) & (raw_data[1] & 0b1000_0000 != 0) {
149            return Err(());
150        }
151        // The third byte must not be a status byte.
152        if (raw_data.len() == 3) & (raw_data[2] & 0b1000_0000 != 0) {
153            return Err(());
154        }
155        // Construct and return the reference.
156        let self_ptr = raw_data as *const [u8] as *const Self;
157        Ok(unsafe { self_ptr.as_ref() }.unwrap())
158    }
159}
160
161#[repr(C)]
162/// Raw representation of a system-exclusive message.
163///
164/// System exclusive messages are very flexible: They start with a specific status byte and end with
165/// another and anything else does not matter. However, since they have a level of flexibility that
166/// other messages don't have, they have to be handled by another atom type; This one!
167///
168/// A `SystemExclusiveMessage` doesn't use a writing frame extension. This means that the whole
169/// message has to be written in one go when initializing.
170pub struct SystemExclusiveMessage([u8]);
171
172impl SystemExclusiveMessage {
173    /// Return the data bytes between the start and end status byte.
174    pub fn get_data(&self) -> &[u8] {
175        assert!(self.0.len() >= 2);
176        let data = &self.0;
177        let len = data.len();
178        &data[1..len - 1]
179    }
180}
181
182impl<'a> AtomBody for SystemExclusiveMessage {
183    type InitializationParameter = [u8];
184
185    fn get_uri() -> &'static CStr {
186        unsafe { CStr::from_bytes_with_nul_unchecked(crate::uris::EVENT_URI) }
187    }
188
189    unsafe fn initialize_body<'b, W>(
190        writer: &mut W,
191        data: &[u8],
192        _urids: &mut CachedMap,
193    ) -> Result<(), ()>
194    where
195        W: WritingFrame<'b> + WritingFrameExt<'b, Self>,
196    {
197        writer.write_sized(&START_OF_SYSTEM_EXCLUSIVE_STATUS)?;
198        writer.write_raw(data)?;
199        writer.write_sized(&END_OF_SYSTEM_EXCLUSICE_STATUS)?;
200        Ok(())
201    }
202
203    fn create_ref<'b>(raw_data: &'b [u8]) -> Result<&'b Self, ()> {
204        // Creating the reference.
205        let self_ptr = raw_data as *const [u8] as *const Self;
206        let self_ref = unsafe { self_ptr.as_ref() }.unwrap();
207
208        // Assuring a minimal length of two bytes.
209        if self_ref.0.len() < 2 {
210            return Err(());
211        }
212
213        // Check the first and the last byte to be the correct status bytes.
214        let first_byte: u8 = *self_ref.0.first().unwrap();
215        let last_byte: u8 = *self_ref.0.last().unwrap();
216        if (first_byte != START_OF_SYSTEM_EXCLUSIVE_STATUS)
217            | (last_byte != END_OF_SYSTEM_EXCLUSICE_STATUS)
218        {
219            return Err(());
220        }
221
222        // Check for interior status bytes.
223        // Original MIDI allows some of them, but LV2 doesn't.
224        for byte in &self_ref.0[1..self_ref.0.len() - 1] {
225            if (*byte & 0b1000_0000) != 0 {
226                return Err(());
227            }
228        }
229
230        Ok(self_ref)
231    }
232}
233
234unsafe fn write_channel_status<'a, W, A>(writer: &mut W, status: u8, channel: u4) -> Result<(), ()>
235where
236    W: WritingFrame<'a> + WritingFrameExt<'a, A>,
237    A: AtomBody + ?Sized,
238{
239    let channel: u8 = channel.into();
240    let status = status + channel;
241    writer.write_sized(&status).map(|_| ())
242}
243
244unsafe fn write_data<'a, W, A>(writer: &mut W, data: u7) -> Result<(), ()>
245where
246    W: WritingFrame<'a> + WritingFrameExt<'a, A>,
247    A: AtomBody + ?Sized,
248{
249    let data: u8 = data.into();
250    writer.write_sized(&data).map(|_| ())
251}
252
253unsafe fn write_u14_data<'a, W, A>(writer: &mut W, data: u14) -> Result<(), ()>
254where
255    W: WritingFrame<'a> + WritingFrameExt<'a, A>,
256    A: AtomBody + ?Sized,
257{
258    let data: u16 = data.into();
259    let msb: u8 = ((data & 0b0011_1111_1000_0000) >> 7) as u8;
260    let lsb: u8 = (data & 0b0000_0000_0111_1111) as u8;
261    writer.write_sized(&lsb)?;
262    writer.write_sized(&msb)?;
263    Ok(())
264}