Files
steelseries-live-scale/apex7-ableton-scale-lighting.md
khannurien 425eb86327 Add standalone GameSense scale lighting for the Apex 7
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>
2026-08-12 13:10:35 +00:00

5.5 KiB
Raw Permalink Blame History

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 011):

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, integer 011 (0 = C … 11 = B)
  • scale_intervals — list of ints, e.g. major = [0, 2, 4, 5, 7, 9, 11]
  • scale_name — display name string
  • scale_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:

  1. 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>.
  2. Register a game + event + handler, then POST event data to http://127.0.0.1:<port>/game_event (register via /game_metadata and /bind_game_event).
  3. Per-key control options:
    • custom-zone-keys — address specific keys by USB HID usage code, with context-color to set their color at runtime.
    • bitmap mode — 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

  1. 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.
  2. M4L device that reads root_note / scale_intervals from the LOM and prints the computed key set. Verify against the mapping table.
  3. Wire the two together (Node for Max inside the device), observe the scale property so lighting updates live.
  4. Polish: base color, highlight color, octave key, handle scale-mode off.

Open decisions for the user

  • Platform: Windows or macOS (changes the coreProps.json path).
  • Lighting style: bitmap (background + highlight) vs. just lighting the scale keys.
  • Scale source: selected clip vs. enforced global scale.

References