Subdivide phase by Demand sequence

hey, im trying to subdivide a phase by a sequence of divisions. First i create a measure phase running at 120 bpm. I then create a step phase by multiplying by the steps per measure and wrap between 0 and 1. I create triggers from these phases with rampToTrig. I then use a Demand sequence of durations triggered by the step trigger and create the event phases by using the measure phase multiplied by the steps per measure and divided by the durations and wrap it between 0 and 1. For some sequences this seems to work fine for others not and i have no idea why that is:

(
var rampToTrig = { |phase|
	var history = Delay1.ar(phase);
	var delta = (phase - history);
	var sum = (phase + history);
	var trig = (delta / sum).abs > 0.5;
	Trig1.ar(trig, SampleDur.ir);
};

{	
	var measurePhase, measureTrigger, stepPhase, stepTrigger, durations, eventPhase, eventTrigger;
	
	var plotScale = 100;
	var bpm = 120 * plotScale;
	var beatsPerSec = bpm / 60;
	var beatsPerMeasure = 4;
	var measureRate = beatsPerSec / beatsPerMeasure;
	var stepsPerMeasure = 12;
	
	// measure phase & trigger
	measurePhase = (Phasor.ar(DC.ar(0), measureRate * SampleDur.ir) - SampleDur.ir).wrap(0, 1);
	measureTrigger = rampToTrig.(measurePhase);

	// step phase & trigger
	stepPhase = (measurePhase * stepsPerMeasure).wrap(0, 1);
	stepTrigger = rampToTrig.(stepPhase);

	//durations = Demand.ar(stepTrigger, 0, Dseq([3, 3, 3, 2, 2, 1, 3, 3, 3, 3, 3, 3], inf));
	durations = Demand.ar(stepTrigger, 0, Dseq([3, 3, 3, 3, 3, 3, 2, 2, 1, 3, 3, 3], inf));

	// create event triggers from sequence of durations
	eventPhase = (measurePhase * stepsPerMeasure / durations).wrap(0, 1);
	eventTrigger = rampToTrig.(eventPhase);
	
	[measurePhase, stepPhase, eventPhase];
}.plot(0.03);
)

works perfectly for this one: [3, 3, 3, 3, 3, 3, 2, 2, 1, 3, 3, 3]
grafik

but not for the uncommented other one: [3, 3, 3, 2, 2, 1, 3, 3, 3, 3, 3, 3]
grafik

Can someone tell me how to fix that? thanks

after looking at this video about building the Make Noise 0-CTRL sequencer in gen~, especially from timestamp 17:35. i have tried to use an accumulator in the form of Duty running at sample rate, multiplied by the step slope, divided by the Demand sequence and wrapped between 0 and 1. The accumulation works fine, but the tricky part is to advance through the pattern. I thought this would be easy by using a Demand sequence. But Im not getting the desired result.

If the division is just a single number, any number, the rampToDiv function for accumulation and ramp division works perfectly fine. But not if it is a Demand sequence.

(
var rampToSlope = { |phase|
	var history = Delay1.ar(phase);
	var delta = (phase - history);
	delta.wrap(-0.5, 0.5);
};

var rampToTrig = { |phase|
	var history = Delay1.ar(phase);
	var delta = (phase - history);
	var sum = (phase + history);
	var trig = (delta / sum).abs > 0.5;
	Trig1.ar(trig, SampleDur.ir);
};

var rampToDiv = { |slope, div|
	var accum = Duty.ar(SampleDur.ir, 0, Dseries(0, 1));
	(slope / div * accum).wrap(0, 1); 
};

{
	var plotScale = 100;
	var bpm = 120 * plotScale;
	var beatsPerSec = bpm / 60;
	var beatsPerMeasure = 4;
	var measureRate = beatsPerSec / beatsPerMeasure;
	var stepsPerMeasure = 12;

	// measure phase & trigger
	var measurePhase = (Phasor.ar(DC.ar(0), measureRate * SampleDur.ir) - SampleDur.ir).wrap(0, 1);
	var measureSlope = rampToSlope.(measurePhase);
	var measureTrigger = rampToTrig.(measurePhase);

	// step phase & trigger
	var stepPhase = (measurePhase * stepsPerMeasure).wrap(0, 1);
	var stepTrigger = rampToTrig.(stepPhase);
	var stepSlope = rampToSlope.(stepPhase);

	// any number works perfectly fine!!!
	var div = 3;
	//var div = Demand.ar(stepTrigger, 0, Dseq([3, 3, 3, 2, 2, 1, 3, 3, 3, 3, 3, 3], inf));
	//var div = Demand.ar(stepTrigger, 0, Dseq([3, 3, 2, 1, 3], inf));
	
	var phaseDiv = rampToDiv.(stepSlope, div);
	
	[measurePhase, stepPhase, phaseDiv];
}.plot(0.03);
)

I have made another attempt with TDuty instead, but same result for one sequence it works for the other not.

