Arduino MIDI File Parser
MidiFileParserState.h
1 #pragma once
2 #include "RingBuffer.h"
3 
4 namespace midi {
5 
9 enum midi_parser_status {
10  MIDI_PARSER_DELAY = -3,
11  MIDI_PARSER_EOB = -2,
12  MIDI_PARSER_ERROR = -1,
13  MIDI_PARSER_INIT = 0,
14  MIDI_PARSER_HEADER = 1,
15  MIDI_PARSER_TRACK = 2,
16  MIDI_PARSER_TRACK_MIDI = 3,
17  MIDI_PARSER_TRACK_META = 4,
18  MIDI_PARSER_TRACK_SYSEX = 5,
19 };
20 
21 enum midi_file_format {
22  MIDI_FILE_FORMAT_SINGLE_TRACK = 0,
23  MIDI_FILE_FORMAT_MULTIPLE_TRACKS = 1,
24  MIDI_FILE_FORMAT_MULTIPLE_SONGS = 2,
25 };
26 
30 struct midi_header {
31  int32_t size;
32  uint16_t format;
33  int16_t tracks_count;
34  int16_t time_division;
35 };
36 
40 struct midi_track {
41  int32_t size;
42  int32_t number; // track number
43 };
44 
45 enum midi_status {
46  MIDI_STATUS_NA = 0x0,
47  MIDI_STATUS_NOTE_OFF = 0x8,
48  MIDI_STATUS_NOTE_ON = 0x9,
49  MIDI_STATUS_NOTE_AT = 0xA, // after touch
50  MIDI_STATUS_CC = 0xB, // control change
51  MIDI_STATUS_PGM_CHANGE = 0xC,
52  MIDI_STATUS_CHANNEL_AT = 0xD, // after touch
53  MIDI_STATUS_PITCH_BEND = 0xE,
54 };
55 
59 enum midi_meta {
60  MIDI_META_SEQ_NUM = 0x00,
61  MIDI_META_TEXT = 0x01,
62  MIDI_META_COPYRIGHT = 0x02,
63  MIDI_META_TRACK_NAME = 0x03,
64  MIDI_META_INSTRUMENT_NAME = 0x04,
65  MIDI_META_LYRICS = 0x05,
66  MIDI_META_MAKER = 0x06,
67  MIDI_META_CUE_POINT = 0x07,
68  MIDI_META_CHANNEL_PREFIX = 0x20,
69  MIDI_META_END_OF_TRACK = 0x2F,
70  MIDI_META_SET_TEMPO = 0x51,
71  MIDI_META_SMPTE_OFFSET = 0x54,
72  MIDI_META_TIME_SIGNATURE = 0x58,
73  MIDI_META_KEY_SIGNATURE = 0x59,
74  MIDI_META_SEQ_SPECIFIC = 0x7F,
75 };
76 
81  unsigned status : 4;
82  unsigned channel : 4;
83  uint8_t param1;
84  uint8_t param2;
85 };
86 
92  uint64_t time_ms;
93  operator bool() { return status != 0; }
94 };
95 
96 
101  uint8_t type;
102  int32_t length;
103  const uint8_t *bytes; // reference to the input buffer
104 };
105 
110  uint8_t sysex;
111  uint8_t type;
112  int32_t length;
113  const uint8_t *bytes; // reference to the input buffer
114 };
115 
120  midi_parser_state() = default;
121  midi_parser_state(midi_parser_status status){
122  this->status = status;
123  }
124  enum midi_parser_status status;
125  enum midi_parser_status status_internal;
126  enum midi_status buffered_status;
127  unsigned buffered_channel;
128 
129  /* input buffer */
130  midi::RingBuffer in;
131 
132  /* result */
133  int64_t vtime;
134  int64_t vtime_ms=0;
135  // microseconds per quarter note - or from latest Set Tempo event
136  uint64_t tempo = 1000;
137  struct midi_header header;
138  struct midi_track track;
139  struct midi_midi_event midi;
140  struct midi_meta_event meta;
141  struct midi_sysex_event sysex;
142 
143  int64_t timeInTicks() {
144  return vtime;
145  }
146 
147  uint64_t timeInMs() {
148  if (vtime_ms!=0) return vtime_ms;
149  float ticks_per_quarter = header.time_division!=0 ? header.time_division: 48;
150  float us_per_quarter = tempo;
151  float us_per_tick = us_per_quarter / ticks_per_quarter;
152  float milliseconds = timeInTicks() * us_per_tick / 1000;
153  return milliseconds;
154  }
155 
156 };
157 
158 } // ns
RingBuffer that supports extensive peek operations to access and compare the next values.
Definition: RingBuffer.h:16
MIDI Header Information.
Definition: MidiFileParserState.h:30
MIDI Metadata Event Information.
Definition: MidiFileParserState.h:100
MIDI Event Information.
Definition: MidiFileParserState.h:80
MIDI Parser State Information.
Definition: MidiFileParserState.h:119
MIDI Sysex Event Information.
Definition: MidiFileParserState.h:109
Definition: MidiFileParserState.h:90
uint64_t time_ms
cummulated time in milliseconds
Definition: MidiFileParserState.h:92
MIDI Track Information.
Definition: MidiFileParserState.h:40