惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

K
KPMG report finds enterprise disconnect between AI and its ROI | CIO
AI
AI
Exploit-DB.com RSS Feed
Exploit-DB.com RSS Feed
博客园 - 三生石上(FineUI控件)
Google Online Security Blog
Google Online Security Blog
N
News and Events Feed by Topic
Microsoft Security Blog
Microsoft Security Blog
AWS News Blog
AWS News Blog
S
Securelist
Schneier on Security
Schneier on Security
MyScale Blog
MyScale Blog
W
WeLiveSecurity
Hacker News: Ask HN
Hacker News: Ask HN
爱范儿
爱范儿
阮一峰的网络日志
阮一峰的网络日志
Project Zero
Project Zero
Recent Commits to openclaw:main
Recent Commits to openclaw:main
P
Proofpoint News Feed
I
Intezer
人人都是产品经理
人人都是产品经理
The Register - Security
The Register - Security
T
The Exploit Database - CXSecurity.com
宝玉的分享
宝玉的分享
L
LINUX DO - 热门话题
月光博客
月光博客
C
CERT Recently Published Vulnerability Notes
F
Fortinet All Blogs
GbyAI
GbyAI
博客园 - 聂微东
F
Full Disclosure
L
LINUX DO - 最新话题
T
The Blog of Author Tim Ferriss
Engineering at Meta
Engineering at Meta
IT之家
IT之家
Scott Helme
Scott Helme
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
S
Security Affairs
I
InfoQ
The Hacker News
The Hacker News
雷峰网
雷峰网
Hacker News - Newest:
Hacker News - Newest: "LLM"
V2EX - 技术
V2EX - 技术
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
SecWiki News
SecWiki News
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
大猫的无限游戏
大猫的无限游戏
博客园_首页
B
Blog RSS Feed
S
Secure Thoughts
A
About on SuperTechFans

Lobsters

CIFSwitch: a non-universal Linux local root vulnerability RIPE NCC session fixation: poaching logins with an Atlas probe GNOME 2.20 but its Web Components Agentic Search for Context Engineering – Leonie Monigatti Garnix is shutting down [not OC] akashina.tngl.sh/jjc Concerning Emacs (and Jazz) Nitpicking the shell history scene in ‘Tron: Legacy’ What's cooking on SourceHut? Q2 2026 The tenth OpenPGP email summit Package managers that package package managers Clojure on Fennel part three: parsing WordPress at 23 Finding Miscompiles for Fun, Not Profit GitHub - creusot-rs/creusot: Creusot helps you prove your Rust code is correct. Announcing Rust 1.96.0 | Rust Blog A Love Letter to Neovim sqlite AGENTS.md Am I a Bad Friend? CSS vs. JavaScript • Josh W. Comeau Erlang Ecosystem Foundation - Supporting the BEAM community A brief note about slot access cost in Common Lisp Keyboard latency probe Rethinking the GNOME clipboard issues Back to the Building Blocks’ Building Blocks Tech Notes: Theseus: translating win32 to wasm Fast is better than slow Content-addressed Rust builds (or, what kache actually caches) Intent to Prototype: Embedding API Canada’s Bill C-22 and the security cost of collecting more data 5 PostgreSQL locking behaviors that trip people up okmij.org Stop advertising in your commits! | AksDev GitHub - mplsllc/macsurf: A modern web browser for Classic Mac OS 9 PowerPC. Real CSS3, ES5 JavaScript, native HTTPS — built with CodeWarrior on the Carbon API. Introducing DoomBench - Can Your Data Stack Run DOOM? What are some of your favourite developer tools? Building a Scalable Ingestion Pipeline with Temporal (Part 1) Converting shallow Git bundles into normal repositories Are you a member of any professional associations? What is a harmonic? An interactive comic about additive synthesis How Virtual Tables Work in the Itanium C++ ABI Using SwiftUI to Build a Mac-assed App in 2026 Rust (and Slint) on a jailbroken Kindle. ~jack/lambda-on-lambda - Serverless Haskell on AWS - sourcehut git Human proof for FOSS contributions Extremely simple internet radio controlled via IRC Announcing BABLR Splitting Konsole views from Helix to run tools | AksDev GitHub - yugr/rust-slides Serving files over HTTP three ways: synchronous, epoll, and io_uring update docs with information about building with build.py (#979) · astral-sh/python-build-standalone@c9c40c5 A Simple Makefile Tutorial On C extensions, portability, and alternative compilers Switching to Colemak | Pedro Alves Just How Bad Was The Intel IAPX432? Nix's Substituter List Is Not a Routing Table Accelerating copy_if using SIMD Lambda on Lambda: Serverless Haskell on AWS | Blog Announcing feed-repeat v1.0 Scaling Akvorado BMP RIB with sharding EYG news: A host of CLI improvements, new guides and new effects The social contract of writing JS Crossword C array types are weird; and related topics Flatpak will depend on systemd – OSnews Migrating from Go to Rust | corrode Rust Consulting A portentous reunion Vivado Licensing Options How my minimal, memory-safe Go rsync steers clear of vulnerabilities the entropy layer of a wavelet codec, on its own GitHub - nferhat/fht-compositor: A dynamic tiling Wayland compositor. Debian SE Linux and PinTheft Does bulk memmove speed up std::remove_if? (No.) 声明式部分更新 | Blog | Chrome for Developers Fully in-browser container builds Dianne Skoll's Web Site - Remind The Architecture of Open Source Applications (Volume 1)Berkeley DB Pardon MIE? - ironPeak Blog “Long-Term Support” doesn’t mean what you think Jira IS Turing-Complete May I recommend thinking of Emacs as your Fortress of Solitude hershey Floodgap Gopher-HTTP gateway gopher://thelambdalab.xyz/1cuneiforth/ HP QuickWeb, Singular And Pointless That one time I used Go panics for flow control A new suite of modern tools coming for editing and publishing RFCs From the Tabletop… The Digital Antiquarian Building a Host-Tuned GCC to Make GCC Compile Faster Are we self-sovereign PKI yet? Claw Patrol: an open-source security firewall for agents | Deno Revised^7 Report on Scheme, Large: Procedural Fascicle Draft is now public A Network Allow-List Won't Stop Exfiltration — André Graf From AFSK to Goertzel – µArt.cz Software For My New Home Server Introducing Neptune: Direct3D virtualization for QEMU AI Agent Bankrupted Their Operator While Trying to Scan DN42 - Lan Tian @ Blog mimalloc: A new, high-performance, scalable memory allocator for the modern era Making wl_shm fast The Soul of Maintaining a New Machine - Third Draft | Books in Progress What is Git made of?
Syncing lights with music: Marzullo's algorithm in the DJ booth
Aaron Janse · 2026-06-01 · via Lobsters

