Open-source project
grame-cncm/faust avatar
grame-cncm/faust

Faust: a compiled functional language for DSP, and how to get a first binary out of it

Functional programming language for signal processing and sound synthesis

3,173 stars431 forksC++NOASSERTION

At a glance

What is it?
Faust turns a signal-processing specification into C++, C, Java, LLVM IR or WebAssembly at sample level. This is what the compiler actually does, how the CMake build and the faust2 tools fit together, and where the approach stops being the right one.
Who is it for?
Adopt Faust if you write DSP that has to ship to several targets and you would rather maintain one specification than four hand-written implementations; the compiler and the faust2 scripts are the whole point. Do not adopt it if you need a language where you can hand-tune the inner loop per target, or if you expect the README alone to get you through the build: it points at the wiki instead.
Can I use it commercially?
Check first. The repository uses a licence we do not classify automatically, so read its LICENSE file before any commercial use.
Is it still maintained?
Yes. The repository last received commits 1 day ago.
What is it written in?
Mainly C++, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on September 30, 2026, and from our analysis. They are not legal advice.

Editorial analysis

What Faust solves, and who it is for

Faust is a functional programming language for real-time signal processing and synthesis, developed mainly at Grame, Centre National de Creation Musicale. The problem it addresses is portability of DSP code. A single specification is meant to produce a native standalone application, an iOS or Android app, or a plugin in Csound, LADSPA, Max/MSP, PD, Q, SuperCollider, VST or AU, without rewriting the algorithm for each host. The README's framing is that a Faust specification is fully compiled, not interpreted at run time.

The audience is therefore narrower than "audio programmers" in general. It suits people who already know what a delay line, a biquad or a wavetable is, and who are tired of maintaining the same filter in three plugin formats. It also suits researchers who need to express a signal chain compactly and then measure it. It is a poor fit for someone who wants to write a DSP algorithm in C and step through it in a debugger line by line, because the code you debug is generated, not written.

The compiler pipeline: one specification, many backends

The core of the project is in the compiler/ folder, and the README describes the translation as happening at sample level: the compiler emits code that processes audio one sample at a time, in the target language you select. The backends listed in the README include C, C++, Java, LLVM IR and WebAssembly. Because LLVM IR can be produced and then JIT-compiled, Faust can be embedded inside a C++ program through a library called libfaust, which the README says is needed by sister projects including FaustLive, FaucK and faustgen~.

The repository is organised so that this split is visible. compiler/ holds the compiler itself, architecture/ holds the architecture files for supported targets, libraries/ holds the DSP libraries, examples/ holds example programs by category, and tools/ holds the faust2... scripts that wrap compilation into a binary or a plugin. The README notes that the libraries now live in a separate project, grame-cncm/faustlibraries, and are pulled in as a git submodule, along with oboe, faust2ck, py2max and node-matcher-plugin. That submodule arrangement matters operationally: the Makefile targets begin with an updatesubmodules step, so a fresh clone is not a complete source tree until the submodules are fetched.

One design consequence worth stating plainly: the quality of the output depends on the backend, not only on your specification. A specification that compiles cleanly to C++ may take a different path through the WebAssembly backend, and the README does not claim that every backend produces identical numerics or identical performance. If your project targets one platform only, you are paying the cost of a multi-backend compiler to use one backend.

Installing Faust and compiling a first example

The README states that since release 2.5.18 compilation and installation is based on CMake, and it directs readers to the Faust wiki pages or to the simple tutorial at github.com/grame-cncm/faust/wiki/BuildingSimple for details. The README itself does not contain a step-by-step build recipe, so the commands below come from the repository's own Makefile and Dockerfile rather than from the README prose.

The Makefile exposes several targets with different scope. compiler builds a regular set of backends, most builds a wider set, all builds everything, and developer builds all backends with developer targets. A minimal build looks like this:

bash
make compiler

That target first updates the submodules and then runs the CMake configuration under build/ with BACKENDS=regular.cmake and TARGETS=regular.cmake, followed by the actual build. If you need the broadest set of targets, the Makefile offers:

bash
make all

The repository also ships a Dockerfile that builds Faust inside debian:stable-slim. It installs build-essential, llvm, libncurses-dev, libncursesw6, libmicrohttpd-dev, git, cmake and pkg-config, copies the tree into /faust, runs make and make install, then purges the build toolchain and sets the entry point to /usr/local/bin/faust. If you would rather not install the toolchain locally, that file is the reference for what a working build environment needs.

Once the compiler is installed, examples/ contains example programs organised by category: analysis, delayEcho, filtering, generator, physicalModeling, reverb, spat and others. The README points at three zero-configuration browser tools for trying them without a local build: the Online Faust Editor at fausteditor.grame.fr, the Online Faust IDE at faustide.grame.fr, and Faust Playground. For a first local run, the tools/ folder holds the faust2... scripts that turn a .dsp file into a binary or a plugin; the README does not enumerate their flags, so check the README inside tools/ before assuming a target name.

Where the build and the documentation will bite you

The README is explicit that it is not the installation guide: it sends you to the wiki. That is a real cost for anyone evaluating the project on a deadline, because the repository's own top-level file does not tell you which packages to install for which backend, or what to do when a backend is missing at configure time. The Dockerfile gives one known-good package list for Debian, and it is a short list, but it is tied to that image.

