changeset 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 75f154085a4d
children 87b81f959706
files data/fileio/MIDIFileReader.cpp data/fileio/MIDIFileReader.h
diffstat 2 files changed, 28 insertions(+), 19 deletions(-) [+]
line wrap: on
line diff
--- a/data/fileio/MIDIFileReader.cpp	Fri Sep 25 12:02:22 2009 +0000
+++ b/data/fileio/MIDIFileReader.cpp	Tue Sep 29 10:34:57 2009 +0000
@@ -58,7 +58,10 @@
 MIDIFileReader::MIDIFileReader(QString path,
                                MIDIFileImportPreferenceAcquirer *acquirer,
 			       size_t mainModelSampleRate) :
+    m_smpte(false),
     m_timingDivision(0),
+    m_fps(0),
+    m_subframes(0),
     m_format(MIDI_FILE_BAD_FORMAT),
     m_numberOfTracks(0),
     m_trackByteCount(0),
@@ -416,23 +419,14 @@
     m_numberOfTracks = midiBytesToInt(midiHeader.substr(10,2));
     m_timingDivision = midiBytesToInt(midiHeader.substr(12,2));
 
-    if (m_format == MIDI_SEQUENTIAL_TRACK_FILE) {
-#ifdef MIDI_DEBUG
-        cerr << "MIDIFileReader::parseHeader()"
-                  << "- can't load sequential track file"
-                  << endl;
-#endif
-        return false;
+    if (m_timingDivision >= 32768) {
+        m_smpte = true;
+        m_fps = 256 - (m_timingDivision >> 8);
+        m_subframes = (m_timingDivision & 0xff);
+    } else {
+        m_smpte = false;
     }
 
-#ifdef MIDI_DEBUG
-    if (m_timingDivision < 0) {
-        cerr << "MIDIFileReader::parseHeader()"
-                  << " - file uses SMPTE timing"
-                  << endl;
-    }
-#endif
-
     return true; 
 }
 
@@ -706,7 +700,7 @@
             if (!noteOffFound) {
 		MIDITrack::iterator j = m_midiComposition[track].end();
 		--j;
-                (*i)->setDuration((*j)->getTime()  - (*i)->getTime());
+                (*i)->setDuration((*j)->getTime() - (*i)->getTime());
 	    }
         }
     }
@@ -957,7 +951,14 @@
 
     for (MIDITrack::const_iterator i = track.begin(); i != track.end(); ++i) {
 
-	RealTime rt = getTimeForMIDITime((*i)->getTime());
+        RealTime rt;
+        unsigned long midiTime = (*i)->getTime();
+
+        if (m_smpte) {
+            rt = RealTime::frame2RealTime(midiTime, m_fps * m_subframes);
+        } else {
+            rt = getTimeForMIDITime(midiTime);
+        }
 
 	// We ignore most of these event types for now, though in
 	// theory some of the text ones could usefully be incorporated
@@ -1006,8 +1007,13 @@
 
                 if ((*i)->getVelocity() == 0) break; // effective note-off
 		else {
-		    RealTime endRT = getTimeForMIDITime((*i)->getTime() +
-							(*i)->getDuration());
+		    RealTime endRT;
+                    unsigned long endMidiTime = (*i)->getTime() + (*i)->getDuration();
+                    if (m_smpte) {
+                        endRT = RealTime::frame2RealTime(endMidiTime, m_fps * m_subframes);
+                    } else {
+                        endRT = getTimeForMIDITime(endMidiTime);
+                    }
 
 		    long startFrame = RealTime::realTime2Frame
 			(rt, model->getSampleRate());
--- a/data/fileio/MIDIFileReader.h	Fri Sep 25 12:02:22 2009 +0000
+++ b/data/fileio/MIDIFileReader.h	Tue Sep 29 10:34:57 2009 +0000
@@ -108,7 +108,10 @@
 
     bool skipToNextTrack();
 
+    bool                   m_smpte;
     int                    m_timingDivision;   // pulses per quarter note
+    int                    m_fps;              // if smpte
+    int                    m_subframes;        // if smpte
     MIDIFileFormatType     m_format;
     unsigned int           m_numberOfTracks;