Nodes/ComfyUI-OldTimeRadio/ Stable Audio Theme (v2)
ComfyUI Node

Stable Audio Theme (v2)

This node is where your radio drama's theme music actually gets written

By jbrick2070·Created 5 months ago·Updated about 20 hours ago· 7
Stable Audio Theme (v2)
    • cue_audio_clips
    • cue_manifest_json
    • render_log
    • done
    script_json{}
    enginestable_audio_3
    ledger_json
    gate_in
    music_style

    If you found this node by itself, you probably have the ComfyUI-OldTimeRadio pack installed and are staring at a graph you didn't build. Good - that's the normal way in. OTR_StableAudioTheme is one stage in a machine that turns a story into a finished radio-drama video, and its job is narrow: compose the episode's music cues - the opening theme, the closing theme, and the interstitial stingers - from the script that the earlier stages already wrote. You almost never touch it in the shipped workflow, but if you're hand-wiring a pipeline, it's the music department.

    The name is slightly off, by the way. The default engine is Stable Audio 3, but the dropdown is a roster, not a single model. The pack's whole audio layer runs on a pluggable engine registry, and this node just picks which music engine serves the episode. Default is stable_audio_3, a ComfyUI-native adapter that drives ComfyUI's own Stable Audio nodes (ConditioningStableAudio, EmptyLatentAudio, the usual sampler stack) - no extra PyPI dependency, and it runs through ComfyUI's model management so it plays nice with everything else resident in memory. musicgen is still there as the legacy fallback, stable_audio_music is opt-in behind a flag and HF token, and sonilo / google_lyria are cloud routes that stay off unless you deliberately pick them. The important behavior: unusable engines fail closed, with a named error, never a silent swap to something else you didn't choose.

    The two inputs that matter:

    • script_json - the frozen v2 ledger from OTR_LedgerFreezeCascade. This is the story contract; the node reads cue mood from it and passes it through verbatim.
    • ledger_json - the cast-locked ledger from OTR_CastLock. It carries the episode seed, which becomes the per-cue music seed, so the same episode re-renders the same themes. Deterministic, as everything in this pack is.

    engine is the dropdown, and gate_in is an optional ordering signal - wire an upstream done into it to force this node to run after whatever produced that token.

    It returns four things: cue_audio_clips, one padded AUDIO batch holding every cue; cue_manifest_json, which maps each batch row back to a cue id (opening/closing/interstitial) and its exact sample count, so downstream consumers can slice without guessing; a render_log; and a done token you can feed into the next stage's gate_in.

    Installing and the one thing that bites. Install the pack via ComfyUI Manager (search "ComfyUI-OldTimeRadio") or git clone https://github.com/jbrick2070/ComfyUI-OldTimeRadio into ComfyUI/custom_nodes/, then restart. Make sure you're on the v2.0-alpha branch - that's where active development lives.

    Nothing auto-downloads. The Stable Audio 3 adapter needs two weights you have to place yourself:

    ComfyUI/models/checkpoints/stable_audio_3_small_music.safetensors
    ComfyUI/models/text_encoders/t5gemma_b_b_ul2.safetensors
    

    Both come from Comfy-Org/stable-audio-3 on Hugging Face (ungated). Miss one and the node fails loudly with a message naming exactly which file it can't find and where it expects it - read the console on first run. This pack is heavy (tens of GB of models across the whole pipeline), so budget disk space accordingly.

    The genuinely confusing part for beginners is that this node does nothing without its upstream ledger stages. Drop it on a blank canvas, feed it {}, and you get an empty batch - it's a stage in a pipeline, not a standalone music generator. If you just want to hear Stable Audio in ComfyUI, a stock Stable Audio workflow is the lighter path; this node earns its keep when you're running the whole episode machine. The rendered episodes land in output/otr/obs/, ready for OBS.

    CategoryOldTimeRadio/v2/audio

    Inputs (5)

    NameTypeDefaultDescription
    script_jsonSTRING{}Frozen v2 ledger JSON from OTR_LedgerFreezeCascade. Passed VERBATIM to the legacy engine on the batch path; read for cue mood on the clip path.
    engineCOMBOstable_audio_3Theme-music engine. Legacy MusicGen is the byte-identical default; stable_audio_music is opt-in (flag + HF token) until the GPU pilot promotes it. Unusable selections fail closed with a named error.
    ledger_jsonoptSTRINGCast-locked ledger from OTR_CastLock (carries episode_seed). Read on the clip path for the per-cue seed; the batch path delegates the raw script_json.
    gate_inoptSTRINGOptional ordering signal. Wire an upstream 'done' here to force this node to run after it.
    music_styleoptSTRINGYour own music, in your own words -- 'gamelan orchestra', 'surf rock', 'solo cello'. Applies to the generated opening and closing cues, and only on the listener-authored My Story bank. Blank uses the bank's own genre: sci-fi news is Detroit techno, media archive a jazz quartet, the LLM-written Original Radio Drama bank salsa, public domain Chicago house, Shakespeare an Elizabethan consort.

    Outputs (4)

    NameTypeDescription
    cue_audio_clipsAUDIO
    cue_manifest_jsonSTRING
    render_logSTRING
    doneSTRING