Chucklib Livecode Manual Cl

User Manual: Pdf

Open the PDF directly: View PDF PDF.
Page Count: 46

DownloadChucklib-Livecode Manual Cl-manual
Open PDF In BrowserView PDF
Chucklib-Livecode Manual
H. James Harkins
January 30, 2018

Contents
1 Introduction
1.1 Overview . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
1.2 Acknowledgments . . . . . . . . . . . . . . . . . . . . . . . . . .

2
2
3

2 Installation
2.1 Installation with git . . . . . . . . . . . . . . . . . . . . . . . . . .
2.2 Installation without git . . . . . . . . . . . . . . . . . . . . . . . .
2.3 Running cll in a session . . . . . . . . . . . . . . . . . . . . . . .

3
3
3
4

3 Tutorial
3.1 Drums . . . . .
3.2 Pattern strings
3.3 Generators . .
3.4 Sound effects .
3.5 Pitched notes .
3.6 Phrases . . . .
3.7 Errors . . . . .

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

5
5
7
7
10
11
16
17

4 Process prototype
4.1 Data structure . . . . .
4.2 PR(\abstractLiveCode)
4.3 Parameter map . . . .
4.4 Event processing . . .
4.5 Phrase sequence . . .

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

18
18
18
21
22
23

5 Livecoding statement reference
5.1 Statement types . . . . . . . . . . . . . . .
5.2 Set pattern statement . . . . . . . . . . .
5.3 Start/stop statement . . . . . . . . . . . .
5.4 TODO Deprecate Randomizer statement
5.5 Make statement . . . . . . . . . . . . . . .
5.6 Passthrough statement . . . . . . . . . . .
5.7 Chuck statement . . . . . . . . . . . . . .

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

23
23
24
30
30
32
33
34

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

1

5.8
5.9
5.10
5.11

Func call statement . . . . . . . . . . . . .
Copy or transfer statement . . . . . . . .
Show pattern statement . . . . . . . . . .
TODO Check for more Helper functions

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

34
34
35
36

6 Generators
6.1 TODO Generator design [0/1] . . . . . . .
6.2 Generator usage . . . . . . . . . . . . . . .
6.3 Generators and rhythm . . . . . . . . . . .
6.4 TODO Check for new Built-in generators .
6.5 Writing new generators . . . . . . . . . . .

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

36
36
38
40
40
42

7 Extending cll
43
7.1 Statement regular expression . . . . . . . . . . . . . . . . . . . . 43
7.2 Handler object . . . . . . . . . . . . . . . . . . . . . . . . . . . . 45
8 Code examples

1

45

Introduction

1.1

Overview

Chucklib-livecode (cll for short) is a system of extremely compact commands
extending the SuperCollider programming language. The commands manipulate musical processes in real time to facilitate live-coding performances. “Processes” in this sense refers to my chucklib quark, introduced in The SuperCollider
Book.1
I began implementing cll in August 2014, and it reached a stage where
I could begin performing with it in March 2015. The public extensions are
hosted on github.2
cll consists of two main parts:
1. A chucklib process prototype (PR) that implements the methods that the
musical processes need, in order to receive information from live-coding
statements.
2. A preprocessor installed into the SuperCollider interpreter. The preprocessor translates the cll command syntax into standard SuperCollider code.
This document will cover the process prototype first. You need to understand its structure in order to understand the commands.
1 Harkins, H. James. (2011). “Composition for Live Performance with dewdrop_lib and chucklib.” In Wilson, S., Cottle, D., Collins N. [eds.] The SuperCollider Book. Cambridge, Mass.: MIT Press.
pp. 589–612.
2 http://github.com/jamshark70/chucklib-livecode

2

1.2

Acknowledgments

Thanks are due to:
• James McCartney and all the other developers who contributed to SuperCollider over the years. Without SuperCollider, none of this would exist.
• Alex McLean, for his work on the Tidal live-coding language for music.3
Tidal demonstration videos online were the first to capture my imagination about live coding, leading me in this direction.
• Thor Magnusson, whose ixilang system4 provided some of the inspiration
for cll syntax.
• Canton Becker of http://sampleswap.org for granting permission to redistribute some audio files from sampleswap’s online collection. These
are used in the ddwLivecodeInstruments quark, referenced in the Tutorial (section 3).

2

Installation

cll requires SuperCollider 3.7 or later, and recommends v3.9+. (It is released
using the Quarks v2 system, which is not supported prior to SC 3.7.)
2018/01/12: You should update all of the ddw* quarks. The built-in instruments in the ddwLivecodeInstruments quark require code changes in several
places, and they will not work correctly if you’re using out of date quark versions.

2.1

Installation with git

If you have installed the git version-control system on your machine, SuperCollider can automatically download and install Quark extensions. Simply evaluate Quarks.install("ddwChucklib-livecode"). If there are no error messages,
recompile the class library and you should be ready to proceed.
Optionally, also evaluate Quarks.install("ddwLivecodeInstruments") to
install a pack of ready-to-play instruments. These are used in the Tutorial (3).

2.2

Installation without git

If you haven’t installed git or don’t want to, you can download the required
Quark directories manually. In each of these web pages, look for the green
“Clone or Download” menu. From here, you can download a ZIP.
3 McLean, Alex. “Making Programming Languages to Dance to: Live Coding with Tidal.” Proceedings of the 2nd ACM SIGPLAN international workshop on Functional art, music, modeling &
design, September 6, 2014, Gothenburg, Sweden, pp. 63–70.
4 http://www.ixi-audio.net/ixilang/, accessed October 4, 2016.

3

• ddwChucklib: https://github.com/jamshark70/ddwChucklib
• ddwPrototype: https://github.com/jamshark70/ddwPrototype
• ddwCommon: https://github.com/jamshark70/ddwCommon
• ddwGUIEnhancements: https://github.com/jamshark70/ddwGUIEnhancements
• ddwMixerChannel: https://github.com/jamshark70/ddwMixerChannel
• ddwPatterns: https://github.com/jamshark70/ddwPatterns
• ddwTemperament: https://github.com/jamshark70/ddwTemperament
• ddwVoicer: https://github.com/jamshark70/ddwVoicer
• crucial-library: https://github.com/crucialfelix/crucial-library@tags/
4.1.5
• [optional] ddwLiveCodeInstruments: https://github.com/jamshark70/
ddwLivecodeInstruments
• In the SC IDE, go to File → Open user support directory.
• In this location, if there is no folder called downloaded-quarks, create this
empty folder now.
• Unpack all the ZIP files into the directory. After this, you should have:
– downloaded-quarks/ddwChucklib
– downloaded-quarks/ddwPrototype
– … and so on. If there is a -master suffix on the directory names,
please remove it.
• In SC, run the statement Quarks.install("ddwChucklib-livecode"). If it
doesn’t find the quarks, try recompiling the class library and then run the
statement again.
• If all is successful, recompile the class library and proceed.

2.3

Running cll in a session

cll adds three convenience functions to load the environment:
• \loadCl.eval: Load the cll preprocessor and a few helper functions.
• \loadClExtras.eval: Load extra user-interface components (mobile control with TouchOSC, and interactive code editor).
• \loadAllCl.eval: Load both of these at once.
These are not executed by default at SC startup, because you may not want
the preprocessor in every SC session. Once you load the environment, the preprocessor is active until the next time you recompile the class library.
4

3

Tutorial

First, if you didn’t install the optional ddwLivecodeInstruments quark, please
do so now. Without these, you will have to learn the mechanics of creating a
live-coding process before playing any music. See section 2 for details.
When starting a new session, run \loadAllCl.eval first.
ddwLivecodeInstruments provides a set of standard electronic drums (Section 3.1), and several synthesizers for pitched notes (Section 3.5).
I recommend working step-by-step, starting with the drums (because there
are fewer variables and moving parts) before moving on to pitches. You will
probably get more out of it by typing the code examples yourself, rather than
copying/pasting.5 I’ve tried to make it easy to get started, but bear in mind
that this improvisational instrument has 3.5 years of development behind it.
You shouldn’t expect to understand it all in 15 minutes (just as you wouldn’t
expect to read a couple of tutorials about SuperCollider itself and “understand”
it in depth). Take your time. Experiment. Start with the examples and change
them.
If you encounter problems, you could post on the SuperCollider users mailing list6 or the ddwChucklib-livecode issue tracker.7 (Also note that this is the
first version of the tutorial. Many things may be badly explained as yet. Don’t
hesitate to raise an issue if something is confusing.)

3.1

Drums

We’ll start with drums (Listing 1), because the notation is a little simpler.
Kicks and snares are created by the convenience function /drum.(name); use
/hh.(name) for hi-hats. Available names are:
• /drum.(name)
– \deepkick: BP(\dk)

– \tightkick: BP(\tk)
– \midkick: BP(\mk)

– \tightsnr: BP(\tsn)
– \fatsnr: BP(\fsn)

– \pitchsnr: BP(\psn)
– \snr80: BP(\s8)
– \clap: BP(\clp)

5 Copying from this PDF is likely to change the code formatting and possibly break the code. If
you must copy/paste, use the file cl-manual-examples.scd.
6 https://www.birmingham.ac.uk/facilities/ea-studios/research/supercollider/
mailinglist.aspx
7 https://github.com/jamshark70/ddwChucklib-livecode/issues

5

\loadAllCl . eval ;
TempoClock . tempo = 124/60;
/ hh .( \hardhh );
/ hhh = " . -. -. -. - " ;
/ hhh +
/ drum .( \tightsnr );
/ tsn = " - -" ;
/ tsn +
/ drum .( \deepkick );
/ dk = " o | o| _o | " ;
/ dk +
// mixing board
/ makeEmptyMixer8 .() ;
/ hhh => MCG (0) ;
/ tsn => MCG (1) ;
/ dk = > MCG (2) ;
/ hhh / tsn /dk Listing 1: A quick techno-ish drumset.

• /hh.(name)
– \thickhh: BP(\hh)

– \thinhh: BP(\thh)
– \hardhh: BP(\hhh)

– \synthhh: BP(\shh)
Note the pattern to use an instrument:
• Create it, using the right convenience function. The result is a BP object—
a Chucklib “bound process.” Address commands to the process object
by putting its name in parentheses: BP(\dk), for instance. Many cll commands use only the name with a leading slash: /dk.
• Give it some music to play (by assigning it a pattern string). More about
pattern strings below.
• Start it (+). If + is start, - is stop. You can start and stop several processes
at once by listing them on the same line, each name beginning with its
slash. By default, the processes will start or stop on the next bar line. You
can override this by putting a number of beats after the + or -: /dk+8 for
the next even bar line.
6

loadAllCl creates a few MixerChannel objects: ~master (main output),
~rvbmc (long-tail reverb) and ~shortrvbmc (short-tale reverb). If you want to
adjust the mix, first run /makeEmptyMixer8.(). After that, you can “chuck”
mixers, processes or Voicers into mixing board slots: ~master => MCG(7), e.g.,
for the rightmost slot. Later, when you create playing objects, you can chuck
them in as well. For instance, where Listing 1 creates a tightsnr player, you
can do /tsn => MCG(0) and adjust the level and post-send reverb amount. For
pitched instruments (later), you need to chuck the Voicer: VC(\pbs) => MCG(1)
or /VC.pbs => MCG(1).

3.2

Pattern strings

Cll uses single characters for notes, and spaces for timing placeholders.
• Kick drums: o = normal weight, _ = ghost note
• Snare drums: - = normal weight, . = ghost note8
• Hi-hats: - = open hat, . = closed hat
By default, the unit of time is one bar (taken from the default TempoClock,
whose default beatsPerBar is 4). The characters and placeholders divide this
time span equally: /hhh has 8 characters, splitting the bar into 8th-notes, while
/tsn has 4. You might think the spaces in /tsn are rests, but they aren’t: they
only specify the passage of time, here forcing the two snare drum strokes onto
beats 2 and 4.
The kick drum pattern is slightly more complicated. The vertical pipes (|)
are dividers: before, after and between the dividers, there are 4 time spans
(beats), each of which is divided equally by the characters contained within.
So the first beat is a quarter-note, the second divides into 8th-notes and the
third into 16ths. With a little practice, you can read the rhythm directly from
the ASCII notation.
• Exercise: Edit the given pattern strings to create more interesting rhythms.
After every change, reevaluate the line. This is the basic process of improvising with cll.

3.3

Generators

Cll can also generate new materials algorithmically. (The Quick start guide can
provide only a brief demonstration, not complete documentation. See Section
3.3 for more detail.)
Generators take a given pattern string as their initial input, and modify it
by inserting, deleting or replacing entries. (The initial pattern string can be
empty, by the way.) A few basic functions are:
8 The characters for kicks and snares are different, so that a kick and a snare could be combined
into one process. However, this feature is not fully implemented as of this writing.

7

/ hhh / tsn / dk +
// A
/ tsn = " \ins ( " - -" , " . " , 2, 0.25) " ;
// B
/ tsn = " \ins ( " - -" , " . " , 2, 0.5) " ;
// C
/ tsn = " \ins ( " - -" , " . " , 2, 0.5) :: \shift (, " . " , 2, 0.25) " ;
// D
/ hhh = " \ins ( " " , " -" , 1 , 0.5) :: \ins (, " . " , 7, 0.5) " ;
// E
/ hhh = " \ins ( " . " , " -" , 1, 0.5) :: \ins (, " . " , 6, 0.5) ";
// F
/ hhh = " \ins ( " . " , " -" , 1, 0.5) :: \ins (, " . " , 6, 0.5) :: \ins (, ". "
, 2, 0.25) " ;
// G
/ hhh = " \fork ( " " , "| \ins (, " -" , 1, 0.5) || x " ) :: \ins (, " . " , 7,
0.5) :: \ins (, " . " , 2, 0.25) " ;
/ hhh / tsn /dk Listing 2: Generators for drums.

8

• \ins("string", "item pool", number, quant): Insert number new items,
randomly chosen from the item pool, at rhythmic intervals given by quant
(e.g. 0.25 = quarter beats = 16th-notes).
• \shift("string", "item pool", number, quant): Locate number of the
items in item pool, and shift them earlier or later by the rhythmic value
given by quant.
• I will expand this list later.
For example, the snare drum would benefit from some ghost notes, and it’s
more fun if they change from bar to bar. We could insert them into any open
16th-note (Listing 2, example A). But if you play this long enough, eventually
you will hear some bars with too many 8th-notes. This sounds stilted. It would
be better to force the ghost notes onto off-beat 16ths. An easy way to do that is
to place the ghost notes onto 8th-notes (B), and then shift them (C). Note the
:: syntax. This creates a generator chain, where the result of the first generator
feeds into the first input of the second. (Because the chain provides the source
string for \shift(), you don’t need to write a source—but you still need the
comma.)
For hi-hats, a musically sensible way to operate is to place one or more
open hats, and then fill the remaining spaces with closed hats (D). Here too,
eventually you will run into a musical problem: an open hat on the downbeat
sounds awkward. Instead, you can place a closed hat explicitly in the first slot
(E), “protecting” that space from insertion. (The example adjusts the number
of closed hats to insert at the end, from 7 to 6. While formally correct, it isn’t
necessary in the performance. \ins() will add as many as it can, and not complain if it doesn’t reach the requested number.) Finally, for some more spice,
you can add a few 16th-notes.
Another way to “protect” part of the bar from a generator is to \fork() it.
\fork() takes a source string, and another string placing generators in specific
parts of the bar. In example G, the fork string places an \ins() on beat 2, and
follows it with an x on beat 4. The \ins(), then, cannot operate before beat
2, and the x ends the \ins() generator’s range of influence. So the open hat
can be inserted in positions 2, 2.5, 3 and 3.5 (not including 4, which belongs
to x). x is not a generator, so it does nothing in the context of \fork() except
delimit time. After the fork(), the remaining generators operate on the whole
bar, as before. This is an important technique to control the time over which
generators may take effect.
It isn’t very useful for drums, but a typical generator usage is to insert wildcards (usually * or @) to define the rhythm, and then replace them using a number of generators inspired by SuperCollider patterns: \seq(), \rand(), \shuf(),
\wrand() and such. These are more useful when you have a larger number of
possible items to choose from, such as when playing a pitched instrument.
HINT: If you have installed the ddwSnippets Quark, generator objects will
automatically add their own templates into the snippets collection. The snippets can help you with the order of arguments: press the snippet hotkey (which
9

\loadAllCl . eval ; // If you haven ' t already done this
TempoClock . tempo = 124/60;
// The beat
BP (#[ tk , clp , hhh , tsn ]) . free ; // Clean up first
/ drum .( \tightkick ); / drum .( \clap ); / hh .( \hardhh );
/ tk = " o || o | " ;
/ clp = " - " ;
/ hhh = " ........ " ;
/ tk / clp / hhh +
/ drum .( \tightsnr );
/ tsn = " |||. " ;
/ tsn +
/ clp = " | -|| . " ;
/ tsn = " |||. . " ;
// make the effects
/ make ( bufBP : mch ( set : \machine ));
/ mch = " | -|| " ;
/ mch +
/ mch = " | -| , ,| " ;
/ tk / clp / hhh / tsn / mch -;
Listing 3: Adding sound effects to a simple beat.

you configure using DDWSnippets.learn), type a few letters of the generator
name, and the template will be inserted into your document.

3.4

Sound effects

The bufBP template provides some unusual percussion sounds, for extra color.
The sounds are organized into “sets,” so that each resulting process has
a simpler interface. To choose a sound set, use the parameter notation of the
/make command: /make(bufBP:name(set:\setName)), substituting your desired
process name for name and the name of the set for setName.
• machine: Servomotor clips (3)
• tink: Metallic (2)
• whistle: A sound reminiscent of a train whistle (3)

10

• wiggle: A, well, “wiggle” (for lack of a better word) (3)
In pattern strings, you can use the following characters (chosen as a visual
approximation of pitch level and duration):
Pitch
High
Middle
Low

Long
^
_

Short
!
.
,

Note, however, that the tink set has only two sounds, omitting the high
pitch level. With this set, ^ and ! are rests (silent).
Figure 3 is a simple example. You should play with the other sets and make
your own rhythms.

3.5

Pitched notes

Pitched-note processes require a Voicer instrument and a BP process to play
the notes.
Available Voicers:
• anapadVC: Analog-style pad.
• distbsVC: Distorted-sine bass.
• fmMelVC: Maps notes onto FM modulator ratio, playing harmonics. A bit
strange.
• fmbassVC: FM bass.
• fmbrassVC: Brassy FM tone.
• fmclavVC: FM clav tone.
• fmpadVC: FM pad.
• klankVC: Detuned bell-like timbre. Not sustaining.
• pbsVC: Pulse-wave bass.
• pulseLeadVC: Pulse-wave synth lead.
• staccVC: Analog-style staccato notes.
Available BP processes:
• melBP: Monophonic melody player. Use for basses and leads.
• chordBP: Block-chord player.
• arpegBP: Chord arpeggiator.
11

Mode ( \dmixo ) => Mode ( \default ) ;
/ make ( pbsVC : pbs / melBP : bs ( octave :3) ) ;
/ bs = " 1 _ | 1.|

7 ~4 | x " ;

/ bs +
/bs Listing 4: Bassline template.

3.5.1 Basses and leads
First, make the instrument and player. Behind the scenes, this is a three-step
process: create the Voicer instrument, create the playing process, and connect
the instrument to the player. If you write the /make command as shown in
Listing 4, cll will do all three in one go.
The general form is /make(factoryID:instanceID(parameters...)) with
additional factory/instance pairs separated by slashes.
For basses in particular, get in the habit of assigning the octave. This is the
normal octave event parameter from the SuperCollider pattern system. Assuming C as the modal root, octave 5 puts scale degree 0 at middle C. Octave 3 in
the example pulls the bass two octaves lower. If you forget, you can correct it
later by /bs(setDefault(\octave, 4)) or whichever octave number you need.
Then you can assign notes using cll’s pitch notation. Pitches are modal (and
currently assume seven degrees to the octave, like Western scales—a later
enhancement may support more or fewer degrees). So, it’s recommended to
choose the mode before you play by “chucking” (=>) a specific mode into
Mode(\default). Modes are identified by the root pitch (c, cs = c-sharp,
db = d-flat, and so on) plus a modal identifier (Table 1). B-flat lydian is
Mode(\bblyd).
Table 1: Modal identifiers.

Mode
Major (Ionian)
Dorian
Phrygian
Lydian
Mixolydian
Minor (Aeolian)
Locrian

ID
maj
dor
phr
lyd
mixo
min
loc

The modal root is 1. Each note begins with a single digit, going up from
there: 8 is an octave higher, 9 is the 9th, and 0 is the 10th (octave above the
third). This follows the arrangement of digits on the keyboard: the further right
you go, the higher the pitch. You can also attach various modifiers:
12

/ make ( anapadVC : pad / chordBP : ch ( chords : \one ));
/ ch = " 87 ~05 " ;
/ ch +
VC ( \pad ). gui
MBM (0) [ \two ] => BP ( \ch ) ;
MBM (0) [ \smallch ] => BP ( \ch );
/ch Listing 5: Chord-playing template.

• ' or ,: Up or down one octave. '' is up two octaves, and so on.
• + or -: Up or down a semitone (like sharp or flat). NOTE: Flats are not
completely working as of this writing.
• . or _ or ~: Staccato, legato or slurred articulation. A slur will slide into
the next note, if the instrument supports it.
• >: Accent articulation. Always prevents a slur, and depending on the instrument, it might hit the note a little harder. > may be combined with
other articulations.
The digit plus its modifiers becomes a single event—so, in Listing 4, beat 3
contains five characters but four events (7~ is just one event). Timing is based
on events, not characters.
Any event that does not begin with a digit—the x—is a rest, which cuts off
the preceding note (in contrast to a space, which affects timing only).
Leads follow the same principles, except in a higher octave.
Exercise: Modify the given template to add more notes. Try the different
articulation styles.
3.5.2 Chords
chordBP (Listing 5) uses the same pitch notation, but to control the top note of
a harmony. The harmonies come from chord templates stored in a MIDI buffer
object (MIDIRecBuf). Currently, four are provided (later documentation: how
to create your own chord templates).
• one: Single notes (so that the chord player can start as a melody, and
grow into harmony).
• two: Two-note chords, in all intervals from a second to an octave.
• smallch: Three-note chords, not all standard triads.
13

• bigch: Six-note chords.
The chord templates will be adapted to the top note and the current chord
root (later documentation: how to control the root).
Articulations (including slur!) are valid.
3.5.3 Arpeggiator
NOTE: The arpeggiator is a bit complex to use, and it isn’t a high priority for
the first round of documentation. I’m providing an example (Listing 6) to give
you some hints, and I want to expand the documentation later. For now, try it,
and if you run into trouble, file an issue at https://github.com/jamshark70/
ddwChucklib-livecode/issues.
The arpeggiator is a bit strange. It uses the same harmony-processing logic
as chordBP, but the pitches in the pattern string are indices of chord notes, not
the actual sounding pitches. 1 is the top note, 2 is the next lower, and so on
proceeding down the chord to 7. 8, as a normal pitch, is an octave higher than
1; in the arpeggiator, it takes the top note of the chord and raises it by an octave
(and all seven indices do octave displacement in the same way).
To make best use of this process, you need to assign alternate parameters:
top for the top note of the harmony (which behaves like chordBP) and skip for
extra thickness. The default skip is 0, meaning to play single notes. Try the
other values (1–5). Note that the harmony will not change unless top changes,
so it’s a good idea to supply a slower-moving pattern for this parameter.
The double-dots are a syntax shortcut. Cll processes can store any number of
phrases and switch between them. So far, we are using only the default phrase,
main. The full form of the skip and top statements in the example is, in fact,
/arp.main.top = "..."; omitting main leaves /arp..top. (You can’t leave out
one of the dots. If you do, top will be interpreted as a phrase name, and it won’t
behave the way you want.)
3.5.4 Pitched instrument parameters
Voicer instruments have two types of parameters: “global controls” and event
parameters.
Global controls act like knobs on conventional synthesizers, by affecting
all playing notes. These can be displayed automatically in a GUI window by
running VC(\name).gui. Alternately, you could load Chucklib’s performance
GUI (BP.loadGui) and “chuck” (or drag) Voicers into the control slots at the
right: VC(\name) => VP(0) to put the instrument into the topmost space, and
so on.
Event parameters should normally take care of themselves. If you need
to override, use the form /processName(setDefault(\parameter, value)). It
should be rare to need to do this, but it’s useful, for instance, if you forget to
set the octave of a bass process and it starts playing in the middle register. Just

14

/ make ( fmclavVC : fmc / arpegBP : arp ( chords : \bigch ));
// These are indices , from the top down , into the current chord
.
/ arp = " 1234 " ;
/ arp +
// Add some lower notes as a second layer .
// Accent articulates the start of the bar .
/ arp = " \ins ( " 1 >234 " , " 456 " , 6 , 0.25) " ;
// Extend the second layer higher .
/ arp = " \ins ( " 1 >234 " , " 23456 " , 7, 0.25) " ;
// Use wildcards to substitute a sequential pattern .
/ arp = " \ins ( " 1 >234 " , " * " , 7 , 0.25) :: \seq (, " 65432 " )" ;
// Change the harmony ' s top note every bar .
/ arp .. top = " \seq ( "* " , " 5 '6 '3 '2 '" ) " ;
// Skip : Play dyads instead of single notes .
/ arp .. skip = " 2 " ;
// Skip can also accent specific notes .
/ arp .. skip = " 20 |20 |20 |20 " ;
// same , but algorithmic
/ arp .. skip = " \choke ( " 2222 " , 0.25 , "0 " ) " ;
// Add a second process to change the chord root .
// After this , you should hear tonic , dominant
// and subdominant functions .
// No instrument -- this is for data only .
/ make ( melBP : root ( bassID : \bass ) );
/ root = " \seq ( " * " , " 154 " ) " ;
/ root +
/ arp / root Listing 6: Example of arpeggiator usage.

15

TempoClock . tempo = 124/60;
/ drum .( \tightkick ); / drum .( \tightsnr ); / hh .( \thinhh );
/ tk = " oooo " ;
/ tsn = " - -" ;
/ thh = " \ins ( " . " , " -" , 1, 0.5) :: \ins (, " . " , 6, 0.5) ";
/ tk / tsn / thh +
/ tk . fill = " o ||
_| o __ " ;
/ tsn . fill = " | -| \ins ( " - " , " . " , 4, 0.25) | ";
/ tk = ( main *3. fill ); / tsn = ( main *3. fill );
/ tk / tsn / thh Listing 7: Phrase selection for drum fills.

do /process(setDefault(\octave, 3)) (or other value) and the next note will
be lower.
(This is a tutorial, not reference documentation for all the instruments. Documentation to be expanded later.)

3.6

Phrases

The examples so far repeat a single bar’s worth of content. Cll processes allow
you to define multiple bars, and choose between them.
Each bar, or phrase, has a name. Attach it after the process name, with a
dot: /process.phrase = "content". Then, use a phrase selection pattern (Section 5.2.5) to choose the bars in succession. Listing 7 demonstrates with drum
processes, playing the basic pattern for three bars and a fill pattern for the
fourth.
Alternately, you can create multi-bar structures using a few convenience
functions (Listing 8):
• /setupbars.(\proc, n, \prefix): Creates n empty bars, named \prefix0,
\prefix1 and so on.
• /setm.(\proc, n, \prefix): Tell the process to use a multi-bar phrase
set for playback.
• /bars.(\proc, n, \prefix): Do both at the same time.
IMPORTANT: Do not omit the . between the function name and the arguments. Cll distinguishes between a function-call shortcut /name.(args) and

16

// If the bass doesn ' t exist , first do this :
/ make ( pbsVC : pbs / melBP : bs ( octave :3) ) ;
/ bars .( \bs , 2, \a );
/ bs . a0 = " 1 >|4 ~5~7 | 4 ~ |3 ' ~" ;
/ bs . a1 = " 5> ~ |6| 4~ | 3 " ;
/ setupbars .( \bs , 2, \b ) ;
/ bs . b0 = " 9 >.9.9 | 4' ~ |
3 '|8 ~7~8~ " ;
/ bs . b1 = " 33.| 4.5 ~ | 431.|6.6. 6. " ;
// short form of / setm .( \bs , 2 , \b )
/ bs = (b **2) ;
/ bs +
/bs Listing 8: Multi-bar bassline.

a method-passthrough shortcut /proc(method(args)), with the dot to tell the
difference.
Note that /bars.() will tell the process to start playing a silent phrase structure. So, you should use it only when setting up a new process. If you’re already
playing material, it’s better to /setupbars.() first, fill the bars with material,
and then switch to the material using /setm.().
An alternate syntax for /setm.() is /proc = (prefix**n). This command
also sets the process’s quant to the same number of bars, so that the process
will start and stop on the boundaries of the entire phrase set. Be careful when
switching from a single-bar structure to multiple bars: you should hit /setm.()
or the alternate syntax within the bar before the boundary.
For convenience, /setupbars.() will try to insert a code template with the
empty bars into the current SC-IDE document.

3.7

Errors

Cll syntax errors will usually be reported as SuperCollider execution errors,
with a full stack trace. In general, you can ignore the stack trace.
A common error is “ERROR: clPatternSet: BP(‘abc’) does not exist,” meaning
that a cll command referred to a process that hasn’t been created. Look for a
misspelled name. (Cll is a translator, converting its own syntax into SC language
code. Many of the translations depend on information within the object. If
the objects don’t exist, translation is impossible. So, it fails in the translation
stage—but the translation happens in SC language code, so it must be reported
as an execution error.)
17

If an error occurs within a process while it’s playing, usually the bottom
of the stack trace will refer to awake or prStart. Please report such errors to
https://github.com/jamshark70/ddwChucklib-livecode/issues; as much as
possible, cll should try to continue playing without stopping processes. If this
does happen to you, the way to recover is to stop, reset, play (it is necessary to
stop the process before replaying it):
// Playback error recovery
/ proc -;
/ proc ( reset );
/ proc +;

4

Process prototype

4.1

Data structure

cll organizes musical behavior, and musical content, hierarchically:
• Chucklib processes (BP) contain any number of phrases. Every process has
its own variable scope (i.e., independent namespace). Activity in one process does not interfere with other processes.
• Each phrase contains multiple parameters. (The phrase itself is implemented as a PbindProxy, so that its contents can be changed at any time.)
• Each parameter is defined by a pattern string, parsed and rendered into
SuperCollider pattern syntax by the Set pattern statement (Section 5.2).
• Parameter values are defined by the parameter map (parmMap).
cll processes create two phrases by default:
main The default phrase, which plays if the user hasn’t specified a different
phrase sequence. main is also the default phrase that Set pattern acts on—
thus, a user can work with single-bar loops using only main, and never
specify a phrase ID.
rest An empty phrase, which only occupies time.

4.2

PR(\abstractLiveCode)

To create a cll process, “chuck” PR(\abstractLiveCode) into a BP (“Bound Process”), with a parameter dictionary providing the details. Parameters to include
in the dictionary:
userprep A function, called when the process is created. Use this function to
create any resources that the process will require.
18

(
PR ( \abstractLiveCode ). chuck ( BP ( \beep ) , nil , (
userprep : {
~buf = Buffer . read (
s , Platform . resourceDir +/+ " sounds / a11wlk01 . wav " ,
4982 , 10320
);
~defaults [ \bufnum ] = ~buf ;
SynthDef ( \buf1 , { | out , bufnum , pan , amp , time = 1|
var sig = PlayBuf . ar (1 , bufnum ) ,
eg = EnvGen . kr (
Env . linen (0.02 ,
min ( time , BufDur . ir ( bufnum ) - 0.04) , 0.02) ,
doneAction : 2
);
Out . ar ( out , Pan2 . ar ( sig , pan , amp * eg ));
}) . add ;
},
userfree : {
~buf . free ;
},
defaultParm : \amp ,
parmMap : (
amp : ( $ .: 0.1 , $ -: 0.4 , $ ^: 0.8) ,
pan : (
$ <: -0.9 , $ >: 0.9 ,
$ (: -0.4 , $ ): 0.4 ,
$ -: 0
)
),
defaults : ( instrument : \buf1 ) ,
postDefaults : Pbind (
\time , ( Pkey ( \dur ) * 0.6 / Pfunc { ~clock . tempo }) . clip
(0.04 , 0.2)
)
));
)
// Use it , with cll statements :
TempoClock . tempo = 2;
/ beep = " ^|.. .| .- | .
/ beep +; // start it

";

// " Set pattern "

/ beep .. pan = " <><><><>" ;
/ beep -;
/ beep ( free );
Listing 9: A simple cll process.

19

userfree A function, called when the process is destroyed. Clean up any resources allocated in userprep.
defaultParm The name of the default parameter affected by Set pattern statements (Section 5.2). The default parameter also controls rhythm.
parmMap A nested dictionary of parameters, their allowed values, and the characters that will identify these values in pattern strings.
defaults An Event or event pattern providing default values for the events
that the process will play.
postDefaults (optional) An event pattern that can do further calculations on
the parameter values.
Note: Chucklib documentation says to place the initialization function into
prep, and cleanup into freeCleanup. PR(\abstractLiveCode) uses these
functions for its own initialization and cleanup, and calls userprep and
userfree from there. Do not override prep and freeCleanup, or your process will not work properly.
This dictionary is not limited to these items. You may add any other data
and functions that you need, to define complex behavior in terms of simpler
functions and patterns.
In Listing 9, userprep loads a buffer and userfree releases it. By default,
Set pattern will operate on amp, and parmMap defines three values for it (soft,
medium and loud). parmMap also provides some panning options. The defaults
dictionary specifies the SynthDef to use (it may provide other synth defaults as
well, not needed in this example), and postDefaults calculates the sounding
duration of each note based on rhythm.
Note the line ~defaults[\bufnum] = ~buf: You may add values into defaults
as part of userprep. That’s necessary in this case because the buffer number is
not known in advance. The only way to supply the buffer number as a default
is to read the buffer first, and put it into the defaults dictionary only after that.
Note: Clearly, the code to initialize the process in Listing 9 is too long to
be practical to type in the middle of a performance. For practical purposes,
you should place all of the process definitions into a separate file, which
you would load once at the beginning of a performance. See also the Make
statement (Section 5.5), which makes it easy to instantiate the processes as
needed during the performance, reducing the overhead of initial loading.
(In fact, Chucklib was designed from the beginning to “package” complex
musical behaviors into objects that are simpler to use, once defined. cll is
an even more compact layer of control on top of this, following the same
design principle: definition and performance usage are different, and call for
different types of code.)

20

4.3

Parameter map

The parameter map parmMap is easiest to write as a set of nested Events:
parmMap : (
parmName : (
char : value ,
char : value ,
char : value ...
),
parmName : (...)
)
Listing 10: Template for the parameter map.

parmName keys should be Symbols. The keys of the inner dictionaries should
be characters (Char), because the elements of the pattern strings that represent
“notes” are characters.
The inner dictionaries may contain two other items, optionally:
isPitch If true, enables pitch notation for this parameter (Section 5.2.4).
alias An alternate name for this parameter, to use in the pattern. For example,
if the parameter should choose from a number of SynthDefs, it would be
inconvenient to type instrument in the performance every time you need
to control it, whereas def would be faster. You can do this as follows:
parmMap : (
def : (
alias : \instrument ,
$s : \sawtooth , $p : \pulse , $f : \fm
)
)
// Then you can set the " instrument " pattern :
/ proc . phrase . def = " s " ;

Written this way, def in the Set pattern statement will be populate
instrument in the resulting events.
4.3.1 Array arguments in the parameter map
Array arguments are valid, and will be placed into resulting events as given
in the parameter map. In Listing 11, freqs will receive the array [200, 300,
400] and process that array according to the event prototype’s rules.
parmMap : (
freqs : (
$2 : [200 , 300 , 400] ,
),
parmName : (...)

21

)
Listing 11: How to write arrays in the parameter map.

Envelopes may be passed to arrayed Synth controls in the same way:
Env.perc(0.01, 0.5).asArray.
Note: The above is valid for the event prototype used by default in
PR(\abstractLiveCode). This is not SuperCollider’s default event; it’s a custom event prototype defined in chucklib that plays single nodes and integrates more easily with MixerChannel. Because each such event plays only
one node, array arguments are passed as is. The normal default event expands one-dimensional arrays into multiple nodes. The way to avoid this
is to wrap the array in another array level.
parmMap
array format
[1, 2, 3]
[[1, 2, 3]]

singleSynthPlayer
meaning
Pass the array to one
node
Invalid

Default event meaning
Distribute the three values to three nodes
Pass the array to one
node

One other use of parameter map array is used to set disparate Event keys using one cll parameter. Pbind allows multiple keys to be set at once by providing
an array for a key. cll supports this by using an array for the alias!
parmMap : (
filt : (
alias : [ \ffreq , \rq ],
$x : [2000 , 0.05]
)
)
Listing 12: Arrays for multiple-parameter setting using one cll parameter.

4.4

Event processing

Every event produced by a cll process goes through three stages:
1. Insert all the items from defaults.
2. Insert the values from the current phrase (defined by pattern strings).
3. Insert any values from postDefaults. This may be a Pbind, and it has
access to all the values from 1 and 2 by Pkey.
Thus, you can use postDefaults to derive values from items defined in the
parameter map, or to check for invalid values.
22

Table 2: List of available chucklib-livecode statements.

Type
Set pattern
Start/stop
Randomizer
Make
Passthrough
Chuck
Func call
Copy
Transfer
Show pattern

4.5

Function
Add new musical information into a process
Start or stop one or more
procesess
Create several randomized
patterns at once
Instantiate a process or
voicer
Pass a method call to a BP
Pass a chuck => operation
to a BP
Call a function in chucklib’s
Func collection
Copy a phrase or phrase set
into a different name
Like ”Copy,” but also uses
the new phrase for play
Copies a phrase pattern’s
string into the document,
for editing

Syntax outline
/proc.phrase.parm =
"data"
/proc/proc/proc+ or /proc.phrase.parm *n +ki
"base"
/make(factory/factory)
/proc(method and
arguments)
/proc => target
/funcname.(arguments)
/proc.phrase*n -> new
/proc.phrase*n ->> new
/proc.phrase.parm

Phrase sequence

cll “Set pattern” statements put musical information into any number of
phrases. When you play the process, it chooses the phrases one by one using a
pattern stored as phraseSeq. “Set pattern” has a compact way to express phrase
sequences, allowing sequences, random selection (with or without weights) and
wildcard matching. See Phrase selection for details (Section 5.2.5).
This design supports musical contrast. The performer can create divergent
materials under different phrase identifiers. Then, during the performance, she
can change the phrase-selection pattern to switch materials on the fly. Sudden
textural changes require changing many phrase-selection pattern at once. For
this, Register commands can save sequences of statements to reuse quickly and
easily.

5
5.1

Livecoding statement reference
Statement types

cll statements begin with a slash: /. Statements may be separated by semicolons
and submitted as a batch.
23

// run one at a time
/ kick . fotf = " ----";
/ snare . bt24 = " - -" ;
// or as a batch
/ kick . fotf = " ----"; / snare . bt24 = " - -" ;
Listing 13: Cll statements, one by one or as a batch.

cll supports the statements shown in Table 2, in order of importance.

5.2

Set pattern statement

Set pattern is the primary interface for composing or improvising musical materials. As such, it’s the most complicated of all the commands.
This statement type subdivides into two functions: phrase definition and
phrase selection.
5.2.1 Phrase definition
Most “Set pattern” statements follow this format:
/ proc . phrase . parm = quant " string " ;
Listing 14: Syntax template for the Set pattern statement.

Syntax elements:
proc The BP’s name.
phrase (optional) The phrase name. If not given, main is assumed.
parm (optional) The parameter name. The BP must define a default parameter
name, to use if this is omitted.
quant (optional) Determines the phrase’s length, in beats.
• A number, or numeric math expression, specifies the number of
beats.

• + followed by a number indicates “additive rhythm.” The number
is taken as a base note value. All items in the string are assumed to
occupy this note value, making it easier to create fractional-length
phrases. (If only + is given, the BP may specify division; otherwise
0.25 is the default.)
• If quant is omitted entirely, the BP’s beatsPerBar is used. Usually
this is the beatsPerBar of the BP’s assigned clock.
string Specifies parameter values and rhythms.

24

Note: Both the phrase and parameter names are optional. That allows the
following syntactic combinations:
Syntax
/proc = "string"
/proc.x = "string"
/proc.x.y = "string"
/proc..y = "string"

Behavior
Set phrase ”main,” default parameter
Set phrase ”x,” default parameter
Set phrase ”x,” parameter ”y”
Set phrase ”main,” parameter ”y”

Of these, the last looks somewhat surprising. It makes sense if you think of
the double-dot as a delimiter for an empty phrase name.

5.2.2 Pattern string syntax
Pattern strings place values at time points within the bar. The values come
from the parameter map. Timing comes from the items’ positions within the
string, based on the general idea of equal division of the bar.
Two characters are reserved: a space is a timing placeholder, and a vertical
bar, |, is a divider.
If the string has no dividers, then the items within it (including placeholders) are equally spaced throughout the bar. This holds true even if it’s a nonstandard division: #4 (Figure 1) has seven characters in the string, producing
a septuplet.
If there are dividers, the measure’s duration will be divided first: n dividers
produce n + 1 units. Then, within each division, items will be equally spaced.
The spacing is independent for each division. For example, in #6 below, the
first division contains one item, but the second contains two. For all the divisions to have the same duration, then, - in the second division should be half
as long as in the first.
Note: It isn’t exactly right to think of a space as a “rest.” "- - " is not really
two quarter notes separated by quarter rests; it’s actually two half notes! If
you need to silence notes explicitly, then you should define an item in the
parameter map whose value is a Rest object.

Note: Set pattern writes the character identifiers for the values into the
pattern: for example, a pattern string "--" becomes Pseq([$-, $-], 1).
PR(\abstractLiveCode) post-processes each parameter, ensuring that the
right event keys receive the right values. The conversion from identifier
value occurs for each parameter; you should be able to rely on accessing the
final values by Pkey. This supports Generators (Section 3.3), which should
also return the value identifiers.

25

1. "--"
2. "----"
3. "- --"
7

4. "- --- -"
5. "-|-|-|-"
6. "-|--|-|-"
7. "--| -

|- --| -"

Figure 1: Some examples of cll rhythmic notation, with and without dividers.

5.2.3 Timing of multiple parameters
Each parameter can have its own timing, but a Pbind can play with only one
rhythm, raising a potential conflict.
The Pbind rhythm is determined by the pattern string for the defaultParm
declared in the process. When you set the defaultParm, the rhythm defined
in that string is assigned to the \dur key, where it drives the process’s timing.
Other parameters encode timing into a Pstep, to preserve the values’ positions
within the bar. Think of these as “sample-and-hold” values, where the control
value changes at times given by its own rhythm, but is sampled only at the times
given by the defaultParm rhythm.
For example, here, the default parameter’s rhythm is two half notes. At the
same time, a filter parameter changes on beats 1, 2 and 4. The process will play
two events, on beats 1 and 3. On beat 1, the filter will use its a value; on beat
3, it will use the most recent value, which is b. The filter will not change on beat
2, because there is no event occurring on that beat!
What about c? There is no event coming on or after beat 4, so c will be
ignored in this case. But, if you add another note late in the bar, then it will
pick up c, without any other change needed.
/x = " --" ;
/x. filt = " ab c " ;
/x = " -|-

-" ;

// " c " is not heard

// now " c " is heard on beat 4.5

Listing 15: Multiple parameters with different timing.

26

5.2.4 TODO Pitch notation [0/2]
5.2.4.1 TODO Accents in list (also: no PmonoArtic support)
5.2.4.2 TODO Fix bass example If a parameter’s map specifies isPitch:
true, then it does not need to specify any other values and the following rules
apply:
• Scale degrees are given by decimal digits, where 1 is the tonic and 0
is the interval of a tenth above that (following the number row on the
keyboard).9
• + and - raise and lower the pitch by a semitone.
• ' and , displace the pitch by an octave up or down, respectively.10 Multiple apostrophes or commas displace by multiple octaves. (This syntax
is borrowed from LilyPond.)
• . indicates a staccato note.
• _ indicates legato (sustain duration slightly shorter than note duration).
• ~ slurs this note into the next note.
Note: You should use the default event prototype for this process. Include
the following in the “chuck” parameter dictionary, as in Listing 16:
event: (eventKey: \default)

