Satyr Edit (Plan β Plan) π
Fix the song's notes before YuE2 ever sings them
- voice_1
- voice_2
- abc
- report
- seconds
Why this exists at all
YuE2 doesn't go straight from text to audio. It composes first: it writes an ABC score - a vocal melody, an instrumental line, chord symbols, section labels - and then renders that score into sound. In ComfyUI that score is just a STRING input on YuE2 Generate Music, tokenised verbatim and never validated.
Which means it's the one piece of YuE2 conditioning you can edit by hand. It's also the only piece with a time axis: M:, L: and Q: make bar lengths arithmetic, so the plan states the song's duration. style and lyrics are one flat blob each for the whole track.
Satyr Edit is a piano roll for that score. Hit the β button on the node after one run and you get both voices on a grid, the chord lane, the bar ruler with time and key changes, and the section lane - plus plain-tone playback, so you can hear the plan before you spend a render on it.
How it works
The node is mostly a host: on a run, the plan from abc lands on the node and is handed to the editor, and wiring for lyrics and voices is pushed across with it, so unwiring one clears it there too.
Press πΎ Save and something carefully conservative happens. Anything you didn't touch is written back as the exact text it came from, byte for byte - save without editing and the plan is identical, line ends included. Only the parts you changed get re-rendered, and they're re-rendered the way ComfyUI's own SheetSage2 β ABC exporter writes plans: at most four bars per group, the chord restated at every barline, key-relative spelling, long notes split and tied, empty bars folded to Z. That's not fussiness for its own sake - that's the text YuE2 was trained on, so an edit in that dialect is an edit the model can read.
Saving also flips use_edited on, and that's the part with teeth: with it on, the abc input isn't evaluated at all. Whatever feeds it - YuE2 Generate ABC, an LLM writing plans, a whole upstream branch - stops running. Flip it off and the upstream plan flows through again; your edit stays on the node until you discard it.
The inputs and outputs that matter
abc(STRING, lazy) - the plan, fromYuE2 Generate ABC,Satyr TrimorSatyr Import.use_edited- edited plan, or upstream plan. The editor turns this on when you save.plan_state- the editor's own storage. Don't type in it.lyrics(optional) - the same marked-up lyricsSatyr Scorereads. Editor-only: it shows which syllable each Vocal note sings, and how many notes each section has for its words. It does not change the outgoing plan.voice_1/voice_2(optional) -Character Cardvoice outputs. With two wired, the editor names each singer's band and flags a section whose register contradicts its marker.
Outputs: abc goes into YuE2 Generate Music or Satyr Music (Guided YuE2); report says which plan went out, its length, key and tempo, plus anything structurally wrong - wire it to a text preview; seconds is the plan's duration, which is what Empty YuE2 Latent Audio wants.
The editing rules, and why one of them is locked
Notes drag up and down by semitones, bars can be duplicated, deleted or inserted, sections renamed and reordered, chords typed into the chord lane, tempo set with β©=. Transpose moves the selection - picked notes, or a whole section with its chords and key, which is a modulation. Every edit is one undo step.
π Vocal rhythm is on when the editor opens, and that's a considered choice rather than a limitation. YuE2 wrote that rhythm for the words' stresses, and on a real render notes added, removed or split in the Vocal line moved the pauses inside the lines - the words came out phrased as if they'd been written differently. So Vocal rhythm changes are refused by default; whole bars can still come and go, and Ins moves freely. Unlock it when you know why.
One thing to be honest about: the two voice bands are drawn, and each phrase is coloured by which band its median sits in - but that's a reading of who the model wrote it for, not a switch. How many singers a song has is decided by the style string, and on the base model moving a phrase across the band line isn't a reliable lever; the pack's docs got it working once at a fixed seed with a genre LoRA on the CLIP at strength 2.0, and not without it.
Install, and the one real dependency
Manager, search Kinburg-Nodes, or:
cd ComfyUI/custom_nodes
git clone https://github.com/Kinburg/Kinburg-Nodes
Restart ComfyUI afterwards - the piano roll is a frontend extension the pack ships, and a restart is what loads it. The node lives under Kinburg-Nodes β Bestiary β Satyr.
Two gotchas. The pack's install.py runs automatically on a Manager install and pulls a CUDA llama-cpp-python wheel for the Local LLM nodes - you don't need it here, but don't be surprised by the download. And the plan writer uses the ABC exporter that ships in ComfyUI core (comfy/audio_encoders/sheetsage2_abc.py), imported when the node runs, so on a ComfyUI old enough not to have it the pack still loads but this node errors. Update ComfyUI if you see that.
Finally: abc must actually be a YuE2 plan - an empty input is a clear error rather than a silent pass-through of nothing, which is the right call when the alternative is a wasted render.
Inputs (6)
| Name | Type | Default | Description |
|---|---|---|---|
| abc | STRING | The plan to edit β from 'YuE2 Generate ABC', 'Satyr Trim' or 'Satyr Import'. Run the graph up to this node once and the plan is on the node for the editor to open. With 'use_edited' on this input is not evaluated at all, so whatever feeds it does not run β the same freeze as Show Text's saved text. | |
| use_edited | BOOLEAN | false | Which plan goes out. On: the one you saved in the editor, and the upstream is not run at all. Saving in the editor turns this on. Off: the plan from the 'abc' input, passed through. Your edit is kept on the node β turn this back on to use it again. |
| plan_state | STRING | The edited plan and the last plan that came in, kept by the editor. Not edited by hand. | |
| lyricsopt | STRING | The lyrics with '[Verse 1 - Keen Burg]' markers β the same text Satyr Score reads. Only for the editor: it shows which syllable each Vocal note sings, which singer each section is marked for, and how many notes each section has for its words. The plan going out is not changed by it. The words are laid onto the plan exactly the way Satyr Score lays them, so the editor and that node's report agree. | |
| voice_1opt | KINBURG_VOICE | A band member β a Character Card's 'voice' output, the same cards Satyr Score takes. With two wired, the editor names the singer of each voice band and marks a section whose register contradicts its marker. | |
| voice_2opt | KINBURG_VOICE | β |
Outputs (3)
| Name | Type | Description |
|---|---|---|
| abc | STRING | β |
| report | STRING | β |
| seconds | FLOAT | β |