Skip to main content

DJ playlist optimizer using Google OR-Tools for harmonic mixing and BPM matching

Project description

🎧 djkr8 - Playlist Optimizer for rekordbox

Optimize rekordbox playlists for harmonic mixing using Google OR-Tools constraint programming.

Features

  • Longest Path Optimization: Finds the maximum number of tracks that can be mixed together
  • Energy Flow Management: Enforces non-decreasing energy progression with max +1 increase per transition (1-5 range)
  • 🎵 Harmonic Mixing: Uses the Camelot Wheel system for key compatibility
  • 🚀 Energy Boost Transitions: Strategic +2 hour jumps (5A→7A) for crowd excitement, used sparingly (max 3 per set)
  • 📊 Transition Quality Scoring: Intelligently weights transitions by harmonic quality (1.0 = perfect, 0.6 = energy boost)
  • 🎧 Rekordbox Integration: Read playlists directly from your local Rekordbox 6/7 database (tested with v7.2.8)
  • 🔊 BPM Matching: Supports direct, halftime, and doubletime BPM compatibility
  • ⚙️ Configurable Strictness: STRICT, MODERATE, or RELAXED harmonic compatibility levels
  • 📤 Rekordbox Export: Export results to Rekordbox XML or write directly to the Rekordbox database
  • 🚀 Fast: Powered by Google OR-Tools CP-SAT solver (award-winning constraint solver)
  • 📦 SDK + CLI: Use as a Python library or command-line tool

Installation

uv add djkr8

Or with pip:

pip install djkr8

Quick Start

SDK Usage

from djkr8 import PlaylistOptimizer, Track, HarmonicLevel

tracks = [
    Track(id="track_001", key="8A", bpm=128),
    Track(id="track_002", key="8B", bpm=130),
    Track(id="track_003", key="9A", bpm=125),
]

optimizer = PlaylistOptimizer(
    bpm_tolerance=10,
    allow_halftime_bpm=True,
    max_violation_pct=0.10,
    harmonic_level=HarmonicLevel.STRICT,
)

result = optimizer.optimize(tracks)

for i, track in enumerate(result.playlist, 1):
    print(f"{i}. {track.id} ({track.key}, {track.bpm} BPM)")

CLI Usage

# Basic usage
djkr8 tracks.json

# With custom settings
djkr8 tracks.json --bpm-tolerance 8 --harmonic-level moderate

# Energy flow management
djkr8 tracks.json --energy-weight 5.0      # Prioritize higher energy tracks
djkr8 tracks.json --allow-energy-drops    # Disable strict non-decreasing energy constraint

# Save results to JSON
djkr8 tracks.json --output result.json

# Use with Rekordbox (v6/v7)
krate --rekordbox                                      # List playlists
krate --rekordbox --playlist "Techno"                  # Optimize specific playlist
krate --rekordbox --playlist "Techno" --output r.xml   # Export to Rekordbox XML
krate --rekordbox --playlist "Techno" --write-to-db    # Write directly to Rekordbox DB

# Enable verbose logging
djkr8 tracks.json -v          # INFO level
djkr8 tracks.json -vv         # DEBUG level

Rekordbox Integration

The tool provides two ways to save your optimized playlists back to Rekordbox:

1. XML Export (Recommended)

Export the results to an XML file that can be imported into Rekordbox:

krate --rekordbox --playlist "My Playlist" --output optimized.xml

In Rekordbox:

  1. Go to File > Import > Import Playlist
  2. Select optimized.xml
  3. The playlist will appear in the ROOT folder (e.g., My Playlist_20260115_120000)

2. Direct Database Write (Advanced)

Write the optimized playlist directly to your Rekordbox 6 database:

krate --rekordbox --playlist "My Playlist" --write-to-db

⚠️ WARNING:

  • Close Rekordbox before running this command.
  • This modifies your master.db file directly.
  • Backup your database before using this feature.

Input Format

JSON file with tracks containing id, key (Camelot notation), and bpm:

{
  "tracks": [
    {"id": "track_001", "key": "8A", "bpm": 128},
    {"id": "track_002", "key": "8B", "bpm": 130},
    {"id": "track_003", "key": "9A", "bpm": 125}
  ]
}

How It Works

1. BPM Compatibility

Adjacent tracks must have compatible BPMs within tolerance:

Track A Track B Tolerance Match? Reason
128 BPM 130 BPM ±10 Direct (diff = 2)
128 BPM 64 BPM ±10 Half-time (128 = 64×2)
75 BPM 150 BPM ±10 Double-time (75×2 = 150)
128 BPM 100 BPM ±10 Too far

2. Harmonic Mixing (Camelot Wheel)

Harmonic compatibility levels:

STRICT (default):

  • Same key (8A → 8A)
  • ±1 hour same letter (8A → 7A, 9A)
  • Same hour different letter (8A → 8B)

MODERATE:

  • Above + ±1 hour different letter (8A → 9B, 7B)

RELAXED:

  • Above + ±3 hours (8A → 5A, 11A)

3. Optimization Goal

Maximize playlist length while optimizing transition quality and respecting harmonic constraints.

Multi-Objective Optimization:

  • Primary: Maximize playlist length (more tracks = better)
  • Secondary: Maximize transition quality scores (smoother mixes = better)
  • Constraints: Energy flow, harmonic violations, energy boosts

