LFGauss Gaussian function oscillator

LFGauss.ar(duration, width, iphase, loop, doneAction)

A non-band-limited gaussian function oscillator. Output ranges from minval to 1.

LFGauss implements the formula: f(x) = exp(squared(x - iphase) / (-2.0 * squared(width)))

where x is to vary in the range -1 to 1 over the period dur. minval is the initial value at -1

duration duration of one full cycle ( for freq input: dur = 1 / freq )

width relative width of the bell. Best to keep below 0.25 when used as envelope. (default: 0.1)

iphase initial offset (default: 0)

loop if loop is > 0, UGen oscillates. Otherwise it calls doneAction after one cycle (default: 1)

doneAction doneAction, which is evaluated after cycle completes (2 frees the synth, default: 0).

See UGen-doneActions for more detail.

Some plots:

s.boot ;

// a 0.1 second grain

{ LFGauss.ar(0.1, 0.12) }.plot(0.1);

// shifting left

{ LFGauss.ar(0.1, 0.12, -1, loop: 0) }.plot(0.1);

// moving further away from the center

{ LFGauss.ar(0.1, 0.12, 2) }.plot(0.2);

// several grains

{ LFGauss.ar(0.065, 0.12, 0, loop: 1) }.plot(0.3);

Some calculations:

assuming iphase = 0:

minval for a given width: minval = exp(-1.0 / (2.0 * squared(width)))

width for a given minval: width = sqrt(-1.0 / log(minval))

width at half maximum (0.5): (2 * sqrt(2 * log(2)) * width) = ca. 2.355 * width

// minval for a width of 0.1:

(exp(1 / (-2.0 * squared(0.1)))) // 2e-22

// maximum width for a beginning at -60dB:

// we want the beginning small enough to avoid clicks

sqrt(-1 / ( 2 * log(-60.dbamp))) // 0.269

// minval for width of 0.25

(exp(1 / (-2.0 * squared(0.25)))).ampdb // -70dB

// maximum is always 1:

{ LFGauss.ar(0.1, XLine.kr(1, 0.03, 1), 0, loop: 1) }.plot(1);

// a gauss curve in sclang:

(0..1000).normalize(-1, 1).collect(_.gaussCurve(1, 0, 0.1)).plot;

// rescale the function to the range 0..1

(

{

var width = XLine.kr(0.04, 1.0, 1);

var min = (exp(1.0 / (-2.0 * squared(width))));

var gauss = LFGauss.ar(0.1, width, loop: 1);

gauss.linlin(min, 1, 0, 1);

}.plot(1)

);

// range does the same implicitly

(

{

var width = XLine.kr(0.04, 1.0, 1);

LFGauss.ar(0.1, width, loop: 1).range(0, 1);

}.plot(1)

);

Sound examples:

// modulating duration

{ LFGauss.ar(XLine.kr(0.1, 0.001, 10), 0.03) * 0.2 }.play;

// modulating width, freq 60 Hz

{ LFGauss.ar(1/60, XLine.kr(0.1, 0.001, 10)) * 0.2 }.play;

// modulating both: x position is frequency, y is width factor.

// note the artefacts due to alisasing at high frequencies

{ LFGauss.ar(MouseX.kr(1/8000, 0.1, 1), MouseY.kr(0.001, 0.1, 1)) * 0.1 }.play;

// LFGauss as amplitude modulator

{ LFGauss.ar(MouseX.kr(1, 0.001, 1), 0.1) * SinOsc.ar(1000) * 0.1 }.play;

// modulate iphase

{ LFGauss.ar(0.001, 0.2, [0, MouseX.kr(-1, 1)]).sum * 0.2 }.scope;

// for very small width we are "approaching" a dirac function

{ LFGauss.ar(0.01, SampleDur.ir * MouseX.kr(10, 3000, 1)) * 0.2 }.play;

// dur and width can be modulated at audio rate

(

{ var dur = SinOsc.ar(MouseX.kr(2, 1000, 1) * [1, 1.1]).range(0.0006, 0.01);

var width = SinOsc.ar(0.5 * [1, 1.1]).range(0.01, 0.3);

LFGauss.ar(dur, width) * 0.2

}.play

);

// several frequecies and widths combined

(

{

var mod = LFGauss.ar(MouseX.kr(1, 0.07, 1), 1 * (MouseY.kr(1, 3) ** (-1..-6)));

var carr = SinOsc.ar(200 * (1.3 ** (0..5)));

(carr * mod).sum * 0.1

}.play;

)

// test spectrum

(

{

var son = LeakDC.ar(LFGauss.ar(0.005, 0.2));

BPF.ar(son * 3, MouseX.kr(60, 2000, 1), 0.05)

}.play;

)

Gabor Grain:

(

var freq = 1000;

var ncycles = 10;

var width = 0.25;

var dur = ncycles / freq;

{

var env = LFGauss.ar(dur, width, loop: 0, doneAction: 2);

var son = FSinOsc.ar(freq, 0.5pi, env);

son

}.plot(dur);

)

(

SynthDef(\gabor, { |out, i_freq = 440, i_sustain = 1, i_pan = 1, i_amp = 0.1, i_width = 0.25 |

var env = LFGauss.ar(i_sustain, i_width, loop: 0, doneAction: 2);

var son = FSinOsc.ar(i_freq, 0.5pi, env);

OffsetOut.ar(out, Pan2.ar(son, i_pan, i_amp));

}).add;

)

// modulating various parameters

(

Pdef(\x,

Pbind(

\instrument, \gabor,

\freq, Pbrown(step:0.01).linexp(0, 1, 100, 14000),

\dur, Pbrown().linexp(0, 1, 0.004, 0.02),

\legato, Pbrown(1, 3, 0.1, inf),

\pan, Pwhite() * Pbrown()

)

).play

)

// modulating width only

(

Pdef(\x,

Pbind(

\instrument, \gabor,

\freq, 1000,

\dur, 0.01,

\width, Pseg(Pseq([0.25, 0.002], inf), 10, \exp),

\legato, 2

)

).play

)

// compare with sine grain.

(

SynthDef(\gabor, { |out, i_freq = 440, i_sustain = 1, i_pan = 1, i_amp = 0.1, i_width=0.25 |

var env = EnvGen.ar(Env.sine(i_sustain * i_width), doneAction: 2);

var son = FSinOsc.ar(i_freq, 0.5pi, env);

OffsetOut.ar(out, Pan2.ar(son, i_pan, i_amp));

}).add;

)