Skip to content

Faust Processor

David Braun edited this page Jun 30, 2022 · 2 revisions

New to FAUST?

Using FAUST processors

Let's start by looking at FAUST DSP files, which end in .dsp. For convenience, the standard library is always imported, so you don't need to import("stdfaust.lib"); Here's an example using a demo stereo reverb:

faust_reverb.dsp:

process = dm.zita_light;

faust_test.py:

DSP_PATH = "C:/path/to/faust_reverb.dsp"  # Must be absolute path
INPUT_AUDIO_PATH = "C:/path/to/piano.wav"
DURATION = 10.

faust_processor = engine.make_faust_processor("faust")
faust_processor.set_dsp(DSP_PATH)  # You can do this anytime.

# Using compile() isn't necessary, but it's an early warning check.
faust_processor.compile() # throws a catchable Python Runtime Error for bad Faust code

print(faust_processor.get_parameters_description())

# You can set parameters by index or by address.
faust_processor.set_parameter("/Zita_Light/Dry/Wet_Mix", 1.)
faust_processor.set_parameter(0, 1.)

# Unlike VSTs, these parameters aren't necessarily 0-1 values.
# For example, if you program your FAUST code to have a 15000 kHz filter cutoff
# you can set it naturally:
#     faust_processor.set_parameter(7, 15000)

print('val: ', faust_processor.get_parameter("/Zita_Light/Dry/Wet_Mix"))
print('val: ', faust_processor.get_parameter(0))

graph = [
  (engine.make_playback_processor("piano", load_audio_file(INPUT_AUDIO_PATH)), []),
  (faust_processor, ["piano"])
]

engine.load_graph(graph)
engine.render(DURATION)

Here's an example that mixes two stereo inputs into one stereo output and applies a low-pass filter.

dsp_4_channels.dsp:

declare name "MyEffect";
import("stdfaust.lib");
myFilter = fi.lowpass(10, hslider("cutoff",  15000.,  20,  20000,  .01));
process = si.bus(4) :> sp.stereoize(myFilter);

faust_test_stereo_mixdown.py:

INPUT_AUDIO_PATH1 = "piano.wav"
INPUT_AUDIO_PATH2 = "vocals.wav"
DURATION = 10.

faust_processor = engine.make_faust_processor("faust")
faust_processor.set_dsp("C:/path/to/dsp_4_channels.dsp")  # Must be absolute path
print(faust_processor.get_parameters_description())
faust_processor.set_parameter("/MyEffect/cutoff", 7000.0)  # Change the cutoff frequency.
# or set automation like this
faust_processor.set_automation("/MyEffect/cutoff", 15000+5000*make_sine(2, DURATION))
graph = [
  (engine.make_playback_processor("piano", load_audio_file(INPUT_AUDIO_PATH1)), []),
  (engine.make_playback_processor("vocals", load_audio_file(INPUT_AUDIO_PATH2)), []),
  (faust_processor, ["piano", "vocals"])
]

engine.load_graph(graph)
engine.render(DURATION)

Polyphony in Faust

Polyphony is supported too. You simply need to provide DSP code that refers to correctly named parameters such as freq or note, gain, and gate. For more information, see the FAUST manual. In DawDreamer, you must set the number of voices on the processor to 1 or higher. The default (0) disables polyphony. Refer to tests/test_faust_poly*.py.

Soundfiles in Faust

Faust code in DawDreamer can use the soundfile primitive. Normally soundfile is meant to load .wav files, but DawDreamer uses it to receive data from numpy arrays. Refer to tests/test_faust_soundfile.py which contains an example of loading 88 piano notes and playing them with polyphony.

soundfile_test.py

# suppose audio1, audio2, and audio3 are np.array shaped (Channels, Samples)
soundfiles = {
  'mySound': [audio1, audio2, audio3]
}
faust_processor.set_soundfiles(soundfiles)

soundfile_test.dsp

soundChoice = nentry("soundChoice", 0, 0, 2, 1); // choose between 0, 1, 2
process = soundChoice,_~+(1):soundfile("mySound",2):!,!,_,_;

Note that soundfile("mySound",2) has 2 as a hint that the audio is stereo. It's unrelated to the Python side where mySound's dictionary value has 3 numpy arrays.