Skip to content

AIStockBrah/WaxEngine

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

2 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

WaxEngine

Algorithmic trip-hop music generator inspired by Wax Tailor

WaxEngine is a Python program that composes and renders original downtempo/cinematic hip-hop instrumentals. It combines music theory rules, genre-specific production techniques, and layered audio processing to produce full tracks -- no samples, no AI models, just code that understands the groove.


What It Sounds Like

WaxEngine generates tracks with these characteristics:

  • Dusty boom-bap drums with MPC-style swing and ghost notes
  • Jazz-informed harmony -- minor 7th chords, chromatic bass walks, modal interchange
  • Cinematic orchestration -- strings, horns, and harp layered under the beat
  • Rhodes and vibraphone melodies with pentatonic phrasing
  • Vinyl warmth -- crackle, tape wobble, and lo-fi filtering baked in
  • Dynamic arrangements that build, breathe, and resolve like a film score

Tempo range: 75-95 BPM. Duration: 3-5 minutes per track. Every generation is unique.


Quick Start

Prerequisites

  • Python 3.11+
  • FluidSynth (apt install fluidsynth libfluidsynth-dev or brew install fluid-synth)
  • ffmpeg (for MP3 export)
  • libxcb-cursor0 (Linux only, for GUI: apt install libxcb-cursor0)
  • A General MIDI SoundFont (.sf2)

Installation

# Clone the repo
git clone https://github.com/youruser/waxengine.git
cd waxengine

# Create virtual environment and install dependencies
python -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt

# Download a SoundFont
mkdir -p soundfonts
# Place a GM SoundFont (e.g., FluidR3_GM.sf2) in soundfonts/

Launch the GUI

python src/gui.py

A dark-themed window opens where you can select presets, tweak parameters, generate tracks, and play them back -- all without touching the command line.

Generate from the Command Line

# Default random parameters
python -m src

# Use a mood preset
python -m src --preset noir_detective

# Custom key and tempo
python -m src --tempo 84 --key Dm --swing 0.60 --output my_track.wav

# MIDI only (fast, no audio rendering)
python -m src --midi-only --output my_track.mid

# Reproducible generation
python -m src --seed 42 --verbose

Your track appears in ./output/ (or wherever --output points).


Usage

GUI

python src/gui.py

The GUI provides:

  • Parameter controls -- Dropdowns for preset, root, mode, template, and progression. Sliders for tempo and swing with randomize checkboxes. Seed input and format selection.
  • Preset auto-fill -- Selecting a preset populates all fields with its values. "(Random)" resets everything.
  • Background generation -- The Generate button runs in a separate thread so the UI stays responsive.
  • Arrangement view -- After generation, a table shows each section's type, bar count, intensity, and active instruments.
  • Audio playback -- Play/Stop button for the generated WAV file.
  • Output access -- Displays the file path with an Open Folder button.

Command Line Options

Flag Description Default
--preset, -p Named style preset None (random)
--tempo, -t BPM (75-95) Random
--key, -k Root key (e.g., Am, Dm, Gm) Random minor key
--swing Swing ratio (0.50-0.75) Random 0.55-0.65
--seed, -s Random seed for reproducibility Random
--format, -f Output format: wav or mp3 wav
--output, -o Output file path ./output/waxengine_<seed>_<timestamp>.<ext>
--midi-only Export MIDI without audio rendering False
--template Song structure: classic, cinematic, minimal, noir Random
--progression Chord progression name Random
--verbose, -v Show arrangement plan and progress False
--list-presets List all available presets and exit --

Presets

Preset Vibe Key BPM Template
noir_detective Dark, smoky, suspenseful D minor 78 noir
dusty_grooves Classic vinyl hip-hop A dorian 88 classic
orchestral_hiphop Grand, cinematic G minor 82 cinematic
midnight_jazz Late-night lounge E dorian 76 minimal
melancholic_drift Dreamy, beautiful sadness C aeolian 75 cinematic
tension_rising Phrygian suspense, uneasy A phrygian 80 noir

Python API

from src.generation.pipeline import generate

# Simple generation with defaults
result = generate()

# Use a preset with overrides
result = generate(
    preset_name="noir_detective",
    seed=42,
    verbose=True,
)

# Full control
result = generate(
    root="D",
    mode="minor",
    bpm=82,
    swing=0.60,
    template_name="cinematic",
    progression_name="noir_minor",
    seed=100,
    output_format="wav",
)