One of my favorite side projects is automatically syncing lights with music at house parties. I built a system to do this back in 2022-23, and it’s since been used at dozens of small events.

It’s a fun intersection of technology and non-technical topics, so I finally put aside time to write about it as a short series of posts. In this inaugural post I’ll talk about how we can keep in sync with a live DJ, even if they skip parts of a song or change tempos.

I wanted my lighting system to be fully automatic and follow the structure of a song and build up to a drop, like you see at concerts. Ideally I could hit play on Spotify, Djay Pro (auto-DJing), or Rekordbox (live DJing) and some colorful lights would start doing their thing. This requires knowing the song that’s currently playing and where we are in the song, so we can plan a light show for the entire song.1

I wanted to extract this info (the current track and seek position) from the music software directly, rather than attempting shenanigans with a microphone (consider remixes and repeated choruses)2. How do we do this?

Spotify is the easiest platform to integrate with because we can query its internal state using AppleScript3.

But what about Rekordbox and Djay Pro? A lot of reverse engineering work has been done on Rekordbox, including extracting playback state from DJ hardware network packets or process memory dumps on Windows. But these approaches have a huge number of limitations.

I settled on screen-recording Rekordbox and using OCR to extract info from its UI. This is terrible, yet it worked very well and was easiest to set up on the laptop used for DJing. I did a similar thing for Djay Pro, where I was able to use macOS accessibility tools instead of OCR.

For example, from the following screenshot we’d extract the “00:30.9” seek time, “124.0” playback speed, track title, and the artist4:

We need 10ms of precision for the seek time to make lights look in sync, yet UIs often truncate seek time to 0.1s or 1s. How do we work around this?

Because the current seek position is a moving target, we’ll think in terms of the track’s wall clock start time and its playback speed. We’ll also quantify uncertainty by thinking in terms of intervals.

One approach is to average now-truncatedSeek across a bunch of screenshots. If we record in a hot loop5 and avoid aliasing, this average will be close to the true song start time, offset by 0.05s or 0.5s depending on truncation. I used the averaging approach for a while and it worked well enough, but it made it hard to tell if latency bugs came from the audio stack, the lights, the song analysis, or the seek position estimate being wrong.

Fortunately there’s a more robust approach. In each screenshot, the truncated seek time implies an interval of precise seek times, in turn implying an interval of track start times. If we take a bunch of screenshots, we can look at where these intervals overlap, giving us a lot more precision:

This is essentially Marzullo’s algorithm, which was created for “estimating accurate times from a number of noisy time sources” and is used by NTP.

The algorithm lets us do some cool things:

  • We can intentionally time our screenshots to bisect our start time estimate interval, getting us to 1ms accuracy (we do this by screenshotting when we think the truncated time will tick, and checking if we over/under-shot)

  • OCR errors are a non-issue, because they’re out-voted by accurate reads

  • Playback speed changes are handled naturally if we look for the most popular (tempo, start time interval) intersection instead of only thinking about start time

  • We can write better heuristics to detect the DJ skipping part of a song. For example, we can quickly detect the DJ skipping part of a song by checking if recent screenshots’ intervals all agree with each other but all disagree with previous screenshots’ intervals

Migrating to this approach let me trust the seek position estimate and freed my mind to think about other things. That’s everything I could ask for in a playback state tracking implementation.

If people find this interesting, I’ll write more about this project in follow-up posts. Some possible topics:

  • How should we plan light effects? How about DJ transitions? Why use markov chains?

  • How can we use various hardware protocols to control lights? (IR remotes, DMX, ws2812b)

  • How can I abuse LED strips to get more than 256^3 colors?

Discussion about this post

Ready for more?