Note: Items in pitch sequences may include more than one character: 3 is
one note, as is 6+,~. They are converted into SequenceNote objects in the
pattern, because SequenceNotes can encode pitch and articulation information. Post-processing in PR(\abstractLiveCode) extracts the articulation
value and assigns it to \legato (or \sustain for staccato notes).
Listing 16 illustrates the kind of articulation that is possible with this notation, using a 90s-throwback acid-style bassline. Though the sound is not as
cool as a real TB303, careful use of slurs and staccatos mimics the feel of the
venerable old machine.11 A further refinement would be to add values for filter
frequency and filtMul into the parameter map.
9 In

SuperCollider pattern terms, 1 translates into degree 0.
a diatonic scale (7 degrees) is assumed.
11 Note the trick to get monophonic synthesis. Assigning a PmonoArtic into postDefaults effectively turns the entire event-producing chain into a PmonoArtic—even if it adds no musically useful
information into the resulting events. Caveat: If you will have any notes slur across the barline,
make sure to include alwaysReset: true in the BP parameter dictionary.
10 Currently

27

(
SynthDef ( \sqrbass , { | out , freq = 110 , gate = 1,
freqMul = 1.006 , amp = 0.1 ,
filtMul = 3, filtDecay = 0.12 , ffreq = 2000 , rq = 0.1 ,
lagTime = 0.1|
var sig = Mix (
Pulse . ar (
Lag . kr ( freq , lagTime ) * [1 , freqMul ],
0.5
)
) * amp ,
filtEg = EnvGen . kr (
Env ([ filtMul , filtMul , 1] , [0.005 , filtDecay ], \exp ) ,
gate
),
ampEg = EnvGen . kr (
Env . adsr (0.01 , 0.08 , 0.5 , 0.1) ,
gate , doneAction : 2
);
sig = RLPF . ar ( sig , ( ffreq * filtEg ). clip (20 , 20000) , rq );
Out . ar ( out , ( sig * ampEg ) . dup ) ;
}) . add ;
BP ( \acid ). free ;
PR ( \abstractLiveCode ). chuck ( BP ( \acid ) , nil , (
event : ( eventKey : \default ) ,
alwaysReset : true ,
defaultParm : \degree ,
parmMap : (
degree : ( isPitch : true ) ,
),
defaults : (
ffreq : 300 , filtMul : 8, rq : 0.2 ,
octave : 3, root : 6 , scale : Scale . locrian . semitones
),
postDefaults : PmonoArtic ( \sqrbass ,
\dummy , 1
)
));
TempoClock . tempo = 132/60;
)
/ acid = " 1 _

