Chucklib Livecode Manual Cl

User Manual: Pdf

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

Chucklib-Livecode Manual
H. James Harkins
January 30, 2018
Contents
1 Introduction 2
1.1 Overview ............................... 2
1.2 Acknowledgments .......................... 3
2 Installation 3
2.1 Installation with git .......................... 3
2.2 Installation without git ........................ 3
2.3 Running cll inasession ....................... 4
3 Tutorial 5
3.1 Drums................................. 5
3.2 Patternstrings ............................ 7
3.3 Generators .............................. 7
3.4 Soundeects ............................. 10
3.5 Pitchednotes............................. 11
3.6 Phrases ................................ 16
3.7 Errors ................................. 17
4 Process prototype 18
4.1 Datastructure............................. 18
4.2 PR(\abstractLiveCode) . . . . . . . . . . . . . . . . . . . . . . . . 18
4.3 Parametermap............................ 21
4.4 Eventprocessing ........................... 22
4.5 Phrasesequence ........................... 23
5 Livecoding statement reference 23
5.1 Statementtypes............................ 23
5.2 Set pattern statement . . . . . . . . . . . . . . . . . . . . . . . . 24
5.3 Start/stop statement . . . . . . . . . . . . . . . . . . . . . . . . . 30
5.4 TODO Deprecate Randomizer statement . . . . . . . . . . . . . 30
5.5 Makestatement............................ 32
5.6 Passthrough statement . . . . . . . . . . . . . . . . . . . . . . . . 33
5.7 Chuckstatement ........................... 34
1
5.8 Func call statement . . . . . . . . . . . . . . . . . . . . . . . . . . 34
5.9 Copy or transfer statement . . . . . . . . . . . . . . . . . . . . . 34
5.10 Show pattern statement . . . . . . . . . . . . . . . . . . . . . . . 35
5.11 TODO Check for more Helper functions . . . . . . . . . . . . . 36
6 Generators 36
6.1 TODO Generator design [0/1] . . . . . . . . . . . . . . . . . . . 36
6.2 Generatorusage ........................... 38
6.3 Generators and rhythm . . . . . . . . . . . . . . . . . . . . . . . 40
6.4 TODO Check for new Built-in generators . . . . . . . . . . . . . 40
6.5 Writing new generators . . . . . . . . . . . . . . . . . . . . . . . 42
7 Extending cll 43
7.1 Statement regular expression . . . . . . . . . . . . . . . . . . . . 43
7.2 Handlerobject ............................ 45
8 Code examples 45
1 Introduction
1.1 Overview
Chucklib-livecode (cll for short) is a system of extremely compact commands
extending the SuperCollider programming language. The commands manipu-
late musical processes in real time to facilitate live-coding performances. “Pro-
cesses” 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 preproces-
sor translates the cll command syntax into standard SuperCollider code.
This document will cover the process prototype rst. You need to under-
stand its structure in order to understand the commands.
1Harkins, H. James. (2011). “Composition for Live Performance with dewdrop_lib and chuck-
lib.” In Wilson, S., Cottle, D., Collins N. [eds.] The SuperCollider Book. Cambridge, Mass.: MIT Press.
pp. 589–612.
2http://github.com/jamshark70/chucklib-livecode
2
1.2 Acknowledgments
Thanks are due to:
James McCartney and all the other developers who contributed to Super-
Collider 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 rst to capture my imagina-
tion about live coding, leading me in this direction.
Thor Magnusson, whose ixilang system4provided some of the inspiration
for cll syntax.
Canton Becker of http://sampleswap.org for granting permission to re-
distribute some audio les from sampleswap’s online collection. These
are used in the ddwLivecodeInstruments quark, referenced in the Tuto-
rial (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 instru-
ments in the ddwLivecodeInstruments quark require code changes in several
places, and they will not work correctly if you’re using out of date quark ver-
sions.
2.1 Installation with git
If you have installed the git version-control system on your machine, SuperCol-
lider can automatically download and install Quark extensions. Simply evalu-
ate 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.
3McLean, Alex. “Making Programming Languages to Dance to: Live Coding with Tidal.” Pro-
ceedings of the 2nd ACM SIGPLAN international workshop on Functional art, music, modeling &
design, September 6, 2014, Gothenburg, Sweden, pp. 63–70.
4http://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 les into the directory. After this, you should have:
downloaded-quarks/ddwChucklib
downloaded-quarks/ddwPrototype
… and so on. If there is a -master sux on the directory names,
please remove it.
In SC, run the statement Quarks.install("ddwChucklib-livecode"). If it
doesn’t nd 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 con-
trol 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 pre-
processor 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 rst.
ddwLivecodeInstruments provides a set of standard electronic drums (Sec-
tion 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.5I’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 mail-
ing list6or the ddwChucklib-livecode issue tracker.7(Also note that this is the
rst 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)
5Copying from this PDF is likely to change the code formatting and possibly break the code. If
you must copy/paste, use the le cl-manual-examples.scd.
6https://www.birmingham.ac.uk/facilities/ea-studios/research/supercollider/
mailinglist.aspx
7https://github.com/jamshark70/ddwChucklib-livecode/issues
5
\loadAllCl. eval ;
TempoClock. tempo = 12 4/60;
/ hh .( \h ardh h );
/ hhh = ". -. -. -. - ";
/ hhh +
/ drum .( \tightsnr);
/ tsn = " - -";
/ tsn +
/ drum .( \deepkick);
/ dk = "o| o | _o | ";
/ dk +
// mix ing boa rd
/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 com-
mands 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, rst 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 rst 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 im-
provising 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:
8The characters for kicks and snares are dierent, 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 .2 5) " ;
// B
/ tsn = " \ins (" - -" , " ." , 2 , 0 .5 ) " ;
// C
/ tsn = " \ins (" - -" , " ." , 2 , 0 .5 ) :: \ sh if t ( , " ." , 2, 0 .2 5) " ;
// D
/ hhh = " \in s ( "" , " -" , 1 , 0. 5) :: \i ns ( , "." , 7 , 0.5 ) ";
// E
/ hhh = " \ins (" .", "-" , 1, 0. 5) :: \in s ( , " ." , 6, 0. 5) " ;
// F
/ hhh = " \ins (" .", "-" , 1, 0. 5) :: \in s ( , " ." , 6, 0. 5) :: \in s (, "."
, 2, 0. 25) ";
// G
/ hhh = " \f or k ( "" , " |\ins( , "-", 1 , 0 .5) || x " ) :: \i ns ( , " ." , 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 benet 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 o-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 rst generator
feeds into the rst 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 ll 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 rst 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 com-
plain 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 specic
parts of the bar. In example G, the fork string places an \ins() on beat 2, and
follows it with an xon beat 4. The \ins(), then, cannot operate before beat
2, and the xends the \ins() generator’s range of inuence. So the open hat
can be inserted in positions 2, 2.5, 3 and 3.5 (not including 4, which belongs
to x). xis 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 eect.
It isn’t very useful for drums, but a typical generator usage is to insert wild-
cards (usually *or @) to dene the rhythm, and then replace them using a num-
ber 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 snip-
pets can help you with the order of arguments: press the snippet hotkey (which
9
\loadAllCl. eva l ; // If you haven 't alr ead y done this
TempoClock. temp o = 12 4/ 60 ;
// The b ea t
BP (#[ tk , clp , hhh , tsn ]) . free ; // C lean up fir st
/ drum .( \tightkick) ; / drum .( \clap) ; / hh .( \har dh h );
/ tk = "o|| o|";
/ clp = " - " ;
/ hhh = "........";
/ tk / clp / hhh +
/ drum .( \tightsnr) ;
/ tsn = " |||. ";
/ tsn +
/ clp = " | -| | . " ;
/ tsn = " |||. . ";
// make the effe cts
/ mak e ( buf BP : m ch ( set : \machine));
/ mch = " | -|| " ;
/ mch +
/ mch = " | -| , ,| ";
/ tk / clp / hhh / t sn / mch -;
Listing 3: Adding sound eects to a simple beat.
you congure using DDWSnippets.learn), type a few letters of the generator
name, and the template will be inserted into your document.
3.4 Sound eects
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 Long Short
High ^ !
Middle - .
Low _ ,
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 (\ dm ixo ) = > M ode (\default);
/ mak e ( pbs VC : p bs / m el BP : bs ( o ct ave :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. Assum-
ing 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 specic mode into
Mode(\default). Modes are identied by the root pitch (c,cs = c-sharp,
db = d-at, and so on) plus a modal identier (Table 1). B-at lydian is
Mode(\bblyd).
Table 1: Modal identiers.
Mode ID
Major (Ionian) maj
Dorian dor
Phrygian phr
Lydian lyd
Mixolydian mixo
Minor (Aeolian) min
Locrian 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 modiers:
12
/ mak e ( an ap adV C : pad / c hor dBP : ch ( c ho rds : \one) );
/ ch = " 87 ~05 " ;
/ ch +
VC (\pad) . gui
MBM (0) [ \t wo ] = > 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 at). 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 in-
strument, it might hit the note a little harder. >may be combined with
other articulations.
The digit plus its modiers becomes a single event—so, in Listing 4, beat 3
contains ve 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 o
the preceding note (in contrast to a space, which aects timing only).
Leads follow the same principles, except in a higher octave.
Exercise: Modify the given template to add more notes. Try the dierent
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 buer
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 rst 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, le 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 aecting
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
/ mak e ( fm cl avV C : fmc / a rpe gBP : a rp ( c hor ds : \b igch ));
// The se are indices , from the top down , into the current c hord
.
/ arp = " 1234 ";
/ arp +
// Add some l owe r no tes as a second laye r .
// A cc ent ar ti cul at es the st ar t of the bar .
/ arp = " \ins ( " 1 >2 34 " , " 456" , 6 , 0 .2 5) " ;
// Exten d the sec on d l ayer higher .
/ arp = " \ins ( " 1 >2 34 " , " 23456" , 7 , 0.2 5) " ;
// Use w il dc ar ds to s ubsti tu te a s equen ti al pattern .
/ arp = " \ins ( " 1 >2 34 " , " *" , 7 , 0 .25 ) :: \s eq ( , " 65432")";
// C ha nge the ha rmon y 's to p note eve ry b ar .
/ arp .. top = " \s eq ( "*" , " 5'6 ' 3'2 ' ")";
// Skip : Play dy ad s i ns te ad of si ng le no tes .
/ arp .. sk ip = "2";
// Skip can also acc en t s pe ci fic not es .
/ arp .. sk ip = " 20 | 20 |20 | 20 " ;
// same , but a lg orith mi c
/ arp .. sk ip = " \ch ok e (" 2222" , 0. 25 , " 0")";
// Add a sec on d p roc es s to c ha ng e the ch or d roo t .
// Aft er this , you sh ould he ar tonic , do min ant
// and s ub do min an t f un ct io ns .
// No i nst rum ent -- thi s is for data onl y .
/ make ( melB P : roo t ( bass ID : \bass));
/ root = " \seq ( "*" , " 15 4 ")";
/ root +
/ arp / r oot -
Listing 6: Example of arpeggiator usage.
15
TempoClock. temp o = 12 4/ 60 ;
/ drum .( \tightkick) ; / drum .( \tightsnr) ; / hh . ( \thinhh ) ;
/ tk = " oooo " ;
/ tsn = " - -" ;
/ thh = " \ins (" .", "-" , 1, 0. 5) :: \in s ( , " ." , 6, 0. 5) " ;
/ tk / tsn / thh +
/ tk . fi ll = "o || _ |o __ " ;
/ tsn . fi ll = " | -| \i ns ( " -" , " ." , 4, 0 .25 ) | ";
/ tk = ( ma in *3. fill ); / tsn = ( main *3. f ill ) ;
/ tk / tsn / thh -
Listing 7: Phrase selection for drum lls.
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. Doc-
umentation to be expanded later.)
3.6 Phrases
The examples so far repeat a single bar’s worth of content. Cll processes allow
you to dene 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 (Sec-
tion 5.2.5) to choose the bars in succession. Listing 7 demonstrates with drum
processes, playing the basic pattern for three bars and a ll pattern for the
fourth.
Alternately, you can create multi-bar structures using a few convenience
functions (Listing 8):
/setupbars.(\proc, n, \prefix): Creates nempty 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 ar-
guments. Cll distinguishes between a function-call shortcut /name.(args) and
16
// If the bas s doesn ' t exist , fir st do this :
/ mak e ( pbs VC : p bs / m el BP : bs ( o ct ave :3) ) ;
/ bar s .( \bs , 2 , \ a );
/ bs . a 0 = " 1 >|4 ~5 ~7 | 4 ~ |3 ' ~ " ;
/ bs . a 1 = " 5 >~ |6| 4 ~| 3 " ;
/setupbars.(\bs , 2 , \b ) ;
/ bs . b 0 = " 9 >.9.9 | 4' ~| 3 '|8 ~7 ~8 ~ ";
/ bs . b 1 = " 3 3. | 4.5 ~ | 4 31 .| 6. 6. 6 . ";
// s ho rt fo rm of / set m .( \bs , 2 , \b )
/ bs = ( b ** 2) ;
/ bs +
/bs -
Listing 8: Multi-bar bassline.
amethod-passthrough shortcut /proc(method(args)), with the dot to tell the
dierence.
Note that /bars.() will tell the process to start playing a silent phrase struc-
ture. So, you should use it only when setting up a new process. If you’re already
playing material, it’s better to /setupbars.() rst, ll 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
/ pr oc -;
/ proc ( re set ) ;
/ 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 pro-
cess does not interfere with other processes.
Each phrase contains multiple parameters. (The phrase itself is imple-
mented as a PbindProxy, so that its contents can be changed at any time.)
Each parameter is dened by a pattern string, parsed and rendered into
SuperCollider pattern syntax by the Set pattern statement (Section 5.2).
Parameter values are dened by the parameter map (parmMap).
cll processes create two phrases by default:
main The default phrase, which plays if the user hasn’t specied a dierent
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 Pro-
cess”), 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) . ch uc k ( BP (\beep) , nil , (
userprep: {
~buf =Buff er . read (
s , Platform. r esour ce Di r +/+ " so un ds / a 11w lk 01 . w av " ,
4982 , 1 0320
);
~defaults[\b uf nu m ] = ~buf;
SynthDef(\buf1 , { | out , bufnum , pan , amp , time = 1|
var sig = P la yB uf . ar (1 , b uf nu m ) ,
eg = EnvG en . kr (
Env. li nen (0.02 ,
min ( time , BufDur .ir ( bufnum ) - 0.04 ) , 0.0 2) ,
doneAction: 2
);
Out . ar ( out , Pan2. ar ( sig , pan , am p * eg ) ) ;
}) . add ;
},
userfree: {
~buf. fre e ;
},
de fault Pa rm : \amp ,
parmMap : (
amp : ( $.: 0.1 , $-: 0.4 , $^: 0.8) ,
pan : (
$<: -0.9 , $>: 0.9 ,
$(: -0.4 , $): 0.4 ,
$-: 0
)
) ,
de fau lts : ( instr um en t : \buf1) ,
postDefaults: Pbind(
\time , ( Pkey(\dur) * 0.6 / Pfunc {~ clock . t emp o }) . c li p
(0.04 , 0.2)
)
));
)
// Use it , with cll st ateme nt s :
TempoClock. temp o = 2;
/ beep = " ^|.. .| .- | . " ;// " Set pa tte rn "
/ beep +; // start it
/ beep .. p an = "<><><><>";
/ be ep -;
/ beep ( f ree ) ;
Listing 9: A simple cll process.
19
userfree A function, called when the process is destroyed. Clean up any re-
sources allocated in userprep.
defaultParm The name of the default parameter aected by Set pattern state-
ments (Section 5.2). The default parameter also controls rhythm.
parmMap A nested dictionary of parameters, their allowed values, and the char-
acters 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 pro-
cess will not work properly.
This dictionary is not limited to these items. You may add any other data
and functions that you need, to dene complex behavior in terms of simpler
functions and patterns.
In Listing 9, userprep loads a buer and userfree releases it. By default,
Set pattern will operate on amp, and parmMap denes three values for it (soft,
medium and loud). parmMap also provides some panning options. The defaults
dictionary species 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 buer number is
not known in advance. The only way to supply the buer number as a default
is to read the buer rst, 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 denitions into a separate le, 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 dened. cll is
an even more compact layer of control on top of this, following the same
design principle: denition and performance usage are dierent, and call for
dierent 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 : val ue .. .
) ,
pa rmN ame : (.. .)
)
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 : (
ali as : \instrument ,
$s :\sawtooth ,$p :\pulse ,$f :\fm
)
)
// Then you can set the " i nstru ment " pat ter n :
/ proc . ph ra se . 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 : (
fre qs : (
$2 : [200 , 300 , 400] ,
) ,
pa rmN ame : (.. .)
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 cus-
tom event prototype dened in chucklib that plays single nodes and inte-
grates more easily with MixerChannel. Because each such event plays only
one node, array arguments are passed as is. The normal default event ex-
pands one-dimensional arrays into multiple nodes. The way to avoid this
is to wrap the array in another array level.
parmMap
array format
singleSynthPlayer
meaning
Default event mean-
ing
[1, 2, 3] Pass the array to one
node
Distribute the three val-
ues to three nodes
[[1, 2, 3]] Invalid Pass the array to one
node
One other use of parameter map array is used to set disparate Event keys us-
ing 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 : (
ali as : [ \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 (dened 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 dened in the
parameter map, or to check for invalid values.
22
Table 2: List of available chucklib-livecode statements.
Type Function Syntax outline
Set pattern Add new musical informa-
tion into a process
/proc.phrase.parm =
"data"
Start/stop Start or stop one or more
procesess
/proc/proc/proc+ or -
Randomizer Create several randomized
patterns at once
/proc.phrase.parm *n +ki
"base"
Make Instantiate a process or
voicer
/make(factory/factory)
Passthrough Pass a method call to a BP /proc(method and
arguments)
Chuck Pass a chuck => operation
to a BP
/proc => target
Func call Call a function in chucklib’s
Func collection
/funcname.(arguments)
Copy Copy a phrase or phrase set
into a dierent name
/proc.phrase*n -> new
Transfer Like ”Copy,” but also uses
the new phrase for play
/proc.phrase*n ->> new
Show pattern Copies a phrase pattern’s
string into the document,
for editing
/proc.phrase.parm
4.5 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 dierent phrase identiers. Then, during the performance, she
can change the phrase-selection pattern to switch materials on the y. 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 Livecoding statement reference
5.1 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 = " - -- -";
/ sna re . b t24 = " - -" ;
// or as a b atch
/kick.fotf = " - -- -"; / sna re . b t24 = " - -" ;
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 ma-
terials. As such, it’s the most complicated of all the commands.
This statement type subdivides into two functions: phrase denition and
phrase selection.
5.2.1 Phrase denition
Most “Set pattern” statements follow this format:
/ proc . ph ra se . par m = q ua nt " s tr ing " ;
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 dene 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, species 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 Species parameter values and rhythms.
24
Note: Both the phrase and parameter names are optional. That allows the
following syntactic combinations:
Syntax Behavior
/proc = "string" Set phrase ”main,” default parameter
/proc.x = "string" Set phrase ”x,” default parameter
/proc.x.y = "string" Set phrase ”x,” parameter ”y”
/proc..y = "string" 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 placehold-
ers) are equally spaced throughout the bar. This holds true even if it’s a non-
standard division: #4 (Figure 1) has seven characters in the string, producing
a septuplet.
If there are dividers, the measure’s duration will be divided rst: ndividers
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
rst division contains one item, but the second contains two. For all the divi-
sions to have the same duration, then, -in the second division should be half
as long as in the rst.
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 dene an item in the
parameter map whose value is a Rest object.
Note: Set pattern writes the character identiers 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 identier
value occurs for each parameter; you should be able to rely on accessing the
nal values by Pkey. This supports Generators (Section 3.3), which should
also return the value identiers.
25
1. "--"
2. "----"
3. "- --"
4. "- --- -"
7
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 conict.
The Pbind rhythm is determined by the pattern string for the defaultParm
declared in the process. When you set the defaultParm, the rhythm dened
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 lter parameter changes on beats 1, 2 and 4. The process will play
two events, on beats 1 and 3. On beat 1, the lter will use its avalue; on beat
3, it will use the most recent value, which is b.The lter 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 cwill 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. fil t = " ab c " ;// "c" is not hea rd
/x = " -|- -" ;// now " c" is he ard on beat 4.5
Listing 15: Multiple parameters with dierent 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 species 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 Mul-
tiple 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: 3is
one note, as is 6+,~. They are converted into SequenceNote objects in the
pattern, because SequenceNotes can encode pitch and articulation informa-
tion. 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 no-
tation, 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 renement would be to add values for lter
frequency and filtMul into the parameter map.
9In SuperCollider pattern terms, 1translates into degree 0.
10Currently a diatonic scale (7 degrees) is assumed.
11Note the trick to get monophonic synthesis. Assigning a PmonoArtic into postDefaults eec-
tively 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.
27
(
SynthDef(\sqrbass , { |out , freq = 110 , gat e = 1,
freqMul = 1.006 , amp = 0.1 ,
filtMul = 3 , filtD eca y = 0.12 , ffr eq = 2000 , rq = 0.1 ,
lagTime = 0.1 |
var sig = Mix(
Pulse. ar (
Lag . kr ( fre q , l agT im e ) * [1 , f re qM ul ] ,
0.5
)
) * amp ,
filt Eg = EnvGen . kr (
Env([ filtMul , filtMul , 1] , [0.005 , fi ltDec ay ] , \exp) ,
gate
) ,
amp Eg = EnvGen . k r (
Env. ads r (0.01 , 0.08 , 0.5 , 0.1 ) ,
gate , d on eA ction : 2
);
sig = RLPF . ar ( sig , ( ffr eq * f il tEg ) . cli p (20 , 2 00 00 ) , rq ) ;
Out . ar ( out , ( si g * a mp Eg ) . dup ) ;
}) . add ;
BP (\acid) . fre e ;
PR (\abstractLiveCode) . ch uc k ( BP (\acid) , nil , (
eve nt : ( eventKe y : \default) ,
al waysR es et : true ,
de fault Pa rm : \degree ,
parmMap : (
de gre e : ( is Pi tc h : t ru e ) ,
) ,
defaults: (
ffr eq : 300 , fil tMu l : 8, rq : 0.2 ,
octa ve : 3 , root : 6, scale : Scale. locrian . s em it on es
) ,
postDefaults: PmonoArtic(\sqrbass ,
\dummy , 1
)
));
TempoClock. temp o = 13 2/ 60 ;
)
/ acid = "1 _ 1.|5 ~3_9 .4.|7.2 ~4_5 ' .| 5 _8~ 2_ 4 ." ;
/ acid +;
/ ac id -;
Listing 16: A retro acid-house bassline, demonstrating pitch notation.
28
5.2.5 Phrase selection
Statements to set the phrase sequence follow a dierent syntax:
/ proc = ( gro up ...) ;
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 dened, or a regular expres-
sion 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 aand 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 exam-
ple, to have an 80% chance of afor four bars, then an 80% chance of bfor 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:
/ p ro c . p ref ix . par m * n + k i % q " st ring "
Listing 19: Syntax template for randomizer statement.
proc The process into which the new variations will go.
prefix A phrase identier. Mandatory.
parm (optional) The parameter to control.
nThe number of variations to create. Each becomes a new phrase: prefix0,
prefix1 up to n1.
kThe number of sequence items to add.
iThe sequence item: either a single character (dened 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
dierent 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
// a ss umi ng BP ( \ sn r ) de fin es :
// " -" ( no rma l n ot e )
// "." ( sof te r no te )
// P rod uces str ong not es on 2 and 4 , and one note el sewhe re
/ snr . a *10 +1. " | - || - " ;
/ snr = ( '^ a ' ); // r ando mly choose one v ari at ion for eac h bar
// " -" = open , "." = c lo sed
/ hh = " ..| .. |. .| .. " ;// all closed at fir st
// add an ope n HH on any em pty 16 th
/ hh . a *10 +1 - m ai n ; // " mai n " r ef er s to the a bov e
/ hh = ( '^ a ' );
// t ota lly ra ndom HH r hythm ( pr ob ab ly so un ds stu pid )
{" -. ". w cho ose (#[0.16 , 0.8 4]) } = > Fu nc (\randHH ) ;
/ hh . b *10 + 9 \randHH " ||| " ;
// or r an dom n ot es on 8 ths
/ hh . b *10 + 5 \randHH %0.5 " ||| " ;
// or , ran dom notes , but don ' t all ow two " -" in a row
(
{ | pr ev |
if ( pre v == $-) { $.}{
" -. ". wcho ose (#[0 .16 , 0.8 4])
}
} => Func(\ ran dHH ) ;
)
/ hh . b *10 + 9 \randHH " ||| " ;
Listing 20: Examples of randomizer statements.
31
1. Use qto 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 nd out where notes already exist. Remove these
time points from the available list.
3. Randomly choose ktime points, and add iat 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 ntimes.
5.4.1 Functions as items
Normally, iis simply a character indicating a specic value from the parameter
map. If you want the item itself to be randomized, dene 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 ( fa ct or y0 : t ar get Na me 0 / fac tor y1 : t arg etNam e1 /. ..) ;
// Or , with autoGui
/ make *( f act or y0 : t arg etNam e0 / fact ory 1 : ta rge tN am e1 /.. .) ;
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 dene 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
(
de fault Na me : \demo ,
make : { | na me |
PR (\abstractLiveCode) . ch uc k ( BP ( n am e ) , nil , (
eve nt : ( eventKe y : \default) ,
de fault Pa rm : \degree ,
parmMap : ( degree : ( isPi tc h : true ))
));
}, t ype : \b p ) => Fact (\ de mo BP );
)
// DO THI S IN P ER FORMA NCE
/ m ak e ( d emo BP : dm ) ; // : dm o ve rr id es d ef au lt Na me
/ dm = " 1353427 ,5 , ";
/ dm +;
/dm -;
/ dm ( fr ee ) ;
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 speci-
ed, 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 ( c lo ck = ~myTempoClock) ;
// ... is the same as running :
BP (\snr). cl ock = ~myTempoClock;
// Or ...
/VC . b ass ( re lease All ) ; // V C ( \ba ss ) . r el ea se Al l ;
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 . k eys = > MCG( 0) ; / / V C ( \ke ys ) = > 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 .( a rg ume nts ) ;
// 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 be-
tween the old and new versions, setting up a musical form.
/ pro c . phr ase *n -> n ewP hr ase ; // co py
/ proc . ph ra se * n ->> n ew Phr ase ; // 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
prex. /proc.a*2 -> b will copy a0 to b0 and a1 to b1. (If nis omitted,
both phrase and newPhrase will be used literally.)
newPhrase The name under which to store a copy. If nis given, this is a phrase
group prex.
The dierence between “copy” and “transfer” is:
Copy (->) simply duplicates the phrase information, but continues play-
ing 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 modies 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 nis 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 - re tur n at the end of this line
// the l in e magi cally ch ang es 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).
12It 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 denitions are provided to make it easier to work with multi-bar
phrase groups. I will introduce them using cll Func call statement syntax (Sec-
tion 5.8).
/setupbars.(\proc, n, \prefix) Create empty phrases for prefix0,prefix1
up to n1. This also inserts Set pattern (Section 5.2) templates into the
code document, for you to start lling 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 ( k ick ) ;
/ bars .( \kick , 2 , \a ) ;
// the f oll ow ing line s are a ut om atica ll y inse rte d
/ k ic k . a0 = "";
/ k ic k . 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 xed note se-
quences, 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 rst argument is the event source: a “set pat-
tern” string or another generator. The generator requests the event list from
the source, processes it and passes the modied 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-specied values.
Filter generators alter the ow 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 gener-
ator to “ll in” the new rhythmic elements.
(
BP (\ y ). free ;
PR (\abstractLiveCode) . ch uc k ( BP (\y ) , nil , (
eve nt : ( eventKe y : \default) ,
de fault Pa rm : \degree ,
parmMap : ( degree : ( isPi tc h : true ))
));
)
TempoClock. temp o = 14 0/ 60 ;
/y = "12 4| 5 6| 12 |45 " ;
/ y +;
/y = " \se q (" ** *| * *| ** |** " , " 12456" , " *")";
/y = " \ins ( \s eq ( " ** *| * *| ** |** " , " 12456" , " *") , " *" , 7 ,
0.2 5) " ;
/y = " \seq ( \i ns ( \s eq ( "** *| * *| ** |** " , " 12456" , " *" ) , "*" ,
7 , 0. 25) , " 6 , 214 " , " *")";
/y = " \se q (" ** *| * *| ** |** " , " 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 ve
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 ve 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 rst bar will begin with 1and the second,
with 6.
Generators are “composed” by wrapping another generator around the out-
side: \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 ll all the empty rhythmic positions.) *is not a valid pitch specier, 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 “chain-
ing” or “composition” operator, ::, makes it possible to write each generator as
an isolated unit. The nal variant sounds the same as the nested version, but is
easier to read. The :: operator takes the result of the rst \seq() and replaces
the rst 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 pat-
tern” string.
As noted earlier, every character in a pattern string corresponds to a met-
rical position within the bar.13 The entire generator string, from the opening
backslash to the closing parenthesis, likewise occupies one and only one metri-
cal 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. \ ra nd s tar ts on t he d ow nbe at and o ccu pie s the w ho le b ar .
/y = " \r an d ( \in s (" 1," , "*" , 3 , 0.5) , " 13467" , " *")";
/ y +;
// 2. \r and s tarts on beat 2
13The 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 ,| \r an d ( \i ns ( " 6," , " *" , 3, 0.5) , " 13467" , " *") || " ;
// 3. \r and s tarts on the 2nd 16 th - no te of beat 2
/y = "1 ,|6 , \ ra nd ( \i ns ( "" , " *" , 3, 0.5) , " 13467" , " *") || " ;
// 4. \r and s tarts on the 2nd 16 th - no te of beat 2
// and st ops on the 'and ' of 4
/y = "1 ,|6 , \ ra nd ( \i ns ( "" , " *" , 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 possi-
ble time points quant beats apart. These time points are measured from the
beginning of the generator. In Listing 30, examples 3 and 4 oset the gener-
ator by one 16th-note—so \ins() will syncopate by a 16th. Further, source
strings will be compressed to t 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, where-
upon 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 require-
ment 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 modiers). 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-inuenced style with an opening backtick:
`name. Currently this is used only in the \pdefn() generator.
By convention, the rst 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 dene.
6.3 Generators and rhythm
Previous cll versions used a “rhythm generator” to supply timing, when a gen-
erator 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 dierence
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 gen-
erator’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 ex-
ist), 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 , " Pi an o Ph as e "- ish
(
BP (\ y ). free ;
PR (\abstractLiveCode). ch uck ( BP (\y ) , nil , (
eve nt : ( eventKe y : \default , pan : - 0.6) ,
de fault Pa rm : \degree ,
parmMap : ( degree : ( isPi tc h : true ))
));
BP (\ z ). free ;
PR (\abstractLiveCode). ch uck ( BP (\z ) , nil , (
eve nt : ( eventKe y : \default , pan : 0 .6) ,
de fault Pa rm : \degree ,
40
parmMap : ( degree : ( isPi tc h : true ))
));
)
TempoClock. se tM et er At Be a t (3 , TempoClock. n ex tB ar );
TempoClock. temp o = 112 /6 0;
/y = " \se q (" *^*^*^*^*^*^" , " 268" , " *" ) :: \s eq ( , " 3 7 " , "^")";
/z = " \se q (" *^*^*^*^*^*^" , " 268" , " *" ) :: \s eq ( , " 3 7 " , "^")";
/ y/ z +;
/z = " \se q (" *^*^*^*^*^*^" , " 268" , " *" ) :: \s eq ( , " 3 7 " , "^" ) ::
\rot ( , -0. 25) " ;
/z = " \se q (" *^*^*^*^*^*^" , " 268" , " *" ) :: \s eq ( , " 3 7 " , "^" ) ::
\ro t (, -0.5) " ;
/z = " \se q (" *^*^*^*^*^*^" , " 268" , " *" ) :: \s eq ( , " 3 7 " , "^" ) ::
\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
rst 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) Shues the items into ran-
dom order, and returns each one before choosing a new order, like
Pn(Pshuf(items, 1), inf).
\pdefn("source", `pdefnKey, "wildcards", reset) Like \seq(), but obtain-
ing 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 genera-
tor. This means you can create sequential patterns spanning barlines.
The behavior of reset > 0 is undened.
Pdefn(\y ,Pn (Pseries (0 , 1, 8) , inf ) . c ol le ct { |d |
SequenceNote( d , nil , 0.9 ) }) ;
/ y. a0 = " * \i ns ( "*" , " *" , 2 , 0 .5) :: \ pd ef n ( , ` y , " *")";
/ y. a1 = " \ins ( "*" , " *" , 3 , 0. 5) : : \ pd ef n ( , `y , "*")";
/y = ( a ** 2) ;
6.4.3 Filter generators
\fork("source", "timed generators") Applies dierent generators to dier-
ent segments of the bar. For instance, the source could insert nwildcards
throughout the bar, while timed generators could replace wildcards in the
rst half of the bar with one value, and a dierent 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 = " \in s (" " , " *" , 10 , 0. 25 ) :: \ fo rk ( , " \seq ( , " 13 " ,"*")
\seq ( , " 14 " ,"*")")";
/y = " \in s (" " , " 1, " , 10 , 0 .2 5) :: \ fo rk ( , " \seq(, " 1 3 " ,"1,"
) x\s eq ( , " 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
nishing with currentEnvironment. In general, start with ~baseItems =
~args[0].
14In 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 rst.
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 de-
nition 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 gener-
ally 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 dur-
ing 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 straightfor-
ward.
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 state-
ment 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 -> " ^ * m ak e\ \ (.* \\ ) " ,
\clFuncCall -> " ^ * ` id \\ . \ \ (.* \\ ) " ,
\clPassThru -> " ^ *( [A - Z ][ A - Za - z0 -9 _ ] * \\ .) ? ` i d\ \ ( .* \\ ) " ,
\clChuck -> " ^ *( [A - Z ][ A - Za - z0 -9 _ ]* \\ .) ? ` id *= > .* " ,
\clPatternSet -> " ^ * ` id ( \\ .| ` i d |` i d\ \ * [0 -9 ]+ ) * = .* " ,
\clGenerator -> " ^ * ` id ( \\ .| ` i d )* \\ *.* " ,
// h arder match sho uld c om e 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 rst. 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 ->> rst 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 . regul ar - ex press ion s . info / f loa tin gp oi nt . h tml
flo at : "[ \\ -+] ?[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 ex-
pression 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 = { | co de |
// p ar se ' code ' an d bu il d the SC l an gua ge s ta te me nt ( s) ...
translatedStatement // r eturn val ue
};
} => PR (\clMyNewStatement);
Listing 33: Template for cll statement handlers.
Very simple statements may be implemented as functions added into
PR(\chucklibLiveCode).
PR (\chucklibLiveCode). cl MyNew St ate me nt = { | code |
// p ar se ' code ' an d bu il d the SC l an gua ge s ta te me nt ( s) ...
translatedStatement // r eturn value
};
Listing 34: Adding a function into PR(\chucklibLiveCode) for simple statement types.
8 Code examples
1 A quick techno-ish drumset. . . . . . . . . . . . . . . . . . . . . . 6
2 Generators for drums. . . . . . . . . . . . . . . . . . . . . . . . . 8
3 Adding sound eects to a simple beat. . . . . . . . . . . . . . . . 10
4 Basslinetemplate. .......................... 12
5 Chord-playing template. . . . . . . . . . . . . . . . . . . . . . . . 13
6 Example of arpeggiator usage. . . . . . . . . . . . . . . . . . . . 15
7 Phrase selection for drum lls. . . . . . . . . . . . . . . . . . . . 16
8 Multi-barbassline. .......................... 17
9 A simple cll process. . . . . . . . . . . . . . . . . . . . . . . . . . 19
10 Template for the parameter map. . . . . . . . . . . . . . . . . . . 21
11 How to write arrays in the parameter map. . . . . . . . . . . . . 21
12 Arrays for multiple-parameter setting using one cll parameter. . 22
13 Cll statements, one by one or as a batch. . . . . . . . . . . . . . . 24
14 Syntax template for the Set pattern statement. . . . . . . . . . . 24
15 Multiple parameters with dierent timing. . . . . . . . . . . . . . 26
16 A retro acid-house bassline, demonstrating pitch notation. . . . . 28
17 Syntax template for “Set pattern” phrase selection. . . . . . . . . 29
45
18 Nested phrase-selection groups. . . . . . . . . . . . . . . . . . . . 29
19 Syntax template for randomizer statement. . . . . . . . . . . . . 30
20 Examples of randomizer statements. . . . . . . . . . . . . . . . . 31
21 Syntax template for make statements. . . . . . . . . . . . . . . . 32
22 Example of the make statement. . . . . . . . . . . . . . . . . . . 33
23 Syntax template for passthrough statements. . . . . . . . . . . . 33
24 Syntax template for Chuck statements. . . . . . . . . . . . . . . . 34
25 Syntax template for func-call statements. . . . . . . . . . . . . . 34
26 Syntax template for copy/transfer statements. . . . . . . . . . . . 34
27 Demonstration of “Show pattern” statements. . . . . . . . . . . . 35
28 Common initialization sequence, using helper functions. . . . . . 36
29 Isorhythmic cycles with generators. . . . . . . . . . . . . . . . . 37
30 Interaction between generator syntax and “set pattern” rhythmic
notation................................. 38
31 Cll statement regular expression templates. . . . . . . . . . . . . 44
32 Regular expression macros for SC language tokens. . . . . . . . . 44
33 Template for cll statement handlers. . . . . . . . . . . . . . . . . 45
34 Adding a function into PR(\chucklibLiveCode) for simple state-
menttypes. .............................. 45
Emacs 24.3.1 (Org mode 8.3beta)
46

Navigation menu