Mercurial > hg > svcore
comparison data/fileio/MIDIFileReader.cpp @ 1527:710e6250a401 zoom
Merge from default branch
author | Chris Cannam |
---|---|
date | Mon, 17 Sep 2018 13:51:14 +0100 |
parents | 1dc64d3d323c |
children | 70e172e6cc59 |
comparison
equal
deleted
inserted
replaced
1324:d4a28d1479a8 | 1527:710e6250a401 |
---|---|
51 using std::map; | 51 using std::map; |
52 using std::set; | 52 using std::set; |
53 | 53 |
54 using namespace MIDIConstants; | 54 using namespace MIDIConstants; |
55 | 55 |
56 //#define MIDI_SVDEBUG 1 | 56 //#define MIDI_DEBUG 1 |
57 | 57 |
58 | 58 |
59 MIDIFileReader::MIDIFileReader(QString path, | 59 MIDIFileReader::MIDIFileReader(QString path, |
60 MIDIFileImportPreferenceAcquirer *acquirer, | 60 MIDIFileImportPreferenceAcquirer *acquirer, |
61 sv_samplerate_t mainModelSampleRate) : | 61 sv_samplerate_t mainModelSampleRate, |
62 ProgressReporter *) : // we don't actually report progress | |
62 m_smpte(false), | 63 m_smpte(false), |
63 m_timingDivision(0), | 64 m_timingDivision(0), |
64 m_fps(0), | 65 m_fps(0), |
65 m_subframes(0), | 66 m_subframes(0), |
66 m_format(MIDI_FILE_BAD_FORMAT), | 67 m_format(MIDI_FILE_BAD_FORMAT), |
72 m_fileSize(0), | 73 m_fileSize(0), |
73 m_mainModelSampleRate(mainModelSampleRate), | 74 m_mainModelSampleRate(mainModelSampleRate), |
74 m_acquirer(acquirer) | 75 m_acquirer(acquirer) |
75 { | 76 { |
76 if (parseFile()) { | 77 if (parseFile()) { |
77 m_error = ""; | 78 m_error = ""; |
78 } | 79 } |
79 } | 80 } |
80 | 81 |
81 MIDIFileReader::~MIDIFileReader() | 82 MIDIFileReader::~MIDIFileReader() |
82 { | 83 { |
83 for (MIDIComposition::iterator i = m_midiComposition.begin(); | 84 for (MIDIComposition::iterator i = m_midiComposition.begin(); |
84 i != m_midiComposition.end(); ++i) { | 85 i != m_midiComposition.end(); ++i) { |
85 | 86 |
86 for (MIDITrack::iterator j = i->second.begin(); | 87 for (MIDITrack::iterator j = i->second.begin(); |
87 j != i->second.end(); ++j) { | 88 j != i->second.end(); ++j) { |
88 delete *j; | 89 delete *j; |
89 } | 90 } |
90 | 91 |
91 i->second.clear(); | 92 i->second.clear(); |
92 } | 93 } |
93 | 94 |
94 m_midiComposition.clear(); | 95 m_midiComposition.clear(); |
95 } | 96 } |
96 | 97 |
108 | 109 |
109 long | 110 long |
110 MIDIFileReader::midiBytesToLong(const string& bytes) | 111 MIDIFileReader::midiBytesToLong(const string& bytes) |
111 { | 112 { |
112 if (bytes.length() != 4) { | 113 if (bytes.length() != 4) { |
113 throw MIDIException(tr("Wrong length for long data in MIDI stream (%1, should be %2)").arg(bytes.length()).arg(4)); | 114 throw MIDIException(tr("Wrong length for long data in MIDI stream (%1, should be %2)").arg(bytes.length()).arg(4)); |
114 } | 115 } |
115 | 116 |
116 long longRet = ((long)(((MIDIByte)bytes[0]) << 24)) | | 117 long longRet = ((long)(((MIDIByte)bytes[0]) << 24)) | |
117 ((long)(((MIDIByte)bytes[1]) << 16)) | | 118 ((long)(((MIDIByte)bytes[1]) << 16)) | |
118 ((long)(((MIDIByte)bytes[2]) << 8)) | | 119 ((long)(((MIDIByte)bytes[2]) << 8)) | |
123 | 124 |
124 int | 125 int |
125 MIDIFileReader::midiBytesToInt(const string& bytes) | 126 MIDIFileReader::midiBytesToInt(const string& bytes) |
126 { | 127 { |
127 if (bytes.length() != 2) { | 128 if (bytes.length() != 2) { |
128 throw MIDIException(tr("Wrong length for int data in MIDI stream (%1, should be %2)").arg(bytes.length()).arg(2)); | 129 throw MIDIException(tr("Wrong length for int data in MIDI stream (%1, should be %2)").arg(bytes.length()).arg(2)); |
129 } | 130 } |
130 | 131 |
131 int intRet = ((int)(((MIDIByte)bytes[0]) << 8)) | | 132 int intRet = ((int)(((MIDIByte)bytes[0]) << 8)) | |
132 ((int)(((MIDIByte)bytes[1]))); | 133 ((int)(((MIDIByte)bytes[1]))); |
133 return(intRet); | 134 return(intRet); |
140 // | 141 // |
141 MIDIByte | 142 MIDIByte |
142 MIDIFileReader::getMIDIByte() | 143 MIDIFileReader::getMIDIByte() |
143 { | 144 { |
144 if (!m_midiFile) { | 145 if (!m_midiFile) { |
145 throw MIDIException(tr("getMIDIByte called but no MIDI file open")); | 146 throw MIDIException(tr("getMIDIByte called but no MIDI file open")); |
146 } | 147 } |
147 | 148 |
148 if (m_midiFile->eof()) { | 149 if (m_midiFile->eof()) { |
149 throw MIDIException(tr("End of MIDI file encountered while reading")); | 150 throw MIDIException(tr("End of MIDI file encountered while reading")); |
150 } | 151 } |
153 throw MIDIException(tr("Attempt to get more bytes than expected on Track")); | 154 throw MIDIException(tr("Attempt to get more bytes than expected on Track")); |
154 } | 155 } |
155 | 156 |
156 char byte; | 157 char byte; |
157 if (m_midiFile->read(&byte, 1)) { | 158 if (m_midiFile->read(&byte, 1)) { |
158 --m_trackByteCount; | 159 --m_trackByteCount; |
159 return (MIDIByte)byte; | 160 return (MIDIByte)byte; |
160 } | 161 } |
161 | 162 |
162 throw MIDIException(tr("Attempt to read past MIDI file end")); | 163 throw MIDIException(tr("Attempt to read past MIDI file end")); |
163 } | 164 } |
164 | 165 |
169 // | 170 // |
170 string | 171 string |
171 MIDIFileReader::getMIDIBytes(unsigned long numberOfBytes) | 172 MIDIFileReader::getMIDIBytes(unsigned long numberOfBytes) |
172 { | 173 { |
173 if (!m_midiFile) { | 174 if (!m_midiFile) { |
174 throw MIDIException(tr("getMIDIBytes called but no MIDI file open")); | 175 throw MIDIException(tr("getMIDIBytes called but no MIDI file open")); |
175 } | 176 } |
176 | 177 |
177 if (m_midiFile->eof()) { | 178 if (m_midiFile->eof()) { |
178 throw MIDIException(tr("End of MIDI file encountered while reading")); | 179 throw MIDIException(tr("End of MIDI file encountered while reading")); |
179 } | 180 } |
210 // | 211 // |
211 long | 212 long |
212 MIDIFileReader::getNumberFromMIDIBytes(int firstByte) | 213 MIDIFileReader::getNumberFromMIDIBytes(int firstByte) |
213 { | 214 { |
214 if (!m_midiFile) { | 215 if (!m_midiFile) { |
215 throw MIDIException(tr("getNumberFromMIDIBytes called but no MIDI file open")); | 216 throw MIDIException(tr("getNumberFromMIDIBytes called but no MIDI file open")); |
216 } | 217 } |
217 | 218 |
218 long longRet = 0; | 219 long longRet = 0; |
219 MIDIByte midiByte; | 220 MIDIByte midiByte; |
220 | 221 |
221 if (firstByte >= 0) { | 222 if (firstByte >= 0) { |
222 midiByte = (MIDIByte)firstByte; | 223 midiByte = (MIDIByte)firstByte; |
223 } else if (m_midiFile->eof()) { | 224 } else if (m_midiFile->eof()) { |
224 return longRet; | 225 return longRet; |
225 } else { | 226 } else { |
226 midiByte = getMIDIByte(); | 227 midiByte = getMIDIByte(); |
227 } | 228 } |
228 | 229 |
229 longRet = midiByte; | 230 longRet = midiByte; |
230 if (midiByte & 0x80) { | 231 if (midiByte & 0x80) { |
231 longRet &= 0x7F; | 232 longRet &= 0x7F; |
232 do { | 233 do { |
233 midiByte = getMIDIByte(); | 234 midiByte = getMIDIByte(); |
234 longRet = (longRet << 7) + (midiByte & 0x7F); | 235 longRet = (longRet << 7) + (midiByte & 0x7F); |
235 } while (!m_midiFile->eof() && (midiByte & 0x80)); | 236 } while (!m_midiFile->eof() && (midiByte & 0x80)); |
236 } | 237 } |
237 | 238 |
238 return longRet; | 239 return longRet; |
239 } | 240 } |
240 | 241 |
244 // | 245 // |
245 bool | 246 bool |
246 MIDIFileReader::skipToNextTrack() | 247 MIDIFileReader::skipToNextTrack() |
247 { | 248 { |
248 if (!m_midiFile) { | 249 if (!m_midiFile) { |
249 throw MIDIException(tr("skipToNextTrack called but no MIDI file open")); | 250 throw MIDIException(tr("skipToNextTrack called but no MIDI file open")); |
250 } | 251 } |
251 | 252 |
252 string buffer, buffer2; | 253 string buffer, buffer2; |
253 m_trackByteCount = -1; | 254 m_trackByteCount = -1; |
254 m_decrementCount = false; | 255 m_decrementCount = false; |
255 | 256 |
256 while (!m_midiFile->eof() && (m_decrementCount == false)) { | 257 while (!m_midiFile->eof() && (m_decrementCount == false)) { |
257 buffer = getMIDIBytes(4); | 258 buffer = getMIDIBytes(4); |
258 if (buffer.compare(0, 4, MIDI_TRACK_HEADER) == 0) { | 259 if (buffer.compare(0, 4, MIDI_TRACK_HEADER) == 0) { |
259 m_trackByteCount = midiBytesToLong(getMIDIBytes(4)); | 260 m_trackByteCount = midiBytesToLong(getMIDIBytes(4)); |
260 m_decrementCount = true; | 261 m_decrementCount = true; |
261 } | 262 } |
262 } | 263 } |
263 | 264 |
264 if (m_trackByteCount == -1) { // we haven't found a track | 265 if (m_trackByteCount == -1) { // we haven't found a track |
265 return false; | 266 return false; |
266 } else { | 267 } else { |
282 SVDEBUG << "MIDIFileReader::open() : fileName = " << m_fileName.c_str() << endl; | 283 SVDEBUG << "MIDIFileReader::open() : fileName = " << m_fileName.c_str() << endl; |
283 #endif | 284 #endif |
284 | 285 |
285 // Open the file | 286 // Open the file |
286 m_midiFile = new ifstream(m_path.toLocal8Bit().data(), | 287 m_midiFile = new ifstream(m_path.toLocal8Bit().data(), |
287 ios::in | ios::binary); | 288 ios::in | ios::binary); |
288 | 289 |
289 if (!*m_midiFile) { | 290 if (!*m_midiFile) { |
290 m_error = "File not found or not readable."; | 291 m_error = "File not found or not readable."; |
291 m_format = MIDI_FILE_BAD_FORMAT; | 292 m_format = MIDI_FILE_BAD_FORMAT; |
292 delete m_midiFile; | 293 delete m_midiFile; |
293 m_midiFile = 0; | 294 m_midiFile = 0; |
294 return false; | 295 return false; |
295 } | 296 } |
296 | 297 |
297 bool retval = false; | 298 bool retval = false; |
298 | 299 |
299 try { | 300 try { |
300 | 301 |
301 // Set file size so we can count it off | 302 // Set file size so we can count it off |
302 // | 303 // |
303 m_midiFile->seekg(0, ios::end); | 304 m_midiFile->seekg(0, ios::end); |
304 std::streamoff off = m_midiFile->tellg(); | 305 std::streamoff off = m_midiFile->tellg(); |
305 m_fileSize = 0; | 306 m_fileSize = 0; |
306 if (off > 0) m_fileSize = off; | 307 if (off > 0) m_fileSize = off; |
307 m_midiFile->seekg(0, ios::beg); | 308 m_midiFile->seekg(0, ios::beg); |
308 | 309 |
309 // Parse the MIDI header first. The first 14 bytes of the file. | 310 // Parse the MIDI header first. The first 14 bytes of the file. |
310 if (!parseHeader(getMIDIBytes(14))) { | 311 if (!parseHeader(getMIDIBytes(14))) { |
311 m_format = MIDI_FILE_BAD_FORMAT; | 312 m_format = MIDI_FILE_BAD_FORMAT; |
312 m_error = "Not a MIDI file."; | 313 m_error = "Not a MIDI file."; |
313 goto done; | 314 goto done; |
314 } | 315 } |
315 | 316 |
316 unsigned int i = 0; | 317 unsigned int i = 0; |
317 | 318 |
318 for (unsigned int j = 0; j < m_numberOfTracks; ++j) { | 319 for (unsigned int j = 0; j < m_numberOfTracks; ++j) { |
319 | 320 |
320 #ifdef MIDI_DEBUG | 321 #ifdef MIDI_DEBUG |
321 SVDEBUG << "Parsing Track " << j << endl; | 322 SVDEBUG << "Parsing Track " << j << endl; |
322 #endif | 323 #endif |
323 | 324 |
324 if (!skipToNextTrack()) { | 325 if (!skipToNextTrack()) { |
325 #ifdef MIDI_DEBUG | 326 #ifdef MIDI_DEBUG |
326 cerr << "Couldn't find Track " << j << endl; | 327 SVDEBUG << "Couldn't find Track " << j << endl; |
327 #endif | 328 #endif |
328 m_error = "File corrupted or in non-standard format?"; | 329 m_error = "File corrupted or in non-standard format?"; |
329 m_format = MIDI_FILE_BAD_FORMAT; | 330 m_format = MIDI_FILE_BAD_FORMAT; |
330 goto done; | 331 goto done; |
331 } | 332 } |
332 | 333 |
333 #ifdef MIDI_DEBUG | 334 #ifdef MIDI_DEBUG |
334 cerr << "Track has " << m_trackByteCount << " bytes" << endl; | 335 SVDEBUG << "Track has " << m_trackByteCount << " bytes" << endl; |
335 #endif | 336 #endif |
336 | 337 |
337 // Run through the events taking them into our internal | 338 // Run through the events taking them into our internal |
338 // representation. | 339 // representation. |
339 if (!parseTrack(i)) { | 340 if (!parseTrack(i)) { |
340 #ifdef MIDI_DEBUG | 341 #ifdef MIDI_DEBUG |
341 cerr << "Track " << j << " parsing failed" << endl; | 342 SVDEBUG << "Track " << j << " parsing failed" << endl; |
342 #endif | 343 #endif |
343 m_error = "File corrupted or in non-standard format?"; | 344 m_error = "File corrupted or in non-standard format?"; |
344 m_format = MIDI_FILE_BAD_FORMAT; | 345 m_format = MIDI_FILE_BAD_FORMAT; |
345 goto done; | 346 goto done; |
346 } | 347 } |
347 | 348 |
348 ++i; // j is the source track number, i the destination | 349 ++i; // j is the source track number, i the destination |
349 } | 350 } |
350 | 351 |
351 m_numberOfTracks = i; | 352 m_numberOfTracks = i; |
352 retval = true; | 353 retval = true; |
353 | 354 |
354 } catch (MIDIException e) { | 355 } catch (const MIDIException &e) { |
355 | 356 |
356 SVDEBUG << "MIDIFileReader::open() - caught exception - " << e.what() << endl; | 357 SVDEBUG << "MIDIFileReader::open() - caught exception - " << e.what() << endl; |
357 m_error = e.what(); | 358 m_error = e.what(); |
358 } | 359 } |
359 | 360 |
360 done: | 361 done: |
361 m_midiFile->close(); | 362 m_midiFile->close(); |
362 delete m_midiFile; | 363 delete m_midiFile; |
365 | 366 |
366 // Convert the deltaTime to an absolute time since the track | 367 // Convert the deltaTime to an absolute time since the track |
367 // start. The addTime method returns the sum of the current | 368 // start. The addTime method returns the sum of the current |
368 // MIDI Event delta time plus the argument. | 369 // MIDI Event delta time plus the argument. |
369 | 370 |
370 unsigned long acc = 0; | 371 unsigned long acc = 0; |
371 | 372 |
372 for (MIDITrack::iterator i = m_midiComposition[track].begin(); | 373 for (MIDITrack::iterator i = m_midiComposition[track].begin(); |
373 i != m_midiComposition[track].end(); ++i) { | 374 i != m_midiComposition[track].end(); ++i) { |
374 acc = (*i)->addTime(acc); | 375 acc = (*i)->addTime(acc); |
375 } | 376 } |
376 | 377 |
377 if (consolidateNoteOffEvents(track)) { // returns true if some notes exist | 378 if (consolidateNoteOffEvents(track)) { // returns true if some notes exist |
378 m_loadableTracks.insert(track); | 379 m_loadableTracks.insert(track); |
379 } | 380 } |
380 } | 381 } |
381 | 382 |
382 for (unsigned int track = 0; track < m_numberOfTracks; ++track) { | 383 for (unsigned int track = 0; track < m_numberOfTracks; ++track) { |
383 updateTempoMap(track); | 384 updateTempoMap(track); |
384 } | 385 } |
400 return false; | 401 return false; |
401 } | 402 } |
402 | 403 |
403 if (midiHeader.compare(0, 4, MIDI_FILE_HEADER) != 0) { | 404 if (midiHeader.compare(0, 4, MIDI_FILE_HEADER) != 0) { |
404 #ifdef MIDI_DEBUG | 405 #ifdef MIDI_DEBUG |
405 SVDEBUG << "MIDIFileReader::parseHeader()" | 406 SVDEBUG << "MIDIFileReader::parseHeader()" |
406 << "- file header not found or malformed" | 407 << "- file header not found or malformed" |
407 << endl; | 408 << endl; |
408 #endif | 409 #endif |
409 return false; | 410 return false; |
410 } | 411 } |
411 | 412 |
412 if (midiBytesToLong(midiHeader.substr(4,4)) != 6L) { | 413 if (midiBytesToLong(midiHeader.substr(4,4)) != 6L) { |
413 #ifdef MIDI_DEBUG | 414 #ifdef MIDI_DEBUG |
414 SVDEBUG << "MIDIFileReader::parseHeader()" | 415 SVDEBUG << "MIDIFileReader::parseHeader()" |
415 << " - header length incorrect" | 416 << " - header length incorrect" |
416 << endl; | 417 << endl; |
417 #endif | 418 #endif |
418 return false; | 419 return false; |
419 } | 420 } |
420 | 421 |
421 m_format = (MIDIFileFormatType) midiBytesToInt(midiHeader.substr(8,2)); | 422 m_format = (MIDIFileFormatType) midiBytesToInt(midiHeader.substr(8,2)); |
472 | 473 |
473 bool firstTrack = true; | 474 bool firstTrack = true; |
474 | 475 |
475 while (!m_midiFile->eof() && (m_trackByteCount > 0)) { | 476 while (!m_midiFile->eof() && (m_trackByteCount > 0)) { |
476 | 477 |
477 if (eventCode < 0x80) { | 478 if (eventCode < 0x80) { |
478 #ifdef MIDI_DEBUG | 479 #ifdef MIDI_DEBUG |
479 cerr << "WARNING: Invalid event code " << eventCode | 480 SVDEBUG << "WARNING: Invalid event code " << eventCode |
480 << " in MIDI file" << endl; | 481 << " in MIDI file" << endl; |
481 #endif | 482 #endif |
482 throw MIDIException(tr("Invalid event code %1 found").arg(int(eventCode))); | 483 throw MIDIException(tr("Invalid event code %1 found").arg(int(eventCode))); |
483 } | 484 } |
484 | 485 |
485 deltaTime = getNumberFromMIDIBytes(); | 486 deltaTime = getNumberFromMIDIBytes(); |
486 | 487 |
487 #ifdef MIDI_DEBUG | 488 #ifdef MIDI_DEBUG |
488 cerr << "read delta time " << deltaTime << endl; | 489 SVDEBUG << "read delta time " << deltaTime << endl; |
489 #endif | 490 #endif |
490 | 491 |
491 // Get a single byte | 492 // Get a single byte |
492 midiByte = getMIDIByte(); | 493 midiByte = getMIDIByte(); |
493 | 494 |
494 if (!(midiByte & MIDI_STATUS_BYTE_MASK)) { | 495 if (!(midiByte & MIDI_STATUS_BYTE_MASK)) { |
495 | 496 |
496 if (runningStatus < 0) { | 497 if (runningStatus < 0) { |
497 throw MIDIException(tr("Running status used for first event in track")); | 498 throw MIDIException(tr("Running status used for first event in track")); |
498 } | 499 } |
499 | 500 |
500 eventCode = (MIDIByte)runningStatus; | 501 eventCode = (MIDIByte)runningStatus; |
501 data1 = midiByte; | 502 data1 = midiByte; |
502 | 503 |
503 #ifdef MIDI_DEBUG | 504 #ifdef MIDI_DEBUG |
504 SVDEBUG << "using running status (byte " << int(midiByte) << " found)" << endl; | 505 SVDEBUG << "using running status (byte " << int(midiByte) << " found)" << endl; |
505 #endif | 506 #endif |
506 } else { | 507 } else { |
507 #ifdef MIDI_DEBUG | 508 #ifdef MIDI_DEBUG |
508 cerr << "have new event code " << int(midiByte) << endl; | 509 SVDEBUG << "have new event code " << int(midiByte) << endl; |
509 #endif | 510 #endif |
510 eventCode = midiByte; | 511 eventCode = midiByte; |
511 data1 = getMIDIByte(); | 512 data1 = getMIDIByte(); |
512 } | 513 } |
513 | 514 |
514 if (eventCode == MIDI_FILE_META_EVENT) { | 515 if (eventCode == MIDI_FILE_META_EVENT) { |
515 | 516 |
516 metaEventCode = data1; | 517 metaEventCode = data1; |
517 messageLength = getNumberFromMIDIBytes(); | 518 messageLength = getNumberFromMIDIBytes(); |
518 | 519 |
519 //#ifdef MIDI_DEBUG | 520 //#ifdef MIDI_DEBUG |
520 cerr << "Meta event of type " << int(metaEventCode) << " and " << messageLength << " bytes found, putting on track " << metaTrack << endl; | 521 SVDEBUG << "Meta event of type " << int(metaEventCode) << " and " << messageLength << " bytes found, putting on track " << metaTrack << endl; |
521 //#endif | 522 //#endif |
522 metaMessage = getMIDIBytes(messageLength); | 523 metaMessage = getMIDIBytes(messageLength); |
523 | 524 |
524 long gap = accumulatedTime - trackTimeMap[metaTrack]; | 525 long gap = accumulatedTime - trackTimeMap[metaTrack]; |
525 accumulatedTime += deltaTime; | 526 accumulatedTime += deltaTime; |
526 deltaTime += gap; | 527 deltaTime += gap; |
527 trackTimeMap[metaTrack] = accumulatedTime; | 528 trackTimeMap[metaTrack] = accumulatedTime; |
528 | 529 |
529 MIDIEvent *e = new MIDIEvent(deltaTime, | 530 MIDIEvent *e = new MIDIEvent(deltaTime, |
530 MIDI_FILE_META_EVENT, | 531 MIDI_FILE_META_EVENT, |
531 metaEventCode, | 532 metaEventCode, |
532 metaMessage); | 533 metaMessage); |
533 | 534 |
534 m_midiComposition[metaTrack].push_back(e); | 535 m_midiComposition[metaTrack].push_back(e); |
535 | 536 |
536 if (metaEventCode == MIDI_TRACK_NAME) { | 537 if (metaEventCode == MIDI_TRACK_NAME) { |
537 m_trackNames[metaTrack] = metaMessage.c_str(); | 538 m_trackNames[metaTrack] = metaMessage.c_str(); |
538 } | 539 } |
539 | 540 |
540 } else { // non-meta events | 541 } else { // non-meta events |
541 | 542 |
542 runningStatus = eventCode; | 543 runningStatus = eventCode; |
543 | 544 |
544 MIDIEvent *midiEvent; | 545 MIDIEvent *midiEvent; |
545 | 546 |
546 int channel = (eventCode & MIDI_CHANNEL_NUM_MASK); | 547 int channel = (eventCode & MIDI_CHANNEL_NUM_MASK); |
547 if (channelTrackMap[channel] == -1) { | 548 if (channelTrackMap[channel] == -1) { |
548 if (!firstTrack) ++lastTrackNum; | 549 if (!firstTrack) ++lastTrackNum; |
549 else firstTrack = false; | 550 else firstTrack = false; |
550 channelTrackMap[channel] = lastTrackNum; | 551 channelTrackMap[channel] = lastTrackNum; |
551 } | 552 } |
552 | 553 |
553 unsigned int trackNum = channelTrackMap[channel]; | 554 unsigned int trackNum = channelTrackMap[channel]; |
554 | 555 |
555 // accumulatedTime is abs time of last event on any track; | 556 // accumulatedTime is abs time of last event on any track; |
556 // trackTimeMap[trackNum] is that of last event on this track | 557 // trackTimeMap[trackNum] is that of last event on this track |
557 | 558 |
558 long gap = accumulatedTime - trackTimeMap[trackNum]; | 559 long gap = accumulatedTime - trackTimeMap[trackNum]; |
559 accumulatedTime += deltaTime; | 560 accumulatedTime += deltaTime; |
560 deltaTime += gap; | 561 deltaTime += gap; |
561 trackTimeMap[trackNum] = accumulatedTime; | 562 trackTimeMap[trackNum] = accumulatedTime; |
562 | 563 |
563 switch (eventCode & MIDI_MESSAGE_TYPE_MASK) { | 564 switch (eventCode & MIDI_MESSAGE_TYPE_MASK) { |
564 | 565 |
565 case MIDI_NOTE_ON: | 566 case MIDI_NOTE_ON: |
566 case MIDI_NOTE_OFF: | 567 case MIDI_NOTE_OFF: |
570 | 571 |
571 // create and store our event | 572 // create and store our event |
572 midiEvent = new MIDIEvent(deltaTime, eventCode, data1, data2); | 573 midiEvent = new MIDIEvent(deltaTime, eventCode, data1, data2); |
573 | 574 |
574 /* | 575 /* |
575 cerr << "MIDI event for channel " << channel << " (track " | 576 SVDEBUG << "MIDI event for channel " << channel << " (track " |
576 << trackNum << ")" << endl; | 577 << trackNum << ")" << endl; |
577 midiEvent->print(); | 578 midiEvent->print(); |
578 */ | 579 */ |
579 | 580 |
580 | 581 |
581 m_midiComposition[trackNum].push_back(midiEvent); | 582 m_midiComposition[trackNum].push_back(midiEvent); |
582 | 583 |
583 if (midiEvent->getChannelNumber() == MIDI_PERCUSSION_CHANNEL) { | 584 if (midiEvent->getChannelNumber() == MIDI_PERCUSSION_CHANNEL) { |
584 m_percussionTracks.insert(trackNum); | 585 m_percussionTracks.insert(trackNum); |
585 } | 586 } |
586 | 587 |
587 break; | 588 break; |
588 | 589 |
589 case MIDI_PITCH_BEND: | 590 case MIDI_PITCH_BEND: |
590 data2 = getMIDIByte(); | 591 data2 = getMIDIByte(); |
603 | 604 |
604 case MIDI_SYSTEM_EXCLUSIVE: | 605 case MIDI_SYSTEM_EXCLUSIVE: |
605 messageLength = getNumberFromMIDIBytes(data1); | 606 messageLength = getNumberFromMIDIBytes(data1); |
606 | 607 |
607 #ifdef MIDI_DEBUG | 608 #ifdef MIDI_DEBUG |
608 cerr << "SysEx of " << messageLength << " bytes found" << endl; | 609 SVDEBUG << "SysEx of " << messageLength << " bytes found" << endl; |
609 #endif | 610 #endif |
610 | 611 |
611 metaMessage= getMIDIBytes(messageLength); | 612 metaMessage= getMIDIBytes(messageLength); |
612 | 613 |
613 if (MIDIByte(metaMessage[metaMessage.length() - 1]) != | 614 if (MIDIByte(metaMessage[metaMessage.length() - 1]) != |
642 } | 643 } |
643 } | 644 } |
644 } | 645 } |
645 | 646 |
646 if (lastTrackNum > metaTrack) { | 647 if (lastTrackNum > metaTrack) { |
647 for (unsigned int track = metaTrack + 1; track <= lastTrackNum; ++track) { | 648 for (unsigned int track = metaTrack + 1; track <= lastTrackNum; ++track) { |
648 m_trackNames[track] = QString("%1 <%2>") | 649 m_trackNames[track] = QString("%1 <%2>") |
649 .arg(m_trackNames[metaTrack]).arg(track - metaTrack + 1); | 650 .arg(m_trackNames[metaTrack]).arg(track - metaTrack + 1); |
650 } | 651 } |
651 } | 652 } |
652 | 653 |
653 return true; | 654 return true; |
654 } | 655 } |
655 | 656 |
662 { | 663 { |
663 bool notesOnTrack = false; | 664 bool notesOnTrack = false; |
664 bool noteOffFound; | 665 bool noteOffFound; |
665 | 666 |
666 for (MIDITrack::iterator i = m_midiComposition[track].begin(); | 667 for (MIDITrack::iterator i = m_midiComposition[track].begin(); |
667 i != m_midiComposition[track].end(); i++) { | 668 i != m_midiComposition[track].end(); i++) { |
668 | 669 |
669 if ((*i)->getMessageType() == MIDI_NOTE_ON && (*i)->getVelocity() > 0) { | 670 if ((*i)->getMessageType() == MIDI_NOTE_ON && (*i)->getVelocity() > 0) { |
670 | 671 |
671 notesOnTrack = true; | 672 notesOnTrack = true; |
672 noteOffFound = false; | 673 noteOffFound = false; |
673 | 674 |
674 for (MIDITrack::iterator j = i; | 675 for (MIDITrack::iterator j = i; |
675 j != m_midiComposition[track].end(); j++) { | 676 j != m_midiComposition[track].end(); j++) { |
676 | 677 |
677 if (((*j)->getChannelNumber() == (*i)->getChannelNumber()) && | 678 if (((*j)->getChannelNumber() == (*i)->getChannelNumber()) && |
678 ((*j)->getPitch() == (*i)->getPitch()) && | 679 ((*j)->getPitch() == (*i)->getPitch()) && |
679 ((*j)->getMessageType() == MIDI_NOTE_OFF || | 680 ((*j)->getMessageType() == MIDI_NOTE_OFF || |
680 ((*j)->getMessageType() == MIDI_NOTE_ON && | 681 ((*j)->getMessageType() == MIDI_NOTE_ON && |
681 (*j)->getVelocity() == 0x00))) { | 682 (*j)->getVelocity() == 0x00))) { |
682 | 683 |
683 (*i)->setDuration((*j)->getTime() - (*i)->getTime()); | 684 (*i)->setDuration((*j)->getTime() - (*i)->getTime()); |
692 | 693 |
693 // If no matching NOTE OFF has been found then set | 694 // If no matching NOTE OFF has been found then set |
694 // Event duration to length of track | 695 // Event duration to length of track |
695 // | 696 // |
696 if (!noteOffFound) { | 697 if (!noteOffFound) { |
697 MIDITrack::iterator j = m_midiComposition[track].end(); | 698 MIDITrack::iterator j = m_midiComposition[track].end(); |
698 --j; | 699 --j; |
699 (*i)->setDuration((*j)->getTime() - (*i)->getTime()); | 700 (*i)->setDuration((*j)->getTime() - (*i)->getTime()); |
700 } | 701 } |
701 } | 702 } |
702 } | 703 } |
703 | 704 |
704 return notesOnTrack; | 705 return notesOnTrack; |
705 } | 706 } |
707 // Add any tempo events found in the given track to the global tempo map. | 708 // Add any tempo events found in the given track to the global tempo map. |
708 // | 709 // |
709 void | 710 void |
710 MIDIFileReader::updateTempoMap(unsigned int track) | 711 MIDIFileReader::updateTempoMap(unsigned int track) |
711 { | 712 { |
712 cerr << "updateTempoMap for track " << track << " (" << m_midiComposition[track].size() << " events)" << endl; | 713 SVDEBUG << "updateTempoMap for track " << track << " (" << m_midiComposition[track].size() << " events)" << endl; |
713 | 714 |
714 for (MIDITrack::iterator i = m_midiComposition[track].begin(); | 715 for (MIDITrack::iterator i = m_midiComposition[track].begin(); |
715 i != m_midiComposition[track].end(); ++i) { | 716 i != m_midiComposition[track].end(); ++i) { |
716 | 717 |
717 if ((*i)->isMeta() && | 718 if ((*i)->isMeta() && |
718 (*i)->getMetaEventCode() == MIDI_SET_TEMPO) { | 719 (*i)->getMetaEventCode() == MIDI_SET_TEMPO) { |
719 | 720 |
720 MIDIByte m0 = (*i)->getMetaMessage()[0]; | 721 MIDIByte m0 = (*i)->getMetaMessage()[0]; |
721 MIDIByte m1 = (*i)->getMetaMessage()[1]; | 722 MIDIByte m1 = (*i)->getMetaMessage()[1]; |
722 MIDIByte m2 = (*i)->getMetaMessage()[2]; | 723 MIDIByte m2 = (*i)->getMetaMessage()[2]; |
723 | 724 |
724 long tempo = (((m0 << 8) + m1) << 8) + m2; | 725 long tempo = (((m0 << 8) + m1) << 8) + m2; |
725 | 726 |
726 cerr << "updateTempoMap: have tempo, it's " << tempo << " at " << (*i)->getTime() << endl; | 727 SVDEBUG << "updateTempoMap: have tempo, it's " << tempo << " at " << (*i)->getTime() << endl; |
727 | 728 |
728 if (tempo != 0) { | 729 if (tempo != 0) { |
729 double qpm = 60000000.0 / double(tempo); | 730 double qpm = 60000000.0 / double(tempo); |
730 m_tempoMap[(*i)->getTime()] = | 731 m_tempoMap[(*i)->getTime()] = |
731 TempoChange(RealTime::zeroTime, qpm); | 732 TempoChange(RealTime::zeroTime, qpm); |
732 } | 733 } |
733 } | 734 } |
734 } | 735 } |
735 } | 736 } |
736 | 737 |
737 void | 738 void |
742 double tempo = 120.0; | 743 double tempo = 120.0; |
743 int td = m_timingDivision; | 744 int td = m_timingDivision; |
744 if (td == 0) td = 96; | 745 if (td == 0) td = 96; |
745 | 746 |
746 for (TempoMap::iterator i = m_tempoMap.begin(); i != m_tempoMap.end(); ++i) { | 747 for (TempoMap::iterator i = m_tempoMap.begin(); i != m_tempoMap.end(); ++i) { |
747 | 748 |
748 unsigned long mtime = i->first; | 749 unsigned long mtime = i->first; |
749 unsigned long melapsed = mtime - lastMIDITime; | 750 unsigned long melapsed = mtime - lastMIDITime; |
750 double quarters = double(melapsed) / double(td); | 751 double quarters = double(melapsed) / double(td); |
751 double seconds = (60.0 * quarters) / tempo; | 752 double seconds = (60.0 * quarters) / tempo; |
752 | 753 |
753 RealTime t = lastRealTime + RealTime::fromSeconds(seconds); | 754 RealTime t = lastRealTime + RealTime::fromSeconds(seconds); |
754 | 755 |
755 i->second.first = t; | 756 i->second.first = t; |
756 | 757 |
757 lastRealTime = t; | 758 lastRealTime = t; |
758 lastMIDITime = mtime; | 759 lastMIDITime = mtime; |
759 tempo = i->second.second; | 760 tempo = i->second.second; |
760 } | 761 } |
761 } | 762 } |
762 | 763 |
763 RealTime | 764 RealTime |
764 MIDIFileReader::getTimeForMIDITime(unsigned long midiTime) const | 765 MIDIFileReader::getTimeForMIDITime(unsigned long midiTime) const |
767 RealTime tempoRealTime = RealTime::zeroTime; | 768 RealTime tempoRealTime = RealTime::zeroTime; |
768 double tempo = 120.0; | 769 double tempo = 120.0; |
769 | 770 |
770 TempoMap::const_iterator i = m_tempoMap.lower_bound(midiTime); | 771 TempoMap::const_iterator i = m_tempoMap.lower_bound(midiTime); |
771 if (i != m_tempoMap.begin()) { | 772 if (i != m_tempoMap.begin()) { |
772 --i; | 773 --i; |
773 tempoMIDITime = i->first; | 774 tempoMIDITime = i->first; |
774 tempoRealTime = i->second.first; | 775 tempoRealTime = i->second.first; |
775 tempo = i->second.second; | 776 tempo = i->second.second; |
776 } | 777 } |
777 | 778 |
778 int td = m_timingDivision; | 779 int td = m_timingDivision; |
779 if (td == 0) td = 96; | 780 if (td == 0) td = 96; |
780 | 781 |
782 double quarters = double(melapsed) / double(td); | 783 double quarters = double(melapsed) / double(td); |
783 double seconds = (60.0 * quarters) / tempo; | 784 double seconds = (60.0 * quarters) / tempo; |
784 | 785 |
785 /* | 786 /* |
786 SVDEBUG << "MIDIFileReader::getTimeForMIDITime(" << midiTime << ")" | 787 SVDEBUG << "MIDIFileReader::getTimeForMIDITime(" << midiTime << ")" |
787 << endl; | 788 << endl; |
788 SVDEBUG << "timing division = " << td << endl; | 789 SVDEBUG << "timing division = " << td << endl; |
789 cerr << "nearest tempo event (of " << m_tempoMap.size() << ") is at " << tempoMIDITime << " (" | 790 SVDEBUG << "nearest tempo event (of " << m_tempoMap.size() << ") is at " << tempoMIDITime << " (" |
790 << tempoRealTime << ")" << endl; | 791 << tempoRealTime << ")" << endl; |
791 cerr << "quarters since then = " << quarters << endl; | 792 SVDEBUG << "quarters since then = " << quarters << endl; |
792 cerr << "tempo = " << tempo << " quarters per minute" << endl; | 793 SVDEBUG << "tempo = " << tempo << " quarters per minute" << endl; |
793 cerr << "seconds since then = " << seconds << endl; | 794 SVDEBUG << "seconds since then = " << seconds << endl; |
794 SVDEBUG << "resulting time = " << (tempoRealTime + RealTime::fromSeconds(seconds)) << endl; | 795 SVDEBUG << "resulting time = " << (tempoRealTime + RealTime::fromSeconds(seconds)) << endl; |
795 */ | 796 */ |
796 | 797 |
797 return tempoRealTime + RealTime::fromSeconds(seconds); | 798 return tempoRealTime + RealTime::fromSeconds(seconds); |
798 } | 799 } |
805 if (m_loadableTracks.empty()) { | 806 if (m_loadableTracks.empty()) { |
806 if (m_acquirer) { | 807 if (m_acquirer) { |
807 m_acquirer->showError | 808 m_acquirer->showError |
808 (tr("MIDI file \"%1\" has no notes in any track").arg(m_path)); | 809 (tr("MIDI file \"%1\" has no notes in any track").arg(m_path)); |
809 } | 810 } |
810 return 0; | 811 return 0; |
811 } | 812 } |
812 | 813 |
813 std::set<unsigned int> tracksToLoad; | 814 std::set<unsigned int> tracksToLoad; |
814 | 815 |
815 if (m_loadableTracks.size() == 1) { | 816 if (m_loadableTracks.size() == 1) { |
816 | 817 |
817 tracksToLoad.insert(*m_loadableTracks.begin()); | 818 tracksToLoad.insert(*m_loadableTracks.begin()); |
818 | 819 |
819 } else { | 820 } else { |
820 | 821 |
821 QStringList displayNames; | 822 QStringList displayNames; |
822 | 823 |
823 for (set<unsigned int>::iterator i = m_loadableTracks.begin(); | 824 for (set<unsigned int>::iterator i = m_loadableTracks.begin(); |
824 i != m_loadableTracks.end(); ++i) { | 825 i != m_loadableTracks.end(); ++i) { |
825 | 826 |
826 unsigned int trackNo = *i; | 827 unsigned int trackNo = *i; |
827 QString label; | 828 QString label; |
828 | 829 |
829 QString perc; | 830 QString perc; |
830 if (m_percussionTracks.find(trackNo) != m_percussionTracks.end()) { | 831 if (m_percussionTracks.find(trackNo) != m_percussionTracks.end()) { |
831 perc = tr(" - uses GM percussion channel"); | 832 perc = tr(" - uses GM percussion channel"); |
832 } | 833 } |
833 | 834 |
834 if (m_trackNames.find(trackNo) != m_trackNames.end()) { | 835 if (m_trackNames.find(trackNo) != m_trackNames.end()) { |
835 label = tr("Track %1 (%2)%3") | 836 label = tr("Track %1 (%2)%3") |
836 .arg(trackNo).arg(m_trackNames.find(trackNo)->second) | 837 .arg(trackNo).arg(m_trackNames.find(trackNo)->second) |
837 .arg(perc); | 838 .arg(perc); |
838 } else { | 839 } else { |
839 label = tr("Track %1 (untitled)%3").arg(trackNo).arg(perc); | 840 label = tr("Track %1 (untitled)%3").arg(trackNo).arg(perc); |
840 } | 841 } |
841 | 842 |
842 displayNames << label; | 843 displayNames << label; |
843 } | 844 } |
844 | 845 |
845 QString singleTrack; | 846 QString singleTrack; |
846 | 847 |
847 bool haveSomePercussion = | 848 bool haveSomePercussion = |
848 (!m_percussionTracks.empty() && | 849 (!m_percussionTracks.empty() && |
864 pref == MIDIFileImportPreferenceAcquirer::MergeAllNonPercussionTracks) { | 865 pref == MIDIFileImportPreferenceAcquirer::MergeAllNonPercussionTracks) { |
865 | 866 |
866 for (set<unsigned int>::iterator i = m_loadableTracks.begin(); | 867 for (set<unsigned int>::iterator i = m_loadableTracks.begin(); |
867 i != m_loadableTracks.end(); ++i) { | 868 i != m_loadableTracks.end(); ++i) { |
868 | 869 |
869 if (pref == MIDIFileImportPreferenceAcquirer::MergeAllTracks || | 870 if (pref == MIDIFileImportPreferenceAcquirer::MergeAllTracks || |
870 m_percussionTracks.find(*i) == m_percussionTracks.end()) { | 871 m_percussionTracks.find(*i) == m_percussionTracks.end()) { |
871 | 872 |
872 tracksToLoad.insert(*i); | 873 tracksToLoad.insert(*i); |
873 } | 874 } |
874 } | 875 } |
875 | 876 |
876 } else { | 877 } else { |
877 | 878 |
878 int j = 0; | 879 int j = 0; |
879 | 880 |
880 for (set<unsigned int>::iterator i = m_loadableTracks.begin(); | 881 for (set<unsigned int>::iterator i = m_loadableTracks.begin(); |
881 i != m_loadableTracks.end(); ++i) { | 882 i != m_loadableTracks.end(); ++i) { |
882 | 883 |
883 if (singleTrack == displayNames[j]) { | 884 if (singleTrack == displayNames[j]) { |
884 tracksToLoad.insert(*i); | 885 tracksToLoad.insert(*i); |
885 break; | 886 break; |
886 } | 887 } |
887 | 888 |
888 ++j; | 889 ++j; |
889 } | 890 } |
890 } | 891 } |
891 } | 892 } |
892 | 893 |
893 if (tracksToLoad.empty()) return 0; | 894 if (tracksToLoad.empty()) return 0; |
894 | 895 |
895 int n = int(tracksToLoad.size()), count = 0; | 896 int n = int(tracksToLoad.size()), count = 0; |
896 Model *model = 0; | 897 Model *model = 0; |
897 | 898 |
898 for (std::set<unsigned int>::iterator i = tracksToLoad.begin(); | 899 for (std::set<unsigned int>::iterator i = tracksToLoad.begin(); |
899 i != tracksToLoad.end(); ++i) { | 900 i != tracksToLoad.end(); ++i) { |
900 | 901 |
901 int minProgress = (100 * count) / n; | 902 int minProgress = (100 * count) / n; |
902 int progressAmount = 100 / n; | 903 int progressAmount = 100 / n; |
903 | 904 |
904 model = loadTrack(*i, model, minProgress, progressAmount); | 905 model = loadTrack(*i, model, minProgress, progressAmount); |
905 | 906 |
906 ++count; | 907 ++count; |
907 } | 908 } |
908 | 909 |
909 if (dynamic_cast<NoteModel *>(model)) { | 910 if (dynamic_cast<NoteModel *>(model)) { |
910 dynamic_cast<NoteModel *>(model)->setCompletion(100); | 911 dynamic_cast<NoteModel *>(model)->setCompletion(100); |
911 } | 912 } |
912 | 913 |
913 return model; | 914 return model; |
914 } | 915 } |
915 | 916 |
916 Model * | 917 Model * |
917 MIDIFileReader::loadTrack(unsigned int trackToLoad, | 918 MIDIFileReader::loadTrack(unsigned int trackToLoad, |
918 Model *existingModel, | 919 Model *existingModel, |
919 int minProgress, | 920 int minProgress, |
920 int progressAmount) const | 921 int progressAmount) const |
921 { | 922 { |
922 if (m_midiComposition.find(trackToLoad) == m_midiComposition.end()) { | 923 if (m_midiComposition.find(trackToLoad) == m_midiComposition.end()) { |
923 return 0; | 924 return 0; |
924 } | 925 } |
925 | 926 |
926 NoteModel *model = 0; | 927 NoteModel *model = 0; |
927 | 928 |
928 if (existingModel) { | 929 if (existingModel) { |
929 model = dynamic_cast<NoteModel *>(existingModel); | 930 model = dynamic_cast<NoteModel *>(existingModel); |
930 if (!model) { | 931 if (!model) { |
931 cerr << "WARNING: MIDIFileReader::loadTrack: Existing model given, but it isn't a NoteModel -- ignoring it" << endl; | 932 SVDEBUG << "WARNING: MIDIFileReader::loadTrack: Existing model given, but it isn't a NoteModel -- ignoring it" << endl; |
932 } | 933 } |
933 } | 934 } |
934 | 935 |
935 if (!model) { | 936 if (!model) { |
936 model = new NoteModel(m_mainModelSampleRate, 1, 0.0, 0.0, false); | 937 model = new NoteModel(m_mainModelSampleRate, 1, 0.0, 0.0, false); |
937 model->setValueQuantization(1.0); | 938 model->setValueQuantization(1.0); |
938 model->setObjectName(QFileInfo(m_path).fileName()); | 939 model->setObjectName(QFileInfo(m_path).fileName()); |
939 } | 940 } |
940 | 941 |
941 const MIDITrack &track = m_midiComposition.find(trackToLoad)->second; | 942 const MIDITrack &track = m_midiComposition.find(trackToLoad)->second; |
942 | 943 |
954 rt = RealTime::frame2RealTime(midiTime, m_fps * m_subframes); | 955 rt = RealTime::frame2RealTime(midiTime, m_fps * m_subframes); |
955 } else { | 956 } else { |
956 rt = getTimeForMIDITime(midiTime); | 957 rt = getTimeForMIDITime(midiTime); |
957 } | 958 } |
958 | 959 |
959 // We ignore most of these event types for now, though in | 960 // We ignore most of these event types for now, though in |
960 // theory some of the text ones could usefully be incorporated | 961 // theory some of the text ones could usefully be incorporated |
961 | 962 |
962 if ((*i)->isMeta()) { | 963 if ((*i)->isMeta()) { |
963 | 964 |
964 switch((*i)->getMetaEventCode()) { | 965 switch((*i)->getMetaEventCode()) { |
965 | 966 |
966 case MIDI_KEY_SIGNATURE: | 967 case MIDI_KEY_SIGNATURE: |
967 // minorKey = (int((*i)->getMetaMessage()[1]) != 0); | 968 // minorKey = (int((*i)->getMetaMessage()[1]) != 0); |
968 sharpKey = (int((*i)->getMetaMessage()[0]) >= 0); | 969 sharpKey = (int((*i)->getMetaMessage()[0]) >= 0); |
969 break; | 970 break; |
970 | 971 |
971 case MIDI_TEXT_EVENT: | 972 case MIDI_TEXT_EVENT: |
972 case MIDI_LYRIC: | 973 case MIDI_LYRIC: |
973 case MIDI_TEXT_MARKER: | 974 case MIDI_TEXT_MARKER: |
974 case MIDI_COPYRIGHT_NOTICE: | 975 case MIDI_COPYRIGHT_NOTICE: |
975 case MIDI_TRACK_NAME: | 976 case MIDI_TRACK_NAME: |
976 // The text events that we could potentially use | 977 // The text events that we could potentially use |
977 break; | 978 break; |
978 | 979 |
979 case MIDI_SET_TEMPO: | 980 case MIDI_SET_TEMPO: |
980 // Already dealt with in a separate pass previously | 981 // Already dealt with in a separate pass previously |
981 break; | 982 break; |
982 | 983 |
983 case MIDI_TIME_SIGNATURE: | 984 case MIDI_TIME_SIGNATURE: |
984 // Not yet! | 985 // Not yet! |
985 break; | 986 break; |
986 | 987 |
987 case MIDI_SEQUENCE_NUMBER: | 988 case MIDI_SEQUENCE_NUMBER: |
988 case MIDI_CHANNEL_PREFIX_OR_PORT: | 989 case MIDI_CHANNEL_PREFIX_OR_PORT: |
989 case MIDI_INSTRUMENT_NAME: | 990 case MIDI_INSTRUMENT_NAME: |
990 case MIDI_CUE_POINT: | 991 case MIDI_CUE_POINT: |
991 case MIDI_CHANNEL_PREFIX: | 992 case MIDI_CHANNEL_PREFIX: |
992 case MIDI_SEQUENCER_SPECIFIC: | 993 case MIDI_SEQUENCER_SPECIFIC: |
993 case MIDI_SMPTE_OFFSET: | 994 case MIDI_SMPTE_OFFSET: |
994 default: | 995 default: |
995 break; | 996 break; |
996 } | 997 } |
997 | 998 |
998 } else { | 999 } else { |
999 | 1000 |
1000 switch ((*i)->getMessageType()) { | 1001 switch ((*i)->getMessageType()) { |
1001 | 1002 |
1002 case MIDI_NOTE_ON: | 1003 case MIDI_NOTE_ON: |
1003 | 1004 |
1004 if ((*i)->getVelocity() == 0) break; // effective note-off | 1005 if ((*i)->getVelocity() == 0) break; // effective note-off |
1005 else { | 1006 else { |
1006 RealTime endRT; | 1007 RealTime endRT; |
1007 unsigned long endMidiTime = (*i)->getTime() + (*i)->getDuration(); | 1008 unsigned long endMidiTime = (*i)->getTime() + (*i)->getDuration(); |
1008 if (m_smpte) { | 1009 if (m_smpte) { |
1009 endRT = RealTime::frame2RealTime(endMidiTime, m_fps * m_subframes); | 1010 endRT = RealTime::frame2RealTime(endMidiTime, m_fps * m_subframes); |
1010 } else { | 1011 } else { |
1011 endRT = getTimeForMIDITime(endMidiTime); | 1012 endRT = getTimeForMIDITime(endMidiTime); |
1012 } | 1013 } |
1013 | 1014 |
1014 long startFrame = RealTime::realTime2Frame | 1015 long startFrame = RealTime::realTime2Frame |
1015 (rt, model->getSampleRate()); | 1016 (rt, model->getSampleRate()); |
1016 | 1017 |
1017 long endFrame = RealTime::realTime2Frame | 1018 long endFrame = RealTime::realTime2Frame |
1018 (endRT, model->getSampleRate()); | 1019 (endRT, model->getSampleRate()); |
1019 | 1020 |
1020 QString pitchLabel = Pitch::getPitchLabel((*i)->getPitch(), | 1021 QString pitchLabel = Pitch::getPitchLabel((*i)->getPitch(), |
1021 0, | 1022 0, |
1022 !sharpKey); | 1023 !sharpKey); |
1023 | 1024 |
1024 QString noteLabel = tr("%1 - vel %2") | 1025 QString noteLabel = tr("%1 - vel %2") |
1025 .arg(pitchLabel).arg(int((*i)->getVelocity())); | 1026 .arg(pitchLabel).arg(int((*i)->getVelocity())); |
1026 | 1027 |
1027 float level = float((*i)->getVelocity()) / 128.f; | 1028 float level = float((*i)->getVelocity()) / 128.f; |
1028 | 1029 |
1029 Note note(startFrame, (*i)->getPitch(), | 1030 Note note(startFrame, (*i)->getPitch(), |
1030 endFrame - startFrame, level, noteLabel); | 1031 endFrame - startFrame, level, noteLabel); |
1031 | 1032 |
1032 // SVDEBUG << "Adding note " << startFrame << "," << (endFrame-startFrame) << " : " << int((*i)->getPitch()) << endl; | 1033 // SVDEBUG << "Adding note " << startFrame << "," << (endFrame-startFrame) << " : " << int((*i)->getPitch()) << endl; |
1033 | 1034 |
1034 model->addPoint(note); | 1035 model->addPoint(note); |
1035 break; | 1036 break; |
1036 } | 1037 } |
1037 | 1038 |
1038 case MIDI_PITCH_BEND: | 1039 case MIDI_PITCH_BEND: |
1039 // I guess we could make some use of this... | 1040 // I guess we could make some use of this... |
1040 break; | 1041 break; |
1041 | 1042 |
1042 case MIDI_NOTE_OFF: | 1043 case MIDI_NOTE_OFF: |
1043 case MIDI_PROG_CHANGE: | 1044 case MIDI_PROG_CHANGE: |
1044 case MIDI_CTRL_CHANGE: | 1045 case MIDI_CTRL_CHANGE: |
1048 break; | 1049 break; |
1049 | 1050 |
1050 default: | 1051 default: |
1051 break; | 1052 break; |
1052 } | 1053 } |
1053 } | 1054 } |
1054 | 1055 |
1055 model->setCompletion(minProgress + | 1056 model->setCompletion(minProgress + |
1056 (count * progressAmount) / totalEvents); | 1057 (count * progressAmount) / totalEvents); |
1057 ++count; | 1058 ++count; |
1058 } | 1059 } |
1059 | 1060 |
1060 return model; | 1061 return model; |
1061 } | 1062 } |
1062 | 1063 |