1.|5 ~3_9 .4.|7.2 ~4_5 '.|5 _8~2_4 . ";

/ acid +;
/ acid -;
Listing 16: A retro acid-house bassline, demonstrating pitch notation.

28

5.2.5 Phrase selection
Statements to set the phrase sequence follow a different syntax:
/ proc = ( group ...) ;
Listing 17: Syntax template for “Set pattern” phrase selection.

group can consist of any of the following elements:
Phrase ID The name of any phrase that’s already defined, or a regular expression in single quote marks. If more than one existing phrase matches the
regular expression, one of the matches will be chosen at random; e.g., to
choose randomly among phrases beginning with x, write '^x'.
Name sequence Two or more of any of these items, separated by dots and
enclosed in parentheses: (a0.a1.a2). These will be enclosed in Pseq.
Random selection Two or more of any of these items, separated by vertical
bars (|) and enclosed in parentheses: (a0|a1|a2). These will be enclosed
in Prand. One will be chosen before advancing to the next ID.
Phrase group A name, followed by two asterisks and a number of bars in the
phrase group. If a four-bar phrase is stored as a0, a1, a2, and a3, you
can write it simply as a**4. The preprocessor will expand this to regular
expression matches, as if you had written ('^a0'.'^a1'.'^a2'.'^a3').
The use of regular expression matching here is to make it easier to have
slight variations on the bars within the phrase group, while keeping the
same musical shape.
Any of these items may optionally attach a number of repeats *n: (a*3.b)
translates to Pseq([Pn(\a, 3), \b], inf), and (a*3|b) to Prand([Pn(\a, 3),
\b], inf).
Items in a random selection may also attach a weight %w, which must be
given as an integer: (a%6|b%4) has a 60% chance of choosing a and a 40%
chance of b. If no weight is given, the default is 1. Weights are ignored for
sequences (separated by dots).
Groups may be nested, producing complex structures compactly. For example, to have an 80% chance of a for four bars, then an 80% chance of b for two
bars, you would write:
(( a %4| b) *4.( a|b %4) *2)
Listing 18: Nested phrase-selection groups.

You may also include both . and | in a single set of parentheses. The dot
(for sequence) takes precedence: (a.b|c) evaluates as ((a.b)|c).

29

5.3

Start/stop statement

The start/stop statement takes the following form:
• Start: /proc1/proc2/proc3+quant
• Stop: /proc1/proc2/proc3-quant
Any number of process names may be given, each with a leading slash.
quant, an integer, tells each process to start or stop on the next multiple
number of beats. In 4/4 time, /proc+4 will start the process on the next bar
line; /proc+8 will start on the next event-numbered bar line (i.e., every other
bar). quant is optional; if not given, each process will use its own internal quant
setting. By default, this is one bar; however, the setm helper function overrides
this for the given number of bars.

5.4 TODO Deprecate Randomizer statement
Randomizers create randomized variations on a given string:
/ proc . prefix . parm *n + ki % q " string "
Listing 19: Syntax template for randomizer statement.

proc The process into which the new variations will go.
prefix A phrase identifier. Mandatory.
parm (optional) The parameter to control.
n The number of variations to create. Each becomes a new phrase: prefix0,
prefix1 up to n − 1.
k The number of sequence items to add.
i The sequence item: either a single character (defined in the parmMap) or the
name of a Func, with a leading backslash \.
q (optional) The quantization factor, determining where in the bar the new
notes may be placed.
string A template, providing items and rhythms that should be constant over
all variations. You may use an existing pattern string from any process by
omitting the quote marks and substituting phrase.parm (if the template
comes from the same process) or /proc.phrase.parm (if it comes from a
different process).
Note: At present, the string must contain vertical-bar dividers (|). I may
remove this limitation in a future version. For now, passing a string without
dividers will cause an error.
The randomizer’s algorithm is:
30

// assuming BP ( \snr ) defines :
// " -" ( normal note )
// "." ( softer note )
// Produces strong notes on 2 and 4, and one note elsewhere
/ snr . a *10 +1. " | -|| - " ;
/ snr = ( '^ a '); // randomly choose one variation for each bar
// " -" = open , "." = closed
/ hh = " ..|..|..|.. "; // all closed at first
// add an open HH on any empty 16 th
/ hh .a *10 +1 - main ; // " main " refers to the above
/ hh = ( '^ a ');
// totally random HH rhythm ( probably sounds stupid )
{ " -. " . wchoose (#[0.16 , 0.84]) } => Func ( \randHH );
/ hh .b *10 +9 \randHH " ||| " ;
// or random notes on 8 ths
/ hh .b *10 +5 \randHH %0.5 " ||| " ;
// or , random notes , but don ' t allow two " -" in a row
(
{ | prev |
if ( prev == $ -) { $ . } {
" -. " . wchoose (#[0.16 , 0.84])
}
} => Func ( \randHH );
)
/ hh .b *10 +9 \randHH " ||| " ;
Listing 20: Examples of randomizer statements.

31

1. Use q to determine the valid time points at which to place notes. In 4/4
time, with the default q = 0.25, there will be 16 time points.
2. Evaluate the string, to find out where notes already exist. Remove these
time points from the available list.
3. Randomly choose k time points, and add i at each of these points.
4. Write the results into a pattern string, and call the Set pattern statement
(Section 5.2) to add the pattern into the process.
5. Do the above n times.
5.4.1 Functions as items
Normally, i is simply a character indicating a specific value from the parameter
map. If you want the item itself to be randomized, define a function to calculate
the random value, save it in a chucklib Func, and use the Func’s name in place
of the item.
For each new item, the Func will be passed two arguments: the item before
the randomly-chosen time point (or nil) and the item after the time point (or
nil). You may add other arguments, in parentheses, after the function name;
e.g. +3\myRand(1, 3) would call \myRand.eval(prev, next, 1, 3).

5.5

Make statement

The make statement instantiates one or more chucklib factories.
/ make ( factory0 : targetName0 / factory1 : targetName1 /...) ;
// Or , with autoGui
/ make *( factory0 : targetName0 / factory1 : targetName1 /...) ;
Listing 21: Syntax template for make statements.

factory The name of a Fact object to create.
targetName (optional) The name under which to create the instance. If not
given, the make statement looks into the factory for the defaultName. If
not found, the factory’s name will be used.
Multiple factory:targetName pairs may be given, separated by slashes.
Both BP and VC factories are supported.
As noted earlier, the code to define cll processes is not performance-friendly.
Instead, you can write this code into Fact object, and then /make them as you
need them in performance.

32

(
// THIS PART IN THE INIT FILE
(
defaultName : \demo ,
make : { | name |
PR ( \abstractLiveCode ). chuck ( BP ( name ) , nil , (
event : ( eventKey : \default ) ,
defaultParm : \degree ,
parmMap : ( degree : ( isPitch : true ))
));
}, type : \bp ) => Fact ( \demoBP ) ;
)
// DO THIS IN PERFORMANCE
/ make ( demoBP : dm ); // : dm overrides defaultName
/ dm = " 1353427 ,5 , " ;
/ dm +;
/dm -;
/ dm ( free );
Listing 22: Example of the make statement.

/make* instead of /make will try to chuck process or voicer mixers into
chucklib MCG objects, for display in a mixing board, and voicers into empty
chucklib VP objects, for speed in setting up players during performance. MCG
and VP arrays are created by BP.loadGui.
5.5.1 TODO Make statement parameters

5.6

Passthrough statement

The passthrough statement takes arbitrary SuperCollider code, enclosed in
parentheses, and applies it to any existing chucklib object. If no class is specified, BP is assumed. No syntax checking is done in the preprocessor, apart from
counting parentheses to know which one really ends the statement.
// This ...
/ snr ( clock = ~myTempoClock );
// ... is the same as running :
BP ( \snr ). clock = ~myTempoClock ;
// Or ...
/ VC . bass ( releaseAll );

// VC ( \bass ) . releaseAll ;

Listing 23: Syntax template for passthrough statements.

33

5.7

Chuck statement

The chuck statement is a shortcut for chucking any existing chucklib object into
some other object. If no class is given, BP is assumed.
// This ...
/ snr => MCG (0) ;
// ... is the same as running :
BP ( \snr ) = > MCG (0) ;
// Or ...
/ VC . keys => MCG (0) ;

// VC ( \keys ) => MCG (0) ;

Listing 24: Syntax template for Chuck statements.

5.8

Func call statement

The Func call statement is a shortcut to evaluate a function saved in chucklib’s
Func collection. This makes it easier to use helper functions. No syntax checking
is done in the preprocessor.
/ func .( arguments );
// e . g .:
/ bars .( \proc , 2, \a );
Listing 25: Syntax template for func-call statements.

Note: The dot after the function name is critical! Without it, the statement
looks exactly like a passthrough, and the preprocessor will treat it as such.

5.9

Copy or transfer statement

Copy/transfer statements create additional copies of phrases, so that you can
transform the material while keeping the old copy. Then you can switch between the old and new versions, setting up a musical form.
/ proc . phrase *n -> newPhrase ;
/ proc . phrase *n ->> newPhrase ;

// copy
// transfer

Listing 26: Syntax template for copy/transfer statements.

proc The process on which to operate.
phrase The phrase name to copy.

34

n (optional) If given, copy a multi-bar phrase group, treating phrase as the
prefix. /proc.a*2 -> b will copy a0 to b0 and a1 to b1. (If n is omitted,
both phrase and newPhrase will be used literally.)
newPhrase The name under which to store a copy. If n is given, this is a phrase
group prefix.
The difference between “copy” and “transfer” is:
• Copy (->) simply duplicates the phrase information, but continues playing the original phrases. If you change the new copies, you won’t hear
the changes until you change the phrase selection pattern. This is good
for preparing new material and switching to it suddenly.
• Transfer (->>) duplicates the phrase information and modifies the phrase
selection pattern, replacing every instance of the old phrase name with
the new.12 Changing the new copies will now be heard immediately. This
is good for slowly evolving new material, while keeping the option to
switch back to an older (presumably simpler) version later.

5.10

Show pattern statement

Less a “statement” than an interface convenience, this feature looks up the
string for a given phrase and parameter, and inserts it into the code document.
Invoke this behavior by typing /proc.phrase.parm and evaluating the line by
itself. As in other contexts, phrase and parm are optional and default to main
and the process’s defaultParm respectively. For a multi-bar phrase group, type
/proc.phrase*n.parm (where n is the number of bars in the group.)
This is useful after a copy/transfer statement.
/ snr . a = " - -" ;
/ snr . a -> b;
/ snr . b

// now hit ctrl - return at the end of this line

// the line magically changes to
/ snr . b = " - -" ;
Listing 27: Demonstration of “Show pattern” statements.

Note: You must be using SuperCollider IDE 3.7 or above. Automatic code
insertion is not supported for other editors, or in SC 3.6.x (as it uses new
features introduced in SC 3.7).
12 It does this by producing a compileString from the phrase selection pattern, performing string
replacement, and then recompiling the pattern. This should work with all cll phrase selection
strings (Section 5.2.5). It is not guaranteed to work with hand-written patterns that generate phrase
names algorithmically.

35

5.11 TODO Check for more Helper functions
Three Func definitions are provided to make it easier to work with multi-bar
phrase groups. I will introduce them using cll Func call statement syntax (Section 5.8).
/setupbars.(\proc, n, \prefix) Create empty phrases for prefix0, prefix1
up to n − 1. This also inserts Set pattern (Section 5.2) templates into the
code document, for you to start filling in musical material.
/setm.(\proc, n, \prefix) Set the process’s phrase selection pattern to play
this phrase group. It also changes quant in the process, so that starting
and stopping the process will align to the proper number of bars.
/bars.(\proc, n, \prefix) Calls both setupbars and setm at once.
A typical sequence of performance instructions for me is:
/ make ( kick );
/ bars .( \kick , 2, \a );
// the following lines are automatically inserted
/ kick . a0 = " " ;
/ kick . a1 = " " ;
Listing 28: Common initialization sequence, using helper functions.

After the templates appear, I edit the strings to produce the rhythms I want,
and then launch the process with /kick+. In this example, the phrase group
occupies two bars. setm automatically sets the process’s quant to two bars, so
the process will then launch on an even-numbered barline.

6

Generators

The basic syntax of the Set pattern statement (Section 5.2) denotes fixed note sequences, which always play exactly the same events. Generators create phrases
whose contents can change on each iteration, adding another dimension of
musical interest.

6.1 TODO Generator design [0/1]
6.1.1 TODO Clarify location of chaining example
Generators manipulate lists of events, provided by “set pattern” strings, one bar
at a time. (As such, they are not a precise analog to SuperCollider patterns.)
Typically, the generator’s first argument is the event source: a “set pattern” string or another generator. The generator requests the event list from
the source, processes it and passes the modified list up to its parent. Chaining
generators in this way allows complex behaviors from simple units. Generators
36

should be written such that it’s possible to use any generator at any point in a
chain.
At present, generators divide into these main categories:
• Rhythm generators insert new items into the event list, or delete them.
New items may be event characters directly, or wildcards to be replaced
by the second category.
• Content generators replace wildcards with user-specified values.
• Filter generators alter the flow of control.
These are not the only possible generator types, and there is no prescribed
sequence for using them. However, it’s been most successful so far to use a
rhythm generator to embellish a base rhythm, and then apply a content generator to “fill in” the new rhythmic elements.
(
BP ( \y ). free ;
PR ( \abstractLiveCode ). chuck ( BP ( \y ) , nil , (
event : ( eventKey : \default ) ,
defaultParm : \degree ,
parmMap : ( degree : ( isPitch : true ))
));
)
TempoClock . tempo = 140/60;
/y = " 12 4| 5 6| 12 |45 " ;
/y +;
/y = " \seq (" ** *| * *| ** |** " , " 12456 " , " * ") " ;
/y = " \ins ( \seq ( " ** *| * *| ** |** " , " 12456 " , " * " ) , " * " , 7,
0.25) " ;
/y = " \seq ( \ins ( \seq ( " ** *| * *| ** |** " , " 12456 " , "* " ) , " * " ,
7, 0.25) , " 6 ,214 " , " *" ) " ;
/y = " \seq (" ** *| * *| ** |** " , " 12456 " , " * ") :: \ins (, " * " , 7,
0.25) :: \seq (, " 6 ,214 " , " * " ) " ;
/y -;
Listing 29: Isorhythmic cycles with generators.

