Old 03-17-2020, 10:49 AM   #1
TonE
Human being with feelings
 
Join Date: Feb 2009
Location: Reaper HAS send control via midi !!!
Posts: 4,032
Default Simplest way of adding inertia to a slider? [jsfx]

Example:
If I have two sliders as follows:

slider10:sent=1<{0,1,1}>Sent Status
slider11:blocked=0<{0,1,1}>Blocked Status

Example is from Random Note Gate by Time Waster, where I added those two sliders additionally, based on the probability parameter. Now as those sliders can switch too quickly, which I would like to use to trigger/control wet parameters of some vst fx, like a big reverb for example, I would like to control a bit how slow the slider should move back, after its triggering, it should move back a bit slower.

What is the most elegant way of doing it in jsfx, I am already grep'ing a bit for 'inertia', but thought let me ask also in the forum, some master might give better replies eventually. Thanks in advance. Of course the more universal the solution the better, then I could take any jsfx, create for any variable I want a slider, plus I could quickly give this slider some inertia, opening up this variable to control anything we want, via parameter modulation with linking feature.

Maybe parameter modulation should have some additional 'inertia' parameter, so this step could be saved, as this is a very useful and universal concept. Maybe devs will read this in 10 years.

Last edited by TonE; 03-19-2020 at 06:36 AM.
TonE is offline   Reply With Quote
Old 03-19-2020, 02:51 AM   #2
Talagan
Human being with feelings
 
Join Date: Feb 2016
Location: Paris / France
Posts: 301
Default

Hi TonE, I'm posting here to continue the discussion initiated there : https://forum.cockos.com/showthread....28#post2259028

This is a "working" example of inertia. You can see it's effect using the debugger, the current variable will follow the slider with a delay. This technique actually implements a simple low-pass filter ; as I wrote in the other thread, I'm not sure however that using the time_precise function is the best choice for evaluating time, maybe you should count the elapsed samples instead and implement this in the @sample block, it'd be more robust and not subject to the computer randomness.


Code:
desc:INERTIA TEST TALAGAN

slider1:0<0,100,1>parameter1

@init
inertia = 1; // Caracteristic time, in seconds

target  = slider1;
current = target;
last_t = time_precise();

@slider
target  = slider1;

@block
t          = time_precise();
dt         = t - last_t;
last_t     = t;
alpha      = dt / (dt+inertia);
current    = (1 - alpha) * current + alpha * target;
Talagan is offline   Reply With Quote
Old 03-19-2020, 04:29 AM   #3
pepe44
Human being with feelings
 
pepe44's Avatar
 
Join Date: Jul 2013
Location: Portugal
Posts: 1,827
Default

i don't understand too much of scripting, but for a user perspective, when you press CTRL and drag some fader you have a different behaviour, slower values change (inertia?) so maybe that can be used has a default behavior for your sliders i´m guessing. If you know the exact code that does that , no ?
pepe44 is offline   Reply With Quote
Old 03-19-2020, 04:58 AM   #4
sai'ke
Human being with feelings
 
sai'ke's Avatar
 
Join Date: Aug 2009
Location: NL
Posts: 1,457
Default

Quote:
Originally Posted by Talagan View Post
Hi TonE, I'm posting here to continue the discussion initiated there : https://forum.cockos.com/showthread....28#post2259028

This is a "working" example of inertia. You can see it's effect using the debugger, the current variable will follow the slider with a delay. This technique actually implements a simple low-pass filter ; as I wrote in the other thread, I'm not sure however that using the time_precise function is the best choice for evaluating time, maybe you should count the elapsed samples instead and implement this in the @sample block, it'd be more robust and not subject to the computer randomness.


Code:
desc:INERTIA TEST TALAGAN

slider1:0<0,100,1>parameter1

@init
inertia = 1; // Caracteristic time, in seconds

target  = slider1;
current = target;
last_t = time_precise();

@slider
target  = slider1;

@block
t          = time_precise();
dt         = t - last_t;
last_t     = t;
alpha      = dt / (dt+inertia);
current    = (1 - alpha) * current + alpha * target;
I would recommend against doing it in block, since you'll still have stepping from the blocksize. If nobody has posted any more by the end of the day, I can post a working example for both inertia and sample accurate automation. I recently added this to swellotron (for the gain) as well, so looking at the diff of the last commit there will give you an implementation.
__________________
[Tracker Plugin: Thread|Github|Reapack] | [Routing Plugin: Thread|Reapack] | [More JSFX: Thread|Descriptions|Reapack]
sai'ke is offline   Reply With Quote
Old 03-19-2020, 05:07 AM   #5
Talagan
Human being with feelings
 
Join Date: Feb 2016
Location: Paris / France
Posts: 301
Default

Quote:
Originally Posted by pepe44
i don't understand too much of scripting, but for a user perspective, when you press CTRL and drag some fader you have a different behaviour, slower values change (inertia?) so maybe that can be used has a default behavior for your sliders i´m guessing. If you know the exact code that does that , no ?
Not sure if it was the original question But thanks anyway for the "fine tuning" tip, that I did not know!

