Skip to content
charlie roberts edited this page Apr 26, 2019 · 38 revisions

What is Gibberwocky for Max?

A quick way to augment a Max patcher with live coded sequencing & modulations. Live coding happens in a browser-based text editor, following similar idioms as in the widely-used Gibber environment. Modulations can be messages, UI knob tweaks, and even arbitrary signal graphs.

Installing

Open Max's Package Manager, find & install the gibberwocky package

Alternatively, download/checkout https://github.com/gibber-cc/gibberwocky.max into Documents/Max 8/Packages (or My Documents/Max 8/Packages on windows)

Make sure you have a recent version of Chrome (or Firefox or Safari (or maybe even Edge now)).

Using Gibberwocky

Add a [gibberwocky] object to your Max patcher. Turn on audio in the patcher, if it isn't already on.

Send the [gibberwocky] object a bang to open the editor (alternatively, just open http://gibberwocky.cc/burble in your browser). In the editor's console, if it says "gibberwocky.max is ready to burble", you're all set!

Note: You might need to open port 8081 on your firewall.

What can Gibberwocky modulate?

Gibberwocky -> Max

  • message => messages/lists from [gibberwocky] 1st outlet
  • param => messages to UI objects with scripting names
  • device => messages to device objects (including sending midinotes and setting parameters)
  • signal => audio outlets of [gibberwocky]

Message

message("hello")("world")

...will send the message hello world out of the gibberwocky 1st outlet. So will:

message("hello.world")    
synth1.a.b.c.d.e.f.g.h( 'i?' ) // sends 'synth1 a b c d e f g h i?'

A message path of this kind can also be stored as an callable object, for re-use:

hello = message("hello")
hello("world")

Sequencing

Messages (and params and device params etc.) can also be sequenced:

// sends "hello world" every whole note:
message("hello").seq("world", 1)

// sends "hello world" every quarter note:
message("hello").seq("world", 1/4)

If the arguments to seq(val, dur) are arrays, they will be iterated over each time:

// alternates between sending "hello me" and "hello you" every quarter note
message("hello").seq(["me", "you"], 1/4)

You can stop all sequences in gibberwocky with the Ctrl+. keyboard shortcut (Ctrl + period). You can also stop all sequences on a specific object:

devices['synth'].stop()

Param

Device

parameters

// set the synth resonance:
devices['synth']['filter_resonance'](.95)

// alternate filter cutoff between 100Hz and 10kHz every beat:
devices['synth']['cutoff'].seq([100, 10000], 1/4)

midinote

// midi note number:
devices['synth'].midinote( 60 )  
// midi note number, midi velocity, duration in ms:
devices['synth'].midinote( 60, 120, 1000 )  

Note, velocity, and duration can all be sequenced independently:

devices['bass'].midinote.seq( 60, 1/2 )
devices['bass'].velocity.seq( [16, 64, 127], 1/2 )
devices['bass'].duration.seq( [10, 100,500], 1/2 )

Note

devices['synth'].note( 'eb4' )

Signal

You can send gen~ graphs from the browser to gibberwocky to be compiled and run within Max. Most gen~ operators are available in gibberwocky. This section provides a quick tutorial on creating a simple LFO.

In gen~, the cycle function generates a sine oscillator (as opposed to sin, which calculates the mathematical sin of a number). Let's start by passing a straight sine oscillator to our leftmost signal output.

osc = cycle(4)
signals[0]( osc )

We can access the properties of any gen~ object using bracket notation, starting from 0. In the above example, the first parameter of our osc object is the frequency (which we set to four) which means we can change it as follows:

osc[0]( 2 )
// sequence changes to frequency over time
osc[0].seq( [2,4,8], 1/2 )

Typically for an LFO you'll want to also have control over the amplitude (or gain) of the signal, and the center point (or bias). We can create this using an offset and a multiplier.

// create a sine oscillator bias and amp of .5, yielding a range of {0,1}
osc = cycle(4)
amp = mul( .5, osc )
bias= add( .5, amp )
signals[0]( bias )

// sequence amp
amp[0].seq( [.5,.25,.15], 1 )

This can be shortened:

osc = add( .5, mul( .5, cycle(2) ) 

In the above codeblock, osc[0] controls the bias, osc[1] controls the gain, and osc[2] controls the frequency.

Sequencing with signals

gibberwocky makes it easy to sample continuous waveforms in order to generate patterns for sequencing. If we pass a gen~ graph (similar to the LFO we created in the last section) to a sequence, we can then specify how often we want to sample it in order to trigger output. For example, to create a pattern of notes distributed between {-7,7} along a sine wave:

osc = round( mul( cycle(1), 4 ) )
devices['synth'].note.seq( osc, [1/4,1/8] )

This can also be fun to use with drums, where triggering different notes triggers different sounds. The below oscillator will range from 36–44:

osc = cycle( btof(4) ) // btof is beats-to-frequency
amp = mul( 4, osc )
bias= add( 40, amp )
devices.drums.midinote.seq( bias, 1/16 )

Euclid

You can also specify Euclidean rhythms using the Euclid() function, which returns a pattern:

devices['drums'].midinote.seq( 36, Euclid(5,8) )

Euclidean rhythms are specifcations of rhythm using a number of pulses allocated over a number of beats. The algorithm attempts to distribute the pulses as evenly as possible over all beats while maintaining a grid. Examples of these distributions are given below (where 'x' represents a pulse and '.' represents a rest):

1,4 : x...
2,3 : x.x
2,5 : x.x..
3,5 : x.x.x
3,8 : x..x..x.
5,8 : x.xx.xx. 
4,9 : x.x.x.x..
5,9 : x.x.x.x.x

As in Gibber, by default the number of beats chosen also determines the time used by each beat; selecting '5,8' means 5 pulses spread across 8 1/8 notes. However, you can also specify a different temporal resolution for the resulting pattern: '5,8,1/16' means 5 pulses spread across 8 beats where each beat is a 1/16th note.

You can read a paper describing Euclidean rhythms here: http://archive.bridgesmathart.org/2005/bridges2005-47.pdf

Clone this wiki locally