Skip to content

Latest commit

 

History

6 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

link-audio-osc (LinkOSC)

Receive Ableton Link Audio or a macOS audio input, analyze it, and send OSC — a macOS utility for audio-reactive visuals.

Release License: GPL-2.0-or-later Platform

📖 User Manual · ユーザーマニュアル (日本語) · OSC spec for receiver builders / AI assistants · Monitor output design

Offline sibling: vjbake bakes the same analysis (identical source & calibration) from audio files into 60 fps JSON + a pixel data video — build a show against vjbake data, run it live against LinkOSC.

LinkOSC main window

LinkOSC joins an Ableton Link session, subscribes to a Link Audio channel (Live 12.4+ publishes its tracks/Main natively — no BlackHole or virtual audio driver needed) or a selected macOS input device, runs a realtime analysis chain, and streams the results as OSC to up to 4 destinations. Beat position comes from the Link timeline. A dev mode loops a bundled WAV + MIDI at a fixed BPM so you can build OSC receivers without Live running.

Running it standalone (no Live, no other Link peers)? It also receives OSC on UDP port 9100 by default — /bpm sets the tempo and /beat/reset re-aligns the beat. See OSC control input.

Built with SwiftUI + Metal + Accelerate (vDSP) + the official Link SDK (abl_link C API). Apple Silicon, macOS 13+.

OSC output

Building a receiver (or asking an AI to)? Feed OSC-SPEC.md to your assistant — it is a self-contained, machine-oriented specification of everything below (exact typetags, ranges, calibration, pacing, keepalive rules, JSON summary).

Address Payload Rate
/fft float × 128 (0..1, linear bands 0..Nyquist) 60 fps
/vol float (RMS 0..1) 60 fps
/pfft float × 128 — percussive-only spectrum (HPSS) 60 fps
/pvol float — percussive-only volume 60 fps
/hfft float × 128 — harmonic-only spectrum (HPSS) 60 fps
/hvol float — harmonic-only volume 60 fps
/hpss float harmonic, float percussive (0..1 energies) 60 fps
/novelty float 0..1 (spectral novelty) 60 fps
/chroma float × 12 (pitch classes C..B, max-normalized) 60 fps
/beat int 0,1,2,3 (quarter notes, Link timeline) — off by default, enable with send /beat on change
/attack float strength — fullband onset on detection
/pattack float strength — onset on the HPSS percussive component only on detection
/section float magnitude + float×5 deltas (sub/low/mid/high/perc) at bar heads, on big change
/note int note, int velocity (dev mode, from the MIDI loop) on note-on
/ping int 1 (keepalive) every 500 ms

Checked analyses in the UI are always computed & sent; unchecked ones cost no CPU. /pfft//pvol make it easy to drive effects from drums only — tonal material is filtered out by the HPSS separation, and /pattack fires on percussive onsets only.

OSC control input

For running LinkOSC standalone — no Live, no other Link peers, LinkOSC owning the timeline itself. It listens on a UDP port so another app drives the tempo and the beat. Turn on OSC control in in the Ableton Link section and set the port (default 9100).

Address Payload Effect
/bpm float (or int) BPM, 20–999 Sets the Link tempo
/beat/reset int beat, optional (default 0) Maps "now" to that beat of the bar, re-aligning the /beat count

With no other peers both take effect immediately — that is the intended setup.

Uncheck send /beat only while playing. Standalone, nothing ever starts the Link transport, so it stays stopped and that option would gate /beat off entirely. The Link timeline itself keeps running regardless, so unchecked you get a free-running /beat that /beat/reset re-aligns. (/beat itself is off by default too — turn on send /beat first.)

If you do connect Live or another peer later, both messages still work but change meaning: /bpm moves everyone's tempo, and Link defers /beat/reset to the next matching phase (the next bar head) rather than jumping the shared timeline.

Only f and i arguments are accepted, one message per datagram (no bundles). See OSC-SPEC.md §8 for the full contract. Verify the path end to end with:

LinkOSC.app/Contents/MacOS/LinkOSC --oscintest

Destinations section

