Metadata-Version: 2.4
Name: beat-engine
Version: 0.1.0
Summary: Code-first beat making in Python — sample-driven, config-driven, no DAW required
Author: Hugo Charels
License-Expression: MIT
Project-URL: Homepage, https://github.com/hugocharels/beat-engine
Project-URL: Repository, https://github.com/hugocharels/beat-engine
Project-URL: Issues, https://github.com/hugocharels/beat-engine/issues
Keywords: music,beats,midi,audio,production,samples,drum-machine
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Developers
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Multimedia :: Sound/Audio
Classifier: Topic :: Multimedia :: Sound/Audio :: MIDI
Classifier: Topic :: Multimedia :: Sound/Audio :: Sound Synthesis
Requires-Python: >=3.11
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: numpy>=1.24
Requires-Dist: soundfile>=0.12
Requires-Dist: pedalboard>=0.9
Provides-Extra: dev
Requires-Dist: pytest>=7; extra == "dev"
Requires-Dist: ruff; extra == "dev"
Requires-Dist: build; extra == "dev"
Requires-Dist: twine; extra == "dev"
Requires-Dist: pre-commit; extra == "dev"
Provides-Extra: sf2
Requires-Dist: pyfluidsynth>=1.3; extra == "sf2"
Provides-Extra: loudness
Requires-Dist: pyloudnorm>=0.1; extra == "loudness"
Dynamic: license-file

# beat-engine

