MuScriptor 转多乐器混音,先单独跑一条贝斯轨看对齐

文章导读
MuScriptor 拿到手后,建议先单独跑一条贝斯轨看对齐。贝斯是单声部、音高稳定、起音清晰,出问题时容易区分是输入格式、权重加载还是节拍对齐的锅;而整首歌一次喂进去,分轨之间互相污染了,你也不知道该从哪一步回头检查。先用最小样本把链路跑通,再扩到整段混音,误差才留在可解释的范围内。
📋 目录
  1. Ⅰ 在仓库说明里确认输入音频的格式与乐器覆盖范围
  2. Ⅱ 导出一条贝斯干音,用最小推理脚本跑通一次
  3. Ⅲ 把输出 MIDI 拖进 DAW,逐小节比对拍点
  4. Ⅳ 单轨稳定后再喂整段混音,检查是否出现串音
  5. Ⅴ 记录一次试跑的耗时与显存峰值
A A

MuScriptor 拿到手后,建议先单独跑一条贝斯轨看对齐。贝斯是单声部、音高稳定、起音清晰,出问题时容易区分是输入格式、权重加载还是节拍对齐的锅;而整首歌一次喂进去,分轨之间互相污染了,你也不知道该从哪一步回头检查。先用最小样本把链路跑通,再扩到整段混音,误差才留在可解释的范围内。

把一条贝斯干音当作最小验证样本:先按仓库说明确认输入采样率、声道与乐器覆盖范围,用最小脚本跑通“加载权重→读音频→前向推理→写 MIDI”,再拖进 DAW 逐小节量拍点偏移。单轨能稳定对齐,才值得把整段混音喂进去并逐轨听串音。边界是:单轨都对不齐时,多轨结果不可信,应先回到格式与推理配置排查。

在仓库说明里确认输入音频的格式与乐器覆盖范围

先别急着写推理代码,把 README 和配置文件里的输入约束读一遍。需要确认的通常是这几项:期望采样率、单声道还是立体声、单次推理的最长片段或窗口长度、是否内部重采样、以及模型声明的乐器覆盖范围(贝斯是否在列、低音区是否被截断)。这些字段以仓库 README 和 config 中的实际键名为准,示例里的键名只能当占位,不要拿它反推具体数值。

拿到贝斯干音后,先看它本身的实际参数,再决定要不要预处理:

ffprobe -v error -show_entries stream=sample_rate,channels,channel_layout,codec_name,duration \
  -of default=noprint_wrappers=1 bass.wav
soxi bass.wav   # 装了 sox 时,可直接看 Sample Rate / Channels / Duration

如果实际采样率和配置不一致,用 sox 或 ffmpeg 转成仓库要求的格式再喂,比在代码里临时补重采样更容易复现问题。时长上,建议第一轮裁一小段(比如一段主歌或副歌),避免整首跑完才发现格式错了。

MuScriptor 转多乐器混音,先单独跑一条贝斯轨看对齐

导出一条贝斯干音,用最小推理脚本跑通一次

这一步的目标不是跑出好结果,而是用最少变量确认环境、权重和写出流程都是通的。可以按下面这个通用骨架写一个最小脚本,函数名和类名以仓库实际提供的为准,下面只是占位:

import soundfile as sf
from muscriptor_pkg import load_model   # 模块路径以仓库为准

model = load_model(ckpt_path, device='cuda')
audio, sr = sf.read('bass.wav', dtype='float32')
notes = model.transcribe(audio, sr)      # 占位:返回谱面对象或 note 列表
notes.write('bass.mid')                  # 占位:或用仓库自带的写出函数

放在仓库示例脚本同级目录执行,占位运行命令形如:

python run_infer.py `--config` configs/infer.yaml `--audio` bass.wav `--out` bass.mid

跑完先确认三件事:命令行没有静默吞掉异常、生成的 MIDI 文件非空、用任意 MIDI 查看器能看到音符数量在合理范围。如果 MIDI 是空的,先查音频是否被读成全静音、采样率是否被误判,再查权重路径。

把输出 MIDI 拖进 DAW,逐小节比对拍点

在 DAW 里新建工程,按已知曲速设好 BPM 并关掉量化,把干音和转出的 MIDI 放在同一时间起点,然后逐小节看。第一个小节先量固定偏移:如果整条 MIDI 相对干音稳定地早或晚若干毫秒,且后面各小节偏移量基本一致,这是可补偿的固定偏移,整体挪一下轨或调整起始时间即可,不用重跑。

MuScriptor 转多乐器混音,先单独跑一条贝斯轨看对齐

接着看第 5、9、13 小节。如果偏移量随小节数逐渐变大,说明问题在速度或时间换算上,优先查 BPM 是否与工程一致、模型是否按片段切分后拼接、以及配置里的 hop 或帧移参数。如果偏移忽早忽晚、没有规律,更可能是起音检测本身不稳定:连续的贝斯长音被切成多个短音,或滑音、闷音位置判错,这类问题靠挪轨解决不了,需要回头看音频质量和模型对低音区的处理。

节拍网格的影响也要分开看:工程 BPM 设错会让所有音符看起来“按比例漂移”,这和模型误差很像。改一次 BPM 重新对齐,就能把两种原因区分开。

单轨稳定后再喂整段混音,检查是否出现串音

单轨对齐可接受后,再切一段混音试跑,第一轮不建议直接上整首歌,先用十几秒到几十秒的密集段落。输入上注意:不要削波的素材、少加混响和重压缩、按仓库要求决定给单声道还是立体声,混音电平不要贴顶。如果仓库支持指定目标乐器,就在推理时明确指定贝斯,而不是让它自由分配。

MuScriptor 转多乐器混音,先单独跑一条贝斯轨看对齐

逐轨独奏时,判断串音主要靠听感和音符形态:贝斯轨里冒出和弦音或三度叠置、出现明显的鼓瞬态、音符数量比干音明显偏多、本该持续的根音被切碎成很多短音,都属于可疑信号。排查顺序建议是:先换成更短更干净的片段复现;再把同一段单独一条贝斯喂进去对比输出;确认是混音引入的问题后,再考虑调整推理参数或做前置分轨;最后才判断是不是要放弃整段输入,改成分轨处理后合并。每一步都用同一段素材对比,避免换素材后结论失真。

记录一次试跑的耗时与显存峰值

试跑时把规模相关的指标记下来,后面批量处理才知道能一次跑多长。建议记录的项:音频时长、片段长度或窗口设置、总耗时(墙钟时间)、显存峰值、最大显存占用时的批大小、GPU 型号、输出 MIDI 的音符数。同一段素材换不同片段长度再跑一次,就能看出耗时随长度怎么增长。

/usr/bin/time -v python run_infer.py `--config` configs/infer.yaml \
  `--audio` mix.wav `--out` mix.mid 2> time.log

nvidia-smi `--query-gpu`=memory.used,memory.total,utilization.gpu \
  `--format`=csv -l 1

# 若推理脚本里能加代码,可在前后打点
torch.cuda.reset_peak_memory_stats()
# ... 推理 ...
print(torch.cuda.max_memory_allocated() / 1024**2, 'MiB')

nvidia-smi 的轮询只能看到采样时刻的占用,峰值以脚本内的 max_memory_allocated 为准;两者对不上时,差额通常来自进程外的其他占用。把耗时和显存峰值记在同一张表里,后续设置批量上限时直接查表,不必每次靠猜。