Chris@8: Chris@93: module yetilab.stream.framer; Chris@8: Chris@25: /** Chris@25: * Framer expresses a stream (or a file) as a lazy list of (possibly Chris@25: * overlapping) frames of mono data. Chris@25: */ Chris@25: Chris@93: block = load yetilab.block.block; Chris@93: bf = load yetilab.block.blockfuncs; Chris@93: af = load yetilab.stream.audiofile; Chris@93: win = load yetilab.transform.window; Chris@93: fft = load yetilab.transform.fft; Chris@8: Chris@32: blockList framesize stream = Chris@14: if stream.finished? then Chris@14: (stream.close (); [] ); Chris@13: else Chris@32: block.resizedTo framesize (stream.readMono framesize) Chris@32: :. \(blockList framesize stream); Chris@13: fi; Chris@13: Chris@47: overlappingBlockList size hop stream valid buffer = Chris@29: ( Chris@29: b = stream.readMono hop; Chris@24: obtained = block.length b; Chris@23: Chris@32: // Retain framesize - hop samples from old buffer, add hop samples Chris@29: // (zero-padded if necessary) just read Chris@47: buffer = block.concat Chris@47: [block.rangeOf buffer hop (size-hop), Chris@47: block.resizedTo hop b]; Chris@23: Chris@23: // Number of "valid" elements (not tail-end zero-padding) left in buffer Chris@24: remaining = valid - (hop - obtained); Chris@23: Chris@23: if remaining <= 0 then Chris@23: stream.close (); Chris@23: []; Chris@12: else Chris@47: buffer :. \(overlappingBlockList size hop stream remaining buffer); Chris@23: fi); Chris@14: Chris@32: frames { framesize, hop } stream = Chris@32: if framesize == hop then Chris@32: blockList framesize stream Chris@30: else Chris@32: overlappingBlockList framesize hop stream Chris@47: framesize (block.zeros framesize); Chris@30: fi; Chris@14: Chris@49: windowedFrames { framesize, hop, window } stream = Chris@49: (win = window framesize; Chris@49: map (bf.multiply win) (frames { framesize, hop } stream)); Chris@49: Chris@49: frequencyDomainFrames { framesize, hop } stream = Chris@49: (f = fft.realForward framesize; Chris@49: map f (windowedFrames { framesize, hop, window = win.hann } stream)); Chris@23: Chris@11: { Chris@30: frames, Chris@49: windowedFrames, Chris@49: frequencyDomainFrames, Chris@49: Chris@49: framesOfFile parameters filename = Chris@81: case af.open filename of Chris@81: Stream s: Frames (frames parameters s); Chris@81: Error e: Error e; Chris@81: esac, Chris@49: Chris@49: windowedFramesOfFile parameters filename = Chris@81: case af.open filename of Chris@81: Stream s: Frames (windowedFrames parameters s); Chris@81: Error e: Error e; Chris@81: esac, Chris@49: Chris@49: frequencyDomainFramesOfFile parameters filename = Chris@81: case af.open filename of Chris@81: Stream s: Frames (frequencyDomainFrames parameters s); Chris@81: Error e: Error e; Chris@81: esac, Chris@11: } Chris@8: