问题描述
fireredvad/core/audio_feat.py 中 AudioFeat.extract() 方法的 elif 分支,对 tuple 的解包顺序是 soundfile 风格的 (data, sr),但项目内其他位置统一使用 (sr, data) 格式。如果有人传入 (sample_rate, wav_np) 格式的 tuple,sample_rate 和 wav_np 会被互换。
问题代码
# fireredvad/core/audio_feat.py, AudioFeat.extract()
def extract(self, audio):
if isinstance(audio, str):
wav_np, sample_rate = sf.read(audio, dtype="int16") # soundfile 返回 (data, sr)
elif isinstance(audio, (list, tuple)):
wav_np, sample_rate = audio # ← 解包顺序是 (data, sr)
else:
wav_np = audio
sample_rate = 16000
项目内的格式约定
项目内其他位置统一使用 (sample_rate, wav_np) 格式:
| 位置 |
代码 |
格式 |
fireredasr2system.py:71 |
batch_asr_wav.append((sample_rate, wav_segment)) |
(sr, data) |
asr_feat.py:34 |
for (sample_rate, wav_np), path, uttid in zip(...) |
(sr, data) |
asr_feat.py KaldifeatFbank.__call__ |
sample_rate, wav_np = wav |
(sr, data) |
audio_feat.py KaldifeatFbank.__call__ |
sample_rate, wav_np = wav |
(sr, data) |
elif 分支的 wav_np, sample_rate = audio 与上述约定方向相反。
当前影响
暂无实际影响——所有现有调用方传给 AudioFeat.extract() 的参数都是 str(走 if 分支)或 np.ndarray(走 else 分支),elif 分支目前是死代码:
| 调用方 |
传参 |
走的分支 |
vad.py:68 vad.detect(audio) |
str 路径 |
if |
aed.py:69 aed.detect(audio) |
str 路径 |
if |
stream_vad.py:77 extract(audio_frame) |
np.ndarray |
else |
stream_vad.py:89 extract(audio_chunk) |
np.ndarray |
else |
stream_vad.py:107 extract(audio) |
str 或 np.ndarray |
if/else |
fireredasr2system.py:54 vad.detect(wav_path) |
str 路径 |
if |
潜在风险
如果未来有调用方以 (sample_rate, wav_np) 格式的 tuple 传入(与项目约定一致),elif 分支会互换 sample_rate 和 wav_np:
wav_np 实际拿到的是整数 16000
sample_rate 实际拿到的是 numpy 数组
assert sample_rate == 16000 会失败(numpy 数组 != 16000),报错反而掩盖了根因
建议修复
将 elif 解包顺序统一为 (sample_rate, wav_np):
elif isinstance(audio, (list, tuple)):
sample_rate, wav_np = audio # 统一为 (sr, data) 格式
这需要同步更新 elif 分支上游可能传 tuple 的调用方,确保它们也遵循 (sample_rate, wav_np) 格式。
同类问题排查
项目中还有一个类似的历史遗留不一致:AudioFeat.extract 的 if 分支使用 sf.read() 返回的 (data, sr) 格式,而 KaldifeatFbank.__call__ 返回的也是 (sr, data) 格式。建议整个项目统一 tuple 约定为 (sample_rate, wav_np),与 kaldi 生态的 (sr, wav) 惯例一致。
问题描述
fireredvad/core/audio_feat.py中AudioFeat.extract()方法的 elif 分支,对 tuple 的解包顺序是 soundfile 风格的(data, sr),但项目内其他位置统一使用(sr, data)格式。如果有人传入(sample_rate, wav_np)格式的 tuple,sample_rate 和 wav_np 会被互换。问题代码
项目内的格式约定
项目内其他位置统一使用
(sample_rate, wav_np)格式:fireredasr2system.py:71batch_asr_wav.append((sample_rate, wav_segment))(sr, data)asr_feat.py:34for (sample_rate, wav_np), path, uttid in zip(...)(sr, data)asr_feat.pyKaldifeatFbank.__call__sample_rate, wav_np = wav(sr, data)audio_feat.pyKaldifeatFbank.__call__sample_rate, wav_np = wav(sr, data)elif 分支的
wav_np, sample_rate = audio与上述约定方向相反。当前影响
暂无实际影响——所有现有调用方传给
AudioFeat.extract()的参数都是str(走 if 分支)或np.ndarray(走 else 分支),elif 分支目前是死代码:vad.py:68vad.detect(audio)aed.py:69aed.detect(audio)stream_vad.py:77extract(audio_frame)stream_vad.py:89extract(audio_chunk)stream_vad.py:107extract(audio)fireredasr2system.py:54vad.detect(wav_path)潜在风险
如果未来有调用方以
(sample_rate, wav_np)格式的 tuple 传入(与项目约定一致),elif 分支会互换 sample_rate 和 wav_np:wav_np实际拿到的是整数 16000sample_rate实际拿到的是 numpy 数组assert sample_rate == 16000会失败(numpy 数组 != 16000),报错反而掩盖了根因建议修复
将 elif 解包顺序统一为
(sample_rate, wav_np):这需要同步更新 elif 分支上游可能传 tuple 的调用方,确保它们也遵循
(sample_rate, wav_np)格式。同类问题排查
项目中还有一个类似的历史遗留不一致:
AudioFeat.extract的 if 分支使用sf.read()返回的(data, sr)格式,而KaldifeatFbank.__call__返回的也是(sr, data)格式。建议整个项目统一 tuple 约定为(sample_rate, wav_np),与 kaldi 生态的(sr, wav)惯例一致。