Skip to content

AnyByte/LinkBridge

 
 

Repository files navigation

LinkBridge

A tiny macOS menu bar app that forwards Ableton Link tempo to a hardware MIDI output. Drop it next to a Link-enabled DJ app or DAW and any MIDI gear that syncs to incoming MIDI clock will follow the tempo in real time.

  ┌──────────────┐    Link    ┌──────────────┐    MIDI clock    ┌──────────────┐
  │  djay Pro /  │ ─────────▶ │  LinkBridge  │ ───────────────▶ │  Hardware    │
  │  Live / etc. │            │  (menu bar)  │   (CoreMIDI)     │  MIDI device │
  └──────────────┘            └──────────────┘                  └──────────────┘

Requirements

  • macOS 15 (Sequoia) or later, Apple Silicon (tested on M2 Pro)
  • Python 3.11 or 3.12 (only needed for running from source / building the .app)
  • A USB-connected MIDI device with external clock support
  • An Ableton Link source on the same machine or LAN

Quick start (from source)

python3.11 -m venv venv
source venv/bin/activate
pip install -r requirements.txt
python -m linkbridge

A ♪ <bpm> icon appears in the macOS menu bar within a few seconds. Click it, choose your MIDI output device from the Output Device submenu, and the clock starts streaming as soon as a Link peer reports a tempo.

Build a standalone .app

source venv/bin/activate
pip install -r requirements-dev.txt
./scripts/build_app.sh

The bundle is produced at dist/LinkBridge.app. To package it as a distributable disk image:

./scripts/build_dmg.sh 2.0.0

This produces dist/LinkBridge-v2.0.0.dmg containing LinkBridge.app plus a symlink to /Applications for drag-to-install. Releases on GitHub Releases ship the .dmg exclusively.

Installation flow:

  • Download LinkBridge-v<version>.dmg from the latest release
  • Double-click the .dmg to mount it
  • Drag LinkBridge.app onto the Applications shortcut in the disk image window
  • Eject the disk image
  • Launch from /Applications

On first launch (Gatekeeper bypass for unsigned apps):

The bundle is unsigned (no Apple Developer ID), so macOS Gatekeeper on Sequoia (15+) blocks the first launch with a "could not be opened because Apple cannot check it for malicious software" dialog. Apple removed the older right-click → Open shortcut in Sequoia, so the only way through is via System Settings:

  1. Double-click LinkBridge.app once. It will be blocked — dismiss the dialog.
  2. Open System Settings → Privacy & Security.
  3. Scroll down to the Security section. You will see "LinkBridge was blocked to protect your Mac" with an Open Anyway button on the right.
  4. Click Open Anyway, authenticate with Touch ID or your password if prompted, and confirm the follow-up dialog.
  5. LinkBridge launches. Subsequent launches work normally without any prompts.

Local network permission:

Right after the first successful launch, macOS asks "Allow LinkBridge to find devices on local networks?" — click Allow. Without this permission, Ableton Link cannot discover any peers and the menu bar tempo stays at the default 120 BPM forever. The bundle ships a description string explaining what the permission is used for.

Menu reference

♪ 125.0
────────────
Output Device  ▸  ● Circuit Tracks MIDI
                  ○ DDJ-FLX4
                  ────
                  ↻ Refresh devices
Enable Start/Stop events  ☐
────────────
Quit
Item Behavior
♪ <bpm> Live tempo from the active Link peer. Shows ♪ -- when no MIDI device is selected, ♪ ERR if the clock thread crashed.
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.
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.
Quit Sends a final MIDI STOP if needed, closes the port, exits cleanly.

Compatibility — which DJ software works?

LinkBridge passes through whatever Ableton Link tempo it can see. The catch is that not every DJ app broadcasts its deck tempo to Link — most of them only listen.

"Just works" — fully automatic

These apps act as Link tempo masters when a deck is playing, so LinkBridge picks up the tempo automatically with zero manual steps:

  • djay Pro for Mac (Algoriddim) — officially supports the DDJ-FLX4 and many other Pioneer / Numark / Reloop controllers; the playing deck becomes the Link master automatically.
  • Mixxx 2.5+ — open source, free, ships with a community DDJ-FLX4 mapping and bidirectional Link support.
  • Ableton Live, Logic Pro with Link, GarageBand, and any other Link-aware DAW — playing the timeline broadcasts tempo to Link.

Works with a small manual step — Rekordbox

Rekordbox 7.x has a hard one-way Link integration: the LINK button on each deck makes that deck follow Link, but Rekordbox does not broadcast the playing deck's tempo back to Link. This is a Rekordbox limitation, not a LinkBridge bug. See Pioneer's Ableton Link FAQ and this community feature request.

To use LinkBridge with Rekordbox, drive the Link tempo manually from Rekordbox's Ableton Link sub-window:

  1. Open Rekordbox and open its Ableton Link sub-window (the small window with the BPM display, TAP, +, - buttons).
  2. Read the BPM of the track currently loaded on your master deck.
  3. Type or click that BPM into the Link sub-window using the +/- buttons (or use TAP to find it by ear).
  4. LinkBridge picks it up immediately and your hardware follows.
  5. When you change tracks, repeat — Rekordbox does not auto-update Link.

