changeset 563:8c1b62eb33c7

Some failing resampler tests, matching those currently in qm-dsp
author Chris Cannam
date Sun, 11 May 2014 16:02:43 +0100
parents 3b07478932a1
children 4d08613cc9a2
files src/may/stream/test/test_resample.yeti
diffstat 1 files changed, 73 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- a/src/may/stream/test/test_resample.yeti	Thu May 01 11:36:14 2014 +0100
+++ b/src/may/stream/test/test_resample.yeti	Sun May 11 16:02:43 2014 +0100
@@ -5,6 +5,7 @@
 mat = load may.matrix;
 syn = load may.stream.syntheticstream;
 manip = load may.stream.manipulate;
+channels = load may.stream.channels;
 resample = load may.stream.resample;
 win = load may.signal.window;
 waves = load may.stream.waves;
@@ -12,6 +13,54 @@
 
 { compare, compareUsing, compareMatrices, assert, time } = load may.test;
 
+measureFrequency sampleRate cycles stream =
+   (case stream.available of
+    Known n:
+       (v = channels.mixedDown (stream.read n);
+        var firstCrossing = -1;
+        var lastCrossing = -1;
+        var nCrossings = 0;
+        for [0..vec.length v - 2] do i:
+            if nCrossings < cycles and vec.at v i <= 0 and vec.at v (i+1) > 0 then
+                if firstCrossing < 0 then
+                    firstCrossing := i;
+                fi;
+                lastCrossing := i;
+                nCrossings := nCrossings + 1;
+            fi;
+        done;
+        if nCrossings < 2 then 0
+        else
+            cycle = (lastCrossing - firstCrossing) / (nCrossings - 1);
+            freq = sampleRate / cycle;
+            eprintln "lastCrossing = \(lastCrossing), firstCrossing = \(firstCrossing), dist = \(lastCrossing - firstCrossing), nCycles = \(nCrossings - 1), cycle = \(cycle), freq = \(freq)";
+            freq;
+        fi);
+   _: failWith "Expected stream duration to be known";
+   esac);
+
+testFrequencyIntegrity freq sourceRate targetRate =
+   (// Test that downsample and then upsample again produces a signal
+    // at the same frequency as the original (i.e. the overall speed
+    // is retained exactly, regardless of the SNR on the way).
+    nCycles = 5000;
+    duration = int (nCycles * sourceRate / freq);
+    originals = manip.duplicated 2
+       (manip.withDuration duration (syn.sinusoid sourceRate freq));
+    there = manip.duplicated 2
+       (resample.resampledTo targetRate originals[0]);
+    back = resample.resampledTo sourceRate there[0];
+    origFreq = measureFrequency sourceRate (nCycles - 2) originals[1];
+    backFreq = measureFrequency sourceRate (nCycles - 2) back;
+    if not (compare backFreq origFreq) then
+        iFreq = measureFrequency targetRate (nCycles - 2) there[1];
+        eprintln "** note: rate conversion \(sourceRate) -> \(targetRate) -> \(sourceRate)";
+        eprintln "** frequency measured from intermediate stream: \(iFreq)";
+        false
+    else
+        true
+    fi);
+
 [
 
 // Test for duration of decimated stream (does not test contents, that
@@ -208,6 +257,30 @@
     compareMatrices 1e-5 (mat.newRowVector b) (mat.newRowVector data);
 ),
 
+"down-up-2": \(
+    testFrequencyIntegrity 440 44100 22050;
+),
+
+"down-up-5": \(
+    testFrequencyIntegrity 440 44100 8820;
+),
+
+"down-up-16": \(
+    testFrequencyIntegrity 440 48000 3000;
+),
+
+"up-down-2": \(
+    testFrequencyIntegrity 440 44100 88200;
+),
+
+"up-down-5": \(
+    testFrequencyIntegrity 440 9600 48000;
+),
+
+"up-down-16": \(
+    testFrequencyIntegrity 440 3000 48000;
+),
+
 "same-rate": \(
     // Test that resample to the original rate leaves data unchanged
     data = vec.fromList [ 0, 0.1, -0.3, -0.4, -0.3, 0, 0.5, 0.2, 0.8, -0.1 ];