如何在语音音频文件中检测非语音高声信号的起止位置?
音频非语音高声信号起止检测方案
核心逻辑
你要的信号需要同时满足非语音、响度超过语音平均水平两个条件,实现上拆分两步走即可:先做语音/非语音区域区分,再做响度阈值筛选。
分步实现方案
- 音频预处理:将音频统一转成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
相关产品推荐
相关产品推荐