Listing 29 demonstrates one possibility. The initial idea is a cycle of five
pitches laid over nine notes within a bar. Without generators, it’s necessary to
drop one pitch at the end of every bar (or, write the five possible distinct bars
by hand—time moves quickly on stage, so this is painful). But, using the \seq()
37

generator, we can specify the rhythm using a * wildcard; \seq() replaces each
wildcard with successive pitches. \seq also remembers its state from one bar
to the next, so, in this example, the first bar will begin with 1 and the second,
with 6.
Generators are “composed” by wrapping another generator around the outside: \ins(..., "*", 7, 0.25) inserts seven wildcards at randomly chosen
1/4-beat positions. (There are 16 per bar, and 9 are already occupied, so this
will fill all the empty rhythmic positions.) * is not a valid pitch specifier, so
these are performed as rests. Wrapping in one more layer, another \seq(),
overlays a new cycle, four notes this time. The result is a shifting arpeggiation
that should repeat every 20 bars—but written as a single bar’s pattern string.
The nested notation has the drawback that the parameters of outer-layer
generators may be far away from the generator name. A double-colon “chaining” or “composition” operator, ::, makes it possible to write each generator as
an isolated unit. The final variant sounds the same as the nested version, but is
easier to read. The :: operator takes the result of the first \seq() and replaces
the first parameter of the subsequent \ins() with it, and on down the chain.
The initial comma inside \ins() is required as a placeholder, but nothing need
be supplied; empty commas become nil.

6.2

Generator usage

6.2.1 Generators and pattern strings
Generators are invoked using the syntax \name(arguments) within a “set pattern” string.
As noted earlier, every character in a pattern string corresponds to a metrical position within the bar.13 The entire generator string, from the opening
backslash to the closing parenthesis, likewise occupies one and only one metrical position. The generator remains active until the next event, which may be a
literal item or another generator. Spaces in the pattern string are placeholders,
and indicate how long the generator should be in force. Listing 30 illustrates.
(Argument lists call for further discussion and are not relevant to generators’
rhythmic position; so, the examples omit arguments.)
In example 3 of Listing 30, beat 2 contains four items: 6,, \rand(...), space
and space. Thus beat 2 is subdivided into 16th-notes, and the generator begins
on the second of those.
// 1. \rand starts on the downbeat and occupies the whole bar .
/y = " \rand ( \ins ( " 1, " , " * " , 3, 0.5) , " 13467 " , " * " ) " ;
/y +;
// 2. \rand starts on beat 2
13 The exception is pitch, where a scale degree number may be followed by accidental, octave
and articulation designations. In this case, for instance, the four characters 4,+. make up a single
metrical instant.

38

/y = " 1 ,| \rand ( \ins ( " 6, " , "* " , 3, 0.5) , " 13467 " , " * ") || " ;
// 3. \rand starts on the 2 nd 16 th - note of beat 2
/y = " 1 ,|6 , \rand ( \ins ( " " , "* " , 3, 0.5) , " 13467 " , " * ")

|| " ;

// 4. \rand starts on the 2 nd 16 th - note of beat 2
// and stops on the 'and ' of 4
/y = " 1 ,|6 , \rand ( \ins ( " " , "* " , 3, 0.5) , " 13467 " , " * ")

|| x " ;

/y -;
Listing 30: Interaction between generator syntax and “set pattern” rhythmic notation.

Note: \ins("source", "new", num, quant) inserts num new items at possible time points quant beats apart. These time points are measured from the
beginning of the generator. In Listing 30, examples 3 and 4 offset the generator by one 16th-note—so \ins() will syncopate by a 16th. Further, source
strings will be compressed to fit into the generator’s duration. If "|||" at
the outermost layer produces four divisions of one beat each, the same
inside example 3’s \ins() generator would divide 2.75 beats by 4, whereupon each division would consist of 11 64th-notes. These examples avoid
the problem by supplying empty source strings. Otherwise, be careful (or,
structure your music to take advantage of the resulting Nancarrow-esque
polyrhythms).
6.2.2 Generator arguments
Every generator expression currently requires an argument list in parentheses
following the generator’s name. (If a generator doesn’t require arguments, an
empty pair of parentheses is currently still required. I may remove this requirement later, but for now, it’s not optional.)
Arguments are separated by commas. Each argument should be one of the
following:
• A quoted string containing items to use for subsequent events. An “item”
may be a single character or a generator; if the pattern string is for a pitch
parameter, the item may consist of more than one character (including
octave, accidental and articulation modifiers). Quotes for these strings
should not be escaped with backslashes, even though these quoted strings
appear within quotes. The set pattern parser reads the pattern string up
to a closing quote that appears outside generator expressions.
• A subordinate generator expression (which must begin with a backslash
and end with a closing parenthesis).
• A number.
39

• A Symbol, written in LISP-influenced style with an opening backtick:
`name. Currently this is used only in the \pdefn() generator.
By convention, the first argument to any generator should be its source: a
pattern string or generator. Generators may be freely composed if they follow
this rule. Breaking the rule will result in combinations of generators that cannot
be made to work. Other arguments are free for each generator to define.

6.3

Generators and rhythm

Previous cll versions used a “rhythm generator” to supply timing, when a generator was used for the default parameter. (As discussed in Section 5.2.3, the
default parameter controls the rhythm of the entire process.)
Beginning with v0.3, all generators are timed according to the rhythm in the
source string and any subsequent manipulation. There is no syntactic difference
when using a generator in default or non-default parameters.

6.4 TODO Check for new Built-in generators
6.4.1 Rhythm generators
\ins("source", "new items", numToAdd, quant) Locates unoccupied metric
positions within the bar, every quant beats apart beginning with the generator’s onset time, chooses numToAdd of them randomly, and inserts
new items at those positions.
\shift("source", "shiftable items", numToShift, quant) Locates numToShift
occurrences of the shiftable items within the source (they must already exist), and moves them forward or back by quant beats. A good way to get
syncopation is to insert items on a strong beat, and then shift them by a
smaller subdivision.
\rot("source", quant) Add quant to every item’s onset time, and wrap all the
times into the generator’s boundaries: basically, a strict canon.
// Reich , " Piano Phase "- ish
(
BP ( \y ). free ;
PR ( \abstractLiveCode ). chuck ( BP ( \y ) , nil , (
event : ( eventKey : \default , pan : -0.6) ,
defaultParm : \degree ,
parmMap : ( degree : ( isPitch : true ))
));
BP ( \z ). free ;
PR ( \abstractLiveCode ). chuck ( BP ( \z ) , nil , (
event : ( eventKey : \default , pan : 0.6) ,
defaultParm : \degree ,

40

parmMap : ( degree : ( isPitch : true ))
));
)
TempoClock . setMeterAtBeat (3 , TempoClock . nextBar );
TempoClock . tempo = 112/60;
/y = " \seq ( " *^*^*^*^*^*^ " , " 268 " , " * " ) :: \seq (, " 37 " , " ^ " )" ;
/z = " \seq ( " *^*^*^*^*^*^ " , " 268 " , " * " ) :: \seq (, " 37 " , " ^ " )" ;
/y/z +;
/z = " \seq ( " *^*^*^*^*^*^ " , " 268 " , " * " ) :: \seq (, " 37 " , " ^ " ) ::
\rot (, -0.25) " ;
/z = " \seq ( " *^*^*^*^*^*^ " , " 268 " , " * " ) :: \seq (, " 37 " , " ^ " ) ::
\rot (, -0.5) " ;
/z = " \seq ( " *^*^*^*^*^*^ " , " 268 " , " * " ) :: \seq (, " 37 " , " ^ " ) ::
\rot (, -0.75) " ;
/y/z -;

6.4.2 Content generators
\seq("source", "items", "wildcards", reset) Replaces wildcards in the source
with items, one by one, preserving order. Reset is optional; if it’s a number
greater than 0, the item sequence will reset on every bar.
\rand("source", "items", "wildcards") Like \seq(), but chooses from items
randomly. (Reset is not relevant, as there is no order to preserve.)
\wrand("source", "items", "wildcards", weight0, weight1, weight2...)
Weighted random selection, like Pwrand. Weight0 is associated with the
first element of items; weight1 with the second, and so on. The generator
automatically does normalizeSum on the weights, so you don’t have to
worry about making them add up to 1.0. Do not enclose the weights in
array brackets. (As in \rand(), reset is irrelevant.)
\xrand("source", "items", "wildcards", reset) Reads the items in random
order without repeating the same item twice in a row, like Pxrand.
\shuf("source", "items", "wildcards", reset) Shuffles the items into random order, and returns each one before choosing a new order, like
Pn(Pshuf(items, 1), inf).
\pdefn("source", `pdefnKey, "wildcards", reset) Like \seq(), but obtaining replacement items from a Pdefn. For non-pitched parameters, the
41

