FAUST (programming language)

Last updated
FAUST
Original author(s) Yann Orlarey, Dominique Fober, Stéphane Letz
Developer(s) GRAME, Centre National de Création Musicale
Initial release2002 (2002)
Stable release
2.54.9 [1] / December 18, 2022 (2022-12-18)
Written in C++
Operating system Linux, OS X, Windows, Unix
Type Functional programming language for audio signal processing
License GPL
Website faust.grame.fr

FAUST (Functional AUdio STream) is a domain-specific purely functional programming language for implementing signal processing algorithms in the form of libraries, audio plug-ins, or standalone applications. A FAUST program denotes a signal processor: a mathematical function that is applied to some input signal and then fed out.

Contents

Overview

The FAUST programming model combines a functional programming approach with a block diagram syntax:

A FAUST program doesn’t describe a sound or a group of sounds, but a signal processor. 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 code into a C++ object, which may then interface with other C++ code to produce a full program.

The generated code works at the sample level. It is therefore suited to implement low-level DSP functions like recursive filters. The code may also be embedded. It is self-contained and does not depend on any DSP library or runtime system. It has a very deterministic behavior and a constant memory size.

The semantics of FAUST is driven to be simple and well-defined. It allows the FAUST compiler to be semantically driven. Instead of compiling a program literally, it compiles the mathematical function it denotes. This may promote component reuse. Moreover, having access to the exact semantics of a FAUST program can simplify preservation issues.

FAUST is a textual language but block diagram oriented. It combines two approaches: functional programming and algebraic block diagrams, which are constructed via function composition. For that, FAUST relies on a block diagram algebra of five composition operations.

Example code

FAUST programs define a process function that operates on incoming data. This is analogous to the main function in most programming languages. The following is an example that produces silence:

process=0;

The second example copies the input signal to the output. It involves the _ primitive that denotes the identity function for signals:

process=_;

Another example sums a stereo signal into a mono signal using the + primitive:

process=+;
Block diagrams generated by Faust from some simple programs Faust-simple-block-diagram.jpg
Block diagrams generated by Faust from some simple programs

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]. 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)).

Block diagram composition

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.

Simple examples of block diagram composition Faust-simple-block-diagrams.jpg
Simple examples of block diagram composition
The block diagram composition operators used in FAUST
f~gRecursive composition (precedence 4)
f,gParallel composition (precedence 3)
f:gSequential composition (precedence 2)
f<:gSplit composition (precedence 1)
f:>gMerge composition (precedence 1)

Using the sequential composition operator : the output of + can be routed to the input of abs to compute the absolute value of the signal:

process=+:abs;

Here is an example of parallel composition using the , operator that arranges its left and right expressions in parallel. This is analogous to a stereo cable.

process=_,_;

These operators can be arbitrarily combined. The following code multiplies an input signal with 0.5:

process=_,0.5:*;

The above may be rewritten in curried form:

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 an 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=+~_;

Generating full applications

Using specific architecture files, a 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. As of 2021, more than 30 architectures are supported and new ones may be implemented by anyone.

Screenshot of mixer.dsp (available in the FAUST distribution) using the jack-qt architecture Faust-mixer-jackqt.jpg
Screenshot of mixer.dsp (available in the FAUST distribution) using the jack-qt architecture
Some architecture files available for FAUST
alsa-gtk.cppALSA application + GTK
alsa-qt.cppALSA application + QT4
android.cppAndroid applications
au.cppAudio Unit plug-in
ca-qt.cppCoreAudio application + QT4
ios-coreaudio.cppiPhone and iPad applications
jack-gtk.cppJACK application + GTK
jack-qt.cppJACK application + QT4
ladspa.cppLADSPA plug-in
max-msp.cppMax MSP plug-in
pd.cppPuredata plug-in
q.cppQ language plug-in
supercollider.cppSupercollider plug-in
vst.cppVST plug-in
vsti-mono.cppMonophonic VST Instrument plug-in
vsti-poly.cppPolyphonic VST Instrument plug-in

Generating block diagrams

A useful option makes it possible to generate the block diagram representation of the program as one or more SVG graphic files.

It is useful to note the difference between the block diagram and the generated C++ code. As stated, the key idea here is not to compile the block diagram literally, but the mathematical function it denotes. Modern C/C++ compilers also don’t compile programs literally. But because of the complex semantics of C/C++ (due to side effects, pointer aliasing, etc.) they can’t go very far in that direction. This is a distinct advantage of a purely functional language: it allows compilers to do very advanced optimisations.

Arrows-like semantics

The Faust semantics is almost the same as that of Haskell's Arrows type class. However, the Arrow type class is not bound to signal processors.

Equivalences between FAUST and Arrow combinators
f~gloop((\(a,b)->(b,a))^>>f>>>id&&&(delay>>>g)) where delay is not a method of the Arrow type class, but is specific to signal processing arrows
f,gf***g
f:gf>>>g
f<:gf>>^h>>>g with appropriate function h (or &&& in special cases)
f:>gf>>^h>>>g with appropriate function h

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.

Related Research Articles

Procedural programming is a programming paradigm, derived from imperative programming, based on the concept of the procedure call. Procedures simply contain a series of computational steps to be carried out. Any given procedure might be called at any point during a program's execution, including by other procedures or itself. The first major procedural programming languages appeared circa 1957–1964, including Fortran, ALGOL, COBOL, PL/I and BASIC. Pascal and C were published circa 1970–1972.

In computer science, a compiler-compiler or compiler generator is a programming tool that creates a parser, interpreter, or compiler from some form of formal description of a programming language and machine.

In computer engineering, a hardware description language (HDL) is a specialized computer language used to describe the structure and behavior of electronic circuits, and most commonly, digital logic circuits.

