AudioGen是Meta开源的文本生成音频模型,能根据一句自然语言描述合成各种音效和环境音。不过上手之后很快会发现一个问题:默认生成的音频往往只有几秒钟,拿来做游戏背景音、视频氛围音明显不够长。这篇文章就围绕时长展开,先说清楚duration参数怎么用,再介绍几种实用的拼接延长技巧,附上完整代码。

一、AudioGen的时长控制原理与duration参数设置
AudioGen官方仓库audiocraft提供了两个主要接口:命令行工具和Python API。时长控制的核心参数是duration,单位为秒。在Python API中,它通过AudioGen.get_generation_preceding_tokens相关的机制换算成token数量——模型内部以每秒75个token的速率编码音频,因此生成的长度本质上由token数决定。
直接把duration设大就行了吗?并不是。AudioGen基于的语言模型在推理时受限于最大上下文长度,默认配置下生成的音频通常在10秒以内比较稳定,强行设置30秒可能出现生成失败、结果被截断或质量明显下降。在调用generate时,可以通过传入不同参数观察行为差异:
from audiocraft.models import AudioGen
model = AudioGen.get_pretrained_model('facebook/audiogen-medium')
model.set_generation_params(duration=8) # 生成8秒音频
wav = model.generate(
['birds singing in a quiet forest'],
progress=True
)另一个容易被忽略的点是批处理。当你一次生成多条音频时,所有样本共享同一个duration设置,无法在同一次调用里给不同条目指定不同时长。如果需要长短不一的音效,要么分多次调用,要么统一生成长时长后再裁剪,后者在素材复用上反而更灵活。
还要注意显存占用:duration越长,中间token序列越长,注意力机制的显存开销呈平方级增长。8秒和10秒的差距在小显存卡上可能就是能否跑通的区别。遇到显存不足,可以尝试device='cuda'换为CPU推理(速度慢但能出结果),或者降低模型规模。
二、分段生成加交叉淡入淡出拼接
要获得超过10秒的音频,最可靠的方案是多次生成分段音频再拼接。直接首尾相连往往会在接缝处产生明显的爆音或断裂感,因为两段音频的相位和波形在边界上不连续。解决办法是交叉淡化(crossfade):取前一段的尾部和后一段的开头做重叠区域,重叠区内前段音量线性下降、后段线性上升。
import numpy as np
import torch
def crossfade_concat(segments, sr, fade_sec=0.5):
"""将多段音频用交叉淡化拼接成一条长音频"""
fade_len = int(sr * fade_sec)
result = segments[0]
for seg in segments[1:]:
# 前一段尾部与当前段开头做等长重叠
overlap = result[-fade_len:] * np.linspace(1, 0, fade_len) \
+ seg[:fade_len] * np.linspace(0, 1, fade_len)
result = np.concatenate([result[:-fade_len], overlap, seg[fade_len:]])
return result
# 每段生成6秒,最后拼成约20秒
segments = []
for _ in range(4):
wav = model.generate(['gentle rain on a wooden roof'], progress=False)
seg = wav[0, 0].cpu().numpy()
segments.append(seg)
long_audio = crossfade_concat(segments, sr=16000)
print('拼接后总时长约', len(long_audio) / 16000, '秒')拼接方案的关键在于prompt的设计。如果四段使用同一个描述词,模型每次生成的具体内容仍然不同(比如鸟叫声的节奏、雨声的密度),拼接后听起来像同一场景的自然变化,效果反而比强行一次生成30秒更稳定。对于持续性的环境音(雨声、风声、篝火声),淡化时长建议0.5到1秒;对于节奏感强的音效(脚步、键盘敲击),淡化时长应缩短到0.2秒以内,否则会糊掉节拍。
这个方案的缺点是接缝处偶尔仍能听出细微差异,尤其是包含明显音高变化的段落。此时可以借助专业的音频处理库进一步处理,比如用pydub做更精细的等功率淡化,或用librosa对拼接点附近的频谱做平滑,都能进一步弱化接缝感。
三、循环播放与层叠叠加营造长氛围
除了拼接不同段落,另一种思路是短音频循环。对于本身变化不大的环境音,一段8秒的高质量素材循环播放,听众几乎察觉不到边界。提升循环自然度的技巧是让首尾平滑衔接:把音频末尾复制到开头前面,做一次交叉淡化后再裁掉多余部分,得到首尾波形连续的“无缝循环”素材。
import soundfile as sf
def seamless_loop(audio, sr, fade_sec=0.8):
fade_len = int(sr * fade_sec)
tail = audio[-fade_len:]
head = audio[:fade_len]
# 用尾部接在开头前做淡化,得到首尾连续的循环体
blended = tail * np.linspace(1, 0, fade_len) + head * np.linspace(0, 1, fade_len)
loop = np.concatenate([blended, audio[fade_len:-fade_len]])
return loop
# 导出无缝循环素材,播放器里设置循环即可无限延长
sf.write('rain_loop.wav', seamless_loop(long_audio, 16000), 16000)第三种增强手段是层叠叠加。取同一段或不同段的环境音,各自加一个随机的时间偏移和轻微的音量差异后混合,可以掩盖单段循环中的可预测模式。叠加层数两到三层即可,太多层会推高整体响度导致削波,记得在混合后做归一化:
def layer_mix(segments, total_len):
mixed = np.zeros(total_len)
for seg in segments:
offset = np.random.randint(0, total_len // 3)
padded = np.roll(seg, offset) # 随机偏移
mixed[:len(padded)] += padded * (0.5 + 0.3 * np.random.rand())
peak = np.max(np.abs(mixed))
return mixed / peak * 0.9 # 归一化防止削波三种方案如何选择?如果需要内容有明确变化(比如雷声由远及近),用分段拼接;如果只是持续氛围,无缝循环加层叠叠加性价比最高,素材体积小且可以任意延长;要求最严格的场景可以组合使用:先分段拼接得到基础长音频,再导出为无缝循环素材,最后按需叠加。掌握这套流程后,AudioGen的时长限制基本不再是项目里的障碍。