intro-to-algorave.txt

A workshop on making music live with code, for beginner programmers.

Table of Contents

Live Coding

verb.
Writing and running code in a live environment, where one is able to run and manipulate the program at the same time.
noun.
A form of performance art using code as the interface to create art with an emphasis on live manipulation of code that is usually visible to the audience. Both pre-planned and fully improvised.

Ethos

Software development is usually a practice focused on achieving a relatively objective goal, with quantifiable results:

  • Commerce
  • Automation
  • Production

Live Coding is an alternative approach to the meaning of writing code focused on:

  • Performance
  • Creativity
  • Community

To me, live coding is a reaction to the alienation technology can too often represent. It emphasizes the poetic, aesthetic, and artistic aspects of code.

Code uniquely expresses thought processes and creative problem-solving; showing your code reveals how you think.

The Scene

Live-coding has scenes all around the world, from Mexico City to the UK to Berlin to Tokyo.

The closest scene with people who regularly perform, that I know of, is in NYC. They meet regularly in Brooklyn. However, they meet on Fridays with little notice, so it's pretty hard to make plans around going... though I have wanted to for years.


My hope is we will have a scene around here soon :)

History

repl
Computer terminals and scripted programming languages run a Read-Eval-Print Loop which allows the programmer to use a program interactively; both running and editing the code. This concept is very old and goes back to at least 1964.
1980s
According to the TOPLAP wiki, Forth programmers in the 1980s did live performances using code to control synthesizers via MIDI.
TOPLAP
An informal organization formed in 2004 to promote live coding.
Algorave
First coined in 2011 by Alex McLean and Nick Collins, a style of live-coding performance of dance music featuring 2 performers: music and visuals, with code projected behind the performers.

Manifesto

The TOPLAP Manifesto is a semi-serious document that outlines a few important principles:

Show your work
The code is an integral part of the performance. Traditionally, the code is projected behind the performer.
No Backups
Mistakes are part of the experience: opportunities to demonstrate skill, to show the human behind the performance.
Programs are Instruments
A piano keyboard is an interface to making music. So is code: the code is the interface, the programmer is the artist. The art of live coding demonstrates mental and physical dexterity.

In addition to these principles, there are a few values worth highlighting:

Openness and Esotericism
A lot of the tools we use are freely offered, developed collaboratively under open-source licenses. Being an underground movement, it is still largely experimental.
Anti-Colonialism
Many people involved in the scene are aligned with broadly anti-colonial politics. Live coding is ephemeral, largely or completely improvised, and resists commercialization.
Diversity
Broadly, the Algorave community is committed to diversity. In particular, the scene prominently features a lot of women and takes active measures to ensure gender diversity and equality among performers.

The Tools

SuperCollider
James McCartney created SuperCollider in 1996, scriptable synth engine which provides a toolkit for live-editable synth making and music sequencing. It was made open source (free for anyone to use and modify) in 2002.
Tidal Cycles
A framework for live coding which supports editing and running patterns live. Initially developed by Alex McLean in 2006, Tidal Cycles was adopted more broadly in 2013. Contributors to the project integrated it with SuperCollider in 2015.
Strudel
A new web-browser based live-coding environment from the same community and using the same ideas as Tidal Cycles, which is a lot more accessible and easy to use.
Hydra
A browser based framework for live-coding visuals, often seen paired in performance with a live coder.

Examples

Yaxu & HelloCatFood
Alex McLean, creator of Tidal Cycles is making the music, hellocatfood (Antonio Roberts) is using Pure Data to create visuals.
Heavy Lifting & Graham Dunning
Heavy Lifting (AKA Lucy) and Graham Dunning are contributors to Tidal Cycles and have lots of performances available online.
DJ Dave & Char Stiles
dj_dave on Sonic Pi and Char Stiles writing GLSL for visuals (pretty hardcore!).
Dan Gorelick & Char Stiles
Dan Gorelick and Char Stiles performing together; Dan's videos really helped me to get started when I picked up tidal cycles for a second time, and it stuck.

Strudel

We are using Strudel today.

But first…

Javascript

Strudel uses JavaScript.

We will review some fundamentals.

Syntax

Programming languages are far stricter and more formal than spoken or normal written languages.

  • Prevent ambiguity (to the computer)
  • Minimal to no context (meaning does not change)
  • Express logical/mathematical reasoning

Requires a shift in how you think.

Expressions

An expression is the most fundamental element of a program.

They can be data:

5
true
"hello"
[0, 55, 100]

And operations on that data:

5 + 1.1
100*0.5 + 1/4
"hello " + "world"

Logic

The comparison operators let you ask a question about two numbers and get true or false in return:

OperatorMeaning
a < bless than
a > bgreater than
a == bis equal to
a != bis not equal to

Some work on values that are already true or false

OperatorMeaning
a && btrue if a and b are true
a || btrue if a or b is true

Variables

Many languages have ways to give a name to and refer to a value multiple times:

let x = 5;
let y = x*x;

let result = x + y + 4;

This is an example of a statement. Instead of producing a value, a statement produces an effect.

Flow

Execution of a JavaScript program generally flows in order from top to bottom.

