prolink-extension
v1.0.0Ableton Extension for Capturing DJ Sets via ProLink
Unverified listing. This repo is new or has little community activity and the developer has not claimed it. Extensions run code inside Live — read the source, check the author, and only install things you trust.
Ableton ProLink Extension
An Ableton Live extension that captures a live DJ set from Pioneer CDJs/XDJs in real time and writes it into Ableton's arrangement view as MIDI clips and cue points.
Press Record. Perform your set. Open Ableton. The entire performance appears as an editable timeline.
What it captures
- Track loads with artist/title metadata
- On-air transitions (clip start/end in arrangement)
- Hot cue triggers → arrangement cue points
- Loop enter/exit → cue points
- BPM changes → Ableton tempo
- Master deck changes
- Session start/stop
Requirements
- Ableton Live with Extensions support
- Pioneer CDJ/XDJ gear on the same LAN
- Node.js ≥ 24.14.1
- Java (for Beat Link API auto-launch)
Installation
Build the .ablx package and load it into Ableton:
npm install
npm run build
This produces prolink-extension-1.0.0.ablx. Load it via Ableton's Extensions panel.
Beat Link API JAR: The pre-built JAR is vendored at
vendor/beat-link-api.jarand is bundled automatically into the.ablx. No external dependency required.
Usage
- Connect Pioneer gear to the same network as your machine.
- In Ableton, right-click any Audio or MIDI track → ProLink: Start Capture.
- A status dialog opens showing deck state and connection status.
- Perform your set. Two MIDI tracks ("Deck 1", "Deck 2") are created in the arrangement, clips are placed as each track goes on-air, and cue points mark transitions and hot cues.
- Click Stop in the dialog (or right-click → ProLink: Stop Capture) when done.
The session is also saved as JSON to Ableton's extension storage directory under sessions/.
Development
npm run build:dev # dev bundle with sourcemaps (no .ablx zip)
npm run start # build:dev + load into Ableton via extensions-cli
npm run watch # build:dev + file watch + extensions-cli run
npm run typecheck # TypeScript type check only
npm test # run all tests
npx vitest run src/__tests__/Dispatcher.test.ts # single test file
The Ableton Extensions CLI (@ableton-extensions/cli) and SDK (@ableton-extensions/sdk) are vendored locally in vendor/ as .tgz files.
Architecture
Dual event-source model
The extension has two Pioneer event sources that run simultaneously during capture:
| Source | When primary |
|---|---|
| prolink-connect (direct UDP) | Beat Link Trigger is NOT running |
| Beat Link API poller (HTTP, 200 ms) | Beat Link Trigger IS running (occupies the same UDP ports) |
Both sources feed the same EventStore. The poller always runs; prolink-connect is skipped (with a warning) if it fails to bind.
Event pipeline
graph LR
subgraph Pioneer["Pioneer Network (UDP)"]
CDJ["CDJ/XDJ\ndecks"]
end
subgraph Sources["Event Sources"]
PL["prolink-connect\nlistener"]
BL["Beat Link API\npoller (200 ms)"]
end
subgraph Core["Core"]
ES["EventStore\n(append-only log)"]
D["Dispatcher\n(stateful router)"]
end
subgraph Output["Output"]
AW["AbletonWriter\nMIDI clips + cue points"]
VB["ViewBridge\nSSE → status dialog"]
end
CDJ -- "UDP status packets" --> PL
CDJ -- "HTTP /params.json\n(via Beat Link API)" --> BL
PL --> ES
BL --> ES
ES --> D
D --> AW
D --> VB
EventStore— append-only in-memory log ofProLinkEventvalues; flushes to JSON on stop.Dispatcher— stateful router; caches track metadata per deck and maps each event type to the correct writer/bridge calls.AbletonWriter— converts wall-clock timestamps to Ableton beat positions, then creates/renames/finalizes MIDI clips and cue points via the Extensions SDK.ViewBridge— runs a local SSE HTTP server (random port), injects the port into the status dialog HTML, and resolves the stop promise when the dialog closes.
Session lifecycle
sequenceDiagram
participant U as User
participant E as Extension
participant BL as Beat Link API
participant PL as prolink-connect
participant AS as Ableton Song
U->>E: Right-click → Start Capture
E->>BL: Launch JAR if not running
E->>PL: bringOnline() + connect()
Note over PL: Falls back to BL-only<br/>if UDP ports occupied
E->>AS: createMidiTrack() × 2<br/>(Deck 1, Deck 2)
E->>U: Status dialog opens
loop During set
BL-->>E: /params.json poll
PL-->>E: CDJ status packets
E->>AS: clips, cue points, tempo
E->>U: SSE state update
end
U->>E: Stop Capture
E->>AS: Finalize open clips
E->>E: Flush EventStore → JSON
E->>U: Dialog closes
Timing model
All timestamps are wall-clock milliseconds (Date.now()). src/utils/timing.ts converts them to Ableton beats using the master BPM at capture start. Beat position updates as the master BPM changes.
Ableton artifacts produced
| Event | Ableton artifact |
|---|---|
SESSION_START | Two MIDI tracks: "Deck 1", "Deck 2" |
ON_AIR_START | MIDI clip created; cue point ▶ D1: Artist – Title |
ON_AIR_END | Clip resized to actual duration; cue point ■ D1 |
TRACK_METADATA | Clip renamed if name was provisional |
BPM_CHANGE (master) | song.tempo updated |
LOOP_ENTER / LOOP_EXIT | Cue points ↺ Loop D1 / ↺ Loop End D1 |
| Hot cues (from metadata) | Cue points D1 Hot Cue A/B/… offset from clip start |
Extension Host constraints
- The bundle is CJS (esbuild) — the Extension Host's sandboxed Node.js blocks dynamic
require()resolution, sobetter-sqlite3andiconv-liteare aliased to empty stubs. - All Ableton SDK property mutations must go inside
context.withinTransaction(). remotedb.get()(prolink-connect metadata path) holds an internal mutex with no try/finally; the code uses aremotedbPendingset to prevent concurrent in-flight calls per device, which would otherwise deadlock.
Rate this extension
One rating per account; you can change it any time.
Comments
No comments yet.