关于comfyui的mmaudio音频生成插件时时间不一致问题(一)

起因时这样的,我在根据视频生成音频的时候,发现生成的音频与视频的时间不对

可以明显看到,视频的FPS=16,长度(图片数量)=537

理论时间也输出了 537/16 = 33.5625 秒,但是我们可以看到生成的音频时长是21秒,看一下后台什么情况

后台计算的视频长度是21.48秒,不对啊,于是我又尝试了一下别的视频,发现都不对劲,时间总是不对

我们倒推算一下,537张,时间21.48秒,那么帧率就是 537/21.48 = 25 FPS

于是我尝试了别的帧率的视频,发现这个mmaudio节点是默认所有视频25帧的,而且不给改,这就很操蛋了,我要是硬件够的话,我还用用16帧???

解决办法

  1. 所有视频都用25FPS

  2. 修改节点

修改节点准备

莫名的激动,之前只是改一改一些导入错误而已,第一次尝试修改,暂时就是准备给他加一个可以输入的参数,用来输入帧率,这样我们就可以调控视频的帧率了

要修改外观,然后代替里面的默认25帧的参数就行,很简单

代码查询

最难的一步,看一下kijia大佬写的插件,先弄懂大部分的代码就行

一步一步来,先了解一下comfyui的插件规定,怎么写才是对的

插件规定骨架

不管是音频节点、图像节点,ComfyUI 的节点都遵循一个固定模板,先记住这个骨架,下面的代码时资料的例子,瞎写的,不是哪个节点

python 复制代码
# 1. 导入必要的库(比如处理音频的mmaudio、ComfyUI的基础类、数值处理的numpy等)
import torch
import mmaudio
from mmaudio.apis import inference_audio
from comfyui.nodes import NodeBase  # 不同版本写法可能略不同,核心是继承基类

# 2. 定义一个节点类(比如"音频特征提取节点"),必须继承ComfyUI的节点基类
class MMAudioFeatureExtractor(NodeBase):
    # 2.1 【关键】定义节点的输入参数(UI上能填的参数都在这)
    @classmethod
    def INPUT_TYPES(cls):
        return {
            "required": {  # 必选参数(UI上标红,必须填)
                "audio_path": ("STRING", {"default": "your_audio.wav", "multiline": False}),  # 字符串类型(音频文件路径)
                "feature_type": (["mfcc", "mel", "spectrogram"], {"default": "mfcc"}),  # 下拉选择框(可选特征类型)
                "sample_rate": ("INT", {"default": 16000, "min": 8000, "max": 48000}),  # 整数类型(采样率)
            },
            "optional": {  # 可选参数(不填也能运行)
                "normalize": ("BOOLEAN", {"default": True}),  # 布尔值(是否归一化)
            }
        }
    
    # 2.2 【关键】定义节点的输出类型(节点能输出什么数据)
    RETURN_TYPES = ("TENSOR", "STRING")  # 输出:张量(特征数据)、字符串(特征类型说明)
    RETURN_NAMES = ("feature_tensor", "feature_info")  # 输出的名字(UI上显示的输出端口名)
    
    # 2.3 【关键】定义节点执行的核心函数名(下面的process方法就是实际干活的)
    FUNCTION = "extract_feature"
    
    # 2.4 【关键】定义节点在UI上的分类(比如"Audio/MMAudio",方便找)
    CATEGORY = "Audio/MMAudio"
    
    # 2.5 【核心逻辑】节点的实际功能(输入参数 → 处理 → 输出结果)
    def extract_feature(self, audio_path, feature_type, sample_rate, normalize=True):
        # 步骤1:加载音频文件(调用mmaudio的方法)
        audio_data, sr = mmaudio.load(audio_path, sr=sample_rate)
        
        # 步骤2:根据选择的特征类型,提取音频特征
        if feature_type == "mfcc":
            feature = mmaudio.features.mfcc(audio_data, sr=sr, normalize=normalize)
        elif feature_type == "mel":
            feature = mmaudio.features.mel_spectrogram(audio_data, sr=sr)
        else:
            feature = mmaudio.features.spectrogram(audio_data, sr=sr)
        
        # 步骤3:把特征转成ComfyUI能传递的张量(PyTorch Tensor)
        feature_tensor = torch.from_numpy(feature)
        
        # 步骤4:准备输出信息
        feature_info = f"提取{feature_type}特征,采样率{sample_rate},形状{feature_tensor.shape}"
        
        # 必须返回:和RETURN_TYPES数量、顺序完全一致的结果
        return (feature_tensor, feature_info)

