The goal of this first step is to add MIDI support to a simple synthesizer written in Faust. For this to work, you must use an up-to-date version of Google Chrome. Chrome is the only browser providing MIDI support so using a different one (e.g., Firefox) will not work. There are 3 MIDI interfaces in the MaxLab and one in studio E and D that you can use for this exercise. They all work with USB and some of them need to be powered with an external power supply (that you should find with them).
Say we have this simple synthesizer (feel free to copy this code and paste in the Faust online editor):
import("stdfaust.lib");
freq = hslider("freq",300,50,2000,0.01) : si.smoo;
gain = hslider("gain",0.8,0,1,0.01) : si.smoo;
process = os.sawtooth(freq)*gain;
Note the use of
si.smoo
on all its parameters to prevent clicking.
We would like to control freq
and gain
using a MIDI interface. To assign a specific MIDI controller (i.e., a knob, a slider, etc.) to a Faust parameter, a metadata must be used. MIDI controllers on a MIDI interface are numbered from 0 to 127. There’s a white tape on the interfaces in the MaxLab indicating which number is assigned to which controller. The interfaces in studio D and E are a bit fancier, and the ctrl
number should be displayed on their screen when interacting with the controller.
Say we’d like to assign a knob whose number is 11 to freq
and another knob with number 55 to gain
, all we have to write is the following:
import("stdfaust.lib");
freq = hslider("freq[midi: ctrl 11]",300,50,2000,0.01) : si.smoo;
gain = hslider("gain[midi: ctrl 55]",0.8,0,1,0.01) : si.smoo;
process = os.sawtooth(freq)*gain;
Now try to assign knobs on of the interfaces available at CCRMA to freq
and gain
to see how this works. Note that the minimum value of the Faust parameter (i.e., 50 for freq
) will be assigned to the lowest position of the knob and that its maximum value (i.e., 2000 for freq
) to the highest position of the knob.
For further information on MIDI support in Faust, please refer to the corresponding section in the Faust documentation.
The Faust distribution comes with a series of libraries implementing a wide range of synthesizers, audio effects, etc. The source code of the Faust libraries can be found in the Faust Libraries repository on GitHub: https://github.com/grame-cncm/faustlibraries. Also, the documentation of the Faust libraries is available on the Faust website: https://faust.grame.fr/doc/libraries/
Each .lib
file contains the source code of a specific library.
All standard Faust libraries are accessible through a series of prefixes declared in stdfaust.lib
. For example, to call the sine oscillator function (osc
) declared in oscillators.lib
, one might write:
import("oscillators.lib");
process = osc(440);
and alternatively:
import("stdfaust.lib");
process = os.osc(440);
Some functions of the Faust libraries host their own user interface. Most of these functions are declared in demos.lib
and physmodels.lib
. For example, a ready-to-use clarinet physical model can be found physmodels.lib
and called with just 2 lines of code:
import("stdfaust.lib");
process = pm.violin_ui;
Exploring the source code of physmodels.lib
, the declaration of the violin_ui
function can be easily found: https://github.com/grame-cncm/faustlibraries/blob/master/physmodels.lib#L1474
As an exercise, try to write your own version of violin_ui
(i.e., my_violin_ui
) where some of the parameters of the model are controlled using one of the MIDI interfaces available at CCRMA (hint: don’t forget to add pm
when you call violinModel
since you’ll be outside of physmodels.lib
).
Vibrato is a crucial esthetic feature when performing with some musical instruments in western music. Moreover, in the case of sound synthesis it can help make the harmonic content of a sound more “coherent” (effect of source segregation).
Vibrato can be implemented in Faust simply by modulating the pitch of the generated sound with a sine wave oscillator (e.g., pitch + osc(vibratoFreq)*vibratoAmp
).
Try to modify the previous example by adding 2 user interface elements to control the frequency and the amplitude of the vibrato. The frequency shouldn’t exceed 10Hz and a good default value is 6Hz. Also, map these 2 new parameters to MIDI controllers on the interface.
Hint: don’t forget that a sine function has both positive and negative values.
compressors.lib
, misceffects.lib
, phaflangers.lib
, reverbs.lib
, and vaeffects.lib
contain a wide range of audio effects. Some of them have a demo version (with a built-in UI) that can be found in demos.lib
. This table gives of an overview of the most standard audio effects available in the Faust libraries.
We’d like to “improve” our instrument from the previous step (violin with vibrato) with a phasor. A stereo phaser is available in demos.lib
: https://github.com/grame-cncm/faustlibraries/blob/master/demos.lib#L477. Copy its code in your Faust program and rename it as we did for violin_ui
(i.e., my_phaser2_demo
). Connect the output of my_violin_ui
to my_phaser2_demo
. Since my_violin_ui
has one output and my_phaser2_demo
has 2 inputs (stereo), we must use the split operator:
process = my_violin_ui <: my_phaser2_demo;
Try to assign some of the parameters of the phaser to MIDI controllers on the interface that you’re using. Keep in mind that a Faust parameter can contain multiple metadata (i.e., speed = ctl_group(hslider("[1] Speed [unit:Hz] [style:knob][midi: ctrl 26]",0.5,0,10,0.001))
)
demos.lib
, physmodels.lib
, the Faust examples page, and of the Faust 250a starter codes. Also have a look at the Standard Functions section of the Faust libraries documentation.