Pdefn should yield characters corresponding to parmMap items. For pitched
parameters, it should yield e.g. SequenceNote(degree, nil, length)
where length is 0.4 for staccato, 0.9 for legato (but rearticulating the
next note) and 1.01 for slurred.
• Pdefn streams are shared globally across all instances of this generator. This means you can create sequential patterns spanning barlines.
• The behavior of reset > 0 is undefined.

Pdefn ( \y , Pn ( Pseries (0 , 1 , 8) , inf ). collect { |d|
SequenceNote (d , nil , 0.9) }) ;
/y. a0 = " * \ins ( "* " , " * " , 2, 0.5) :: \pdefn (, `y , " *" ) " ;
/y. a1 = " \ins ( " *" , " * " , 3, 0.5) :: \pdefn (, `y , " * ") " ;
/y = (a **2) ;

6.4.3 Filter generators
\fork("source", "timed generators") Applies different generators to different segments of the bar. For instance, the source could insert n wildcards
throughout the bar, while timed generators could replace wildcards in the
first half of the bar with one value, and a different value in the second
half. Here, timed generators includes two items, and \fork() occupies the
entire bar. So both \seq() instances get half a bar. Source items in any
portions of the bar not covered by one of the timed generators will pass
through unchanged.
/y = " \ins ( " " , "* " , 10 , 0.25) :: \fork (, " \seq (, " 13 " , " * " )
\seq (, " 14 " , " * " ) ") " ;
/y = " \ins ( " " , "1, " , 10 , 0.25) :: \fork (, " \seq (, " 13 " , " 1, "
) x\seq ( , " 14 " , " 1, " ) " ) " ;

\chain("source", generator, generator...) For internal use only.

6.5

Writing new generators

Generators inherit from PR(\clGen).14 They should implement:
~prep Validate the entries in the ~args array, and return the Proto object by
finishing with currentEnvironment. In general, start with ~baseItems =
~args[0].
14 In Proto, inheritance is handled by “cloning” the Proto: PR(\clGen).clone { ...
overrides... }.

42

~process Generally begins with ~items = ~getUpstreamItems.();. Following
this, manipulate the ~items array and return it at the end. Be careful
to copy or collect the array (to avoid corrupting ~baseItems) and—
important!—if you modify any of the items, be sure to copy it first.
Generators should take care to respect their time span, given by ~time (the
generator’s onset within the bar) and ~dur (the number of beats occupied by
this generator). Do not modify any items outside this time span. See the definition of PR(\clGenRot) for an example.
~baseItems and ~items are arrays of Events, containing:
item The entry to be played. For non-pitched parameters, these will generally be characters. Otherwise, pitch strings are parsed into SequenceNote
objects.
time The event’s onset time within the bar. This is relative to the bar line, not
the generator’s onset time.
dur The number of beats until the next event. This may not be reliable during processing. The top-level generator will correct the dur values before
streaming out the events.
This documentation may be expanded at a later date.

7

Extending cll

cll is designed to be extensible: adding new statements is relatively straightforward.
Processing a cll statement goes through two main steps:
1. PR(\chucklibLiveCode) tests the statement against a number of regular
expressions, to determine what type of statement it is.
2. Then, a PR object to handle the statement is instantiated, and the statement is passed to that object’s process method.
So, to implement a new statement type, you need to do two things, matching
the above stages.

7.1

Statement regular expression

First, add a statement ID and regular expression into PR(\chucklibLiveCode).
Within this object, ~statements is an array of Associations: \statementID ->
"regexp".

43

~statements = [
\clMake -> " ^ * make\\ (.* \\ ) " ,
\clFuncCall -> " ^ *` id\\ . \\ (.* \\ ) " ,
\clPassThru -> " ^ *([ A - Z ][ A - Za - z0 -9 _ ]* \\ .) ?` id\\ (.* \\ ) " ,
\clChuck -> "^ *([ A - Z ][ A - Za - z0 -9 _ ]* \\ .) ?` id *= >.* " ,
\clPatternSet -> " ^ *` id ( \\ .| ` id |` id\\ *[0 -9]+) * = .* " ,
\clGenerator -> " ^ *` id ( \\ .| ` id ) * \\ *.* " ,
// harder match should come first
\clXferPattern -> " ^ * ` id ( \\ .` id ) ?( \\ *` int ) ? ->>" ,
\clCopyPattern -> " ^ * ` id ( \\ .` id ) ?( \\ *` int ) ? ->" ,
\clStartStop -> " ^([/ ` spc ]* ` id ) +[ ` spc ]*[+ -] " ,
\clPatternToDoc -> " ^ *` id ( \\ .| ` id ) *[ ` spc ]* $ "
];
Listing 31: Cll statement regular expression templates.

More restrictive matches should come first. For instance, \clXferPattern
comes before \clCopyPattern. If they were reversed, -> in the “copy” regular
expression would match the “xfer” statement as well as the “copy” statement.
Checking ->> first ensures that the more permissive test takes place only after
the stricter test fails.
Within these strings, a backtick (`) introduces a macro that will be expanded
into part of a regular expression. Available macros are:
~tokens = (
al : "A - Za - z " ,
dig : " 0 -9 " ,
id : "[A - Za - z ][ A - Za - z0 -9 _ ]* " ,
int : " ( -[0 -9]+|[0 -9]+) " ,
// http :// www . regular - expressions . info / floatingpoint . html
float : " [ \\ -+]?[0 -9]* \\ .?[0 -9]+([ eE ][ \\ -+]?[0 -9]+) ? " ,
spc : "
" // space , tab , return
);
Listing 32: Regular expression macros for SC language tokens.

You should match only as much of the syntax as you need to determine the
statement type. This is not the place for syntax validation. For example, the
\clGenerator statement has a fairly complex syntax, but the matching regular
expression is looking only for one or more IDs separated by dots, followed
by a space and then an asterisk. This will dispatch to PR(\clGenerator); it
is this object’s responsibility to report syntax errors (generally by throwing
descriptive Error objects).
Note: The leading slash is stripped from the statement before regular expression matching. Don’t include the slash in your regular expression.

44

7.2

Handler object

Usually, a statement handler is a PR object, containing a Proto object prototype.
The PR’s name must match the statement ID created in the last step.
The Proto must implement process, which takes code (the statement, as a
String) as its argument. It should return a string containing the SuperCollider
language syntax to perform the right action.
Proto {
~process = { | code |
// parse ' code ' and build the SC language statement ( s ) ...
translatedStatement // return value
};
} => PR ( \clMyNewStatement );
Listing 33: Template for cll statement handlers.

Very simple statements may be implemented as functions added into
PR(\chucklibLiveCode).
PR ( \chucklibLiveCode ). clMyNewStatement = { | code |
// parse ' code ' and build the SC language statement ( s ) ...
translatedStatement // return value
};
Listing 34: Adding a function into PR(\chucklibLiveCode) for simple statement types.

8

Code examples
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

A quick techno-ish drumset. . . . . . . . . . . . . . . . . . . . .
Generators for drums. . . . . . . . . . . . . . . . . . . . . . . .
Adding sound effects to a simple beat. . . . . . . . . . . . . . .
Bassline template. . . . . . . . . . . . . . . . . . . . . . . . . .
Chord-playing template. . . . . . . . . . . . . . . . . . . . . . .
Example of arpeggiator usage. . . . . . . . . . . . . . . . . . .
Phrase selection for drum fills. . . . . . . . . . . . . . . . . . .
Multi-bar bassline. . . . . . . . . . . . . . . . . . . . . . . . . .
A simple cll process. . . . . . . . . . . . . . . . . . . . . . . . .
Template for the parameter map. . . . . . . . . . . . . . . . . .
How to write arrays in the parameter map. . . . . . . . . . . .
Arrays for multiple-parameter setting using one cll parameter.
Cll statements, one by one or as a batch. . . . . . . . . . . . . .
Syntax template for the Set pattern statement. . . . . . . . . .
Multiple parameters with different timing. . . . . . . . . . . . .
A retro acid-house bassline, demonstrating pitch notation. . . .
Syntax template for “Set pattern” phrase selection. . . . . . . .
45

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

6
8
10
12
13
15
16
17
19
21
21
22
24
24
26
28
29

18
19
20
21
22
23
24
25
26
27
28
29
30

Nested phrase-selection groups. . . . . . . . . . . . . . . . . . . .
Syntax template for randomizer statement. . . . . . . . . . . . .
Examples of randomizer statements. . . . . . . . . . . . . . . . .
Syntax template for make statements. . . . . . . . . . . . . . . .
Example of the make statement. . . . . . . . . . . . . . . . . . .
Syntax template for passthrough statements. . . . . . . . . . . .
Syntax template for Chuck statements. . . . . . . . . . . . . . . .
Syntax template for func-call statements. . . . . . . . . . . . . .
Syntax template for copy/transfer statements. . . . . . . . . . . .
Demonstration of “Show pattern” statements. . . . . . . . . . . .
Common initialization sequence, using helper functions. . . . . .
Isorhythmic cycles with generators. . . . . . . . . . . . . . . . .
Interaction between generator syntax and “set pattern” rhythmic
notation. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
31 Cll statement regular expression templates. . . . . . . . . . . . .
32 Regular expression macros for SC language tokens. . . . . . . . .
33 Template for cll statement handlers. . . . . . . . . . . . . . . . .
34 Adding a function into PR(\chucklibLiveCode) for simple statement types. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
Emacs 24.3.1 (Org mode 8.3beta)

46

29
30
31
32
33
33
34
34
34
35
36
37
38
44
44
45
45



Source Exif Data:
File Type                       : PDF
File Type Extension             : pdf
MIME Type                       : application/pdf
PDF Version                     : 1.5
Linearized                      : No
Page Mode                       : UseOutlines
Language                        : English
Page Count                      : 46
Creator                         : Emacs 24.3.1 (Org mode 8.3beta)
Title                           : Chucklib-Livecode Manual
Author                          : H. James Harkins
Producer                        : XeTeX 0.99998
Create Date                     : 2018:01:30 21:36:49+08:00
EXIF Metadata provided by EXIF.tools

Navigation menu