@TonE, here's an alternate version, with a custom interpolator from 0..1 to 0..1 and using @sample. Also, I got rid of the time_precise function since we now the real delta time between two samples (which is 1/samplerate).

Code:
desc:INERTIA TEST TALAGAN 2

slider1:0<0,100,1>parameter1

@init

// How long the inertia will last
inertia       = 5;

// Time between two samples
sample_dt     = 1.0/srate;

// Initialisation of variable parameters
target        = slider1;
start         = target;
current       = start;
progress_time = 0;

@slider

// Slider event : update target and course parameters
target        = slider1;
start         = current;
progress_time = 0;

@sample

// Can be any interpolating function from 0..1 to 0..1
function interpolate01(progress_01) (
  progress_01 * progress_01; // x^2 interpolator
);

progress_01 = (inertia == 0)?(1):(progress_time/inertia);
progress_01 = (progress_01 > 1)?(1):(progress_01); // Clamp > 1
progress_01 = (progress_01 < 0)?(0):(progress_01); // Clamp < 0

current     = start + interpolate01(progress_01) * (target-start);

progress_time += sample_dt;

Last edited by Talagan; 03-19-2020 at 05:34 AM.
Talagan is offline   Reply With Quote
Old 03-19-2020, 05:17 AM   #6
Talagan
Human being with feelings
 
Join Date: Feb 2016
Location: Paris / France
Posts: 301
Default

Quote:
Originally Posted by sai'ke View Post
I would recommend against doing it in block, since you'll still have stepping from the blocksize. If nobody has posted any more by the end of the day, I can post a working example for both inertia and sample accurate automation. I recently added this to swellotron (for the gain) as well, so looking at the diff of the last commit there will give you an implementation.
Thanks a lot and sorry for the cross-posting :-) I'm having a glance at the diff (https://github.com/JoepVanlier/JSFX/...e9a8d08bf2ab33) and it looks pretty interesting, in the same spirit but with more complex features. Maybe we can stay simpler here (for pedagogical reasons) but feel free to comment the latest example in light of what you've implemented :-)
Talagan is offline   Reply With Quote
Old 03-19-2020, 05:39 AM   #7
IXix
Human being with feelings
 
Join Date: Jan 2007
Location: mcr:uk
Posts: 3,891
Default

This works well enough and is pretty neat. The inertia time is approximate though.

edit: that's weird, the forum is messing up the slider def.
edit again: fixed with additional spaces
Code:
slider1:param.target = 0<0,1,.01>Param

@init
function SetInertia(ms)
  instance(inertia, coeff, ncoeff)
(
  inertia = ms;
  coeff = exp(-5 / (ms * 0.001 * srate));
  ncoeff = 1 - coeff;
);

function Update()
  instance(target, coeff, ncoeff)
(
  this = this * coeff + target * ncoeff;
);

param.SetInertia(500);

@sample
param.Update();

Last edited by IXix; 03-19-2020 at 05:44 AM.
IXix is offline   Reply With Quote
Old 03-19-2020, 06:08 AM   #8
TonE
Human being with feelings
 
Join Date: Feb 2009
Location: Reaper HAS send control via midi !!!
Posts: 4,032
Default

Thanks Talagan,

changing to

slider1:current=0<0,100,1>parameter1

seems to work, however always in one direction, it should work instead bipolarly, when the linked parameter goes down, it should move in the same direction, only slower. Now no matter into which direction the master moves, the slave has always same direction, is independent of the master, which is wrong.

Apart from this it looks very good, thanks. I will try a bit more.

UPDATE: Oh, I missed the above 5 posts, will read them first. Thanks all you are all wonderful.
TonE is offline   Reply With Quote
Old 03-19-2020, 06:32 AM   #9
TonE
Human being with feelings
 
Join Date: Feb 2009
Location: Reaper HAS send control via midi !!!
Posts: 4,032
Default

In case it is not clear it is about output inertia, not input inertia. I am just presenting some internal variable to the outside world as a slider, and its movement slowed down a bit (compared to its real internal value change), so the effect has enough time to work, so humans can hear it. Maybe elephants can even hear such quick changes, who knows.
TonE is offline   Reply With Quote
Old 03-19-2020, 07:08 AM   #10
IXix
Human being with feelings
 
Join Date: Jan 2007
Location: mcr:uk
Posts: 3,891
Default

Quote:
Originally Posted by TonE View Post
In case it is not clear it is about output inertia, not input inertia...
Same principals apply, just need to juggle things around a bit..

Code:
slider1:input= 0<0,1,.01>Input
slider2:output= 0<0,1,.01>Output

@init

function SetInertia(ms)
  instance(inertia, coeff, ncoeff)
(
  inertia = ms;
  coeff = exp(-5 / (ms * 0.001 * srate));
  ncoeff = 1 - coeff;
);

function Update()
  instance(target, coeff, ncoeff)
(
  this = this * coeff + target * ncoeff;
);

output.SetInertia(1000);

@slider
output.target = input;

@sample
output.Update();
IXix is offline   Reply With Quote
Old 03-19-2020, 08:11 AM   #11
Talagan
Human being with feelings
 
