Contents

Operators

Akkado uses operators for arithmetic, comparison, logic, and signal flow.

Operator precedence

From highest to lowest precedence:

PrecedenceOperatorNameAssociativityExample
9 (highest)(...), f(...)Call, groupLeftlp(sig, 800)
8!Prefix NOTRight!gate
7^PowerRightx ^ 2
6* / @Multiply, divide, moduloLefta * b
5+ -Add, subtractLefta + b
4> < >= <=ComparisonLeftx > 0
3== !=EqualityLeftx == 0
2&&Logical ANDLefta && b
1\|\|Logical ORLefta \|\| b
0 (lowest)\|>PipeLefta \|> b

Arithmetic operators

All arithmetic operators work on signals at audio rate:

// Addition - mix two oscillators
sine(220) + sine(330) |> out(@)

// Subtraction - phase cancellation
sine(220) - sine(220.5) |> out(@)

// Multiplication - amplitude modulation
sine(220) * sine(5) |> out(@)

// Division - scaling
saw(110) / 2 |> out(@)

// Power - exponential curves
lfo(0.5) ^ 2 |> out(@)

Comparison operators

Compare two signals sample-by-sample. Output is 1.0 (true) or 0.0 (false).

// Gate from a continuous signal
lfo(0.5) > 0 |> ar(@, 0.01, 0.1) |> out(@)

// Square wave from a sine via threshold
sine(440) > 0 |> out(@)

// Range detection
freq = lfo(0.5) * 1000
in_range = (freq >= 200) && (freq <= 800)

== and != use an epsilon of 1e-6, so floating-point drift does not produce false negatives.

Logic operators

Combine boolean signals. Inputs are treated as truthy when > 0. Outputs are 0.0 or 1.0.

// Layered gates
g1 = n"1 0 0 0"
g2 = n"0 0 1 0"
combined = g1 || g2  // "1 0 1 0"

// Accent only when both conditions fire
loud = lfo(0.5) > 0.5
hit = trigger(4)
band = loud && hit

// Inverse gate, fires when there's no trigger
sustain = !trigger(4)

Conditional selection

There is no infix ternary; use the select function:

// Switch oscillators based on a gate
gate = n"1 0 1 0"
select(gate, saw(440), sqr(220)) |> out(@)

Operator desugaring

All operators are converted to function calls during parsing:

OperatorDesugars To
a + badd(a, b)
a - bsub(a, b)
a * bmul(a, b)
a / bdiv(a, b)
a ^ bpow(a, b)
a > bgt(a, b)
a < blt(a, b)
a >= bgte(a, b)
a <= blte(a, b)
a == beq(a, b)
a != bneq(a, b)
a && bband(a, b)
a \|\| bbor(a, b)
!abnot(a)

The pipe operator

The |> operator defines signal flow. It has the lowest precedence so it always splits an expression at the natural boundary:

// Signal flows left to right
saw(110) |> lp(@, 800) |> out(@)

See Pipes & Holes for full details.

The hole operator

The @ symbol is an explicit input port:

// @ refers to the left-hand side of |>
saw(110) |> lp(@, 500) |> out(@)

Combining operators

Operators follow precedence rules:

// Multiplication before addition
a + b * c    // equals a + (b * c)

// && binds tighter than ||
1 || 0 && 0  // equals 1 || (0 && 0) = 1

// Comparison binds tighter than logic
5 > 3 && 2 < 4  // equals (5 > 3) && (2 < 4) = 1

// Arithmetic binds tighter than comparison
2 + 3 > 4    // equals (2 + 3) > 4 = 1

// Use parentheses to override
(a + b) * c

Unary minus

Negation works on numbers and signals:

// Negative number
saw(-110)   // Won't work - use neg()

// Correct way
saw(110) |> neg(@) |> out(@)

// Or multiply by -1
saw(110) * -1 |> out(@)

Related: Pipes & Holes, Math Functions, Conditionals & Logic