Nodes/ComfyUI-AudioSuiteAdvanced/Character Vocal Extractor (ASA)
ComfyUI Node

Character Vocal Extractor (ASA)

Pull One Character's Voice Out of a Full Recording — Everything Else Goes Silent

By whmc76·Created about a year ago·Updated 15 days ago· 29
Character Vocal Extractor (ASA)
  • audio
  • narrator_audio
  • character1_audio
  • character2_audio
  • character3_audio
  • character4_audio
  • character5_audio
  • extraction_info
subtitle_json
offset_seconds0.00
duration_seconds0.00
fill_silencetrue

Character Vocal Extractor (ASA) is the node that finally does something you can't do with a wave file in a text editor: it takes a full recording with several people talking and produces one clean audio track per person - the narrator on one output, Character 1 on the next, and so on. For every character, the segments where they don't talk are turned into silence, so you get their voice in isolation, timed exactly as it was in the original. Think of it as a surgical mute button driven by a transcript.

This is the middle of the pack's dubbing pipeline. Upstream, Multi-Speaker Speech To Text produces a JSON transcript of who said what and when; this node consumes that JSON plus the original audio and splits it into per-character tracks. Once you have Character 1's voice on its own output, you can re-record that one line with a different actor, process that one voice, or simply drop every speaker onto their own track for a clean mix.

How it works

The node parses your subtitle_json (an array of entries with id, start, end, text), then matches each entry's id against a fixed set of roles: Narrator, Character1, Character2, Character3, Character4, Character5. For each role it builds an all-silence buffer the same length as the original audio and copies only that character's segments back in at their original positions. Characters with no matching segments get a full-length silence track - unless you flip fill_silence off, in which case you get an empty/absent track instead. All six tracks are emitted at once, plus extraction_info, a plain-text summary of how many segments and how many seconds were found per character (handy for a sanity check without listening to anything).

Two crop parameters were added in v1.0.2 and follow the "UTK Audio Crop Process" convention: offset_seconds and duration_seconds. Set duration_seconds to 0 and offset_seconds to 5 and you process from the 5-second mark to the end; set both and you get that window only; leave both at 0 and the whole clip is used. Zero duration means "no crop" - don't set a duration of 0 and expect zero-length audio.

The inputs you'll actually set

  • audio - the original recording.
  • subtitle_json - the speaker-tagged transcript, normally wired straight from Multi-Speaker Speech To Text's output.
  • offset_seconds / duration_seconds - crop window; leave at 0 to use the full clip.
  • fill_silence - keep true (default) so every output port always has a track of the right length.

Outputs: narrator_audio, character1_audio through character5_audio (all AUDIO), and extraction_info (STRING).

Installing it

Ships in whmc76/ComfyUI-AudioSuiteAdvanced (display "AudioSuiteAdvanced"). ComfyUI Manager → search "AudioSuiteAdvanced", or:

cd ComfyUI/custom_nodes
git clone https://github.com/whmc76/ComfyUI-AudioSuiteAdvanced
cd ComfyUI-AudioSuiteAdvanced
pip install -r requirements.txt

Restart ComfyUI. The node itself downloads no models - the heavy lifting (whisper, pyannote) is all upstream in the STT node.

Where people get burned

The number-one gotcha is the role ID mismatch. This node only recognizes Narrator and Character1Character5. The STT node emits pyannote labels like SPEAKER_00 - which match nothing here, so every track comes back silent. You must map your speaker IDs onto the fixed role names first (a simple text-replace node between the two outputs will do).

Second, the JSON must have id, start, and end on every entry, and times must be parseable as M:SS / H:MM:SS. If your transcript comes from a different source with a different schema, the node raises a parse error rather than guessing. Third, the sample rate of your audio and the timestamps in the JSON must agree about what a "second" is - feed this node the same audio you ran through STT, and you'll be fine.

One honest trade-off: this node gates, it doesn't separate. If two characters talk over each other, both get that shared audio - the node can only silence what isn't yours, it can't subtract the other voice. For overlapping speech you'd want a source-separation model, not a mute button.

CategoryAudioSuiteAdvanced

Inputs (5)

NameTypeDefaultDescription
audioAUDIO
subtitle_jsonSTRING
offset_secondsFLOAT0.000–100000000000000000
duration_secondsFLOAT0.000–100000000000000000
fill_silenceBOOLEANtrue

Outputs (7)

NameTypeDescription
narrator_audioAUDIO
character1_audioAUDIO
character2_audioAUDIO
character3_audioAUDIO
character4_audioAUDIO
character5_audioAUDIO
extraction_infoSTRING