SuperCollider CLASSES (extension)

NL
ExtensionExtension

Non Linear Filter Equation
Inherits from: UGen : AbstractFunction : Object

//SLUGens released under the GNU GPL as extensions for SuperCollider 3, by Nick Collins, http://composerprogrammer.com/index.html 

Description

Represents the arbitrary non-linear filter difference equation in the time domain:

y(n) = b00x(n)^b01 + b10x(n-1)^b11 + ... + b(Nb0)x(n-Nb0)^Nb1 + a00y(n-1)^a01 + ... + a(Na0)y(n-Na0)^Na1

Though no cross-terms combining powers of x and y are allowed.

Stability is definitely not guaranteed; most equations will quickly blow-up. See the guard arguments below. It is recommended that you stick to positive exponents for signals which are within -1 to 1, else explosion of values is inevitable.

(0.1)**(-1.26) //negative exponents cause blowup for smaller signals abs(sig) < 1.0

(1.1)**(2.26) //positive exponents cause blowup for larger signals abs(sig) > 1.0

You need to pass in the parameters via two buffers, of arbitrary size.

Class Methods

*ar (input, bufnuma: 0, bufnumb: 1, guard1: 1000, guard2: 100, mul: 1, add: 0)

Arguments:

input

What do you want to filter?

bufnuma

Feedback filter coefficients, from previous outputs, in triples of (index,coefficient, exponent) from lowest to highest index

bufnumb

Feedforward filter coefficients, from previous inputs, in pairs of (index,coefficient, exponent) from lowest to highest index

guard1

Watch out for blow-up and reset if necessary; this is the value of the maximum absolute output allowed.

guard2

Watch out for blow-up and reset if necessary; this is the value of the maximum absolute change of output allowed.

On discovering blow-up, filter output is set back to zero for the last Na stored outputs, so that feedback cannot occur.

This UGen can be expensive to run because of the power operations that have to be carried out to calculate each new sample. You can only change the filter equations on the fly where you change multiplier coefficients and exponents; indices are set at initialisation however.

Inherited class methods

Instance Methods

Inherited instance methods

Examples

(
a=[0,0.02,1,3,-0.01,0.5]; //feedback coefficients
b=[0,0.3,1, 1,-0.3,2, 2,0.1,0.4]; //feedforward coefficients
c=Buffer.sendCollection(s, a, 1);
d=Buffer.sendCollection(s, b, 1);
)

{SinOsc.ar(MouseX.kr(440,1760),0,0.2)}.play //without

{NL.ar(SinOsc.ar(MouseX.kr(440,1760),0,0.5),c.bufnum, d.bufnum).clip2(1.0)}.play //with



(
a=[0,0.02,1, 1,-0.02,0.3]; //feedback coefficients
b=[0,0.5,1, 3,-0.2,4, 7,0.2,0.26]; //feedforward coefficients
c=Buffer.sendCollection(s, a, 1);
d=Buffer.sendCollection(s, b, 1);
)


//you can hear the nonlinearities (extra tones in the signal)
{RLPF.ar(NL.ar(Saw.ar(MouseX.kr(440,1760),0.5),c.bufnum, d.bufnum, 1.0),1000,0.1)}.play



//random buffers; this code may lead to repeated indices, but shouldn't affect the result (will just add to sum)
(
a=Array.fill(10,{[rrand(0,50),0.2.rand2, rrand(0.1,2.1)]}).sort({|a,b| a[0] < b[0]}).flatten; //feedback coefficients
b=Array.fill(10,{[rrand(1,50),0.2.rand2, rrand(0.1,2.1)]}).sort({|a,b| a[0] < b[0]}).flatten; //feedforward coefficients
b=[0,1,1]++b;
c=Buffer.sendCollection(s, a, 1);
d=Buffer.sendCollection(s, b, 1);
)


{LPF.ar(NL.ar(Saw.ar(MouseX.kr(440,1760),MouseY.kr(0.0,1.0)),c.bufnum, d.bufnum), 1000)}.play


//check impulse response
{NL.ar(Impulse.ar(1),c.bufnum, d.bufnum)}.plot(1024/(s.sampleRate))




//Take advantage of sparsity of array to have larger spaced coefficients; causes rhythmic blowups sometimes! 
//random buffers; this code may lead to repeated indices, but shouldn't affect the result (will just add to sum)
(
a=Array.fill(10,{[rrand(0,5000),0.7.rand2, exprand(0.1,6.1)]}).sort({|a,b| a[0] < b[0]}).flatten; //feedback coefficients
b=Array.fill(5,{[rrand(1,500),0.2.rand2, exprand(0.1,6.1)]}).sort({|a,b| a[0] < b[0]}).flatten; //feedforward coefficients
b=[0,1,1]++b;
c=Buffer.sendCollection(s, a, 1);
d=Buffer.sendCollection(s, b, 1);
)


{Pan2.ar(LPF.ar((NL.ar(AudioIn.ar,c.bufnum, d.bufnum,10000, 1000)*0.1).clip2(1.0), MouseX.kr(100,10000,'exponential')),LFNoise2.kr(0.5))}.play



(
//limited update
r= {
inf.do{
e= a.copy; 
f=b.copy; 

10.do{|i| e[3*i+1]=0.7.rand2;  e[3*i+2]=exprand(0.1,6.1);  }; 
6.do{|i| f[3*i+1]=0.2.rand2;  f[3*i+2]=exprand(0.1,6.1);  }; 

c.sendCollection(e);
d.sendCollection(f);

1.0.wait;
}
}.fork; 
)

r.stop;