changeset 615:755fc02a1565

Associate a note-on time with each pending note-off as well, so we can check whether a rewind action (or looping) has caused us to jump to before the note began. Also improve implementation of note-off structure comparator
author Chris Cannam
date Mon, 13 Aug 2018 14:13:38 +0100
parents 0aee6ff48018
children 7d3a6357ce64 e98a42e94d90
files audio/AudioGenerator.cpp audio/AudioGenerator.h
diffstat 2 files changed, 42 insertions(+), 9 deletions(-) [+]
line wrap: on
line diff
--- a/audio/AudioGenerator.cpp	Mon Aug 13 11:44:33 2018 +0100
+++ b/audio/AudioGenerator.cpp	Mon Aug 13 14:13:38 2018 +0100
@@ -568,6 +568,24 @@
         std::vector<ClipMixer::NoteStart> starts;
         std::vector<ClipMixer::NoteEnd> ends;
 
+        while (noteOffs.begin() != noteOffs.end() &&
+               noteOffs.begin()->onFrame > reqStart) {
+
+            // We must have jumped back in time, as there is a
+            // note-off pending for a note that hasn't begun yet. Emit
+            // the note-off now and discard
+
+            off.frameOffset = 0;
+            off.frequency = noteOffs.begin()->frequency;
+
+#ifdef DEBUG_AUDIO_GENERATOR
+            cerr << "mixModel [clip]: adding rewind-caused note-off at frame offset 0 frequency " << off.frequency << endl;
+#endif
+
+            ends.push_back(off);
+            noteOffs.erase(noteOffs.begin());
+        }
+        
         for (NoteList::const_iterator ni = notes.begin();
              ni != notes.end(); ++ni) {
 
@@ -595,9 +613,9 @@
             }
 
             while (noteOffs.begin() != noteOffs.end() &&
-                   noteOffs.begin()->frame <= noteFrame) {
+                   noteOffs.begin()->offFrame <= noteFrame) {
 
-                sv_frame_t eventFrame = noteOffs.begin()->frame;
+                sv_frame_t eventFrame = noteOffs.begin()->offFrame;
                 if (eventFrame < reqStart) eventFrame = reqStart;
 
                 off.frameOffset = eventFrame - reqStart;
@@ -622,13 +640,14 @@
             
             starts.push_back(on);
             noteOffs.insert
-                (NoteOff(on.frequency, noteFrame + noteDuration));
+                (NoteOff(on.frequency, noteFrame + noteDuration, noteFrame));
         }
 
         while (noteOffs.begin() != noteOffs.end() &&
-               noteOffs.begin()->frame <= reqStart + m_processingBlockSize) {
+               noteOffs.begin()->offFrame <=
+               reqStart + m_processingBlockSize) {
 
-            sv_frame_t eventFrame = noteOffs.begin()->frame;
+            sv_frame_t eventFrame = noteOffs.begin()->offFrame;
             if (eventFrame < reqStart) eventFrame = reqStart;
 
             off.frameOffset = eventFrame - reqStart;
--- a/audio/AudioGenerator.h	Mon Aug 13 11:44:33 2018 +0100
+++ b/audio/AudioGenerator.h	Mon Aug 13 14:13:38 2018 +0100
@@ -112,15 +112,29 @@
 
     struct NoteOff {
 
-        NoteOff(float _freq, sv_frame_t _frame) :
-            frequency(_freq), frame(_frame) { }
+        NoteOff(float _freq, sv_frame_t _offFrame, sv_frame_t _onFrame) :
+            frequency(_freq), offFrame(_offFrame), onFrame(_onFrame) { }
 
         float frequency;
-        sv_frame_t frame;
+        sv_frame_t offFrame;
+
+        // This is the frame at which the note whose note-off appears
+        // here began. It is used to determine when we should silence
+        // a note because the playhead has jumped back in time - if
+        // the current frame for rendering is earlier than this one,
+        // then we should end and discard the note
+        //
+        sv_frame_t onFrame;
 
         struct Comparator {
             bool operator()(const NoteOff &n1, const NoteOff &n2) const {
-                return n1.frame < n2.frame;
+                if (n1.offFrame != n2.offFrame) {
+                    return n1.offFrame < n2.offFrame;
+                } else if (n1.onFrame != n2.onFrame) {
+                    return n1.onFrame < n2.onFrame;
+                } else {
+                    return n1.frequency < n2.frequency;
+                }
             }
         };
     };