Trip-hop / downtempo music generation pipeline — from config to complete, playable tracks. Inspired by Portishead, Massive Attack, and Vegyn's Headache project.
Input: mood preset + config
Output: finished .wav / .mp3 you can play immediately
# 1. Install dependencies
uv sync
# 2. Generate a track (defaults: melancholic, ~78 BPM, ~3 min)
uv run python generate_track.py
# 3. Find your track in ./output/Note: MP3 export requires ffmpeg to be installed on your system (
brew install ffmpegon macOS).
# Basic
uv run python generate_track.py
# Full control
uv run python generate_track.py \
--mood paranoid \
--bpm 85 \
--length 120 \
--seed 42 \
--vocal-engine gtts \
--output ./my_tracks
# Instrumental only (no vocals)
uv run python generate_track.py --vocal-engine silent
# Supply your own spoken-word text
uv run python generate_track.py --text "Beneath the surface. We oscillate. The architecture of silence."| Flag | Default | Description |
|---|---|---|
--mood, -m |
melancholic |
Mood preset: melancholic, paranoid, ethereal |
--bpm, -b |
from preset | Tempo (70–90 BPM typical) |
--length, -l |
from arrangement | Target track length in seconds |
--seed, -s |
random | Seed for reproducible output |
--vocal-engine, -v |
gtts |
TTS engine: gtts, pyttsx3, silent |
--text, -t |
generated | Custom text for vocals |
--output, -o |
./output |
Output directory |
┌──────────────┐ ┌───────────────┐ ┌────────────────┐
│ 1. LYRICS │───▶│ 2. VOCALS │───▶│ │
│ (generator) │ │ (TTS engine) │ │ │
└──────────────┘ └───────────────┘ │ │
│ 4. ARRANGER │
┌──────────────┐ ┌───────────────┐ │ (structure) │
│ 3. SYNTH │───▶│ Drums │───▶│ │
│ (engines) │ │ Bass │ │ │
│ │ │ Pads │ └───────┬────────┘
│ │ │ Textures │ │
└──────────────┘ └───────────────┘ ▼
┌────────────────┐ ┌─────────┐
│ 5. MIXER │───▶│ .wav │
│ (effects + │ │ .mp3 │
│ master bus) │ │ stems/ │
└────────────────┘ └─────────┘
Template-based spoken-word poetry with curated word banks per mood. Produces introspective, abstract text matching the trip-hop aesthetic.
Converts lyrics to audio via text-to-speech:
- gTTS — Google TTS (free, needs internet, natural-sounding)
- pyttsx3 — Offline system TTS (more robotic = on-brand)
- silent — Instrumental-only mode
All sounds generated from scratch via numpy — no samples required:
- Drums: Kick (pitch-swept sine + transient), snare (tone + noise), hi-hat (metallic partials + HP noise), clap (layered noise bursts)
- Bass: Sub-bass sine + harmonics, warm/deep/distorted characters
- Pads: Detuned super-saw-style oscillators with LFO modulation
- Textures: Vinyl crackle, tape hiss, ambient washes
Programmatic track structure with sections:
- Intro → Verse 1 → Break → Verse 2 → Bridge → Outro
- Per-section drum/bass/pad activation
- Swing and velocity humanisation
- Per-stem effects (vocal reverb/delay, snare reverb, etc.)
- Stereo panning and widening
- Master bus compression, saturation, EQ
- Export: WAV + MP3 + instrumental version + individual stems
Each run produces:
output/
├── hollow_shadow_20260207_143022.wav # Full track with vocals
├── hollow_shadow_20260207_143022.mp3 # MP3 version
├── hollow_shadow_20260207_143022_instrumental.wav # No vocals
├── hollow_shadow_20260207_143022_lyrics.txt # Generated lyrics
└── hollow_shadow_20260207_143022_stems/ # Individual stems
├── stem_kick.wav
├── stem_snare.wav
├── stem_hihat.wav
├── stem_bass.wav
├── stem_pads.wav
├── stem_textures.wav
└── stem_vocals.wav
Slow, heavy, dark — Portishead / Dummy-era vibes. 75 BPM, Am, sparse drums, warm bass, wide pads.
Tense, claustrophobic — Massive Attack / Mezzanine. 85 BPM, Am, standard drums, distorted bass, crisp hats.
Dreamy, floating — Cocteau Twins meet Air. 70 BPM, Dm, sparse/lo-fi drums, deep bass, lush pads.
mood-machine/
├── generate_track.py # CLI entry point
├── pyproject.toml # Project config & dependencies (uv)
├── config/
│ └── moods/
│ ├── melancholic.yaml
│ ├── paranoid.yaml
│ └── ethereal.yaml
├── mood_machine/
│ ├── __init__.py
│ ├── config.py # Configuration management
│ ├── pipeline.py # Main orchestrator
│ ├── lyrics/
│ │ └── generator.py # Poetry/lyrics generation
│ ├── vocals/
│ │ └── engine.py # TTS wrappers
│ ├── synth/
│ │ ├── core.py # Oscillators, envelopes, utilities
│ │ ├── drums.py # Drum synthesis
│ │ ├── bass.py # Bass synthesis
│ │ ├── pads.py # Pad/chord synthesis
│ │ └── textures.py # Vinyl crackle, hiss, ambience
│ ├── sequencer/
│ │ ├── patterns.py # Drum/bass patterns, chord progressions
│ │ └── arranger.py # Full track arrangement
│ └── mixing/
│ ├── effects.py # Reverb, delay, compression, EQ
│ └── mixer.py # Stereo mixdown engine
├── output/ # Generated tracks
└── samples/ # (reserved for future sample packs)
| Package | Purpose |
|---|---|
| numpy | All audio synthesis and DSP |
| scipy | Filters, convolution reverb |
| pydub | Audio format conversion and export |
| gTTS | Google Text-to-Speech (free) |
| pyttsx3 | Offline system TTS (fallback) |
| PyYAML | Config file parsing |
| pedalboard | High-quality effects (optional, falls back to scipy) |
- ffmpeg — Required for MP3 export and gTTS audio processing
# macOS brew install ffmpeg # Ubuntu/Debian sudo apt install ffmpeg
Add a YAML file to config/moods/:
mood: dystopian
bpm: 82
key: Cm
synth:
pad_filter_cutoff: 1000
bass_character: distorted
drum_tone: lo-fi
drums:
pattern_style: standard
swing: 0.55
progression:
- { root: C, type: minor7, bars: 2 }
- { root: Ab, type: major7, bars: 2 }
- { root: Eb, type: major, bars: 2 }
- { root: Bb, type: dom7, bars: 2 }Then: uv run python generate_track.py --mood dystopian
Implement the VocalEngine interface in mood_machine/vocals/engine.py:
class ElevenLabsTTS(VocalEngine):
def synthesise(self, text: str) -> np.ndarray:
# Call ElevenLabs API, return numpy array
...- Reproducibility: Use
--seed 42to get the same track every time - Quick iteration: Use
uv run python generate_track.py --vocal-engine silent --length 30for fast test renders - Stem mixing: Import stems into a DAW for manual mixing/mastering
- Custom lyrics: Use
--textwith your own spoken-word poetry
MIT