You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在语音音频文件中检测非语音高声信号的起止位置?

音频非语音高声信号起止检测方案

核心逻辑

你要的信号需要同时满足非语音、响度超过语音平均水平两个条件,实现上拆分两步走即可:先做语音/非语音区域区分,再做响度阈值筛选。

分步实现方案

  • 音频预处理:将音频统一转成16kHz单声道格式,按10~30ms为一帧、50%重叠率切分,方便后续逐帧计算特征。
  • 语音区域标记:使用成熟的VAD(语音活动检测)工具识别所有人类语音的起止时间戳,直接过滤掉语音区域,剩下的片段作为待检测的候选池。常用的轻量工具包括WebRTC VAD、Silero VAD,不需要额外训练数据就能拿到不错的识别效果。
  • 计算语音平均响度:对所有识别出来的语音片段,逐帧计算RMS(均方根)响度,取所有语音帧响度的中位数作为基准阈值,你可以根据实际需求给阈值加10%~30%的上浮,减少误检概率。
  • 筛选目标信号:遍历所有非语音候选区域,逐帧计算响度,把连续多帧响度超过基准阈值的片段摘出,再过滤掉时长小于50ms的极短干扰信号,最终输出的就是符合要求的信号起止时间。

参考代码片段(Python)

import librosa
import torch
# 依赖安装:pip install librosa torchaudio silero-vad

# 加载音频并统一参数
SAMPLING_RATE = 16000
audio_path = "你的音频文件路径.wav"
wav, sr = librosa.load(audio_path, sr=SAMPLING_RATE, mono=True)

# 加载VAD模型识别语音片段
vad_model, utils = torch.hub.load(repo_or_dir='snakers4/silero-vad', model='silero_vad', force_reload=False)
get_speech_timestamps, _, _, _, _ = utils
speech_ts = get_speech_timestamps(wav, vad_model, sampling_rate=SAMPLING_RATE)

# 计算语音段平均响度
speech_rms_list = []
for seg in speech_ts:
    seg_audio = wav[seg["start"]:seg["end"]]
    seg_rms = librosa.feature.rms(y=seg_audio)[0].mean()
    speech_rms_list.append(seg_rms)
avg_speech_loudness = sum(speech_rms_list) / len(speech_rms_list)
# 阈值上浮20%减少误检
threshold = avg_speech_loudness * 1.2

# 检测非语音区域的高声片段
# 先标记所有语音帧为已排除
is_speech_frame = [False] * len(wav)
for seg in speech_ts:
    for i in range(seg["start"], seg["end"]):
        is_speech_frame[i] = True

high_noise_segs = []
current_start = None
frame_step = int(SAMPLING_RATE * 0.01) # 10ms步长

for i in range(0, len(wav), frame_step):
    if is_speech_frame[i]:
        if current_start is not None:
            # 结束当前非语音高声段
            duration = (i - current_start) / SAMPLING_RATE
            if duration > 0.05: # 过滤小于50ms的干扰
                high_noise_segs.append((current_start/SAMPLING_RATE, i/SAMPLING_RATE))
            current_start = None
        continue
    # 计算当前帧响度
    frame = wav[i:i+frame_step]
    frame_rms = librosa.feature.rms(y=frame)[0][0]
    if frame_rms > threshold:
        if current_start is None:
            current_start = i
    else:
        if current_start is not None:
            duration = (i - current_start) / SAMPLING_RATE
            if duration > 0.05:
                high_noise_segs.append((current_start/SAMPLING_RATE, i/SAMPLING_RATE))
            current_start = None

# 输出结果
print("符合要求的非语音高声信号起止时间(单位:秒):")
for start, end in high_noise_segs:
    print(f"{start:.2f} - {end:.2f}")

优化建议

  • 针对鼠标点击、物体敲击这类极短信号,可以把切帧步长改到5ms,提高时间分辨率,避免漏检
  • 如果需要进一步区分短音乐和其他音效,可以给筛选出来的片段加一个轻量音频分类头做二次校验
  • 音频背景噪音较大的场景,可以先做降噪预处理再跑VAD,减少语音识别的误差

内容的提问来源于stack exchange,提问作者Damn Vegetables

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.05 11:06:00