Dseq skips first value

Hi all,

I stumbled into an interesting situation with Dseq. Sometimes, the first value is skipped, depending on whether .midicps is applied to the internal array vs. the UGen itself. I suspect there is a legitimate explanation involving demand UGens’ output being “different” somehow from that of normal UGens.

Wondering why specifically this is the case, and whether this behavior is documented somewhere.

Eli

s.boot;

(
{ // works as expected
	var d, freq;
	d = Dseq([60, 68, 76].midicps, inf);
	freq = Demand.kr(Impulse.kr(6), 0, d);
	SinOsc.ar(freq) * 0.1!2;
}.play;
)

(
{ // skips first value
	var d, freq;
	d = Dseq([60, 68, 76], inf).midicps;
	freq = Demand.kr(Impulse.kr(6), 0, d);
	SinOsc.ar(freq) * 0.1!2;
}.play;
)

Interestingly, if you reset Demand, the second example works:

(
{ // with an initial reset of Demand.kr, the first value is not skipped, without the reset, the first value is skipped
	var d, freq;
	d = Dseq([60, 68, 76], inf).midicps;
	freq = Demand.kr(Impulse.kr(7), Impulse.kr(0), d);
	SinOsc.ar(freq) * 0.1!2;
}.play;
)

I wonder if this is essentially the same behavior that makes Stepper “skip” its first value, depending on whether the algorithm begins with a reset trigger (i.e., the UGen function starts playing at the exact same moment an “advance” trigger is received). But I still feel like there’s more going on — I don’t know how to explain the behavior change produced by moving the .midicps method.

s.boot;

(
{ // includes first value
	var sig, freq;
	freq = Stepper.kr(Impulse.kr(6), Impulse.kr(0), 0, 2) + 70;
	SinOsc.ar(freq.midicps) * 0.1!2;
}.play;
)

(
{ // skips first value
	var sig, freq;
	freq = Stepper.kr(Impulse.kr(6), 0, 0, 2) + 70;
	SinOsc.ar(freq.midicps) * 0.1!2;
}.play;
)

The help file for demand states that:

By design, a reset trigger only resets the demand ugens; it does not reset the value at Demand's output. Demand continues to hold its value until the next value is demanded, at which point its output value will be the first expected item in the list. To jump to the start value upon receipt of a reset trigger, one can add (+) the two triggers together: {...example with reset...}

Not that a I really understand the behaviour but could it have something to do with .midicps being lazily evaluated while a Dseq with the .midicps inside, like your first example, is evaluated at init time and therefor already holds the first value when the first trigger appears, thus skipping to value 2?

Thanks, right, I saw this in the help doc, and assumed it is essentially meant to explain this potentially confusing behavior:

s.boot;

(
x = {
	var d, freq;
	d = Dseq([60, 68, 76].midicps, inf);
	freq = Demand.kr(\advance.tr(0), \reset.tr(0), d);
	SinOsc.ar(freq) * 0.1!2;
}.play;
)

x.set(\advance, 1); // steps through Dseq values

x.set(\reset, 1); // resets Dseq so that next 'advance' outputs 60
// but does not reset or otherwise disrupt Demand output signal

x.set(\advance, 1); // 60.midicps

But this help doc excerpt doesn’t really explain why moving the location of the .midicps method changes the behavior.

That sounds plausible to me, but I would love to get confirmation and possibly a deeper explanation, if anyone’s able to offer some insight.