PaulBratslavsky/chordlens-visualizer

A Max for Live device that shows what you're playing on a guitar neck or piano keyboard, live inside Ableton

★ 0Forks 0JavaScriptGitHub ↗Compare

README

ChordLens Visualizer

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.


Install

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.

Quick 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"

Manual install

  1. Code → Download ZIP above, then unzip.

  2. Take these three files:

    • ChordLens Visualizer.amxd
    • chordlens-visualizer.js
    • chordlens-key.v8.js
  3. 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 .amxd on its own and you get an empty box where the fretboard should be.

Use it

  1. In Live's browser, open User Library (or Categories → Max for Live).
  2. Drag ChordLens Visualizer onto a MIDI track, before your instrument.
  3. 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.


The views

Click the buttons in the device to switch. Everything is a click — there's nothing to configure.

Guitar

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.

Piano

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.

Everywhere

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.


How it works

midiin ─┬─▶ midiout                              passthrough, so your instrument
        │                                        still sounds
        ├─▶ midiparse ─0─▶ prepend note ─┐
        │              └─2─▶ prepend cc ─┼─▶ jsui   the views
live.thisdevice ─▶ v8 (song key) ────────┘
  • midiin, not notein — midiin carries the track's MIDI including clip playback; notein only hears physical MIDI ports and would miss clips.
  • The passthrough matters. Without midiin → midiout the device swallows the notes and the instrument after it goes silent.
  • midiparse outlet 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 v8 object reads Ableton's song key. It needs to be a separate object because jsui draws but cannot touch the Live API, and v8 can touch it but cannot draw. They talk over a key <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.


Files

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.


Development

python3 build-device.py --install

Writes the .amxd and copies it, with both scripts, into your User Library.

Why --install matters. 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. --install keeps 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.

Tests

node test.js

Plain 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.


Troubleshooting

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 dropped

The 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.


Licence

MIT. Do what you like with it.


Related

  • 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.

Contributors

codingafterthirty

Issues