ExprTK support
Several processes allow to write simple math expressions. Such processes include:
- Micromap: for very simple math expressions, e.g.
x * 100
. - Expression Audio Generator: generates multi-channel audio.
- Expression Audio Filter: filters multi-channel audio.
- Expression Value Generator: generates values suitable for the device explorer.
- Expression Value Filter: filters values suitable for the device explorer.
These expressions are evaluated within score using the ExprTK library.
The expression can be written in the process built-in editor on multiple lines.
Numerous math functions are available: sin
, cos
, abs
, log
, as well as the usual pi
, etc. constants.
Audio handling
For audio processes, the processing is done per-frame. The input x
is an array, where x[0]
is the first channel, x[1]
the second channel, etc.
Note that ExprTK has powerful array processing features; the following two codes implement the same distortion:
// This is the syntax to get the size of the array
// e.g. the number of channels here:
var n := x[];
for (var i := 0; i < n; i += 1) {
var dist := tan(x[i]*log(1 + 200 * a));
out[i] := clamp(-1, dist, 1);
}
out := clamp(-1, tan(x * log(1 + 200 * a)), 1);
Array handling
For value processes, the same expression syntax cannot be used for single-value or array input:
- Use
x
,px
,po
to write an expression that processes single values, e.g. a float input. - Use
xv
,pxv
,pov
to write an expression that processes arrays.
For instance:
tanh(x + 1)
will process a single float as input, while:
return [ xv[0] cos(xv[1]), xv[0] sin(xv[1]) ];
will take a vec2 that contains polar coordinates [r, theta]
and convert it into cartesian coordinates [x, y]
.
Available variables
Everywhere
t
: the current timepos
: the position in the intervala, b, c
: three provided controlspa, pb, pc
: previous value of a, b, cm1, m2, m3
: three provided variables (which will keep their value across a tick)- In the audio cases they are arrays.
Value mapping
x
: the value of the current input if it’s a single valuepx
: the value of the previous input if it was a single valuepo
: the value of the previous output if it was a single valuexv
: the value of the current input if it’s an arraypxv
: the value of the previous input if it was an arraypov
: the value of the previous output if it was an arraydt
: the time delta
Audio mapping
x
: the value of the current sampleout
: where to write the outputpx
: the value of the previous samplefs
: the sampling rate
Value generator
dt
: the time delta
Audio generator
out
: where to write the outputfs
: the sampling rate
Available functions
ExprTK-provided functions:
- Basic math:
min, max, avg, sum, abs, ceil, floor, round, roundn, exp, log, log10, logn, pow, root, sqrt, clamp, inrange, swap
- Trigonometry:
sin, cos, tan, acos, asin, atan, atan2, cosh, cot, csc, sec, sinh, tanh, d2r, r2d, d2g, g2d, hyp
- Numeric integration and differentiation
- Vector Processing:
BLAS-L1 (axpy, axpby, axpb), all/any-true/false, count, rotate-left/right, shift-left/right, sort, nth_element, iota, sum, kahan-sum, dot-product, copy
score-provided functions
random(min, max)
: returns a random real number in the given interval.random(0, 1)
can be 0., 0.3, 0.23455436, 1.round(random(1, 20))
is a 20-sided dice with lower probabilities for 1, 20.floor(random(1, 21))
is a 20-sided dice with same probabilities for everyone.
noise(t, octaves, persistence)
: Perlin noise.t
should be something that increases ;pos
is generally a good candidate.octaves
: the higher this is, the more detailed the noise is. 2 would be smooth, 7 very detailed but more computationally intensive. Between 1 and 10.persistence
: how much each octave fades. 1: no fade, very noisy. 0: very smooth.5 * (noise(pos * 100, 4, 0.5) - 0.5)
gives a convincing fairly dynamic noise between -1 and 1.noise(pos * 10, 3, 0.1)
gives a very smooth evolution between 0 and 1.
Examples
The user library comes with a few utility functions, be sure to check them in the preset pane !
Contributing useful functions to the library is also very welcome.
Value generator
Logistic function
Implemented as a preset (Logistic
):
if(m1 == 0) {
m2 := 0.8;
m1 := 1;
}
var r := 4 * a;
m2 := r * m2 * (1 - m2)
Value mapper
Add noise
Implemented as a preset (Noisify
):
var rnd_m := pow(2, 31);
var rnd_a := 1103515245;
var rnd_c := 12345;
if(m2 == 0) {
m2 := 1;
m1 := 12345678;
}
var r := (rnd_a * m1 + rnd_c) % rnd_m;
m1 := r;
x + a * r / (2^33);
Audio generator
Sine wave
Implemented as a preset (Sine
):
var phi := 2 * pi * (20 + a * 500) / fs;
m1[0] += phi;
out[0] := b * cos(m1[0]);
out[1] := b * cos(m1[0]);
Square wave
Implemented as a preset (Square
):
var phi := 2 * pi * (20 + a * 500) / fs;
m1[0] += phi;
var f := cos(m1[0]) > 0 ? b : -b;
out[0] := f;
out[1] := f;
Wobbly synth
Implemented as a preset (Wobbly
):
var freq_l := 225 + cos(t/(100*(a+0.1)));
freq_l := 2 * pi * m1[0] * freq_l * b / fs;
var freq_r := 215 + sin(t/(100*(a+0.1)));
freq_r := 2 * pi * m1[0] * freq_l * b / fs;
m1[0] += 1;
out[0] := b * cos( freq_l );
out[1] := b * cos( freq_r );
Audio filter
Crude distortion
2-channel version:
out[0] := clamp(0, tan(x[0]*log(1 + 200 * a)), 1);
out[1] := clamp(0, tan(x[1]*log(1 + 200 * a)), 1);
Any number of channel version:
var n := x[];
for (var i := 0; i < n; i += 1) {
var dist := tan(x[i]*log(1 + 200 * a));
out[i] := clamp(-1, dist, 1);
}