GlitchFree Vowel synthesis - with Soprano/tenor etc Formant tables

to demistify the two approaches:

The two windows i have been using for either of the approaches are nearly identical in behaviour and have one common feature, they collapse to 1 if the index is 0.

(
var raisedCos = { |phase, index|
	var cosine = cos(phase * 2pi);
	exp(index.abs * (cosine - 1));
};

var gaussianWindow = { |phase, index|
	var halfCosCycle = sin(phase * pi) * index;
	exp(halfCosCycle.neg * halfCosCycle);
};

{
	var index = 2;
	var rate = 100;
	var phase = Phasor.ar(DC.ar(0), rate * SampleDur.ir);
	var sigA = raisedCos.(phase, index);
	var sigB = gaussianWindow.(phase, index);

	[sigA * cos(phase * 2pi), sigB * cos(phase * 2pi)];
}.plot(0.02);
)

grafik

with the mod FM you have control over the bandwidth via the index and the harmonics independently, but the spectrum is always harmonic:

(
var crossfade_formants = { |phase, harm|
	var harm_even = harm.round(2);
	var harm_odd = ((harm + 1).round(2) - 1);
	var sig_even = cos(phase * 2pi * harm_even);
	var sig_odd = cos(phase * 2pi * harm_odd);
	XFade2.ar(sig_even, sig_odd, harm.fold(0, 1) * 2 - 1);
};

var raisedCos = { |phase, index|
	var cosine = cos(phase * 2pi);
	exp(index.abs * (cosine - 1));
};

{
	var freq, phase, harmonic, index, gaussWindow, formants, sig;

	freq = \freq.kr(440);
	phase = Phasor.ar(DC.ar(0), freq * SampleDur.ir);

	harmonic = MouseX.kr(1, 10);
	index = MouseY.kr(0, 10);
	
	gaussWindow = raisedCos.(phase, index);
	formants = crossfade_formants.(phase, harmonic);

	sig = formants * gaussWindow;
	
	sig = LeakDC.ar(sig);

	sig!2 * 0.1;
	
}.play;
)

with the single sideband PM approach the bandwidth and the harmonics are controlled both via the index, but you can additionally create inharmonic sounds by adjusting the modRatio:

(
var raisedCos = { |phase, index|
	var cosine = cos(phase * 2pi);
	exp(index.abs * (cosine - 1));
};

{
	var carrFreq, modFreq, carrPhase, modPhase, index;
	var gaussWindow, mod, carr, sig;

	carrFreq = \freq.kr(440);
	modFreq = carrFreq * MouseY.kr(1, 2);

	carrPhase = Phasor.ar(DC.ar(0), carrFreq * SampleDur.ir);
	modPhase = Phasor.ar(DC.ar(0), modFreq * SampleDur.ir);

	index = MouseX.kr(0, 30);
	
	gaussWindow = raisedCos.(modPhase, index);
	mod = sin(modPhase * 2pi);
	carr = sin(carrPhase * 2pi + (mod * index));

	sig = carr * gaussWindow;

	sig = LeakDC.ar(sig);

	sig!2 * 0.1;
	
}.play;
)

you decide what suits your needs!

1 Like