Warped gaussian window

hey granular people, once i have posted a version of a warpable tukey window and here is a kind of follow up, a warpable gaussian window.

(
var transferFunc = { |phase, skew|
	phase = phase.linlin(0, 1, skew.neg, 1 - skew);
	phase.bilin(0, skew.neg, 1 - skew, 0.5, 0, 1);
};

var gaussian = { |phase, index|
	var cosine = cos(phase * pi) * index;
	exp(cosine.neg * cosine);
};

var hanning = { |phase|
	1 - cos(phase * 2pi) / 2;
};

var gaussWarped = { |phase, index, skew|
	var warpedPhase = transferFunc.(phase, skew);
	var gauss = gaussian.(warpedPhase, index);
	var hann = hanning.(warpedPhase);
	gauss * hann;
};

{
	var phase = Phasor.ar(0, 50 * SampleDur.ir);
	gaussWarped.(phase, \index.kr(0), \skew.kr(0.5));
}.plot(0.02);
)

If you set the waveshaping index to 0 it collapes to a hanning window.

grafik

if you set the waveshaping index higher you can get a quite narrow pulse:
grafik

which can be skewed to the left for percussive shapes:
grafik
or the right for reversed percussive shapes:
grafik

It is a stateless window function, you can modulate index and skew with lfos.

enjoy :slight_smile:

3 Likes

Nice! Looking forward to trying this

Here is the warped tukey window once again (I guess the code for the tukey window could be optimized when you drive it with a triangle from 0 to 1 to 0 instead of a ramp from 0 to 1):

(
var transferFunc = { |phase, skew|
	phase = phase.linlin(0, 1, skew.neg, 1 - skew);
	phase.bilin(0, skew.neg, 1 - skew, 0.5, 0, 1);
};

var tukeyWindow = { |phase, width|
	var segmentLength = 0.5 * width;
	var x = 0.5 * (1 - cos(phase * 2pi / width));
	var y = 0.5 * (1 - cos((phase - 1) * 2pi / width));
	var w1 = x * (phase < segmentLength);
	var w2 = (1 - w1) * (phase >= segmentLength) * (phase <= (1 - segmentLength));
	var w3 = y * (phase > (1 - segmentLength));
	w1 + w2 + w3;
};

var tukeyWarped = { |phase, width, skew|
	var warpedPhase = transferFunc.(phase, skew);
	tukeyWindow.(warpedPhase, width);
};

{
	var phase = Phasor.ar(0, 50 * SampleDur.ir);
	tukeyWarped.(phase, \width.kr(1), \skew.kr(0.5));
}.plot(0.02);
)

hanning window for width = 1 and skew = 0.5:
grafik

width at 0.5:
grafik

additional skew for sustained percussive shapes:
grafik
or reverse sustained percussive shapes:
grafik

3 Likes

and here is yet another window with an adjustable curve:

(
var transferFunc = { |phase, skew, shape|
	phase = phase.linlin(0, 1, skew.neg, 1 - skew);
	phase.bilin(0, skew.neg, 1 - skew, 1, 0, 0);
};

var curvedSegments = { |phase, skew, curve|
	var warpedPhase = transferFunc.(phase, skew);
	warpedPhase.lincurve(0, 1, 0, 1, curve);
};

{
	var phase = Phasor.ar(0, 50 * SampleDur.ir);
	curvedSegments.(phase, \skew.kr(0.05), \curve.kr(2.0));
}.plot(0.02);
)

grafik
grafik
grafik

4 Likes

I have reworked all the three windows, now they all have the same interface and added a 4th one.
Because the windows are symmetric, you only have to calculate one side and can drive them with a triangle instead of a ramp to mirror them. The transfer function can skew the triangle to the left and the right.

warped gaussian window

(
var transferFunc = { |phase, skew|
	phase = phase.linlin(0, 1, skew.neg, 1 - skew);
	phase.bilin(0, skew.neg, 1 - skew, 1, 0, 0);
};

var unitGauss = { |phase, index|
	var cosine = cos(phase * 0.5pi) * index;
	exp(cosine.neg * cosine);
};

var unitHann = { |phase|
	1 - cos(phase * pi) / 2;
};

var gaussWindow = { |phase, skew, index|
	var warpedPhase = transferFunc.(phase, skew);
	var gauss = unitGauss.(warpedPhase, index);
	var hann = unitHann.(warpedPhase);
	gauss * hann;
};

{
	var phase = Phasor.ar(0, 50 * SampleDur.ir);
	gaussWindow.(phase, \skew.kr(0.5), \index.kr(5));
}.plot(0.02);
)

warped tukey window

(
var transferFunc = { |phase, skew|
	phase = phase.linlin(0, 1, skew.neg, 1 - skew);
	phase.bilin(0, skew.neg, 1 - skew, 1, 0, 0);
};

var unitTukey = { |phase, width|
	var sustain = 1 - width;
	var cosine = 1 - cos(phase * pi / sustain) / 2;
	Select.ar(phase < sustain, [K2A.ar(1), cosine]);
};

var tukeyWindow = { |phase, skew, width|
	var warpedPhase = transferFunc.(phase, skew);
	unitTukey.(warpedPhase, width);
};

{
	var phase = Phasor.ar(0, 50 * SampleDur.ir);
	tukeyWindow.(phase, \skew.kr(0.5), \width.kr(0.5));
}.plot(0.02);
)

warped curved segments

(
var transferFunc = { |phase, skew, shape|
	phase = phase.linlin(0, 1, skew.neg, 1 - skew);
	phase.bilin(0, skew.neg, 1 - skew, 1, 0, 0);
};

var curvedSegments = { |phase, skew, curve|
	var warpedPhase = transferFunc.(phase, skew);
	warpedPhase.lincurve(0, 1, 0, 1, curve);
};

{
	var phase = Phasor.ar(0, 50 * SampleDur.ir);
	curvedSegments.(phase, \skew.kr(0.5), \curve.kr(2.0));
}.plot(0.02);
)

warped and raised tukey window
a combination of the tukey and the gauss window

(
var transferFunc = { |phase, skew|
	phase = phase.linlin(0, 1, skew.neg, 1 - skew);
	phase.bilin(0, skew.neg, 1 - skew, 1, 0, 0);
};

var unitTukeyGauss = { |phase, width, index|
	var sustain = 1 - width;
	var cosine = cos(phase * 0.5pi / sustain) * index;
	var gaussian = exp(cosine * cosine.neg);
	var hanning = 1 - cos(phase * pi / sustain) / 2;
	Select.ar(phase < sustain, [K2A.ar(1), gaussian * hanning]);
};

var tukeyGaussWindow = { |phase, skew, width, index|
	var warpedPhase = transferFunc.(phase, skew);
	unitTukeyGauss.(warpedPhase, width, index);
};

{
	var phase = Phasor.ar(0, 50 * SampleDur.ir);
	tukeyGaussWindow.(phase, \skew.kr(0.5), \width.kr(0), \index.kr(10));
}.plot(0.02);
)
4 Likes