Csound is a domain-specific computer programming language for audio programming. It is called Csound because it is written in C, as opposed to some of its predecessors.

<span class="mw-page-title-main">State diagram</span> Diagram of behavior of finite state systems

A state diagram is a type of diagram used in computer science and related fields to describe the behavior of systems. State diagrams require that the system described is composed of a finite number of states; sometimes, this is indeed the case, while at other times this is a reasonable abstraction. Many forms of state diagrams exist, which differ slightly and have different semantics.

In programming language theory, semantics is the rigorous mathematical study of the meaning of programming languages. Semantics assigns computational meaning to valid strings in a programming language syntax.

<span class="mw-page-title-main">ChucK</span> Audio programming language

ChucK is a concurrent, strongly timed audio programming language for real-time synthesis, composition, and performance, which runs on Linux, Mac OS X, Microsoft Windows, and iOS. It is designed to favor readability and flexibility for the programmer over other considerations such as raw performance. It natively supports deterministic concurrency and multiple, simultaneous, dynamic control rates. Another key feature is the ability to live code; adding, removing, and modifying code on the fly, while the program is running, without stopping or restarting. It has a highly precise timing/concurrency model, allowing for arbitrarily fine granularity. It offers composers and researchers a powerful and flexible programming tool for building and experimenting with complex audio synthesis programs, and real-time interactive control.

<span class="mw-page-title-main">Max (software)</span> Visual programming language

Max, also known as Max/MSP/Jitter, is a visual programming language for music and multimedia developed and maintained by San Francisco-based software company Cycling '74. Over its more than thirty-year history, it has been used by composers, performers, software designers, researchers, and artists to create recordings, performances, and installations.

<span class="mw-page-title-main">Visual programming language</span> Programming language written graphically by a user

In computing, a visual programming language or block coding is a programming language that lets users create programs by manipulating program elements graphically rather than by specifying them textually. A VPL allows programming with visual expressions, spatial arrangements of text and graphic symbols, used either as elements of syntax or secondary notation. For example, many VPLs are based on the idea of "boxes and arrows", where boxes or other screen objects are treated as entities, connected by arrows, lines or arcs which represent relations.

In computer science, a continuation is an abstract representation of the control state of a computer program. A continuation implements (reifies) the program control state, i.e. the continuation is a data structure that represents the computational process at a given point in the process's execution; the created data structure can be accessed by the programming language, instead of being hidden in the runtime environment. Continuations are useful for encoding other control mechanisms in programming languages such as exceptions, generators, coroutines, and so on.

In computer programming, dataflow programming is a programming paradigm that models a program as a directed graph of the data flowing between operations, thus implementing dataflow principles and architecture. Dataflow programming languages share some features of functional languages, and were generally developed in order to bring some functional concepts to a language more suitable for numeric processing. Some authors use the term datastream instead of dataflow to avoid confusion with dataflow computing or dataflow architecture, based on an indeterministic machine paradigm. Dataflow programming was pioneered by Jack Dennis and his graduate students at MIT in the 1960s.

<span class="mw-page-title-main">Block diagram</span> Graphical system analysis method

A block diagram is a diagram of a system in which the principal parts or functions are represented by blocks connected by lines that show the relationships of the blocks. They are heavily used in engineering in hardware design, electronic design, software design, and process flow diagrams.

<span class="mw-page-title-main">IDEF0</span>

IDEF0, a compound acronym, is a function modeling methodology for describing manufacturing functions, which offers a functional modeling language for the analysis, development, reengineering and integration of information systems, business processes or software engineering analysis.

The zero-crossing rate (ZCR) is the rate at which a signal changes from positive to zero to negative or from negative to zero to positive. Its value has been widely used in both speech recognition and music information retrieval, being a key feature to classify percussive sounds.

In computer programming, homoiconicity is a property of some programming languages. A language is homoiconic if a program written in it can be manipulated as data using the language, and thus the program's internal representation can be inferred just by reading the program itself. This property is often summarized by saying that the language treats code as data.

In computer programming, flow-based programming (FBP) is a programming paradigm that defines applications as networks of "black box" processes, which exchange data across predefined connections by message passing, where the connections are specified externally to the processes. These black box processes can be reconnected endlessly to form different applications without having to be changed internally. FBP is thus naturally component-oriented.

Functional reactive programming (FRP) is a programming paradigm for reactive programming using the building blocks of functional programming. FRP has been used for programming graphical user interfaces (GUIs), robotics, games, and music, aiming to simplify these problems by explicitly modeling time.

<span class="mw-page-title-main">Functional flow block diagram</span>

A functional flow block diagram (FFBD) is a multi-tier, time-sequenced, step-by-step flow diagram of a system’s functional flow. The term "functional" in this context is different from its use in functional programming or in mathematics, where pairing "functional" with "flow" would be ambiguous. Here, "functional flow" pertains to the sequencing of operations, with "flow" arrows expressing dependence on the success of prior operations. FFBDs may also express input and output data dependencies between functional blocks, as shown in figures below, but FFBDs primarily focus on sequencing.

SIGNAL is a programming language based on synchronized data-flow : a process is a set of equations on elementary flows describing both data and control.

SequenceL is a general purpose functional programming language and auto-parallelizing compiler and tool set, whose primary design objectives are performance on multi-core processor hardware, ease of programming, platform portability/optimization, and code clarity and readability. Its main advantage is that it can be used to write straightforward code that automatically takes full advantage of all the processing power available, without programmers needing to be concerned with identifying parallelisms, specifying vectorization, avoiding race conditions, and other challenges of manual directive-based programming approaches such as OpenMP.

References