Build step 1 of the Ableton scale-lighting brief: a dependency-free Node script that drives the keyboard directly, with the scale passed on the command line. Live and Max for Live come later. Lighting uses one event with 14 context-color handlers — a background zone covering every key except the 13 note keys, plus one handler per note key addressed by USB HID code. Colors travel in the event frame, so handlers are bound once and a scale change is a single POST, which is what the M4L step will need. Chose custom zones over bitmap mode: bitmap's 22x6 grid has no documented index-to-key table per model, while HID codes are exact. Painting the whole board with the background zone covers the same blackout caveat bitmap was suggested for. tools/fake-gamesense.js stands in for the GameSense server and renders the resolved frame as ANSI colour, so the mapping is verifiable without hardware or Windows. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
5.5 KiB
SteelSeries Apex 7 × Ableton Live — Scale-Aware Key Lighting
Handoff brief for a Claude Code agent. Translated and structured from a planning conversation. Goal: build the tooling to highlight the notes of the currently selected Ableton scale on the physical keyboard's RGB backlight.
Project goal
Use the per-key RGB backlight of a SteelSeries Apex 7 to highlight, in real time, the keys that correspond to the notes of the scale currently selected in Ableton Live 12. The physical keyboard is fitted with transparent keycaps so the light reads clearly as note highlighting.
The full desired flow:
Live 12 (Live API: root_note + scale_intervals)
→ Max for Live device (computes the pitch classes in the scale)
→ Node for Max (POST JSON over HTTP)
→ GameSense server (127.0.0.1)
→ Apex 7 per-key RGB
Hardware notes
- Keyboard: SteelSeries Apex 7 — per-key RGB, MX-compatible (cross-stem) switches, so standard MX keycaps fit.
- Keycaps: transparent / "pudding" MX keycaps for light bleed. (Already swapped; not part of the software build.)
- Requires SteelSeries GG running in the background for GameSense to work.
Key ↔ note mapping (Ableton computer MIDI keyboard)
When Ableton's computer MIDI keyboard is enabled, one octave maps like a piano. White keys on the bottom row, black keys on the row above:
| Note | Key | Note | Key |
|---|---|---|---|
| C | A | F# | T |
| C# | W | G | G |
| D | S | G# | Y |
| D# | E | A | H |
| E | D | A# | U |
| F | F | B | J |
| C | K |
Z / X = octave down/up, C / V = velocity down/up.
Pitch-class → key lookup (index 0–11):
0 C -> A
1 C# -> W
2 D -> S
3 D# -> E
4 E -> D
5 F -> F
6 F# -> T
7 G -> G
8 G# -> Y
9 A -> H
10 A# -> U
11 B -> J
(12 C -> K, the octave key)
Reading the scale from Live 12
Live 12 exposes the global/selected scale on the Song object in the Live
Object Model (LOM), accessible from Max for Live:
root_note— root, integer0–11(0 = C … 11 = B)scale_intervals— list of ints, e.g. major =[0, 2, 4, 5, 7, 9, 11]scale_name— display name stringscale_mode— whether scale mode is on
Compute the lit pitch classes:
lit = { (root_note + interval) % 12 for interval in scale_intervals }
Then map each pitch class to its QWERTY key via the table above.
Caveat: in Live 12 the scale is set per clip. Decide whether to observe the selected clip's scale or fix a global scale (existing "Scale Awareness" M4L packs can help enforce a global scale). Observe the relevant LOM property so the lighting updates when the scale changes.
Controlling the Apex 7 (SteelSeries GameSense SDK)
GameSense runs a local REST server. Flow:
- Read the server port from
coreProps.json:- Windows:
%PROGRAMDATA%\SteelSeries\SteelSeries Engine 3\coreProps.json - macOS:
/Library/Application Support/SteelSeries Engine 3/coreProps.json - The file gives an address like
127.0.0.1:<port>.
- Windows:
- Register a game + event + handler, then POST event data to
http://127.0.0.1:<port>/game_event(register via/game_metadataand/bind_game_event). - Per-key control options:
custom-zone-keys— address specific keys by USB HID usage code, withcontext-colorto set their color at runtime.bitmapmode — paint the whole keyboard at once (a 132-length array of[R,G,B], interpreted as a 22×6 grid mapped to nearest keys). Best for "dim background + bright scale keys" because it sets every key each update.
HID usage codes for the relevant letter keys (USB HID keyboard page):
A 0x04 S 0x16 D 0x07 F 0x09 G 0x0A H 0x0B J 0x0D K 0x0E
W 0x1A E 0x08 T 0x17 Y 0x1C U 0x18
Caveat: as soon as a GameSense event arrives, the keyboard enters "GameSense mode" and other keys go dark unless you set them. Set a base color for all keys (bitmap mode handles this cleanly), then override the scale keys.
The bridge: Max for Live → GameSense
Cleanest option is Node for Max running inside the M4L device: it can read
coreProps.json and issue the HTTP POSTs directly — no separate app needed.
Alternative: Max sends OSC/UDP to a small external Python/Node script that talks to GameSense.
Suggested build order
- Standalone script (Node or Python) that talks to GameSense: register a game, light a hardcoded set of keys by HID code, set a dim background. Verify on hardware.
- M4L device that reads
root_note/scale_intervalsfrom the LOM and prints the computed key set. Verify against the mapping table. - Wire the two together (Node for Max inside the device), observe the scale property so lighting updates live.
- Polish: base color, highlight color, octave key, handle scale-mode off.
Open decisions for the user
- Platform: Windows or macOS (changes the
coreProps.jsonpath). - Lighting style: bitmap (background + highlight) vs. just lighting the scale keys.
- Scale source: selected clip vs. enforced global scale.
References
- SteelSeries GameSense SDK (JSON handlers, per-key / bitmap lighting): https://github.com/SteelSeries/gamesense-sdk
- Live Object Model —
Song(scale properties): https://docs.cycling74.com/apiref/lom/song/ - Controlling Live using Max for Live: https://help.ableton.com/hc/en-us/articles/5402681764242-Controlling-Live-using-Max-for-Live
- Keys and Scales in Live 12 FAQ: https://help.ableton.com/hc/en-us/articles/11425083250972-Keys-and-Scales-in-Live-12-FAQ