changeset 27:cb86b8b7ed90

Add output bin names; begin handling tuning frequency
author Chris Cannam
date Wed, 30 Sep 2015 10:26:24 +0100
parents 3d1c5cabadcc
children 7b618e3f9a8b
files src/PitchFilterbank.cpp src/PitchFilterbank.h src/TipicVampPlugin.cpp
diffstat 3 files changed, 56 insertions(+), 26 deletions(-) [+]
line wrap: on
line diff
--- a/src/PitchFilterbank.cpp	Tue Sep 29 17:14:05 2015 +0100
+++ b/src/PitchFilterbank.cpp	Wed Sep 30 10:26:24 2015 +0100
@@ -13,6 +13,8 @@
 #include <stdexcept>
 #include <iostream>
 
+#include <cmath>
+
 using namespace std;
 
 static const int HIGHEST_FILTER_INDEX_AT_882 = 38;   // MIDI pitch 59
@@ -23,11 +25,23 @@
 class PitchFilterbank::D
 {
 public:
-    D(int sampleRate, float tuningFrequency) :
+    D(int sampleRate, double tuningFrequency) :
 	m_nfilters(HIGHEST_FILTER_INDEX + 1),
 	m_sampleRate(sampleRate),
 	m_tuningFrequency(tuningFrequency)
     {
+	// To handle a non-440 tuning frequency, we resample the input
+	// by this tuning ratio and then adjust the output block
+	// timings accordingly. Ratio is calculated on the basis that
+	// for tuning freq >440 we want to lower the pitch of the
+	// input audio by slowing it down, therefore we want to
+	// pretend that it came in at a lower sample rate than it
+	// really did, and for >440 the opposite applies. The
+	// effective input sample rate is the rate at which we pretend
+	// the audio was supplied.
+	m_tuningRatio = 440.0 / m_tuningFrequency;
+	m_effectiveInputSampleRate = int(round(m_sampleRate * m_tuningRatio));
+
 	//!!! todo: tuning frequency adjustment
 	// * resample input by a small amount
 	// * adjust output block timings by a small amount
@@ -39,9 +53,9 @@
 	// here & so need to adapt magnitudes in compensation to match
 	// original
 	
-	m_resamplers[882] = new Resampler(sampleRate, 882);
-	m_resamplers[4410] = new Resampler(sampleRate, 4410);
-	m_resamplers[22050] = new Resampler(sampleRate, 22050);
+	m_resamplers[882] = new Resampler(m_effectiveInputSampleRate, 882);
+	m_resamplers[4410] = new Resampler(m_effectiveInputSampleRate, 4410);
+	m_resamplers[22050] = new Resampler(m_effectiveInputSampleRate, 22050);
 	
 	for (int i = 0; i < m_nfilters; ++i) {
 	    int ix = i + 20;
@@ -62,7 +76,7 @@
     }
 
     int getSampleRate() const { return m_sampleRate; }
-    float getTuningFrequency() const { return m_tuningFrequency; }
+    double getTuningFrequency() const { return m_tuningFrequency; }
 
     RealBlock process(const RealSequence &in) {
 
@@ -206,7 +220,9 @@
 private:
     int m_nfilters;
     int m_sampleRate;
-    float m_tuningFrequency;
+    int m_effectiveInputSampleRate;
+    double m_tuningFrequency;
+    double m_tuningRatio;
 
     // This vector is initialised with 88 filter instances.
     // m_filters[n] (for n from 0 to 87) is for MIDI pitch 21+n, so we
@@ -249,7 +265,7 @@
     }
 };
 
-PitchFilterbank::PitchFilterbank(int sampleRate, float tuningFrequency) :
+PitchFilterbank::PitchFilterbank(int sampleRate, double tuningFrequency) :
     m_d(new D(sampleRate, tuningFrequency))
 {
 }
@@ -263,7 +279,7 @@
 PitchFilterbank::reset()
 {
     int rate = m_d->getSampleRate();
-    float freq = m_d->getTuningFrequency();
+    double freq = m_d->getTuningFrequency();
     delete m_d;
     m_d = new D(rate, freq);
 }
@@ -280,3 +296,11 @@
     return m_d->getRemainingOutput();
 }
 
