changeset 291:c40821ff70f8

Hurrah! Overlap-add now produces valid output streams (finally) and passes the tests
author Chris Cannam
date Fri, 31 May 2013 15:14:09 +0100
parents 21ec05237c1a
children 240eb77ee2e8
files yetilab/stream/filter.yeti yetilab/stream/framer.yeti yetilab/stream/test/test_framer.yeti
diffstat 3 files changed, 78 insertions(+), 68 deletions(-) [+]
line wrap: on
line diff
--- a/yetilab/stream/filter.yeti	Fri May 31 10:58:00 2013 +0100
+++ b/yetilab/stream/filter.yeti	Fri May 31 15:14:09 2013 +0100
@@ -9,6 +9,8 @@
 load yetilab.vector.type;
 load yetilab.matrix.type;
 
+//!!! todo: synchronized for everything with state assignment
+
 minDurationOf d1 d2 =
     case d1 of 
     Known a:
--- a/yetilab/stream/framer.yeti	Fri May 31 10:58:00 2013 +0100
+++ b/yetilab/stream/framer.yeti	Fri May 31 15:14:09 2013 +0100
@@ -13,9 +13,10 @@
 fft = load yetilab.transform.fft;
 mat = load yetilab.matrix;
 ch = load yetilab.stream.channels;
-syn = load yetilab.stream.syntheticstream;
 filt = load yetilab.stream.filter;
 
+//!!! todo: synchronized for everything with state assignment
+
 blockList framesize stream =
     if stream.finished? then
         stream.close ();
@@ -94,26 +95,25 @@
         close = \(),
     });
 
