IndexInBetween for autotune using non-standard tunings

I’m working on trying to build an autotune that I can use with non-standard tunings. I came across the IndexInBetween through its use as an autotune in the help file. So far, implementing it as it is in the help file seems to only round a note down rather than round a note to the nearest note in the scale/tuning. For instance, if the note is 300hz, and Tartini detects 290hz, whatever note is lower than 300hz in the scale plays, and so to get the desired pitch one must always sing sharp. Is there an easy way to get closer to a “nearest note” behavior here? Any help much appreciated.

(
~scale = 300*Scale.major.tuning_(\just).ratios.asList;
~scale = (~scale.add((~scale*[1/4, 1/2, 2, 4]))).flat.round(0.00001).sort;
SynthDef(\tunedInJIM, {
	arg ratio = 1, timeDisp = 0, grainPer = 2, fbDry = 1;
	var index, in, tuned, f0, fdiff, out, local;
	var scale = ~scale;
	var buffer = scale.as(LocalBuf);
	in = SoundIn.ar(0);
	f0 = Tartini.kr(in);
	index = IndexInBetween.kr(buffer, f0);
	fdiff = index.frac * (Index.kr(buffer, index + 1) - Index.kr(buffer, index));
	fdiff = fdiff[0].poll;
	tuned = PitchShiftPA.ar(in, f0, 1-(fdiff/f0), formantRatio: ratio, minFreq: 60, maxFormantRatio: 4, grainsPeriod: grainPer, timeDispersion: timeDisp);
	out = (tuned)/2;
	out = Limiter.ar(4*HPF.ar(out, 10), 0.9, 0.01);
	Out.ar(0, out!2);
}).add;

x = Synth.new(\tunedInJIM)
)
1 Like

Nearest-note, you need to write .round for that:

(
x = Scale.major.tuning_(\just).ratios ++ [2];

a = {
	var buf = x.as(LocalBuf);
	var f = LFTri.kr(0.1).exprange(1, 1.999);
	var index = IndexInBetween.kr(buf, f);
	// print out f at the moment when index changes *integer*
	index = index.round;
	Poll.kr(Changed.kr(index), f);
	(SinOsc.ar(60.midicps * Index.kr(buf, index)) * 0.1).dup
}.play;
)

hjh