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 countdown
  • trig: the trigger signal (1: start at n; 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 value
  • trig: the trigger signal (1: start at 0; 0: increase until n)

(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 samples
  • p: 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 split
  • m: 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: list
  • p: 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: condition
  • cond: signal selected while cond is true
  • else: 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 samples
  • lgen: list of circuits
  • id: 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 function
  • end(x,y) to end a break-point function
  • point(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} when x < x_{0}
  • f(x) = y_{n} when x > x_{n}
  • f(x) = y_{i} + (y_{i+1}-y_{i})*(x-x_{i})/(x_{i+1}-x_{i}) when x_{i} <= x and x < 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 of index 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 crossfade
  • b: 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-light
  • slidingSump(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 samples
  • slidingMin(n,maxn): the sliding min of the last n input samples
  • slidingMean(n): the sliding mean of the last n input samples, CPU-light
  • slidingMeanp(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-light
  • slidingRMSp(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 process
  • maxN: the maximum number of values to process, needs to be a power of 2
  • op: 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 process
  • maxN: 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 process
  • maxN: 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 process
  • maxN: 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 process
  • maxN: 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 process
  • maxN: the maximum number of values to process, needs to be a power of 2