Note about the tempo slider: When a hardware controller like the DDJ-FLX4 is connected, Rekordbox disables the on-screen TEMPO slider for Link control entirely. The Link sub-window's +/- buttons (or MIDI- mapped equivalents) are the only way to drive Link tempo from a controller-attached Rekordbox session.

If the manual workflow is too tedious for your set, the rkbx_link project reads Rekordbox's process memory directly and pushes the master deck's tempo into Link automatically. It requires re-signing Rekordbox to add the get-task-allow entitlement and running with sudo — see its MACOS_SETUP.md for details. LinkBridge does not currently bundle this behaviour but composes cleanly with rkbx_link if you run them side-by-side.

Using with Novation Circuit Tracks

The Circuit Tracks needs one Setup-view setting before it accepts external clock — this is a one-time change that persists across reboots.

  1. On the Circuit Tracks, hold Shift and press Save to enter Setup view.
  2. On the bottom row of pads find the four "MIDI data control" Rx/Tx pads. The rightmost pair is MIDI Clock Rx/Tx. Make sure Clock Rx is lit (factory default is OFF).
  3. Press Play on the Circuit Tracks to exit Setup view.

After that:

  • Launch LinkBridge and pick Circuit Tracks MIDI from the Output Device submenu.
  • If the Circuit Tracks is stopped when LinkBridge starts streaming clock, it instantly enters external sync mode — the Tempo/Swing view shows SYN in red. Press Play and the pattern follows the incoming tempo.
  • If the Circuit Tracks was already playing an internal pattern when LinkBridge connected, it ignores the incoming clock and keeps playing at its internal tempo. Recovery is one button press: tap Stop on the Circuit Tracks; SYN appears immediately because the clock stream was already flowing. Press Play again and you're locked.
  • When LinkBridge quits, the clock stream stops, SYN disappears, and the Circuit Tracks reverts to internal clock — any pattern that was playing via SYN halts.

This behaviour is the Circuit Tracks's, not LinkBridge's. Most other class-compliant USB MIDI gear follows incoming clock without any external-sync arming step.

Files and logs

Path Purpose
~/Library/Application Support/LinkBridge/settings.json Last selected device and Start/Stop toggle state
~/Library/Logs/LinkBridge/linkbridge.log Rotating log file (1 MB × 3)

Set LINKBRIDGE_DEBUG=1 in the environment for verbose logging:

LINKBRIDGE_DEBUG=1 python -m linkbridge

Architecture

A single Python process with three threads sharing a lock-guarded ClockState dataclass:

Thread Module Job
Main linkbridge/app.py rumps menu bar UI, 500 ms label refresh
Clock linkbridge/clock_engine.py 24 ppqn MIDI clock generator with drift compensation
Link linkbridge/link_monitor.py aalink callback loop pushing tempo + transport into ClockState

The Settings store and the MidiOutput helpers (linkbridge/settings.py, linkbridge/midi_output.py) are stateless utilities used by the threads above.

Tests

source venv/bin/activate
pytest

22 unit tests cover Settings, MidiOutput, and ClockEngine using fake clocks / fake MIDI sinks — no hardware or Link peer required. The Link monitor and the menu bar app are validated by manual smoke tests against real hardware (the smoke procedure is documented in the project plan).

Releasing a new version

Releases are cut by a single click in the GitHub Actions tab — no local commands or git tagging required.

  1. Go to https://github.com/AnyByte/LinkBridge/actions/workflows/release.yml
  2. Click Run workflow
  3. Type the new version (e.g. 2.1.0, no v prefix)
  4. Click Run workflow

The CI will then:

  • Bump the version strings in linkbridge/__init__.py and setup.py
  • Commit and tag the bump on main (v2.1.0)
  • Run the test suite
  • Build LinkBridge.app and package it as a .dmg via hdiutil
  • Create a draft GitHub Release with auto-generated notes (built from the pull request history since the previous tag) and the LinkBridge-v2.1.0.dmg attached

Find the draft release on the Releases page, edit the notes if you want, then click Publish release.

You can also trigger the workflow from a terminal:

gh workflow run release.yml -f version=2.1.0
gh run watch  # follow the build

The release workflow uses bump-my-version under the hood (file list in pyproject.toml) and prepends each new release section to CHANGELOG.md via scripts/update_changelog.py. The changelog entries are auto-generated from the pull requests merged since the previous tag using GitHub's release-notes API.

Original Linux implementation

This project began as a Linux/ALSA application. The pre-port code is preserved in git history at commit 33d8e36 and any earlier ancestor. To run the Linux version, check out that commit: git checkout 33d8e36. The macOS port is the only thing actively developed from v2.0.0 onwards.

License

See LICENSE.

About

macOS menu bar app that forwards Ableton Link tempo to a MIDI clock output. Sync hardware sequencers (Novation Circuit Tracks, drum machines, etc.) to djay Pro, Mixxx, Live, Logic, or Rekordbox in real time. Pure Python, packaged as .dmg.

Topics

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors

Languages

  • Python 95.7%
  • Shell 4.3%