(
var rampToTrig = { |phase|
	var history = Delay1.ar(phase);
	var delta = (phase - history);
	var sum = (phase + history);
	var trig = (delta / sum).abs > 0.5;
	Trig1.ar(trig, SampleDur.ir);
};

var rampToSlope = { |phase|
	var history = Delay1.ar(phase);
	var delta = (phase - history);
	delta.wrap(-0.5, 0.5);
};

var rampToDiv = { |slope, div, trig|
	var accum = Duty.ar(SampleDur.ir, trig, Dseries(0, 1));
	(slope / div * accum).wrap(0, 1);
};

{
	var measurePhase, measureTrigger, stepPhase, stepTrigger, durations, eventPhase, eventTrigger, stepSlope;

	var plotScale = 100;
	var bpm = 120 * plotScale;
	var beatsPerSec = bpm / 60;
	var beatsPerMeasure = 4;
	var measureRate = beatsPerSec / beatsPerMeasure;
	var stepsPerMeasure = 12;

	// measure phase & trigger
	measurePhase = (Phasor.ar(DC.ar(0), measureRate * SampleDur.ir) - SampleDur.ir).wrap(0, 1);
	measureTrigger = rampToTrig.(measurePhase);

	// step phase & trigger
	stepPhase = (measurePhase * stepsPerMeasure).wrap(0, 1);
	stepSlope = rampToSlope.(stepPhase);
	stepTrigger = rampToTrig.(stepPhase);

	durations = Demand.ar(stepTrigger, 0, Dseq([3, 3, 3, 3, 3, 3, 2, 2, 1, 3, 3, 3], inf));
	//durations = Demand.ar(stepTrigger, 0, Dseq([3, 3, 3, 2, 2, 1, 3, 3, 3, 3, 3, 3], inf));

	eventTrigger = TDuty.ar(durations / (stepSlope * SampleRate.ir));
	eventPhase = rampToDiv.(stepSlope, durations, measureTrigger);

	[measurePhase, stepPhase, eventPhase];
}.plot(0.03);
)

instead of using all these external functions and Demand sequences, i have also tried it with vanilla Select. and an index created with (measurePhase * stepsPerMeasure).floor. same result.

(
{	
	var measurePhase, stepPhase, durations, eventPhase, stepIndex;
	
	var plotScale = 100;
	var bpm = 120 * plotScale;
	var beatsPerSec = bpm / 60;
	var beatsPerMeasure = 4;
	var measureRate = beatsPerSec / beatsPerMeasure;
	var stepsPerMeasure = 12;
	
	// measure phase
	measurePhase = Phasor.ar(DC.ar(0), measureRate * SampleDur.ir);

	// step phase & index
	stepPhase = (measurePhase * stepsPerMeasure).wrap(0, 1);
	stepIndex = (measurePhase * stepsPerMeasure).floor;

	// doesnt work !!!
	durations = Select.ar(stepIndex, K2A.ar([3, 3, 3, 2, 2, 1, 3, 3, 3, 3, 3, 3]));
	
	// works !!!
	//durations = Select.ar(stepIndex, K2A.ar([3, 3, 3, 3, 3, 3, 2, 2, 1, 3, 3, 3]));
		
	eventPhase = (measurePhase * stepsPerMeasure / max(1, durations)).wrap(0, 1);
	
	[measurePhase, stepPhase, eventPhase];
}.plot(0.03);
)

i think a sequence of divisions does not work together with wrap. I dont know why, but in the meantime i came up with this solution. The downside here is that you cant fully use the potential of ramp division which is using non-integers values. The following attempt just works for a sequence of integers which are masking the step triggers to get the event triggers which are resetting the accumulator. You still can curve the phase of the measure ramp to create bpm synced swing or ratchets (i will make another post on this when ready), which is an advantage over a trigger based approach and if you add the subsample offset calculation for the accumulator you get a sequence of subsample accurate event phases ready for granulation.

(
var rampToSlope = { |phase|
	var history = Delay1.ar(phase);
	var delta = (phase - history);
	delta.wrap(-0.5, 0.5);
};

var rampToTrig = { |phase|
	var history = Delay1.ar(phase);
	var delta = (phase - history);
	var sum = (phase + history);
	var trig = (delta / sum).abs > 0.5;
	Trig1.ar(trig, SampleDur.ir);
};

var accum = { |trig|
	Duty.ar(SampleDur.ir, trig, Dseries(0, 1));
};

{
	var measurePhase, measureTrigger, stepPhase, stepTrigger, stepIndex, stepSlope;
	var durations, eventTrigger, eventPhase;

	var plotScale = 100;
	var bpm = 160 * plotScale;
	var beatsPerSec = bpm / 60;
	var beatsPerMeasure = 4;
	var measureRate = beatsPerSec / beatsPerMeasure;
	var stepsPerMeasure = 12;

	// measure phase & trigger
	measurePhase = (Phasor.ar(DC.ar(0), measureRate * SampleDur.ir) - SampleDur.ir).wrap(0, 1);
	measureTrigger = rampToTrig.(measurePhase);

	// step phase, slope & trigger
	stepPhase = (measurePhase * stepsPerMeasure).wrap(0, 1);
	stepSlope = rampToSlope.(stepPhase);
	stepTrigger = rampToTrig.(stepPhase);

	durations = Ddup(2, Dseq([2, 6, 1, 2, 1], inf));
	durations = Demand.ar(stepTrigger, 0, Ddup(durations, durations));

	stepIndex = Demand.ar(stepTrigger, 0, Dseq([Dseries(0, 1, durations)], inf));

	eventTrigger = stepTrigger * Demand.ar(stepTrigger, 0, Dswitch1([1] ++ (0 ! (stepsPerMeasure - 1)), stepIndex));
	eventPhase = stepSlope / max(1, durations) * accum.(eventTrigger);

	[measurePhase, stepPhase, eventPhase];
}.plot(0.03);
)

grafik

1 Like