Mercurial > hg > may
changeset 284:7932bbb7bacb
Toward frame -> stream processing. Need overlap-add.
author | Chris Cannam |
---|---|
date | Wed, 29 May 2013 22:59:23 +0100 |
parents | e330ac62703b |
children | be39f21456a1 |
files | yetilab/matrix.yeti yetilab/signal/window.yeti yetilab/stream/filter.yeti yetilab/stream/framer.yeti yetilab/stream/syntheticstream.yeti yetilab/stream/test/test_framer.yeti |
diffstat | 6 files changed, 103 insertions(+), 38 deletions(-) [+] |
line wrap: on
line diff
--- a/yetilab/matrix.yeti Wed May 29 17:32:58 2013 +0100 +++ b/yetilab/matrix.yeti Wed May 29 22:59:23 2013 +0100 @@ -173,7 +173,7 @@ zeroSizeMatrix () = zeroMatrix { rows = 0, columns = 0 }; -isZeroSize? m = (width m == 0 or height m == 0); +empty?' m = (width m == 0 or height m == 0); generate f { rows, columns } = if rows < 1 or columns < 1 then zeroSizeMatrix () @@ -340,7 +340,7 @@ esac); equal' comparator vecComparator m1 m2 = - if isZeroSize? m1 and isZeroSize? m2 then + if empty?' m1 and empty?' m2 then true elif size m1 != size m2 then false @@ -639,7 +639,7 @@ //!!! doc this filter -- zero-size elts are ignored concat direction mm = - concat' direction (filter do mat: not (isZeroSize? mat) done mm); + concat' direction (filter do mat: not (empty?' mat) done mm); //!!! next two v. clumsy @@ -727,7 +727,7 @@ zeroMatrix, identityMatrix, zeroSizeMatrix, - isZeroSize?, + empty? = empty?', equal, equalUnder, transposed, @@ -774,7 +774,7 @@ zeroMatrix is { .rows is number, .columns is number } -> matrix, identityMatrix is { .rows is number, .columns is number } -> matrix, zeroSizeMatrix is () -> matrix, - isZeroSize? is matrix -> boolean, + empty? is matrix -> boolean, equal is matrix -> matrix -> boolean, equalUnder is (number -> number -> boolean) -> matrix -> matrix -> boolean, transposed is matrix -> matrix,
--- a/yetilab/signal/window.yeti Wed May 29 17:32:58 2013 +0100 +++ b/yetilab/signal/window.yeti Wed May 29 22:59:23 2013 +0100 @@ -85,6 +85,7 @@ Bartlett (): bartlett sampling; esac); +//!!! should use vector. but does anyone use this function anyway? would we use it in framer if it used vector? windowed windowFunc frames = case frames of []: frames;
--- a/yetilab/stream/filter.yeti Wed May 29 17:32:58 2013 +0100 +++ b/yetilab/stream/filter.yeti Wed May 29 22:59:23 2013 +0100 @@ -270,7 +270,7 @@ s with { get finished? () = - s.finished? and (mat.isZeroSize? history), + s.finished? and (mat.empty? history), get available () = case s.available of Known n: Known (n + mat.width history);
--- a/yetilab/stream/framer.yeti Wed May 29 17:32:58 2013 +0100 +++ b/yetilab/stream/framer.yeti Wed May 29 22:59:23 2013 +0100 @@ -14,6 +14,7 @@ mat = load yetilab.matrix; ch = load yetilab.stream.channels; syn = load yetilab.stream.syntheticstream; +filt = load yetilab.stream.filter; blockList framesize stream = if stream.finished? then @@ -58,33 +59,85 @@ framesize (map \(vec.zeros framesize) [0..stream.channels-1]); fi; -streamContiguous rate framesize fr = - if empty? frames then - syn.empty rate 1 - else - var position = 0; - var frames = fr; - var fini = false; - channels = mat.height (head frames); // so we don't need to keep head ptr +streamContiguous rate framesize frames = + (var remaining = frames; + var buffered = mat.zeroSizeMatrix (); + var position = 0; + channels = mat.height (head frames); // so we don't need to keep a head ptr + { + get position () = position, + get channels () = channels, + get sampleRate () = rate, + get finished? () = empty? remaining and mat.empty? buffered, + get available () = + // Don't take length of frames -- we don't want to lose laziness. + // If the caller cares that much, they can measure frames themselves + if empty? remaining then + Known (mat.width buffered) + else + Unknown () + fi, + read count = + (framesFor samples acc = + if samples <= 0 or empty? remaining then + acc + else + this = head remaining; + remaining := tail remaining; + framesFor (samples - mat.width this) (acc ++ [this]) + fi; + source = mat.concat (Horizontal ()) (framesFor count [buffered]); + toReturn = mat.columnSlice source 0 count; + position := position + mat.width toReturn; + buffered := mat.columnSlice source count (mat.width source); + toReturn), + close = \(), + }); + +streamOverlapping rate framesize hop frames = + (var remaining = frames; + var buffered = mat.zeroSizeMatrix (); + var position = 0; + w = win.hann framesize; + channels = mat.height (head frames); // so we don't need to keep a head ptr + filt.delayedBy (- (framesize - hop)) { get position () = position, get channels () = channels, get sampleRate () = rate, - get available () = if fini then Known 0 else Unknown () fi, - get finished? () = fini, - - + get finished? () = empty? remaining and mat.empty? buffered, + get available () = + // Don't take length of frames: we don't want to lose + // laziness. If the caller cares that much, they can + // measure frames themselves + if empty? remaining then + Known (mat.width buffered) + else + Unknown () + fi, + read count = + (framesFor samples acc = + if samples <= 0 or empty? remaining then + acc + else + this = mat.newMatrix (RowMajor ()) + (map (bf.multiply w) (mat.asRows (head remaining))); + remaining := tail remaining; + framesFor (samples - hop) (acc ++ [this]) + fi; + source = mat.concat (Horizontal ()) (framesFor count [buffered]); + toReturn = mat.columnSlice source 0 count; + buffered := mat.columnSlice source count (mat.width source); + toReturn), close = \(), - } - fi; - + }); + //!!! doc: convert frames back to a stream streamed rate { framesize, hop } frames = if framesize == hop then streamContiguous rate framesize frames else - //!!! OLA - syn.empty rate 1; + streamOverlapping rate framesize hop frames fi; monoFrames params stream = @@ -115,5 +168,7 @@ frequencyDomainFramesOfFile parameters filename = frequencyDomainFrames parameters (af.open filename), + + streamed, }
--- a/yetilab/stream/syntheticstream.yeti Wed May 29 17:32:58 2013 +0100 +++ b/yetilab/stream/syntheticstream.yeti Wed May 29 22:59:23 2013 +0100 @@ -3,6 +3,7 @@ ch = load yetilab.stream.channels; vec = load yetilab.vector; +mat = load yetilab.matrix; load yetilab.vector.type; load yetilab.stream.type; @@ -69,7 +70,7 @@ sinusoid is number -> number -> stream, whiteNoise is number -> stream, silent is number -> stream, - empty = number -> number -> stream, + empty is number -> number -> stream, }
--- a/yetilab/stream/test/test_framer.yeti Wed May 29 17:32:58 2013 +0100 +++ b/yetilab/stream/test/test_framer.yeti Wed May 29 22:59:23 2013 +0100 @@ -8,12 +8,27 @@ { compare, compareUsing } = load yetilab.test.test; -testStream n is number -> 'a = syn.precalculated 1000 (vec.fromList [1..n]); +rate = 10; + +testStream n is number -> 'a = syn.precalculated rate (vec.fromList [1..n]); compareFrames frames1 frames2 = all id (map2 do f1 f2: compareUsing mat.equal f1 f2 done frames1 (map (mat.newRowVector . vec.fromList) frames2)); +testFrames parameters length expected = + (f = fr.frames parameters (testStream length); + str = fr.streamed rate parameters f; + sz = parameters.framesize; + ts = testStream length; + compareFrames f expected and + compareUsing mat.equal + (str.read 2) (ts.read 2) and + compareUsing mat.equal + (str.read (length - 2)) (ts.read (length - 2)) and + compare str.position length and + compare str.available (Known (sz - (length % sz)))); + [ "framecount-2x2": \( @@ -72,28 +87,21 @@ ), "frames-2x5": \( - fr = fr.frames { framesize = 2, hop = 2 } (testStream 5); - expected = [ [1,2], [3,4], [5,0] ]; - compareFrames fr expected; + testFrames { framesize = 2, hop = 2 } 5 [ [1,2], [3,4], [5,0] ]; ), "frames-4.3x4": \( - fr = fr.frames { framesize = 4, hop = 3 } (testStream 4); - expected = [ [0,1,2,3], [3,4,0,0] ]; - compareFrames fr expected; + testFrames { framesize = 4, hop = 3 } 4 [ [0,1,2,3], [3,4,0,0] ]; ), "frames-3.2x4": \( - fr = fr.frames { framesize = 3, hop = 2 } (testStream 4); - expected = [ [0,1,2], [2,3,4], [4,0,0] ]; - compareFrames fr expected; + testFrames { framesize = 3, hop = 2 } 4 [ [0,1,2], [2,3,4], [4,0,0] ]; ), "frames-3.1x6": \( - fr = fr.frames { framesize = 3, hop = 1 } (testStream 6); - expected = [ [0,0,1], [0,1,2], [1,2,3], [2,3,4], - [3,4,5], [4,5,6], [5,6,0], [6,0,0] ]; - compareFrames fr expected; + testFrames { 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] ]; ), ] is hash<string, () -> boolean>;