Reverse engineering Formant.ar using only Sine oscillators

Hello, just to have a better understanding of this Ugen, could someone put me on track here ? Thanks a lot.

Do you want to do this in a SynthDef with just SinOsc? Or … what do you mean by ‘on track?’

Yes, a SynthDef with SinOsc’s (do we need to use also a BPF ?).
I would like to understand the structural relation between fundfreq / formfreq / bwfreq…
Thanks !

Great - that helps. And yes, I’m guessing in the end you’ll need more that SinOscs (which makes the title of the topic a little confusing unless you want an example to get as close as you can). I don’t have an answer at the moment, but I’ll take a look later to see what I can suggest.

for creating formants you need two resonances. for example two RLPFs or two SinOscs:

(
{
	var lfo = MouseX.kr(1,0);
	var sig = SinOsc.ar(lfo.linexp(0, 1, 100, 500)) + SinOsc.ar(lfo.linexp(0, 1, 1000, 500));

	sig ! 2 * 0.1;
}.play;
)

s.freqscope;

EDIT: here are also two versions of windowed sync which is doing a kind of fake RLPF by shifting the formants:

1.)

(
SynthDef(\windowsync, {
	arg syncEgTop=8, syncRatio=2, syncDcy=0.5;

	var syncEnv = EnvGen.kr(Env([syncEgTop / syncRatio, 1], [syncDcy], \exp));
	var gainEnv = EnvGen.kr(Env.adsr(0.01, 0.3, 0.6, 0.1), \gate.kr(1), doneAction: Done.freeSelf);

	var freq = \freq.ar(440);
	var sig, in, phase, synced;
	
	in = LFTri.ar(freq);
	phase = Sweep.ar(in, freq * syncRatio * syncEnv);
	synced = SinOsc.ar(0, (phase % 1) * 2pi).squared;
	
	sig = synced * in;

	sig = sig * gainEnv;

	sig = Pan2.ar(sig, \pan.kr(0), \amp.kr(0.25));
	Out.ar(\out.kr(0), sig);
}).add;
)

(instrument: \windowsync, freq: [57,60,64,65,70].midicps, syncEgTop: 20).play;

2.)

(
SynthDef(\windowsync, {
	arg freq=440, syncRatio=2, syncEgTop=20, syncDcy=0.5, overlap=1;
	var sig, fundamental, synced;

	var freqEnv = EnvGen.kr(Env([syncEgTop / syncRatio, 1], [syncDcy], \exp));
	var gainEnv = EnvGen.kr(Env.adsr(0.01, 0.3, 0.6, 0.1), \gate.kr(1), doneAction: Done.freeSelf);

	fundamental = GrainSin.ar(
		numChannels: 1,
		trigger: Impulse.ar(freq),
		dur: 1 / freq,
		freq: freq,
	);

	synced = GrainSin.ar(
		numChannels: 1,
		trigger: fundamental,
		dur: overlap / freq,
		freq: freq * syncRatio * freqEnv,
	);

	sig = synced.squared * fundamental;
	sig = LeakDC.ar(sig);

	sig = sig * gainEnv;

	sig = Pan2.ar(sig, \pan.kr(0), \amp.kr(0.25));
	Out.ar(\out.kr(0), sig);
}).add;
)

(instrument: \windowsync, freq: [57,60,64,65,70].midicps, syncEgTop: 20).play;

and a vector phase shaping pseudo Ugen ive been working on some time ago. whichs produces formants for bigger vertical values:

(
var nearestEven, nearestOdd, vps;

nearestEven = {
	arg val;
	var val_floor, val_ceil, res, distance;
	val_floor = val.floor;
	val_ceil = val.ceil;
	res = Select.ar(val % 2,
		[ val_floor, val_ceil ],
	);
	distance = (val - res).abs;
	[ res, distance ];
};

nearestOdd = {
	arg val;
	var val_floor, val_ceil, res, distance;
	val_floor = val.floor;
	val_ceil = val.ceil;
	res = Select.ar(val + 1 % 2,
		[ val_floor, val_ceil ],
	);
	distance = (val - res).abs;
	[ res, distance ];
};

vps = { |trig, freq, horizontal, vertical|
	var vertical_even = nearestEven.(vertical);
	var vertical_odd = nearestOdd.(vertical);
	var cos, phasor, sig;
	vertical = [vertical_even[0], vertical_odd[0]];
	phasor = Phasor.ar(Impulse.ar(trig), freq/2 * SampleDur.ir, horizontal.neg, 1-horizontal, horizontal.neg);
	phasor = phasor.bilin(0, horizontal.neg, 1-horizontal, vertical, 0, 1);
	cos = (phasor * 2pi).cos.neg;
	sig = XFade2.ar(cos[0], cos[1], vertical_even[1] * 2 - 1);
	sig = LeakDC.ar(sig);
	sig;
};

{
	var freq = \freq.kr(110);
	var horizontal = MouseX.kr(0.01,0.99);
	var vertical = K2A.ar(MouseY.kr(1.0,10.0));
	var sig = vps.(0, freq,  horizontal, vertical);
	sig!2 * 0.1;
}.play(fadeTime: 0);
)
1 Like

Great examples, the vector phase is wonderfull, thanks a lot @ dietcv !

Hi there -
I just came across this post - I am also interested in how the Formant uGen works and trying to better understand the use of formants in electronic sound also.

@dietcv’s examples suggest several different approaches and I’d like to get a better understanding about the concepts behind them.

To start with, is a formant, by definition, any two resonances? Can it be three, four, five? Is there anything particular about the ratio between the two resonances?

With the Formant.ar uGen, obviously there is something else going on. Presumably, there is a fundamental tone, a formant frequency (which in this scenario is just a second frequency?), and then a pulse-width frequency. I’m unclear about exactly is being done and why.

Also, what is “windowed sync” exactly? Both of the examples sound great - but I don’t understand the intent of the approach. Is this related to ideas of formant synthesis?
Thanks!

@alikthename made awesome videos about synthesis (and SuperCollider) a couple years ago : https://www.youtube.com/playlist?list=PLXCUkMwOEWQtB-leHHSexTizzcACdozp9 . Sadly, I can see some of them are now missing :confused: .

Anyway, he’s talking about formants in, I think, the third one, which is called ’ 3: Pulsar synthesis with GrainFM - Musical Sound Design In Supercollider’ . I don’t know if this exactly what we’re talking about here, but I think this might help anyone interested in frequencies relations inside a sound.