Stem-separated music visualizer. Layer together drums, bass, vocal and other stems - each driving Milkdrop presets to create your own unique visual masterpieces.
Comprehensive visual editor allows you to browse and tune presets in real time - automate preset switching, layer in effects, post processing and a whole bunch more. Render the final output in high definition and high frame rates using ffmpeg.
Built on projectM and Demucs amongst others. Developed on WSL2; Linux with a display is the current checkout setup. A Windows zip is documented under Windows zip.
- Python 3.10+
- FFmpeg
- libprojectM 4.2+ (needs
_opengl_render_frame_fboand_set_frame_time) - Optional: NVIDIA GPU + CUDA for faster Demucs separation
- WSL2: wsl-builds simplifies deps...
./wsl-stacker.sh spoddycoder dev-ai
./wsl-builder.sh media ffmpeg,libprojectmIf you are experiencing audio glitches try disabling systemd-timesyncd.
microsoft/wslg#1257.
If the visual editor feels sluggish and CPU-bound, check that Mesa is using the GPU (not software llvmpipe)...
glxinfo | grep "OpenGL renderer"
# bad: llvmpipe
# good: D3D12
# if you see llvmpipe, force Mesa's D3D12 driver...
export GALLIUM_DRIVER=d3d12Create a virtual environment...
# using venv
python3 -m venv cleave
source cleave/bin/activate
# or using conda
conda create -n cleave python=3.10
conda activate cleaveInstall dependencies...
# CUDA 13.0 (Linux + NVIDIA GPU)
pip install -r requirements-torch-cu130.txt
# or CPU-only
pip install -r requirements-torch-cpu.txt
# rest of deps
pip install -r requirements.txt
# for development and tests
pip install -r requirements-dev.txtGitHub Releases are tagged source archives (vX.Y.Z) for Linux/WSL. Pick a tag, unpack it, and follow Setup above (plus Get Some Milkdrop Presets). System deps (Python 3.10+, FFmpeg, libprojectM 4.2+) are not bundled. cleave --version reports the running version.
The next tagged release attaches a Windows x64 zip (cleave-<version>-windows-x64.zip) and installer (cleave-<version>-windows-x64-setup.exe) as well. v0.1.0 is source-only. Until a tag is cut, testers can download both from Actions via workflow_dispatch on .github/workflows/windows-freeze.yml (5-day artifacts).
main is the integration trunk. User-visible work lands there and adds a bullet under [Unreleased] in CHANGELOG.md in the same change. cleave.__version__ stays at the last shipped tag until a milestone. Then Unreleased becomes a dated X.Y.Z section, the version is bumped, and vX.Y.Z is tagged from main. No calendar cadence. Do not collect work on a long-lived release or develop branch.
How to cut a tag: docs/structured-releases.md.
The installer (cleave-<version>-windows-x64-setup.exe) defaults to Program Files\Cleave. Uninstall removes only the program folder; it does not delete Documents\cleave\ or %APPDATA%\cleave\. The zip (cleave-<version>-windows-x64.zip) is the same onedir tree without an installer: unpack and run from that folder.
Drop a wav onto cleave.exe, or run cleave.exe play <wav>. First run downloads Demucs and Beat This weights into Documents\cleave\models and shows named progress in the loading window. CPU separate is slow. The installer can download extra CUDA files from PyTorch (about 2 GB) for faster stem splitting when it detects an NVIDIA GPU (driver 580.88 or newer). Default answer is No. Skip or fail leaves CPU split. Silent setup does not download CUDA unless you pass /CUDA=1 (that switch still downloads if no NVIDIA GPU is present). The zip stays CPU-only.
cleave.exe play <wav>
cleave.exe play <project>
cleave.exe render <project>
The build is unsigned. If SmartScreen warns on the setup exe or the zip, choose Run anyway.
User data lives in Documents\cleave\ (same projects/, presets/, textures/ tree as Linux). Settings: %APPDATA%\cleave\config.yaml. Override the data root with CLEAVE_DATA.
Milkdrop presets still go under Documents\cleave\presets (see Get Some Milkdrop Presets; use that path instead of ~/.local/share/cleave/).
Maintainers: docs/windows-freeze.md.
Clone or place Milkdrop preset packs in the default location...
mkdir -p ~/.local/share/cleave/presets
cd ~/.local/share/cleave/presets
git clone https://github.com/projectM-visualizer/presets-cream-of-the-crop
git clone https://github.com/projectM-visualizer/presets-milkdrop-original
mkdir -p ~/.local/share/cleave/textures
cd ~/.local/share/cleave/textures
git clone https://github.com/projectM-visualizer/presets-milkdrop-texture-packNote: There are many thousands of Milkdrop presets available, these are just a few of the best.
./cleave.py play ~/music/mysong.wavThis will separate the track into its component stem tracks (bass, drums, vocals, other), perform some audio analysis, then open the editor.
./cleave.py --helpAvailable commands...
playplay song in the editor, accepts a source audio file or project slug/path.separatecan be run on its own without opening the editor.renderaccepts a project slug or path (not a source audio file).backuparchives a full project directory (mix, stems, configs, renders etc.) to a.cleave-tar.gzfile.restoreunpacks a.cleave-tar.gzarchive intoprojects/<slug>/(slug fromproject.yaml).
Note: use --help on any command for options.
- Press
hto show context sensitive help and controls.- The help will change as you move around the interface with the arrow keys.
- If you're using CPU to render, the editor may run at low frame rates with multiple layers
- Change
Editor Settings->preview qualityto help with this. - The final render will still be at full quality and full frame rate.
- Change
The editor has a preset curation mode that provides a simple way to categorise presets into folders for future use.
Editor Settings -> editor mode -> preset curation. While focused on a preset file row:
f- copy the preset intofavourites/(original stays in the pack).c- copy the preset into a cast role directory (see below for more info on cast roles)b- move the preset intoblacklist/(permanently removed from pack).- All preset folders live under
paths.preset_root(default~/.local/share/cleave/presets/).- Browse them in the Editor like any other pack folder.
- Subdirectories inside
favourites/orblacklist/appear as destination choices in the confirm modal, which makes it easy to categorise them in any way you choose, eg:
favourites/a-tier/
favourites/b-tier/
favourites/lots-of-black/
favourites/full-colour-wash/
The timeline provides a comprehensive way to automate layer visibility, preset choice, opacity and blend. When enabled, the standard layer visibility controls are disabled, the timeline takes over.
- Provide a simple way to mark specific points in the song for preset cuts.
- Press
Ctrl + Enterto drop a song marker at any point in the song. - These can be used as snap points and are also used by the
timeline presetas anchor points for generation.
- Powered by Beat This! an AI beat detection library.
- By default it will use the full-mix stem for analysis.
- Choose a different stem with the
--beat-detection-stemswitch.
- Choose a different stem with the
- You can snap cues to the grid either on record or after record.
- This makes it easy to generate a complete layered visualisation of a song.
- For best results you should curate presets into Roles.
- If song markers are available, they will be used to drive the preset generation (do this for best results).
- There are multiple song marker types:
-standard song marker, no special behaviour.crescendo- used to denote where the visual intensity should build t, before crashing off to low intensity.dimininuendo- used to denote where the visual intensity should reduce to, before returning to normal intensity.begin- used to denote where crescendo or dimininuendo ramp should begin.sustain- used to denote where crescendo or dimininuendo should hit maximum / minimum intensity.
CRESCENDO: thin ↗↗↗ FULL ──── FULL ──── ► solo
begin sustain crescendo
DIMINUENDO: FULL ↘↘↘ thin ──── thin ──── ► restore
begin sustain diminuendo
cleave creates a new directory under ~/.local/share/cleave/projects/ for each song.
The project directory stores all files required in a self-contained bundle...
project.yaml- project metadatacleave-viz.yaml- editor & final render configuration. Not everything in here is surfaced in the editor UI just yetsignals.json- audio analysis data (schema version 4) used bycleave effectsand the opt-in timeline preset conductor; re-runseparateon existing projects after a schema bump so envelopes stay currentmysong.wav- original source audio is copied into the project directorystems/- separated audio stemsrenders/- final output renderspresets/- presets used by the project are copied into the project directory
Cleave uses OS user-data directories. Default locations...
Linux (XDG):
- User data:
~/.local/share/cleave/projects/presets/presets/favourites/presets/blacklist/
- Configuration:
~/.config/cleave/config.yaml- Editor settings (preview quality, panel width, fade)
Windows (checkout or the Windows zip):
- User data:
Documents\cleave\(sameprojects/,presets/,textures/tree) - Configuration:
%APPDATA%\cleave\config.yaml
On every OS:
- Override the data root with
CLEAVE_DATA(e.g.CLEAVE_DATA=.for a dev checkout). - When a project omits
paths, preset browsing defaults to<data root>/presets.paths.preset_rootincleave-viz.yamloverrides this default when set.
Windows freeze layout and FFmpeg/libprojectM sidecars: docs/windows-freeze.md.
- The editor supports up to eight libprojectM layers at tiered resolutions
- Composited to 1280x720 content by default (editable
cleave-viz.yaml) - Live preview upscales via
editor.upscaleand runs at display frame rate - Offline render output resolution is set under
render.width/render.height(default 1280x720) and frame rate underrender.fps - Each layer's libprojectM instance receives PCM from its assigned stem; stereo stems are fed as stereo, mono as mono.
- Milkdrop draws on black, so cleave treats black as transparent and uses pixel brightness as blend weight (
black-keydefault).
Signal-driven compositor modifiers on top of each layer. Tune depths (0-100%).
| Stem | Effects |
|---|---|
| Drums | pulse, flash, grit |
| Bass | pulse (sub_bass, mid_bass), flash, grit |
| Vocals | pulse, hue (pitch), flash, grit |
| Other | pulse, flash, grit |
- TODO: Document
- TODO: Document
- Milkdrop / projectM - visualizer engine
- Demucs - audio separation
- Beat This! - beat and downbeat detection
- FFmpeg - video encoding
- pygame - window, input, overlay UI, and SDL2 audio
- OpenGL / PyOpenGL - layer compositing and rendering
- ModernGL - GPU post-processing
- librosa - audio analysis and feature extraction
- NumPy - numerical arrays for audio and effects
- PyYAML - configuration format
- soundfile - WAV I/O