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:
follower.x=value.x;
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)
{
follower.x=follower.x-(speed.x/100);
value.x=value.x-(speed.x/100);
}
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)
{
follower.x=follower.x-(speed.x/100);
value.x=value.x-(speed.x/100);
}
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;
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)
{
follower.x=follower.x-(speed.x/100);
if (value.x>=follower.x) go.x=0 &&
(follower.x=value.x);
}
if (go.x==1 && value.x>follower.x)
{
follower.x=follower.x+(speed.x/100);
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 :-)