This post is a collection of notes on how to write plugins for SuperCollider.

This post will be updated as I go along.

This repo contains example code for writing plugins in both the “old” and “new” style which I found helpful in understanding this subject.

Also check out this cookiecutter template for generating plugins and the Server Plugin API.

The two different styles

There are two different headers that contain SuperCollider’s plugin boiler plate code. These are imported at the top of both your .cpp and .hpp file and will lead to two different styles of writing your plugin code.

New style c++ wrapper

#include "SC_PlugIn.hpp"

This header will import “newer” c++ headers that are recognizable as lower case method names such as:

set_calc_function<BoringMixer, &BoringMixer::next>();

See BoringMixer (new style) for a more extensive example.

Old style

#include "SC_PlugIn.h"

This imports the older header, which leads to code with a lot of upper case macros like

SETCALC(BoringMixer_next)

See BoringMixer (old style) for a more extensive example.

Macros

This is a transcription of Dan Stowell’s very helpful table in the SuperCollider Book (MIT), slightly edited and transcribed for the “new” c++ style for writing plugins. It contains some of the macros available when writing UGens/Plugins in c++ in SuperCollider.

Macro Description
in(index) a float* pointer to input number index
out(index) a float* pointer to output number index
in0(index) a single (control-rate) value from input number index
out0(index) a single (control-rate) value at output number index
inRate(index) The rate of input index, an integer value corresponding to 1 of the following constants: calc_ScalarRate (scalar-rate), calc_BufRate(control-rate), calc_FullRate (audio-rate), calc_DemandRate (demand-rate)
set_calc_function<ClassName, &ClassName::next>() Set the calculation function for ugen ClassName to next
sampleRate() Samplerate of the ugen as a double. Note: For control-rate UGens this is not the full audio rate but audio rate/blocksize
sampleDur() Reciprocal of sampleRate() (seconds per sample)
bufferSize() Equal to the block size if the unit is audio rate and 1 if the unit is control rate
ClearUnitOutputs(unit, inNumSamples) Print text to the SuperCollider post window; arguments are just like those for the C function printf
Print(text) Print text to the SuperCollider post window; arguments are just like those for the C function printf, eg: Print("Hello\n")
RTAlloc(world, numBytes) Allocate memory from the real-time pool – analogous to malloc(numBytes)
RTRealloc(world, pointer, numBytes) Reallocate memory from the real-time pool – analogous to realloc(pointer, numBytes)
RTFree(world, pointer) Free allocated memory back to the real-time pool – analogous to free(pointer)
fullSampleRate() The full audio sample rate of the server (irrespective of the rate of the UGen) as a double
fullBufferSize() The integer number of samples in an audio-rate input (irrespective of the rate of the UGen)

The Randomness API

There’s an API for a bunch of randomness functions that come with the SuperCollider plugin development framework, most of which reflect sclang equivalents so are probably well known to people with experience i sclang. These are described in the header file SC_RGen.h.

To use them, first include the header file in your plugin’s .hpp file.

#include "SC_RGen.h"

Then instantiate a random number generator class in your header file (under the private: keyword for example) as a member variable.

RGen & rgen = *mParent -> mRGen;

With this, you now have access to the random number generators in your calculation functions in your plugin like so:

const float random_float = rgen.frand();

Available methods for random number generation

uint32 trand();

int32 irand(int32 scale);
int32 irand2(int32 scale);
int32 ilinrand(int32 scale);
int32 ibilinrand(int32 scale);

float fcoin();
float frand();
float frand2();
float frand0();
float frand8();
float flinrand();
float fbilinrand();
float fsum3rand();

double drand();
double drand2(double scale);
double linrand(double scale);
double bilinrand(double scale);
double exprandrng(double lo, double hi);
double exprand(double scale);
double biexprand(double scale);
double sum3rand(double scale);

Interpolation

Interpolation functions available (for working with buffers):

float lininterp(float x, float a, float b) 
float cubicinterp(float x, float y0, float y1, float y2, float y3)

Example from the example-plugins repo’s AnalogEcho example:

// Four integer phases into the buffer
int phase1 = writephase - offset;
int phase2 = phase1 - 1;
int phase3 = phase1 - 2;
int phase0 = phase1 + 1;
float d0 = buf[phase0 & mask];
float d1 = buf[phase1 & mask];
float d2 = buf[phase2 & mask];
float d3 = buf[phase3 & mask];

// Use cubic interpolation with the fractional part of the delay in samples
float delayed = cubicinterp(frac, d0, d1, d2, d3);