Programmatic DJ Mixing Tools

Research into tools and libraries that can execute a DJ mix from written instructions — loading tracks, time-stretching, beat-matching, applying EQ crossfades, and rendering a continuous output file.

Links: DJ Set 1, Set Mastering Pipeline, Camelot From YouTube, DJ EQ Blending Technique, Crossover Calibration


The Use Case

We have a detailed markdown document describing an 11-track DJ set with:

Goal: A tool that reads these instructions and executes the mix automatically, producing a continuous WAV/FLAC file.

Requirements Checklist

Requirement Description
Load tracks Read multiple audio files (WAV, FLAC, MP3)
Time-stretch Change tempo without pitch shift (e.g., 120 BPM -> 123)
Cue points Start playback at bar X, end at bar Y
Crossfade with EQ Overlap two tracks with independent EQ control per track
Gain staging Per-track volume adjustments
Output Render a single continuous audio file

Category 1: Python Libraries (Build-It-Yourself Stack)

The most flexible approach: assemble a pipeline from individual Python libraries. This gives maximum control over every parameter but requires writing the orchestration code yourself.

Core Stack Recommendation

librosa          — BPM detection, beat tracking, audio analysis
pyrubberband     — High-quality time-stretching (wraps Rubber Band Library)
pedalboard       — EQ, filtering, compression, gain (Spotify's library, wraps JUCE)
soundfile        — High-quality audio I/O (WAV, FLAC, OGG)
numpy            — Array math for mixing/overlaying signals
scipy.signal     — Biquad filters, Butterworth EQ (if not using pedalboard)
pydub            — Simple crossfades, format conversion, quick prototyping

Library-by-Library Assessment

librosa

pyrubberband

pedalboard (Spotify)

pydub

soundfile

scipy.signal

Proposed Python Pipeline Architecture

[DJ Set Markdown/JSON]
    |
    v
[Parser] — Extract per-track cue points, BPM targets, overlap bars, EQ notes, gain values
    |
    v
[For each track:]
    |-- soundfile.read() → numpy array
    |-- librosa.beat.beat_track() → beat/bar positions (or use pre-computed from Camelot)
    |-- pyrubberband.time_stretch() or pedalboard.time_stretch() → match target BPM
    |-- Trim to cue-in / cue-out bar positions
    |
    v
[Transition Engine:]
    |-- For each transition:
    |   |-- Get outgoing track's tail (N bars)
    |   |-- Get incoming track's head (N bars)
    |   |-- Apply EQ to outgoing (e.g., pedalboard.HighpassFilter to cut lows)
    |   |-- Apply EQ to incoming (e.g., fade in lows gradually)
    |   |-- Apply gain envelopes (linear or equal-power crossfade)
    |   |-- Sum the overlapping audio (numpy addition)
    |
    v
[Concatenation] — Join all sections: solo portions + crossfaded overlaps
    |
    v
[Output] — soundfile.write() → WAV/FLAC

Estimated Development Effort


Category 2: Dedicated DJ Automation Tools (Closest to Turnkey)

pyCrossfade ★ MOST RELEVANT

MixingBear + AudioOwl

Mix Machine

Automix (MZehren)


Category 3: DAW Scripting

DawDreamer ★ STRONGEST DAW OPTION

Reaper + ReaScript

Ableton Live + Python


Category 4: CLI Tools

Rubber Band CLI

FFmpeg

SoX (Sound eXchange)


Category 5: Open Source DJ Software with Scripting

Mixxx

DJ.Studio


Recommendation Matrix

Approach Time-Stretch EQ Crossfade Programmatic Quality Effort Best For
DawDreamer Yes (Rubber Band) Yes (VST3 + built-in) Fully (Python) Professional Medium Full pipeline in one tool
Python Stack (librosa + pyrubberband + pedalboard) Yes (Rubber Band) Yes (pedalboard) Fully (Python) Professional Medium-High Maximum flexibility
pyCrossfade (modified) Yes (per-bar) Yes Mostly (needs wrapping) Good Low-Medium Quick prototype
Reaper + ReaScript Yes (built-in) Yes (ReaEQ) Mostly (needs Reaper) Professional Medium If you use Reaper already
FFmpeg chain Adequate Yes (filters) CLI scripting Adequate Medium Quick and dirty
Mixxx Auto DJ Yes Yes Partially Good Low Real-time only

Top Recommendations for DJ Set 1

Recommendation 1: DawDreamer (Best Single Tool)

DawDreamer can do everything we need in a single Python script:

This is essentially “script an Ableton session in Python.” The Camelot analysis data maps directly to DawDreamer’s API.

Recommendation 2: Custom Python Stack (Most Flexible)

If DawDreamer proves too opaque or its audio graph model doesn’t fit:

import soundfile as sf
import pyrubberband as pyrb
from pedalboard import Pedalboard, HighpassFilter, LowpassFilter, LowShelfFilter, Gain
import numpy as np
import librosa

This gives you explicit control over every sample. Pedalboard handles EQ and effects with professional quality. pyrubberband handles time-stretching. numpy handles the mixing math. More code but fewer abstractions.

Recommendation 3: pyCrossfade as Starting Point (Fastest to Prototype)

Fork pyCrossfade and modify it to:

  1. Accept pre-computed beat data from Camelot (skip the slow madmom analysis)
  2. Chain 11 transitions sequentially
  3. Add per-transition EQ parameters from our markdown spec

This gets a working prototype fastest, but may hit limitations for complex transitions (clean cuts, percussive bridges, the “HARD” transition 9->10).


Integration with Existing Projects

Data Flow: Camelot -> Mix Engine -> Mastering

[Camelot From YouTube]
    |-- analysis_cache.json (BPM, beats, bars, keys, events per track)
    |
    v
[DJ Set 1 README.md]
    |-- Human-curated mix instructions (cue points, overlaps, EQ notes)
    |
    v
[Mix Engine] (DawDreamer or Python Stack — THIS RESEARCH)
    |-- Parse instructions
    |-- Time-stretch tracks to target BPMs
    |-- Apply cue points (bar X to bar Y)
    |-- Execute crossfades with EQ
    |-- Gain staging
    |-- Render continuous mix
    |
    v
[dj-set-1-mix.wav]
    |
    v
[Set Mastering Pipeline]
    |-- Structure-aware mastering (Dolby.io API, Ozone, or custom)
    |-- Output: dj-set-1-mastered.wav

The mix engine is the missing middle piece between Camelot’s analysis and the mastering pipeline.


Decision (2026-02-20)

Chosen approach: Recommendation 2 — Custom Python Stack. Implemented as CyborgDJ.

Rationale: Each library has a simple API, crossfade logic is built from scratch (full control over every sample), and the orchestration code IS the project. DawDreamer remains a fallback if the individual tools give trouble.

Stack: soundfile (I/O) + librosa (beat detection) + pyrubberband (time-stretch) + pedalboard (EQ/effects) + numpy (mixing math).

Next Steps


2026-07-22 Revision — what superseded what

Deep-research pass (6 angles, 25 sources, adversarial verification: 10 of 25 claims confirmed, 15 refuted). The low confirmation rate is the headline — treat this section’s unlisted topics as open, not answered.

Separation — the Demucs line was superseded

The band-split RoFormer family (BS-RoFormer / Mel-RoFormer, ByteDance SAMI) beats the Demucs line by ~2–3 dB average SDR on MUSDB18-HQ (BS-RoFormer 9.80–10.02 no-extra-data, 11.99 with; HTDemucs 7.52 no-extra-data, deployed htdemucs_ft ~9.00). But ByteDance released neither code nor weights — every usable implementation is a community reimplementation, and reproductions land materially below the paper figure. Budget for a gap between published SDR and what runs.

The binding constraint for this project: everything outside drums/bass/vocals separates far worse. The catch-all “other” stem sits at 8.7–9.0 dB across every top model vs 14+ dB for bass and drums; purpose-built guitar (~9.0) and piano (~7.8) models do no better. Prog/trance is overwhelmingly “other” content — pads, leads, arps. This confirms the pro-DJ intuition that melodic dance tracks separate badly, and it is a model-quality ceiling, not a stem-definition artifact.

Consequence: use stems to discover, not to render. Bass and drum detection survives poor separation; soloed melodic stems do not.

Verified tooling (checked directly 2026-07-22, not via the research pass)

Tool License Last push Role
audio-separator 0.44.5 MIT 2026-07-20 The separation answer. pip, Py≥3.10, MDX/VR/MDXC-RoFormer + htdemucs_6s (guitar/piano), chunked to avoid OOM
pyrekordbox MIT 2026-07-20 Reads Rekordbox master.db — grids in, not just XML out
Music-Source-Separation-Training MIT 2026-07-12 RoFormer weights/training
beat_this MIT 2026-05-28 Beats + downbeats; preferred over All-In-One on maintenance
madmom BSD code / CC BY-NC-SA models 2026-03-20 ⚠️ models are NonCommercial — see below
all-in-one MIT 2024-05-09 Joint beats+downbeats+segments, but 2 yrs stale, NATTEN-from-source on Windows, pop song-form labels

madmom licensing trap (LICENSE read directly): source is 3-clause BSD, but data/model files are CC BY-NC-SA 4.0 — “if you want to include any of these files … in a commercial product, please contact Gerhard Widmer.” Fine for personal use; blocking for anything licensed or sold. GitHub reports NOASSERTION for exactly this reason. beat_this is MIT and avoids it.

madmom install reality: pip install git+https://github.com/CPJKU/madmom.git only. PyPI’s newest wheel is 0.16.1 from 2018; the numpy/Py3.10+ fixes live on main and were never released. Zipball installs fail on a missing submodule.

Cue-point detection is NOT solved — and there is no mix-quality metric

That last point is the strategic one: a rendered-output critic is novel work, not a reinvention. The field is immature, and the two assets needed to build one — genre-matched beat-grid ground truth and genre-matched preference labels — are things a working DJ has and researchers don’t.

Does the 2026-02-20 decision still hold?

Yes, with one swap. The custom Python stack remains right; the analysis front-end changes: librosa stays as the DSP/feature layer (load, STFT, CQT chroma, third-octave), and the eviction is surgical — beat, downbeat and structure detection only, plus audio-separator in place of raw demucs. DawDreamer remains an unexercised fallback.

Still open (do not read absence as absence)


Tags