# Access results
print(f"Duration: {result.duration_seconds:.0f}s")
print(f"MIDI: {result.midi_path}")
print(f"Audio: {result.audio_path}")
print(f"Generation time: {result.generation_time:.1f}s")

You can also work with parameters directly:

from src.generation.parameters import randomize_parameters, parameters_summary

params = randomize_parameters(root="A", mode="dorian", bpm=88, seed=42)
print(parameters_summary(params))

Custom Presets

Create a JSON file in presets/:

{
  "description": "Rainy cafe atmosphere",
  "root": "D",
  "mode": "dorian",
  "bpm": 78,
  "swing": 0.58,
  "template": "minimal",
  "progression": "dorian_groove"
}

Use it with --preset rainy_cafe (filename without .json).


How It Works

Architecture

Parameters --> Arranger --> Composition Engines --> MIDI --> Renderer --> Mixer --> Output
                 |               |                                        |
                 |          +----+-----+                             +----+------+
                 |          |  Drums   |                             | Per-track |
                 |          |  Bass    |                             | effects   |
                 v          |  Keys    |                             | Vinyl FX  |
            Song Structure  |  Strings |                             | Master    |
            Chord Map       |  Melody  |                             +-----------+
            Section Plan    |  Texture |
                            +----------+

Generation Pipeline

  1. Parameter Selection -- Tempo, key, swing, structure template, and instrument configs are chosen (from preset or randomized within genre-appropriate ranges).

  2. Arrangement Planning -- A structure template is selected (classic, cinematic, minimal, or noir), sections are assigned chord progressions, and instrument entry/exit is planned per section.

  3. Composition -- Each instrument engine independently generates its part:

    • Drums: Boom-bap patterns with swing, ghost notes, fills at transitions
    • Bass: Root-fifth patterns with chromatic approach notes and octave jumps
    • Keys: Rhodes comping with voice-led extended chord voicings
    • Strings: Sustained pads split into high (violins) and low (cello) with voice leading
    • Melody: Pentatonic/modal phrases with call-and-response structure
    • Textures: Ambient pads, reverse swells, risers for transitions
  4. MIDI Assembly -- All parts are quantized with swing, humanized, and assembled into a multi-track MIDI file.

  5. Audio Rendering -- FluidSynth renders each track to audio using SoundFont instruments.

  6. Effects Processing -- Per-track chains (EQ, compression, reverb, saturation) plus tremolo on keys. Vinyl processor adds crackle, tape wobble, and lo-fi warmth.

  7. Mixing -- Tracks are leveled, panned with constant-power law, and summed through a master chain (glue compression, smile EQ, tape saturation, limiter at -1dB).

  8. Export -- Final mix is written to WAV (24-bit) or MP3.


Music Theory Under the Hood

Chord Progressions

WaxEngine includes 17 curated trip-hop progressions:

  • noir_minor: i - iv - v - i (minor blues foundation)
  • aeolian_cadence: i - bVI - bVII - i
  • modal_wandering: i - iv - bVII - bIII
  • minor_jazz_turnaround: ii dim7 - V7(b9) - i
  • phrygian_tension: i - bII - i (Phrygian color)
  • cinematic_build, dorian_groove, melancholic_drift, suspense, and more

Chords are voiced with extensions (7ths, 9ths) and inversions, then voice-led to minimize movement between voicings.

Rhythm & Swing

All rhythmic content passes through a swing quantizer that shifts alternate subdivisions forward by a configurable ratio (default 60%). Humanization adds timing jitter and velocity variation to avoid mechanical feel.

Melody Generation

Melodic phrases are built from weighted random walks on pentatonic/modal subsets. Constraints include maximum interval size, phrase length (2-4 bars), mandatory rest periods, and tendency toward chord tones on strong beats.


Project Structure

