SuperCollider patterns and MIDI chords
presented at the Algorave Helsinki January 2026 meetup: how to use a MIDI keyboard to set chords for a SuperCollider pattern to play. this can be a nice way to add some hands-on control to your patterns.
i originally wrote this for "anxiety", a track that blends SuperCollider-patterned Game Boy sounds with drums from TidalCycles. i played it at the Aalto Media Lab Winter Demo Day in 2020, which was online-only for reasons you might be able to guess.
s.boot;
MIDIIn.connectAll;
(
// this list tracks the notes currently being held down
~keysDown = [];
// this one saves the held notes even after they are released
~chord = [0, 3, 7] + 48;
MIDIdef.noteOn(\chordOn, { |vel, num|
// if all keys were released before pressing this one, reset the chord
if(~keysDown.isEmpty) {
~chord = [];
};
// add to both arrays, avoiding duplicates
if(~keysDown.includes(num).not) {
~keysDown = ~keysDown.add(num);
};
if(~chord.includes(num).not) {
~chord = ~chord.add(num);
("chord = "++~chord).postln;
};
});
MIDIdef.noteOff(\chordOff, { |vel, num|
// remove from keysDown but not from the chord
~keysDown.remove(num);
});
)
// example synth
(
SynthDef(\saw, { |out=0, freq, amp=0.1|
var sig;
sig = Saw.ar(freq);
sig = RLPF.ar(sig, EnvGen.ar(Env([5000,1000], [0.4], [-9])));
sig = sig * EnvGen.ar(Env.perc(0.001,0.4), doneAction: Done.freeSelf);
sig = sig * amp ! 2;
Out.ar(out, sig);
}).add;
)
// example patterns
// just keep playing the chord all at once
(
Pdef(\test, Pbind(
\instrument, \saw,
\dur, Pseq([3,3,2]/8, inf),
\midinote, Pfunc { ~chord }
)).play;
)
// or arpeggiate
(
Pdef(\test, Pbind(
\instrument, \saw,
\dur, 1/8,
\midinote, Pseries(0, 1).collect { |i| ~chord.wrapAt(i) }
)).play;
)