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 on every tick.
- Expression Value Filter: filters values suitable for the device explorer.
- Arraygen: generates an array of values.
- Arraymap: applies the function to each value of the input array.
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);
Using arrays in ExprTK
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]
.
Note that it isn’t possible to create dynamic arrays in ExprTK. To return an array, it has to be wrapped in an array itself and then unwrapped with an Object filter:
Alternatively, the Arraygen object can be used to create an array from a generator expression.
Using Arraygen
Arraygen will generate an array with as many elements as chosen.
The expression will be used to generate each element.
i
represents the current element index, starting from zero and n
is useable as the total count of elements.
Arraygen can also return arrays:
Download the example score here.
## Using Arraymap {#arraymap}
Arraymap applies the expression to every element used as input. The same variables are useable than for Arraygen, the only difference is that triggering is bound to the presence of an input value instead of the timeline.
Available variables
Everywhere
t
: the current time in flicks.pos
: the position in the interval
Value filter, Value generator, Audio filter, Audio generator
a, 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 filter, Micromap, Arraymap
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 valuedt
: the time delta
Value filter, Micromap
xv
: the value of the current input if it is an arraypxv
: the value of the previous input if it was an arraypov
: the value of the previous output if it was an array
Value generator
dt
: the time deltapo
: the value of the previous output
Audio filter
x
: the value of the current sampleout
: where to write the outputpx
: the value of the previous samplefs
: the sampling rate
Audio generator
out
: where to write the outputfs
: the sampling rate
Arraymap, Arraygen
i
: the current indexn
: the total count
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);
}