A SOUL patch is a bundle of files which contains everything needed to implement an audio synthesiser or effect. It contains no natively executable code - an application is needed to load and play a patch.
In many ways a patch resembles a traditional audio plugin (e.g. VST/AudioUnit/AAX), but has significant differences too.
Similarities:
Differences:
A difference in the overall philosophy lies in the distinction between “sounds” and “plugins”.
If you were delivering a set of 100 “sounds” using a traditional plugin format, you’d build a single large native plugin (the engine), and then supply a set of 100 programs (a.k.a. “presets”, “patches”, “sounds”, etc) which can be loaded onto that engine.
Because SOUL patches are compact and script-based, there’s less reason to structure things like that. A SOUL patch can be treated more like an individual sounds (hence the name “patch” rather than “plugin”). Delivering a set of 100 sounds using SOUL could be done by simply providing 100 separate SOUL patches. Internally they may all share most of the same DSP and GUI codebase (when loaded, the JIT compiler will detect and coalesce any duplicated code). However, the fact that the sounds needn’t share all their engine code means that individual sounds can be fine-tuned to eliminate wasted processing overhead, or to tweak the underlying DSP for particular sounds.
A patch is identified by a manifest file with the suffix .soulpatch
which contains information and links to the set of files and resources that it requires.
The .soulpatch
file is JSON, and contains details about this particular patch, e.g.
{
"soulPatchV1": {
"ID": "com.mycompany.sounds.awesome_synth_sound_34",
"version": "1.0",
"name": "Awesome Synth Sound 34",
"description": "This is an awesome sound",
"category": "synth",
"manufacturer": "The Cool Synth Company Inc",
"icon": "AwesomeSoundIcon.svg",
"website": "https://mycoolsynthcompany.com",
"isInstrument": true,
"source": [ "AwesomeSound34.soul", "SomeSharedLibraryCode.soul" ],
"externals": {
"SampleSet::kickdrum": "sounds/kick1.ogg",
"SampleSet::hihat": "sounds/hihat.flac",
"SampleSet::bass": "sounds/bass.wav",
"SampleSet::crash": "sounds/crash22.wav"
},
"view": [ "AwesomeGUI.js", "AwesomeGUI.faceplate" ]
}
}
The main duties of this file are to provide:
.soul
source files to build and link (the “source” parameter can be either a single path or an array of paths). One of the processors must be annotated as [[ main ]]
to tell the host which processor should be loaded and runexternal
variable bindings if needed by the program.The folder that contains the manifest file may also contain any resource files that are needed (e.g. audio files, image files for the GUI, etc).
The set of inputs and outputs declared in the main SOUL processor are used by a host to determine the i/o bus layout and set of parameters for the patch. e.g.
processor MySynth
{
input event midi::Message midiIn; // a MIDI input channel
input event float cutoff [[ name: "Cutoff", min: 0, max: 127, init: 80, unit: "semi", step: 0.1 ]];
input event float resonance [[ name: "Resonance", min: 0, max: 100, init: 20, unit: "%", step: 1 ]];
output stream float<2> audioOut; // a stereo audio output
The externals
object in the manifest contains a set of values which need to be provided for external variables in the program (see the SOUL language guide for more details about how to declare an external variable). Each item in the externals list maps the (fully-qualified) name of a SOUL external variable to either a value (primitive or an object or array, etc), or a filename which should be loaded and turned into a float array. The patch loader uses JUCE for reading audio files, so will load WAV, AIFF, FLAC, Ogg-Vorbis and MP3 on all platforms, and maybe other formats on MacOS and Windows where the OS APIs support it.
To let you create a host that can load and run SOUL patches, we have the following resources:
soul
command-line utility can load and play patches, hot-reloading them when the code is modified.The binaries and libraries can be downloaded as github releases: https://github.com/soul-lang/SOUL/releases/latest
In SOUL, each input declaration can have an arbitrary set of properties (‘annotations’) attached to it, e.g.
input event float cutoff [[ name: "Cut-off", min: 0, max: 127, init: 80, unit: "semi", step: 0.1 ]];
input event float turbo [[ name: "Turbo Boost", boolean, text: "off|on" ]]
If you’d like an input to be treated by a host as a parameter rather than an audio stream, you can attach some of the following annotations to it:
name:
The name that a host should display for this parameter. If not specified, the endpoint name is used.unit:
If supplied, this string indicates the units for this value, e.g. "dB"
or "%"
or "Hz"
.min:
The minimum value of the range of a parameter (inclusive). If not specified, the default is 0.max:
The maximum value of the range of a parameter (inclusive). If not specified, the default is 1.step:
A snapping interval to which the value should be quantised. If not specified, the default is 0, which means the value is continuous.init:
The initial, or default value for a parameter. This should be between the min
and max
values. If not specified, the default is the same as min
.boolean:
If this flag is present (either just as boolean
with no value, or explicitly boolean: true
or boolean: false
), it tells the host whether the parameter should be treated as a two-position switch. If so, the host may want to show the user a button rather than a slider. If you set this flag, it’s best to not set the min
, max
or step
, and the value will be toggled between 0 and 1 by default.hidden:
If the hidden
property is present, hosts should ignore this parameter and not show it to the user. (But don’t be surprised if some hosts don’t respect this flag).automatable:
Tells the host whether to allow this parameter to be automated. If not specified, the default is true
. (It’d be optimistic to expect all hosts to recognise this flag).text:
This can be used for two main purposes:
%d
is replaced by an integer version of the parameter value.%f
is replaced by a floating point display of the value, where number of decimal places can be specified, e.g. %3f
= “up to 3 decimal places”, %02f
= “exactly 2 decimal places”.%+d
or %+f
will always print a +
or -
sign before the number.text
property can be a list of items separated by a vertical pipe character |
. These will be evenly spread across the range of the parameter, e.g. text: "low|medium|high", max: 9
will show “low” for values 0 -> 3, “medium” for 3 -> 6, and “high” for 6 -> 9. If you omit a max
setting, then max
will set to the number of items - 1. If you omit step
, it will be set to snap to the size of each item. If you provide a list of items like this, some hosts may choose to display them as a drop-down list rather than using a slider.group:
An optional tag for the host to use to group sets of related parameters together when displaying them to the user. Use forward-slashes to create nested hierarchies of groups.The SOUL Patch API interfaces and helper classes are found here.