Extending ChucK - Programming for Musicians and Digital Artists: Creating music with ChucK (2015)

Programming for Musicians and Digital Artists: Creating music with ChucK (2015)

Appendix H. Extending ChucK

ChucK contains multiple levels of extensibility, each essential and appropriate to specific tasks and levels of user expertise. ChucK’s ethos of on-the-fly development creates a desire to design and implement new audio processors in ChucK itself in real-time, working down to the per-sample level if necessary. Implementing these components in ChucK allows their use on any OS ChucK supports with no additional effort from the developer. For these cases we have Chugens and Chub-graphs. On the other hand, real-time performance requirements often mandate the use of compiled native machine code for complex audio-rate processing. There also exists a wealth of C/C++-based software libraries for audio synthesis and effects, such as FluidSynth and Faust. These situations can be handled straightforwardly given portable bindings between ChucK and native compiled code, which is the intent of ChuGins.

Note

Portions of this appendix have been adapted from S. Salazar, and G. Wang (2012), “Chugens, Chubgraphs, ChuGins: 3 Tiers for Extending ChucK,” in Proceedings of the International Computer Music Conference, Ljubljana, Slovenia, with permission of the authors.

Chugens

Chugens (pronounced “chyoo-jens”) facilitate rapid prototyping of audio synthesis and processing algorithms. Chugens also provide a basic framework for extending ChucK’s built-in audio processing functionality. Using the Chugen system, a programmer can implement sample-rate audio algorithms within the ChucK development environment, utilizing the full array of programming facilities provided by ChucK. These processing units can be naturally integrated into standard ChucK programs, even in the same script file, providing seamless control of audio-rate processing, control-rate manipulation, and higher-level compositional organization.

A Chugen is created first by subclassing the built-in Chugen class. This subclass is required to implement a tick function, which accepts a single float argument (the input sample) and returns a single float (the output sample). The tick function is fundamental to a ChucK’s audio architecture; to produce a continuous audio stream, ChucK produces 44100 or 48000 samples per second, and each UGen in your program has its own tick function which generates its contribution to the current sample.

The following code uses a Chugen to synthesize a sinusoid using the cosine function, Math.cos.

class MyCosine extends Chugen

{

0 => int p;

440 => float f;

second/samp => float SRATE;

fun float tick(float in)

{

return Math.cos(p++*2*pi*f/SRATE);

}

}

Note that a cosine wave is a sine wave that is 90° “behind” (out of phase with) a sine wave—in most cases it will sound exactly like a sine wave.

A Chugen, once defined, may then be integrated into audio graphs like any standard ChucK UGen.

MyCosine cos => NRev reverb => dac;

Since the tick function is a standard ChucK class member function, it can be as simple or as elaborate as required. Standard library calls, file I/O, multiprocessing (using spork), and other general ChucK programming structures can be integrated into the tick function and supporting code. In the case of an audio synthesizer that does not process an existing signal, the input sample may be ignored. For performance reasons, it’s important to consider that the tick function will be called for every sample of audio, so simple tick functions will typically perform better. Moreover, the intrinsic overhead of ChucK’s VM architecture will cause Chugens to underperform compared to a native C/C++ implementation.

Since Chugens are only a type of ChucK class, they may define functions to provide structured access to whichever parameters they wish to expose to the programmer.

class MyCosine extends Chugen

{

0 => int p;

440 => float freq;

second/samp => float SRATE;

fun void setFreq(float theFreq)

{

theFreq => freq;

}

fun float tick(float in)

{

return Math.cos(p++*2*pi*freq/SRATE);

}

}

Here, we have added a setFreq function, which allows us to set the frequency of the cosine wave. As a general rule, you should always provide a function to set or get parameters from your Chugens, instead of allowing direct manipulation of member variables within the class. Providing a function to get and set a Chugen parameter indicates which parameters make sense to manipulate, and which ones are only important internally; messing with internal properties of any class is almost always a bad idea.

Lastly, we can make a public Chugen, just like normal classes, using the public keyword.

public class MyCosine extends Chugen

By making a Chugen public, we can use it in other ChucK scripts running in the same virtual machine.

Chubgraphs

Chubgraphs (pronounced “chub-graphs”) provide a way to construct new unit generators by composition, arranging multiple existing UGens into a single unit. In this way, common arrangements of existing UGens can be defined and instantiated. Chub-graph parameters can be exposed in a structured manner via class member functions.

A Chubgraph is defined by extending the Chubgraph class, which has built-in member variables named inlet and outlet. inlet is a UGen that represents the input signal to the Chubgraph, and outlet is the output signal. The Chubgraph’s internal audio processing graph is created by spanning a sequence of UGens between inlet and outlet. The following Chubgraph implements a basic feedback echo processor:

class Feedback extends Chubgraph

{

inlet => Gain dry => outlet;

dry => Delay delay => outlet;

delay => Gain feedback => delay;

0.8 => feedback.gain;

1::second => delay.delay;

}

(Chubgraphs that don’t need to process an input signal, such as audio synthesis algorithms, may omit the connection from inlet.)

Compared to Chugens, Chubgraphs have significant performance advantages, as audio-rate processing still occurs in the native machine code underlying its component UGens. However Chubgraphs are limited to audio algorithms that can be expressed as combinations of existing UGens. Implementing, for example, intricate mathematical formulae or conditional logic in the form of a UGen graph is possible but fraught with hazard.

Chubgraphs can be included in your audio patch like any other UGen. Like with Chugens, Chubgraphs can be declared as public to be used in other ChucK scripts, and can define member functions to provide control over any parameters that are available.

ChuGins

ChuGins (pronounced “chug-ins”) allow near limitless possibilities for expansion of ChucK’s capabilities. A ChuGin is a distributable dynamic library, typically written in C or C++ compiled to native machine code, which ChucK can load at runtime. When loaded, the ChuGin defines one or more classes that are then made available to ChucK programs. These classes may define new UGens or provide general programming functionality beyond that built into ChucK. Since these classes are normal ChucK classes implemented with native code, member functions and variables can be used to provide an interface to control parameters.

ChuGins are best suited for audio algorithms that are reasonably well understood and stand to gain from the performance of compiled machine code. The write-compile-run development cycle and C/C++-based programming mandated by Chu-Gins make implementation of audio processors require more effort than the Chub-graph or Chugen approaches. For UGens you intend to use over an extended period of time, the effort to implement a ChuGin will quickly pay off in the form of lower CPU usage.

An additional advantage of ChuGins is that they may provide functionality far outside the intrinsic capabilities of ChucK. Complex C/C++-based synthesis packages can be imported wholesale into ChucK, opening up an abundance of sonic possibilities. ChuGins have been implemented to bring audio processing programs from the Faust programming language into ChucK, for example. Similarly, the SoundFont renderer FluidSynth has been packaged as a ChuGin. This functionality is not limited to audio processing, as they may also be used to create general purpose programming libraries.

All of this power comes at the cost of ease of use, and as such we do not have enough pages to fully cover the ChuGin development process. We encourage programmers interested in making ChuGins to head to the ChucK extensions website for an online tutorial on ChuGin development:http://chuck.stanford.edu/extend/. The source code for many existing ChuGins can be found at https://github.com/ccrma/chugins.