Join Date: Feb 2016
Location: Paris / France
Posts: 301
Default

Quote:
Originally Posted by IXix View Post
Same principals apply, just need to juggle things around a bit..
I do agree with @IXix, in my example the value given by the slider is the input, the current variable is the output, so you can apply the same principals on any input and enslave any output (like a slider for example)
Talagan is offline   Reply With Quote
Old 03-19-2020, 09:44 AM   #12
TonE
Human being with feelings
 
Join Date: Feb 2009
Location: Reaper HAS send control via midi !!!
Posts: 4,032
Default

Dear Talagan, yes your example works, with my tiny addition at the top. IX's for example did not work as I wanted, now I will check his new version, if that works. The simpler the solution the better.
TonE is offline   Reply With Quote
Old 03-19-2020, 10:40 AM   #13
TonE
Human being with feelings
 
Join Date: Feb 2009
Location: Reaper HAS send control via midi !!!
Posts: 4,032
Default

None of the solutions so far works exactly as wanted. It works for the half correctly.

When the value jumps from 1 to 0, it works, meaning follows slowly, with inertia.

When the value jumps from 0 to 1, it does not work, it jumps up immediately, instead it should also follow slowly. Any quick changes should be prevented, this is the goal here. The essence of the entire story.

IX's solution works nicely, however I have no slider as input, but a variable.

Last edited by TonE; 03-19-2020 at 10:46 AM.
TonE is offline   Reply With Quote
Old 03-19-2020, 11:55 AM   #14
IXix
Human being with feelings
 
Join Date: Jan 2007
Location: mcr:uk
Posts: 3,891
Default

Quote:
Originally Posted by TonE View Post
IX's solution works nicely, however I have no slider as input, but a variable.
I just used a slider to illustrate how it works. All you do is feed the output slider a value...

Code:
@sample
output.target = someValue;
output.Update();
IXix is offline   Reply With Quote
Old 03-19-2020, 01:23 PM   #15
sai'ke
Human being with feelings
 
sai'ke's Avatar
 
Join Date: Aug 2009
Location: NL
Posts: 1,457
Default

I really like how clean your implementation was IXix
__________________
[Tracker Plugin: Thread|Github|Reapack] | [Routing Plugin: Thread|Reapack] | [More JSFX: Thread|Descriptions|Reapack]
sai'ke is offline   Reply With Quote
Old 03-19-2020, 01:55 PM   #16
IXix
Human being with feelings
 
Join Date: Jan 2007
Location: mcr:uk
Posts: 3,891
Default

Quote:
Originally Posted by sai'ke View Post
I really like how clean your implementation was IXix
Thanks!
IXix is offline   Reply With Quote
Old 03-19-2020, 02:55 PM   #17
Talagan
Human being with feelings
 
Join Date: Feb 2016
Location: Paris / France
Posts: 301
Default

Quote:
Originally Posted by TonE View Post
None of the solutions so far works exactly as wanted. It works for the half correctly.

When the value jumps from 1 to 0, it works, meaning follows slowly, with inertia.

When the value jumps from 0 to 1, it does not work, it jumps up immediately, instead it should also follow slowly. Any quick changes should be prevented, this is the goal here. The essence of the entire story.

IX's solution works nicely, however I have no slider as input, but a variable.
Maybe something's wrong somewhere else in your implementation? I don't see any problem with the above implementations when the value jumps from 0 to 1 (I'm not sure to understand what you mean, though). If you want a complete exemple, here's an extent of the precedent one:

Code:
desc:INERTIA TEST TALAGAN 2

slider1:0<0,100,1>parameter1
slider2:0<0,100,1>parameter2

@init

// How long the inertia will last
inertia       = 1;

// Time between two samples
sample_dt     = 1.0/srate;

// Initialisation of variable parameters
target        = slider1;
start         = target;
current       = start;
progress_time = 0;

@slider

// Slider event : update target and course parameters

(slider1 != target)?(
  target        = slider1;
  start         = current;
  progress_time = 0;
);

@sample

// Can be any interpolating function from 0..1 to 0..1
function interpolate01(progress_01) (
  sqrt(progress_01);
);

progress_01 = (inertia == 0)?(1):(progress_time/inertia);
progress_01 = (progress_01 > 1)?(1):(progress_01); // Clamp > 1
progress_01 = (progress_01 < 0)?(0):(progress_01); // Clamp < 0

current     = start + interpolate01(progress_01) * (target-start);
slider2     = current;
progress_time += sample_dt;
I have used a sqrt interpolator so that it slowly brakes when converging (but you can change the interpolator if you want as long as it is a function from 0..1 to 0..1). There are two sliders, slider2 is controlled by slider1 with inertia. You can play with slider1 and see the result on slider2

Last edited by Talagan; 03-19-2020 at 05:05 PM.
Talagan is offline   Reply With Quote
Reply

Thread Tools
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off

Forum Jump


All times are GMT -7. The time now is 04:48 AM.


Powered by vBulletin® Version 3.8.11
Copyright ©2000 - 2024, vBulletin Solutions Inc.