Sung Pitch
The pink line that shows you every note the transcription got wrong
- audio
- sung_pitch
Plenio's cover workflow transcribes a recording into a score, and then YuE2 sings that score back at you. Which means the thing you actually need to see is where the transcription disagrees with the singing. Sung Pitch draws it: a separation model pulls the vocals out, a pitch tracker follows them, and the piano roll paints the result as a curve over the transcribed notes.
It is analysis only. Nothing it produces ever reaches the model. Think of it as a diagnostic light on the dashboard you consult before you approve the score.
What it does, exactly
Two stages, both local:
- The separation model isolates the vocal stem - the same BS-RoFormer checkpoint Separate Stems uses (
models/audio_separation). - A YIN pitch tracker (plain NumPy, in the pack's own audio code) follows the fundamental of that stem and emits a curve: MIDI note values over time, plus how much of the file is actually voiced.
Then Song Sheet draws it. In the score editor of a cover, the curve is the pink line over the transcribed vocal notes, sitting next to the source recording's waveform lane. A wrong note, an octave-off phrase, a syllable the transcriber invented - all visible at a glance instead of buried in an ABC score you'd have to sing mentally.
Inputs and outputs
- audio (required) - the source recording, i.e. the cover's original.
- separation (required, combo) - the separation checkpoint in
models/audio_separation, or the literal optionwhole mix (no separation - less reliable). - sung_pitch (output,
PLENIO_PITCH) - wire it into the Song Sheet node'ssung_pitchinput. Display only.
whole mix is the no-download escape lane: it tracks the loudest pitch in the mix, which in a band context is very often an instrument. Fine for a rough look at an a cappella-ish recording; misleading for anything dense. If you have the checkpoint, use it.
One implementation detail for the multi-item case: the node analyses the first item of the audio batch it receives. If you feed it a batch of takes or a long file split into pieces, you're looking at the first one.
In the cover workflow
The 2 · YuE2 · Cover template is where this lives. You load a source, SheetSage2 reads the score out of it, faster-whisper places the sung words, and the Song Sheets stop for review before anything renders. Opening the score tab shows the waveform, the notes, and this curve. There's a small piece of interface honesty here worth knowing about: when the singing sits an octave below the notated line, the editor draws the curve in the notes' octave and labels it sung +8va - otherwise the pink line would sit a whole octave from the notes it's being compared against and read as total failure. wave and sung in the roll's toolbar hide the lanes when you want a clean editor for a cover that's departing far from the original.
Also useful: if the whole curve is offset in time rather than wrong in pitch, that's beat detection, not singing, and ⇆ align in the transport moves the recording.
Installing it
Same pack, same single model file:
cd ComfyUI/custom_nodes
git clone https://github.com/jplenio/Plenio-Music-Production-System
mkdir -p ComfyUI/models/audio_separation
# model_bs_roformer_ep_17_sdr_9.6568.ckpt (527 MB) → ComfyUI/models/audio_separation
Manager search is Plenio Music Production System; restart after. The pack installs no Python packages - the separation inference code is vendored - and this node adds nothing of its own. (The cover template's lyrics path is the one place Plenio ever asks for something extra: python -m pip install faster-whisper, and it tells you when it needs it. Sung Pitch doesn't need it.)
Common issues
No curve, and the run still finished. That's the design: this node fails soft because it's display-only, and a failed analysis must not cost you a cover render. The node's summary tells you which of the cases you hit - no audio came in, the separation model isn't in models/audio_separation (put it there, or switch to whole mix), the separation threw and was logged, or the model produced no vocal stem at all.
The combo only shows whole mix. The folder is empty. Create ComfyUI/models/audio_separation, drop the checkpoint in, refresh the frontend, and the file appears in the list.
It says "less reliable" and means it. On a busy mix, the tracker will lock onto whatever is loudest and most periodic - usually a bass or a guitar, not the singer. A curve that traces the bassline while the vocals sit above it is not a bug in the tracker.
It costs a real separation run. Time and VRAM, before you've rendered anything. On long sources that's on top of SheetSage2, which is already the memory hog of the cover path; the template's optional Excerpt node (up to 5:00) exists for exactly that reason.
The pitch is off by exactly an octave. Check the editor's octave handling before you go editing notes - and remember that a note-length or tuning disagreement between the transcription and the curve is information, not noise. If you never open the score tab, just leave this node out of the graph; the cover runs exactly the same without it.
Inputs (2)
| Name | Type | Default | Description |
|---|---|---|---|
| audio | AUDIO | The source recording (the cover's original). | |
| separation | COMBO | A separation model in models/audio_separation (the one of Separate Stems) for the vocal stem; 'whole mix' tracks the loudest pitch of the mix, which is often an instrument. |
Outputs (1)
| Name | Type | Description |
|---|---|---|
| sung_pitch | PLENIO_PITCH | For Song Sheet: the curve in the piano roll. |