Save Audio (WAV)
Float32, exactly as the model made it
- audio
- ui_widget
- output_reference
- receipt
ComfyUI's audio path is a bit of a backwater - TTS and music arrive through packs that fight over transformers and torch versions, and the saving step is usually whatever the model's own pack ships. LF_SaveAudio is a deliberate, boring alternative: take an AUDIO value, write one WAV per batch item, in order, and don't touch the samples.
That's the feature. It does not clip, normalize, trim, or resample. It writes IEEE float32 WAV (pcm_f32le) - lossless, headroom preserved, values outside [-1, 1] kept rather than squashed. If a model emits a hot spike, you keep the spike, and it's your job to decide what to do about it rather than having a saver do it invisibly.
How it works
It validates the input first, which is where most of its code lives: the waveform has to be a non-empty float tensor shaped [batch, channels, samples], mono or stereo, with an integer sample rate between 1 and 384,000 Hz. Non-finite samples, wrong shapes and unsafe filename prefixes fail before anything is written to disk, so a bad run doesn't leave a half-file behind.
Encoding goes through PyAV, not Python's wave module - that's a real dependency of this pack's requirements (av>=17.0.0), and if your environment is missing it, this node dies on import rather than at save time.
Filenames get a counter and are created exclusively, so re-running a graph won't overwrite yesterday's take, and a failed write deletes its own incomplete file while leaving already-completed batch items alone. Output destinations must stay inside ComfyUI's output directory.
The inputs and outputs that matter
Two required inputs, both of which you'll set:
audio- the AUDIO value. One file per item in the batch, in source order.filename_prefix- defaultaudio/ComfyUI. This is a path and a prefix:audio/ComfyUIwritesoutput/audio/ComfyUI_00001_.wav. Put the subfolder in here rather than reorganizing afterwards.
Outputs:
output_reference- a list of portablepath/to/file.wav [output]strings, one per saved item. Useful for feeding a downstream node or your own logging; the[output]annotation marks it as a reference to ComfyUI's output tree rather than an absolute path.receipt- the bookkeeping JSON, schemalf.audio_file.receipt.v1. Per file: index, relative filename, format, encoding, sample rate, channel count, sample count, duration in seconds and byte length. If you're generating a batch of candidates and picking one later, this is how you compare them without listening to all of them.
It's an output node, so it runs when you hit queue - no extra preview node needed. The optional masonry widget gives you playable controls backed by the durable output references, so the WAVs still play after you reload the graph from history.
How to install it
ComfyUI Manager → search LF Nodes → install → restart, or:
cd ComfyUI/custom_nodes
git clone https://github.com/lucafoscili/lf-nodes
python -m pip install -r lf-nodes/requirements.txt
Use the interpreter that runs ComfyUI - this is more important than usual here, because av has to be importable by that process specifically. The pack's requirements are long (154 nodes' worth: torch, opencv, rembg, transformers, vtracer and more), so a fresh install is a real download. lucafoscili/comfyui-lf is the archived predecessor repo; lf-nodes is the one you want.
Common issues & troubleshooting
ImportError mentioning av. PyAV isn't installed in ComfyUI's environment, or it got clobbered by another node pack that pinned a different version. Re-run the requirements install and restart ComfyUI.
"Audio must contain a waveform tensor and sample_rate." You fed it an IMAGE, or something that looks like audio but isn't a Comfy AUDIO dict. Some audio packs emit raw tensors; those need converting first.
"Unsafe prefix" / output-path errors. The prefix tries to escape ComfyUI's output directory - absolute paths and .. are refused. Relative subfolder is all you get, and that's the right call for a node that writes to your disk.
Your loop isn't actually seamless, and the saver told you so. This is worth internalizing from the pack's own release notes: a file can be a perfect float32 WAV and still have a quiet tail that clicks when looped. The saver isn't making anything sample-exact - if an upstream model produced 10.031 seconds for a "10 second" request, you get 10.031 seconds. Trim and audition downstream.
Everything sounds quieter than other WAVs. Different bit depth and no normalization. Float32 WAV peaks are often quieter on paper than the 16-bit files other tools write. Nothing is wrong, but if a downstream tool expects 16-bit PCM you'll want to convert.
Playback clips but the file is fine. Values outside [-1, 1] are retained; your player clips them. That's the honest tradeoff of a saver that refuses to guess at a limiter.
Inputs (3)
| Name | Type | Default | Description |
|---|---|---|---|
| audio | AUDIO | Mono or stereo AUDIO batch; each item becomes one WAV file. | |
| filename_prefix | STRING | audio/ComfyUI | Output-relative path and filename prefix. WAV files receive a collision-safe counter. |
| ui_widgetopt | LF_MASONRY | [object Object] | — |
Outputs (2)
| Name | Type | Description |
|---|---|---|
| output_reference | STRING | Ordered WAV references relative to ComfyUI output, annotated with [output]. |
| receipt | JSON | Batch receipt containing saved filenames, sample rates, channel counts, durations, and byte lengths. |