WaxEngine/
├── src/
│   ├── __main__.py            # Module entry point (python -m src)
│   ├── main.py                # CLI entry point
│   ├── gui.py                 # PyQt6 GUI (python src/gui.py)
│   ├── theory/                # Scales, chords, progressions, rhythm
│   │   ├── scales.py          # 17 scale/mode definitions
│   │   ├── chords.py          # Chord voicing engine (22 qualities)
│   │   ├── progressions.py    # 17 curated progressions
│   │   └── rhythm.py          # Swing, humanization, syncopation
│   ├── composition/           # Instrument generators
│   │   ├── arranger.py        # Song structure templates & section planning
│   │   ├── drums.py           # Boom-bap patterns with swing/ghost notes
│   │   ├── bassline.py        # Walking bass, root-fifth, syncopated
│   │   ├── melody.py          # Pentatonic/modal phrase generation
│   │   ├── keys.py            # Rhodes/Wurlitzer comping patterns
│   │   ├── strings.py         # High/low string pads with voice leading
│   │   └── textures.py        # Ambient pads, swells, risers
│   ├── synthesis/             # Audio rendering & effects
│   │   ├── renderer.py        # FluidSynth MIDI-to-audio
│   │   ├── effects.py         # Per-track & master effect chains
│   │   ├── vinyl.py           # Crackle, hiss, wow/flutter, bit reduction
│   │   └── mixer.py           # Multi-track mixing & export
│   ├── generation/            # Pipeline orchestration
│   │   ├── pipeline.py        # End-to-end generation
│   │   ├── parameters.py      # Layered randomization system
│   │   └── presets.py         # Named style presets
│   └── utils/
│       └── midi_utils.py      # NoteEvent, GM constants, MIDI helpers
├── soundfonts/                # FluidR3_GM.sf2 SoundFont
├── output/                    # Generated tracks (.mid, .wav)
├── presets/                   # JSON preset configurations
├── tests/                     # 5 test suites
├── requirements.txt
└── pyproject.toml

Audio Processing

Per-Track Effect Chains

Track EQ Compression Reverb Special
Drums HP 60Hz, cut 300Hz Fast attack, 4:1 Short room Tape saturation
Bass LP 3kHz, boost 80Hz Slow attack, 3:1 None Light overdrive
Keys Scoop 400Hz, air 10kHz Medium, 2:1 Medium plate Tremolo
Strings HP 150Hz Gentle 2:1 Large hall --
Textures BP 200Hz-4kHz None Long hall --

Master Chain

  1. Smile EQ (subtle low/high boost)
  2. Glue compression (slow attack, 1.5:1)
  3. Tape saturation (subtle warmth)
  4. Vinyl noise layer (crackle at -24dB)
  5. Limiter at -1dB

Examples

# Quick dark cinematic track
python -m src --preset noir_detective --seed 1337 --verbose

# Upbeat jazzy groove
python -m src --tempo 92 --key Am --preset dusty_grooves

# Long atmospheric piece with specific progression
python -m src --preset orchestral_hiphop --tempo 78 --progression cinematic_build

# MIDI only for loading into a DAW
python -m src --midi-only --output ./daw_import.mid

# Batch generate 10 unique tracks
for i in $(seq 1 10); do
  python -m src --seed $i --output "./output/track_$i.wav"
done

# List all available presets
python -m src --list-presets

Testing

208 tests across 5 test suites:

python -m pytest tests/ -v
Suite Tests Coverage
test_theory.py 51 Scales, chords, progressions, rhythm
test_composition.py 42 All instrument generators
test_arrangement.py 44 Arranger, textures, parameters
test_rendering.py 39 Renderer, effects, vinyl, mixer
test_pipeline.py 32 Full pipeline, presets, CLI

Limitations

  • No vocals or spoken word -- Instrumentals only. Wax Tailor's signature dialogue samples and vocal features are not replicated.
  • SoundFont-dependent quality -- Output quality is bounded by the SoundFont instruments used. Higher-quality SoundFonts produce better results.
  • Not machine learning -- Algorithmic/rule-based composition. Deterministic and reproducible given the same seed.
  • No real sample chopping -- The "sample collage" aesthetic is approximated through melodic fragmentation and lo-fi processing, not actual sample manipulation.

Requirements

mido>=1.3.0
pydub>=0.25.1
numpy>=1.24.0
scipy>=1.10.0
soundfile>=0.12.0
pyfluidsynth>=1.3.0
pedalboard>=0.7.0
PyQt6>=6.5.0

Optional:

music21>=9.1.0
pretty_midi>=0.2.10
librosa>=0.10.0
matplotlib>=3.7.0

System dependencies: fluidsynth, libfluidsynth-dev, ffmpeg, libxcb-cursor0 (Linux)


License

MIT License. All generated music is original and royalty-free.


Acknowledgments

Inspired by the production artistry of Wax Tailor (Jean-Christophe Le Saoût). This project is an homage to his cinematic approach to hip-hop production. WaxEngine is not affiliated with or endorsed by Wax Tailor.

About

create dem beatz yo

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages