Nodes/ComfyUI-OldTimeRadio/ Cast Lock (v2 ledger authority)
ComfyUI Node

Cast Lock (v2 ledger authority)

OTR_CastLock

By jbrick2070·Created 5 months ago·Updated about 16 hours ago· 7
Cast Lock (v2 ledger authority)
    • ledger_json
    • cast_lock_revision
    • cast_report
    • done
    script_json{}
    voice_bankdefault
    cast_voice_policypreserve_ledger
    allow_voice_reusefalse
    char_voice_engineauto
    announcer_voice_engineauto
    gate_in
    voice_devicedefault

    Cast Lock is the "single v2 ledger authority" - the node that decides, once and for all, which character gets which voice reference. It takes the frozen script from OTR_LedgerFreezeCascade and rewrites it into the canonical ledger_json that every downstream voice node reads. Think of it as the casting director: it doesn't write the lines and it doesn't render them, but it stamps the decisions that make the render deterministic.

    That last word is the whole game. OldTimeRadio is obsessed with reproducibility - byte-identical audio baselines, frozen ledgers, no silent drift. CastLock is where the cast assignment gets locked so that rerunning an episode with the same inputs gives you the same voices.

    How it works

    Two policies, one big difference:

    • preserve_ledger (default) - keep whatever voice assignments the writer put in the ledger. Byte-safe: the writer's choices survive untouched.
    • auto_registry - assign voice references from the configured bank using a deterministic caster, with a gender floor enforced.

    Under the hood it stamps voice_ref_id, the character TTS engine, and the announcer TTS engine into the durable cast. The voice_bank dropdown picks the reference-bank scope: default casts from the chatterbox/indextts2 reference banks; bark_legacy/kokoro_builtin keep the preset-based engines; elevenlabs_cloud and google_tts are the cloud scopes.

    The one setting that will bite you is allow_voice_reuse (default off). When the bank runs out of unique voice references, off means the cast fails closed - the render stops rather than give two characters the same voice. That's the "two characters never share a voice" rule made structural. If you have more characters than distinct voices, either shrink the cast or consciously flip this on.

    The inputs that matter

    script_json is required (the frozen ledger). cast_voice_policy and voice_bank do the real work. char_voice_engine / announcer_voice_engine default to auto, which resolves from the bank - set them explicitly to force a cloud pick, but the pack fails loud if the bank can't represent it. voice_device (cuda/cpu/mps) is explicit with no auto-detect - set it to match your machine or the voice engines refuse at load.

    Outputs: ledger_json (the canonical rewrite - feed this to the voice nodes), cast_lock_revision (an INT revision counter so you can see the cast changed), cast_report, and done for the chain.

    Install and gotchas

    Pack-level install (ComfyUI Manager → ComfyUI-OldTimeRadio, restart; active dev is on the v2.0-alpha branch). No model downloads - CastLock is pure ledger logic. The main gotchas are conceptual, not mechanical: flip allow_voice_reuse only when you understand you're letting two characters share a voice, and remember voice_device has no auto-detect, so a wrong mps on an NVIDIA box is a loud refusal, not a quiet fallback. That's the pack's style - it would rather stop and tell you than silently render with a device it didn't ask for.

    CategoryOldTimeRadio/v2/audio

    Inputs (8)

    NameTypeDefaultDescription
    script_jsonSTRING{}Frozen v2 ledger JSON from OTR_LedgerFreezeCascade (node 62 slot 1). CastLock rewrites it into the canonical ledger_json; the legacy raw path keeps reading this untouched string.
    voice_bankoptCOMBOdefaultVoice reference bank scope used by auto_registry. 'default' casts from the chatterbox / indextts2 reference banks; bark_legacy / kokoro_builtin keep the preset-based engines.
    cast_voice_policyoptCOMBOpreserve_ledgerpreserve_ledger: keep the writer's voice assignments (byte-safe default). auto_registry: assign voice references from the bank with the deterministic caster.
    allow_voice_reuseoptBOOLEANfalseWhen the bank runs out of unique references, allow reusing one already assigned (the gender floor still holds). Off -> casting fails closed instead.
    char_voice_engineoptCOMBOautoCharacter TTS engine CastLock stamps into the durable cast. auto resolves from voice_bank; explicit cloud picks fail loud if the bank is incompatible.
    announcer_voice_engineoptCOMBOautoAnnouncer TTS engine CastLock stamps into the durable cast. auto keeps the shipped Kokoro announcer.
    gate_inoptSTRINGOptional ordering signal (wire an upstream done).
    voice_deviceoptCOMBOdefaultDevice for local voice and music engines. 'default' asks ComfyUI what this machine has and RECORDS what it chose; an explicit device is never second-guessed and still fails loud if it is not there.

    Outputs (4)

    NameTypeDescription
    ledger_jsonSTRING
    cast_lock_revisionINT
    cast_reportSTRING
    doneSTRING