Chris@8
|
1
|
Chris@93
|
2 module yetilab.stream.framer;
|
Chris@8
|
3
|
Chris@25
|
4 /**
|
Chris@25
|
5 * Framer expresses a stream (or a file) as a lazy list of (possibly
|
Chris@25
|
6 * overlapping) frames of mono data.
|
Chris@25
|
7 */
|
Chris@25
|
8
|
Chris@93
|
9 block = load yetilab.block.block;
|
Chris@93
|
10 bf = load yetilab.block.blockfuncs;
|
Chris@93
|
11 af = load yetilab.stream.audiofile;
|
Chris@93
|
12 win = load yetilab.transform.window;
|
Chris@93
|
13 fft = load yetilab.transform.fft;
|
Chris@8
|
14
|
Chris@32
|
15 blockList framesize stream =
|
Chris@14
|
16 if stream.finished? then
|
Chris@14
|
17 (stream.close (); [] );
|
Chris@13
|
18 else
|
Chris@32
|
19 block.resizedTo framesize (stream.readMono framesize)
|
Chris@32
|
20 :. \(blockList framesize stream);
|
Chris@13
|
21 fi;
|
Chris@13
|
22
|
Chris@47
|
23 overlappingBlockList size hop stream valid buffer =
|
Chris@29
|
24 (
|
Chris@29
|
25 b = stream.readMono hop;
|
Chris@24
|
26 obtained = block.length b;
|
Chris@23
|
27
|
Chris@32
|
28 // Retain framesize - hop samples from old buffer, add hop samples
|
Chris@29
|
29 // (zero-padded if necessary) just read
|
Chris@47
|
30 buffer = block.concat
|
Chris@47
|
31 [block.rangeOf buffer hop (size-hop),
|
Chris@47
|
32 block.resizedTo hop b];
|
Chris@23
|
33
|
Chris@23
|
34 // Number of "valid" elements (not tail-end zero-padding) left in buffer
|
Chris@24
|
35 remaining = valid - (hop - obtained);
|
Chris@23
|
36
|
Chris@23
|
37 if remaining <= 0 then
|
Chris@23
|
38 stream.close ();
|
Chris@23
|
39 [];
|
Chris@12
|
40 else
|
Chris@47
|
41 buffer :. \(overlappingBlockList size hop stream remaining buffer);
|
Chris@23
|
42 fi);
|
Chris@14
|
43
|
Chris@32
|
44 frames { framesize, hop } stream =
|
Chris@32
|
45 if framesize == hop then
|
Chris@32
|
46 blockList framesize stream
|
Chris@30
|
47 else
|
Chris@32
|
48 overlappingBlockList framesize hop stream
|
Chris@47
|
49 framesize (block.zeros framesize);
|
Chris@30
|
50 fi;
|
Chris@14
|
51
|
Chris@49
|
52 windowedFrames { framesize, hop, window } stream =
|
Chris@49
|
53 (win = window framesize;
|
Chris@49
|
54 map (bf.multiply win) (frames { framesize, hop } stream));
|
Chris@49
|
55
|
Chris@49
|
56 frequencyDomainFrames { framesize, hop } stream =
|
Chris@49
|
57 (f = fft.realForward framesize;
|
Chris@49
|
58 map f (windowedFrames { framesize, hop, window = win.hann } stream));
|
Chris@23
|
59
|
Chris@11
|
60 {
|
Chris@30
|
61 frames,
|
Chris@49
|
62 windowedFrames,
|
Chris@49
|
63 frequencyDomainFrames,
|
Chris@49
|
64
|
Chris@49
|
65 framesOfFile parameters filename =
|
Chris@81
|
66 case af.open filename of
|
Chris@81
|
67 Stream s: Frames (frames parameters s);
|
Chris@81
|
68 Error e: Error e;
|
Chris@81
|
69 esac,
|
Chris@49
|
70
|
Chris@49
|
71 windowedFramesOfFile parameters filename =
|
Chris@81
|
72 case af.open filename of
|
Chris@81
|
73 Stream s: Frames (windowedFrames parameters s);
|
Chris@81
|
74 Error e: Error e;
|
Chris@81
|
75 esac,
|
Chris@49
|
76
|
Chris@49
|
77 frequencyDomainFramesOfFile parameters filename =
|
Chris@81
|
78 case af.open filename of
|
Chris@81
|
79 Stream s: Frames (frequencyDomainFrames parameters s);
|
Chris@81
|
80 Error e: Error e;
|
Chris@81
|
81 esac,
|
Chris@11
|
82 }
|
Chris@8
|
83
|