Spectral Mashup Engine (S42)
The auto-synced mashup engine, warts and all
- track_a_main
- track_b_layer
- mashed_audio
- detected_bpm_a
- detected_bpm_b
The mashup node is the showpiece of CutFlow's audio suite: feed it two tracks and it tries to make them agree on tempo, shift one's key, duck one under the other, and blend them into a single "mashed" mix - automatically. S42_SpectralMashupEngine is genuinely ambitious for a ComfyUI node, and it gets further than you'd expect. It also has sharp edges, because BPM detection and pitch-shifting are hard and the implementations here are pragmatic approximations.
Know what you're getting: this is a deterministic DSP chain - auto-BPM detection, time-stretch-to-tempo, pitch-shift, spectral ducking, and a mix balance. No model weights, no GPU, no magic. Which makes it predictable, and predictably imperfect.
How it works, step by step
- BPM detection. Each track's tempo is estimated by autocorrelating its spectral flux - a real, standard method, though it's happiest with percussion-heavy music and will guess on ambient pads.
- Master tempo. If
target_bpmis 0, Track A's detected BPM wins; otherwise your value overrides it. - Sync. Both tracks are time-stretched (phase-vocoder style) so they run at the master BPM.
- Pitch shift.
shift_b_semitonestransposes Track B by shifting its spectral bins (0 = in key, ±12 = an octave either way). - Spectral ducking. This is the interesting one - Track A's magnitude is used as a mask to carve Track B's spectrum down wherever A is loud, giving you that "the main track pulls out from under the vocal" sidechain feel, without any envelope followers.
- Blend and normalize.
mix_balancesets the A/B mix, and the output is peak-normalized.
Inputs
track_a_main,track_b_layer- the two tracks. A is the anchor.target_bpm- 0 for auto (Track A's BPM), or a hard value.shift_b_semitones- -12 to +12. 0 = as-is.spectral_ducking- 0.65 default; how hard B ducks under A.mix_balance- 0.5 default; A vs B in the final blend.
Outputs
mashed_audio- the result.detected_bpm_a/detected_bpm_b- the measured tempos, which are gold for debugging (and a sign of whether to trust the sync).
Installing it
Part of S42 CutFlow: ComfyUI Manager → search "S42 CutFlow", or git clone https://github.com/GeekyGhost/S42-CutFlow into ComfyUI/custom_nodes/, install requirements, restart. Needs torchaudio (bundled with the portable build).
Gotchas
The BPM detector is the weak link - two tracks with clean beats usually sync fine; anything with rubato, long intros, or sparse arrangement will produce a nonsense BPM, and both tracks get mangled to match it. The pitch shift is a bin-shift, so it's fine for keys but not studio-grade (expect some phasey smear). And there's no sample-rate conversion: Track B is assumed to match A's rate, and if not, the spectral math is off. Treat it as a sketchpad: set target_bpm yourself when the auto-detect looks wrong, keep mix_balance modest, and export the result to a real DAW for the final polish.
Inputs (6)
| Name | Type | Default | Description |
|---|---|---|---|
| track_a_main | AUDIO | — | |
| track_b_layer | AUDIO | — | |
| target_bpm | FLOAT | 00–300 | 0.0 uses Track A's auto-detected BPM. |
| shift_b_semitones | INT | 0-12–12 | — |
| spectral_ducking | FLOAT | 0.650–1 | — |
| mix_balance | FLOAT | 0.500–1 | — |
Outputs (3)
| Name | Type | Description |
|---|---|---|
| mashed_audio | AUDIO | — |
| detected_bpm_a | FLOAT | — |
| detected_bpm_b | FLOAT | — |