The submodule dependency is the second friction point. libraries, tools/faust2ck, architecture/android/app/oboe, architecture/smartKeyboard/android/app/oboe, architecture/max-msp/py2max and node-matcher-plugin are all submodules, and the README documents the update-and-commit dance needed to synchronise them. A shallow clone or a tarball that skips submodules will not build the full set of targets. The README also notes that the currently used stable py2max version is v0.4.1, which tells you the submodule pointers are not always at the newest upstream commit.

Branch discipline is the third thing to understand before you file a bug. master-dev is described as the preferred development branch and as the main development branch, while master is kept functional and merged from master-dev around releases. If you build from master-dev, you are building the branch the developers commit to, not the branch the README describes as always functional.

Faust against writing the DSP by hand, and against a host-native language

The obvious alternative is writing the algorithm directly in C++ against your host's SDK, which is what most plugin developers do. The difference is not speed of the generated code in the abstract; it is where the work lives. With hand-written C++ you control the inner loop exactly, you can use the host's own SIMD conventions, and you can attach a debugger to the code you wrote. With Faust you give up that control in exchange for one specification that can be retargeted, and you accept generated code as the artifact you ship.

A second alternative, for people who want a language rather than a compiler, is to stay inside the host's own scripting or patching environment, for example writing the same signal chain as a patch. That keeps you in a familiar tool and avoids a build step, but it ties the algorithm to that host. Faust's whole premise, stated in the README, is the opposite: the same specification should reach Csound, LADSPA, Max/MSP, PD, Q, SuperCollider, VST and AU, plus iOS and Android apps. If you only ever ship to one of those, the multi-target machinery is overhead you are carrying for nothing.

A third comparison the README makes implicitly is with interpretation. Faust is fully compiled, so there is no run-time interpreter between your specification and the samples. That is the design bet: more work at build time, less at run time. It also means your build pipeline, not your audio callback, is where things go wrong.

Licence and upgrade cost

The repository's licence field is NOASSERTION and the top-level tree contains a COPYING.txt file. GitHub could not map the project to a standard licence identifier, so the only reliable way to know your obligations is to read COPYING.txt in the repository and, if you are distributing a plugin, to have someone qualified read it with you. Nothing here is legal advice, and the licence identifier on the repository page is not a substitute for the file itself.

Upgrade cost is shaped by the release cadence visible in the release list: 2.85.5 in March 2026, 2.85.9 in July 2026, and 2.88.0 in September 2026, with the Makefile in the tree already carrying version 2.89.2. That is a project that moves. The practical consequence is that generated code, architecture files and the faust2 scripts can all change between the version you pinned and the version you upgrade to, so the thing to re-test on upgrade is not the compiler build but the output: regenerate your DSP, rebuild your plugin, and listen. The README gives no rollback procedure and no compatibility statement for generated code, so pin a version in your build and treat the upgrade as a change to your shipped artifact.

What to check before you commit to Faust

Start with the target list, not the language. The README says an exhaustive list of supported architectures lives in the README inside architecture/, and the faust2 scripts live in tools/. Confirm that the specific target you need is present in both places before you invest in writing specifications. If your target is not there, the multi-backend promise does not apply to you.

Then confirm the build on your own machine. The Makefile's compiler target is the smallest useful build, and the Dockerfile is the reference for the packages it needs on Debian. If your platform is not Debian-based, the README does not give you a package list, so budget time for that.

Finally, decide which branch you are building. master-dev is where development happens, master is the branch kept functional for releases. For a product, the release packages linked from the repository are the safer starting point than the development branch, and the version number in the Makefile is a reminder that the tree you clone may already be ahead of the last release.

Editorial conclusion

Adopt Faust if you write DSP that has to ship to several targets and you would rather maintain one specification than four hand-written implementations; the compiler and the faust2 scripts are the whole point. Do not adopt it if you need a language where you can hand-tune the inner loop per target, or if you expect the README alone to get you through the build: it points at the wiki instead. Before committing, verify that the faust2 script for your actual target exists in tools/, that the LLVM and libmicrohttpd packages the Dockerfile installs are available on your machine, and that the generated code passes your own listening and CPU tests.

Frequently asked questions

What is Faust?

Faust (Functional Audio Stream) is a functional programming language designed for real-time signal processing and synthesis, developed mainly at Grame, Centre National de Creation Musicale. The README states that it is fully compiled and translates DSP specifications into efficient code for C++, C, Java, LLVM IR, WebAssembly and other targets.

How to install Faust?

The README says that since release 2.5.18 compilation and installation is based on CMake, and it points to the wiki pages and the BuildingSimple tutorial for details. The repository's Makefile provides targets such as make compiler and make all, and the Dockerfile shows a Debian package set that includes llvm, cmake and libmicrohttpd-dev.

How to use Faust?

You write a DSP specification and compile it to a target language or platform; the README lists examples in the examples/ folder organised by category and faust2... scripts in tools/ that produce binaries and plugins. For a local build, the Makefile's compiler target builds a regular set of backends before you compile anything with the resulting faust binary.

Is Faust hard to read?

The README does not comment on the readability of Faust source. What it does say is that the language is functional and fully compiled, and that a single specification can be retargeted to many platforms, which is the property the syntax is built around.

Official sources

  1. grame-cncm/faust on GitHub
  2. Issues
  3. Project website
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/grame-cncm-faust.svg)](https://hysenlabs.com/projects/grame-cncm-faust)