This is an online version of the Audio Plug-Ins Designed with Faust workshop that took place at CCRMA (Stanford University) on July 6-10 2015. It aims at giving a broad introduction to digital signal processing and to the Faust programming language. By the end of this course, students should have a full collection of plug-ins usable in various DAWs and computer music environments. While previous experience in programming is helpful but not required to take this course, we expect students to have basic notions of algebra, calculus and to have some experience using computers to make music.

Additional information on the different topics treated in this course can be found in Julius Orion III Smith's book series:

For any question/comment/suggestion, please contact me.

Content

1. Installing Faust
         Linux
         MacOSX
         Windows
2. Introduction/What is Faust?
3. Basic Notions of Acoustics and Digital Audio Technologies
4. Faust Semantic Basics and Simple Audio Effects: Panner and Tremolo
         Simple Gain Controller
         Simple Panner
         Tremolo
5. Ring Modulation (Amplitude Modulation)
         Ring Modulator
         Stereo Ring Modulation (Automated Panning)
6. Additive Synthesis
         Simple Additive Synthesizer
7. Delay and Tour of oscillator.lib
         Different Kinds of Delays in Faust
8. One Zero Lowpass/Highpass Filter, Feed-Forward Comb Filter and Simple Flanger
         "One Zero" Lowpass / Highpass Filter
         Feed-Forward Comb Filter
         Simple Feed-Forward Flanger
9. Debugging and Generating Plug-ins
10. Iteration
         Additive Synthesizer with Independent Frequency Control
11. Recursion: Echo Effect and Feedback Comb Filter
         Echo Effect
         Feedback Comb Filter
12. Introduction to Physical Modeling
         Karplus-Strong: Virtual String
13. Other Kinds of Filters and Filter Bank
         Filter Bank
14. Cubic Distortion
         Cubic Distortion Plug-in
15. Vocoder and Conditions
         Vocoder
16. Guest Lecture by Julius Smith: Signal Processing Libraries for Faust
17. Reverb
         Simple Schroeder Reverberator: Freeverb
17. Dynamic Range Compression
         Dynamic Range Compressor

1. Installing Faust: Getting Ready for the Course

Linux

If you encounter a problem during one of the following steps, feel free to send me an e-mail.

While the Faust compiler itself was designed to not rely on any external library, some of the tools gravitating around Faust do have a few dependencies. Thus you need to make sure that the following packages are installed on your system before we begin: git, llvm (3.4), llvm-dev (3.4), libmicrohttpd and qjackctl.

For the workshop, we will use some of the latest features of Faust so it is strongly recommended that you compile and install Faust from the Git repository. For that, open a terminal window, cd to the location where you want to download Faust's source code and then type:

git clone git://git.code.sf.net/p/faudiostream/code faudiostream-code
cd faudiostream-code
git checkout faust2
make
sudo make install

Hopefully, everything went well and now if you type: faust and press the return key in your terminal, the following message should be returned: ERROR : no files specified; for help type "faust --help". However, if you get something like faust: command not found, something probably went wrong.

Next, we need to install FaustLive which is an "on-the-fly" compiler for Faust (we'll see during the workshop what this means). It is a great tool that enables you to compile Faust codes "almost in real-time" and that makes programming in Faust very smooth. While it is strongly recommended that you compile it from the source, you can try to download and run this pre-compiled version (64 bits only) directly. Otherwise, open a terminal window and cd to the location where you want to download FaustLive's source code and type:

git clone git://git.code.sf.net/p/faudiostream/faustlive faudiostream-faustlive
cd faudiostream-faustlive
make
sudo make install

You should keep Faust's source code for the workshop: it will be probably helpful.

Hopefully, things went well. To see if it worked just type: FaustLive & in your terminal and the FaustLive interface should appear. If it does, hooray! You're now ready to code in Faust!

Optionally, you can also get the following packages: lv2-dev, ladspa-sdk, libjack-jackd2-dev and libgtk2.0-dev as well as any dependency related to a specific Faust architecture (to get a non-exhaustive list, just type faust2 in a terminal and then press the TAB key).

MacOSX

In order to install some of Faust's dependencies, you will have to use the terminal of your laptop that you can find in the Applications folder. If you never used it before, keep in mind that you have to press the return key after every command. Commands are indicated in this document using this font. This might sound stupid but don't forget to press the return key to run each command :). If you encounter a problem during one of the following steps, feel free to send me an e-mail.

