Merge pull request #506 from andrewcsmith/patch-2
[supercollider.git] / SCClassLibrary / Common / Audio / FFTUnpacking.sc
blobbc96ceda23f251b620220653e8085ff72091121e
1 /**
2 "Unpack FFT" UGens (c) 2007 Dan Stowell.
3 Magical UGens for treating FFT data as demand-rate streams.
4 */
6 // Actually this just wraps up a bundle of Unpack1FFT UGens
7 UnpackFFT : MultiOutUGen {
8         *new { | chain, bufsize, frombin=0, tobin |
9                 var upperlimit = bufsize/2;
10                 tobin = if(tobin.isNil, upperlimit, {tobin.min(upperlimit)});
11                 ^[Unpack1FFT(chain, bufsize, (frombin..tobin), 0),
12                   Unpack1FFT(chain, bufsize, (frombin..tobin), 1)].flop.flatten;
13         }
16 Unpack1FFT : UGen {
17         *new { | chain, bufsize, binindex, whichmeasure=0 |
18                 //("bufsize:"+bufsize).postln;
19                 ^this.multiNew('demand', chain, bufsize, binindex, whichmeasure);
20         }
23 // This does the demanding, to push the data back into an FFT buffer.
24 PackFFT : PV_ChainUGen {
26         *new { | chain, bufsize, magsphases, frombin=0, tobin, zeroothers=0 |
27                 tobin = tobin ?? {bufsize/2};
28                 ^this.multiNewList(['control', chain, bufsize, frombin, tobin, zeroothers, magsphases.size] ++ magsphases.asArray)
29         }
33 // Conveniences to apply calculations to an FFT chain
34 PV_ChainUGen : WidthFirstUGen {
36         // Give it a func to apply to whole set of vals: func(mags, phases)
37         pvcalc { |numframes, func, frombin=0, tobin, zeroothers=0|
38                 var origmagsphases, magsphases, ret;
39                 origmagsphases = UnpackFFT(this, numframes, frombin, tobin).clump(2).flop;
40                 magsphases = func.value(origmagsphases[0], origmagsphases[1]);
41                 // Add phases back if they've been ignored
42                 magsphases = magsphases.size.switch(
43                         1, {magsphases ++ origmagsphases[1]},
44                         2, {magsphases},
45                         // any larger than 2 and we assume it's a list of magnitudes
46                            {[magsphases, origmagsphases[1]]}
47                         );
48                 magsphases = magsphases.flop.flatten;
49                 ^PackFFT(this, numframes, magsphases, frombin, tobin, zeroothers);
50         }
51         // The same but for two chains together
52         pvcalc2 { |chain2, numframes, func, frombin=0, tobin, zeroothers=0|
53                 var origmagsphases, origmagsphases2, magsphases, ret;
54                 origmagsphases  = UnpackFFT(this,   numframes, frombin, tobin).clump(2).flop;
55                 origmagsphases2 = UnpackFFT(chain2, numframes, frombin, tobin).clump(2).flop;
56                 magsphases = func.value(origmagsphases[0], origmagsphases[1], origmagsphases2[0], origmagsphases2[1]);
57                 // Add phases back if they've been ignored
58                 magsphases = magsphases.size.switch(
59                         1, {magsphases ++ origmagsphases[1]},
60                         2, {magsphases},
61                         // any larger than 2 and we assume it's a list of magnitudes
62                            {[magsphases, origmagsphases[1]]}
63                         );
64                 magsphases = magsphases.flop.flatten;
65                 ^PackFFT(this, numframes, magsphases, frombin, tobin, zeroothers);
66         }
68         // Give it a func to apply to each bin in turn: func(mag, phase, index)
69         pvcollect { |numframes, func, frombin=0, tobin, zeroothers=0|
70                 var magsphases, ret;
71                 magsphases = UnpackFFT(this, numframes, frombin, tobin).clump(2);
72                 magsphases = magsphases.collect({ |mp, index|
73                         ret = func.value(mp[0], mp[1], index + frombin, index).asArray;
74                         ret = if(ret.size==1, {ret ++ mp[1]}, ret); // Add phase if it's been ignored
75                 }).flatten;
76                 ^PackFFT(this, numframes, magsphases, frombin, tobin, zeroothers);
77         }