Skip to main content

Time-stretch drum breaks to target BPMs with automatic tempo detection

Project description

breaks-machine

Time-stretch drum breaks to target BPMs while preserving transient quality.

Perfect for preparing drum breaks for hardware samplers, live performance, or production workflows where you need breaks at specific tempos.

Features

  • Automatic BPM Detection: Intelligently detects tempo from filename patterns or uses librosa for audio analysis
  • Multiple Target Modes: Stretch to single BPM, multiple targets, or ranges with custom steps
  • Batch Processing: Process entire directories of breaks in one command
  • High-Quality Stretching: Uses Rubberband with crispness=5 optimized for transient preservation
  • Format Conversion: Optional sample rate, bit depth, and channel conversion
  • Smart Detection: Multi-strategy BPM detection with subdivision correction for complex breakbeats

Requirements

System Dependencies

Rubberband is required for time-stretching:

macOS:

brew install rubberband

Ubuntu/Debian:

sudo apt-get install rubberband-cli libsndfile1 ffmpeg

Windows: Download Rubberband from https://breakfastquay.com/rubberband/ and add to PATH.

Python

Python 3.13+ required.

Installation

With uv (recommended):

uv tool install breaks-machine

With pip:

pip install breaks-machine

From source:

git clone https://github.com/yourusername/breaks-machine.git
cd breaks-machine
uv sync

Quick Start

Single File, Single Target

Stretch a break to 140 BPM:

breaks-machine stretch amen_170.wav --target 140

Output: output/amen_170/amen_170_140bpm.wav

Multiple Targets

Create versions at different BPMs:

breaks-machine stretch amen_170.wav --targets 90,120,140,160

Output:

output/amen_170/
├── amen_170_90bpm.wav
├── amen_170_120bpm.wav
├── amen_170_140bpm.wav
└── amen_170_160bpm.wav

BPM Range

Generate versions across a range:

breaks-machine stretch break.wav --range 80-160 --step 10

Creates versions at 80, 90, 100, ..., 160 BPM.

Batch Processing

Process an entire directory:

breaks-machine stretch ./breaks/ --target 140 --output ./processed/

With Manual BPM Override

If auto-detection fails or you know the correct tempo:

breaks-machine stretch break.wav --bpm 175 --target 140

CLI Reference

breaks-machine stretch INPUT_PATH [OPTIONS]

Arguments

  • INPUT_PATH: Path to audio file (.wav, .flac) or directory containing audio files

Options

Target Specification (required, choose one):

  • -t, --target BPM: Single target BPM
  • --targets BPM,BPM,...: Comma-separated target BPMs
  • -r, --range START-END: BPM range with optional step

BPM Detection:

  • -b, --bpm BPM: Manual source BPM override
  • -w, --warn: Warn if detected BPM differs from filename

Output:

  • -o, --output DIR: Output directory (default: ./output)

Format Conversion:

  • --sample-rate HZ: Target sample rate (e.g., 44100, 48000)
  • --bit-depth {16,24}: Target bit depth
  • --mono: Convert to mono

Stretching:

  • --crispness {0-6}: Rubberband crispness (default: 5, higher preserves transients)
  • -s, --step N: Step size for range mode (default: 10)

Examples

Basic usage:

# Stretch to single target
breaks-machine stretch amen_170.wav -t 140

# Multiple targets
breaks-machine stretch break.wav --targets 90,120,140

# Range with custom step
breaks-machine stretch break.wav --range 100-140 --step 5

With format conversion:

# Convert to 44.1kHz mono 16-bit
breaks-machine stretch break.wav -t 140 --sample-rate 44100 --bit-depth 16 --mono

Batch processing:

# Process directory
breaks-machine stretch ./breaks/ -t 140 -o ./output/

# With manual BPM for all files
breaks-machine stretch ./breaks/ -t 140 --bpm 170

How It Works

Architecture

Input Audio → BPM Detection → Time Stretching → Format Conversion → Output
                    ↓                 ↓                  ↓
              detector.py       stretcher.py      converter.py

BPM Detection Priority

  1. Manual Override (--bpm): If specified, uses this value
  2. Filename Parsing: Looks for patterns like amen_170.wav, break-140bpm.flac
  3. Auto-Detection: Uses librosa with multi-strategy detection:
    • Tries multiple tempo priors (120, 140, 170 BPM)
    • Applies subdivision correction for complex breakbeats
    • Prefers direct detections over derived subdivisions
    • Biases toward common breakbeat range (140-180 BPM)

