feat: initial release - Audio ↔ Tensor bridge nodes for ComfyUI

- AudioToTensor: Converts ComfyUI AUDIO to VCAUDIOTENSOR (mono, resampled)
- TensorToAudio: Converts VCAUDIOTENSOR back to ComfyUI AUDIO
- Compatible with MuseTalk-KJ, VoiceCraft, and any Whisper-based node
- Zero additional dependencies (uses PyTorch + torchaudio)
This commit is contained in:
Ryan Holanda
2026-02-20 15:41:32 -03:00
commit 9ebd2a85e5
6 changed files with 205 additions and 0 deletions
+27
View File
@@ -0,0 +1,27 @@
# Python
__pycache__/
*.py[cod]
*$py.class
*.so
*.egg-info/
dist/
build/
*.egg
# Virtual environments
.venv/
venv/
env/
# IDE
.vscode/
.idea/
*.swp
*.swo
*~
.DS_Store
# Testing
.pytest_cache/
.coverage
htmlcov/
+21
View File
@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2026 Ryan Holanda
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
+29
View File
@@ -0,0 +1,29 @@
# ComfyUI-AudioBridge
Bridges ComfyUI's native **AUDIO** type to raw audio tensors (**VCAUDIOTENSOR**) used by nodes like [MuseTalk-KJ](https://github.com/kijai/ComfyUI-MuseTalk-KJ) and VoiceCraft.
## Nodes
| Node | Description |
| ------------------ | ------------------------------------------------------------------------- |
| **Audio → Tensor** | Converts `AUDIO` → `VCAUDIOTENSOR` (mono, resampled to target rate) |
| **Tensor → Audio** | Converts `VCAUDIOTENSOR` → `AUDIO` (wraps tensor back for standard nodes) |
## Why?
ComfyUI's native `AUDIO` type is a dict (`{waveform, sample_rate}`), but some custom nodes expect `VHS_AUDIO` (a callable) or `VCAUDIOTENSOR` (a raw torch tensor). This node bridges the gap without requiring VideoHelperSuite or duplicate audio loading.
## Install
```bash
cd ComfyUI/custom_nodes
git clone https://github.com/RyanHolanda/ComfyUI-AudioBridge.git
```
No additional dependencies required — uses PyTorch and torchaudio (already included with ComfyUI).
## Usage Example
```
LoadAudio → [Audio → Tensor] → whisper_to_features → MuseTalk Sampler
```
+2
View File
@@ -0,0 +1,2 @@
from .nodes import NODE_CLASS_MAPPINGS, NODE_DISPLAY_NAME_MAPPINGS
__all__ = ["NODE_CLASS_MAPPINGS", "NODE_DISPLAY_NAME_MAPPINGS"]
+104
View File
@@ -0,0 +1,104 @@
"""
ComfyUI-AudioBridge
Bridges ComfyUI's native AUDIO type to other audio formats used by
custom nodes (e.g. MuseTalk, VoiceCraft).
"""
import torch
import torchaudio
class AudioToTensor:
"""
Converts ComfyUI's native AUDIO type to a raw audio tensor.
ComfyUI AUDIO = {"waveform": Tensor, "sample_rate": int}
Output = mono torch tensor resampled to target rate (default 16kHz).
Compatible with MuseTalk-KJ's VCAUDIOTENSOR input type and any node
that expects a raw audio waveform tensor.
"""
@classmethod
def INPUT_TYPES(s):
return {
"required": {
"audio": ("AUDIO",),
"target_sample_rate": ("INT", {
"default": 16000,
"min": 8000,
"max": 48000,
"step": 1000,
"tooltip": "Target sample rate in Hz. 16000 for Whisper/MuseTalk."
}),
},
}
RETURN_TYPES = ("VCAUDIOTENSOR", "INT")
RETURN_NAMES = ("audio_tensor", "audio_dur")
FUNCTION = "convert"
CATEGORY = "AudioBridge"
DESCRIPTION = "Converts ComfyUI AUDIO to a raw tensor (VCAUDIOTENSOR). Use with MuseTalk, VoiceCraft, or any node expecting raw audio tensors."
def convert(self, audio, target_sample_rate):
waveform = audio["waveform"].squeeze(0) # (channels, samples)
sample_rate = audio["sample_rate"]
# Convert to mono
if waveform.shape[0] > 1:
waveform = waveform.mean(0, keepdim=True)
# Resample if needed
if sample_rate != target_sample_rate:
waveform = torchaudio.functional.resample(
waveform, sample_rate, target_sample_rate
)
audio_dur = waveform.shape[1] / target_sample_rate
return (waveform, int(audio_dur))
class TensorToAudio:
"""
Converts a raw audio tensor back to ComfyUI's native AUDIO type.
Useful for routing processed audio back into standard ComfyUI nodes.
"""
@classmethod
def INPUT_TYPES(s):
return {
"required": {
"audio_tensor": ("VCAUDIOTENSOR",),
"sample_rate": ("INT", {
"default": 16000,
"min": 8000,
"max": 48000,
"step": 1000,
}),
},
}
RETURN_TYPES = ("AUDIO",)
RETURN_NAMES = ("audio",)
FUNCTION = "convert"
CATEGORY = "AudioBridge"
DESCRIPTION = "Converts a raw audio tensor (VCAUDIOTENSOR) back to ComfyUI AUDIO type."
def convert(self, audio_tensor, sample_rate):
# Ensure correct shape: (batch, channels, samples)
if audio_tensor.dim() == 1:
audio_tensor = audio_tensor.unsqueeze(0).unsqueeze(0)
elif audio_tensor.dim() == 2:
audio_tensor = audio_tensor.unsqueeze(0)
return ({"waveform": audio_tensor, "sample_rate": sample_rate},)
NODE_CLASS_MAPPINGS = {
"AudioToTensor": AudioToTensor,
"TensorToAudio": TensorToAudio,
}
NODE_DISPLAY_NAME_MAPPINGS = {
"AudioToTensor": "Audio → Tensor",
"TensorToAudio": "Tensor → Audio",
}
+22
View File
@@ -0,0 +1,22 @@
[project]
name = "comfyui-audiobridge"
version = "1.0.0"
description = "Bridges ComfyUI's native AUDIO type to raw audio tensors (VCAUDIOTENSOR) for MuseTalk, VoiceCraft, and more."
readme = "README.md"
license = {text = "MIT"}
requires-python = ">=3.10"
authors = [
{name = "Ryan Holanda", email = ""},
]
keywords = ["comfyui", "audio", "musetalk", "whisper", "tts"]
classifiers = [
"Development Status :: 5 - Production/Stable",
"License :: OSI Approved :: MIT License",
"Programming Language :: Python :: 3",
"Topic :: Multimedia :: Sound/Audio",
]
[project.urls]
Homepage = "https://github.com/RyanHolanda/ComfyUI-AudioBridge"
Repository = "https://github.com/RyanHolanda/ComfyUI-AudioBridge"
Issues = "https://github.com/RyanHolanda/ComfyUI-AudioBridge/issues"