changeset 327:df9a8e16bae6 livemode-octave-higher

Experiment with dropping the bottom octave off each template (since most of the information is in higher harmonics anyway!) -- this is about 15% faster again and has half the latency, but per
author Chris Cannam
date Tue, 19 May 2015 09:29:00 +0100
parents caaac814c22a
children 8545b883775e
files src/Instruments.h src/LiveInstruments.cpp src/Silvet.cpp
diffstat 3 files changed, 44 insertions(+), 22 deletions(-) [+]
line wrap: on
line diff
--- a/src/Instruments.h	Mon May 18 16:33:36 2015 +0100
+++ b/src/Instruments.h	Tue May 19 09:29:00 2015 +0100
@@ -35,7 +35,7 @@
     int templateNoteCount;
     int templateHeight;
     int templateMaxShift;
-    int templateSize;
+    int templateSize; // height plus space for shift at either end
 
     int lowestNote;
     int highestNote;
--- a/src/LiveInstruments.cpp	Mon May 18 16:33:36 2015 +0100
+++ b/src/LiveInstruments.cpp	Tue May 19 09:29:00 2015 +0100
@@ -37,25 +37,29 @@
 
     InstrumentPack::Templates t;
     bool first = true;
+
+    // The live instrument template is one octave shorter than the
+    // original, as well as having only 12 bpo instead of 60
+    int height = SILVET_TEMPLATE_HEIGHT/5 - 12;
     
     for (const auto &origt: original.templates) {
 
-	t.lowestNote = origt.lowestNote;
+	t.lowestNote = origt.lowestNote + 12;
 	t.highestNote = origt.highestNote;
         t.data.resize(origt.data.size());
 
 	for (int j = 0; j < int(origt.data.size()); ++j) {
 
-	    t.data[j].resize(SILVET_TEMPLATE_HEIGHT/5);
+	    t.data[j].resize(height);
 
-	    for (int k = 0; k < SILVET_TEMPLATE_HEIGHT/5; ++k) {
+	    for (int k = 0; k < height; ++k) {
 
                 if (!merge || first) {
                     t.data[j][k] = 0.f;
                 }
 
-                for (int m = 0; m < 5; ++m) {
-                    t.data[j][k] += origt.data[j][k * 5 + m + 2];
+                for (int m = 2; m < 3; ++m) {
+                    t.data[j][k] += origt.data[j][60 + k * 5 + m + 2];
                 }
 	    }
 	}
@@ -73,6 +77,7 @@
     }
 
     // re-normalise
+
     for (auto &t: templates) {
         for (auto &d: t.data) {
             float sum = 0.f;
@@ -80,20 +85,20 @@
             for (auto &v: d) v /= sum;
         }
     }
-    
+
     InstrumentPack live(original.lowestNote,
 			original.highestNote,
 			original.name,
 			templates);
 
-    live.templateHeight = SILVET_TEMPLATE_HEIGHT/5;
+    live.templateHeight = height;
     live.templateMaxShift = 0;
-    live.templateSize = live.templateHeight;
+    live.templateSize = height;
     
     live.maxPolyphony = original.maxPolyphony;
     live.pitchSparsity = original.pitchSparsity;
     live.sourceSparsity = original.sourceSparsity;
-    live.levelThreshold = original.levelThreshold / 15;
+    live.levelThreshold = original.levelThreshold / 20;
 
     return live;
 }
--- a/src/Silvet.cpp	Mon May 18 16:33:36 2015 +0100
+++ b/src/Silvet.cpp	Tue May 19 09:29:00 2015 +0100
@@ -500,8 +500,14 @@
 
     if (m_mode != HighQualityMode) {
         // We don't actually return any notes from the bottom octave,
-        // so we can just pad with zeros
-        minFreq *= 2;
+        // so we can just pad with zeros. In live mode the template is
+        // an octave shorter as well. Each octave the min frequency is
+        // raised by halves the processing latency.
+        if (m_mode == LiveMode) {
+            minFreq *= 4;
+        } else {
+            minFreq *= 2;
+        }
     }
 
     int bpo = 12 *
@@ -774,7 +780,7 @@
     double columnThreshold = 1e-5;
     
     if (m_mode == LiveMode) {
-        columnThreshold /= 15;
+        columnThreshold /= 20;
     }
     
     vector<double> pitches(pack.templateNoteCount, 0.0);
@@ -865,12 +871,22 @@
             vector<double> inCol = in[i];
             vector<double> outCol(pack.templateHeight);
 
-            // In HQ mode, the CQ returns 600 bins and we ignore the
-            // lowest 55 of them (assuming binsPerSemitone == 5).
-            // 
-            // In draft and live mode the CQ is an octave shorter,
-            // returning 540 bins or equivalent, so we instead pad
-            // them with an additional 5 or equivalent zeros.
+            // In HQ mode, the CQ returns 600 bins (10 octaves at 5
+            // bins per semitone) and we ignore the lowest 55 of them,
+            // giving us 545 bins total, which matches the height of
+            // each of our instrument templates.
+            //
+            // In draft mode the CQ is an octave shorter, returning
+            // 540 bins, so we instead pad with an additional 5 zeros
+            // at the lowest frequencies to get the same 545 bins.
+            //
+            // In live mode the CQ is two octaves shorter and only has
+            // 1 bin per semitone, and the template is also an octave
+            // shorter. So we get 96 bins (= 8 * 12) and want 97 (=
+            // (545 / 5) - 12), meaning we have to pad with one extra
+            // bin at the lowest frequency position. Essentially this
+            // is the same as draft mode (pad with bins-per-semitone
+            // bins), just that the result is a shorter vector.
             // 
             // We also need to reverse the column as we go, since the
             // raw CQ has the high frequencies first and we need it
@@ -885,11 +901,12 @@
                     outCol[j] = inCol[ix];
                 }
             } else {
-                for (int j = 0; j < bps; ++j) {
+                int pad = bps;
+                for (int j = 0; j < pad; ++j) {
                     outCol[j] = 0.0;
                 }
-                for (int j = bps; j < pack.templateHeight; ++j) {
-                    int ix = inCol.size() - j + (bps-1);
+                for (int j = pad; j < pack.templateHeight; ++j) {
+                    int ix = inCol.size() - j + (pad-1);
                     outCol[j] = inCol[ix];
                 }
             }