nom_midi/
types.rs

1mod note;
2pub use note::Note;
3
4#[derive(Debug, PartialEq, Clone)]
5pub struct SimpleMidiFile<'src> {
6    pub header: MidiHeader,
7    pub tracks: Vec<Track<'src>>,
8}
9
10// header
11// ======
12
13/// A data structure for the Midi file header chunk
14#[derive(Debug, PartialEq, Copy, Clone)]
15pub struct MidiHeader {
16    /// The format of the file
17    pub format: MidiFormat,
18    /// The way time is divided
19    pub division: Division,
20}
21
22/// Represents the different formats of a midi file
23///
24/// The parameter is the number of tracks
25#[derive(Debug, PartialEq, Copy, Clone)]
26pub enum MidiFormat {
27    /// There is only 1 track
28    SingleTrack,
29    /// There are multiple tracks to be played concurrently
30    MultipleTrack(u16),
31    /// There are multiple songs that can be played in any order/combination
32    /// (e.g. a set of sequences for a drum machine)
33    MultipleSong(u16),
34}
35
36impl MidiFormat {
37    /// How many tracks are there in the format
38    pub fn count(&self) -> u16 {
39        match *self {
40            MidiFormat::SingleTrack => 1,
41            MidiFormat::MultipleTrack(ref n) => *n,
42            MidiFormat::MultipleSong(ref n) => *n,
43        }
44    }
45}
46
47/// The way time is divided in the midi track
48#[derive(Debug, PartialEq, Copy, Clone)]
49pub enum Division {
50    /// This means the time is indicated by the number of sub-divisons of a quarter-note
51    /// (a.k.a. crotchet). For example, 4 would mean the maximum resolution is semi-quavers.
52    ///
53    /// A common choice is 96 = 2^5 * 3 allowing dotted notes down to hemidemisemiquavers
54    Metrical(u16),
55    /// The time is absolute, and expresses as a combination of frames per second, and the
56    /// sub-frame resolution
57    Timecode {
58        /// The number of frames per second
59        fps: Fps,
60        /// The sub-frame resolution
61        ///
62        /// Typical values are 4 (corresponding to MIDI Time Code), 8, 10, 80 (corresponding to
63        /// SMPTE bit resolution), or 100.
64        res: u8,
65    },
66}
67
68/// There are only 4 valid fps, below
69#[derive(Debug, PartialEq, Copy, Clone)]
70#[repr(u8)]
71pub enum Fps {
72    /// 24 fps
73    TwentyFour = 24,
74    /// 25 fps
75    TwentyFive = 25,
76    /// 29 fps
77    TwentyNine = 29,
78    /// 30 fps
79    Thirty = 30,
80}
81
82impl Into<u8> for Fps {
83    fn into(self) -> u8 {
84        self as u8
85    }
86}
87
88// Track
89// =====
90
91/// A track chunk (a collection of events)
92#[derive(Debug, PartialEq, Clone)]
93pub struct Track<'src> {
94    pub events: Vec<Event<'src>>,
95}
96
97// Events
98// ======
99
100/// An event present in a track chunk
101#[derive(Debug, PartialEq, Clone)]
102pub struct Event<'src> {
103    pub delta_time: u32,
104    pub event: EventType<'src>,
105}
106
107/// The type of an event in a track chunk, along with event-specific data
108#[derive(Debug, PartialEq, Clone)]
109pub enum EventType<'src> {
110    Midi(MidiEvent),
111    SystemExclusive(SystemExclusiveEvent<'src>),
112    EscapeSequence(EscapeSequence<'src>),
113    Meta(MetaEvent<'src>),
114}
115
116// Midi Events
117// ===========
118
119/// The midi event, along with the channel it applies to
120#[derive(Debug, PartialEq, Copy, Clone)]
121pub struct MidiEvent {
122    /// The channel the midi event applies to
123    pub channel: u8,
124    /// The event
125    pub event: MidiEventType,
126}
127
128/// A midi event
129///
130/// Normally, the majority of messages will be of this type. They are the key messages for
131/// starting and stopping sound, along with changing pitch.
132///
133/// Note that for all values, the top bit is not used, so the numbers will be interpreted the same
134/// for either u8 or i8. I use u8 here.
135#[derive(Debug, PartialEq, Copy, Clone)]
136pub enum MidiEventType {
137    /// Stop sounding the given note
138    ///
139    /// The second param is the release velocity
140    NoteOff(Note, u8),
141    /// Start sounding the given note
142    ///
143    /// The second param is the attack velocity
144    NoteOn(Note, u8),
145    /// Apply aftertouch pressure to the given note
146    ///
147    /// The second param is the amount of aftertouch
148    PolyphonicPressure(Note, u8),
149    /// Set a controller to a value
150    ///
151    /// The first param is the controller to set, and the second param is the value to set it to
152    Controller(u8, u8),
153    /// Select the specified program
154    ///
155    /// The second param is the program to set.
156    ProgramChange(u8),
157    /// Allows all notes to have a specific aftertouch used as default, similar to
158    /// `PolyphonicPressure`
159    ChannelPressure(u8),
160    /// Apply pitch bend to all notes
161    ///
162    /// First param is less significant byte, and second is most significant byte. The value of
163    /// `0x00 0x40` means 'no bend', less means bend down and more means bend up.
164    PitchBend(u8, u8),
165}
166
167// SysEx Events
168// ============
169
170/// A system exclusive message
171#[derive(Debug, PartialEq, Clone)]
172pub struct SystemExclusiveEvent<'src>(pub &'src [u8]);
173
174/// An escape sequence (something not possible to include elsewhere)
175#[derive(Debug, PartialEq, Clone)]
176pub struct EscapeSequence<'src>(pub &'src [u8]);
177
178// Meta Events
179// ===========
180
181/// A special non-MIDI event
182#[derive(Debug, PartialEq, Clone)]
183pub enum MetaEvent<'src> {
184    /// The sequence number (as would be used in a MIDI Cue message)
185    SequenceNumber(u16),
186    /// Free text, can include comments and other useful information, if that information
187    /// doesn't naturally fit in another text-based field
188    Text(&'src [u8]),
189    /// A copyright notice
190    Copyright(&'src [u8]),
191    /// The name of the current sequence or track (depending on context)
192    SequenceOrTrackName(&'src [u8]),
193    /// The name of the current track
194    //TrackName(String),
195    /// The name of the instrument for this track (e.g. "Flute", "Piano", "Tenor", etc.)
196    InstrumentName(&'src [u8]),
197    /// A syllable or set of syllables to be sung as part of a vocal track.
198    Lyric(&'src [u8]),
199    /// A useful position-dependent note in the music (e.g. rehersal mark "A", loop point,
200    /// section name)
201    Marker(&'src [u8]),
202    /// A marker to indicate this event should be synchronized with some non-midi event, e.g. "car
203    /// crash on screen", "actors leave stage", etc.
204    CuePoint(&'src [u8]),
205    /// Indicates what patch or program name should be used by the immediately subsequent Bank
206    /// Select and Program Change messages.
207    ProgramName(&'src [u8]),
208    /// The name of the hardware device used to produce sounds for this track. Might be inserted
209    /// for example if using a branded synth or keyboard to generate midi events.
210    DeviceName(&'src [u8]),
211    /// Indicate which channel subsequent SysEx and Meta events apply to. Lasts until the next
212    /// event of this type, or a normal MIDI event
213    MidiChannelPrefix(u8), // actually u4
214    /// Specify which port future MIDI event apply to. This exists to increase the 4-bit channel
215    /// limit, and so it's functionality overlaps with channels
216    MidiPort(u8), // actually u7
217    /// This event must be at the end of each track, and must not be anywhere else
218    EndOfTrack,
219    /// Specifies the number of microseconds per quarter note for future MIDI events.
220    Tempo(u32), // actually u24
221    /// This is complicated and I don't understand it.
222    SMPTEOffset(SMPTEOffset),
223    /// Set the time signature. If no time signature event occurs before a MIDI event the default
224    /// is `(4, 4)`
225    TimeSignature(TimeSignature),
226    /// Set the key signature. The default is C major.
227    KeySignature(KeySignature),
228    /// Vendor specific events. I don't try to parse them - just return the data
229    SequencerSpecificEvent(&'src [u8]),
230    /// An unrecognised event. To be future-compatible, just ignore these
231    Unknown(u8, &'src [u8]),
232}
233
234/// I don't understand this, but I should be decoding it correctly for those that do
235#[derive(Debug, PartialEq, Clone)]
236pub struct SMPTEOffset {
237    pub fps: Fps,
238    pub hour: u8,      // 0 - 23
239    pub minute: u8,    // 0 - 59
240    pub second: u8,    // 0 - 59
241    pub no_frames: u8, // 0-23/24/28/29, depending on fps
242    pub no_fractional_frames: u8,
243}
244
245/// A time signature
246///
247/// # Examples
248/// Assuming `no_32nd_in_quarter` is 8
249///
250///  - A time signature of 4/4, with a metronome click every 1/4 note, would be encoded
251///  `FF 58 04 04 02 18 08`. There are 24 MIDI Clocks per quarter-note, hence cc=24 (0x18).
252///
253///  - A time signature of 6/8, with a metronome click every 3rd 1/8 note, would be encoded
254///  `FF 58 04 06 03 24 08` Remember, a 1/4 note is 24 MIDI Clocks, therefore a bar of 6/8 is
255///  72 MIDI Clocks. Hence 3 1/8 notes is 36 (=0x24) MIDI Clocks.
256///
257/// (from http://www.somascape.org/midi/tech/mfile.html)
258#[derive(Debug, PartialEq, Copy, Clone)]
259pub struct TimeSignature {
260    /// The number of beats per bar
261    pub top: u8,
262    /// The size of those beats (1 = semibreve, 2 = minim, 3 = crotchet etc.)
263    pub bottom: u8,
264    /// Clock ticks between metronome clicks
265    pub ticks_per_metronome_click: u8,
266    /// The number of notated 32nd-notes in a MIDI quarter note - for a 1-1 corresponence this
267    /// should be 8.
268    pub number_32nd_in_quarter: u8,
269}
270
271/// All possible Key Signatures
272#[derive(Debug, PartialEq, Copy, Clone)]
273pub enum KeySignature {
274    CMajor,
275    // sharps
276    GMajor,
277    DMajor,
278    AMajor,
279    EMajor,
280    BMajor,
281    FSharpMajor,
282    CSharpMajor,
283    // flats
284    FMajor,
285    BFlatMajor,
286    EFlatMajor,
287    AFlatMajor,
288    DFlatMajor,
289    GFlatMajor,
290    CFlatMajor,
291
292    // minor
293    AMinor,
294    // sharps
295    EMinor,
296    BMinor,
297    FSharpMinor,
298    CSharpMinor,
299    GSharpMinor,
300    DSharpMinor,
301    ASharpMinor,
302    // flats
303    DMinor,
304    GMinor,
305    CMinor,
306    FMinor,
307    BFlatMinor,
308    EFlatMinor,
309    AFlatMinor,
310}
311
312impl KeySignature {
313    /// Count the number of sharps or flats
314    pub fn count(&self) -> u8 {
315        use self::KeySignature::*;
316        match *self {
317            CMajor | AMinor => 0,
318            GMajor | FMajor | EMinor | DMinor => 1,
319            DMajor | BFlatMajor | BMinor | GMinor => 2,
320            AMajor | EFlatMajor | FSharpMinor | CMinor => 3,
321            EMajor | AFlatMajor | CSharpMinor | FMinor => 4,
322            BMajor | DFlatMajor | GSharpMinor | BFlatMinor => 5,
323            FSharpMajor | GFlatMajor | DSharpMinor | EFlatMinor => 6,
324            CSharpMajor | CFlatMajor | ASharpMinor | AFlatMinor => 7,
325        }
326    }
327
328    /// Helper fn for whether there are sharps or flats, that doesn't panic
329    fn is_sharps_unchecked(&self) -> bool {
330        use self::KeySignature::*;
331        match *self {
332            GMajor | DMajor | AMajor | EMajor | BMajor | FSharpMajor | CSharpMajor | EMinor
333            | BMinor | FSharpMinor | CSharpMinor | GSharpMinor | DSharpMinor | ASharpMinor => true,
334            _ => false,
335        }
336    }
337
338    /// Whether there are sharps or flats
339    ///
340    /// # Panics
341    /// Panics if there are no sharps or flats. Use `count` to check this first to avoid
342    pub fn is_sharps(&self) -> bool {
343        use self::KeySignature::*;
344        match *self {
345            CMajor | AMinor => panic!("No sharps or flats"),
346            _ => self.is_sharps_unchecked(),
347        }
348    }
349
350    /// Get a tuple of the number of sharps/flats, and a bool that is true for sharps, false for
351    /// flats.
352    ///
353    /// The second value is not specified (could be anything) when the first is 0.
354    pub fn for_display(&self) -> (u8, bool) {
355        (self.count(), self.is_sharps_unchecked())
356    }
357}