+void
+PitchFilterbank::getPitchRange(int &minMidiPitch, int &maxMidiPitch)
+{
+    minMidiPitch = 21;
+    maxMidiPitch = 108;
+}
+
+
--- a/src/PitchFilterbank.h	Tue Sep 29 17:14:05 2015 +0100
+++ b/src/PitchFilterbank.h	Wed Sep 30 10:26:24 2015 +0100
@@ -8,7 +8,7 @@
 class PitchFilterbank
 {
 public:
-    PitchFilterbank(int sampleRate, float tuningFrequency);
+    PitchFilterbank(int sampleRate, double tuningFrequency);
     ~PitchFilterbank();
 
     void reset();
@@ -17,6 +17,8 @@
 
     RealBlock getRemainingOutput();
 
+    static void getPitchRange(int &minMidiPitch, int &maxMidiPitch);
+    
 private:
     class D;
     D *m_d;
--- a/src/TipicVampPlugin.cpp	Tue Sep 29 17:14:05 2015 +0100
+++ b/src/TipicVampPlugin.cpp	Wed Sep 30 10:26:24 2015 +0100
@@ -9,6 +9,7 @@
 #include <bqvec/VectorOps.h>
 
 #include <iostream>
+#include <sstream>
 
 using namespace std;
 
@@ -170,6 +171,18 @@
 {
 }
 
+static vector<string> noteNames
+    { "C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B" };
+
+static std::string noteName(int i)
+{
+    string name = noteNames[i % 12];
+    int oct = i / 12 - 1;
+    ostringstream sstr;
+    sstr << i << " " << name << oct << ends;
+    return sstr.str();
+}
+
 Tipic::OutputList
 Tipic::getOutputDescriptors() const
 {
@@ -181,7 +194,13 @@
     d.description = "";
     d.unit = "";
     d.hasFixedBinCount = true;
-    d.binCount = 88;
+    int min = 0, max = 0;
+    PitchFilterbank::getPitchRange(min, max);
+    d.binCount = max - min + 1;
+    d.binNames.clear();
+    for (int p = min; p <= max; ++p) {
+	d.binNames.push_back(noteName(p));
+    }
     d.hasKnownExtents = false;
     d.isQuantized = false;
     d.sampleType = OutputDescriptor::FixedSampleRate;
@@ -196,6 +215,7 @@
     d.unit = "";
     d.hasFixedBinCount = true;
     d.binCount = 12;
+    d.binNames = noteNames;
     d.hasKnownExtents = false;
     d.isQuantized = false;
     d.sampleType = OutputDescriptor::FixedSampleRate;
@@ -207,28 +227,12 @@
     d.identifier = "clp";
     d.name = "Chroma Log Pitch Features";
     d.description = "";
-    d.unit = "";
-    d.hasFixedBinCount = true;
-    d.binCount = 12;
-    d.hasKnownExtents = false;
-    d.isQuantized = false;
-    d.sampleType = OutputDescriptor::FixedSampleRate;
-    d.sampleRate = 22050 / 2205; //!!! get block size & hop from filterbank
-    d.hasDuration = false;
     m_clpOutputNo = list.size();
     list.push_back(d);
 
     d.identifier = "crp";
     d.name = "Chroma DCT-Reduced Log Pitch Features";
     d.description = "";
-    d.unit = "";
-    d.hasFixedBinCount = true;
-    d.binCount = 12;
-    d.hasKnownExtents = false;
-    d.isQuantized = false;
-    d.sampleType = OutputDescriptor::FixedSampleRate;
-    d.sampleRate = 22050 / 2205; //!!! get block size & hop from filterbank
-    d.hasDuration = false;
     m_crpOutputNo = list.size();
     list.push_back(d);