Configuration Options

Parameter Default Description
bpm_tolerance 10.0 Maximum BPM difference for direct match
allow_halftime_bpm True Enable half/double-time matching
max_violation_pct 0.10 Max percentage of non-harmonic transitions
harmonic_level STRICT Harmonic compatibility strictness
enforce_energy_flow True Enforce non-decreasing energy with max +1 increase (next >= current and next - current <= 1)
max_energy_boosts 3 Maximum number of energy boost transitions (+2 hours on Camelot wheel) per playlist
transition_quality_weight 10.0 Weight for transition quality in objective function (higher = prefer quality over length)
time_limit_seconds 60.0 Solver time limit

Advanced Features

Energy Boost Mixing

Based on Mixed In Key's Energy Boost technique, you can use strategic harmonic jumps to add excitement:

+2 Hours (Energy Boost): Jump forward 2 hours on the Camelot wheel

# Example: 5A → 7A
# Gives a quick burst of energy to wake up the dancefloor
optimizer = PlaylistOptimizer(max_energy_boosts=3)  # Allow up to 3 boosts

-5 Hours (Armin Variation): Jump backward 5 hours

# Example: 12A → 7A
# Used by Armin Van Buuren and Skrillex for dramatic energy spikes

Best Practices (from professional DJ analysis):

  • Use energy boosts sparingly (every 20-30 minutes, not constantly)
  • Top DJs average 2-3 energy boosts per set
  • Combine with energy level increases for maximum impact
  • Default limit: max_energy_boosts=3 per playlist

Transition Quality Scoring

The optimizer now scores each transition by harmonic quality:

Transition Type Quality Score Example
Perfect match (same key) 1.0 8A → 8A
±1 hour, same letter 0.95 8A → 9A
Relative major/minor 0.9 8A → 8B
±1 hour, different letter 0.8 8A → 9B
Energy Boost (+2) 0.6 5A → 7A
Armin Variation (-5) 0.5 12A → 7A
Mood shift (±3 hours) 0.4 8A → 5A
Clash 0.0 8A → 2B

Quality scores are weighted in the objective function, so the solver prefers smoother transitions when possible.

Examples

See examples/ directory:

  • example_tracks.json - Sample input data
  • sdk_usage.py - SDK usage demonstration
  • logging_example.py - Logging configuration example

Development

# Clone repository
git clone https://github.com/yourusername/djkr8
cd krate

# Install with dev dependencies
uv sync --dev

# Install pre-commit hooks
uv run pre-commit install
uv run pre-commit install --hook-type commit-msg

# Run tests
uv run pytest

# Lint and format
uv run ruff check          # Check for issues
uv run ruff check --fix    # Auto-fix issues
uv run ruff format         # Format code

# Run pre-commit on all files
uv run pre-commit run --all-files

# Run example
uv run python examples/sdk_usage.py

How the Solver Works

The optimizer uses Google OR-Tools CP-SAT solver with:

  1. Binary Variables: included[i] = track i is in playlist
  2. Edge Variables: edge[i,j] = track j follows track i
  3. Circuit Constraint: AddCircuit ensures valid track ordering
  4. BPM Constraints: Only create edges between BPM-compatible tracks
  5. Harmonic Soft Constraints: Penalize non-harmonic transitions
  6. Objective: Maximize sum(included)

License

MIT

Credits

Built with:

  • Google OR-Tools - Constraint programming solver
  • pyrekordbox - Rekordbox database access
  • Camelot Wheel system by Mark Davis (Mixed In Key)

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

djkr8-1.5.0.tar.gz (20.6 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

djkr8-1.5.0-py3-none-any.whl (24.4 kB view details)

Uploaded Python 3

File details

Details for the file djkr8-1.5.0.tar.gz.

File metadata

  • Download URL: djkr8-1.5.0.tar.gz
  • Upload date:
  • Size: 20.6 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for djkr8-1.5.0.tar.gz
Algorithm Hash digest
SHA256 69fc258c0552c914a76aa8783e24e151f7b3be29efef4b24c87779a4bebd23a3
MD5 bc298b2dbc14bb7df97aeaee2e7b2c98
BLAKE2b-256 310393a03f852492266443dff455ba903b4a6da83dcd477c5486974a7abadc6d

See more details on using hashes here.

Provenance

The following attestation bundles were made for djkr8-1.5.0.tar.gz:

Publisher: release.yml on schoi80/djkr8

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file djkr8-1.5.0-py3-none-any.whl.

File metadata

  • Download URL: djkr8-1.5.0-py3-none-any.whl
  • Upload date:
  • Size: 24.4 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for djkr8-1.5.0-py3-none-any.whl
Algorithm Hash digest
SHA256 660747662b65364afa547282cf6e005956ded834d6e9a5e48b03888b07da39cc
MD5 2cebf4880f6c382d578966c1241d4f9f
BLAKE2b-256 30e498fa0d76f1294d9e1b091b6aeb6bc9e2f803f3bd0ad4630cc0e0dda2f09f

See more details on using hashes here.

Provenance

The following attestation bundles were made for djkr8-1.5.0-py3-none-any.whl:

Publisher: release.yml on schoi80/djkr8

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page