Sub-sample accurate granulation with random periods

i think i have found a solution to latch the trigger frequency. The difference is subtle to the original version. I have added an initial trigger, Latch and no subtraction of SampleDur.ir before the last wrap. compare it with the initial one, once more shared down below. To have a closer look i have used the function ~zoomIn shared in this thread: Offset x-axis of function plot - #4 by TXMod

(
var getRandomPeriods = { |rate, randomness|
	var randomPeriod = Ddup(2, (2 ** (Dwhite(-1.0, 1.0) * randomness))) / rate;
	Duty.ar(randomPeriod, DC.ar(0), 1 / randomPeriod);
};

var rampToRandom_NEW = { |rate, randomness|
	var initTrigger = Impulse.ar(0);
	var randomPeriod = getRandomPeriods.(rate, randomness);
	var trig = Changed.ar(randomPeriod) > 0 + initTrigger;
	var accum = Duty.ar(SampleDur.ir, trig, Dseries(0, 1));
	var slope = randomPeriod * SampleDur.ir;
	(slope * accum).wrap(0, 1);
};

{
	rampToRandom_NEW.(\tFreq.kr(500), \randomness.kr(1));
}.plot(0.02);
)

// same here for closer inspection of the different parts with the ~zoomIn function

(
var getRandomPeriods = { |rate, randomness|
	var randomPeriod = Ddup(2, (2 ** (Dwhite(-1.0, 1.0) * randomness))) / rate;
	Duty.ar(randomPeriod, DC.ar(0), 1 / randomPeriod);
};

~rampToRandom_NEW = {
	var randomPeriod, trig, accum, slope, phase;

	randomPeriod = getRandomPeriods.(\rate.kr(500), \randomness.kr(1));
	trig = Changed.ar(randomPeriod) > 0 + Impulse.ar(0);
	accum = Duty.ar(SampleDur.ir, trig, Dseries(0, 1));
	slope = Latch.ar(randomPeriod, trig) * SampleDur.ir;
	phase = (slope * accum).wrap(0, 1);

	[randomPeriod / 1500, trig, phase];
};

~zoomIn.(~rampToRandom_NEW, 3);
)

and while trying out different things, came up with this rampSelfModLatch function:

(
var getPeriods = { |rate|
	 Duty.ar(1 / rate, DC.ar(0), rate);
};

var rampSelfModLatch = { |rate|
	var initTrigger = Impulse.ar(0);
	var period = getPeriods.(rate);
	var trig = Changed.ar(period) > 0 + initTrigger;
	var accum = Duty.ar(SampleDur.ir, trig, Dseries(0, 1));
	var slope = period * SampleDur.ir;
	(slope * accum).wrap(0, 1);
};

{
	var rateMod = 2 ** (SinOsc.ar(50) * \randomness.kr(2));
	var rate = \rate.kr(500) * rateMod;
	rampSelfModLatch.(rate);
}.plot(0.02);
)

// same here for closer inspection of the different parts with the ~zoomIn function
(
var getPeriods = { |rate|
	 Duty.ar(1 / rate, DC.ar(0), rate);
};

~rampSelfModLatch = {
	var rate, rateMod, phase;
	var period, trig, slope, accum;

	rateMod = 2 ** (SinOsc.ar(50) * \randomness.kr(2));
	rate = \rate.kr(500) * rateMod;

	period = getPeriods.(rate);
	trig = Changed.ar(period) > 0 + Impulse.ar(0);
	accum = Duty.ar(SampleDur.ir, trig, Dseries(0, 1));
	slope = Latch.ar(period, trig) * SampleDur.ir;
	phase = (slope * accum).wrap(0, 1);

	[period / 2500, trig, phase];
};

~zoomIn.(~rampSelfModLatch, 3);
)

That was the initial attempt:

// initial attempt for closer inspection of the different parts with the ~zoomIn function

(
var getRandomPeriods = { |rate, randomness|
	var randomPeriod = Ddup(2, (2 ** (Dwhite(-1.0, 1.0) * randomness))) / rate;
	Duty.ar(randomPeriod, DC.ar(0), 1 / randomPeriod);
};

~rampToRandom_OLD = { |rate, randomness|
	var randomPeriod = getRandomPeriods.(\tFreq.kr(500), \randomness.kr(1));
	var trig = Changed.ar(randomPeriod) > 0;
	var accum = Duty.ar(SampleDur.ir, trig, Dseries(0, 1));
	var slope = randomPeriod * SampleDur.ir;
	var phase = accum * slope;
	(phase - SampleDur.ir).wrap(0, 1);
	
	[randomPeriod / 1500, trig, phase];
};

~zoomIn.(x, ~rampToRandom_OLD);
)

function for closer inspection:

(
~zoomIn = { |func, n|

func.loadToFloatArray(0.021, action: { |array|
	var d, u;
	{
		d = array.as(Array).clump(n).flop;	// split into n arrays
		// d[0].size.debug("d[0].size");
		u = ScaledUserViewContainer(nil, Rect(10, 35, 490, 400));
		u.maxZoom = 30; // set higher if you want more zoom range
		u.unscaledDrawFunc = { |view|
			d.do({ |item, i|
				var col = [Color.red, Color.blue, Color.gray][i];
				Pen.color = col;
				Pen.moveTo(0 @ item[0]);
				item.do({ |val, ind|
					var x = ind / item.size;
					var y = (1 - val) ;
					Pen.lineTo(view.translateScale(Point(x, y)));
				});
				Pen.stroke;
			});
		};
	}.defer // defer gui process
});
};
)

Could someone have a look at the different examples. What do you think?