view yetilab/stream/framer.yeti @ 138:f68c92bd2adb

Slightly better text placement
author Chris Cannam
date Tue, 23 Apr 2013 17:01:19 +0100
parents d0abc9afe608
children cb5ab186f146
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 mono 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;

blockList framesize stream =
    if stream.finished? then
       (stream.close (); [] );
    else
        block.resizedTo framesize (stream.readMono framesize)
            :. \(blockList framesize stream);
    fi;

overlappingBlockList size hop stream valid buffer =
   (
    b = stream.readMono hop;
    obtained = block.length b;

    // Retain framesize - hop samples from old buffer, add hop samples
    // (zero-padded if necessary) just read
    buffer = block.concat
       [block.rangeOf buffer hop (size-hop),
        block.resizedTo hop b];

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

    if remaining <= 0 then
        stream.close ();
        [];
    else
        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 (block.zeros framesize);
    fi;

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

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

{ 
    frames,
    windowedFrames,
    frequencyDomainFrames,

    framesOfFile parameters filename =
        case af.open filename of
        Stream s: Frames (frames parameters s);
        Error e: Error e;
        esac,

    windowedFramesOfFile parameters filename = 
        case af.open filename of
        Stream s: Frames (windowedFrames parameters s);
        Error e: Error e;
        esac,

    frequencyDomainFramesOfFile parameters filename = 
        case af.open filename of
        Stream s: Frames (frequencyDomainFrames parameters s);
        Error e: Error e;
        esac,
}