changeset 401:a4e4e9dc8e46 resample

More toward direct resample
author Chris Cannam
date Fri, 27 Sep 2013 12:33:18 +0100
parents fe47d9e8f596
children 4076b141df7b
files src/may/stream/filter.yeti
diffstat 1 files changed, 76 insertions(+), 29 deletions(-) [+]
line wrap: on
line diff
--- a/src/may/stream/filter.yeti	Fri Sep 27 12:32:53 2013 +0100
+++ b/src/may/stream/filter.yeti	Fri Sep 27 12:33:18 2013 +0100
@@ -409,6 +409,7 @@
 
 //!!! todo: partial application so as to preprocess ir (in fast convolution case)
 convolvedWith options ir s = //!!! cheap mono thing here
+//!!! doc note: fast convolution output is padded to next frame boundary
    (if mat.height ir != s.channels then
         failWith "Signal stream and IR must have same number of channels (\(s.channels) != \(mat.height ir))"
     fi;
@@ -447,14 +448,7 @@
     kw = win.kaiser (pp with { length });
     sw = win.sinc (n*2) length;
     println "kaiserSincFilterFor: filter length is \(vec.length sw)";
-
-    f = bf.multiply sw kw;
-    
-    println "sinc peak is \(bf.max sw) at index \(bf.maxindex sw)";
-    println "kaiser peak is \(bf.max kw) at index \(bf.maxindex kw)";
-    println "filter peak is \(bf.max f) at index \(bf.maxindex f)";
-
-    f);
+    bf.multiply sw kw);
 
 bandpassed f0 f1 attenuation bandwidth s =
    (rate = s.sampleRate;
@@ -586,6 +580,13 @@
     lower = min sourceRate targetRate;
     g = gcd higher lower;
 
+    initialAvailable = s.available; // only so as to distinguish Known etc
+    var remaining = 
+        case initialAvailable of
+        Known n: int ((n * targetRate) / sourceRate + 0.5);
+        other: 0;
+        esac;
+
     // Example: ratio of 3:4 in sample periods, corresponding to
     // e.g. resampling from 48kHz to 36kHz. The lower rate has the
     // longer sample period. We need a filter with n=4 values from
@@ -594,20 +595,33 @@
     // the gcd (because the ratio of sample periods is the reciprocal
     // of the ratio of sample rates).
 
-    n = higher / g; // would be 4 in the above example
+    peakToPole = higher / g; // would be 4 in the above example
 
-    println "for target rate \(targetRate) and source rate \(sourceRate), gcd = \(g) and n = \(n), would be \(lower / g) if we used min";
+    println "for target rate \(targetRate) and source rate \(sourceRate), gcd = \(g) and peakToPole = \(peakToPole)";
 
-    // Our filter is a sinc function with peak-to-pole length n,
-    // multiplied by a Kaiser window of transition bandwidth narrow
-    // enough at the effective sample rate n to exclude... what?
+    // Our filter is a sinc function with peak-to-pole length
+    // peakToPole, multiplied by a Kaiser window of transition
+    // bandwidth narrow enough at the effective sample rate n to
+    // exclude... what?
 
     //!!! ponder
-//    filt = kaiserSincFilterFor { n, alpha = 80, bandwidth = 10, sampleRate = lower };
-    filt = kaiserSincFilterFor { n, attenuation = 80, bandwidth = 1, samplerate = higher };
 
-//\() (    plot.plot [Vector filt] );
+    filt = kaiserSincFilterFor {
+        n = peakToPole,
+        attenuation = 140,
+//        bandwidth = 10,
+        bandwidth = lower / 100,
+        samplerate = lower
+    };
 
+/*
+    filt = kaiserSincFilterFor {
+        n = peakToPole, 
+        attenuation = 80, 
+        bandwidth = 1, 
+        samplerate = higher
+    };
+*/
     // Now we have a filter of (odd) length flen in which the lower
     // sample rate corresponds to every n'th point and the higher rate
     // to every m'th where n and m are higher and lower rates divided
@@ -647,12 +661,23 @@
     flen = vec.length filt;
     halflen = int (flen/2); // actual filter length is halflen + halflen + 1
     spacedInput = spaced (targetRate / g) s;
+    
+    initialFill = spacedInput.read halflen;
+
+    println "initialFill = \(initialFill) (requested \(halflen))";
+
     var buffer = mat.toRowMajor
        (mat.concat (Horizontal ())
            [mat.zeroMatrix { rows = s.channels, columns = halflen + 1 },
-            spacedInput.read halflen]);
+            initialFill]);
     var pos = 0;
 
+    expired? () = 
+        case initialAvailable of
+        Known _: remaining <= 0;
+        _: mat.width buffer <= halflen;
+        esac;
+
     reconstructOne ch =
        (var out = 0;
         var series = mat.getRow ch buffer; //!!! check this has length flen
@@ -665,26 +690,48 @@
         out);
 
     readOne () =
-       (result = mat.newColumnVector
-           (vec.fromList (map reconstructOne [0 .. s.channels-1]));
+        if expired? () then
+            mat.zeroSizeMatrix ()
+        else
+            result = mat.newColumnVector
+               (vec.fromList (map reconstructOne [0 .. s.channels-1]));
 //        println "result = \(result)";
-//print ".";
-        m = sourceRate / g;
-        buffer := mat.concat (Horizontal ())
-           [mat.columnSlice buffer m (flen - m),
-            spacedInput.read m];
-        result);
+print ".";
+            m = sourceRate / g;
+            next = spacedInput.read m;
+            buffer := mat.concat (Horizontal ())
+               [mat.columnSlice buffer m (flen - m), next];
+//println "dropped \(m), read \(mat.width next), buffer now \(mat.width buffer)";
+            remaining := if remaining > 0 then remaining - 1 else 0 fi;
+            pos := pos + 1;
+//println "returning \(result)";
+            result
+        fi;
     
     s with
     {
         get sampleRate () = targetRate,
         get position () = pos,
-        get available () = Unknown (), //!!! todo
-        read n = mat.toRowMajor
-           (mat.concat (Horizontal ()) (map do _: readOne () done [1..n])),
+        get available () = 
+            case initialAvailable of
+            Known n: Known remaining;
+            other: other;
+            esac,
+        get finished? () = expired? (),
+        read n = 
+           (result = 
+                mat.toRowMajor
+                   (mat.concat (Horizontal ()) (map do _: readOne () done [1..n]));
+            println "returning from read: \(result)";
+            result)
     });
 
-resampledTo = resampledSplendidlyTo;
+//resampledTo = resampledSplendidlyTo;
+
+//interpolated factor s = resampledTo (s.sampleRate * factor) s;
+//decimated factor s = resampledTo (s.sampleRate / factor) s;
+
+resampledTo = resampledSlowlyTo;
 
 {
     withDuration is number -> stream -> stream,