pulusound

<<< back to home page

SuperCollider patterns and MIDI chords

posted 2026-01-28

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;
)