1use crate::{
4 live::{LiveEvent, SystemCommon},
5 prelude::*,
6 primitive::{read_varlen_slice, write_varlen_slice, SmpteTime},
7};
8
9#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)]
14pub struct TrackEvent<'a> {
15 pub delta: u28,
17 pub kind: TrackEventKind<'a>,
19}
20impl<'a> TrackEvent<'a> {
21 pub(crate) fn read(
25 raw: &mut &'a [u8],
26 running_status: &mut Option<u8>,
27 ) -> Result<TrackEvent<'a>> {
28 let delta = u28::read_u7(raw).context(err_invalid!("failed to read event deltatime"))?;
29 let kind = TrackEventKind::read(raw, running_status)
30 .context(err_invalid!("failed to parse event"))?;
31 Ok(TrackEvent { delta, kind })
32 }
33
34 pub(crate) fn read_bytemap(
35 raw: &mut &'a [u8],
36 running_status: &mut Option<u8>,
37 ) -> Result<(&'a [u8], TrackEvent<'a>)> {
38 let delta = u28::read_u7(raw).context(err_invalid!("failed to read event deltatime"))?;
39 let old_raw = *raw;
40 let kind = TrackEventKind::read(raw, running_status)
41 .context(err_invalid!("failed to parse event"))?;
42 Ok((
43 &old_raw[..old_raw.len() - raw.len()],
44 TrackEvent { delta, kind },
45 ))
46 }
47
48 pub(crate) fn write<W: Write>(
49 &self,
50 running_status: &mut Option<u8>,
51 out: &mut W,
52 ) -> WriteResult<W> {
53 self.delta.write_varlen(out)?;
54 self.kind.write(running_status, out)?;
55 Ok(())
56 }
57
58 pub fn to_static(&self) -> TrackEvent<'static> {
63 TrackEvent {
64 delta: self.delta,
65 kind: self.kind.to_static(),
66 }
67 }
68}
69
70#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)]
75pub enum TrackEventKind<'a> {
76 Midi {
80 channel: u4,
82 message: MidiMessage,
84 },
85 SysEx(&'a [u8]),
92 Escape(&'a [u8]),
94 Meta(MetaMessage<'a>),
97}
98impl<'a> TrackEventKind<'a> {
99 fn read(raw: &mut &'a [u8], running_status: &mut Option<u8>) -> Result<TrackEventKind<'a>> {
100 let mut status = *raw.get(0).ok_or(err_invalid!("failed to read status"))?;
102 if status < 0x80 {
103 status = running_status.ok_or(err_invalid!(
105 "event missing status with no running status active"
106 ))?;
107 } else {
108 *raw = &raw[1..];
111 }
112 let kind = match status {
114 0x80..=0xEF => {
115 *running_status = Some(status);
116 let data = MidiMessage::read_data_u8(status, raw)?;
117 let (channel, message) = MidiMessage::read(status, data);
118 TrackEventKind::Midi { channel, message }
119 }
120 0xFF => {
121 *running_status = None;
122 TrackEventKind::Meta(
123 MetaMessage::read(raw).context(err_invalid!("failed to read meta event"))?,
124 )
125 }
126 0xF0 => {
127 *running_status = None;
128 TrackEventKind::SysEx(
129 read_varlen_slice(raw).context(err_invalid!("failed to read sysex event"))?,
130 )
131 }
132 0xF7 => {
133 *running_status = None;
134 TrackEventKind::Escape(
135 read_varlen_slice(raw).context(err_invalid!("failed to read escape event"))?,
136 )
137 }
138 0xF1..=0xF6 => bail!(err_invalid!(
139 "standard midi files cannot contain system common events"
140 )),
141 0xF8..=0xFE => bail!(err_invalid!(
142 "standard midi files cannot contain system realtime events"
143 )),
144 0x00..=0x7F => panic!("invalid running status without top bit set"),
145 };
146 Ok(kind)
147 }
148
149 fn write<W: Write>(&self, running_status: &mut Option<u8>, out: &mut W) -> WriteResult<W> {
155 match self {
161 TrackEventKind::Midi { channel, message } => {
162 let status = message.status_nibble() << 4 | channel.as_int();
163 if Some(status) != *running_status {
164 out.write(&[status])?;
166 *running_status = Some(status);
167 }
168 message.write(out)?;
169 }
170 TrackEventKind::SysEx(data) => {
171 *running_status = None;
172 out.write(&[0xF0])?;
173 write_varlen_slice(data, out)?;
174 }
175 TrackEventKind::Escape(data) => {
176 *running_status = None;
177 out.write(&[0xF7])?;
178 write_varlen_slice(data, out)?;
179 }
180 TrackEventKind::Meta(meta) => {
181 *running_status = None;
182 out.write(&[0xFF])?;
183 meta.write(out)?;
184 }
185 }
186 Ok(())
187 }
188
189 pub fn as_live_event(&self) -> Option<LiveEvent<'a>> {
194 match self {
195 TrackEventKind::Midi { channel, message } => Some(LiveEvent::Midi {
196 channel: *channel,
197 message: *message,
198 }),
199 TrackEventKind::SysEx(data) => {
200 if data.last() == Some(&0xF7) {
201 let data_u7 = u7::slice_from_int(data);
202 if data_u7.len() == data.len() - 1 {
203 return Some(LiveEvent::Common(SystemCommon::SysEx(data_u7)));
204 }
205 }
206 None
207 }
208 TrackEventKind::Escape(_data) => None,
209 TrackEventKind::Meta(_meta) => None,
210 }
211 }
212
213 pub fn to_static(&self) -> TrackEventKind<'static> {
218 use self::TrackEventKind::*;
219 match *self {
220 Midi { channel, message } => Midi { channel, message },
221 SysEx(_) => SysEx(b""),
222 Escape(_) => Escape(b""),
223 Meta(meta) => Meta(meta.to_static()),
224 }
225 }
226}
227
228#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)]
234pub enum MidiMessage {
235 NoteOff {
237 key: u7,
239 vel: u7,
241 },
242 NoteOn {
244 key: u7,
246 vel: u7,
251 },
252 Aftertouch {
254 key: u7,
256 vel: u7,
258 },
259 Controller {
261 controller: u7,
265 value: u7,
267 },
268 ProgramChange {
270 program: u7,
272 },
273 ChannelAftertouch {
275 vel: u7,
277 },
278 PitchBend {
280 bend: PitchBend,
282 },
283}
284impl MidiMessage {
285 pub(crate) fn msg_length(status: u8) -> usize {
287 const LENGTH_BY_STATUS: [u8; 16] = [0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 1, 1, 2, 0];
288 LENGTH_BY_STATUS[(status >> 4) as usize] as usize
289 }
290
291 pub(crate) fn read_data_u8(status: u8, raw: &mut &[u8]) -> Result<[u7; 2]> {
293 let len = Self::msg_length(status);
294 let data = raw
295 .split_checked(len)
296 .ok_or_else(|| err_invalid!("truncated midi message"))?;
297 Ok(match len {
298 1 => [u7::check_int(data[0])?, u7::from(0)],
299 2 => [u7::check_int(data[0])?, u7::check_int(data[1])?],
300 _ => [u7::from(0), u7::from(0)],
301 })
302 }
303
304 pub(crate) fn get_data_u7(status: u8, data: &[u7]) -> Result<[u7; 2]> {
306 let len = Self::msg_length(status);
307 ensure!(data.len() >= len, err_invalid!("truncated midi message"));
308 Ok(match len {
309 1 => [data[0], u7::from(0)],
310 2 => [data[0], data[1]],
311 _ => [u7::from(0), u7::from(0)],
312 })
313 }
314
315 pub(crate) fn read(status: u8, data: [u7; 2]) -> (u4, MidiMessage) {
319 let channel = u4::from(status);
320 let msg = match status >> 4 {
321 0x8 => MidiMessage::NoteOff {
322 key: data[0],
323 vel: data[1],
324 },
325 0x9 => MidiMessage::NoteOn {
326 key: data[0],
327 vel: data[1],
328 },
329 0xA => MidiMessage::Aftertouch {
330 key: data[0],
331 vel: data[1],
332 },
333 0xB => MidiMessage::Controller {
334 controller: data[0],
335 value: data[1],
336 },
337 0xC => MidiMessage::ProgramChange { program: data[0] },
338 0xD => MidiMessage::ChannelAftertouch { vel: data[0] },
339 0xE => {
340 let lsb = data[0].as_int() as u16;
343 let msb = data[1].as_int() as u16;
344 MidiMessage::PitchBend {
345 bend: PitchBend(u14::from(msb << 7 | lsb)),
346 }
347 }
348 _ => panic!("parsed midi message before checking that status is in range"),
349 };
350 (channel, msg)
351 }
352 pub(crate) fn status_nibble(&self) -> u8 {
354 match self {
355 MidiMessage::NoteOff { .. } => 0x8,
356 MidiMessage::NoteOn { .. } => 0x9,
357 MidiMessage::Aftertouch { .. } => 0xA,
358 MidiMessage::Controller { .. } => 0xB,
359 MidiMessage::ProgramChange { .. } => 0xC,
360 MidiMessage::ChannelAftertouch { .. } => 0xD,
361 MidiMessage::PitchBend { .. } => 0xE,
362 }
363 }
364 pub(crate) fn write<W: Write>(&self, out: &mut W) -> WriteResult<W> {
366 match self {
367 MidiMessage::NoteOff { key, vel } => out.write(&[key.as_int(), vel.as_int()])?,
368 MidiMessage::NoteOn { key, vel } => out.write(&[key.as_int(), vel.as_int()])?,
369 MidiMessage::Aftertouch { key, vel } => out.write(&[key.as_int(), vel.as_int()])?,
370 MidiMessage::Controller { controller, value } => {
371 out.write(&[controller.as_int(), value.as_int()])?
372 }
373 MidiMessage::ProgramChange { program } => out.write(&[program.as_int()])?,
374 MidiMessage::ChannelAftertouch { vel } => out.write(&[vel.as_int()])?,
375 MidiMessage::PitchBend { bend } => {
376 let raw = bend.0.as_int();
377 out.write(&[(raw & 0x7F) as u8, (raw >> 7) as u8])?
378 }
379 }
380 Ok(())
381 }
382}
383
384#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)]
390pub struct PitchBend(pub u14);
391impl PitchBend {
392 #[inline]
394 pub const fn min_raw_value() -> PitchBend {
395 PitchBend(u14::new(0x0000))
396 }
397
398 #[inline]
400 pub const fn mid_raw_value() -> PitchBend {
401 PitchBend(u14::new(0x2000))
402 }
403
404 #[inline]
406 pub const fn max_raw_value() -> PitchBend {
407 PitchBend(u14::new(0x3FFF))
408 }
409
410 #[inline]
414 pub fn from_int(int: i16) -> PitchBend {
415 PitchBend(u14::new((int.max(-0x2000).min(0x1FFF) + 0x2000) as u16))
416 }
417
418 #[inline]
422 pub fn from_f32(float: f32) -> PitchBend {
423 PitchBend::from_int((float.max(-1.0).min(1.0) * 0x2000 as f32) as i16)
424 }
425
426 #[inline]
430 pub fn from_f64(float: f64) -> PitchBend {
431 PitchBend::from_int((float.max(-1.0).min(1.0) * 0x2000 as f64) as i16)
432 }
433
434 #[inline]
436 pub fn as_int(self) -> i16 {
437 self.0.as_int() as i16 - 0x2000
438 }
439
440 #[inline]
442 pub fn as_f32(self) -> f32 {
443 self.as_int() as f32 * (1.0 / 0x2000 as f32)
444 }
445
446 #[inline]
448 pub fn as_f64(self) -> f64 {
449 self.as_int() as f64 * (1.0 / 0x2000 as f64)
450 }
451}
452
453#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)]
456pub enum MetaMessage<'a> {
457 TrackNumber(Option<u16>),
460 Text(&'a [u8]),
462 Copyright(&'a [u8]),
464 TrackName(&'a [u8]),
466 InstrumentName(&'a [u8]),
468 Lyric(&'a [u8]),
470 Marker(&'a [u8]),
472 CuePoint(&'a [u8]),
474 ProgramName(&'a [u8]),
476 DeviceName(&'a [u8]),
478 MidiChannel(u4),
480 MidiPort(u7),
482 EndOfTrack,
484 Tempo(u24),
489 SmpteOffset(SmpteTime),
494 TimeSignature(u8, u8, u8, u8),
497 KeySignature(i8, bool),
501 SequencerSpecific(&'a [u8]),
504 Unknown(u8, &'a [u8]),
509}
510impl<'a> MetaMessage<'a> {
511 pub fn to_static(&self) -> MetaMessage<'static> {
516 use self::MetaMessage::*;
517 match *self {
518 TrackNumber(v) => TrackNumber(v),
519 Text(_) => Text(b""),
520 Copyright(_) => Copyright(b""),
521 TrackName(_) => TrackName(b""),
522 InstrumentName(_) => InstrumentName(b""),
523 Lyric(_) => Lyric(b""),
524 Marker(_) => Marker(b""),
525 CuePoint(_) => CuePoint(b""),
526 ProgramName(_) => ProgramName(b""),
527 DeviceName(_) => DeviceName(b""),
528 MidiChannel(v) => MidiChannel(v),
529 MidiPort(v) => MidiPort(v),
530 EndOfTrack => EndOfTrack,
531 Tempo(v) => Tempo(v),
532 SmpteOffset(v) => SmpteOffset(v),
533 TimeSignature(v0, v1, v2, v3) => TimeSignature(v0, v1, v2, v3),
534 KeySignature(v0, v1) => KeySignature(v0, v1),
535 SequencerSpecific(_) => SequencerSpecific(b""),
536 Unknown(v, _) => Unknown(v, b""),
537 }
538 }
539
540 #[allow(clippy::len_zero)]
541 fn read(raw: &mut &'a [u8]) -> Result<MetaMessage<'a>> {
542 let type_byte = u8::read(raw).context(err_invalid!("failed to read meta message type"))?;
543 let mut data =
544 read_varlen_slice(raw).context(err_invalid!("failed to read meta message data"))?;
545 Ok(match type_byte {
546 0x00 => MetaMessage::TrackNumber({
547 if data.len() >= 2 {
548 Some(u16::read(&mut data)?)
549 } else {
550 None
551 }
552 }),
553 0x01 => MetaMessage::Text(data),
554 0x02 => MetaMessage::Copyright(data),
555 0x03 => MetaMessage::TrackName(data),
556 0x04 => MetaMessage::InstrumentName(data),
557 0x05 => MetaMessage::Lyric(data),
558 0x06 => MetaMessage::Marker(data),
559 0x07 => MetaMessage::CuePoint(data),
560 0x08 => MetaMessage::ProgramName(data),
561 0x09 => MetaMessage::DeviceName(data),
562 0x20 if data.len() >= 1 => MetaMessage::MidiChannel(u4::read(&mut data)?),
563 0x21 if data.len() >= 1 => MetaMessage::MidiPort(u7::read(&mut data)?),
564 0x2F => MetaMessage::EndOfTrack,
565 0x51 if data.len() >= 3 => MetaMessage::Tempo(u24::read(&mut data)?),
566 0x54 if data.len() >= 5 => MetaMessage::SmpteOffset(
567 SmpteTime::read(&mut data).context(err_invalid!("failed to read smpte time"))?,
568 ),
569 0x58 if data.len() >= 4 => MetaMessage::TimeSignature(
570 u8::read(&mut data)?,
571 u8::read(&mut data)?,
572 u8::read(&mut data)?,
573 u8::read(&mut data)?,
574 ),
575 0x59 => {
576 MetaMessage::KeySignature(u8::read(&mut data)? as i8, u8::read(&mut data)? != 0)
577 }
578 0x7F => MetaMessage::SequencerSpecific(data),
579 _ => MetaMessage::Unknown(type_byte, data),
580 })
581 }
582 fn write<W: Write>(&self, out: &mut W) -> WriteResult<W> {
583 let mut write_msg = |type_byte: u8, data: &[u8]| {
584 out.write(&[type_byte])?;
585 write_varlen_slice(data, out)?;
586 Ok(())
587 };
588 match self {
589 MetaMessage::TrackNumber(track_num) => match track_num {
590 None => write_msg(0x00, &[]),
591 Some(track_num) => write_msg(0x00, &track_num.to_be_bytes()[..]),
592 },
593 MetaMessage::Text(data) => write_msg(0x01, data),
594 MetaMessage::Copyright(data) => write_msg(0x02, data),
595 MetaMessage::TrackName(data) => write_msg(0x03, data),
596 MetaMessage::InstrumentName(data) => write_msg(0x04, data),
597 MetaMessage::Lyric(data) => write_msg(0x05, data),
598 MetaMessage::Marker(data) => write_msg(0x06, data),
599 MetaMessage::CuePoint(data) => write_msg(0x07, data),
600 MetaMessage::ProgramName(data) => write_msg(0x08, data),
601 MetaMessage::DeviceName(data) => write_msg(0x09, data),
602 MetaMessage::MidiChannel(chan) => write_msg(0x20, &[chan.as_int()]),
603 MetaMessage::MidiPort(port) => write_msg(0x21, &[port.as_int()]),
604 MetaMessage::EndOfTrack => write_msg(0x2F, &[]),
605 MetaMessage::Tempo(microsperbeat) => {
606 write_msg(0x51, µsperbeat.as_int().to_be_bytes()[1..])
607 }
608 MetaMessage::SmpteOffset(smpte) => write_msg(0x54, &smpte.encode()[..]),
609 MetaMessage::TimeSignature(num, den, ticksperclick, thirtysecondsperquarter) => {
610 write_msg(
611 0x58,
612 &[*num, *den, *ticksperclick, *thirtysecondsperquarter],
613 )
614 }
615 MetaMessage::KeySignature(sharps, minor) => {
616 write_msg(0x59, &[*sharps as u8, *minor as u8])
617 }
618 MetaMessage::SequencerSpecific(data) => write_msg(0x7F, data),
619 MetaMessage::Unknown(type_byte, data) => write_msg(*type_byte, data),
620 }
621 }
622}