Glitch free vowel synthesis test


#1

an initial test of the vocal synthesis instrument I am building using ideas from Frequency Modulation Synthesis of the Singing Voice (Chowning 1989), and Glitch Free FM Vocal Synthesis (Chafe 2013).

also trying out some UI and compositional ideas with the monome grid.


#2

WOW ! Which quark are you using for the FM approach ?


#3

no quarks, just a couple of custom classes to help drive the core of it:

Nearest_Even {
	*ar {
		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 ];
	}
}

Nearest_Odd {
	*ar {
		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 ];
	}
}

Crossfade_Formant {
	*ar {
		arg phasor = 0, phase_mod = 0, harm = 1, pm_index = 1, amp = 1; // lag = 0;
		var harm_even, harm_odd, sig_even, sig_odd, sig, phase;

		phase = phase_mod * pm_index;

		harm_even = Nearest_Even.ar (harm);
		sig_even = cos (phasor * 2pi * harm_even[0] + phase);

		harm_odd = Nearest_Odd.ar (harm);
		sig_odd = cos (phasor * 2pi * harm_odd[0] + phase);

		sig = XFade2.ar (sig_even, sig_odd, harm_even[1] * 2 - 1) * amp;
		^ sig;
	}
}

and then the bulk of the synthesis work is done in the SynthDef:

	detune = LFNoise2.ar (7) / 60;
	vibrato = SinOsc.ar (2 ** (vibrato_freq_env - 6)) * vibrato_width_env / 12;

	fund_phasor = LFSaw.ar (freq_0_env * (2 ** (detune + vibrato))).range (0, 1);
	modulator = sin (fund_phasor * 2pi);

	car_0 = amp_env ** 0.5 * Crossfade_Formant.ar (fund_phasor, modulator, K2A.ar (1), ind_0_env, amp_0_env);
	car_1 = amp_env ** 1.5 * Crossfade_Formant.ar (fund_phasor, modulator, harm_1_env, ind_1_env, amp_1_env);
	car_2 = amp_env ** 2 * Crossfade_Formant.ar (fund_phasor, modulator, harm_2_env, ind_2_env, amp_2_env);

	sig = car_0 + car_1 + car_2;
	sig = sig * drive;
	sig = sig.tanh;