A Max for Live device that shows what you're playing on a guitar neck or a piano keyboard, live, inside Ableton.
Drop it on a MIDI track ahead of your instrument and play. It names the chord, shows you where to grab it, and — for melodies — shows the scale position your hand should be in, with the line lighting up as it moves through the shape.
It sits in the MIDI-effect chain like Ableton's own MIDI Monitor, passes notes straight through, and makes no sound of its own.
Requires Live Suite, or Live Standard/Intro with the Max for Live add-on. Max ships with Live Suite — there's nothing else to install.
Paste this into Terminal. It downloads the device into Live's User Library:
DEST=~/Music/Ableton/User\ Library/Presets/MIDI\ Effects/Max\ MIDI\ Effect
BASE=https://raw.githubusercontent.com/PaulBratslavsky/chordlens-visualizer/main
mkdir -p "$DEST"
curl -fsSL "$BASE/ChordLens%20Visualizer.amxd" -o "$DEST/ChordLens Visualizer.amxd"
curl -fsSL "$BASE/chordlens-visualizer.js" -o "$DEST/chordlens-visualizer.js"
curl -fsSL "$BASE/chordlens-key.v8.js" -o "$DEST/chordlens-key.v8.js"-
Code → Download ZIP above, then unzip.
-
Take these three files:
ChordLens Visualizer.amxdchordlens-visualizer.jschordlens-key.v8.js
-
Put all three in the same folder inside your Live User Library:
macOS —
~/Music/Ableton/User Library/Presets/MIDI Effects/Max MIDI Effect/Windows —Documents\Ableton\User Library\Presets\MIDI Effects\Max MIDI Effect\
All three files must sit side by side. The device loads its two scripts by bare filename, resolved next to itself. Move the
.amxdon its own and you get an empty box where the fretboard should be.
- In Live's browser, open User Library (or Categories → Max for Live).
- Drag ChordLens Visualizer onto a MIDI track, before your instrument.
- Play.
No Instrument Rack, no routing, no second track — it's a MIDI effect, so it sits ahead of the instrument and passes notes through untouched. It follows clip playback as well as live playing.
If it doesn't show up, click ↻ at the top of the User Library, or restart Live.
Click the buttons in the device to switch. Everything is a click — there's nothing to configure.
NOTES — every position on the neck matching what you're holding. Answers where does this note live?
SHAPES — names the chord and searches real fingerings for it, drawn as
chord diagrams laid out horizontally, the way the neck sits when you're holding
the guitar. Barres are drawn as bars, the root is orange, and the hand position
is labelled (5fr). Answers what do I actually grab?
NECK — the same grips boxed and labelled (FR 2, FR 7, FR 11) on one
neck, with notes coloured by pitch class, so you can see how the shapes relate
to each other up the neck.
MELODY — one scale position, with the line lighting up as it passes
through. This is the one for playing a part back: NOTES scatters a single
melody note across twelve places on the neck, which tells you nothing about
where to put your hand. ◀ ▶ steps through the positions.
The scale comes from Ableton's song key when you've set one — the button
reads LIVE. With no key set it infers one from what you play (GUESS), and
clicking unlinks it so you can cycle the scale by hand (MANUAL). Major, the
modes, harmonic and melodic minor, both pentatonics, blues, whole tone and the
diminished scales.
Notes outside the scale are still shown, ringed in white, and named in the
header as they go by (A# out of key). A note that is in the scale but outside
the current box gets a fainter ring. This matters for anything that moves
between keys: hiding a note because it doesn't fit the scale would hide exactly
the note you want to look at, and seeing which one is fighting the scale is how
you tell a passing tone from a modulation.
The held notes on a keyboard, root highlighted, with the range snapped to whole octaves so it doesn't shift under your hands while you play.
A chord readout (Cmaj7, Am7, G/B), a NAMES toggle that letters every
lit position, and tunings for standard guitar, drop D, DADGAD and 4-string
bass.
midiin ─┬─▶ midiout passthrough, so your instrument
│ still sounds
├─▶ midiparse ─0─▶ prepend note ─┐
│ └─2─▶ prepend cc ─┼─▶ jsui the views
live.thisdevice ─▶ v8 (song key) ────────┘
midiin, notnotein—midiincarries the track's MIDI including clip playback;noteinonly hears physical MIDI ports and would miss clips.- The passthrough matters. Without
midiin → midioutthe device swallows the notes and the instrument after it goes silent. midiparseoutlet 2 is control change, which is how all-notes-off (CC 123) arrives when the transport stops. Without it, whatever was sounding at the moment you hit stop stays lit forever — its note-off never comes.- The
v8object reads Ableton's song key. It needs to be a separate object becausejsuidraws but cannot touch the Live API, andv8can touch it but cannot draw. They talk over akey <rootPc> <scaleName>message.
Reading the song key is the thing that makes this a Max device rather than a plugin: VST3 and AU expose tempo and playhead position and nothing at all about key, scale, clips or track structure.
| File | Role |
|---|---|
chordlens-visualizer.js |
Music theory and all drawing, run by jsui |
chordlens-key.v8.js |
Reads Ableton's song key over the Live API, run by v8 |
ChordLens Visualizer.amxd |
The device (generated — don't hand-edit) |
ChordLens Visualizer.maxpat |
The same patch as readable JSON (generated) |
build-device.py |
Generates the device from source |
test.js |
Tests for the theory |
No npm install, no node_modules, no build step to use it.
python3 build-device.py --installWrites the .amxd and copies it, with both scripts, into your User Library.
Why
--installmatters. The moment you drag a device into Live, Ableton copies it into your User Library and reads that copy from then on — editing the file in this folder silently changes nothing.--installkeeps them in step.
Most Max for Live workflows have you assemble the .amxd by hand in the Max
editor: drag in a Max MIDI Effect, select all, delete, paste JSON, save. That's
unnecessary. An .amxd is a small binary header wrapping the patcher JSON —
"ampf" │ len=4 │ "mmmm" │ "meta" │ len=4 │ 1 │ "ptch" │ len │ <JSON> │ NUL
— so build-device.py writes it directly. The patch is source you can diff,
not a binary you edit by clicking.
autowatch is set, so saving chordlens-visualizer.js reloads it in the
running device in under a second. Changing the patch (adding an object) still
needs the device deleted and dragged in again.
node test.jsPlain node, no npm, matching the device's own rule. Covers chord detection, the
voicing search (C still has to give the CAGED shapes x32010 / x35553 / 8aa988), and the scale positions — including the A-minor shapes taken from
guitarscale.org and a transposition
check proving C# minor lands exactly four frets above A minor.
One test exists purely as a scar. jsui shares one global scope across the
whole file, and the voicing search and the scale code both defined a constant
called MIN_POSITION_GAP. The later declaration silently won, so scale
positions came out spaced three frets apart instead of two — no error, just
wrong shapes. Scale constants are prefixed now, and the test pins both
behaviours.
A knob or dial appears where the fretboard should be.
jsui couldn't find its script and fell back to Max's jsui_default.js, which
draws a 2D dial. Either the scripts aren't next to the .amxd, or the patcher
declares the object wrongly — jsui is a UI object, so it needs its own
maxclass and a filename attribute:
{"maxclass": "jsui", "filename": "chordlens-visualizer.js", ...} ✓
{"maxclass": "newobj", "text": "jsui chordlens-visualizer.js"} ✗ argument droppedThe second form is how plain objects (midiin, prepend note) are written,
and it fails silently for UI objects.
Changes to a script do nothing. Live reads the User Library copy, not this
folder. Re-run build-device.py --install.
The device won't pick up a rebuilt .amxd. Delete it from the track and
drag a fresh one in — Live holds the loaded patch in memory.
Notes stay lit after the transport stops. That's what the CC 123 branch prevents. Check Window → Max Console for script errors.
The scale looks wrong. Check whether the button reads LIVE, GUESS or
MANUAL. Live's key is global to the set, so a section that modulates will
disagree with it — click to unlink and set the scale yourself.
MIT. Do what you like with it.
- ChordLens — the desktop app this grew out of, with a Max for Live bridge that sends notes, key and transport out over a WebSocket.
- vst3-plugin-lesson — the same idea built as a VST3/AU plugin, plus an eight-chapter guide to audio plugin development written from it. It also explains why this ended up as a Max device: Live doesn't route track MIDI to third-party plugins in the MIDI-effect slot, so the plugin needs an Instrument Rack workaround to do the same job slightly worse.