changeset 398:333e27d1efa1

Fixes to resampler frequency tests
author Chris Cannam <c.cannam@qmul.ac.uk>
date Mon, 12 May 2014 17:56:08 +0100
parents fd207df9432e
children e48b3f641038
files dsp/rateconversion/Resampler.cpp tests/TestResampler.cpp
diffstat 2 files changed, 91 insertions(+), 58 deletions(-) [+]
line wrap: on
line diff
--- a/dsp/rateconversion/Resampler.cpp	Sat May 10 13:41:06 2014 +0100
+++ b/dsp/rateconversion/Resampler.cpp	Mon May 12 17:56:08 2014 +0100
@@ -26,9 +26,11 @@
 
 using std::vector;
 using std::map;
+using std::cerr;
+using std::endl;
 
 //#define DEBUG_RESAMPLER 1
-//#define DEBUG_RESAMPLER_VERBOSE
+//#define DEBUG_RESAMPLER_VERBOSE 1
 
 Resampler::Resampler(int sourceRate, int targetRate) :
     m_sourceRate(sourceRate),
@@ -106,10 +108,10 @@
     int outputSpacing = m_sourceRate / m_gcd;
 
 #ifdef DEBUG_RESAMPLER
-    std::cerr << "resample " << m_sourceRate << " -> " << m_targetRate
+    cerr << "resample " << m_sourceRate << " -> " << m_targetRate
 	      << ": inputSpacing " << inputSpacing << ", outputSpacing "
 	      << outputSpacing << ": filter length " << m_filterLength
-	      << std::endl;
+	      << endl;
 #endif
 
     // Now we have a filter of (odd) length flen in which the lower
@@ -205,6 +207,19 @@
 	m_phaseData[phase] = p;
     }
 
+#ifdef DEBUG_RESAMPLER
+    int cp = 0;
+    int totDrop = 0;
+    for (int i = 0; i < inputSpacing; ++i) {
+        cerr << "phase = " << cp << ", drop = " << m_phaseData[cp].drop
+             << ", filter length = " << m_phaseData[cp].filter.size()
+             << ", next phase = " << m_phaseData[cp].nextPhase << endl;
+        totDrop += m_phaseData[cp].drop;
+        cp = m_phaseData[cp].nextPhase;
+    }
+    cerr << "total drop = " << totDrop << endl;
+#endif
+
     // The May implementation of this uses a pull model -- we ask the
     // resampler for a certain number of output samples, and it asks
     // its source stream for as many as it needs to calculate
@@ -266,8 +281,8 @@
     m_bufferOrigin = 0;
 
 #ifdef DEBUG_RESAMPLER
-    std::cerr << "initial phase " << m_phase << " (as " << (m_filterLength/2) << " % " << inputSpacing << ")"
-	      << ", latency " << m_latency << std::endl;
+    cerr << "initial phase " << m_phase << " (as " << (m_filterLength/2) << " % " << inputSpacing << ")"
+	      << ", latency " << m_latency << endl;
 #endif
 }
 
@@ -283,12 +298,12 @@
     const double *const __restrict__ buf = m_buffer.data() + m_bufferOrigin;
     const double *const __restrict__ filt = pd.filter.data();
 
-//    std::cerr << "phase = " << m_phase << ", drop = " << pd.drop << ", buffer for reconstruction starts...";
+//    cerr << "phase = " << m_phase << ", drop = " << pd.drop << ", buffer for reconstruction starts...";
 //    for (int i = 0; i < 20; ++i) {
-//        if (i % 5 == 0) std::cerr << "\n" << i << " ";
-//        std::cerr << buf[i] << " ";
+//        if (i % 5 == 0) cerr << "\n" << i << " ";
+//        cerr << buf[i] << " ";
 //    }
-//    std::cerr << std::endl;
+//    cerr << endl;
 
     for (int i = 0; i < n; ++i) {
 	// NB gcc can only vectorize this with -ffast-math
@@ -311,7 +326,7 @@
     int outidx = 0;
 
 #ifdef DEBUG_RESAMPLER
-    std::cerr << "process: buf siz " << m_buffer.size() << " filt siz for phase " << m_phase << " " << m_phaseData[m_phase].filter.size() << std::endl;
+    cerr << "process: buf siz " << m_buffer.size() << " filt siz for phase " << m_phase << " " << m_phaseData[m_phase].filter.size() << endl;
 #endif
 
     double scaleFactor = (double(m_targetRate) / m_gcd) / m_peakToPole;
@@ -328,18 +343,18 @@
     return outidx;
 }
     
