changeset 280:7f000ae124db

Make convolver work. Ugly though
author Chris Cannam
date Tue, 28 May 2013 20:41:11 +0100
parents 3aacfde637fd
children f3784641245f
files yetilab/matrix/test/test_matrix.yeti yetilab/stream/filter.yeti yetilab/stream/syntheticstream.yeti yetilab/stream/test/test_filter.yeti
diffstat 4 files changed, 59 insertions(+), 24 deletions(-) [+]
line wrap: on
line diff
--- a/yetilab/matrix/test/test_matrix.yeti	Mon May 27 23:37:57 2013 +0100
+++ b/yetilab/matrix/test/test_matrix.yeti	Tue May 28 20:41:11 2013 +0100
@@ -397,6 +397,15 @@
        (newMatrix (ColumnMajor ()) [[1,4],[0,5],[3,6]])
 ),
 
+"concatEmpty-horiz-\(name)": \(
+    compareMatrices
+       (mat.concat (Horizontal ()) 
+          [(newMatrix (ColumnMajor ()) [[]]),
+           (newMatrix (RowMajor ()) [[]]),
+           (mat.zeroSizeMatrix ())])
+       (mat.zeroSizeMatrix ());
+),
+
 "sparseConcat-horiz-\(name)": \(
     s = mat.concat (Horizontal ()) 
           [mat.toSparse (newMatrix (ColumnMajor ()) [[1,4],[0,5]]),
--- a/yetilab/stream/filter.yeti	Mon May 27 23:37:57 2013 +0100
+++ b/yetilab/stream/filter.yeti	Tue May 28 20:41:11 2013 +0100
@@ -7,6 +7,7 @@
 
 load yetilab.stream.type;
 load yetilab.vector.type;
+load yetilab.matrix.type;
 
 minDurationOf d1 d2 =
     case d1 of 
@@ -260,36 +261,59 @@
             done [1..copies];
     fi;
 
-convolvedWith ir s = //!!! currently ir is single channel vector only; very slow
-   (var buffer = mat.toRowMajor
-       (mat.zeroMatrix { rows = s.channels, columns = vec.length ir });
+convolvedWith ir s =
+   (if mat.height ir != s.channels then
+        failWith "Signal stream and IR must have same number of channels (\(s.channels) != \(mat.height ir))"
+    fi;
+    var history = mat.toRowMajor
+       (mat.zeroMatrix { rows = s.channels, columns = mat.width ir - 1 });
     s with 
     {
+        get finished? () =
+            s.finished? and (mat.isZeroSize? history),
         get available () = 
             case s.available of
-            Known n: Known (n + vec.length ir - 1);
+            Known n: Known (n + mat.width history);
             other: other;
             esac,
         read count = 
-           (signal = s.read count;
-            out = array (map \(new double[mat.width signal]) [1..s.channels]);
+           (// Example: The IR is four samples long; we have three
+            // samples in history; two samples are available to read
+            // before the stream runs out. That means we can return
+            // up to five samples. Caller requests 6.
+            signal = s.read count;                     // -> two samples
+            siglen = mat.width signal;                 // -> 2
+            histlen = mat.width history;               // -> 3
+            convlen = min count (siglen + histlen);    // -> 5
+            input = mat.resizedTo { rows = s.channels, columns = convlen }
+                signal;  // example input now 5 samples, of which 2 are signal
+            output = array (map \(new double[convlen]) [1..s.channels]);
             for [0..s.channels - 1] do ch:
-                for [0..mat.width signal - 1] do i:
-                    for [0..vec.length ir - 1] do j:
-                    history = 
-                        if j > i then
-                            mat.at buffer ch (mat.width buffer + i - j)
-                        else
-                            mat.at signal ch (i - j)
-                        fi;
-                        out[ch][i] := out[ch][i] + history * (vec.at ir j);
+                for [0..mat.width input - 1] do i:
+                    for [0..mat.width ir - 1] do j:
+                        v = 
+                            if i >= j then
+                                mat.at input ch (i - j)
+                            else
+                                ix = mat.width ir + i - j - 1;
+                                if ix >= histlen then 
+                                    0 
+                                else
+                                    mat.at history ch ix
+                                fi
+                            fi;
+                        output[ch][i] := output[ch][i] + v * (mat.at ir ch j);
                     done;
                 done;
             done;
-            extended = mat.concat (Horizontal ()) [buffer, signal];
+            // Remove from history a number of samples equal to the
+            // number returned; add to it a number equal to the number
+            // read from source
+            extended = mat.concat (Horizontal ()) [history, signal]; // -> 5
+            newlen = (histlen + siglen) - convlen; // -> 0
             w = mat.width extended;
-            buffer := mat.columnSlice extended (w - vec.length ir) w;
-            mat.newMatrix (RowMajor ()) (map vec.vector out)),
+            history := mat.columnSlice extended (w - newlen) w;
+            mat.newMatrix (RowMajor ()) (map vec.vector output)),
     });
 
 {
@@ -300,6 +324,6 @@
     multiplexed is list<stream> -> stream,
     repeated is stream -> stream,
     duplicated is number -> stream -> list<stream>,
-    convolvedWith is vector -> stream -> stream,
+    convolvedWith is matrix -> stream -> stream,
 }
 
--- a/yetilab/stream/syntheticstream.yeti	Mon May 27 23:37:57 2013 +0100
+++ b/yetilab/stream/syntheticstream.yeti	Tue May 28 20:41:11 2013 +0100
@@ -35,7 +35,7 @@
 silent rate =
     generated rate \0;
 
-precalculated rate data = //!!! hang on -- these are returning 1-ch vectors, not matrices like other streams. how is this working?
+precalculated rate data =
    (n = vec.length data;
     var position = 0;
     {
--- a/yetilab/stream/test/test_filter.yeti	Mon May 27 23:37:57 2013 +0100
+++ b/yetilab/stream/test/test_filter.yeti	Tue May 28 20:41:11 2013 +0100
@@ -532,17 +532,19 @@
 ),
 
 "convolvedWith-\(name)": \(
-    ir = vec.fromList [1,2,3];
+    ir = mat.newRowVector (vec.fromList [1,2,3]);
     signal = maybeDuration 2 (syn.precalculated 2 (vec.fromList [1,2]));
     c = filt.convolvedWith ir signal;
     compare c.position 0 and
         compare c.channels 1 and
         compare c.sampleRate 2 and
         compare c.available (maybeKnown 4) and
-        compare (map vec.list (mat.asRows (c.read 3))) [[1,4,7]] and
-        compare c.available (maybeKnown 1) and
+        compare (map vec.list (mat.asRows (c.read 3)))
+            [[ 1*1, 2*1 + 1*2, 0*1 + 2*2 + 1*3 ]] and
+        compare c.available (Known 1) and
         compare c.finished? false and
-        compare (map vec.list (mat.asRows (c.read 4))) [[6]] and
+        compare (map vec.list (mat.asRows (c.read 4)))
+            [[ 0*1 + 0*2 + 2*3 ]] and
         compare c.available (Known 0) and
         compare c.finished? true and
         ( c.close (); true )