comparison data/fileio/MIDIFileReader.cpp @ 301:73537d900d4b

* Add MIDI file export (closes FR#1643721)
author Chris Cannam
date Thu, 04 Oct 2007 11:52:38 +0000
parents 4b2ea82fd0ed
children 14e0f60435b8
comparison
equal deleted inserted replaced
300:5877d68815c7 301:73537d900d4b
26 #include <cstdio> 26 #include <cstdio>
27 #include <algorithm> 27 #include <algorithm>
28 28
29 #include "MIDIFileReader.h" 29 #include "MIDIFileReader.h"
30 30
31 #include "MIDIEvent.h"
32
31 #include "model/Model.h" 33 #include "model/Model.h"
32 #include "base/Pitch.h" 34 #include "base/Pitch.h"
33 #include "base/RealTime.h" 35 #include "base/RealTime.h"
34 #include "model/NoteModel.h" 36 #include "model/NoteModel.h"
35 37
48 using std::ios; 50 using std::ios;
49 using std::vector; 51 using std::vector;
50 using std::map; 52 using std::map;
51 using std::set; 53 using std::set;
52 54
55 using namespace MIDIConstants;
56
53 //#define MIDI_DEBUG 1 57 //#define MIDI_DEBUG 1
54
55 static const char *const MIDI_FILE_HEADER = "MThd";
56 static const char *const MIDI_TRACK_HEADER = "MTrk";
57
58 static const MIDIFileReader::MIDIByte MIDI_STATUS_BYTE_MASK = 0x80;
59 static const MIDIFileReader::MIDIByte MIDI_MESSAGE_TYPE_MASK = 0xF0;
60 static const MIDIFileReader::MIDIByte MIDI_CHANNEL_NUM_MASK = 0x0F;
61 static const MIDIFileReader::MIDIByte MIDI_NOTE_OFF = 0x80;
62 static const MIDIFileReader::MIDIByte MIDI_NOTE_ON = 0x90;
63 static const MIDIFileReader::MIDIByte MIDI_POLY_AFTERTOUCH = 0xA0;
64 static const MIDIFileReader::MIDIByte MIDI_CTRL_CHANGE = 0xB0;
65 static const MIDIFileReader::MIDIByte MIDI_PROG_CHANGE = 0xC0;
66 static const MIDIFileReader::MIDIByte MIDI_CHNL_AFTERTOUCH = 0xD0;
67 static const MIDIFileReader::MIDIByte MIDI_PITCH_BEND = 0xE0;
68 static const MIDIFileReader::MIDIByte MIDI_SELECT_CHNL_MODE = 0xB0;
69 static const MIDIFileReader::MIDIByte MIDI_SYSTEM_EXCLUSIVE = 0xF0;
70 static const MIDIFileReader::MIDIByte MIDI_TC_QUARTER_FRAME = 0xF1;
71 static const MIDIFileReader::MIDIByte MIDI_SONG_POSITION_PTR = 0xF2;
72 static const MIDIFileReader::MIDIByte MIDI_SONG_SELECT = 0xF3;
73 static const MIDIFileReader::MIDIByte MIDI_TUNE_REQUEST = 0xF6;
74 static const MIDIFileReader::MIDIByte MIDI_END_OF_EXCLUSIVE = 0xF7;
75 static const MIDIFileReader::MIDIByte MIDI_TIMING_CLOCK = 0xF8;
76 static const MIDIFileReader::MIDIByte MIDI_START = 0xFA;
77 static const MIDIFileReader::MIDIByte MIDI_CONTINUE = 0xFB;
78 static const MIDIFileReader::MIDIByte MIDI_STOP = 0xFC;
79 static const MIDIFileReader::MIDIByte MIDI_ACTIVE_SENSING = 0xFE;
80 static const MIDIFileReader::MIDIByte MIDI_SYSTEM_RESET = 0xFF;
81 static const MIDIFileReader::MIDIByte MIDI_SYSEX_NONCOMMERCIAL = 0x7D;
82 static const MIDIFileReader::MIDIByte MIDI_SYSEX_NON_RT = 0x7E;
83 static const MIDIFileReader::MIDIByte MIDI_SYSEX_RT = 0x7F;
84 static const MIDIFileReader::MIDIByte MIDI_SYSEX_RT_COMMAND = 0x06;
85 static const MIDIFileReader::MIDIByte MIDI_SYSEX_RT_RESPONSE = 0x07;
86 static const MIDIFileReader::MIDIByte MIDI_MMC_STOP = 0x01;
87 static const MIDIFileReader::MIDIByte MIDI_MMC_PLAY = 0x02;
88 static const MIDIFileReader::MIDIByte MIDI_MMC_DEFERRED_PLAY = 0x03;
89 static const MIDIFileReader::MIDIByte MIDI_MMC_FAST_FORWARD = 0x04;
90 static const MIDIFileReader::MIDIByte MIDI_MMC_REWIND = 0x05;
91 static const MIDIFileReader::MIDIByte MIDI_MMC_RECORD_STROBE = 0x06;
92 static const MIDIFileReader::MIDIByte MIDI_MMC_RECORD_EXIT = 0x07;
93 static const MIDIFileReader::MIDIByte MIDI_MMC_RECORD_PAUSE = 0x08;
94 static const MIDIFileReader::MIDIByte MIDI_MMC_PAUSE = 0x08;
95 static const MIDIFileReader::MIDIByte MIDI_MMC_EJECT = 0x0A;
96 static const MIDIFileReader::MIDIByte MIDI_MMC_LOCATE = 0x44;
97 static const MIDIFileReader::MIDIByte MIDI_FILE_META_EVENT = 0xFF;
98 static const MIDIFileReader::MIDIByte MIDI_SEQUENCE_NUMBER = 0x00;
99 static const MIDIFileReader::MIDIByte MIDI_TEXT_EVENT = 0x01;
100 static const MIDIFileReader::MIDIByte MIDI_COPYRIGHT_NOTICE = 0x02;
101 static const MIDIFileReader::MIDIByte MIDI_TRACK_NAME = 0x03;
102 static const MIDIFileReader::MIDIByte MIDI_INSTRUMENT_NAME = 0x04;
103 static const MIDIFileReader::MIDIByte MIDI_LYRIC = 0x05;
104 static const MIDIFileReader::MIDIByte MIDI_TEXT_MARKER = 0x06;
105 static const MIDIFileReader::MIDIByte MIDI_CUE_POINT = 0x07;
106 static const MIDIFileReader::MIDIByte MIDI_CHANNEL_PREFIX = 0x20;
107 static const MIDIFileReader::MIDIByte MIDI_CHANNEL_PREFIX_OR_PORT = 0x21;
108 static const MIDIFileReader::MIDIByte MIDI_END_OF_TRACK = 0x2F;
109 static const MIDIFileReader::MIDIByte MIDI_SET_TEMPO = 0x51;
110 static const MIDIFileReader::MIDIByte MIDI_SMPTE_OFFSET = 0x54;
111 static const MIDIFileReader::MIDIByte MIDI_TIME_SIGNATURE = 0x58;
112 static const MIDIFileReader::MIDIByte MIDI_KEY_SIGNATURE = 0x59;
113 static const MIDIFileReader::MIDIByte MIDI_SEQUENCER_SPECIFIC = 0x7F;
114 static const MIDIFileReader::MIDIByte MIDI_CONTROLLER_BANK_MSB = 0x00;
115 static const MIDIFileReader::MIDIByte MIDI_CONTROLLER_VOLUME = 0x07;
116 static const MIDIFileReader::MIDIByte MIDI_CONTROLLER_BANK_LSB = 0x20;
117 static const MIDIFileReader::MIDIByte MIDI_CONTROLLER_MODULATION = 0x01;
118 static const MIDIFileReader::MIDIByte MIDI_CONTROLLER_PAN = 0x0A;
119 static const MIDIFileReader::MIDIByte MIDI_CONTROLLER_SUSTAIN = 0x40;
120 static const MIDIFileReader::MIDIByte MIDI_CONTROLLER_RESONANCE = 0x47;
121 static const MIDIFileReader::MIDIByte MIDI_CONTROLLER_RELEASE = 0x48;
122 static const MIDIFileReader::MIDIByte MIDI_CONTROLLER_ATTACK = 0x49;
123 static const MIDIFileReader::MIDIByte MIDI_CONTROLLER_FILTER = 0x4A;
124 static const MIDIFileReader::MIDIByte MIDI_CONTROLLER_REVERB = 0x5B;
125 static const MIDIFileReader::MIDIByte MIDI_CONTROLLER_CHORUS = 0x5D;
126 static const MIDIFileReader::MIDIByte MIDI_CONTROLLER_NRPN_1 = 0x62;
127 static const MIDIFileReader::MIDIByte MIDI_CONTROLLER_NRPN_2 = 0x63;
128 static const MIDIFileReader::MIDIByte MIDI_CONTROLLER_RPN_1 = 0x64;
129 static const MIDIFileReader::MIDIByte MIDI_CONTROLLER_RPN_2 = 0x65;
130 static const MIDIFileReader::MIDIByte MIDI_CONTROLLER_SOUNDS_OFF = 0x78;
131 static const MIDIFileReader::MIDIByte MIDI_CONTROLLER_RESET = 0x79;
132 static const MIDIFileReader::MIDIByte MIDI_CONTROLLER_LOCAL = 0x7A;
133 static const MIDIFileReader::MIDIByte MIDI_CONTROLLER_ALL_NOTES_OFF = 0x7B;
134 static const MIDIFileReader::MIDIByte MIDI_PERCUSSION_CHANNEL = 9;
135
136 class MIDIEvent
137 {
138 public:
139 typedef MIDIFileReader::MIDIByte MIDIByte;
140
141 MIDIEvent(unsigned long deltaTime,
142 MIDIByte eventCode,
143 MIDIByte data1 = 0,
144 MIDIByte data2 = 0) :
145 m_deltaTime(deltaTime),
146 m_duration(0),
147 m_eventCode(eventCode),
148 m_data1(data1),
149 m_data2(data2),
150 m_metaEventCode(0)
151 { }
152
153 MIDIEvent(unsigned long deltaTime,
154 MIDIByte eventCode,
155 MIDIByte metaEventCode,
156 const string &metaMessage) :
157 m_deltaTime(deltaTime),
158 m_duration(0),
159 m_eventCode(eventCode),
160 m_data1(0),
161 m_data2(0),
162 m_metaEventCode(metaEventCode),
163 m_metaMessage(metaMessage)
164 { }
165
166 MIDIEvent(unsigned long deltaTime,
167 MIDIByte eventCode,
168 const string &sysEx) :
169 m_deltaTime(deltaTime),
170 m_duration(0),
171 m_eventCode(eventCode),
172 m_data1(0),
173 m_data2(0),
174 m_metaEventCode(0),
175 m_metaMessage(sysEx)
176 { }
177
178 ~MIDIEvent() { }
179
180 void setTime(const unsigned long &time) { m_deltaTime = time; }
181 void setDuration(const unsigned long& duration) { m_duration = duration;}
182 unsigned long addTime(const unsigned long &time) {
183 m_deltaTime += time;
184 return m_deltaTime;
185 }
186
187 MIDIByte getMessageType() const
188 { return (m_eventCode & MIDI_MESSAGE_TYPE_MASK); }
189
190 MIDIByte getChannelNumber() const
191 { return (m_eventCode & MIDI_CHANNEL_NUM_MASK); }
192
193 unsigned long getTime() const { return m_deltaTime; }
194 unsigned long getDuration() const { return m_duration; }
195
196 MIDIByte getPitch() const { return m_data1; }
197 MIDIByte getVelocity() const { return m_data2; }
198 MIDIByte getData1() const { return m_data1; }
199 MIDIByte getData2() const { return m_data2; }
200 MIDIByte getEventCode() const { return m_eventCode; }
201
202 bool isMeta() const { return (m_eventCode == MIDI_FILE_META_EVENT); }
203
204 MIDIByte getMetaEventCode() const { return m_metaEventCode; }
205 string getMetaMessage() const { return m_metaMessage; }
206 void setMetaMessage(const string &meta) { m_metaMessage = meta; }
207
208 friend bool operator<(const MIDIEvent &a, const MIDIEvent &b);
209
210 private:
211 MIDIEvent& operator=(const MIDIEvent);
212
213 unsigned long m_deltaTime;
214 unsigned long m_duration;
215 MIDIByte m_eventCode;
216 MIDIByte m_data1; // or Note
217 MIDIByte m_data2; // or Velocity
218 MIDIByte m_metaEventCode;
219 string m_metaMessage;
220 };
221
222 // Comparator for sorting
223 //
224 struct MIDIEventCmp
225 {
226 bool operator()(const MIDIEvent &mE1, const MIDIEvent &mE2) const
227 { return mE1.getTime() < mE2.getTime(); }
228
229 bool operator()(const MIDIEvent *mE1, const MIDIEvent *mE2) const
230 { return mE1->getTime() < mE2->getTime(); }
231 };
232
233 class MIDIException : virtual public std::exception
234 {
235 public:
236 MIDIException(QString message) throw() : m_message(message) {
237 cerr << "WARNING: MIDI exception: "
238 << message.toLocal8Bit().data() << endl;
239 }
240 virtual ~MIDIException() throw() { }
241
242 virtual const char *what() const throw() {
243 return m_message.toLocal8Bit().data();
244 }
245
246 protected:
247 QString m_message;
248 };
249 58
250 59
251 MIDIFileReader::MIDIFileReader(QString path, 60 MIDIFileReader::MIDIFileReader(QString path,
252 size_t mainModelSampleRate) : 61 size_t mainModelSampleRate) :
253 m_timingDivision(0), 62 m_timingDivision(0),
323 132
324 // Gets a single byte from the MIDI byte stream. For each track 133 // Gets a single byte from the MIDI byte stream. For each track
325 // section we can read only a specified number of bytes held in 134 // section we can read only a specified number of bytes held in
326 // m_trackByteCount. 135 // m_trackByteCount.
327 // 136 //
328 MIDIFileReader::MIDIByte 137 MIDIByte
329 MIDIFileReader::getMIDIByte() 138 MIDIFileReader::getMIDIByte()
330 { 139 {
331 if (!m_midiFile) { 140 if (!m_midiFile) {
332 throw MIDIException(tr("getMIDIByte called but no MIDI file open")); 141 throw MIDIException(tr("getMIDIByte called but no MIDI file open"));
333 } 142 }
475 284
476 if (!*m_midiFile) { 285 if (!*m_midiFile) {
477 m_error = "File not found or not readable."; 286 m_error = "File not found or not readable.";
478 m_format = MIDI_FILE_BAD_FORMAT; 287 m_format = MIDI_FILE_BAD_FORMAT;
479 delete m_midiFile; 288 delete m_midiFile;
289 m_midiFile = 0;
480 return false; 290 return false;
481 } 291 }
482 292
483 bool retval = false; 293 bool retval = false;
484 294