deprecate SCViewHolder-layRight
[supercollider.git] / SCClassLibrary / Common / Math / Signal.sc
blob18663b0556e39838f9bfd10de1156b84730fd4f5
1 Signal[float] : FloatArray {
3         *sineFill { arg size, amplitudes, phases;
4                 ^Signal.newClear(size).sineFill(amplitudes, phases).normalize
5         }
6         *chebyFill { arg size, amplitudes, normalize=true;
7                 ^Signal.newClear(size).chebyFill(amplitudes, normalize); //.normalizeTransfer //shouldn't normalize by default!
8         }
9         *hammingWindow { arg size, pad=0;
10                 if (pad == 0, {
11                         ^this.newClear(size).fill(0.5).addSine(1, 0.39, -0.5pi);
12                 },{
13                         ^this.newClear(size-pad).fill(0.5).addSine(1, 0.39, -0.5pi) ++ this.newClear(pad);
14                 });
15         }
16         *hanningWindow { arg size, pad=0;
17                 if (pad == 0, {
18                         ^this.newClear(size).fill(0.5).addSine(1, 0.5, -0.5pi);
19                 },{
20                         ^this.newClear(size-pad).fill(0.5).addSine(1, 0.5, -0.5pi) ++ this.newClear(pad);
21                 });
22         }
23         *welchWindow { arg size, pad=0;
24                 if (pad == 0, {
25                         ^this.newClear(size).addSine(0.5, 1, 0);
26                 },{
27                         ^this.newClear(size-pad).addSine(0.5, 1, 0) ++ this.newClear(pad);
28                 });
29         }
30         *rectWindow { arg size, pad=0;
31                 if (pad == 0, {
32                         ^this.newClear(size).fill(1.0);
33                 },{
34                         ^this.newClear(size-pad).fill(1.0) ++ this.newClear(pad);
35                 });
36         }
37         *readNew { arg file;
38                 ^file.readAllSignal;
39         }
41         // operations
42         fill { arg val; _SignalFill ^this.primitiveFailed }
43         scale { arg scale; _SignalScale ^this.primitiveFailed }
44         offset { arg offset; _SignalOffset ^this.primitiveFailed }
46         asWavetable {
47                 // Interpolating oscillators require wavetables in a special format.
48                 // This method returns a wavetable in that format.
49                 _SignalAsWavetable;
50                 ^this.primitiveFailed
51         }
53         asWavetableNoWrap {
54                 // Shaper requires wavetables without wrap.
55                 // This method returns a wavetable in that format.
56                 //To generate size N wavetable need N/2+1 signal values rather than N/2
57                 //because Buffer's add_wchebyshev calculates N/2+1 values whilst
58                 //Signal's _SignalAddChebyshev calculates N/2!
60                 var newsig = Signal.newClear((this.size-1)*2);
61                 var next, cur;
63                 cur= this[0];
64                 (this.size-1).do{|i|
65                 var index= 2*i;
66                 next= this[i+1];
68                 newsig[index]= 2*cur -next;
69                 newsig[index+1]= next-cur;
70                 cur=next;
72                 };
74                 ^newsig
75         }
77         peak { _SignalPeak; ^this.primitiveFailed }
79         normalize { arg beginSamp=0, endSamp;
80                 _SignalNormalize;
81                 ^this.primitiveFailed
82         }
83         normalizeTransfer {
84                 _SignalNormalizeTransferFn;
85                 ^this.primitiveFailed
86         }
88         invert { arg beginSamp=0, endSamp;
89                 _SignalInvert;
90                 ^this.primitiveFailed
91         }
92         reverse { arg beginSamp=0, endSamp;
93                 _SignalReverse;
94                 ^this.primitiveFailed
95         }
96         fade { arg beginSamp=0, endSamp, beginLevel=0.0, endLevel=1.0;
97                 _SignalFade;
98                 ^this.primitiveFailed
99         }
100         rotate { arg n=1;
101                 _SignalRotate
102                 ^this.primitiveFailed
103         }
105         zeroPad { arg minSize;
106                 var size = max(minSize ? 0, this.size).nextPowerOfTwo;
107                 ^this ++ Signal.newClear(size - this.size);
108         }
110         integral { _SignalIntegral; ^this.primitiveFailed }
111         overDub { arg aSignal, index=0;
112                 _SignalOverDub
113                 // add a signal to myself starting at the index
114                 // if the other signal is too long only the first part is overdubbed
115                 ^this.primitiveFailed
116         }
117         overWrite { arg aSignal, index=0;
118                 _SignalOverWrite
119                 // write a signal to myself starting at the index
120                 // if the other signal is too long only the first part is overwritten
121                 ^this.primitiveFailed
122         }
124         play { arg loop=false, mul=0.2, numChannels=1, server;
125                 var buf;
126                 buf = Buffer.alloc(server ? Server.default, this.size, numChannels);
127                 buf.sendCollection(this, 0, 0.1, { buf.play(loop, mul); });
128                 ^buf
129         }
131         waveFill { arg function, start = 0.0, end = 1.0;
132                 var i = 0, step, size, val, x;
134                 // evaluate a function for every sample over the interval from
135                 // start to end.
136                 size = this.size;
137                 if (size <= 0, { ^this });
139                 x = start;
140                 step = (end - start) / size;
141                 while ({ i < size }, {
142                         val = function.value(x, this.at(i), i);
143                         this.put(i, val);
144                         x = x + step;
145                         i = i + 1;
146                 });
147                 ^this
148         }
149         addSine { arg harmonicNumber = 1, amplitude = 1.0, phase = 0.0;
150                 _SignalAddHarmonic
151                 ^this.primitiveFailed
152         }
153         sineFill { arg amplitudes, phases;
154                 this.fill(0.0);
155                 if (phases.isNil, { phases = #[0]; });
156                 amplitudes.do({ arg amp, i; this.addSine(i+1, amp, phases @@ i) });
157         }
158         sineFill2 { arg list;
159                 this.fill(0.0);
160                 list.do({ arg item, i;
161                         var harm, amp, phase;
162                         # harm, amp, phase = item;
163                         this.addSine(harm, amp ? 1.0, phase ? 0.0);
164                 });
165         }
167         addChebyshev { arg harmonicNumber = 1, amplitude = 1.0;
168                 _SignalAddChebyshev
169                 ^this.primitiveFailed
170         }
171         chebyFill { arg amplitudes, normalize=true;
172                 this.fill(0.0);
173                 amplitudes.do({ arg amp, i; this.addChebyshev(i+1, amp); if(i%4==1,{this.offset(1)}); if(i%4==3,{this.offset(-1)}); }); //corrections for JMC DC offsets, as per Buffer:cheby
175                 if(normalize,{this.normalizeTransfer}); //no automatic cheby
176         }
178         //old version
179         chebyFill_old { arg amplitudes;
180                 this.fill(0.0);
181                 amplitudes.do({ arg amp, i; this.addChebyshev(i+1, amp) });
182                 this.normalizeTransfer
183         }
186         *fftCosTable { arg fftsize;
187                 ^this.newClear((fftsize/4) + 1).fftCosTable
188         }
189         fftCosTable {
190                 var harm;
191                 harm = this.size / ((this.size - 1) * 4);
192                 this.addSine(harm, 1, 0.5pi);
193         }
195         fft { arg imag, cosTable;
196                 // argCosTable must contain 1/4 cycle of a cosine (use fftCosTable)
197                 // fftsize is the next greater power of two than the receiver's length
198                 _Signal_FFT
199                 ^this.primitiveFailed
200         }
201         ifft { arg imag, cosTable;
202                 // argCosTable must contain 1/4 cycle of a cosine (use fftCosTable)
203                 // fftsize is the next greater power of two than the receiver's length
204                 _Signal_IFFT
205                 ^this.primitiveFailed
206         }
208         neg { _Neg; ^this.primitiveFailed }
209         abs { _Abs; ^this.primitiveFailed }
210         sign { _Sign; ^this.primitiveFailed }
211         squared { _Squared; ^this.primitiveFailed }
212         cubed { _Cubed; ^this.primitiveFailed }
213         sqrt { _Sqrt; ^this.primitiveFailed }
214         exp { _Exp; ^this.primitiveFailed }
215         //reciprocal { _Recip; ^this.primitiveFailed }
216         //midicps { _MIDICPS; ^this.primitiveFailed }
217         //cpsmidi { _CPSMIDI; ^this.primitiveFailed }
218         //midiratio { _MIDIRatio; ^this.primitiveFailed }
219         //ratiomidi { _RatioMIDI; ^this.primitiveFailed }
220         //ampdb { _AmpDb; ^this.primitiveFailed }
221         //dbamp { _DbAmp; ^this.primitiveFailed }
222         //octcps { _OctCPS; ^this.primitiveFailed }
223         //cpsoct { _CPSOct; ^this.primitiveFailed }
224         log { _Log; ^this.primitiveFailed }
225         log2 { _Log2; ^this.primitiveFailed }
226         log10 { _Log10; ^this.primitiveFailed }
227         sin { _Sin; ^this.primitiveFailed }
228         cos { _Cos; ^this.primitiveFailed }
229         tan { _Tan; ^this.primitiveFailed }
230         asin { _ArcSin; ^this.primitiveFailed }
231         acos { _ArcCos; ^this.primitiveFailed }
232         atan { _ArcTan; ^this.primitiveFailed }
233         sinh { _SinH; ^this.primitiveFailed }
234         cosh { _CosH; ^this.primitiveFailed }
235         tanh { _TanH; ^this.primitiveFailed }
236         distort { _Distort; ^this.primitiveFailed }
237         softclip { _SoftClip; ^this.primitiveFailed }
239         rectWindow { _RectWindow; ^this.primitiveFailed }
240         hanWindow { _HanWindow; ^this.primitiveFailed }
241         welWindow { _WelchWindow; ^this.primitiveFailed }
242         triWindow { _TriWindow; ^this.primitiveFailed }
244         scurve { _SCurve; ^this.primitiveFailed }
245         ramp { _Ramp; ^this.primitiveFailed }
247         + { arg aNumber; _Add; ^aNumber.performBinaryOpOnSignal('+', this) }
248         - { arg aNumber; _Sub; ^aNumber.performBinaryOpOnSignal('-', this) }
249         * { arg aNumber; _Mul; ^aNumber.performBinaryOpOnSignal('*', this) }
250         / { arg aNumber; _FDiv; ^aNumber.performBinaryOpOnSignal('/', this) }
251         mod { arg aNumber; _Mod; ^aNumber.performBinaryOpOnSignal('mod', this) }
252         div { arg aNumber; _IDiv; ^aNumber.performBinaryOpOnSignal('div', this) }
253         pow { arg aNumber; _Pow; ^aNumber.performBinaryOpOnSignal('pow', this) }
254         min { arg aNumber; _Min; ^aNumber.performBinaryOpOnSignal('min', this) }
255         max { arg aNumber; _Max; ^aNumber.performBinaryOpOnSignal('max', this) }
256         ring1 { arg aNumber; _Ring1; ^aNumber.performBinaryOpOnSignal('ring1', this) }
257         ring2 { arg aNumber; _Ring2; ^aNumber.performBinaryOpOnSignal('ring2', this) }
258         ring3 { arg aNumber; _Ring3; ^aNumber.performBinaryOpOnSignal('ring3', this) }
259         ring4 { arg aNumber; _Ring4; ^aNumber.performBinaryOpOnSignal('ring4', this) }
260         difsqr { arg aNumber; _DifSqr; ^aNumber.performBinaryOpOnSignal('difsqr', this) }
261         sumsqr { arg aNumber; _SumSqr; ^aNumber.performBinaryOpOnSignal('sumsqr', this) }
262         sqrsum { arg aNumber; _SqrSum; ^aNumber.performBinaryOpOnSignal('sqrsum', this) }
263         sqrdif { arg aNumber; _SqrDif; ^aNumber.performBinaryOpOnSignal('sqrdif', this) }
264         absdif { arg aNumber; _AbsDif; ^aNumber.performBinaryOpOnSignal('absdif', this) }
265         thresh { arg aNumber; _Thresh; ^aNumber.performBinaryOpOnSignal('thresh', this) }
266         amclip { arg aNumber; _AMClip; ^aNumber.performBinaryOpOnSignal('amclip', this) }
267         scaleneg { arg aNumber; _ScaleNeg; ^aNumber.performBinaryOpOnSignal('scaleneg', this) }
268         clip2 { arg aNumber=1; _Clip2; ^aNumber.performBinaryOpOnSignal('clip2', this) }
269         fold2 { arg aNumber; _Fold2; ^aNumber.performBinaryOpOnSignal('fold2', this) }
270         wrap2 { arg aNumber; _Wrap2; ^aNumber.performBinaryOpOnSignal('wrap2', this) }
271         excess { arg aNumber; _Excess; ^aNumber.performBinaryOpOnSignal('excess', this) }
272         firstArg { arg aNumber; _FirstArg; ^aNumber.performBinaryOpOnSignal('firstArg', this) }
274         == { arg aNumber; _EQ; ^aNumber.performBinaryOpOnSignal('==', this) }
275         != { arg aNumber; _NE; ^aNumber.performBinaryOpOnSignal('!=', this) }
277         clip { arg lo, hi; _ClipSignal; ^this.primitiveFailed }
278         wrap { arg lo, hi; _WrapSignal; ^this.primitiveFailed }
279         fold { arg lo, hi; _FoldSignal; ^this.primitiveFailed }
281         asInteger { _AsInt; ^this.primitiveFailed }
282         asFloat { _AsFloat; ^this.primitiveFailed }
283         asComplex { ^Complex.new(this, 0.0) }
284         asSignal { ^this }
286         // complex support
287         real { ^this }
288         imag { ^0.0 }
290         //PRIVATE:
291         performBinaryOpOnSignal { arg aSelector, aNumber; ^error("Math operation failed.\n") }
292         performBinaryOpOnComplex { arg aSelector, aComplex; ^aComplex.perform(aSelector, this.asComplex) }
293         performBinaryOpOnSimpleNumber { arg aSelector, aSimpleNumber; ^aSimpleNumber.perform(aSelector, this) }
296 Wavetable[float] : FloatArray {
297         // the only way to make a Wavetable is by Signal::asWavetable
298         *new {
299                 ^this.shouldNotImplement(thisMethod)
300         }
301         *newClear {
302                 ^this.shouldNotImplement(thisMethod)
303         }
305         *sineFill { arg size, amplitudes, phases;
306                 ^Signal.sineFill(size, amplitudes, phases).asWavetable
307         }
309         //size must be N/2+1 for N power of two; N is eventual size of wavetable
310         *chebyFill { arg size, amplitudes, normalize=true;
312                 ^Signal.chebyFill(size, amplitudes, normalize).asWavetableNoWrap; //asWavetable causes wrap here, problem
313         }
315         *chebyFill_old { arg size, amplitudes;
317                 //this.deprecated(thisMethod, Buffer.findRespondingMethodFor(\cheby));
319                 ^Signal.chebyFill(size, amplitudes).asWavetable; //asWavetable causes wrap here, problem
320         }
322         asSignal {
323                 _WavetableAsSignal
324                 ^this.primitiveFailed
325         }
327         blend { arg anotherWavetable, blendFrac=0.5;
328                 ^this.asSignal.blend(anotherWavetable.asSignal, blendFrac).asWavetable;
329         }
331         *readNew { arg file;
332                 ^file.readAllSignal.asWavetable;
333         }
334         write { arg path;
335                 var file;
336                 file = File.new(path, "wb");
337                 if (file.notNil, {
338                         file.write(this.asSignal);
339                         file.close;
340                 });
341         }
342         //libMenuAction { arg names;
343         //      this.plot(names.last);
344         //}