Version 0.4, October 10, 2012
Albert Graef <Dr.Graef@t-online.de>
pd-faust is a dynamic environment for running Faust dsps in Pd. It is based on the author’s faust2pd script, but offers many small improvements and some major additional features:
Copyright (c) 2011 by Albert Graef
pd-faust is distributed under the GNU LGPL v3+. Please see the included COPYING and COPYING.LESSER files for details.
This package also includes the faust-stk instruments which are distributed under an MIT-style license, please check the examples/dsp/README-STK file and the dsp files for authorship information and licensing details pertaining to these. The original faust-stk sources can be found in the Faust distribution, cf. http://faust.grame.fr/.
The pd-faust objects are written in the Pure programming language, so you’ll also need an installation of the Pure interpreter (0.51 or later), along with the following packages (minimum required versions are given in parentheses): pd-pure (0.15), pure-faust (0.8), pure-midi (0.5) and pure-stldict (0.3).
Finally, gcc and GNU make (or compatible) are required to compile the helper dsps and the example instruments; please check the Makefile for details.
For a basic installation run make, then sudo make install. This will install the pd-faust objects in your lib/pd/extra/faust folder. Add this directory to your Pd library search path (-path option or Preferences/Path in Pd) and you should be set. The make command also compiles the Faust dsps included in the distribution, so that the provided examples will be ready to run afterwards as well (see Examples below).
The Makefile tries to guess the installation prefix under which Pd is installed. If it guesses wrong, you can tell it the right prefix with make prefix=/some/path. Or you can specify the exact path of the lib/pd directory with make pdlibdir=/some/path; by default the Makefile assumes $(prefix)/lib/pd.
It is also possible to specify an alternative flavour of Pd when building and installing the module, by adding a definition like PD=pd-extended to the make command line. This is known to work with pd-extended and pd-l2ork, two popular alternative Pd distributions available on the web.
The pd-faust objects are installed both in source form (so you can customize them for your own purposes) and in binary form as a Pd object library which can be loaded with Pd’s -lib option. The latter substantially reduces startup times and is thus the recommended way to run pd-faust if you don’t need to customize the pd-faust objects on the fly. To these ends, after completing installation and setting up Preferences/Path in Pd, simply add pdfaust to your preloaded library modules in Pd’s Preferences/Startup dialog.
The pdfaust module must come after the pure entry which loads pd-pure, otherwise you’ll get an error message. In any case the pd-pure loader will be required to run these objects, so it should be configured accordingly; please check the pd-pure documentation for details.
Some further build options are described in the Makefile. In particular, it is possible to compile the Faust dsps to LLVM bitcode which can be loaded directly by the Pure interpreter, but for that you’ll need a special Faust version (see the Faust2 website for how to get this version up and running) and an LLVM-capable C/C++ compiler such as clang or gcc with the dragonegg plugin (please check the Makefile and the LLVM website for details).
If you have the required tools then you can build the bitcode modules by running make bitcode after make. If you run make install afterwards, the bitcode modules will be installed along with the “normal” Faust plugins. In addition, a second object library called pdfaust2 will be built and installed, which can be used as a drop-in replacement for pdfaust and lets you run the bitcode modules. (Note that in the present implementation it is not possible to load both pdfaust and pdfaust2 in Pd, you’ll have to pick one or the other.)
Working with pd-faust basically involves adding a bunch of fsynth~ and fdsp~ objects to a Pd patch along with the corresponding GUI subpatches, and wiring up the Faust units in some variation of a synth-effects chain which typically takes input from Pd’s MIDI interface (notein, ctlin, etc.) and outputs the signals produced by the Faust units to Pd’s audio interface (dac~).
For convenience, pd-faust also includes the midiseq and oscseq objects and a corresponding midiosc abstraction which can be used to handle MIDI input and playback as well as OSC controller automation. This useful helper abstraction is described in more detail under Operating the Patches below.
pd-faust interprets MIDI, OSC and Faust dsp filenames relative to the hosting Pd patch by default. It will also search the midi, osc and dsp subfolders, if they exist, for the corresponding types of files. Failing that, it finally searches the directories on the Pd library path (including their midi, osc and dsp subfolders). To disable this search, just use absolute pathnames (or pathnames relative to the . or .. directory) instead.
The fdsp~ object is invoked as follows:
fdsp~ dspname instname channel
Since the fdsp~ and fsynth~ objects are written in Pure, their creation arguments should be specified in Pure syntax. In particular, both dspname or instname may either be Pure identifiers or double-quoted strings (the former will automatically be translated to the latter). Similarly, the channel argument (as well as the numvoices argument of the fsynth~ object, see below) must be an integer constant in Pure syntax, which is pretty much like Pd syntax but also allows the integer to be specified in hexadecimal, octal or binary.
The fdsp~ object requires a Faust dsp which can work as an effect unit, processing audio input and producing audio output. The unit can have as many audio input and output channels as you like (including zero).
The fsynth~ object works in a similar fashion, but has an additional creation argument specifying the desired number of voices:
fsynth~ dspname instname channel numvoices
The fsynth~ object requires a Faust dsp which can work as a monophonic synthesizer. This typically means that the unit has zero audio inputs and a nonzero number of audio outputs, although it is possible to have synths processing any number of audio input channels as well. (You can even have synths producing zero audio outputs, but this is generally not very useful.) In addition, pd-faust assumes that the Faust unit provides three so-called “voice controls” which indicate which note to play:
pd-faust doesn’t care at which path inside the Faust dsp these controls are located, but they must all be there, and the basenames of the controls must be unique throughout the entire dsp. Otherwise the synth will not work as expected.
Like faust2pd, pd-faust implements the necessary logic to drive the given number of voices of an fsynth~ object. That is, it will actually create a separate instance of the Faust dsp for each voice and handle polyphony by allocating voices from this pool in a round-robin fashion, performing the usual voice stealing if the number of simultaneous notes to play exceeds the number of voices. Also note that an fsynth~ operated in omni mode (channel = 0) automatically filters out messages on channel 10 which is reserved for percussion in the General MIDI standard.
The fdsp~ and fsynth~ objects respond to the following messages:
In addition, the fdsp~ and fsynth~ objects respond to MIDI controller messages of the form ctl val num chan, and the fsynth~ object also understands note-related messages of the form note num vel chan (note on/off) and bend val chan (pitch bend). In either case, pd-faust provides the necessary logic to map controller and note-related messages to the corresponding control changes in the Faust unit.
Like pd-pure, pd-faust also remaps Pd’s menu-open command so that it lets you edit the Faust source of an fdsp~ or fsynth~ object by right-clicking on the object and choosing Open from the context menu.
For each fdsp~ and fsynth~ object, the Pd patch should also contain an (initially empty) “one-off” graph-on-parent subpatch with the same name as the instance name of the Faust unit:
You shouldn’t insert anything into this subpatch, its contents (a bunch of Pd GUI elements corresponding to the control elements of the Faust unit) will be generated automatically by pd-faust when the corresponding fdsp~ or fsynth~ object is created, and whenever the unit gets reloaded at runtime.
As with faust2pd, the default appearance of the GUI can be adjusted in various ways; see Tweaking the GUI Layout below for details.
The relative order in which you insert an fdsp~ or fsynth~ object and its GUI subpatch into the main patch matters. Normally, the GUI subpatch should be inserted first, so that it will be updated automatically when its associated Faust unit is first created, and also when the main patch is saved and then reloaded later.
However, in some situations it may be preferable to insert the GUI subpatch after its associated Faust unit. If you do this, the GUI will not be updated automatically when the main patch is loaded, so you’ll have to reload the dsp manually (sending it a reload message) to force an update of the GUI subpatch. This is useful, in particular, if you’d like to edit the GUI patch manually after it has been generated.
In some cases it may even be desirable to completely “lock down” the GUI subpatch. This can be done by simply renaming the GUI subpatch after it has been generated. When Pd saves the main patch, it saves the current status of the GUI subpatches along with it, so that the renamed subpatch will remain static and will never be updated, even if its associated Faust unit gets reloaded. This generally makes sense only if the control interface of the Faust unit isn’t changed after locking down its GUI patch. To “unlock” a GUI subpatch, you just rename it back to its original name. (In this case you might also want to reinsert the corresponding Faust unit afterwards, if you want to have the GUI generated automatically without an explicit reload again.)
The examples folder contains a few example patches which illustrate how this all works. Having installed pd-faust as described above, you can run these from the examples directory, e.g.: pd test.pd. (You can also run the examples without actually installing pd-faust if you invoke Pd from the main pd-faust source directory, e.g., as follows: pd -lib lib/pdfaust examples/test.pd.)
Here are some of the examples that are currently available:
For your convenience, related MIDI and OSC files as well as the Faust sources of the instruments and effects are contained in corresponding subdirectories (midi, osc, dsp) of the examples directory. A slightly modified version of the faust-stk instruments from the Faust distribution is also included, please check the examples/dsp/README-STK file for more information about these.
The MIDI files are all in standard MIDI file format. (Some of these come from the faust-stk distribution, others can be found on the web.) The OSC files used by pd-faust for controller automation are plain ASCII files suitable for hand-editing if you know what you are doing; the format should be fairly self-explanatory.
The generated Pd GUI elements for the Faust dsps are pretty much the same as with faust2pd (which see). The only obvious change is the addition of a “record” button (gray toggle in the upper right corner) which enables recording of OSC automation data.
In each example distributed with pd-faust you can also find an instance of the midiosc abstraction which serves as a little sequencer applet that enables you to control MIDI playback and OSC recording. The usage of this abstraction should be fairly obvious, but you can also find a brief description below.
If you use the midiosc abstraction in your own patches, you should copy it to the directory containing your patch and other required files, so that MIDI and OSC files are properly located. Alternatively, you can also set up Pd’s search path as described at the beginning of the Usage section.
The first creation argument of midiosc is the name of the MIDI file, either as a Pure identifier (in this case the .mid filename extension is supplied automatically) or as a double-quoted string. Similarly, the second argument specifies the name of the OSC file. Both arguments are optional; if the second argument is omitted, it defaults to the name of the MIDI file with new extension .osc. You can also omit both arguments if neither MIDI file playback nor saving recorded OSC data is required. Or you can leave the first parameter empty (specify "" or 0 instead) to only set an OSC filename, if you don’t need MIDI playback. The latter is useful, in particular, if you use midiosc with an external MIDI sequencer (see below).
The abstraction has a single control outlet through which it feeds the generated MIDI and other messages to the connected fsynth~ and fdsp~ objects. Live MIDI input is also accepted and forwarded to the control outlet, after being translated to the format understood by fsynth~ and fdsp~ objects. In addition, midiosc can also be controlled through an external MIDI sequencer connected to Pd’s MIDI input. To these ends, MIDI Machine Control (MMC) can be used to start and stop OSC playback and recording with the transport controls of the external sequencer program. To make this work, the external sequencer must be configured as an MMC master.
At the bottom of the abstraction there is a little progress bar along with a time display which indicates the current song position. If playback is stopped, you can also use these to change the current position for playback, recording and a number of other operations as described below. Note that if you drive midiosc from an external MIDI sequencer instead, then it is a good idea to load the same MIDI file in midiosc anyway, so that it knows about the length of the MIDI sequence. This will make the progress bar display the proper position in the file.
Here is a brief rundown of the available controls:
Please note that midiosc is merely an example which should cover most common uses. If you don’t need all the fancy functionality it provides, your patches may simply feed control messages directly into fdsp~ and fsynth~ objects instead. On the other hand, if you need even more elaborate input/output interfacing than what midiosc provides, midiosc can be used as a starting point for your own input/output abstractions driving the fdsp~ and fsynth~ objects in your patch.
The fsynth~ object has built-in (and hard-wired) support for MIDI notes, pitch bend and MIDI controller 123 (all notes off).
Other controller data received from external MIDI and OSC devices is interpreted according to the controller mappings defined in the Faust source (this is explained below), by updating the corresponding GUI elements and the control variables of the Faust dsp. For obvious reasons, this only works with active Faust controls.
An fdsp~ or fsynth~ object can also be put in write mode by feeding a message of the form write 1 into its control inlet (the write 0 message disables write mode again). For convenience, the write toggle in the midiosc abstraction allows you to do this simultaneously for all Faust units connected to midiosc‘s control outlet.
When an object is in write mode, it also outputs MIDI and OSC controller data in response to both automation data and the manual operation of the Pd GUI elements, again according to the controller mappings defined in the Faust source, so that it can drive an external device such as a MIDI fader box or a multitouch OSC controller. Note that this works with both active and passive Faust controls.
To configure MIDI controller assignments, the labels of the Faust control elements have to be marked up with the special midi attribute in the Faust source. For instance, a pan control (MIDI controller 10) may be implemented in the Faust source as follows:
pan = hslider("pan [midi:ctrl 10]", 0, -1, 1, 0.01);
pd-faust will then provide the necessary logic to handle MIDI input from controller 10 by changing the pan control in the Faust unit accordingly, mapping the controller values 0..127 to the range and step size given in the Faust source. Moreover, in write mode corresponding MIDI controller data will be generated and sent to Pd’s MIDI output, on the MIDI channel specified in the creation arguments of the Faust unit (0 meaning “omni”, i.e., output on all MIDI channels).
The same functionality is also available for external OSC devices, employing explicit OSC controller assignments in the Faust source by means of the osc attribute. E.g., the following enables input and output of OSC messages for the OSC /pan address:
pan = hslider("pan [osc:/pan]", 0, -1, 1, 0.01);
In contrast to some other architectures included in the Faust distribution, pd-faust only allows literal OSC addresses here. That is, glob-style OSC patterns are not supported as values for the osc attribute.
Also note that while the necessary infrastructure to support OSC input and output is already provided by pd-faust, the OSC input and output facilities themselves which are needed to make this actually work are not implemented in the default version of the midiosc abstraction distributed with pd-faust. That’s because Pd doesn’t provide any built-in objects for OSC input and output, although a few different solutions exist and are included in Hans-Christoph Steiner’s Pd-extended distribution, such as Martin Peach’s OSC externals.
The distribution includes a version of the midiosc abstraction which implements OSC input and output using Martin Peach’s objects in the midiosc-mrpeach.pd file. You most likely have to edit this abstraction for your purposes; at least you’ll have to change the network addresses so that it works with the OSC device or application that you use.
As already mentioned, pd-faust provides the same global GUI layout options as faust2pd. Please check the faust2pd documentation for details. There are a few minor changes in the meaning of some of the options, though, which we consider notable improvements after some experience working with faust2pd. Here is a brief rundown of the available options, as they are implemented in pd-faust:
In pd-faust there is no way to specify the above options on the command line, so you’ll have to put them as pd attributes on the main group of your Faust program, as described in the faust2pd documentation. For instance:
process = vgroup("[pd:no-slider-nums][pd:font-size=12]", ...);
In addition, the following options can be used to change the appearance of individual control items. If present, these options override the corresponding defaults. Each option can also be prefixed with “no-” to negate the option value. (Thus, e.g., no-hidden makes items visible which would otherwise, by means of the global exclude option, be removed from the GUI.)
Again, these options are specified with the pd attribute in the label of the corresponding Faust control. For instance, the following Faust code hides the controls in the aux group, removes the number entry from the pan control, and renders the preset item as a Pd radio control:
aux = vgroup("aux [pd:hidden]", aux_part); pan = hslider("pan [pd:no-slider-num]", 0, -1, 1, 0.01); preset = nentry("preset [pd:radio-slider]", 0, 0, 7, 1);
Also included in the sources is a helper abstraction faust-remote.pd and an accompanying elisp program faust-remote.el. These work pretty much like pure-remote.pd and pure-remote.el in the pd-pure distribution, but are tailored for the remote control of Faust dsps in a Pd patch. In particular, they enable you to quickly reload the Faust dsps in Pd using a simple keyboard command (C-C C-X by default) from Emacs. The faust-remote.el program was designed to be used with Juan Romero’s Emacs Faust mode; please see etc/pure-remote.el in the pd-faust source for usage instructions.
Some parts of this software might still be experimental, under construction and/or bug-ridden. Bug reports, patches and suggestions are welcome. Please send these directly to the author, or post them either to the Faust or the Pure mailing list.
In particular, please note the following known limitations in the current implementation:
Also, please check the TODO file included in the distribution for other issues which we are already aware of and which will hopefully be addressed in future pd-faust versions.