Skip to content

Conditions and Logic ​

A script that only prints what it was given is a calculator. It becomes useful the moment it can look at a value and decide. A pan control at zero should say Centre rather than 0. A level of zero has no decibel value at all and needs a word instead of a number. A message that a capture played back should not be forwarded a second time. All of these are decisions, and in Lua a decision is an if.

The if statement ​

The shape is always the same: if, a condition, then, the lines to run when the condition holds, and end:

lua
local velocity = 100

if velocity > 64 then
    print("a hard hit")
end

If the condition is true, the lines between then and end run. If it is false, Lua skips to the end and carries on. Change 100 to 40, send again, and the log stays quiet.

The condition is built with a comparison. Lua has six of them, and five look the way you expect: <, <=, >, >= and == for equal to. The odd one out is ~=, which means not equal to. The double == matters: a single = is an assignment, and if x = 5 then is not a decision but an error. Every Lua programmer has typed it at least once.

More than one answer ​

When there are several possibilities, elseif asks the next question and else catches whatever is left. Here is the panning example, written as a function so that we can try it with several values at once:

lua
function describePan(value)
    if value == 0 then
        return "Centre"
    elseif value < 0 then
        return "L " .. -value
    else
        return "R " .. value
    end
end

print(describePan(0))
print(describePan(-32))
print(describePan(17))

The log reads Centre, L 32 and R 17. Lua checks the conditions from the top and takes the first one that is true. Note the -value in the middle branch: the number there is negative, and the minus sign turns it back into a distance.

If you give a control the formatter formatPan from the Formatting Values tutorial, this is exactly the function doing the work on the screen. Functions are the subject of a later chapter; for now, read describePan(-32) as run those lines with value set to -32.

Guarding against the impossible ​

Sometimes a condition is there not to choose between answers, but to step around a case that would otherwise fail. A level in decibels is twenty times the logarithm of the level, and the logarithm of zero does not exist:

lua
function describeLevel(value)
    if value == 0 then
        return "-inf dB"
    end

    return string.format("%.1f dB", 20 * math.log(value / 127, 10))
end

print(describeLevel(0))
print(describeLevel(64))
print(describeLevel(127))

The log shows -inf dB, -6.0 dB and 0.0 dB. The if at the top has no else. When the value is zero the function answers and is finished; when it is anything else, the if does nothing and the line after it runs. This shape, deal with the awkward case first and then get on with the normal one, is so common that it has a name, the guard clause, and you will see it in nearly every script in the tutorials.

Combining conditions ​

Three words combine conditions: and, or and not. They read like English, which is a rare gift in a programming language:

lua
local note = 60
local velocity = 0

if velocity == 0 or note > 127 then
    print("treat as a note off")
end

if note >= 36 and note <= 96 then
    print("within the keyboard")
end

if not timer.isEnabled() then
    print("the timer is off")
end

All three lines print. The first one is the rule from the Introduction to MIDI: a Note On with velocity zero means be quiet. The script makes that rule explicit in one readable line.

When you mix and and or in one condition, use parentheses to say what you mean. Lua has rules about which binds tighter, but nobody reading your script should have to remember them.

What counts as true ​

Here is the one rule in this chapter that surprises people coming from other languages. In Lua, only false and nil are false. Everything else is true, including zero and the empty string:

lua
local lives = 0

if lives then
    print("this line runs, because 0 is true")
end

if lives ~= 0 then
    print("this line does not")
end

The upside is that checking whether something exists is very short. A control that has no override gives you nil, so if name then reads as if there is a name. The downside is that if value then is not a test for a non-zero value. When you mean zero, write ~= 0.

A condition that does something ​

So far our conditions have chosen text. A condition can just as well choose an action. This function is the example from the Lua reference, and it belongs in a control's Function field rather than its Formatter: the controller calls it whenever the value changes, and the function colours the control orange when the value is high.

lua
function highlightOnOverload(valueObject, value)
    local control = valueObject:getControl()

    if value > 100 then
        control:setColor(ORANGE)
    else
        control:setColor(WHITE)
    end
end

To try it, put a fader on the page, type highlightOnOverload into its Function field (Expert mode), send to Electra, and turn the knob past 100. We have not talked about valueObject or the colon in control:setColor yet; they belong to the chapter on objects. The if in the middle is the part that matters here, and you can already read it.

What comes next ​

A decision is made once. The next chapter is about doing something many times: ten bytes of a name, eight operators of a DX7, every note of a chord.

Electra One proudly uses Lua and ArduinoJson.
For support contact info@electra.one · © 2019-2026 Electra One