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