view yetilab/stream/framer.yeti @ 178:032c4986b6b0

Implement and test matrix concat
author Chris Cannam
date Thu, 02 May 2013 21:58:58 +0100
parents 3fbaa25aad89
children 479a739c99b1
line wrap: on
line source

module yetilab.stream.framer;

/**
 * Framer expresses a stream (or a file) as a lazy list of (possibly
 * overlapping) frames of data.
 */

block = load yetilab.block.block;
bf = load yetilab.block.blockfuncs;
af = load yetilab.stream.audiofile;
win = load yetilab.transform.window;
fft = load yetilab.transform.fft;
mat = load yetilab.matrix.matrix;
ch = load yetilab.stream.channels;

blockList framesize stream =
    if stream.finished? then
        stream.close ();
        []
    else
        mat.resizedTo { rows = stream.channels, columns = framesize }
           (stream.read framesize)
            :. \(blockList framesize stream);
    fi;

overlappingBlockList size hop stream valid buffer =
   (
    m = stream.read hop;
    obtained = mat.width m;

    // Retain framesize - hop samples from old buffer, add hop samples
    // (zero-padded if necessary) just read
    buffer = map2
        do buf row:
            block.concat
               [block.rangeOf buf hop (size-hop),
                block.resizedTo hop (m.getRow row)];
        done buffer [0..stream.channels-1];

    // Number of "valid" elements (not tail-end zero-padding) left in buffer
    remaining = valid - (hop - obtained);

    if remaining <= 0 then
        stream.close ();
        [];
    else
        mat.newMatrix (RowMajor ()) buffer
            :. \(overlappingBlockList size hop stream remaining buffer);
    fi);

frames { framesize, hop } stream =
    if framesize == hop then
        blockList framesize stream
    else
        overlappingBlockList framesize hop stream 
            framesize (map \(block.zeros framesize) [0..stream.channels-1]);
    fi;

monoFrames params stream =
    map ch.mixedDown (frames params stream);

windowedFrames { framesize, hop, window } stream =
   (win = window framesize;
    map (bf.multiply win) (monoFrames { framesize, hop } stream));

frequencyDomainFrames { framesize, hop } stream =
   (f = fft.realForward framesize;
    map f (windowedFrames { framesize, hop, window = win.hann } stream));

{ 
    frames,
    monoFrames,
    windowedFrames,
    frequencyDomainFrames,

    framesOfFile parameters filename =
        frames parameters (af.open filename),

    monoFramesOfFile parameters filename =
        monoFrames parameters (af.open filename),

    windowedFramesOfFile parameters filename = 
        windowedFrames parameters (af.open filename),

    frequencyDomainFramesOfFile parameters filename = 
        frequencyDomainFrames parameters (af.open filename),
}