Skip to content

Faust adventures

March 2, 2012

Lately, I have been looking into faust – functional audio stream, an interesting language for DSP developed by the guys at GRAME, mainly Yann Orlarey and Stéphane Letz. This is a purely functional language for writing programs that can be compiled into C++ code for various platforms (PD, Csound, SC3 plugins; standalone applications; LLVM; mobile apps; etc). It has also a nice feature which lets you compile Mathematical documents from it to describe the DSP process implemented in the program.

The main thing about this is that we have to get into the functional mode of thinking in order to use and appreciate the system. For instance, typical imperative code will not be directly translatable to faust. Here are some basic elements of the language:

1) The entry point in faust is a ‘process’:

process =  ...

2) There are a basic set of language primitives: arithmetic and comparison operators (including bitwise operations); means of foreign (C++) function, variable and constant access; identity and cut ‘boxes’ (for passing or stopping signals); memory (single-sample) and delay operators; tables (read-only and read-write); selection switch; GUI components (slider, button, number box, etc.).

3) Programs combine these operations using one of five compositions: serial (:); parallel (,); split (<: merge=””>); recursion (~).</:>

and that’s it (there are some further language elements, but with these we can already do a lot).

Now the complication starts. Let’s program a simple sinewave signal. The first thing we need to do is to get a way to represent time in samples. In an imperative way, we could do this with a loop like this

for(i=0; i < end; i++) ...

Well, there are no loop primitives here. So what can we do? We use recursion. Here’s the time passing in faust:

time = (+(1) ~ _ )  - 1;

The recursion operator ~ combines a signal identity ( _ ), which can be understood as the output of the process, and the function +(1), which adds one to it. The recursive composition implies a 1-sample delay as the signal is fed back. So (+(1) ~ _ ) gives us a sequence 1,2,3,… . The subtraction by 1 is to bring the start of the sequence to 0, as we normally treat time sequences as 0-based.

Now, with time in hand, we can generate a sinewave signal. We need a sine function, which we can obtain as a C++ function using a primitive:

sine  =  ffunction(float sinf (float), <math.h>, "");</math.h>

Similarly we can define PI and SR constants

PI          = 3.1415926535897932385;
SR         = 44100.;

With this, we have a faust program that produces a 440Hz sinewave:

process =    time : *(2*PI/SR) : *(440) : sine;

You can see the (extreme) use of the serial composition operator. Start with the sample counter, multiply it by 2*PI/SR so the signal now goes from 0 to 2*PI in 44100 samples, then multiply it by 440Hz to make the signal go to multiples of 2*PI 440 times every 44100 samples. This signal then is sent to the sine function.

For those of you who find this too painful, faust allows a more usual function notation as syntatic sugar (not allowed for diabetics):

process =  sine(2*PI*440*time/SR);

So there you go, Faust. I will hopefully bring some further examples to the mix in later posts.

One Comment
  1. Hello my family member! I wish to say that this article is awesome,
    great written and come with approximately all vital infos.
    I would like to peer extra posts like this .

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: