Mercurial > hg > svcore
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 |