[![CI](https://github.com/hugocharels/beat-engine/actions/workflows/ci.yml/badge.svg)](https://github.com/hugocharels/beat-engine/actions/workflows/ci.yml)
[![PyPI version](https://img.shields.io/pypi/v/beat-engine.svg)](https://pypi.org/project/beat-engine/)
[![Python versions](https://img.shields.io/pypi/pyversions/beat-engine.svg)](https://pypi.org/project/beat-engine/)
[![License: MIT](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)
[![Code style: ruff](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/ruff/main/assets/badge/v2.json)](https://github.com/astral-sh/ruff)
[![Gitmoji](https://img.shields.io/badge/gitmoji-%20😜%20😍-FFDD67.svg)](https://gitmoji.dev/)

Code-first beat making in Python. Bring your own samples (WAV files or SF2 soundfonts), describe a song in TOML or a Python dict, render to WAV / stems / MIDI. No DAW required.

## Status

**0.1.0 — alpha.** The audio pipeline (`numpy` float32 + `pedalboard` direct, no `pydub`, no tempfile round-trips) is complete and tested. The lib already produces well-mixed beats from a config alone, but several "modern pro" features are explicitly deferred to 0.2. Expect breaking config changes between 0.x versions.

**Working today**

- Sample-driven rendering — WAV one-shots, multisample directories, SF2 soundfonts.
- 16 scales, 9 melody contour shapes, A-A' motif sequencer with cross-bar continuity.
- Drum patterns with energy-based switching, accents, ghost notes, fills, ratchets, stutters, drops.
- Voice-leading, chord inversions, chromatic bass approaches.
- Per-instrument Pedalboard FX (Reverb, Compressor, Chorus, Delay, Distortion, Bitcrush, Highpass, Lowpass, PeakFilter, Limiter), sends, sidechain ducking, saturation, tape wobble, auto-pan, stereo width.
- Section dynamics: fade-in / fade-out, crossfade, crescendo / decrescendo, key shift, tape stop, vinyl crackle.
- Master chain: bus compressor + brick-wall limiter, optional LUFS-target normalize.
- WAV / stems / MIDI export.

**Deferred to 0.2**

- Phase-vocoder pitch shift (sustained melodic notes currently shorten with the tape-trick shift).
- Automation envelopes — filter sweeps into the hook, opening reverb tails on the drop.
- Procedural generators: `noise_riser`, `sine_sub`, `impact` — config-only, no samples needed.
- Real 808 glide / portamento.
- Tempo curves and per-section BPM.
- Per-section per-instrument FX overrides.

A 30-second demo render lives in [`examples/demo_beat.py`](examples/demo_beat.py) — `python examples/demo_beat.py` writes `demo_beat.wav` from synthetic samples.

## Install

```bash
pip install beat-engine

# Optional extras:
pip install beat-engine[sf2]        # SoundFont (.sf2) playback via FluidSynth
pip install beat-engine[loudness]   # LUFS-target master normalization
```

## Quick start

```python
from beat_engine import quick_render

quick_render({
    "song": {"bpm": 85, "title": "My Beat", "key": "C minor"},
    "sections": [
        {"name": "verse", "bars": 4, "energy": 0.5},
        {"name": "hook",  "bars": 4, "energy": 0.8},
    ],
    "base": {
        "chord_progression": [["C4", "D#4", "G4"], ["G#3", "C4", "D#4"]],
        "instruments": {
            "kick":  {"sample": "samples/kick.wav",  "pattern": "x---x---x---x---"},
            "snare": {"sample": "samples/snare.wav", "pattern": "----x-------x---", "volume_db": -3},
            "hat":   {"sample": "samples/hihat.wav", "pattern": "x-x-x-x-x-x-x-x-", "volume_db": -10},
            "bass":  {"sample": "samples/bass_C2.wav", "source_note": "C2", "bass_profile": "anchor"},
        },
    },
}, output="my_beat.wav")
```

## CLI

```bash
beat-engine render   songs/my_song              # full mix WAV
beat-engine stems    songs/my_song              # one WAV per instrument
beat-engine midi     songs/my_song              # Standard MIDI File
beat-engine validate songs/my_song              # config lint
```

## Sound sources

You bring your own samples — beat-engine ships no audio.

| Mode | Config keys | Notes |
|---|---|---|
| Single sample | `sample` + `source_note` | One WAV pitch-shifted per note (tape-speed shift, changes duration) |
| Multisample dir | `sample_dir` | Picks closest note from a directory of `note_velocity_rr.wav` files |
| SF2 soundfont | `sf2` + `sf2_preset` + `sf2_bank` | FluidSynth rendering, requires `[sf2]` extra |

## Features

**Sequencing**: 16-step drum patterns, energy-based pattern switching, accent patterns (`H/M/m/l`), ghost notes, fills, ratchets, stutters, drops, swing, per-instrument groove templates (`mpc`/`lazy`/`push`/`funk`), velocity curves (`linear`/`exponential`/`logarithmic`/`soft`/`hard`), humanize, laid-back timing, hit probability.

**Harmony**: 16 scales (major, minor, modes, blues, pentatonics, exotic), voice-leading, chord inversions, chromatic bass approaches, key shifts per section, harmony layer (counter-melody from a source instrument).

**Melody**: auto-generation from scale + contour (`arch`/`ascending`/`descending`/`wave`/`flat`/`valley`/`zigzag`/`random_walk`/`stairs`) + density buckets, with chord-tone snapping on strong beats, A-A' motif sequencing, cross-bar continuity, manual step-list melodies.

**Mixing**: per-instrument FX (Pedalboard) — `Reverb` / `Compressor` / `Chorus` / `Delay` / `Distortion` / `Bitcrush` / `Highpass` / `Lowpass` / `PeakFilter` / `Limiter` — plus reverb/chorus/delay sends, tempo-synced delay, sidechain ducking, saturation (tanh), tape wobble, auto-pan LFO, stereo width (mid/side), per-instrument pan and gain.

**Song-level**: intro fade-in, outro fade-out, section crossfades, crescendo / decrescendo, key shifts, tape-stop outro, vinyl crackle.

**Master chain**: bus compressor + brick-wall `Limiter`. Optional LUFS-target normalization (`target_lufs` in config) when `pyloudnorm` is installed.

**Export**: 24-bit WAV (full mix), per-instrument stems, Standard MIDI File (Type 1).

## Design

beat-engine is a pure-Python lib that delegates DSP to native code:

- **Audio buffers**: `numpy.ndarray` shape `(num_samples, 2)`, `float32`, 44.1 kHz throughout.
- **Effects**: `pedalboard` (JUCE C++) called directly on the in-memory buffers.
- **I/O**: `soundfile` (libsndfile).
- **SF2**: `pyfluidsynth` (FluidSynth C library).

There is no `pydub` and no tempfile round-tripping for FX. The musical logic (sequencing, melody generation, MIDI export) is pure Python and stateless where it can be.

## Project

- **Contributing**: see [CONTRIBUTING.md](CONTRIBUTING.md) — uses [gitmoji](https://gitmoji.dev/) commits and pre-commit hooks.
- **Changelog**: [CHANGELOG.md](CHANGELOG.md) — Keep a Changelog format.
- **Code of conduct**: [CODE_OF_CONDUCT.md](CODE_OF_CONDUCT.md) — Contributor Covenant 2.1.
- **Security**: [SECURITY.md](SECURITY.md) — private vulnerability reporting via GitHub Security Advisories.

## License

[MIT](LICENSE)
