Lissajous
Lissajous is a tool for real time audio performance using Javascript. It wraps succinct tools for creating oscillators and samplers into a chainable API, allowing performers to build and improvise songs with a minimum of code.
Lissajous exists entirely within the Javascript console & was designed for use with Google Chrome or Firefox.
Play with Lissajous
Requires the latest stable Chrome or Firefox build & a relatively recent OS. If you have your own .wav files you can drop them in the window to load them into the environment!
Watch a few demo videos
Tutorial
Read theThe tutorial is a work in progress but already serves as great starting point for new performers!
View the Performance API Documentation
Get a local copy
In order to run Lissajous locally you have to have a copy of the lissajous environment on your machine. Do this by pulling down this repo: git clone [email protected]:kylestetz/lissajous.git
and opening the file /environment/index.html
. The environment doesn't contain any samples- add an /environment/samples/
folder (ignored by git) and add samples via /environment/extras.js
!
This is what Lissajous looks like
// make a triangle wave that loops the notes 69, 67, then 60 in quarter note intervals
t = new track()
t.tri().beat(4).notes(69,67,60)
// load a sample, set the beat to quarter notes, set the note length to a half measure,
// set the envelope to give it a little attack and release, and loop the notes 69, 67, then 60
s = new track()
s.sample(buffer)
s.beat(4).nl(8).adsr(0.1,0,1,1).notes(69,67,60)
// load an array of three AudioBuffers called 'drums', play them in 8th notes and give them
// the sequence drums[0], drums[2], drums[1], drums[2]
d = new track()
d.sample(drums)
d.beat(2).sseq(0,2,1,2)
// load a piano sample and mess it up real good
p = new track()
p.sample(pianoSample)
p.beat(2).nl(2).speed(0.5).clamp(1/16).clshift(-1/16)
Basic Concepts of Lissajous
A performance in the Chrome console using Lissajous takes place in the global namespace. You'll probably create a lot of variables with names like s
or a
or b1
or b2
or doodle
, and this sort of usage is encouraged. Need to start over? Refresh the page.
The key to making the most of Lissajous is to add scripts (e.g. extras.js
) that load all of your samples into the environment on page load. A clever or ambitious performer might write some additional functions to coordinate changes, control transitions, or execute other group-oriented operations with style and grace. Sky's the limit.
Every track has a step sequencer.
Tracks make sound when they are given a beat. Here's the minimum needed to generate some sound:
t = new track()
t.beat(4)
Beat is a step sequencer. Calling t.beat(4)
says "play a note every four 16th notes." The Lissajous API supports an arbitrary number of arguments, allowing us to make more complicated patterns:
t.beat(4,3,2,1,4,2)
If we visualized this in a classic step sequencer view, it would look like this:
1 5 9 13
[x][ ][ ][ ][x][ ][ ][x][ ][x][x][ ][ ][ ][x][ ]
The clock ticks in 32nd notes, and the API is written to support both 16th and 32nd note expressions.
t.beat(1) // play a note every 16th note
t.beat32(1) // play a note every 32nd note
Everything reacts to the step sequencer.
Most of the parameters of a track can be given more than one value (we call this a pattern). For example, with notes:
t = new track()
t.beat(4).notes(69, 67, 60)
Tracks are monophonic. Since we supplied three notes, they will play one at a time, looping back to the beginning when they reach the end. There's no limit to the number of notes you can have in a pattern.
Patterns for each parameter are self-contained and do not rely on each other, allowing us to play with patterns of different lengths:
t = new track()
t.beat(4).nl(4,2).notes(69, 67, 60)
Here we toggle between a note length of 4 and 2 every time a note is hit, but we cycle through three different notes.
Samples can be sliced and diced.
Working with samples is simple in Lissajous. There are helper functions to get your samples loaded onto the page; check out /environment/extras.js
for an example.
var t = new track()
t.sample(mySample)
// play a beat every quarter note with a note length of 4/16th
t.beat(4).nl(4)
// clamp to the first 1/16th of the sample & loop that portion
t.clamp(0, 1/16).loop(1)
// shift the clamp points by -1/16th of the sample size every beat
t.clshift(-1/16)
Todos
- Develop a technique that would make smooth LFOs possible
- MIDI in/out
- Audio In
- sharing JS context across multiple machines
Special Thanks
This project is made possible by a lot of people writing great articles and making great libraries. For the sake of completeness I have added several libraries to this repo.
- "A Tale of Two Clocks - Scheduling Web Audio with Precision" by Chris Wilson (@cwilso)
- Tuna.js by @Dinahmoe
- The BufferLoader function from "Getting Started with Web Audio API" by Boris Smus
- Recorder.js by @mattdiamond
- The Delay node from JAM with Chrome - How we made the audio rock by Oskar Eriksson