Per-destination options: an address-filter preset (All / Streams / Events / Percussive — /ping always sent), an opt-in bundle mode (#bundle packets, chunked ≤1400 B, receiver must unpack), and multicast — set the host to a 239.x.x.x group address (wired LAN recommended; receivers join the group).

Interface pinning: by default OSC leaves via OS routing (Auto — correct for most unicast). The Interface picker pins all output to a specific NIC. This matters when a multicast group must leave a specific port (the OS otherwise emits multicast on the primary interface), or when Wi-Fi and Ethernet share a subnet. Connections are rebuilt automatically on network changes (cable plug/unplug, Wi-Fi switch); if the pinned NIC disappears the app falls back to Auto with a warning and re-pins when it returns. Hover a destination's status dot to see the actual egress path (e.g. via en5 · 10.0.0.23).

Network efficiency: per-frame sends are batched per connection (NWConnection.batch, ~36% lower send-path cost), packets are DSCP-marked as interactive video (Wi-Fi WMM priority), and idle suppression (default on) skips stream messages whose values haven't changed, with a 2 Hz refresh floor — silence costs ~96% fewer packets. /ping and events are never suppressed.

Send pacing: events and small messages go out immediately; the three large spectrum packets (/fft /pfft /hfft, ~670 B each) are staggered into 1 ms slots (+1/+2/+3 ms) instead of bursting in one instant. This avoids receiver-side UDP buffer overruns (single-threaded Max/TouchDesigner patches) and Wi-Fi burst loss; the few-ms skew is imperceptible at 60 fps. Sends are also gated on connection readiness with an in-flight cap — stalled destinations drop packets instead of queueing unboundedly. Verify pacing with ./.build/debug/LinkOSC --pacetest <port>.

Monitor column

Monitoring: the Monitor column has a mute toggle and volume fader for the audible output — they control both the dev-mode WAV playback and a built-in monitor of the received Link Audio stream (jitter-buffered). Local input devices are not played back, preventing microphone feedback. Muting or changing volume never affects analysis or OSC output. Analysis gain has two modes: Auto summarizes each 4-second block (minimum, maximum, median, average and peak), updates once at the block boundary, and holds that gain for the next block. It targets a 0.95 peak, permits brief overshoot up to 1.05, and clamps published analysis values to 0...1; Manual exposes the ×0.1…×8.0 gain fader. The selected mode and manual value are saved. The Monitor header's Adjusted / Raw selector changes only the on-screen spectrum, L/R meters, and history: Adjusted shows the gain-processed signal, while Raw shows the input before analysis gain. OSC output is unchanged.

UI: two-column layout (settings left, monitor right) sized for up to 1280×900 — tall enough that the settings column never scrolls, and shrinkable to 620 pt high on small screens (the left column becomes scrollable). Rendering auto-pauses while the window is fully occluded (zero draw cost in the background; verified by profiler) and each OSC destination row shows a live status dot — gray disabled / orange connecting / green sending / red dropping. Lite mode (switch in the Monitor header) stops all Metal rendering and slows UI refresh to 1 Hz once you're done checking the signal — analysis and OSC output are completely unaffected. /ping 1 is sent every 500 ms as a receiver keepalive.

Analysis chain (lightweight 60 fps ports of flucoma-core ideas)

Analysis section

  • Curves: independent response curves for /fft and /vol (Linear / Sqrt / Log / Pow² / Pow³), also applied to the HPSS variants
  • /attack: spectral flux + adaptive threshold (running median × ratio). Golden presets: Tight / Standard / Smooth
  • /pattack: the same onset detector fed with the HPSS percussive spectrum
  • HPSS: median filtering (temporal → harmonic, spectral → percussive) + Wiener soft masks. Presets Fast(7,17) / Standard(17,31) / Deep(31,63) = (time, freq) kernels
  • /novelty: cosine distance between the mean spectra of the last 8 frames and the 8 before
  • /chroma: 55 Hz–8 kHz bins folded into 12 pitch classes
  • /section: averages a band profile [sub, low, mid, high, percussive] over a configurable judge window after each bar head (1/256, 1/128, 1/64, 1/32, 1/16, 1/8, ¼, ½, 1, or 2 beats; default 1 beat) and compares against recent bar heads. Windows shorter than one 60 fps analysis frame judge on the next frame; longer windows react later but average more audio. sensitivity High/Medium/Low. Fires on overall change or on a strong single-band change (so a kick dropping out of a loud mix is not missed). Negative deltas mean a band disappeared (kick drop → strongly negative sub/perc)
  • Visualizers (Metal): spectrum with harmonic (cyan) / percussive (orange) overlays, L/R + H/P meters, stereo correlation bar, 12-color chroma bars, and an 8-second history graph (vol / novelty / harmonic / percussive + attack / pattack / section markers)

Install

  1. Download LinkOSC-x.y.z.zip from Releases, unzip, move LinkOSC.app anywhere
  2. First launch: the app is ad-hoc signed (not notarized) — right-click → Open, or xattr -dr com.apple.quarantine LinkOSC.app
  3. Allow Local Network access when prompted (required for Link's UDP multicast)
  4. If you select a macOS input device, also allow Microphone access when prompted

Use with Ableton Live 12.4+

Link Audio channel setup

  1. In Live: Settings → Link → Link Audio: On, and turn on the LINK toggle in Live's top bar (if Live's Peers list says "Enable Link to show available peers", Link itself is still off)
  2. In LinkOSC, choose Ableton Link Audio under Audio Input, then pick a channel — Live | Main is the master output. Audio can take a few seconds to start; the channel list re-polls every 2 s and ↻ restarts discovery
  3. Enable OSC destinations (host/port). Everything is saved automatically

To analyze a microphone, audio interface, aggregate device, or virtual device instead, select it from Audio Input → Source. The stable Core Audio device UID is saved. Link can remain enabled so /beat still follows the Link session while audio comes from the selected device. For multi-channel interfaces, choose a non-overlapping stereo pair (Stereo 1–2, Stereo 3–4, …) or an individual input (Mono 1, Mono 2, …) from the Channel menu.

Verify with the bundled monitor: python3 tools/osc_monitor.py 9001

Dev mode

Dev mode

Toggle Dev Mode to work without Live: Link is disabled and a bundled 140 BPM WAV (32 beats) + drum MIDI loop plays through the same analysis → OSC chain, with /beat free-running at the set BPM and /note emitted from the MIDI loop. Use the Bundled menu to switch between dry and effects versions of the loop. The test data is embedded in the app bundle; custom WAV/MIDI paths are saved and fall back to the bundled data if missing. Click Auto BPM to count the loop tempo continuously; it locks after roughly 4–6 seconds, searches only 90–180 BPM, and uses 110–140 BPM as a weak preference.

Build from source

git clone --recursive https://github.com/daitomanabe/link-osc-app
cd link-audio-osc
./build_app.sh        # → dist/LinkOSC.app (release, ad-hoc signed)

Requires macOS 13+ and a Swift 6 toolchain (Command Line Tools are enough). --recursive matters: the Link SDK lives in vendor/link as a git submodule (with its own nested submodules).

CLI diagnostics (debug build: swift build):

./.build/debug/LinkOSC --probe          # show Link peers & Link Audio channels for 10 s
./.build/debug/LinkOSC --publish        # publish a 440 Hz test channel (fake Live)
./.build/debug/LinkOSC --rxtest 9099 Main   # subscribe & report received frames
./.build/debug/LinkOSC --devtest 9099   # dev-mode loop + full analysis self-test
./.build/debug/LinkOSC --selftest 9099  # FFT calibration / Link timeline / OSC encoding
./.build/debug/LinkOSC --ifacetest      # interface pinning: enumerate NICs, prove routing constraint, multicast egress
./.build/debug/LinkOSC --inputtest --capture  # enumerate inputs; also capture when permission is already granted
./.build/debug/LinkOSC --autogaintest   # automatic-gain block hold / statistics / silence regression
./.build/debug/LinkOSC --docshot out.png 12   # self-screenshot of the live UI (regenerates the docs images)

Runtime lifecycle and stall diagnostics are written as JSON Lines to ~/Library/Logs/LinkOSC/runtime.log (rotated at 512 KB; previous file is runtime.log.1). Audio samples and per-frame OSC values are not logged.

License

GPL-2.0-or-later. This project links against the Ableton Link SDK (including Link Audio and the abl_link C extension), which Ableton distributes under GPLv2+; this repository is licensed under the same terms — see LICENSE. If you need to use Link in a proprietary application, Ableton offers separate licensing (link-devs@ableton.com). The bundled test loops (loop-test.wav, loop-test-effects.wav) and MIDI (loop-test.mid) are provided under the repository license. Test media copyright: Copyright (c) 2026 Daito Manabe


日本語メモ

  • 構成: Ableton Link (beat) + Link Audio (audio) を受信 → vDSP で解析 → OSC 送信。 BlackHole 等の仮想オーディオドライバは不要(Live 12.4+ がネイティブでチャンネルを公開)
  • Live 側設定: 設定 → Link → Link Audio「On」と、メイン画面左上の LINK トグルの 両方が必要(設定画面の Peers 欄に "Enable Link to show available peers" と出ている間は Link 本体が OFF)
  • 開発モード: Live なしで内蔵 WAV+MIDI(140BPM・32拍、dry/effects)をループし、 同じ解析チェーンで OSC を送信。/note は MIDI ノートオンから。Auto BPM は 90〜180 BPM の範囲を約4〜6秒で推定(110〜140 BPMを弱く優先)
  • チェック連動: 解析トグルにチェックが付いているものだけが計算・送信・可視化される
  • /pfft /pvol /pattack: HPSS で分離した percussive 成分だけの spectrum / volume / onset。ドラムにだけ反応するエフェクトを作るときに便利
  • 設定はすべて自動保存(UserDefaults)

About

Receive Ableton Link Audio, analyze (FFT / HPSS / onsets / chroma / novelty / sections), and send OSC — a macOS utility for audio-reactive visuals

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages