ComfyUI Node
Siren Cast (Voice Plan) π§
AceStep 1.5 text encode that says who sings where. The audio-code plan the text encoder's LM writes is a 5 Hz, frame-aligned track β the only conditioning in the model with a time axis β so this node builds it section by section, each with its own voice, as one continuous decode rather than separate clips glued together. It also passes the negative caption the core node never passes, without which the LM's cfg_scale guides the bpm and the key and nothing about the prompt. Voices come from Character Card's 'voice' output, so a band member is described once and feeds the lyrics LLM, the cover art and the song. 'seconds' drives Empty Ace Step 1.5 Latent Audio so the two can't disagree.
Siren Cast (Voice Plan) π§
- clip
- voice_1
- voice_2
- conditioning
- seconds
- timeline
- report
- gen_extra_info
βtagsββΊ
βlyricsββΊ
βseed0βΊ
βbpm120βΊ
βduration120.0βΊ
βtimesignature4βΊ
βlanguageenβΊ
βkeyscaleC majorβΊ
βguidancevoice deltaβΊ
βnegative_tagsβΊ
βcast_in_captiontrueβΊ
βlyrics_in_negativefalseβΊ
βgenerate_audio_codestrueβΊ
βcfg_scale2.0βΊ
βtemperature0.85βΊ
βtop_p0.90βΊ
βtop_k0βΊ
βmin_p0.000βΊ
βverbosetrueβΊ
βduet_modelead + backing noteβΊ
βplanββΊ
CategoryKinburg-Nodes/Bestiary/Siren
Inputs (24)
| Name | Type | Default | Description |
|---|---|---|---|
| clip | CLIP | The AceStep 1.5 text encoders β DualCLIPLoader with BOTH qwen_0.6b_ace15 and qwen_4b_ace15 (type 'ace'). Not either/or: the small one embeds the caption and the lyrics, the big one writes the audio-code plan. | |
| tags | STRING | The caption for the WHOLE song β genre, instrumentation, era, mix, energy. Write it as prose, the way the shipped AceStep templates do, not as a comma-separated tag list. Leave the vocals out of it: each section gets its own voice line from the plan, and repeating 'male vocal' here fights the plan for the sections a woman sings. What DOES belong here is anything true of the whole track ('two lead vocalists trading verses' is fine). | |
| lyrics | STRING | The full lyrics, with the usual '[Verse 1 - ...]' / '[Chorus - ...]' markers. Always the WHOLE song, for every section's pass β the LM needs to see where in the text it is, and the marker names are how it lines the plan up with the words. Keep the section markers spelled the same way as the plan's labels. Nothing enforces it, but you will be reading both. | |
| seed | INT | 00β18446744073709550000 | Seed for the audio-code plan β THE seed that decides the musical idea. The sampler's seed only draws noise; change this one for a different piece. Each section draws from seed + its index, so editing one section's voice leaves every earlier section bit-identical. |
| bpm | INT | 12010β300 | Tempo, into the metas the plan is written against. Also what 'N bars' in the plan is measured with. |
| duration | FLOAT | 120.00β2000 | Song length in seconds β used ONLY when the plan is empty. With a plan the length is the sum of its rows and this widget is ignored (the report says so). Either way the true value comes out on 'seconds': wire it into Empty Ace Step 1.5 Latent Audio instead of typing the number twice. Duration is baked into the plan's tokens, so a latent that disagrees with it is the classic AceStep mistake. |
| timesignature | STRING | 4 | Beats per bar, into the metas β and what 'N bars' in the plan is measured with. A plain field rather than a dropdown because a combo input cannot accept the STRING a text parser hands it; anything with a digit in it is read (4, '4', '4/4'). |
| language | STRING | en | Language of the lyrics, prepended to the lyrics embedding. A plain field so the song config can wire straight in, with the usual slips corrected: Ukrainian is 'uk' (not 'ua'), Chinese 'zh' (not 'cn'), Japanese 'ja'. An unknown code is reported and falls back to 'en'. |
| keyscale | STRING | C major | Key and mode, into the metas. A plain field so the song config can wire straight in: 'C major', 'c# minor', 'C sharp minor' and 'Am' are all read. AceStep's list carries both spellings of every black key (C# and Db), so whichever was written is kept; anything it cannot express is reported and falls back to 'C major'. |
| guidance | COMBO | voice delta | What the plan LM's 'cfg_scale' is actually pushing against. This is the fix for 'the model ignores my tags'. β’ voice delta (recommended) β the negative is the SHARED caption, so cfg_scale amplifies whatever this section ADDS to it: the difference between 'someone sings this' and 'SHE sings this'. Note that a section's 4th column rides the same delta, which is right for a duet's 'with male backing harmonies' and is worth knowing for an arrangement note like 'drums drop out'. Sections that add nothing fall back to core behaviour. β’ negative tags β the negative is the 'negative_tags' text below. General prompt adherence rather than per-section vocals. β’ metas only (core behaviour) β what TextEncodeAceStepAudio1.5 does: the negative repeats the same caption and the same lyrics, with only the metas block emptied. So cfg_scale guides bpm/duration/key and NOTHING about the caption. Here for A/B only. In the first two modes the metas are copied into the negative as well, so the two prompts differ in the caption alone. |
| negative_tags | STRING | The caption to guide AWAY from ('spoken word, off-key, muddy mix, drum machine'). Used by the 'negative tags' mode; in 'voice delta' mode it is appended to that section's negative, so it stacks. NOTE this is not the sampler's negative β that one must stay a ConditioningZeroOut. This text never reaches the DiT; it only shapes the plan. | |
| cast_in_caption | BOOLEAN | true | Append the distinct voices used by the plan to the GLOBAL caption β the one that reaches the DiT through cross-attention for the whole track. What it actually governs, from listening: whether a SECOND voice can appear inside a section β the backing lines in round brackets. A section's own caption names one singer, so the only route by which another timbre can reach those frames is this global list. Off, and the brackets tend to be sung by the section's own voice. It is not the accuracy dial (that is 'lyrics_in_negative'), and neither setting is reliable enough to call correct β it depends on the song, so it is worth trying both ways on a new one. |
| lyrics_in_negative | BOOLEAN | false | Keep the lyrics in the LM's negative prompt. True is what the core node does; OFF is the default here, and it is the single most important setting on this node. With the lyrics dropped from the negative, cfg_scale guides the LYRICS as well as the caption β including the '[Verse 1 - Nina]' markers inside them, which is why the voices then land where the text says. Measured across many takes of one song on a fixed seed and sampler: near-perfect assignment with this off, unreliable with it on. Turn it back on only to reproduce the core node's behaviour, or if diction comes out over-articulated. |
| generate_audio_codes | BOOLEAN | true | Run the plan LM at all. Off is for when you are giving the model a reference audio instead (Set Reference Audio), which replaces the plan with the reference's own tokens. Off makes the plan meaningless β there are no codes to assemble β and the node says so. |
| cfg_scale | FLOAT | 2.00β100 | Guidance for the plan LM. Left at the core default on purpose: with 'guidance' set to voice delta it now means something it did not mean before, and that is one change to judge on its own before this number moves. At exactly 1.0 the negative pass is skipped entirely and every guidance mode becomes a no-op (it also halves the LM's cost). |
| temperature | FLOAT | 0.850β2 | Randomness of the plan. 0.85 is the core default; 0.6-0.7 makes the plan follow the caption and the lyrics more closely. Do NOT go to 0: that is greedy decoding, and an autoregressive audio LM decoded greedily tends to fall into a repeating loop β a section that keeps restarting the same bar. |
| top_p | FLOAT | 0.900β2000 | Nucleus sampling for the plan. Core default 0.9. |
| top_k | INT | 00β100 | Keep only the k most likely codes per step. 0 = off, which is the core default. |
| min_p | FLOAT | 0.0000β1 | Drop codes less likely than min_p x the top code. 0 = off. 0.02-0.05 is a gentler way to tighten the plan than lowering temperature, because it only cuts the tail. |
| verbose | BOOLEAN | true | Print the timeline and the warnings to the console. The same text is always on the outputs. |
| duet_mode | COMBO | lead + backing note | What a plan row naming SEVERAL singers ('Nina + Alex') becomes. The plan carries one audio code per 200 ms and a section's caption is one description, so two timbres over the same frames come back as their average β measured once as 'two female vocals' where a man and a woman were asked for. All three modes therefore say ONE thing where two were asked for; they differ in which one. β’ lead + backing note (default) β the first name leads and the rest become a short phrase in words ('with gritty male backing harmonies'). What Siren Score already writes into the plan, applied here too so a hand-typed row behaves the same. β’ one unison duet β names the pair as a SINGLE sound ('two voices singing together in close unison harmony, airy female and gritty male') instead of a lead with backing. Worth A/B-ing on a fixed seed: the measurement above was taken on two full descriptions pasted side by side, which is a contradictory caption rather than a description of a duet, and AceStep has certainly heard duets. Untested β that is what it is here for. β’ both descriptions β the old behaviour, both voices' full tags joined. Here to A/B against. Either way the singers who lose their place in the SECTION caption still reach the global one, so a member who only ever appears in duets is not invisible to the model. Rows naming one singer, or free text, are untouched. Per-line markers in the lyrics remain the only way to make voices genuinely ALTERNATE. |
| planopt | STRING | WHO sings WHERE β one section per line: Intro | - | 8 Verse 1 | Alex | 24 Chorus | Nina | 8 bars Verse 2 | Mike | 0:24 Chorus | Nina + Alex | 8 bars Outro | - | 8 β’ column 1 β the label, only for the report β’ column 2 β a wired voice's name (several joined by '+'), or free text used as-is, or '-' for no vocal β’ column 3 β the length: seconds, '24s', 'm:ss', or 'N bars' (needs bpm) β’ column 4 β OPTIONAL, appended to this section's caption ('drums drop out') Blank lines, '#' comments and a pasted table header are ignored, so this can come straight out of an LLM. The lengths add up to the 'seconds' output β wire that into Empty Ace Step 1.5 Latent Audio and the two can never disagree. EMPTY = one caption for the whole song, i.e. the core node's behaviour plus the guidance fix below. Start there. | |
| voice_1opt | KINBURG_VOICE | A band member β the 'voice' output of a Character Card (or Card Presets). Its 'voice_tags' is what a plan row referring to that name pastes onto the caption; nothing else from the card is used here. Connect one and another slot appears. Plan rows can also just say the description in words, so wiring these is optional β it is how you stop retyping the same voice in every song. | |
| voice_2opt | KINBURG_VOICE | β |
Outputs (5)
| Name | Type | Description |
|---|---|---|
| conditioning | CONDITIONING | β |
| seconds | FLOAT | β |
| timeline | STRING | β |
| report | STRING | β |
| gen_extra_info | GEN_INFO | β |