let a = 0;

a = 5;

let b = a + 10;

But within an expression, the order of operations has rules similar to algebra.

(x + x)*5 + 4 > 0

Control flow

Often-times programs need to alter the flow from top-to-bottom.

if statements enable conditional execution:

let a = 10;
let b = 0;

if (a < 5 || b == 0) {
    b = -1;
} else {
    b = 2;
}

for loops enable repeated execution:

let x = 0;

for (i = 0; i < 10; i += 1) {
    x = x + 1;
}

Functions

Functions allow you to define your own operations that you can repeat with different values.

function f(x, y) {
  return x*y + 1;
}

let z = f(5, 1);

And the shorthand version (which is useful in Strudel):

let f = (x, y) => x*y + 1;

let z = f(5,1);

Complex Data

Sometimes data needs to be bundled together:

let object = { time: "now", location: "armory" };

Access the values with a .name or with ["name"]

object.time
object["time"]

One can also bundle functions inside objects:

let object = {
  time: "now",
  location: "armory",

  info: function () {
    return this.time + " at " + this.location;
  }
};

object.info()

All Together

Of course, all of these concepts can be combined:

function convertColorToNumber(color) {
  // Convert color to lowercase for easier matching
  color = color.toLowerCase();

  // If the color is a hex code, convert it to a number
  if (color[0] === '#') {
    return convertHexToNumber(color);
  }

  // If the color is a named color, return the corresponding number
  if (colorMap[color] !== undefined) {
    return convertHexToNumber(colorMap[color]);
  }

  // If the color is not recognized, return null
  return -1;
}

Strudel 101

Now we should be ready to make some music.

Making a sound

Copy the following into strudel.cc:

$: sound("bd")

Press CTRL+Enter to run your program.

SoundDescription
bdBass drum
sdSnare drum
hhHigh-hat
sawtoothA very bright synth sound
xylophone_hard_ffA xylophone sample
- or ~rest

Try some alternate sounds!

Mininotation

Strudel is based on the view that music takes the form of events arranged in a pattern that repeat over time.

$: sound("bd bd bd bd")

Everything inside "s is a pattern written in mininotation. The events are separated by spaces, and repeat in cycle.



We call each slice the cycle an arc. The length of the cycle stays the same no matter how many arcs divide up the cycle.

$: sound("bd bd ~ bd bd ~")

Try different combinations of sounds.

Subcycles

Brackets group sounds. Everything inside the brackets share the same arc of the cycle.

$: sound("bd [hh hh] bd ~")


Let's visualize:

$: sound("bd [hh hh] bd ~")._punchcard({ labels: 1 })

Try different combinations.

Stacks

Strudel can play more than one sound at a time by adding a comma inside brackets.

$: sound("[bd, oh] sd [cp, oh] sd")
$: sound("hh ~ ~ hh")

Also polyrhythms:

$: sound("[bd bd, cp cp cp] [cp cp, bd sd bd]")
    ._punchcard({ labels: 1 })

Pattern Operators

In a pattern, ! repeats sounds:

$: sound("[bd!4, cp!3]")
    ._punchcard({ labels: 1 })

It can also repeat whole sub-patterns:

$: sound("[cp bd]!2 [bd hh] cp")

Other pattern operators exist, lets try some!

OperatorEffect
@Elongates
!Repeats
*Speeds up
/Slows down

Alternates

Surrounding items in a pattern with < > alternates between them each cycle:

$: sound("<cp [bd hh]> cp cp sd")

Try combining * and other operators with < >

$: sound("<bd*2 oh>*2 <rim lt>!2")
    ._punchcard({ labels: 1 })

It can also repeat whole sub-patterns:

Euclidean Patterns

A euclidean rhythm is a pattern which tries to spread beats evenly across a bar.

The first number is the number of beats to play, the second is the number of beats in a bar.

$: sound("cp(5,8)")

It gets more interesting when you pattern the items and use the third parameter to transpose the sequence:

$: sound("[cp cp](<3 5>,8,<0 1 2>/2)")
    ._punchcard({ labels: 1 })

Melodies

Strudel can track multiple layers of control in a pattern.

We can combine note and sound patterns to create melodies:

$: note("c a f e").sound("triangle")
notedescription
c, d, e, f, g, a, bNotes of the western scale
cs, c#Sharps
fb, ffFlats

Try different notes!

Pattern Structure

Patterns can effect layers independently, but the first one gives the overall structure; compare the following 2 patterns.

$: note("c a f e").sound("triangle square")

How is this different?

$: sound("triangle square").note("c a f e")



It took me a while to start to come to grips with this…

Scales & Scale Degrees

Use n to write numbers instead of notes. The numbers are relative to a scale:

$: n("[0, 4] 1 -4 7").scale("<C:major E:minor>")
    .sound("piano")

Using scaleTranspose, you can offset the numbers:

$: n("[0, 4] 1 -4 7").scale("<C:major E:minor>")
    .scaleTranspose("<0 1 2>/2")
    .sound("piano")
    .color("<red green>")
    .pianoroll({ labels: 1 })

Jam time!

$: sound("<[~ bd]!2 [rim sd]>*4")
    ._punchcard()

