changeset 596:c99892f0c5c3

Proper handling for notes that end at the same frame as a subsequent note of the same pitch begins. The note-off needs to be associated with the prior note, not a spurious zero-duration version of the subsequent note.
author Chris Cannam
date Wed, 18 Apr 2018 15:19:09 +0100
parents b23bebfdfaba
children f03bc1d38cac
files audio/AudioGenerator.cpp audio/ClipMixer.cpp
diffstat 2 files changed, 28 insertions(+), 5 deletions(-) [+]
line wrap: on
line diff
--- a/audio/AudioGenerator.cpp	Thu Mar 01 18:02:22 2018 +0000
+++ b/audio/AudioGenerator.cpp	Wed Apr 18 15:19:09 2018 +0100
@@ -65,7 +65,7 @@
 AudioGenerator::~AudioGenerator()
 {
 #ifdef DEBUG_AUDIO_GENERATOR
-    SVDEBUG << "AudioGenerator::~AudioGenerator" << endl;
+    cerr << "AudioGenerator::~AudioGenerator" << endl;
 #endif
 
     for (int i = 0; i < m_channelBufCount; ++i) {
@@ -570,9 +570,27 @@
              ni != notes.end(); ++ni) {
 
             sv_frame_t noteFrame = ni->start;
+            sv_frame_t noteDuration = ni->duration;
 
             if (noteFrame < reqStart ||
-                noteFrame >= reqStart + m_processingBlockSize) continue;
+                noteFrame >= reqStart + m_processingBlockSize) {
+                continue;
+            }
+
+            if (noteDuration == 0) {
+                // If we have a note-off and a note-on with the same
+                // time, then the note-off will be assumed (in the
+                // logic below that deals with two-point note-on/off
+                // events) to be switching off an earlier note before
+                // this one begins -- that's necessary in order to
+                // support adjoining notes of equal pitch. But it does
+                // mean we have to explicitly ignore zero-duration
+                // notes, otherwise they'll be played without end
+#ifdef DEBUG_AUDIO_GENERATOR
+                cerr << "mixModel [clip]: zero-duration note found at frame " << noteFrame << ", skipping it" << endl;
+#endif
+                continue;
+            }
 
             while (noteOffs.begin() != noteOffs.end() &&
                    noteOffs.begin()->frame <= noteFrame) {
@@ -602,7 +620,7 @@
             
             starts.push_back(on);
             noteOffs.insert
-                (NoteOff(on.frequency, noteFrame + ni->duration));
+                (NoteOff(on.frequency, noteFrame + noteDuration));
         }
 
         while (noteOffs.begin() != noteOffs.end() &&
--- a/audio/ClipMixer.cpp	Thu Mar 01 18:02:22 2018 +0000
+++ b/audio/ClipMixer.cpp	Wed Apr 18 15:19:09 2018 +0100
@@ -159,8 +159,13 @@
         bool ending = false;
 
         foreach (NoteEnd end, endingNotes) {
-            if (end.frequency == note.frequency && 
-                end.frameOffset >= start &&
+            if (end.frequency == note.frequency &&
+                // This is > rather than >= because if we have a
+                // note-off and a note-on at the same time, the
+                // note-off must be switching off an earlier note-on,
+                // not the current one (zero-duration notes are
+                // forbidden earlier in the pipeline)
+                end.frameOffset > start &&
                 end.frameOffset <= m_blockSize) {
                 ending = true;
                 durationHere = end.frameOffset;