Is there a way to have \dur computed on-the-fly?

In a Pattern, I would like to have \dur computed, based on other keys.
But not as a Pfunc.
My use case is that I generate some events with a Pbind, I store these events in an array and would like to manipulate them before replaying them, and have the \dur recomputed accordingly without any other processing.

Prout({
// \dur = \pace * \steps

pbs=(Pdef(\motif)).asStream;
4.do({
    var pb=pbs.next();
    past=past.add(pb);
    pb.yield;
});

2.do({|j|
    4.do({|i|
        var pb=past.wrapAt(i);
        pb[\id]=nil; // !! cleanup
        pb[\pace]=pb[\pace]*2; 
        pb.yield; // \dur is expected to =*2
    })
})
});

I could explicitly recompute pb[\dur], with a function.

But I was trying to define the way to compute the \dur in a prototype:

~proto=(dur: #{ (~pace.notNil.if{~pace}{1})*(~steps.notNil.if{~steps}{1}) };);

with a

play(protoEvent: ~proto)

But SC complains when I execute that.

I guess it is because the expansion mechanism of the Event expects \dur to be a value and not a function. Am I correct ?

Is they an alternative to have \dur defined as a function in a prototype ?

It’s because user functions in an event are converted to values only in the synth argument list, at the time of playing the synth. IIRC they aren’t converted in the event itself. (Reserved keys such as freq and delta are evaluated in the event type function – so, for example, if you specify \degree, the final event after .play will contain freq but not midinote.)

\dur is usually not passed to the synth, and even if it were, the rescheduling value is taken from the event (un-converted) and not from the synth arg list.

I think you’ll have to do it explicitly, I’m afraid.

hjh

The \delta value is only pulled from an Event after it’s played - this is ultimately the value that must be present (not as a function, but as a number), though usually this is calculated based on ~dur (which must also be a number when delta is requested).

As long as you have a \delta or \dur value by the time you finish playing the Event, you should be good - UNLESS the event is passing through something that requires a fixed and available duration (Ppar is an example, since it needs to track how long to wait between Events - though this is also could be fixed…). So, you can e.g. add (callback: { ~delta = ~dur.value * ~stretch.value }) to your event and this should calculate a correct delta by the time you need it.

You can also simply override the delta method in Event to calculate your delta however you want, rather than relying on the built-in _Event_Delta primitive (which needs the values to be calculated ahead of time) - e.g do something like what i did in the callback function. I just did this in a recent project where my duration calculations were complex and couldn’t be determined early in the playback chain - it works just fine. (The comment in the Event source says “implemented by primitive for speed”, which I’m absolutely sure is not an issue in all practical cases).