Correlate Lag time in context

Hi,
I am looking for a way to lag one synth’s parameter according to the previous setting. For instance, we set the amp of a synth at 0.1, then put it to 0.6 which the lag time should be longer than for 0.3, but proportionally. I am thinking in the GUI context when sometimes on the slider you jump from one value to another one.
My idea is to store the previous settings in a variable and then compute the time lag according to this previous value.
Am I in the right direction, or does there exist some other way, or trick to manage that maybe more efficiently?

You are trying to write a stateful context. A very simple way to implement it would be to store the old and new states and set the lag accordingly:

(
~amp = 0.1;  // Initial amplitude value
~lag = 0.1;  // Initial lag time value

SynthDef(\asynth, {
    |freq=440, ampB=0.1, lagB=0.1|
    var sig = SinOsc.ar(freq) * Lag.kr(ampB, lagB).poll(1)
    Out.ar(0, sig ! 2);
}).add;


~setAmp = {
    |newAmp|
    var diff = (newAmp - ~amp).abs;
    ~lag = diff * 20; 
    ~amp = newAmp;
    ~synth.set(\ampB, ~amp, \lagB, ~lag.postln);
};
)

~synth = Synth(\asynth, [\freq, 440, \ampB, ~amp, \lagB, ~lag]);
~setAmp.(0.192);
~setAmp.(0.622);
~setAmp.(0.511);

Yes, thanks for confirming, that was what I thought. :slightly_smiling_face:

1 Like

You can also do it in the language with some interpolation functions and a routine. Something like this ( not tested, double check it before using it):

(

~linearInterp = { |start, end, t| start + (t * (end - start)) };
~expInterp = { |start, end, t| start * ((end / start) ** t) };
~sineInterp = { |start, end, t| start + ((end - start) * sin(t * pi / 2)) };


SynthDef(\gsynth, { |out=0, freq=440, amp=0.1|
    var sig = SinOsc.ar(freq) * amp;
    Out.ar(out, sig ! 2);
}).add;


~currentAmp = 0.1;
~targetAmp = 0.1;
~interpFunc = \linear;
~interpDuration = 1;
~updateRate = 20; 

~interpRoutine = nil;

~startInterpolation = { |target, duration, func=\linear|
    var start = ~currentAmp;
    ~targetAmp = target;
    ~interpDuration = duration;
    ~interpFunc = func;

    ~interpRoutine.stop;

    ~interpRoutine = Routine({
        var steps = ~interpDuration * ~updateRate;
        var stepDuration = 1 / ~updateRate;
        var interpFunction = switch(func,
            \linear, { ~linearInterp },
            \exponential, { ~expInterp },
            \sine, { ~sineInterp }
        );

        steps.do { |i|
            var t = (i + 1) / steps;
            ~currentAmp = interpFunction.(start, target, t);
            ~synth.set(\amp, ~currentAmp);
            stepDuration.wait;
        };

        "Interpolation OK. Current AMP: %\n".postf(~currentAmp);
    }).play;
};


~synth = Synth(\gsynth, [\freq, 440, \amp, ~currentAmp]);

~setAmp = { |newAmp, duration, curve=\linear|
    ~startInterpolation.(newAmp, duration, curve);
};

~setAmp.(0.8, 2, \linear);
)

~setAmp.(0.2, 3, \exponential);
~setAmp.(0.6, 4, \sine);
~setAmp.(0.1, 2, \linear);

~updateRate = 50; // new update rate

~setAmp.(0.9, 2, \exponential);

Yes, it works, but the first solution is more straightforward and can be modulated with VarLag.
This said, it depends on the context.

You can accomplish something similar with Slew. With this you are not controlling the lag time, but rather the lag rate in units per second:

(
~slewDb = {
    var sig = Saw.ar(220);
    var slew = \dbRate.kr(3); // rate of change in dB per second
    var db = Slew.kr(\db.kr(-6), slew, slew).poll;
    sig * db.dbamp ! 2;
}.play;
)

~slewDb.set(\db, -12); // change db
~slewDb.set(\db, -9); // change less (happens faster)
~slewDb.set(\db, -15, \dbRate, 12); // change faster