Skip to content

Commit 6b93bb1

Browse files
author
Максим Лясковский
committed
docs: rewrite README for macOS menu bar port
1 parent 1d92564 commit 6b93bb1

1 file changed

Lines changed: 227 additions & 15 deletions

File tree

README.md

Lines changed: 227 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,227 @@
1-
# Prerequisits
2-
- Python
3-
- GCC
4-
- ALSA
5-
- ALSA dev libraries (`libasound2-dev`)
6-
- ALSA tools (for using `aconnect` that is part of `alsa-utils` package)
7-
8-
# Install
9-
1. Copy the `c_lib.c` and `clock.py`
10-
2. Compile `c_lib.c` to be used by `clock.py` with the following command:<br>
11-
`gcc -O3 -fPIC -shared -o liblinkbridge.so midi_clock_lib.c -lasound`
12-
3. Run the `clock.py`:<br>
13-
`python3 clock.py`
14-
4. Route the MIDI channel using `aconnect`:<br>
15-
To list options `aconnect -l` then from the list type the `aconnect <source> <destination>` for example: `aconnect 128 130`
1+
# LinkBridge
2+
3+
A tiny macOS menu bar app that forwards Ableton Link tempo to a hardware MIDI
4+
output. Drop it next to a Link-enabled DJ app or DAW and any MIDI gear that
5+
syncs to incoming MIDI clock will follow the tempo in real time.
6+
7+
```
8+
┌──────────────┐ Link ┌──────────────┐ MIDI clock ┌──────────────┐
9+
│ djay Pro / │ ─────────▶ │ LinkBridge │ ───────────────▶ │ Hardware │
10+
│ Live / etc. │ │ (menu bar) │ (CoreMIDI) │ MIDI device │
11+
└──────────────┘ └──────────────┘ └──────────────┘
12+
```
13+
14+
## Requirements
15+
16+
- macOS 15 (Sequoia) or later, Apple Silicon (tested on M2 Pro)
17+
- Python 3.11 or 3.12 (only needed for running from source / building the .app)
18+
- A USB-connected MIDI device with external clock support
19+
- An Ableton Link source on the same machine or LAN
20+
21+
## Quick start (from source)
22+
23+
```bash
24+
python3.11 -m venv venv
25+
source venv/bin/activate
26+
pip install -r requirements.txt
27+
python -m linkbridge
28+
```
29+
30+
A `♪ <bpm>` icon appears in the macOS menu bar within a few seconds. Click
31+
it, choose your MIDI output device from the **Output Device** submenu, and
32+
the clock starts streaming as soon as a Link peer reports a tempo.
33+
34+
## Build a standalone `.app`
35+
36+
```bash
37+
source venv/bin/activate
38+
pip install -r requirements-dev.txt
39+
./scripts/build_app.sh
40+
```
41+
42+
The bundle is produced at `dist/LinkBridge.app`. Drag it to `/Applications`
43+
or run it in place.
44+
45+
**On first launch:**
46+
47+
- macOS asks for **local network permission** ("Allow LinkBridge to find
48+
devices on local networks?"). Click **Allow**, otherwise Ableton Link
49+
cannot discover any peers and the tempo stays at the default 120 BPM
50+
forever. The bundle includes a description string explaining what the
51+
permission is used for.
52+
- The bundle is **unsigned** (no Apple Developer ID). If macOS Gatekeeper
53+
blocks it, right-click the `.app` in Finder, choose **Open**, confirm
54+
the warning, then launch normally afterwards.
55+
56+
## Menu reference
57+
58+
```
59+
♪ 125.0
60+
────────────
61+
Output Device ▸ ● Circuit Tracks MIDI
62+
○ DDJ-FLX4
63+
────
64+
↻ Refresh devices
65+
Enable Start/Stop events ☐
66+
────────────
67+
Quit
68+
```
69+
70+
| Item | Behavior |
71+
|---|---|
72+
| `♪ <bpm>` | Live tempo from the active Link peer. Shows `♪ --` when no MIDI device is selected, `♪ ERR` if the clock thread crashed. |
73+
| **Output Device** | All available CoreMIDI outputs. Pick one to route clock to it. The choice is remembered for next launch. `↻ Refresh devices` rebuilds the list — useful after plugging in a new USB device. |
74+
| **Enable Start/Stop events** | When ON, sends MIDI `START` on Link play and MIDI `STOP` on Link stop. Default OFF. The clock tick stream itself is **always** running once a device is selected, regardless of this toggle. |
75+
| **Quit** | Sends a final MIDI STOP if needed, closes the port, exits cleanly. |
76+
77+
## Compatibility — which DJ software works?
78+
79+
LinkBridge passes through whatever Ableton Link tempo it can see. The
80+
catch is that **not every DJ app broadcasts its deck tempo to Link** — most
81+
of them only listen.
82+
83+
### "Just works" — fully automatic
84+
85+
These apps act as Link tempo masters when a deck is playing, so LinkBridge
86+
picks up the tempo automatically with zero manual steps:
87+
88+
- **djay Pro for Mac** (Algoriddim) — officially supports the DDJ-FLX4 and
89+
many other Pioneer / Numark / Reloop controllers; the playing deck
90+
becomes the Link master automatically.
91+
- **Mixxx 2.5+** — open source, free, ships with a community DDJ-FLX4
92+
mapping and bidirectional Link support.
93+
- **Ableton Live**, **Logic Pro** with Link, **GarageBand**, and any other
94+
Link-aware DAW — playing the timeline broadcasts tempo to Link.
95+
96+
### Works with a small manual step — Rekordbox
97+
98+
**Rekordbox 7.x has a hard one-way Link integration:** the LINK button on
99+
each deck makes that deck *follow* Link, but Rekordbox does **not**
100+
broadcast the playing deck's tempo back to Link. This is a Rekordbox
101+
limitation, not a LinkBridge bug. See Pioneer's
102+
[Ableton Link FAQ](https://rekordbox.com/en/support/faq/ableton-link/) and
103+
this [community feature request](https://forums.pioneerdj.com/hc/en-us/community/posts/900002865663-Ableton-Link-in-Rekordbox-Suggestion-Follow-the-Master-Deck-BPM-option).
104+
105+
To use LinkBridge with Rekordbox, drive the Link tempo manually from
106+
Rekordbox's Ableton Link sub-window:
107+
108+
1. Open Rekordbox and open its **Ableton Link** sub-window (the small
109+
window with the BPM display, `TAP`, `+`, `-` buttons).
110+
2. Read the BPM of the track currently loaded on your master deck.
111+
3. Type or click that BPM into the Link sub-window using the `+`/`-`
112+
buttons (or use `TAP` to find it by ear).
113+
4. LinkBridge picks it up immediately and your hardware follows.
114+
5. When you change tracks, repeat — Rekordbox does not auto-update Link.
115+
116+
> **Note about the tempo slider:** When a hardware controller like the
117+
> DDJ-FLX4 is connected, Rekordbox disables the on-screen TEMPO slider for
118+
> Link control entirely. The Link sub-window's `+`/`-` buttons (or MIDI-
119+
> mapped equivalents) are the only way to drive Link tempo from a
120+
> controller-attached Rekordbox session.
121+
122+
If the manual workflow is too tedious for your set, the
123+
[`rkbx_link`](https://github.com/grufkork/rkbx_link) project reads
124+
Rekordbox's process memory directly and pushes the master deck's tempo
125+
into Link automatically. It requires re-signing Rekordbox to add the
126+
`get-task-allow` entitlement and running with `sudo` — see its
127+
`MACOS_SETUP.md` for details. LinkBridge does not currently bundle this
128+
behaviour but composes cleanly with `rkbx_link` if you run them
129+
side-by-side.
130+
131+
## Using with Novation Circuit Tracks
132+
133+
The Circuit Tracks needs one Setup-view setting before it accepts external
134+
clock — this is a one-time change that persists across reboots.
135+
136+
1. On the Circuit Tracks, hold **Shift** and press **Save** to enter
137+
Setup view.
138+
2. On the bottom row of pads find the four "MIDI data control" Rx/Tx
139+
pads. The rightmost pair is **MIDI Clock Rx/Tx**. Make sure **Clock
140+
Rx** is lit (factory default is OFF).
141+
3. Press **Play** on the Circuit Tracks to exit Setup view.
142+
143+
After that:
144+
145+
- Launch LinkBridge and pick **Circuit Tracks MIDI** from the Output
146+
Device submenu.
147+
- If the Circuit Tracks is **stopped** when LinkBridge starts streaming
148+
clock, it instantly enters external sync mode — the Tempo/Swing view
149+
shows `SYN` in red. Press Play and the pattern follows the incoming
150+
tempo.
151+
- If the Circuit Tracks was **already playing an internal pattern** when
152+
LinkBridge connected, it ignores the incoming clock and keeps playing
153+
at its internal tempo. **Recovery is one button press:** tap **Stop**
154+
on the Circuit Tracks; `SYN` appears immediately because the clock
155+
stream was already flowing. Press Play again and you're locked.
156+
- When LinkBridge quits, the clock stream stops, `SYN` disappears, and
157+
the Circuit Tracks reverts to internal clock — any pattern that was
158+
playing via SYN halts.
159+
160+
This behaviour is the Circuit Tracks's, not LinkBridge's. Most other
161+
class-compliant USB MIDI gear follows incoming clock without any
162+
external-sync arming step.
163+
164+
## Files and logs
165+
166+
| Path | Purpose |
167+
|---|---|
168+
| `~/Library/Application Support/LinkBridge/settings.json` | Last selected device and Start/Stop toggle state |
169+
| `~/Library/Logs/LinkBridge/linkbridge.log` | Rotating log file (1 MB × 3) |
170+
171+
Set `LINKBRIDGE_DEBUG=1` in the environment for verbose logging:
172+
173+
```bash
174+
LINKBRIDGE_DEBUG=1 python -m linkbridge
175+
```
176+
177+
## Architecture
178+
179+
A single Python process with three threads sharing a lock-guarded
180+
`ClockState` dataclass:
181+
182+
| Thread | Module | Job |
183+
|---|---|---|
184+
| Main | `linkbridge/app.py` | rumps menu bar UI, 500 ms label refresh |
185+
| Clock | `linkbridge/clock_engine.py` | 24 ppqn MIDI clock generator with drift compensation |
186+
| Link | `linkbridge/link_monitor.py` | aalink callback loop pushing tempo + transport into ClockState |
187+
188+
The Settings store and the MidiOutput helpers (`linkbridge/settings.py`,
189+
`linkbridge/midi_output.py`) are stateless utilities used by the threads
190+
above.
191+
192+
## Tests
193+
194+
```bash
195+
source venv/bin/activate
196+
pytest
197+
```
198+
199+
22 unit tests cover Settings, MidiOutput, and ClockEngine using fake
200+
clocks / fake MIDI sinks — no hardware or Link peer required. The Link
201+
monitor and the menu bar app are validated by manual smoke tests against
202+
real hardware (the smoke procedure is documented in the project plan).
203+
204+
## Regenerating the app icon
205+
206+
The icon source is `assets/icon.png` (1024×1024). To rebuild the
207+
`assets/LinkBridge.icns` file from a fresh source PNG:
208+
209+
```bash
210+
.venv-probe/bin/pip install Pillow # or any venv with Pillow available
211+
python3 scripts/build_icon.py
212+
```
213+
214+
The script flood-fills the white background to transparent, crops to the
215+
non-transparent bbox, generates all 10 macOS iconset sizes, and runs
216+
`iconutil` to produce the final `.icns`.
217+
218+
## Legacy Linux implementation
219+
220+
The original ALSA / C Linux implementation lives in `legacy/` for
221+
reference and is not maintained. If you want to run that on Linux, the
222+
build commands are at the top of `legacy/midi_clock_lib.c` — but the
223+
macOS port in this branch is the only thing actively developed.
224+
225+
## License
226+
227+
See `LICENSE`.

0 commit comments

Comments
 (0)