# 3. 把节点注册到ComfyUI(让UI能识别这个节点)
NODE_CLASS_MAPPINGS = {
    "MMAudioFeatureExtractor": MMAudioFeatureExtractor  # "UI上显示的节点名": 上面定义的类名
}
NODE_DISPLAY_NAME_MAPPINGS = {
    "MMAudioFeatureExtractor": "MMAudio 音频特征提取"  # 更友好的中文显示名
}

上面这个是查的模板,大概就是这样的骨架(理解成必须用这种格式给节点comfyui才会识别到),也就是comfyui给你开放了一套模板,你必须按照这个模板来才可以被comfyui使用

骨架解析

1. 导入库(开头的 import)
  • import torch:ComfyUI 底层用 PyTorch,所有数据(比如音频特征)都要转成 Tensor(张量),所以必须导入;
  • import mmaudio:核心!comfyui-mmaudio 是基于 mmaudio 库做的,所有音频处理(加载、提取特征)都靠它;
  • from comfyui.nodes import NodeBase:继承 ComfyUI 的节点基类,只有继承了,你写的类才是 "ComfyUI 能识别的节点"。
2. 节点类的核心部分(小白重点记)
① INPUT_TYPES(定义输入参数)
  • 这是「UI 上能操作的参数」的定义处,比如你在节点上填 "音频路径"、选 "MFCC 特征"、改 "采样率",都在这定义;
  • 格式说明:
    • "required":必选参数,不填节点跑不了(UI 上会标红);
    • "optional":可选参数,不填也能跑;
    • 每个参数的格式:参数名: (类型, 配置)
      • 类型:"STRING"(字符串,比如文件路径)、"INT"(整数,比如采样率)、"BOOLEAN"(布尔值,True/False)、["选项1","选项2"](下拉选择框);
      • 配置:{"default": 默认值, "min": 最小值, "max": 最大值, "multiline": 是否多行}
② RETURN_TYPES / RETURN_NAMES(定义输出)
  • RETURN_TYPES:节点输出的数据类型,比如"TENSOR"(张量,ComfyUI 里传递数据的核心格式)、"STRING"(字符串)、"AUDIO"(音频,部分版本有专属类型);
  • RETURN_NAMES:给输出端口起名字,方便你在 UI 上看 "这个输出是特征张量,那个是信息"。
③ FUNCTION(指定核心函数)
  • 比如FUNCTION = "extract_feature",意思是:当你点击 "运行" 时,节点会执行extract_feature这个方法(下面定义的 def 函数)。
④ CATEGORY(节点分类)
  • 比如CATEGORY = "Audio/MMAudio",意思是:这个节点会出现在 ComfyUI 的 "Audio" 分类下的 "MMAudio" 子分类里,方便你找。
⑤ 核心方法(比如 extract_feature)
  • 这是节点「实际干活的地方」:接收输入参数 → 调用 mmaudio 做音频处理 → 生成输出;
  • 小白重点看逻辑:
    1. 先加载音频:mmaudio.load(audio_path, sr=sample_rate) → 把音频文件读成 "音频数据 + 采样率";
    2. 再提取特征:根据选的feature_type(比如 mfcc),调用 mmaudio 对应的函数提取特征;
    3. 转格式:把 mmaudio 输出的 numpy 数组转成 PyTorch Tensor(因为 ComfyUI 只认 Tensor);
    4. 返回结果:必须和RETURN_TYPES的数量、顺序完全一致!比如RETURN_TYPES = ("TENSOR", "STRING"),就必须返回(tensor, 字符串)
3. 节点注册(最后两行)
  • NODE_CLASS_MAPPINGS:把你定义的节点类 "注册" 到 ComfyUI,UI 才能显示这个节点;
  • NODE_DISPLAY_NAME_MAPPINGS:给节点起一个 "友好的显示名"(比如中文),不然 UI 上显示的是类名(MMAudioFeatureExtractor),不直观。

上面的太过复杂,当然是一定得看的,我自己总结了一下,根据节点mmaudio的nodes.py为例子(其他节点的文件名字可能不一样,但是一般放在最外层),大概就是:

1. 导入库

这个就是最简单的你要用那些包,python的哪些依赖库,就pip安装的那些,还有自己写的那些文件(核心处理过程)

2.节点的类