Rubberband Crispness

The tool uses crispness=5 by default, which:

  • Preserves transients (drum hits)
  • Minimizes phase artifacts
  • Optimized for percussive material

You can adjust with --crispness {0-6} (higher = more transient preservation).

Supported Formats

  • Input: WAV, FLAC
  • Output: Same format as input (or specify conversion options)

Development

Local Setup

  1. Clone the repository:

    git clone https://github.com/yourusername/breaks-machine.git
    cd breaks-machine
    
  2. Install system dependencies (see Requirements above)

  3. Install Python dependencies:

    uv sync --group dev
    
  4. Run tests:

    uv run pytest tests
    

Using Devcontainer (Optional)

For zero-friction setup with all dependencies pre-installed:

  1. Install prerequisites:

  2. Copy devcontainer template:

    cp -r .devcontainer-template .devcontainer
    
  3. Open in container:

    • VS Code → Command Palette → "Dev Containers: Reopen in Container"
    • Wait for build (first time takes a few minutes)

See .devcontainer-template/README.md for details.

Running Tests

# All tests
uv run pytest tests

# With coverage
uv run pytest tests --cov=src/breaks_machine

# Specific test file
uv run pytest tests/test_detector.py -v

Code Quality

# Format code
uvx ruff format

# Lint code
uvx ruff check --fix

# Type checking (if added)
uvx mypy src/

Manual Testing

The repository includes test breaks in the breaks/ directory:

# Test with real breaks
uv run breaks-machine stretch breaks/FR_Drum_Loop_160.wav -t 140

Project Structure

src/breaks_machine/
├── cli.py          # Click-based CLI entry point
├── detector.py     # BPM detection (filename + librosa)
├── stretcher.py    # Rubberband wrapper
├── converter.py    # Format conversion
└── processor.py    # Processing pipeline

tests/
├── test_cli.py
├── test_detector.py
├── test_stretcher.py
├── test_converter.py
└── test_processor.py

Technical Details

Dependencies

  • click: CLI framework
  • librosa: Audio analysis and BPM detection
  • pyrubberband: Python wrapper for Rubberband
  • soundfile: Audio I/O for WAV/FLAC

System Requirements

  • rubberband-cli: Time-stretching engine
  • libsndfile1: Audio file I/O library
  • ffmpeg: Audio codec support

See the Requirements section for platform-specific installation instructions.

Contributing

Contributions are welcome! Please:

  1. Fork the repository
  2. Create a feature branch
  3. Make your changes
  4. Run tests: uv run pytest tests
  5. Format code: uvx ruff format
  6. Submit a pull request

License

[Add your license here]

Acknowledgments

  • Rubberband: Industry-standard time-stretching library
  • librosa: Audio analysis toolkit
  • Built with modern Python tooling (uv, ruff, pytest)

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

breaks_machine-0.1.0.tar.gz (67.4 kB view details)

Uploaded Source

Built Distribution

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

breaks_machine-0.1.0-py3-none-any.whl (12.8 kB view details)

Uploaded Python 3

File details

Details for the file breaks_machine-0.1.0.tar.gz.

File metadata

  • Download URL: breaks_machine-0.1.0.tar.gz
  • Upload date:
  • Size: 67.4 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for breaks_machine-0.1.0.tar.gz
Algorithm Hash digest
SHA256 2305c958a89ef88951439dacf7bee8c204655f2b4ec8b12f817939ae26b6631a
MD5 79ba4877d63aad8c9b514eb487e08d8c
BLAKE2b-256 f8a8c2bada9d72f9ce606d643b2c1234961c99f6e181525af066e5978c954837

See more details on using hashes here.

File details

Details for the file breaks_machine-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: breaks_machine-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 12.8 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for breaks_machine-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 d4a9e08afd45e469bc6fd1eb6b933ecaf48e896fb2350a1c665c8ff31d580400
MD5 e0df4f53762cb1eb362799636f0f6ede
BLAKE2b-256 50fc3f44f6bb2c4289d0f578fc855034549cb67cf995e5b1bc416838679027ef

See more details on using hashes here.

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