Using a gate with a Penv

Is there a way to use a gate with a Penv?

My use case is that I have a value that changes over time and I want it to ramp up when I detect silence on the input and down when there’s audio incoming. I’m already sending OSC messages detecting audio and silences, so I thought I could use a boolean to track which of these was the last input. Having a value ramp up and down based on a 0 or 1 reminded me of a gate, so I thought I could put a Penv into a Task (or Pbind)

So I have a value that changes over time and I want to it to ramp up when some event occurs and ramp down when a different one occurs. Essentially, I want to offset it from it’s baseline via an Envelope triggered by a gate. A Penv seemed like the most straight forward / lowest overhead to manage this, but I’m stumped.

Maybe somebody has an extension class, but in the core library, I think there’s no way to do that currently. Penv only indexes into the envelope by time (the same way that plotting a gated envelope doesn’t show the sustain/loop portion).

It could probably be hacked using Prout (but it might be easier to write a simple linear or other interpolator into a Prout).

EDIT: Would you want the interpolation ramp to start at the moment the new value is set, or on the next event? Should the ramp rate be specified in terms of time, or number of events? Those make a difference for implementation.

hjh

I’ve patched around this by running an env on the server and sending it to a control bus, so if it worked like that but was less terrible…

Perhaps a bit devil’s advocate, but if the desired behavior is that the lag/slew gate logic runs on its own, and the pattern only samples that, a server-side approach might be a good way to model it. The server already has optimized operators for lowpassing or slewing, sparing the need to write your own lag in the language.

The tricky thing about patterns here is that, like cats, they sleep a lot, and they don’t become aware of what’s going on until they wake up. So, if your stream woke up at beat 100 and it’s sleeping until 100.5, and the gate changed at 100.1, then something outside of the stream needs to know the change and the time when it changed. A 100% pure pattern approach would register the change and start lagging at 100.5, which seems different from what you’re describing. So if you’ll need an agent outside the stream handling the lag, which the stream queries, the only language side advantage I can see is that it would be calculating on demand, rather than continuously.

hjh

I’m ok with the gate getting registered only when the Pbind is next evaluated, which is why I was looking for a Pbind-based solution. I’m sure I could write a Prout or something to do it, but I was hoping not to!

Ok, cool.

Yeah, it would be generally useful to have a slew-limiting or other type of interpolating lowpass thingy in the pattern library. (Or, if the up/down lag times should match, then a moving average filter would do it – but I’m not aware of that in the pattern library, either.)

hjh

Just for fun – with the ddwPatterns quark, the moving average approach would be a (clumsy) one-liner:

(
Pdefn(\gate, 1);

Pdefn(\ramp, (Pseries(0, Pdefn(\gate), inf).drop(1) - Pdelay(Pseries(0, Pdefn(\gate), inf).drop(1), 10, 10)) / 10);

p = Pbind(
	\ramp, Pdefn(\ramp),
	\dur, 0.1,
	\type, \rest
).trace(\ramp).play;
)

Pdefn(\gate, 0);  // 10-event ramp down

Pdefn(\gate, 1);  // 10-event ramp up

p.stop;

… though it doesn’t react immediately to gate changes. Probably a Pseries behavior.

hjh

1 Like