-overlapAdd channels overlap frames =
+overlapAdd overlap frames =
    (ola fr acc =
-        if empty? fr then
-           [acc]
-        else
-            pre = mat.columnSlice acc 0 (mat.width acc - overlap);
-            added = mat.sum (head fr) 
-               (mat.resizedTo { columns = mat.width (head fr), rows = channels }
-                   (mat.columnSlice acc (mat.width acc - overlap) (mat.width acc)));
-    /*               
-            frameSized = mat.resizedTo
-               { columns = framesize, rows = channels };
-            extended = frameSized
-               (mat.columnSlice acc hop (mat.width acc));
-            added = mat.sum (frameSized (head fr)) extended;
-           (mat.columnSlice acc 0 hop) :: ola (tail fr) added;
-*/
-            pre :: ola (tail fr) added;
-        fi;
-    mat.concat (Horizontal ()) (ola frames (mat.zeroSizeMatrix ())));
+        case fr of
+        first::rest:
+           (w = mat.width acc;
+            pre = mat.columnSlice acc 0 (w - overlap);
+            added = mat.sum first
+               (mat.resizedTo (mat.size first)
+               (mat.columnSlice acc (w - overlap) w));
+            pre :: ola rest added);
+         _:
+            [acc];
+        esac;
+    case frames of
+    first::rest:
+        mat.concat (Horizontal ()) (ola rest first);
+     _: 
+        mat.zeroSizeMatrix ();
+    esac);
 
 streamOverlapping rate framesize hop frames =
    (var remaining = frames;
@@ -121,21 +121,21 @@
     var position = 0;
     factor = hop / (framesize/2);
     w = bf.scaled factor (win.hann framesize); // periodic window, not symmetric
-    println "window is \(vec.list w)";
     channels = mat.height (head frames); // so we don't need to keep a head ptr
-    filt.delayedBy (- framesize)
+    syncd = synchronized remaining;
+    finished () = syncd \(empty? remaining and mat.empty? buffered);
+    filt.delayedBy (- (framesize - hop))
         {
-            get position () = position,
+            get position () = syncd \(position),
             get channels () = channels,
             get sampleRate () = rate,
-            get finished? () = empty? remaining and mat.empty? buffered,
-            get available () = Unknown (),
-            read count =
-               (framesFor samples acc =
+            get finished? () = finished (),
+            get available () = if finished () then Known 0 else Unknown () fi,
+            read count = syncd
+              \(framesFor samples acc =
                     if samples <= 0 or empty? remaining then
                         acc
                     else
-                        println "multiplying \(head remaining) by window";
                         this = mat.resizedTo
                             { columns = framesize, rows = channels }
                             (mat.newMatrix (RowMajor ())
@@ -144,13 +144,11 @@
                         remaining := tail remaining;
                         framesFor (samples - hop) (acc ++ [this])
                     fi;
-                source = overlapAdd channels (framesize - hop)
+                source = overlapAdd (framesize - hop)
                    (framesFor count [buffered]);
                 toReturn = mat.columnSlice source 0 count;
                 position := position + mat.width toReturn;
                 buffered := mat.columnSlice source count (mat.width source);
-                println "count = \(count), framesize = \(framesize), hop = \(hop)";
-                println "leaving position = \(position), buffered = \(buffered), returning \(toReturn)";
                 toReturn),
             close = \(),
         });
--- a/yetilab/stream/test/test_framer.yeti	Fri May 31 10:58:00 2013 +0100
+++ b/yetilab/stream/test/test_framer.yeti	Fri May 31 15:14:09 2013 +0100
@@ -19,31 +19,38 @@
 testFramesWith params length expected firstChunkSize =
    (f = fr.frames params (testStream length);
     str = fr.streamed rate params f;
-    sz = params.framesize;
-    ts = testStream length;
-
-    overlapping = params.framesize > params.hop;
-    incomplete = overlapping and // Can't reconstruct with < 50% overlap
-        params.framesize < params.hop * 2; 
-
-    println "firstChunkSize = \(firstChunkSize):";
-
-    firstChunk = str.read firstChunkSize;
-    restChunk = str.read (length - firstChunkSize);
+    ts = testStream length; // newly initialised stream
 
     compareFrames f expected and
-       (incomplete or 
-            compareUsing mat.equal
-                firstChunk (ts.read firstChunkSize)) and
-       (incomplete or 
-            compareUsing mat.equal
-                restChunk (ts.read (length - firstChunkSize))) and
+
+       (firstChunk = str.read firstChunkSize;
+        compareUsing mat.equal
+            firstChunk (ts.read firstChunkSize)) and
+
+        compare str.position firstChunkSize and
+        compare str.finished? false and
+
+       (restChunk = str.read (length - firstChunkSize);
+        compareUsing mat.equal
+            restChunk (ts.read (length - firstChunkSize))) and
         compare str.position length and
-       (overlapping or // (overlapping streamer doesn't know when it'll end!)
-           compare str.available (Known (sz - (length % sz)))));
+
+       (trailingZeros = str.read (params.framesize + 1);
+        compareUsing mat.equal
+            trailingZeros
+               (mat.zeroMatrix
+                { rows = str.channels, columns = mat.width trailingZeros }) and
+           (mat.width trailingZeros < params.framesize)) and
+
+       compare str.finished? true and
+       compare str.available (Known 0));
+
+testFramesInvertible params length expected =
+    all id (map (testFramesWith params length expected) [1..length]);
 
 testFrames params length expected =
-    all id (map (testFramesWith params length expected) [1..length]);
+   (f = fr.frames params (testStream length);
+    compareFrames f expected);
 
 [
 
@@ -103,7 +110,7 @@
 ),
 
 "frames-2x5": \( 
-    testFrames { framesize = 2, hop = 2 } 5 [ [1,2], [3,4], [5,0] ];
+    testFramesInvertible { framesize = 2, hop = 2 } 5 [ [1,2], [3,4], [5,0] ];
 ),
 
 "frames-4.3x4": \( 
@@ -115,46 +122,49 @@
 ),
 
 "frames-3.1x6": \(
-    testFrames { framesize = 3, hop = 1 } 6
+    testFramesInvertible { framesize = 3, hop = 1 } 6
         [ [0,0,1], [0,1,2], [1,2,3], [2,3,4],
           [3,4,5], [4,5,6], [5,6,0], [6,0,0] ];
 ),
 
 "frames-4.2x8": \(
-    testFrames { framesize = 4, hop = 2 } 8
+    testFramesInvertible { framesize = 4, hop = 2 } 8
         [ [0,0,1,2], [1,2,3,4], [3,4,5,6], [5,6,7,8], [7,8,0,0] ];
 ),
 
 "overlapAdd-3.1": \(
     compareUsing (mat.equal)
-       (fr.overlapAdd 1 2 [ mat.newRowVector (vec.fromList [ 1,2,3 ]),
-                            mat.newRowVector (vec.fromList [   4,5,6 ]),
-                            mat.newRowVector (vec.fromList [     7,8,9 ]) ])
+       (fr.overlapAdd 2 [ mat.newRowVector (vec.fromList [ 1,2,3 ]),
+                          mat.newRowVector (vec.fromList [   4,5,6 ]),
+                          mat.newRowVector (vec.fromList [     7,8,9 ]) ])
        (mat.newRowVector (vec.fromList [ 1,6,15,14,9 ]))
 ),
 
 "overlapAdd-3.2": \(
     compareUsing (mat.equal)
-       (fr.overlapAdd 1 1 [ mat.newRowVector (vec.fromList [ 1,2,3 ]),
-                            mat.newRowVector (vec.fromList [     4,5,6 ]),
-                            mat.newRowVector (vec.fromList [         7,8,9 ]) ])
+       (fr.overlapAdd 1 [ mat.newRowVector (vec.fromList [ 1,2,3 ]),
+                          mat.newRowVector (vec.fromList [     4,5,6 ]),
+                          mat.newRowVector (vec.fromList [         7,8,9 ]) ])
        (mat.newRowVector (vec.fromList [ 1,2,7,5,13,8,9 ]))
 ),
 
 "overlapAdd-4.2": \(
     compareUsing (mat.equal)
-       (fr.overlapAdd 1 2 [ mat.newRowVector (vec.fromList [ 1,2,3,4 ]),
-                            mat.newRowVector (vec.fromList [     5,6,7,8 ]),
-                            mat.newRowVector (vec.fromList [         9,0,1,2 ]) ])
+       (fr.overlapAdd 2 [ mat.newRowVector (vec.fromList [ 1,2,3,4 ]),
+                          mat.newRowVector (vec.fromList [     5,6,7,8 ]),
+                          mat.newRowVector (vec.fromList [         9,0,1,2 ]) ])
        (mat.newRowVector (vec.fromList [ 1,2,8,10,16,8,1,2 ]))
 ),
 
-"overlapAdd-6+4.2": \( // Must work even if blocks vary in length (what if shorter than overlap though?)
+"overlapAdd-6+4.2": \(
+    // Must work even if blocks vary in length (what if shorter than
+    // overlap though?)
     compareUsing (mat.equal)
-       (fr.overlapAdd 1 2 [ mat.newRowVector (vec.fromList [ 1,2,3,4,5,6 ]),
-                            mat.newRowVector (vec.fromList [         7,8,9,0 ]),
-                            mat.newRowVector (vec.fromList [             1,2,3,4 ]) ])
-       (mat.newRowVector (vec.fromList [ 1,2,3,4,12,14,10,2,3,4 ]))
+       (fr.overlapAdd 2 [ mat.newRowVector (vec.fromList [ 1,2,3,4,5,6 ]),
+                          mat.newRowVector (vec.fromList [         7,8,9,0 ]),
+                          mat.newRowVector (vec.fromList [             1,2,3 ]),
+                          mat.newRowVector (vec.fromList [               4,5,6 ]) ])
+       (mat.newRowVector (vec.fromList [ 1,2,3,4,12,14,10,6,8,6 ]))
 ),
 
 ] is hash<string, () -> boolean>;