$: n("[0, 4 7](3,8)")
    .scale("D:mixolydian")
    .sound("triangle")
    ._pianoroll({ labels: 1 })

Altering Patterns

Functions can transform patterns:

$: n("[0, 4] 1 -4 7").scale("<C:major E:minor>")
    .scaleTranspose("<0 1 2 3 4>/2")
    .sound("piano")
    .off(1/8, x => x.add(12))
    .fast("<1 0.5> 2")
    .every(3, rev())

Arrays

Programmers love shorthand. Mininotation is shorthand. Compare:

$: sound(["bd", "bd", "bd", ["cp", "bd"]])

$: sound("bd bd bd [cp bd]")

Patterns are lists of events, each item is an arc…

We can even mix-and-match:

$: sound(["bd bd bd", ["cp", "cp"]])
  ._punchcard({ labels: 1 })

$: sound(["bd", "bd", "bd", "cp cp"])

Concatenation

Joining lists together is called concatenation.

However, there are 2 ways to interpret joining patterns.

We can alternate between them each cycle:

$: cat("bd bd bd", "cp cp").sound()

$: sound("<[bd bd bd] [cp cp]>")

We can cram them together:

$: fastcat("bd bd bd", "cp cp").sound()

Redundancy?

Why have so many different ways of doing the same thing?

  1. We can express things multiple ways in natural langauge
  2. Subtle differences which are situationally useful
  3. The most commonly used operations should be the easiest


Even more shorthand:

$: "bd".sound()
$:sound( "hh)
$: "c a f e".note().s("piano")

You get the point, lets move on…

Structure

What if we want to separate rhythm from melody?

$: note("c d e")
    .struct("x x [~ x ~ x] x")
    .s("piano")

Try altering the note and struct patterns separately.

Masks

We can silence parts of a pattern with masks:

$: note("a db g b")
    .mask("<1 [0 1]>")
    .s("piano")

0s are silence, 1s let sound through.

Layering sounds

We can stack sounds on top of eachother:

$: stack("bd bd bd", "cp cp", "hh hh hh hh").s()

Again, same as the following in mininotation

$: sound("[bd bd bd, cp cp, hh hh hh hh]")

BUT we can mix in other stuff:

$: stack([
     note("[a, bd] [g, b2]")
            .stuct("x [~ x] x [x x]")
            .s("piano"),
     sound("bd bd bd bd").mask("<1 [01]>"),
  ])
  .mask("<1@3 [1010]>")

Time

Time is a major element of a pattern, we have lots of ways to modulate time.

Fast and Slow

We can change the speed of the clock:

$: sound("bd").fast(4)

$: sound("cp hh cp hh").slow(4)

And we can get freaky with it:

$: sound("[bd bd] bd bd").fast("<2 0.5 1.33>")

Late & Early

We can nudge time by making a pattern run late or early, offsetting its time by fractions of a cycle.

$: "bd*4"
    .stack("hh*4".late(1/8))
    .stack("sd sd".early(1/16))
    .sound()
    ._punchcard({ labels: 1 })

Swing

We can squash and stretch it at the same time:

$: stack("bd*4".swing(2), "hh*4").s()
  ._punchcard({ labels: 1})

Swing cuts the pattern into 2, and takes the events in the second half and offsets them.

Lets Get Meta

Many strudel functions can take functions which change patterns as arguments:

$: "c f g!2"
  .superimpose(x => x.add(5))
  .note().s("piano")


superimpose layers the altered pattern p onto itself!

Conditional Execution

When chained normally, our function is always applied. Not very musically interesting!!!


Strudel has lots of only sometimes applying functions:

every
$: "c a f e".every(3, x => x.add(2)).note().s("piano")
sometimes
$: "bd*4,sd*2".s().sometimes(x => x.fast(2))
sometimesBy
$: s("piano*4").sometimesBy(0.25, x => x.vowel("a o i u"))
when
$: "cp*4".s().when("0 1 0 0", x => x.delay(0.5))

More Complex

Many more functions exist which do all sorts of weird (fun) combinations of everything we have seen so far!

For example off:

$: "c3 c4"
    .off(1/4, p => p.add(5))
    .note().s("xylophone_medium_ff")

Compare to:

$: "c3 c4"
    .superimpose(x => x.late(1/4).add(5))
    .note().s("piano")

All Together Now

Combining techniques is really powerful:

$: "0 4".fast(2)
    .every(2, x => x.off(3/8, x => x.add(7)))
    .off(1/2, x => x.add(-9))
    .scale("D:mixolydian")
    .note()
    .s("xylophone_medium_ff")
    ._pianoroll({ labels: 1 })

Closing Thoughts

These are the prinicples at work behind strudel! Now it's all practice. Hopefully you have enough understanding to watch others and learn.

Learning to live code is really like learning an instrument. There are both technical and musical lessons to learn all the time.




Like any instrument, strudel has a way of thinking that can push you in entirely new directions… but you can also break all of the rules and make it something entirely new.

One big topic we did not cover is working with longer samples. There is so much you can do to make awesome dub and dnb vibes…



Next time :)

FIN.

This page left intentionally blank.