-std::vector<double>
+vector<double>
 Resampler::process(const double *src, int n)
 {
     int maxout = int(ceil(double(n) * m_targetRate / m_sourceRate));
-    std::vector<double> out(maxout, 0.0);
+    vector<double> out(maxout, 0.0);
     int got = process(src, out.data(), n);
     assert(got <= maxout);
     if (got < maxout) out.resize(got);
     return out;
 }
 
-std::vector<double>
+vector<double>
 Resampler::resample(int sourceRate, int targetRate, const double *data, int n)
 {
     Resampler r(sourceRate, targetRate);
@@ -364,24 +379,28 @@
 
     int m = int(ceil((double(n) * targetRate) / sourceRate));
     
-//    std::cerr << "n = " << n << ", sourceRate = " << sourceRate << ", targetRate = " << targetRate << ", m = " << m << ", latency = " << latency << ", inputPad = " << inputPad << ", m1 = " << m1 << ", n1 = " << n1 << ", n1 - n = " << n1 - n << std::endl;
+#ifdef DEBUG_RESAMPLER
+    cerr << "n = " << n << ", sourceRate = " << sourceRate << ", targetRate = " << targetRate << ", m = " << m << ", latency = " << latency << ", inputPad = " << inputPad << ", m1 = " << m1 << ", n1 = " << n1 << ", n1 - n = " << n1 - n << endl;
+#endif
 
     vector<double> pad(n1 - n, 0.0);
     vector<double> out(m1 + 1, 0.0);
 
-    int got = r.process(data, out.data(), n);
-    got += r.process(pad.data(), out.data() + got, pad.size());
-
+    int gotData = r.process(data, out.data(), n);
+    int gotPad = r.process(pad.data(), out.data() + gotData, pad.size());
+    int got = gotData + gotPad;
+    
 #ifdef DEBUG_RESAMPLER
-    std::cerr << "resample: " << n << " in, " << got << " out" << std::endl;
+    cerr << "resample: " << n << " in, " << pad.size() << " padding, " << got << " out (" << gotData << " data, " << gotPad << " padding, latency = " << latency << ")" << endl;
 #endif
 #ifdef DEBUG_RESAMPLER_VERBOSE
-    std::cerr << "first 10 in:" << std::endl;
-    for (int i = 0; i < 10; ++i) {
-        std::cerr << data[i] << " ";
-        if (i == 5) std::cerr << std::endl;
+    int printN = 50;
+    cerr << "first " << printN << " in:" << endl;
+    for (int i = 0; i < printN && i < n; ++i) {
+	if (i % 5 == 0) cerr << endl << i << "... ";
+        cerr << data[i] << " ";
     }
-    std::cerr << std::endl;
+    cerr << endl;
 #endif
 
     int toReturn = got - latency;
@@ -391,12 +410,12 @@
 			  out.begin() + latency + toReturn);
 
 #ifdef DEBUG_RESAMPLER_VERBOSE
-    std::cerr << "all out (after latency compensation), length " << sliced.size() << ":";
-    for (int i = 0; i < sliced.size(); ++i) {
-	if (i % 5 == 0) std::cerr << std::endl << i << "... ";
-	std::cerr << sliced[i] << " ";
+    cerr << "first " << printN << " out (after latency compensation), length " << sliced.size() << ":";
+    for (int i = 0; i < printN && i < sliced.size(); ++i) {
+	if (i % 5 == 0) cerr << endl << i << "... ";
+	cerr << sliced[i] << " ";
     }
-    std::cerr << std::endl;
+    cerr << endl;
 #endif
 
     return sliced;
--- a/tests/TestResampler.cpp	Sat May 10 13:41:06 2014 +0100
+++ b/tests/TestResampler.cpp	Mon May 12 17:56:08 2014 +0100
@@ -154,22 +154,26 @@
 measureSinFreq(const vector<double> &v, int rate, int countCycles)
 {
     int n = v.size();
-    int firstCrossing = -1;
-    int lastCrossing = -1;
-    int nCrossings = 0;
-    // count -ve -> +ve transitions
-    for (int i = 0; i + 1 < n; ++i) {
-        if (v[i] <= 0.0 && v[i+1] > 0.0) {
-            if (firstCrossing < 0) firstCrossing = i;
-            lastCrossing = i;
-            ++nCrossings;
-            if (nCrossings == countCycles) break;
+    int firstPeak = -1;
+    int lastPeak = -1;
+    int nPeaks = 0;
+    // count +ve peaks
+    for (int i = v.size()/4; i + 1 < n; ++i) {
+        // allow some fuzz
+        int x0 = int(10000 * v[i-1]);
+        int x1 = int(10000 * v[i]);
+        int x2 = int(10000 * v[i+1]);
+        if (x1 > 0 && x1 > x0 && x1 >= x2) {
+            if (firstPeak < 0) firstPeak = i;
+            lastPeak = i;
+            ++nPeaks;
+            if (nPeaks == countCycles) break;
         }
     }
-    int nCycles = nCrossings - 1;
+    int nCycles = nPeaks - 1;
     if (nCycles <= 0) return 0.0;
-    cout << "lastCrossing = " << lastCrossing << ", firstCrossing = " << firstCrossing << ", dist = " << lastCrossing - firstCrossing << ", nCycles = " << nCycles << endl;
-    double cycle = double(lastCrossing - firstCrossing) / nCycles;
+    double cycle = double(lastPeak - firstPeak) / nCycles;
+//    cout << "lastPeak = " << lastPeak << ", firstPeak = " << firstPeak << ", dist = " << lastPeak - firstPeak << ", nCycles = " << nCycles << ", cycle = " << cycle << endl;
     return rate / cycle;
 }
 
@@ -182,10 +186,10 @@
     // sinusoid of the same frequency as we started with. Let's start
     // with a few thousand cycles of it
 
-    int nCycles = 5000;
+    int nCycles = 500;
 
     int duration = int(nCycles * float(sourceRate) / float(freq));
-    cout << "freq = " << freq << ", sourceRate = " << sourceRate << ", targetRate = " << targetRate << ", duration = " << duration << endl;
+//    cout << "freq = " << freq << ", sourceRate = " << sourceRate << ", targetRate = " << targetRate << ", duration = " << duration << endl;
 
     vector<double> in(duration, 0);
     for (int i = 0; i < duration; ++i) {
@@ -200,36 +204,46 @@
 
     BOOST_CHECK_EQUAL(in.size(), back.size());
 
-    double inFreq = measureSinFreq(in, sourceRate, nCycles - 2);
-    double backFreq = measureSinFreq(back, sourceRate, nCycles - 2);
+    double inFreq = measureSinFreq(in, sourceRate, nCycles / 2);
+    double backFreq = measureSinFreq(back, sourceRate, nCycles / 2);
     
-    cout << "inFreq = " << inFreq << ", backFreq = " << backFreq << endl;
+    BOOST_CHECK_SMALL(inFreq - backFreq, 1e-8);
+}
 
-    BOOST_CHECK_SMALL(inFreq - backFreq, 1e-8);
-
-    //    for (int i = 0; i < int(in.size()); ++i) {
-//	BOOST_CHECK_SMALL(in[i] - back[i], 1e-6);
-//    }
-}
+// In each of the following we use a frequency that has an exact cycle
+// length in samples at the lowest sample rate, so that we can easily
+// rule out errors in measuring the cycle length after resampling. If
+// the resampler gets its input or output rate wrong, that will show
+// up no matter what the test signal's initial frequency is.
 
 BOOST_AUTO_TEST_CASE(downUp2)
 {
-    testSinFrequency(440, 44100, 22050);
+    testSinFrequency(441, 44100, 22050);
+}
+
+BOOST_AUTO_TEST_CASE(downUp5)
+{
+    testSinFrequency(300, 15000, 3000);
 }
 
 BOOST_AUTO_TEST_CASE(downUp16)
 {
-    testSinFrequency(440, 48000, 3000);
+    testSinFrequency(300, 48000, 3000);
 }
 
 BOOST_AUTO_TEST_CASE(upDown2)
 {
-    testSinFrequency(440, 44100, 88200);
+    testSinFrequency(441, 44100, 88200);
+}
+
+BOOST_AUTO_TEST_CASE(upDown5)
+{
+    testSinFrequency(300, 3000, 15000);
 }
 
 BOOST_AUTO_TEST_CASE(upDown16)
 {
-    testSinFrequency(440, 3000, 48000);
+    testSinFrequency(300, 3000, 48000);
 }
 
 vector<double>
@@ -287,7 +301,7 @@
 	BOOST_CHECK_SMALL(inSpectrum[i] - outSpectrum[i], 1e-7);
     }
 }
-
+/*
 BOOST_AUTO_TEST_CASE(spectrum)
 {
     int rates[] = { 8000, 22050, 44100, 48000 };
@@ -297,6 +311,6 @@
 	}
     }
 }
-
+*/
 BOOST_AUTO_TEST_SUITE_END()