basics.lib
A library of basic elements. Its official prefix is ba
.
Conversion Tools
(ba.)samp2sec
Converts a number of samples to a duration in seconds.
samp2sec
is a standard Faust function.
Usage
samp2sec(n) : _
Where:
n
: number of samples
(ba.)sec2samp
Converts a duration in seconds to a number of samples.
samp2sec
is a standard Faust function.
Usage
sec2samp(d) : _
Where:
d
: duration in seconds
(ba.)db2linear
Converts a loudness in dB to a linear gain (0-1).
db2linear
is a standard Faust function.
Usage
db2linear(l) : _
Where:
l
: loudness in dB
(ba.)linear2db
Converts a linear gain (0-1) to a loudness in dB.
linear2db
is a standard Faust function.
Usage
linear2db(g) : _
Where:
g
: a linear gain
(ba.)lin2LogGain
Converts a linear gain (0-1) to a log gain (0-1).
Usage
lin2LogGain(n) : _
(ba.)log2LinGain
Converts a log gain (0-1) to a linear gain (0-1).
Usage
log2LinGain(n) : _
(ba.)tau2pole
Returns a real pole giving exponential decay.
Note that t60 (time to decay 60 dB) is ~6.91 time constants.
tau2pole
is a standard Faust function.
Usage
_ : smooth(tau2pole(tau)) : _
Where:
tau
: time-constant in seconds
(ba.)pole2tau
Returns the time-constant, in seconds, corresponding to the given real,
positive pole in (0,1).
pole2tau
is a standard Faust function.
Usage
pole2tau(pole) : _
Where:
pole
: the pole
(ba.)midikey2hz
Converts a MIDI key number to a frequency in Hz (MIDI key 69 = A440).
midikey2hz
is a standard Faust function.
Usage
midikey2hz(mk) : _
Where:
mk
: the MIDI key number
(ba.)hz2midikey
Converts a frequency in Hz to a MIDI key number (MIDI key 69 = A440).
hz2midikey
is a standard Faust function.
Usage
hz2midikey(f) : _
Where:
f
: frequency in Hz
(ba.)semi2ratio
Converts semitones in a frequency multiplicative ratio.
semi2ratio
is a standard Faust function.
Usage
semi2ratio(semi) : _
Where:
semi
: number of semitone
(ba.)ratio2semi
Converts a frequency multiplicative ratio in semitones.
ratio2semi
is a standard Faust function.
Usage
ratio2semi(ratio) : _
Where:
ratio
: frequency multiplicative ratio
(ba.)pianokey2hz
Converts a piano key number to a frequency in Hz (piano key 49 = A440).
Usage
pianokey2hz(pk) : _
Where:
pk
: the piano key number
(ba.)hz2pianokey
Converts a frequency in Hz to a piano key number (piano key 49 = A440).
Usage
hz2pianokey(f) : _
Where:
f
: frequency in Hz
Counters and Time/Tempo Tools
(ba.)countdown
Starts counting down from n included to 0. While trig is 1 the output is n.
The countdown starts with the transition of trig from 1 to 0. At the end
of the countdown the output value will remain at 0 until the next trig.
countdown
is a standard Faust function.
Usage
countdown(n,trig) : _
Where:
n
: the starting point of the countdowntrig
: the trigger signal (1: start atn
; 0: decrease until 0)
(ba.)countup
Starts counting up from 0 to n included. While trig is 1 the output is 0.
The countup starts with the transition of trig from 1 to 0. At the end
of the countup the output value will remain at n until the next trig.
countup
is a standard Faust function.
Usage
countup(n,trig) : _
Where:
n
: the maximum count valuetrig
: the trigger signal (1: start at 0; 0: increase untiln
)
(ba.)sweep
Counts from 0 to period-1
repeatedly, generating a
sawtooth waveform, like os.lf_rawsaw,
starting at 1 when run
transitions from 0 to 1.
Outputs zero while run
is 0.
Usage
sweep(period,run) : _
(ba.)time
A simple timer that counts every samples from the beginning of the process.
time
is a standard Faust function.
Usage
time : _
(ba.)ramp
An linear ramp of 'n' samples to reach the next value
Usage
_ : ramp(n) : _
Where:
n
: number of samples to reach the next value
(ba.)tempo
Converts a tempo in BPM into a number of samples.
Usage
tempo(t) : _
Where:
t
: tempo in BPM
(ba.)period
Basic sawtooth wave of period p
.
Usage
period(p) : _
Where:
p
: period as a number of samples
(ba.)pulse
Pulses (10000) generated at period p
.
Usage
pulse(p) : _
Where:
p
: period as a number of samples
(ba.)pulsen
Pulses (11110000) of length n
generated at period p
.
Usage
pulsen(n,p) : _
Where:
n
: pulse length as a number of samplesp
: period as a number of samples
(ba.)cycle
Split nonzero input values into n
cycles.
Usage
_ : cycle(n) <:
Where:
n
: the number of cycles/output signals
(ba.)beat
Pulses at tempo t
.
beat
is a standard Faust function.
Usage
beat(t) : _
Where:
t
: tempo in BPM
(ba.)pulse_countup
Starts counting up pulses. While trig is 1 the output is counting up, while trig is 0 the counter is reset to 0.
Usage
_ : pulse_countup(trig) : _
Where:
trig
: the trigger signal (1: start at next pulse; 0: reset to 0)
(ba.)pulse_countdown
Starts counting down pulses. While trig is 1 the output is counting down, while trig is 0 the counter is reset to 0.
Usage
_ : pulse_countdown(trig) : _
Where:
trig
: the trigger signal (1: start at next pulse; 0: reset to 0)
(ba.)pulse_countup_loop
Starts counting up pulses from 0 to n included. While trig is 1 the output is counting up, while trig is 0 the counter is reset to 0. At the end of the countup (n) the output value will be reset to 0.
Usage
_ : pulse_countup_loop(n,trig) : _
Where:
n
: the highest number of the countup (included) before reset to 0.trig
: the trigger signal (1: start at next pulse; 0: reset to 0)
(ba.)resetCtr
Function that lets through the mth impulse out of
each consecutive group of n
impulses.
Usage
_ : resetCtr(n,m) : _
Where:
n
: the total number of impulses being splitm
: index of impulse to allow to be output
(ba.)pulse_countdown_loop
Starts counting down pulses from 0 to n included. While trig is 1 the output is counting down, while trig is 0 the counter is reset to 0. At the end of the countdown (n) the output value will be reset to 0.
Usage
_ : pulse_countdown_loop(n,trig) : _
Where:
n
: the highest number of the countup (included) before reset to 0.trig
: the trigger signal (1: start at next pulse; 0: reset to 0)
Array Processing/Pattern Matching
(ba.)count
Count the number of elements of list l.
count
is a standard Faust function.
Usage
count(l)
count((10,20,30,40)) -> 4
Where:
l
: list of elements
(ba.)take
Take an element from a list.
take
is a standard Faust function.
Usage
take(P,l)
take(3,(10,20,30,40)) -> 30
Where:
P
: position (int, known at compile time, P > 0)l
: list of elements
(ba.)subseq
Extract a part of a list.
Usage
subseq(l, p, n)
subseq((10,20,30,40,50,60), 1, 3) -> (20,30,40)
subseq((10,20,30,40,50,60), 4, 1) -> 50
Where:
l
: listp
: start point (0: begin of list)n
: number of elements
Note:
Faust doesn't have proper lists. Lists are simulated with parallel compositions and there is no empty list.
Selectors (Conditions)
(ba.)if
if-then-else implemented with a select2. WARNING : since select2 is strict (always evaluating both branches), the resulting if does not have the usual "lazy" semantic of the C if form, and thus cannot be used to protect against forbidden computations like division-by-zero for instance.
Usage
if(cond, then, else) : _
Where:
cond
: conditioncond
: signal selected while cond is trueelse
: signal selected while cond is false
(ba.)selector
Selects the ith input among n at compile time.
Usage
selector(I,N)
_,_,_,_ : selector(2,4) : _ selects the 3rd input among 4
Where:
I
: input to select (int, numbered from 0, known at compile time)N
: number of inputs (int, known at compile time, N > I)
There is also cselector for selecting among complex input signals of the form (real,imag).
(ba.)select2stereo
Select between 2 stereo signals.
Usage
_,_,_,_ : select2stereo(bpc) : _,_
Where:
bpc
: the selector switch (0/1)
(ba.)selectn
Selects the ith input among N at run time.
Usage
selectn(N,i)
_,_,_,_ : selectn(4,2) : _ selects the 3rd input among 4
Where:
N
: number of inputs (int, known at compile time, N > 0)i
: input to select (int, numbered from 0)
Example test program
N = 64;
process = par(n, N, (par(i,N,i) : selectn(N,n)));
(ba.)selectmulti
Selects the ith circuit among N at run time (all should have the same number of inputs and outputs) with a crossfade.
Usage
selectmulti(n,lgen,id)
Where:
n
: crossfade in sampleslgen
: list of circuitsid
: circuit to select (int, numbered from 0)
Example test program
process = selectmulti(ma.SR/10, ((3,9),(2,8),(5,7)), nentry("choice", 0, 0, 2, 1));
process = selectmulti(ma.SR/10, ((_*3,_*9),(_*2,_*8),(_*5,_*7)), nentry("choice", 0, 0, 2, 1));
Other
(ba.)latch
Latch input on positive-going transition of "clock" ("sample-and-hold").
Usage
_ : latch(clocksig) : _
Where:
clocksig
: hold trigger (0 for hold, 1 for bypass)
(ba.)sAndH
Sample And Hold.
sAndH
is a standard Faust function.
Usage
_ : sAndH(t) : _
Where:
t
: hold trigger (0 for hold, 1 for bypass)
(ba.)downSample
Down sample a signal. WARNING: this function doesn't change the
rate of a signal, it just holds samples...
downSample
is a standard Faust function.
Usage
_ : downSample(freq) : _
Where:
freq
: new rate in Hz
(ba.)peakhold
Outputs current max value above zero.
Usage
_ : peakhold(mode) : _;
Where:
mode
means:
1 - Track and hold max value.
(ba.)peakholder
Tracks abs peak and holds peak for 'n' samples.
Usage
_ : peakholder(n) : _;
Where:
n
: number of samples
(ba.)impulsify
Turns a signal into an impulse with the value of the current sample
(0.3,0.2,0.1 becomes 0.3,0.0,0.0). This function is typically used with a
button
to turn its output into an impulse. impulsify
is a standard Faust
function.
Usage
button("gate") : impulsify;
(ba.)automat
Record and replay to the values the input signal in a loop.
Usage
hslider(...) : automat(bps, size, init) : _
(ba.)bpf
bpf is an environment (a group of related definitions) that can be used to create break-point functions. It contains three functions:
start(x,y)
to start a break-point functionend(x,y)
to end a break-point functionpoint(x,y)
to add intermediate points to a break-point function
A minimal break-point function must contain at least a start and an end point:
f = bpf.start(x0,y0) : bpf.end(x1,y1);
A more involved break-point function can contains any number of intermediate points:
f = bpf.start(x0,y0) : bpf.point(x1,y1) : bpf.point(x2,y2) : bpf.end(x3,y3);
In any case the x_{i}
must be in increasing order (for all i
, x_{i} < x_{i+1}
).
For example the following definition :
f = bpf.start(x0,y0) : ... : bpf.point(xi,yi) : ... : bpf.end(xn,yn);
implements a break-point function f such that:
f(x) = y_{0}
whenx < x_{0}
f(x) = y_{n}
whenx > x_{n}
f(x) = y_{i} + (y_{i+1}-y_{i})*(x-x_{i})/(x_{i+1}-x_{i})
whenx_{i} <= x
andx < x_{i+1}
bpf
is a standard Faust function.
(ba.)listInterp
Linearly interpolates between the elements of a list.
Usage
index = 1.69; range is 0-4
process = listInterp((800,400,350,450,325),index);
Where:
index
: the index (float) to interpolate between the different values. The range ofindex
depends on the size of the list.
(ba.)bypass1
Takes a mono input signal, route it to e
and bypass it if bpc = 1
.
bypass1
is a standard Faust function.
Usage
_ : bypass1(bpc,e) : _
Where:
bpc
: bypass switch (0/1)e
: a mono effect
(ba.)bypass2
Takes a stereo input signal, route it to e
and bypass it if bpc = 1
.
bypass2
is a standard Faust function.
Usage
_,_ : bypass2(bpc,e) : _,_
Where:
bpc
: bypass switch (0/1)e
: a stereo effect
(ba.)bypass1to2
Bypass switch for effect e
having mono input signal and stereo output.
Effect e
is bypassed if bpc = 1
.
bypass1to2
is a standard Faust function.
Usage
_ : bypass1(bpc,e) : _,_
Where:
bpc
: bypass switch (0/1)e
: a mono-to-stereo effect
(ba.)bypass_fade
Bypass an arbitrary (N x N) circuit with 'n' samples crossfade. Once bypassed the
effect is replaced by par(i,N,_). Bypassed circuits can be chained.
Usage
_ : bypass_fade(n,b,e) : _
or
_,_ : bypass_fade(n,b,e) : _,_
n
: number of samples for the crossfadeb
: bypass switch (0/1)e
: N x N circuit
Examples
process = bypass_fade(ma.SR/10, checkbox("bypass echo"), echo);
process = bypass_fade(ma.SR/10, checkbox("bypass reverb"), freeverb);
(ba.)toggle
Triggered by the change of 0 to 1, it toggles the output value between 0 and 1.
Usage
_ : toggle : _
Examples
button("toggle") : toggle : vbargraph("output", 0, 1)
(an.amp_follower(0.1) > 0.01) : toggle : vbargraph("output", 0, 1) takes audio input
(ba.)on_and_off
The first channel set the output to 1, the second channel to 0.
Usage
_ , _ : on_and_off : _
Example
button("on"), button("off") : on_and_off : vbargraph("output", 0, 1)
(ba.)selectoutn
Route input to the output among N at run time.
Usage
_ : selectoutn(N, i) : _,_,...N
Where:
N
: number of outputs (int, known at compile time, N > 0)i
: output number to route to (int, numbered from 0) (i.e. slider)
Example
process = 1 : selectoutn(3, sel) : par(i, 3, vbargraph("v.bargraph %i", 0, 1));
sel = hslider("volume", 0, 0, 2, 1) : int;
Sliding Reduce
Provides various operations on the last N samples using a high order `slidingReduce(op,N,maxN,disabledVal,x)`` fold-like function:
slidingSum(n)
: the sliding sum of the last n input samples, CPU-lightslidingSump(n,maxn)
: the sliding sum of the last n input samples, numerically stable "forever"slidingMax(n,maxn)
: the sliding max of the last n input samplesslidingMin(n,maxn)
: the sliding min of the last n input samplesslidingMean(n)
: the sliding mean of the last n input samples, CPU-lightslidingMeanp(n,maxn)
: the sliding mean of the last n input samples, numerically stable "forever"slidingRMS(n)
: the sliding RMS of the last n input samples, CPU-lightslidingRMSp(n,maxn)
: the sliding RMS of the last n input samples, numerically stable "forever"
Working Principle
If we want the maximum of the last 8 values, we can do that as:
simpleMax(x) =
(
(
max(x@0,x@1),
max(x@2,x@3)
) :max
),
(
(
max(x@4,x@5),
max(x@6,x@7)
) :max
)
:max;
max(x@2,x@3)
is the same as max(x@0,x@1)@2
but the latter re-uses a
value we already computed,so is more efficient. Using the same trick for
values 4 trough 7, we can write:
efficientMax(x)=
(
(
max(x@0,x@1),
max(x@0,x@1)@2
) :max
),
(
(
max(x@0,x@1),
max(x@0,x@1)@2
) :max@4
)
:max;
We can rewrite it recursively, so it becomes possible to get the maximum at have any number of values, as long as it's a power of 2.
recursiveMax =
case {
(1,x) => x;
(N,x) => max(recursiveMax(N/2,x) , recursiveMax(N/2,x)@(N/2));
};
What if we want to look at a number of values that's not a power of 2?
For each value, we will have to decide whether to use it or not.
If N is bigger than the index of the value, we use it, otherwise we replace
it with (0-(ma.INFINITY)
):
variableMax(N,x) =
max(
max(
(
(x@0 : useVal(0)),
(x@1 : useVal(1))
):max,
(
(x@2 : useVal(2)),
(x@3 : useVal(3))
):max
),
max(
(
(x@4 : useVal(4)),
(x@5 : useVal(5))
):max,
(
(x@6 : useVal(6)),
(x@7 : useVal(7))
):max
)
)
with {
useVal(i) = select2((N>=i) , (0-(ma.INFINITY)),_);
};
Now it becomes impossible to re-use any values. To fix that let's first look
at how we'd implement it using recursiveMax, but with a fixed N that is not
a power of 2. For example, this is how you'd do it with N=3
:
binaryMaxThree(x) =
(
recursiveMax(1,x)@0, the first x
recursiveMax(2,x)@1 the second and third x
):max;
N=6
binaryMaxSix(x) =
(
recursiveMax(2,x)@0, first two
recursiveMax(4,x)@2 third trough sixth
):max;
Note that recursiveMax(2,x)
is used at a different delay then in
binaryMaxThree
, since it represents 1 and 2, not 2 and 3. Each block is
delayed the combined size of the previous blocks.
N=7
binaryMaxSeven(x) =
(
(
recursiveMax(1,x)@0, first x
recursiveMax(2,x)@1 second and third
):max,
(
recursiveMax(4,x)@3 fourth trough seventh
)
):max;
To make a variable version, we need to know which powers of two are used, and at which delay time.
Then it becomes a matter of:
- lining up all the different block sizes in parallel: the first
par()
statement - delaying each the appropriate amount:
sumOfPrevBlockSizes()
- turning it on or off:
useVal()
- getting the maximum of all of them:
combine()
In Faust, we can only do that for a fixed maximum number of values: maxN
variableBinaryMaxN(N,maxN,x) =
par(i,maxNrBits,recursiveMax(pow2(i),x)@sumOfPrevBlockSizes(N,maxN,i) : useVal(i)) : combine(maxNrBits) with {
The sum of all the sizes of the previous blocks
sumOfPrevBlockSizes(N,maxN,0) = 0;
sumOfPrevBlockSizes(N,maxN,i) = (subseq((allBlockSizes(N,maxN)),0,i):>_);
allBlockSizes(N,maxN) = par(i, maxNrBits, pow2(i) * isUsed(i) );
maxNrBits = int2nrOfBits(maxN);
get the maximum of all blocks
combine(2) = max;
combine(N) = max(combine(N-1),_);
Decide wether or not to use a certain value, based on N
useVal(i) = select2( isUsed(i), (0-(ma.INFINITY)),_);
isUsed(i) = take(i+1,(int2bin(N,maxN)));
};
(ba.)slidingReduce
Fold-like high order function. Apply a commutative binary operation <op>
to
the last <n>
consecutive samples of a signal <x>
. For example :
slidingReduce(max,128,128,-(ma.INFINITY))
will compute the maximum of the last
128 samples. The output is updated each sample, unlike reduce, where the
output is constant for the duration of a block.
Usage
_ : slidingReduce(op,N,maxN,disabledVal) : _
Where:
N
: the number of values to processmaxN
: the maximum number of values to process, needs to be a power of 2op
: the operator. Needs to be a commutative one.disabledVal
: the value to use when we want to ignore a value.
In other words, op(x,disabledVal)
should equal to x
. For example,
+(x,0)
equals x
and min(x,ma.INFINITY)
equals x
. So if we want to
calculate the sum, we need to give 0 as disabledVal
, and if we want the
minimum, we need to give ma.INFINITY
as disabledVal
.
(ba.)slidingSum
The sliding sum of the last n input samples.
It will eventually run into numerical trouble when there is a persistent dc component. If that matters in your application, use the more CPU-intensive (ba.)slidingSump.
Usage
_ : slidingSum(N) : _
Where:
N
: the number of values to process
(ba.)slidingSump
The sliding sum of the last n input samples.
It uses a lot more CPU then (ba.)slidingSum(n,maxn), but is numerically stable "forever" in return.
Usage
_ : slidingSump(N,maxN) : _
Where:
N
: the number of values to processmaxN
: the maximum number of values to process, needs to be a power of 2
(ba.)slidingMax
The sliding maximum of the last n input samples.
Usage
_ : slidingMax(N,maxN) : _
Where:
N
: the number of values to processmaxN
: the maximum number of values to process, needs to be a power of 2
(ba.)slidingMin
The sliding minimum of the last n input samples.
Usage
_ : slidingMin(N,maxN) : _
Where:
N
: the number of values to processmaxN
: the maximum number of values to process, needs to be a power of 2
(ba.)slidingMean
The sliding mean of the last n input samples.
It will eventually run into numerical trouble when there is a persistent dc component. If that matters in your application, use the more CPU-intensive (ba.)slidinRMSp.
Usage
_ : slidingMean(N,maxN) : _
Where:
N
: the number of values to process
(ba.)slidingMeanp
The sliding mean of the last n input samples.
It uses a lot more CPU then (ba.)slidingMean(n,maxn), but is numerically stable "forever" in return.
Usage
_ : slidingMeanp(N,maxN) : _
Where:
N
: the number of values to processmaxN
: the maximum number of values to process, needs to be a power of 2
(ba.)slidingRMS
The root mean square of the last n input samples.
It will eventually run into numerical trouble when there is a persistent dc component. If that matters in your application, use the more CPU-intensive (ba.)slidinRMSp.
Usage
_ : slidingRMS(N) : _
Where:
N
: the number of values to process
(ba.)slidingRMSp
The root mean square of the last n input samples.
It uses a lot more CPU then (ba.)slidingRMS(n,maxn), but is numerically stable "forever" in return.
Usage
_ : slidingRMSp(N,maxN) : _
Where:
N
: the number of values to processmaxN
: the maximum number of values to process, needs to be a power of 2