Lemur tutorial: Lagging fader

This tutorial show some examples for scripting with the Lemur. The topic is a lagging fader,
a fader which reaches smoothly a certain target value if a button is pressed. It is just a spotlight on scripting, but may help new users to get into it.

You can download the template "laggingfader2" here: http://www.jazzmutant.com/lemuruser_moduledetails.php?id=157
...but we will also build this template from scratch in this tutorial including some sideways to show interesting scripting techniques.

We gonna start with a simple situation: Imagine you want a fader to follow the movement of another fader.
Create a new interface on your Lemur, a container and 2 Faders inside. Name them "value" and "follower".
Now create a script on the highest hierarchical level in that container and name it "action". Make the script executed "on frame" and type in:


While typing you see that the script is first red - which means that it can not be executed - and turns to grey if all spelling is correct.
The end of a scriptline is always a semicolon ";".
After writing or changing a script you have to leave the script-editing (no more blinking cursor) by clicking somewhere else before the changes are taken over.
Your template should now look like this:


If you move the yellow value-fader the red follower-fader will follow. You can stop the script running by unchecking the little checkbox in front of the "action" (just try it out), but it might be better to create a switch on the Lemur to turn that script on and off. Therefore we create a switch and name it "go" and change the script as follows:

    if (go.x==1) follower.x=value.x;

Now the red still follows the yellow, but only if the go-switch is on, which means "1", and you can switch the following on and off.
With that "if"-term you can set a condition that must be true before the rest of the line is executed. The condition, following the "if" in brackets, is (go.x==1). That means our switch "go" "equals to" 1.

Well, it is nice to have a fader following immediately, but it is far away from a "lagging fader". To get into that, we first go a little sideway for demonstration: Imagine you want a automatic fade out on the red fader if the go button is pressed. The script therefore would be:

    if (go.x==1) follower.x=follower.x-0.002;

Now everytime the go-switch is on the red "follower" fader will smoothley fade down. Our if-condition doesn´t change, but the x-value of the "follower" is set to "follower.x-0.002". That means there is a quite tiny amount of the x (which is also the height of the fader) subtracted. As the script is executed "on frame", that substraction happens every frame, as long as our if-condition is still true (the go-switch is on), which will result in a fade out. If you want to change the speed of the fade out, you can change that number (try 0.005 or 0.001). Be aware that the terminus "speed" is not fully correct, because we didn´t change the timeline - it is still the framerate on the Lemur - but the amount of substraction each frame.
In a next step it would be nice to control the speed of the fade out with another fader on the Lemur. Create a fader inside the container, name it "speed" and change the script as follows:

    if (go.x==1) follower.x=follower.x-(speed.x/100);

Now you can control the speed of the fade out. As you see, we don´t use the output of "speed" directly, because it would be to large for substraction on each frame, but divide it through 100. The brackets are not really necessary in that case (from a mathematical point of view), but might help to see the arguments clearer. If you move the speed fader to 0 the fade out will stop, because 0/100 is 0 and nothing is subtracted.
Maybe you want to route that fade out to more than one fader. Let us take the 2nd fader called "value" for example. In this case there are 2 possible scripts. If you want to express it in one line it will be:

    if (go.x==1) (follower.x=follower.x-(speed.x/100)) && (value.x=value.x-(speed.x/100));

The term "&&" is a logical "and". Both arguments have to be in brackets to combine them that way.
A more elegant way to script more than one action inside a if condition is the following:

    if (go.x==1)

As you see the semicolon at the end of the first line is missing - thats an exception from the rule to end the line with a semicolon. We open the actions to do if the condition is true with "{" and close it with "}".

In a next step we want the go-switch to turn automatically off if the fadeout has ended and 0 is reached on both faders. Change the script like this:

    if (go.x==1)
    if (follower.x==0 && value.x==0) go.x=0;

We added another if condition - outside the first if condition - that says: if "follower.x" equals to 0 AND "value.x" equals to 0 then set "go.x" to 0. So we combined 2 arguments to be true before the action is executed. You can combine them also with an OR, so each time one of the 2 faders reaches 0 the go-switch turns off and therefore the fadeout stops. In that case the last line of the script would be:
    if (follower.x==0 || value.x==0) go.x=0;

For a complete list of operators refer to the Lemur manual or go through the multiline scripting tutorial: http://www.jazzmutant.com/workshop_tutorialslist.php?id=multilineA

But now it is time to come to our lagging fader. The basic script would be:

    if (go.x==1 && value.x<follower.x) follower.x=follower.x-(speed.x/100);
    if (go.x==1 && value.x>follower.x) follower.x=follower.x+(speed.x/100);

Both lines differ only very slightly, but are necessary for movements in both directions - until now we always faded down, which is the first line. Fade up - if our "value" is higher then the "follower" - is done in the 2nd line of the script. The "-" just turns into a "+".
Inside the if-condition we combined 2 arguments. But we could also exclude the "go.x==1" because it is the same in both and write the script another way:

    if (go.x==1)
    if(value.x<follower.x) follower.x=follower.x-(speed.x/100);
    if(value.x>follower.x) follower.x=follower.x+(speed.x/100);
    else return;

The 2 if-conditions for both directions are nested inside the first if condition that states that the go-switch has to be activated.
The "else return" is not necessary.... it works also without.

Now you have a fader that follows the other fader with a controlable speed and a switch to turn that function on and off.

No big deal at all....but there is a little problem left. To see that problem insert 2 monitors inside your container and enter at the properties "value.x" and "follower.x" with precision "3" as value. Now you can see that the follower doesn´t match the target-value exactly. It is not a big difference, but according to the application it can matter, so we will get rid of that. The reason for the difference is the stepsize we do in "speed". As you remember, it wasn´t speed but the size of step we add/substract each frame. These steps doesn´t necessarily fit in matching the target - it gets better if you make the steps smaller (lower "speed") - but we will correct that by a little jump to the target value if it is pretty much reached. Furthermore we will add an automatic off for the go-switch if the fading is done.

Including these the final script is:

    if (go.x==1 && value.x<follower.x)
    if (value.x>=follower.x) go.x=0 && (follower.x=value.x);
    if (go.x==1 && value.x>follower.x)
    if (value.x<=follower.x) go.x=0 && (follower.x=value.x);

Line 1-5 is for fading down, line 6-10 for fading up. The if-conditions in line 4 and 9 are nested inside the other if-conditions.

Line 4 (which is part of fade down) says: if the value is bigger or equal than the follower, deactivate the go-switch and set the follower to the (exact) value. Because for fading down, which was chosen in line1 to be true, the value couldn´t be bigger than the follower, and so we have an overshoot to correct.

Line 9 (which is part of fade up) says: if the value is smaller or equal than the follower, deactivate the go-switch and set the follower to the (exact) value.
Because for fading up, which was chosen in line5 to be true, the value couldn´t be smaller than the follower, and so we have an undershoot to correct.

Hm... hope you don´t get to confused here.....but now the follower exactly matches the value :-)
(...as long as you don´t route it to any midicontroller with midifeedback....why? Because midi is limited to 127 values and the midifeedback on the "follower" will cause a little jump to the real Midivalue, which doesn´t correspond to the chosen value on the Lemur (more than 127 values!).... so, not perfect)

You can apply this kind of movement to any Lemur-object, e.g. try a Multiball....
This tutorial was just a little spotlight what you can do with the scripting on the Lemur. I hope you enjoyed it and maybe it could bring up some help or new ideas.
Enjoy :-)

For questions please refer to the thread at the Jazzmutants page:

For more interesting templates and tutorials see http://www.music-interface.com  

G*Matthias (mat@tonvibration.de)