Nodes/ComfyUI-SimpleUtils/Audio > AudioToBase64
ComfyUI Node

Audio > AudioToBase64

Get the sound out of your workflow as text, not a file

By moonstar-x-libs·Created 30 days ago·Updated 20 days ago· 2
Audio > AudioToBase64
  • audio
  • BASE64
◄formatwav►

You know the moment: the workflow just produced a nice 8-second voice line, and what you need isn't a file in ComfyUI/output/ - it's that audio inside a JSON payload, an HTTP response, or a data:audio/wav;base64,... link on a web page. Base64 is how binary crosses a text-only frontier, and core ComfyUI has no node that produces it. This is that node, two widgets wide.

Why you'd reach for it

Audio in ComfyUI is bolted on and thin - it only got interesting once video needed a soundtrack, and it arrives through bespoke packs: TTS suites, ACE-Step for instrumentals, MMAudio for foley. The file side is handled, though. Core ships Save Audio (FLAC), Save Audio (MP3), Save Audio (Opus) and Preview Audio, so if all you want is an mp3 on disk, use those and skip this node entirely.

What none of them do is hand you the audio as a string, which is the whole point: the moment your generation has to leave the canvas for something text-shaped. Usually that's a workflow you drive as a service - wrap ComfyUI behind a small HTTP API and media passes in and out as base64 or URLs, the pattern behind every "I hosted my workflow on Modal" thread. Base64 is the plumbing for that loop.

How it works

AUDIO in ComfyUI is just a dict - {"waveform": tensor, "sample_rate": int} - where the waveform is (batch, channels, samples) floats. The node takes audio["waveform"][0] (so: channels × samples, original rate), clamps samples to [-1, 1], then feeds them to PyAV as a planar-float frame and encodes through the container/codec pair you picked, into an in-memory buffer. No disk, no temp files, no shelling out to ffmpeg - PyAV ships its own FFmpeg, which is why this pack doesn't make you install one.

The four formats aren't interchangeable, so pick on purpose:

  • wav - 16-bit PCM at the input rate. Big, universally understood, good for debugging.
  • flac - lossless, roughly half the size. The right default if you're handing audio to a person.
  • mp3 - keeps the input rate, which has to be one libmp3lame can actually encode (8, 11.025, 12, 16, 22.05, 24, 32, 44.1 or 48 kHz).
  • opus - Ogg/Opus, resampled to 48 kHz for you. Smallest by a wide margin at speech bitrates.

Inputs and outputs that matter

  • audio (AUDIO) - wire in the sound: Load Audio, Record Audio, or a TTS/music node's output.
  • format - the dropdown above, defaulting to wav.

One output, BASE64 (STRING), which goes into any node that takes a string: an API or webhook node, a save-text node, or another base64 node (put Base64ToAudio after it and you've built a converter - wav in, opus out).

It's flagged as an output node, so it always runs and can terminate a graph. What it won't do is show you anything - there's no preview of a 300 KB string on the canvas. Wire it into core's Preview as Text (utils) to eyeball the value, and hang a Preview Audio on the same line if you want to hear what you encoded. Otherwise you're encoding blind.

Install

ComfyUI Manager → search ComfyUI-SimpleUtils, or:

cd ComfyUI/custom_nodes
git clone https://github.com/moonstar-x-libs/ComfyUI-SimpleUtils.git

…then restart. It's under SimpleUtils/Audio as Audio > AudioToBase64; with the CLI it's comfy node install comfyui-simpleutils.

No models to download, and no new pip packages: the dependencies are av, numpy, pillow and torch, all already in ComfyUI's own requirements.txt (av>=14.2.0 included). That's rarer than it sounds in this corner - audio is the layer where dependency conflicts are the default failure mode, because TTS suites drag in transformers and tokenizer pins that fight each other. This pack does no model inference, so it can't start that fight. It is new, though: the base64 audio nodes landed 2026-10-12, so there's no community track record yet.

Where people get burned

Batched audio. It encodes waveform[0], only. Four clips stacked in a batch and you get the first, silently - no warning, and the pack's own test suite pins that behaviour. Split upstream if you need them all.

It never writes a file. Every "where did it save?" question about this node is that question. Feed the string somewhere, or add a Save Audio alongside it if you wanted both.

Size, which is the real trap. Base64 is 4 characters per 3 bytes and WAV is uncompressed: one minute of 44.1 kHz stereo 16-bit is ~10.6 MB of audio, which is ~14 million characters of base64. Don't put that in a text widget. Base64 is for short payloads - a voice line, a sound effect, a stub for an API call. If it's measured in megabytes, you wanted a file upload.

Hot audio gets clamped, not scaled. Samples are clipped to [-1, 1] before encoding, which is the safe behaviour, but it means an over-driven TTS output stays over-driven in your result. Most TTS wrappers have a gain knob - use it upstream instead of hoping the encoder forgives you.

CategorySimpleUtils/Audio

Inputs (2)

NameTypeDefaultDescription
audioAUDIOThe audio to transform.
formatCOMBOwavThe format to encode the audio as.

Outputs (1)

NameTypeDescription
BASE64STRING—