The first thing you want to do is to install FaustLive. It is an "on-the-fly" compiler for Faust (we'll see during the workshop what this means) that will make your coding experience a very smooth one. For that, download FaustLive and follow the install instructions.

To make sure that it worked, open FaustLive and try to open one of the examples like "harpeautomation". If it makes sound, it's a good sign: you're now ready to start coding in Faust!

While FaustLive is great for prototyping, it's missing many "deeper" features of Faust which is why you should still install the Faust compiler. Before you do that, you should make sure that Xcode (developer and command line tools) is installed on your system.

For the workshop, we will use some of the latest features of Faust so it is strongly recommended that you compile and install Faust from the Git repository. For that, create a new folder in your home directory (or anywhere else) called faust. Open a terminal window, and type: cd faust which means "go to the faust folder" from your home directory and press the return key. After that, type the following commands to download, compile and install the Faust compiler:

git clone git://git.code.sf.net/p/faudiostream/code faudiostream-code
cd faudiostream-code
make
sudo make install

You should keep the faust folder for the workshop: it will be probably helpful. If things went well, Faust should now be installed on your system. To make sure that it is the case, type: faust and press the return key in your terminal, the following message should be returned: ERROR : no files specified; for help type "faust --help". However, if you get something like faust: command not found, something probably went wrong.

Lastly, you might want to install the VST SDK on your system if you want to generate VST plug-ins. For that, download this file and unzip it. Open a new terminal window and cd to the folder where you unziped the file and then type: sudo mv vstsdk2.4 /usr/local/include/. After this step, you should be able to compile any Faust code into a VST plug-in by simply typing faust2vst yourFaustFile.dsp in a terminal.

Optionally, you can also get any dependency related to a specific Faust architecture (to get a non-exhaustive list, just type faust2 in a terminal and then press the TAB key). Feel free to contact me if you have a question about that.

Windows

If you encounter a problem during one of the following steps, feel free to send me an e-mail.

Installing the Faust compiler on Windows can be complicated but fortunately, this is not the case of FaustLive that is an "on-the-fly" compiler for Faust (we'll see during the workshop what this means). For that, just download this file and follow the instructions. If you're a Jack user, you might want to check this version. Once this is done, you can try to run one of the examples like "harpeautomation". If it makes sound, it's a good sign: you're ready to code in Faust!

You should download the latest version of the source code of the Faust compiler by clicking on the "Download Snapshot" button on this page and leave it somewhere on your system as it will be very helpful during the workshop.

Lastly, if you don't already have one, you should download an "more advanced" text editor than notepad, etc. I recommend using Notepad++ for example.

2. Introduction/What is Faust?

3. Basic Notions of Acoustics and Digital Audio Technologies

4. Faust Semantic Basics and Simple Audio Effects: Panner and Tremolo

Simple Gain Controller

import("filter.lib");
	
gainController = *(gain : smooth(tau2pole(interpTime)))
with{
	gain = hslider("gain",0.5,0,1,0.1);
	interpTime = hslider("Interpolation Time (s)",0.05,0,1,0.001);
};

process = gainController;

Simple Panner

import("filter.lib");

myPanner = _ <: *(1-pan),*(pan)
with{
	pan = hslider("pan",0.5,0,1,0.01) : smooth(0.999);
};

process = myPanner;

Tremolo

import("music.lib");
import("filter.lib");

tremolo = *(1-depth*(osc(freq)*0.5+0.5))
with{
	freq = hslider("frequency",5,0.1,15,0.01) : smooth(0.999);
	depth = hslider("depth",0,0,1,0.01) : smooth(0.999);
};

process = tremolo;

5. Ring Modulation (Amplitude Modulation)

Ring Modulator

For more theory around amplitude modulation, check this page on Julius Smith's website.

import("music.lib");
import("filter.lib");

ringMod = *(1-depth*(osc(freq)*0.5+0.5))
with{
	freq = hslider("frequency",5,0.1,1000,0.01) : smooth(0.999);
	depth = hslider("depth",0,0,1,0.01) : smooth(0.999);
};

process = ringMod <: _,_;

Stereo Ring Modulation (Automated Panning)

import("music.lib");
import("filter.lib");

stereoRingMod = _ <: *(1-pan),*(pan)
with{
	freq = hslider("frequency",5,0.01,1000,0.01) : smooth(0.999);
	depth = hslider("depth",0,0,1,0.01) : smooth(0.999);
	pan = 1-depth*(osc(freq)*0.5+0.5);
};

process = stereoRingMod;

6. Additive Synthesis

Simple Additive Synthesizer

Check the Wikipedia page on additive synthesis to get more informations on this topic.

import("music.lib");
import("filter.lib");

freq = hslider("freq",300,20,2000,0.01) : smooth(0.999);
gain = hslider("gain",0.3,0,1,0.01) : smooth(0.999);
t = hslider("attRel (s)",0.1,0.001,2,0.001);
gate = button("gate") : smooth(tau2pole(t));

process = osc(freq),osc(freq*2),osc(freq*3) :> /(3) : *(gain)*gate;

7. Delay and Tour of oscillator.lib

Different Kinds of Delays in Faust

import("music.lib");
import("filter.lib");

_' // One sample delay
_@N // N samples delay
delay(NMax,N) // N samples variable delay with NMax, the maximum delay length as a power of 2
fdelay(NMax,N) // Fractional variable delay (allows N to be a decimal number)

8. One Zero Lowpass/Highpass Filter, Feed-Forward Comb Filter and Simple Flanger

"One Zero" Lowpass / Highpass Filter

More informations about this type of filter can be found on Julius Smith's website.

oneZero = _ <: _,_'*b1 :> _
with{
	b1 = hslider("b1",0,-1,1,0.01);
};

process = oneZero;

Feed-Forward Comb Filter

More informations about this type of filter can be found on Julius Smith's website.

import("music.lib");

ffComb = _ <: _,delay(65536,N)*b1 :> _
with{
	b1 = hslider("b1",0,-1,1,0.01);
	N = hslider("N",1,1,500,1);
};

process = ffComb;

Simple Feed-Forward Flanger

More informations about flanging can be found on Julius Smith's website.

import("music.lib");
import("filter.lib");

myFlanger = _ <: _,(65536,N,_ : fdelay) :> _
with{
	modFreq = hslider("Modulation Frequency",2,1,50,0.01) : smooth(0.999);
	depth = hslider("Depth",1,1,100,0.1) : smooth(0.999);
	N = osc(modFreq)*0.5+0.51 : *(depth);
};

process = myFlanger;

9. Debugging and Generating Plug-ins

10. Iteration

Additive Synthesizer with Independent Frequency Control

import("music.lib");
mySine(n) = osc(freq)
with{
	freq = hslider("freq %n",440,50,1000,0.01);
};

process = par(i,4,mySine(i)) :> *(0.25);

11. Recursion: Echo Effect and Feedback Comb Filter

Echo Effect

import("music.lib");
import("filter.lib");

myEcho = _ <: *(dry), (+~(fdelay(65536,delLength)*feedback*-1) : *(1-dry)) :> _
with{
	delLength = hslider("Time (ms)",250,0.1,1000,0.1)*0.001*SR : smooth(0.999);
	feedback = hslider("Feedback",0,0,1,0.001) : smooth(0.999);
	dry = hslider("Wet/Dry",1,0,1,0.01) : smooth(0.999);
};

process = myEcho;

Feedback Comb Filter

More informations about this kind of filter can be found here on Julius Smith's website.

import("music.lib");
import("filter.lib");

myFbComb = +~(delay(2048,delLength)*(-a1))
with{
	a1 = hslider("a1",0,-1,0.999,0.001) : smooth(0.999);
	delLength = hslider("delLength",1,1,2000,1);
};

process = myFbComb;

12. Introduction to Physical Modeling

Karplus-Strong: Virtual String

More informations about this algorithm can be found here on Julius Smith's website.

To learn more about physical modelling of musical instruments, check this online book by Julius Smith.

import("music.lib");
import("filter.lib");

myString(freq,feedback) = +~(fdelay4(1024,delLength) <: (_+_')/2 : *(feedback))
with{
	delLength = SR/freq - 1;
};

frequency = hslider("freq",440,51,2000,0.01);
feedback = hslider("feedback",0.9,0.9,1,0.01);
gate = button("gate");

impulse = gate <: _,_' : - : >(0);

process = impulse : myString(frequency,feedback);

13. Other Kinds of Filters and Filter Bank

Filter Bank

import("music.lib");
import("filter.lib");

bandsNumber = 10;

oneBand(i) = vgroup("Band %i",peak_eq(Lfx,fx,B))
with{
	highestBand = 10000;
	currentFreq = highestBand*(i+1)/bandsNumber;
	fx = hslider("[1]Freq[style:knob]",currentFreq,20,20000,0.1);
	B = hslider("[2]Bdwth[style:knob]",100,1,5000,0.1);
	Lfx = vslider("[3]Level",0,-90,10,0.1);
};

paramEqs(NBand) = hgroup("Filter Bank",seq(i,NBand,oneBand(i)));

process = paramEqs(bandsNumber);

14. Cubic Distortion

Cubic Distortion Plug-in

More informations on this topic can be found here on Julius Smith's website.

import("music.lib");
import("filter.lib");

distortion = +(offset) : *(pregain) : clip(-1,1) : cubic : dcblocker
with{
	drive = hslider("Drive",0,0,1,0.01) : smooth(0.999);
	offset = hslider("Offset",0,-0.1,0.1,0.01) : smooth(0.999);
	pregain = pow(10,drive*2);
	clip(lo,hi) = min(hi) : max(lo);
	cubic(x) = x - x*x*x/3;
};

process = distortion;

15. Vocoder and Conditions

Vocoder

Check the Wikipedia page on Vocoders.

I also recommend How to Wreck a Nice Beach - the Vocoder from WWII to Hip-Hop by Dave Tompkins to get an overview of the history of vocoders.

import("music.lib");
import("filter.lib");
import("effect.lib");
import("oscillator.lib");

simpleVocoder(nBands,att,rel,BWRatio,excitation,source) = source <: par(i,nBands,oneVocoderBand(i,nBands,BWRatio,1) : 
amp_follower_ud(att,rel) : _,excitation : oneVocoderBand(i,nBands,BWRatio)) :> _
with{
	oneVocoderBand(band,bandsNumb,bwRatio,bandGain,x) = x : resonbp(bandFreq,bandQ,bandGain)
	with{
		bandFreq = 25*pow(2,(band+1)*(9/bandsNumb));
		BW = (bandFreq - 25*pow(2,band*9/bandsNumb))*bwRatio;
		bandQ = bandFreq/BW;
	};
};

simpleVocoderDemo = hgroup("Simple Vocoder",lf_imptrain(freq)*gain,_ : simpleVocoder(bands,att,rel,BWRatio) <: _,_) 
with{
	bands = 32;
	vocoderGroup(x) = vgroup("[0]Vocoder",x);
	att = vocoderGroup(hslider("[0]Attack [style:knob]",5,0.1,100,0.1)*0.001);
	rel = vocoderGroup(hslider("[1]Release [style:knob]",5,0.1,100,0.1)*0.001);
	BWRatio = vocoderGroup(hslider("[2]BW [style:knob]",0.2,0.1,2,0.001));
	excitGroup(x) = vgroup("[1]Excitation",x);
	freq = excitGroup(hslider("[0]Frequency [style:knob]",140,50,2000,0.1));
	gain = excitGroup(vslider("[1]Gain",0.5,0,1,0.01) : smooth(0.999));
}; 

process = simpleVocoderDemo;

16. Guest Lecture by Julius Smith: Signal Processing Libraries for Faust

17. Reverb

Simple Schroeder Reverberator: Freeverb

Check this section on artificial reverberation on Julius Smith's website to get more informations on the freeverb algorithm.

import("music.lib");
import("filter.lib");

monoFreeverb(fb1,fb2,damp,spread) = _ <: par(i,8,lpcf(combtuningL(i),fb1,damp)) :> seq(i,4,allpass_comb(1024,allpasstuningL(i),-fb2))
with{
	lpcf(dt,fb,damp) = (+:delay(2048,dt))~ (*(1-damp) : (+ ~ *(damp)) : *(fb));
	origSR = 44100;
	cTuning = (1116,1188,1277,1356,1422,1491,1557,1617);
	combtuningL(i) = take(i+1,cTuning)*SR/origSR : int : +(spread);
	aTuning = (556,441,341,225);
	allpasstuningL(i) = take(i+1,aTuning)*SR/origSR : int;
};

stereoFreeverb(fb1,fb2,damp,spread) = + <: monoFreeverb(fb1,fb2,damp,0),monoFreeverb(fb1,fb2,damp,spread);

freeverbDemo = _,_ <: 
	(*(g)*fixedgain,*(g)*fixedgain : stereoFreeverb(combfeed,allpassfeed,damping,spatSpread)),
	*(1-g),*(1-g) :> _,_
with{
	origSR = 44100;
	scaleroom = 0.28;
	offsetroom = 0.7;
	allpassfeed = 0.5;
	scaledamp = 0.4;
	fixedgain = 0.1;
	mainGroup(x) = vgroup("Freeverb",x);
	knobsGroup(x) = mainGroup(hgroup("[0]",x));
	combfeed = knobsGroup(hslider("[0]Room Size [style:knob]",0.5,0,1,0.01)*scaleroom*SR/origSR + offsetroom);
	damping = knobsGroup(hslider("[1]Damping [style:knob]",0.5,0,1,0.01)*scaledamp*SR/origSR);
	spatSpread = knobsGroup(hslider("[2]Spatial Spread [style:knob]",0.5,0,1,0.01)*46*SR/origSR : int);
	g = mainGroup(hslider("[1]Dry/Wet",0.3,0,1,0.01));
};

process = freeverbDemo;

17. Dynamic Range Compression

Dynamic Range Compressor

More informations on this topic can be found here on Julius Smith's website.

import("music.lib");
import("filter.lib");
import("effect.lib");

simpleCompressor(ratio,thresh,att,rel,kneeAtt,gain) = _ <: _*(amp_follower_ud(att,rel) : linear2db : outminusindb : kneesmooth : visualizer : db2linear)*gain 
with{
	outminusindb(level) = max(level-thresh,0)*(1/ratio-1);
	kneesmooth = smooth(tau2pole(kneeAtt));
	visualizer = hbargraph("[1]Compressor Level [unit:dB]",-50,10);
};

simpleCompressorDemo = mainGroup(simpleCompressor(ratio,thresh,att,rel,kneeAtt,makeUpGain))
with{
	mainGroup(x) = vgroup("Simple Compressor",x);
	envelopesGroup(x) = hgroup("[0]Envelope",x);
	att = envelopesGroup(hslider("[0]Attack [style:knob][unit:ms]",20,0,500,0.1)*0.001);
	rel = envelopesGroup(hslider("[1]Release [style:knob][unit:ms]",20,0,500,0.1)*0.001);
	kneeAtt = envelopesGroup(hslider("[2]Knee Attack [style:knob][unit:ms]",10,0,250,0.1)*0.001);
	thresh = hslider("[2]Threshold [unit:dB]",-30,-60,4,0.1);
	ratio = hslider("[3]Ratio",1,1,10,0.01);
	makeUpGain = hslider("[4]Makeup Gain [unit:dB]",40,-96,96,0.1) : db2linear;
};

process = simpleCompressorDemo;