Hardsync of two Phasors

hey,
after looking at this video describing a specific rhythm technique used by mark fell on intra,
I thought this is basically hard sync of two ramps. Would someone know how to implement that with two phasors?

This was my first attempt following the description in the video:

(
{ |innerLoop = 3, outerLoop = 7|
	var rate = 250;
	
	var outerPhase = (Phasor.ar(DC.ar(0), rate * SampleDur.ir, 0, 1) * outerLoop - SampleDur.ir).wrap(0, outerLoop);
	var outerImpulse = HPZ1.ar(outerPhase) < 0;
	
	var innerPhase = (Phasor.ar(outerImpulse, rate * SampleDur.ir, 0, 1) * innerLoop - SampleDur.ir).wrap(0, innerLoop);
	var innerImpulse = HPZ1.ar(innerPhase) < 0;

	[innerPhase, innerImpulse, outerPhase, outerImpulse];
}.plot(0.02);
)

EDIT: In the book about gen~ which is mentioned in the video its stated that sometimes its better to derive triggers from phases and not phases from triggers. The book makes an argument for using phasors instead of triggers for organising rhythmic structures with the different possibilites for shaping the ramps and getting triggers, steps, lfos etc from it which are synced to the triggers. One advantage i found already is, that its possible to have asynchronous triggers and a continuous phase and for example divide the phase by non-integer values to get non-integer divisions.

Hi,
Something like this?

(
{
  var a = Phasor.ar(0, s.sampleRate.reciprocal * (1/3), 0, 1); // 1/3Hz
  var b = Phasor.ar(Slope.ar(a), s.sampleRate.reciprocal * (1/2), 0, 1); // 1/2 Hz
  var c = Trig.ar(Slope.ar(b), 0.1);
  [a,b, c];
}.plot(6);
)

I’m not done watching the video yet, so I assume this is what you mean.

cool it seems to work.
I have addtionally subtracted SampleDur.ir before wrapping the Phasors, so you also get the initial trigger and replaced Trig.ar by Trig1.ar and used SampleDur.ir for its duration. This seems to result in an appropriate range between 0 and 1 for the trigger.

(
{ |innerLoop = 4, outerLoop = 7|
	var rate = 100;
	var a = (Phasor.ar(0, rate * SampleDur.ir * innerLoop, 0, 1) - SampleDur.ir).wrap(0, 1);
	var b = (Phasor.ar(Slope.ar(a), rate * SampleDur.ir * outerLoop, 0, 1) - SampleDur.ir).wrap(0, 1);
	var c = Trig1.ar(Slope.ar(b), SampleDur.ir);
	[a, b, c];
}.plot(0.02);
)

Is the Slope / Trig1 combination equal to HPZ1 in terms of accurancy?

(
{ |innerLoop = 4, outerLoop = 7|
	var rate = 100;
	var a = (Phasor.ar(0, rate * SampleDur.ir * innerLoop, 0, 1) - SampleDur.ir).wrap(0, 1);
	var b = (Phasor.ar(HPZ1.ar(a) < 0, rate * SampleDur.ir * outerLoop, 0, 1) - SampleDur.ir).wrap(0, 1);
	var c = HPZ1.ar(b) < 0;
	[a, b, c];
}.plot(0.02);
)

EDIT: i guess not:

Slope / Trig1
grafik

HPZ1
grafik

adding Impulse.ar(0) to HPZ1 without subtracting SampleDur.ir from Phasor
grafik

2 Likes

I tried to mock up a Pattern version that has the same trigger semantics - I couldn’t come up with anything off the top of my head, but it would be a cool thing to solve. Obviously, continuously varying the rates wouldn’t work, but I think one could still achieve some cool results?

not sure but couldn’t the pattern version be as simple as something like

Pseq( {|i| [1, 0, 0].wrapAt(i.mod(7)) }.dup(7), inf).asStream.nextN(7)

at least based on the diagram he showed at the beginning of the video.

1 Like

the scaling of the rates could be done more intuitively i guess, but its additionally good to latch the syncedRatio:

(
var hardSyncTrigs = { |rate, syncRatio, syncedRatio|
	var syncPhase = Phasor.ar(DC.ar(0), rate * syncRatio * SampleDur.ir, 0, 1);
	var syncTrig = HPZ1.ar(syncPhase) < 0 + Impulse.ar(0);
	var syncedPhase = Phasor.ar(syncTrig, rate * Latch.ar(syncedRatio, syncTrig).poll * SampleDur.ir, 0, 1);
	HPZ1.ar(syncedPhase) < 0 + Impulse.ar(0);
};

{
	var rate, syncedRatio, syncRatio, trig, freqs, exc, sig;

	rate = 12;
	syncRatio = 1 / 11;
	syncedRatio = 1 / LFSaw.ar(0.1, 1).linlin(-1, 1, 2, 9).round(1);
	trig = hardSyncTrigs.(rate, syncRatio, syncedRatio);

	freqs = (60.5 + [0, 2, 4, 7, 11]).midicps;

	exc = Hasher.ar(Sweep.ar(trig)) * -10.dbamp;
	sig = Pluck.ar(exc, trig, freqs.reciprocal, freqs.reciprocal, \dec.kr(0.5), \coef.kr(0.2)).sum;
	sig = LeakDC.ar(sig);

	sig = Pan2.ar(sig, \pan.kr(0));

	sig * \amp.kr(-15.dbamp);

}.play;
)