你创建一个类MMAudioModelLoader,代表这个节点,然后按照规定定义一些东西就行

INPUT_TYPES看上面的输入类型,对应输入的东西

RETURN_TYPES代表输出的类型,其实就是一个暗号,告诉你我输出的是这个暗号,你要跟我的线连在一起,必须得是一样的暗号才行

这个暗号的名字随便你,只要你不去设置官方设置的一些变成其他类型的输入类型就行(例如INT就是数值类型的输入,就不是连线了)

我们可以直接看看这个节点连接的下一个节点的输入代码,暗号肯定是一样的,至于输出了啥给他,是不用管的,一个数字,一张图片,一个对象,啥都可以(只要符合python代码)

直接搜索这个文件里面的名字定义,肯定有,然后看他对应的类是哪个,马上找到,果真是一样的暗号,天王盖地虎,暗号不对你还连不上的

RETURN_NAMES代表输出的名字,你会发现可以连线出来的哪个名字就跟RETURN_NAMES一样,当然可以定义多个,在括号内继续写就行,用逗号隔开

FUNCTION = "loadmodel"

说明这个类的处理过程就在这个loadmodel方法里面,这里就是怎么读取模型的过程,当然这个方法得写在这个类里面

CATEGORY = "MMAudio"

这个就是规定节点的存放位置,就是你搜索的位置,这里就是放在MMAudio下面,我们直接搜索就能看到了,之前我就纳闷过,有些插件位置跟存放的文件夹不一样,原来是这样,果真还是得直接看代码才行

3.节点注册

简单说就是盖个章,让comfyui官方承认

NODE_CLASS_MAPPINGS 就是映射,里面的节点名字随便你设置,例如MMAudioModelLoader是这个节点的名字,他对应的是绿色的MMAudioModelLoader这个类

我们刚才又在这个类里面把那些什么输入输出啊,要干的事情(方法)全部设置好了,所以这个节点就算弄好了,又给官方承认了,那这个类就搞定了,可以直接在comfyui里面直接用

NODE_DISPLAY_NAME_MAPPINGS 这个就是给这个节点显示的名字,后面的是名字,你设置成"爸爸"都无所谓,只不过到时候会变成这样

ps :NODE_CLASS_MAPPINGS 和 NODE_DISPLAY_NAME_MAPPINGS 这两个不能随便改,官方规定必须使用这两个名字,不然你一改他就不承认了

init.py

这个就是初始化文件了,对应上面的那几个映射,让comfyui能够找到这里

是不是很熟,就是我们刚才定义的那个,然后下面那个all直接一样就行,反正没必要去改,等下又各种问题

就是前面的导入根据你的节点文件名字改就行,这里的是nodes(看你前面的文件名字)

Pyproject TOML

Python 项目的官方配置文件:可以直接理解成这个项目的信息,"项目身份证" + "采购清单"

它的核心作用是:告诉 ComfyUI / Python 编译器 "这个插件是谁、叫什么、需要什么工具才能运行"

感觉像xml的配置文件啊,反正差不多

可以看到上面写了一些

节点名字(name)、节点描述说明(description)、版本号(version)、协议(license)、仓库的地址(Repository)、仓库发布者也就是作者(PublisherId)等等

最重要的就是这个dependencies------这个告诉我们需要什么依赖库才能使用这个节点,就跟那个requirement差不多

太长了,休息一下,下一篇继续

相关推荐
紫丁香3 小时前
AutoGen详解一
后端·python·flask
FreakStudio3 小时前
不用费劲编译ulab了!纯Mpy矩阵micronumpy库,单片机直接跑
python·嵌入式·边缘计算·电子diy
Sendingab4 小时前
2026 年 AI 数字人口播新趋势:智能体 Agent 将如何重构短视频内容生产与营销
人工智能·重构·音视频
清水白石0085 小时前
Free-Threaded Python 实战指南:机遇、风险与 PoC 验证方案
java·python·算法
飞Link5 小时前
具身智能核心架构之 Python 行为树 (py_trees) 深度剖析与实战
开发语言·人工智能·python·架构
桃气媛媛6 小时前
Pycharm常用快捷键
python·pycharm
郭泽斌之心6 小时前
Fay数字人视频播放器
音视频
Looooking7 小时前
Python 之获取安装包所占用磁盘空间大小
python
WenGyyyL7 小时前
ColBERT论文研读——NLP(IR)里程碑之作
人工智能·python·语言模型·自然语言处理