Skip to content

slopsmith/slopsmith-plugin-stems

 
 

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

47 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Slopsmith Plugin: Stems Toggle

A plugin for Slopsmith that turns multi-stem .sloppak songs into a live mixing board. Toggle guitar, bass, drums, vocals, piano, or "other" on the fly during playback, tweak each stem's volume, and the plugin remembers your mix per song.

PSARC songs are untouched — the plugin only activates when a song's song_info payload contains a non-empty stems[] array.

Features

  • Per-stem mute toggles injected into the player control bar
  • Inline volume controls — each stem button fills left-to-right to show its saved volume; drag across the button to set the level
  • Per-song memory — muted stems and volumes are saved to localStorage keyed by filename, so each song reopens with your last mix
  • Mute on load — pick which stems start silenced when a song opens (e.g. always start with vocals off)
  • Karaoke mode — one-click preset that always mutes vocals by default
  • Sample-locked playback — every stem plays from a decoded AudioBuffer through one shared AudioContext, so the stems and the note highway are sample-exact and cannot drift apart
  • Pitch-preserving speed control — slowing a song down (or speeding it up) changes tempo only, not pitch, just like PSARC playback
  • Inert on PSARC — core audio works normally when there are no stems to mix

Installation

cd /path/to/slopsmith/plugins
git clone https://github.com/topkoa/slopsmith-plugin-stems.git stems
docker compose restart

Usage

  1. Convert a PSARC to a .sloppak with the Sloppak Converter plugin (which runs Demucs to split the single mixed track into per-instrument stems), or hand-craft a sloppak directory with multiple stems listed in manifest.yaml.
  2. Play the song. The stem mixer bar appears in #player-controls with one labeled button per stem.
  3. Click a stem to toggle it on/off. Drag left or right across the button to adjust its volume continuously.
  4. Your mute state and volumes are remembered the next time you open the same song.

Settings

Open Settings → Stems Toggle to configure:

  • Karaoke mode — start every new song with vocals muted
  • Mute on load — tick the stems that should default to off (e.g. vocals + piano for a guitar practice preset)

Per-song toggles always override defaults.

How it works

Playing six stems as six independent <audio> elements means six independent HTMLMediaElement decoder clocks — and they do not stay in step. In practice the guitar/core stem's element decoded ~7–8% fast, so the note highway (which clocked off it) ran ahead of the music. The plugin removes HTMLMediaElement decoder clocks from playback entirely.

When a song with stems loads, the plugin:

  1. Fetches every stem and AudioContext.decodeAudioData()s each into an AudioBuffer (a "Decoding stems…" indicator shows while this runs)
  2. Plays each stem through an AudioBufferSourceNode → per-stem GainNode → master GainNodeAudioContext.destination. Every source is start()-ed at the same AudioContext time, so the stems are sample-locked forever
  3. Derives the playhead from the AudioContext clock and shims the core <audio id="audio"> element's play / pause / currentTime / duration / paused to drive this transport, dispatching the matching media events so the rest of slopsmith is unaffected
  4. Publishes window.slopsmith.stems.setMasterVolume so the core "Song" fader drives the master GainNode, moving every stem together
  5. Exposes window.slopsmith.stems.getAnalyser() — an AnalyserNode on the stem mix — for audio-reactive plugins

Transport (play / pause / seek / speed) operates on all stems atomically: seeking stops and recreates every source node at the new offset so they restart locked. Toggling a stem is a pure GainNode.gain.value change.

PSARC songs (no stems) and the JUCE desktop path are untouched — the <audio> shims delegate straight to core whenever no sloppak is active.

Pitch-preserving speed (worklet)

When AudioWorklet is available, the per-stem AudioBufferSourceNodes are replaced by a single stem-mixer AudioWorkletProcessor (assets/stretch-worklet.js) that owns every stem's PCM. It mixes the stems (applying live per-stem gains) and time-stretches the single mixed signal with WSOLA, so the speed slider changes tempo without changing pitch — and because there is one mix and one stretcher, the stems stay sample-locked. At rate 1.0 it is an exact pass-through (no stretch, no added latency); off-unity it reports its constant algorithmic latency so the highway stays aligned with what is heard. The module is self-hosted and loaded from the plugin's assets/ directory via the core /api/plugins/{id}/assets/{path} route.

If AudioWorklet is unavailable (e.g. an old WKWebView) the plugin falls back to the AudioBufferSourceNode-per-stem path, where the speed slider couples pitch to tempo as before; a one-time console warning is logged.

The DSP has a headless test: node tests/stretch-worklet.test.mjs.

Requirements

Requires Slopsmith with .sloppak format support and a song_info payload that includes a stems[] array (available on the feature/sloppak-format branch and its merged descendants).

Other Plugins

  • Sloppak Converter — convert PSARCs into .sloppak files in-app, with optional Demucs stem splitting

License

MIT

About

Multi-stem Web Audio mixer for .sloppak songs in Slopsmith

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages

  • JavaScript 98.6%
  • HTML 1.4%