comparison data/fileio/MIDIFileReader.cpp @ 613:eb1b517f5eeb sv-v1.7

* Support SMPTE timecode in MIDI files (fixes #2739160)
author Chris Cannam
date Tue, 29 Sep 2009 10:34:57 +0000
parents 2e50d95cf621
children 06f13a3b9e9e
comparison
equal deleted inserted replaced
612:75f154085a4d 613:eb1b517f5eeb
56 56
57 57
58 MIDIFileReader::MIDIFileReader(QString path, 58 MIDIFileReader::MIDIFileReader(QString path,
59 MIDIFileImportPreferenceAcquirer *acquirer, 59 MIDIFileImportPreferenceAcquirer *acquirer,
60 size_t mainModelSampleRate) : 60 size_t mainModelSampleRate) :
61 m_smpte(false),
61 m_timingDivision(0), 62 m_timingDivision(0),
63 m_fps(0),
64 m_subframes(0),
62 m_format(MIDI_FILE_BAD_FORMAT), 65 m_format(MIDI_FILE_BAD_FORMAT),
63 m_numberOfTracks(0), 66 m_numberOfTracks(0),
64 m_trackByteCount(0), 67 m_trackByteCount(0),
65 m_decrementCount(false), 68 m_decrementCount(false),
66 m_path(path), 69 m_path(path),
414 417
415 m_format = (MIDIFileFormatType) midiBytesToInt(midiHeader.substr(8,2)); 418 m_format = (MIDIFileFormatType) midiBytesToInt(midiHeader.substr(8,2));
416 m_numberOfTracks = midiBytesToInt(midiHeader.substr(10,2)); 419 m_numberOfTracks = midiBytesToInt(midiHeader.substr(10,2));
417 m_timingDivision = midiBytesToInt(midiHeader.substr(12,2)); 420 m_timingDivision = midiBytesToInt(midiHeader.substr(12,2));
418 421
419 if (m_format == MIDI_SEQUENTIAL_TRACK_FILE) { 422 if (m_timingDivision >= 32768) {
420 #ifdef MIDI_DEBUG 423 m_smpte = true;
421 cerr << "MIDIFileReader::parseHeader()" 424 m_fps = 256 - (m_timingDivision >> 8);
422 << "- can't load sequential track file" 425 m_subframes = (m_timingDivision & 0xff);
423 << endl; 426 } else {
424 #endif 427 m_smpte = false;
425 return false; 428 }
426 }
427
428 #ifdef MIDI_DEBUG
429 if (m_timingDivision < 0) {
430 cerr << "MIDIFileReader::parseHeader()"
431 << " - file uses SMPTE timing"
432 << endl;
433 }
434 #endif
435 429
436 return true; 430 return true;
437 } 431 }
438 432
439 // Extract the contents from a MIDI file track and places it into 433 // Extract the contents from a MIDI file track and places it into
704 // Event duration to length of track 698 // Event duration to length of track
705 // 699 //
706 if (!noteOffFound) { 700 if (!noteOffFound) {
707 MIDITrack::iterator j = m_midiComposition[track].end(); 701 MIDITrack::iterator j = m_midiComposition[track].end();
708 --j; 702 --j;
709 (*i)->setDuration((*j)->getTime() - (*i)->getTime()); 703 (*i)->setDuration((*j)->getTime() - (*i)->getTime());
710 } 704 }
711 } 705 }
712 } 706 }
713 707
714 return notesOnTrack; 708 return notesOnTrack;
955 bool minorKey = false; 949 bool minorKey = false;
956 bool sharpKey = true; 950 bool sharpKey = true;
957 951
958 for (MIDITrack::const_iterator i = track.begin(); i != track.end(); ++i) { 952 for (MIDITrack::const_iterator i = track.begin(); i != track.end(); ++i) {
959 953
960 RealTime rt = getTimeForMIDITime((*i)->getTime()); 954 RealTime rt;
955 unsigned long midiTime = (*i)->getTime();
956
957 if (m_smpte) {
958 rt = RealTime::frame2RealTime(midiTime, m_fps * m_subframes);
959 } else {
960 rt = getTimeForMIDITime(midiTime);
961 }
961 962
962 // We ignore most of these event types for now, though in 963 // We ignore most of these event types for now, though in
963 // theory some of the text ones could usefully be incorporated 964 // theory some of the text ones could usefully be incorporated
964 965
965 if ((*i)->isMeta()) { 966 if ((*i)->isMeta()) {
1004 1005
1005 case MIDI_NOTE_ON: 1006 case MIDI_NOTE_ON:
1006 1007
1007 if ((*i)->getVelocity() == 0) break; // effective note-off 1008 if ((*i)->getVelocity() == 0) break; // effective note-off
1008 else { 1009 else {
1009 RealTime endRT = getTimeForMIDITime((*i)->getTime() + 1010 RealTime endRT;
1010 (*i)->getDuration()); 1011 unsigned long endMidiTime = (*i)->getTime() + (*i)->getDuration();
1012 if (m_smpte) {
1013 endRT = RealTime::frame2RealTime(endMidiTime, m_fps * m_subframes);
1014 } else {
1015 endRT = getTimeForMIDITime(endMidiTime);
1016 }
1011 1017
1012 long startFrame = RealTime::realTime2Frame 1018 long startFrame = RealTime::realTime2Frame
1013 (rt, model->getSampleRate()); 1019 (rt, model->getSampleRate());
1014 1020
1015 long endFrame = RealTime::realTime2Frame 1021 long endFrame = RealTime::realTime2Frame