Add an Audio Effect variant of the device, alongside the MIDI one
The device is a pure observer — it reads the LOM and talks to GameSense and never looks at a note — so it does not have to sit in the path of anything you play. But a Max MIDI Effect without midiin -> midiout swallows MIDI instead of passing it on, so the shipped device routes every note you play through Max's scheduler on its way to your instrument. Pointless cost for this device. max/scale-lighting-audio.maxpat is the same patcher as an Audio Effect, declaring no I/O at all: no midiin/midiout, no plugin~/plugout~. Park it on a dedicated empty Audio track and it is provably out of every signal path. The two patchers differ by exactly midiin, midiout and the patchline between them — @watch 1 and everything else are deliberately left identical on both sides, so an A/B measures the passthrough and nothing else. Both register the same GameSense game, so they have to be loaded one at a time; that and a way to actually measure the difference (compare note onsets across recorded takes, not the CPU meter) are in the README. The patcher test now runs over both files, and two new tests pin the distinction: the MIDI variant must wire midiin to midiout, and the audio variant must declare none of those four objects — the kind of thing a later edit would otherwise silently undo. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
70
README.md
70
README.md
@@ -122,24 +122,75 @@ whole chain from the brief is live:
|
||||
Live 12 → js (LiveAPI) → Node for Max → GameSense → Apex 7
|
||||
```
|
||||
|
||||
### Two variants
|
||||
|
||||
The device is pure observer — it reads the LOM and talks to GameSense, and it
|
||||
never looks at a note. So it does not have to sit in the path of anything you
|
||||
play. Two patchers ship, identical apart from that:
|
||||
|
||||
| Patcher | Live device type | Passthrough |
|
||||
| --- | --- | --- |
|
||||
| `max/scale-lighting.maxpat` | Max **MIDI** Effect | `midiin` → `midiout` |
|
||||
| `max/scale-lighting-audio.maxpat` | Max **Audio** Effect | none |
|
||||
|
||||
The MIDI variant needs the passthrough: a Max MIDI Effect without `midiin` →
|
||||
`midiout` swallows MIDI instead of passing it on. That means when it sits on the
|
||||
track you play, every note you play is routed through Max's scheduler on its way
|
||||
to your instrument — a small cost, and a pointless one here.
|
||||
|
||||
The audio variant declares no I/O at all: no `midiin`/`midiout`, no
|
||||
`plugin~`/`plugout~`. Nothing you play goes through Max. Park it on a **dedicated
|
||||
empty Audio track** and it cannot be in the signal path of anything.
|
||||
|
||||
If you would rather not add a track, the MIDI variant on a dedicated empty MIDI
|
||||
track is just as much out of the way — the cost only appears when the device is
|
||||
on the track you are actually playing.
|
||||
|
||||
### Installing it
|
||||
|
||||
The repo ships a `.maxpat` rather than a `.amxd`, because an `.amxd` has to be
|
||||
The repo ships `.maxpat` files rather than `.amxd`, because an `.amxd` has to be
|
||||
born inside Live:
|
||||
|
||||
1. In Live, drag a **Max MIDI Effect** onto a MIDI track and click its edit
|
||||
(pencil) button to open Max.
|
||||
2. Open `max/scale-lighting.maxpat` in a text editor, copy all of it, then in
|
||||
the Max device window: **Edit → Select All**, **Delete**, **Edit → Paste**.
|
||||
Max pastes the whole patcher, `midiin`/`midiout` passthrough included.
|
||||
3. **File → Save**, and save the device as `max/Ableton Scale Lighting.amxd` —
|
||||
in *this* folder, so `js` and `node.script` find their scripts next to it.
|
||||
1. In Live, drag a **Max Audio Effect** onto a dedicated empty Audio track (or a
|
||||
**Max MIDI Effect** onto a MIDI track, for the MIDI variant) and click its
|
||||
edit (pencil) button to open Max.
|
||||
2. Open the matching `.maxpat` from `max/` in a text editor, copy all of it, then
|
||||
in the Max device window: **Edit → Select All**, **Delete**, **Edit → Paste**.
|
||||
Max pastes the whole patcher.
|
||||
3. **File → Save**, and save the device into `max/` — in *this* folder, so `js`
|
||||
and `node.script` find their scripts next to it. Suggested names:
|
||||
`Ableton Scale Lighting.amxd` and `Ableton Scale Lighting (Audio).amxd`.
|
||||
4. Make sure `dist/` is built (`npm install` in the repo root). `node.script`
|
||||
loads `dist/src/max/device.js`.
|
||||
|
||||
Add this repo's folder in Live's browser (**Add Folder…**) to load the device
|
||||
from there in future sets.
|
||||
|
||||
> **Load one at a time.** Both variants register the same GameSense game
|
||||
> (`ABLETON_SCALE`), so two of them running together fight over the board and
|
||||
> either one's `shutdown` blanks it for both.
|
||||
|
||||
### Comparing the two
|
||||
|
||||
Both patchers keep `@watch 1` on `node.script` and `autowatch` in
|
||||
`scale-observer.js`, so the only difference between them is the passthrough and
|
||||
the A/B measures exactly that.
|
||||
|
||||
The honest test is not "does it feel laggy" — it is a recording. On one MIDI
|
||||
track with an instrument that has a sharp attack:
|
||||
|
||||
1. Record a bar of audio with no device on the track.
|
||||
2. Drop the MIDI variant *before* the instrument, play the same part, record again.
|
||||
3. Do the same with the audio variant on its own separate track.
|
||||
|
||||
Line the three takes up and compare note onsets. Live's CPU meter and Max's
|
||||
**Window → Max Console** are worth a glance too, but neither shows scheduler
|
||||
latency — only the onsets do.
|
||||
|
||||
Note that both variants start a `node.script` process and heartbeat GameSense
|
||||
every 5s regardless of where they sit; that cost is identical and is not what
|
||||
this comparison is about.
|
||||
|
||||
### What it does
|
||||
|
||||
Change the scale in Live's control bar and the board follows: scale notes in
|
||||
@@ -222,7 +273,8 @@ src/errors.ts `catch (err: unknown)` helpers
|
||||
src/index.ts ScaleLighting — the API the M4L device drives
|
||||
src/live.ts LOM values -> a resolved scale, and how to print it
|
||||
src/max/device.ts the Node for Max device: Live's scale in, lighting out
|
||||
max/scale-lighting.maxpat the M4L patcher (paste into a device created in Live)
|
||||
max/scale-lighting.maxpat M4L patcher, MIDI Effect (midiin/midiout passthrough)
|
||||
max/scale-lighting-audio.maxpat M4L patcher, Audio Effect (no passthrough at all)
|
||||
max/scale-observer.js the `js` object that observes the Live Object Model (ES5)
|
||||
max/scale-device.js `node.script` launcher — runs dist/src/max/device.js
|
||||
tools/fake-gamesense.ts terminal simulator of the GameSense server
|
||||
|
||||
Reference in New Issue
Block a user