FAUST (programming language)
||This article may contain too many colloquial terms, phrases or words. (September 2012)|
|Original author(s)||Yann Orlarey, Dominique Fober, Stéphane Letz|
|Developer(s)||GRAME, Centre National de Création Musicale|
|Stable release||0.9.67 / May 19, 2014|
|Operating system||Linux, Mac OS X, Windows, Unix|
|Type||Functional programming language for audio signal processing|
FAUST (Functional AUdio STream) is a programming language that provides a purely functional approach to signal processing while offering a high level of performance. FAUST aims at being complementary to existing audio languages by offering a viable and efficient alternative to C/C++ to develop signal processing libraries, audio plug-ins or standalone applications. The language is based on a simple and well defined formal semantics. A FAUST program denotes a signal processor, a mathematical function that transforms input signals into output signals.
The FAUST programming model combines a functional programming approach with a block-diagram syntax:
- The functional programming approach provides a natural framework for signal processing. Digital signals are modeled as discrete functions of time, signal processors as second order functions that operate on them, and FAUST’s block-diagram composition operators, used to combine signal processors together, as third order functions, etc. .
- Block-diagrams, even if purely textual like in FAUST, promote a modular approach of signal processing that suits very well the sound engineers’ and audio developers’ habits, while providing a powerful and expressive syntax.
A FAUST program doesn’t describe a sound or a group of sounds, but a signal processor, something that transforms input signals and produces output signals. The program source is organized as a set of definitions with at least the definition of the keyword process (the equivalent of main in C):
process = ...;
The FAUST compiler translates FAUST programs into equivalent C++ programs taking care of generating the most efficient code. The result can generally compete with, and sometimes even outperform, C++ code written by seasoned programmers.
The generated code works at the sample level. It is therefore suited to implement low-level DSP functions like recursive filters. Moreover the code can be easily embedded. It is self-contained and does not depend on any DSP library or runtime system. It has a very deterministic behaviour and a constant memory footprint.
The semantic of FAUST is simple and well defined. This is not just of academic interest. It allows the FAUST compiler to be semantically driven. Instead of compiling a program literally, it compiles the mathematical function it denotes. This feature is useful for example to promote components reuse while preserving optimal performance. Moreover having access to the exact semantics of a FAUST program can simplify preservation issues.
FAUST is a textual language but nevertheless block-diagram oriented. It actually combines two approaches: functional programming and algebraic block-diagrams. The key idea is to view block-diagram construction as function composition. For that, FAUST relies on a block-diagram algebra of five composition operations.
Let’s start with some really simple one-line examples of FAUST program. Here is a first example that produces silence:
process = 0;
The second example is a little bit more sophisticated and copies the input signal to the output signal. It involves the _ (underscore) primitive that denotes the identity function on signals (that is a simple audio cable for a sound engineer):
process = _;
Another very simple example is the conversion of a two-channel stereo signal into a one-channel mono signal using the + primitive that adds two signals together:
process = +;
Most FAUST primitives are analogous to their C counterpart on numbers, but lifted to signals. For example the FAUST primitive sin operates on a signal X by applying the C function sin to each sample X(t) of X. In other words sin transforms an input signal X into an output signal Y such that Y (t) = sin(X(t)). All C numerical functions have their counterpart in FAUST. Some signal processing primitives are specific to FAUST. For example the delay operator @ takes two input signals: X (the signal to be delayed) and D (the delay to be applied), and produces an output signal Y such that Y (t) = X(t − D(t)).
Contrary to Max-like visual programming languages where the user does manual connections, FAUST primitives are assembled in block diagrams by using a set of high-level block diagram composition operations. You can think of these composition operators as a generalization of the mathematical function composition operator.
|f~g||Recursive composition (precedence 4)|
|f,g||Parallel composition (precedence 3)|
|f:g||Sequential composition (precedence 2)|
|f<:g||Split composition (precedence 1)|
|f:>g||Merge composition (precedence 1)|
Let’s say that we want to connect the output of + to the input of abs in order to compute the absolute value of the output signal. This connection can be done using the sequential composition operator ':' (colon):
process = + : abs;
Here is an example of parallel composition (a stereo cable) using the operator ',' (comma) that puts in parallel its left and right expressions:
process = _,_;
These operators can be arbitrarily combined. For example to multiply the input signal by 0.5 one can write:
process = _,0.5 : *;
Taking advantage of some syntactic sugar the above example can be rewritten (using what functional programmers know as curryfication):
process = *(0.5);
The recursive composition operator '~' can be used to create block-diagrams with cycles (that include an implicit one-sample delay). Here is the example of an integrator that takes an input signal X and computes an output signal Y such that Y (t) = X(t) + Y(t−1):
process = + ~ _;
Full applications generation
Thanks to specific architecture files, a single FAUST program can be used to produce code for a variety of platforms and plug-in formats. These architecture files act as wrappers and describe the interactions with the host audio and GUI system. Currently more than 10 architectures are supported and new ones can be easily added.
|alsa-gtk.cpp||ALSA application + GTK|
|alsa-qt.cpp||ALSA application + QT4|
|au.cpp||Audio Unit plug-in|
|ca-qt.cpp||CoreAudio application + QT4|
|ios-coreaudio.cpp||iPhone and iPad applications|
|jack-gtk.cpp||JACK application + GTK|
|jack-qt.cpp||JACK application + QT4|
|max-msp.cpp||Max MSP plug-in|
|q.cpp||Q language plug-in|
|vsti-mono.cpp||Monophonic VST Instrument plug-in|
|vsti-poly.cpp||Polyphonic VST Instrument plug-in|
A useful option makes it possible to generates the block diagram representation of the program as one or more SVG graphic files. It is interesting to note the difference between the block diagram and the generated C++ code. As already said, the key idea here is not to compile the block diagram literally, but the mathematical function it denotes. Modern C/C++ compilers too don’t compile programs literally. But because of the complex semantic of C/C++ (due to side effects, pointer aliasing, etc.) they can’t go very far in that direction. This is a distinctive advantage of a purely functional language: it allows compilers to do very advanced optimisations.
Connection to Arrows
The Arrow combinators are more restrictive than their FAUST counterparts, e.g. the nesting of parallel composition is preserved and inputs of the operands of
&&& must match exactly. This allows to assign types to Arrow combinators and it prevents users from accidentally combining signal processors that do not match. In contrast to that, FAUST's split and merge operators automatically fill missing channels.
- Michon, Romain; Smith, Julius O. III (2011). "Faust-STK: a Set of Linear and Nonlinear Physical Models for the Faust Programming Language". Proceedings of the 11th Int. Conference on Digital Audio Effects (DAFx-11): 199–204.
- Fober, Dominique; Orlarey, Yann; Letz, Stéphane (2011). "Faust Architectures Design and OSC Support". Proceedings of the 11th Int. Conference on Digital Audio Effects (DAFx-11): 213–216.
- Smith, Julius O. III; Michon, Romain (2011). "Nonlinear Allpass Ladder Filters in Faust". Proceedings of the 11th Int. Conference on Digital Audio Effects (DAFx-11): 361–364.
- Jouvelot, Pierre; Orlarey, Yann (2011). "Dependent Vector Types for Data Structuring in Multirate Faust". Computer Languages, Systems and Structures - Elsevier.
- Smith III, Julius O. (2011). "Audio Signal Processing in Faust".
- Orlarey, Yann; Letz, Stéphane; Fober, Dominique (2010). "Automatic Parallelization of Audio Applications with Faust". Proceedings of the Congrès Français d'Acoustique.
- Letz, Stéphane; Orlarey, Yann; Fober, Dominique (2010). "Work Stealing Scheduler for Automatic Parallelization in Faust". Proceedings of the Linux Audio Conference (LAC-2010).
- Gräf, Albert (2010). "Term rewriting extension for the Faust programming language". Proceedings of the 8th International Linux Audio Conference (LAC-2010): 117.
- Barthélemy, Jérôme; Bonardi, Alain; Orlarey, Yann; Lemouton, Serge; Ciavarella, Raffaele; Barkati, Karim (2010). "First Steps Towards an Organology of Virtual Instruments in Computer Music". Proceedings of the 2010 International Computer Music Conference (ICMA-2010): 369–372.
- Jouvelot, Pierre; Orlarey, Yann (2010). "Depandant Vector Types for Multirate Faust". Proceedings of the 7th Sound an Music Computing Conference (SMC-2010): 345–352.
- Orlarey, Yann; Letz, Stéphane; Fober, Dominique (2009). "Adding Automatic Parallelization to Faust". Proceedings of the Linux Audio Conference (LAC-2009).
- Jouvelot, Pierre; Orlarey, Yann (2009). "Semantics for Multirate Faust". Technical Repports of Centre de Recherche en Informatique de MINES ParisTech.
- Orlarey, Yann; Fober, Dominique; Letz, Stéphane (2009). Parallelization of Audio Applications with Faust.
- Orlarey, Yann; Fober, Dominique; Letz, Stéphane (2009). "Faust: an Efficient Functional Approach to DSP Programming". New Computanionals Paradigms for Computer Music. Edition Delatour. ISBN 978-2-7521-0054-2.
- Orlarey, Yann; Letz, Stéphane; Fober, Dominique (2008). "Multicore Technologies in Jack and Faust". Proceedings of the 2010 International Computer Music Conference (ICMC-2008).
- Gräf, Albert (2007). "Interfacing Pure Data with Faust". Proceedings of the 5th International Linux Audio Conference (LAC2007): 24.
- Smith III, Julius O. (2007). "Appendix K. Digital Filtering in Faust and PD". Introduction to Digital Filters: With Audio Applications. W3K Publishing. pp. 417–?. ISBN 978-0-9745607-1-7.
- Gräf, Albert; Kersten, Stefan; Orlarey, Yann (2006). "DSP Programming with Faust, Q and SuperCollider". Proceedings of the 4th International Linux Audio Conference (LAC2006).
- Trausmuth, Robert; Dusek, Christian; Orlarey, Yann (2006). "Using Faust for FPGA Programming". Proceedings of the 9th Int. Conference on Digital Audio Effects (DAFx-09).
- Orlarey, Yann; Fober, Dominique; Letz, Stephone (2005). "Demonstration of Faust Signal Processing Language". Proceedings of the International Computer Music Conference 2005. Computer Music Association. p. 286.
- Orlarey, Yann; Fober, Dominique; Letz, Stéphane (2004). "Syntactical and Semantical Aspects of Faust". Soft Computing.
- Scaringella, Nicolas; Orlarey, Yann; Fober, Dominique (2003). "Automatic Vectorization in Faust". Journée de l'Informatique Musicale (JIM-2003).
- Orlarey, Yann; Fober, Dominique; Letz, Stéphane (2002). "An Algebraic Approach to Block Diagram Constructions". Journée de l'Informatique Musicale (JIM-2002).
- Orlarey, Yann; Fober, Dominique; Letz, Stéphane (2002). "An Algebra for Block Diagram Languages". Proceedings of International Computer Music Conference (ICMA-2002).