修改设备端对接
This commit is contained in:
118
talkingq-url/utils/audio_denoiser.py
Normal file
118
talkingq-url/utils/audio_denoiser.py
Normal file
@@ -0,0 +1,118 @@
|
||||
import noisereduce as nr
|
||||
import soundfile as sf
|
||||
import librosa
|
||||
import numpy as np
|
||||
import os
|
||||
|
||||
def normalize_audio_volume(audio, original_rms=None, target_dbfs=-20):
|
||||
"""
|
||||
对音频进行音量归一化
|
||||
|
||||
参数:
|
||||
audio: 音频数据
|
||||
original_rms: 原始音频的RMS值(可选)
|
||||
target_dbfs: 目标音量级别(dBFS)
|
||||
|
||||
返回:
|
||||
归一化后的音频
|
||||
"""
|
||||
# 计算当前音频的RMS
|
||||
current_rms = np.sqrt(np.mean(audio**2))
|
||||
|
||||
# 方法1:恢复到原始音量水平
|
||||
if original_rms is not None and original_rms > 0:
|
||||
scale_factor = original_rms / current_rms
|
||||
normalized_audio = audio * scale_factor
|
||||
print(f"音量恢复: 缩放因子 {scale_factor:.2f}")
|
||||
|
||||
# 方法2:基于目标dBFS的音量归一化
|
||||
else:
|
||||
# 计算当前音频的dBFS
|
||||
current_dbfs = 20 * np.log10(current_rms / (np.max(np.abs(audio)) + 1e-8))
|
||||
|
||||
# 计算需要的增益
|
||||
gain_db = target_dbfs - current_dbfs
|
||||
gain_linear = 10 ** (gain_db / 20)
|
||||
|
||||
normalized_audio = audio * gain_linear
|
||||
print(f"音量归一化: 增益 {gain_db:.1f} dB, 缩放因子 {gain_linear:.2f}")
|
||||
|
||||
# 防止削波(clipping)
|
||||
max_val = np.max(np.abs(normalized_audio))
|
||||
if max_val > 0.95: # 如果接近最大值1.0
|
||||
normalized_audio = normalized_audio * 0.95 / max_val
|
||||
print("已应用防削波处理")
|
||||
|
||||
return normalized_audio
|
||||
def reduce_background_noise(audio_path, output_path=None, use_default_noise=True,
|
||||
noise_path='assets/audio/noise_sample.wav', noise_start=0.1, noise_end=0.5,
|
||||
normalize_volume=True, target_dbfs=-20):
|
||||
"""
|
||||
使用noisereduce库去除背景噪声
|
||||
|
||||
参数:
|
||||
audio_path: 音频文件路径
|
||||
output_path: 输出文件路径(可选)
|
||||
use_default_noise: 是否使用默认噪声样本
|
||||
noise_path: 默认噪声样本路径
|
||||
noise_start: 噪声样本开始时间(秒)(仅当use_default_noise=False时使用)
|
||||
noise_end: 噪声样本结束时间(秒)(仅当use_default_noise=False时使用)
|
||||
"""
|
||||
|
||||
# 加载音频
|
||||
y, sr = librosa.load(audio_path, sr=None)
|
||||
|
||||
print(f"音频信息: 时长 {len(y)/sr:.2f}秒, 采样率 {sr}Hz")
|
||||
|
||||
# 提取或加载噪声样本
|
||||
if use_default_noise:
|
||||
try:
|
||||
noise_path = os.path.join("assets", "audio", "noise_sample.wav")
|
||||
noise_clip, noise_sr = librosa.load(noise_path, sr=None)
|
||||
# 检查采样率是否匹配
|
||||
if noise_sr != sr:
|
||||
print(f"警告: 噪声样本采样率({noise_sr}Hz)与音频采样率({sr}Hz)不匹配")
|
||||
# 重采样噪声样本以匹配音频采样率
|
||||
noise_clip = librosa.resample(noise_clip, orig_sr=noise_sr, target_sr=sr)
|
||||
print("已对噪声样本进行重采样以匹配音频采样率")
|
||||
except FileNotFoundError as e:
|
||||
print(f"错误: {e}")
|
||||
print("将使用当前音频提取噪声样本")
|
||||
use_default_noise = False
|
||||
|
||||
if not use_default_noise:
|
||||
# 从当前音频提取噪声样本
|
||||
noise_start_sample = int(noise_start * sr)
|
||||
noise_end_sample = int(noise_end * sr)
|
||||
noise_clip = y[noise_start_sample:noise_end_sample]
|
||||
print(f"使用当前音频的 {noise_end-noise_start:.2f}秒 噪声样本进行降噪")
|
||||
else:
|
||||
print(f"使用默认噪声样本进行降噪,噪声长度: {len(noise_clip)/sr:.2f}秒")
|
||||
|
||||
# 应用降噪
|
||||
reduced_noise = nr.reduce_noise(
|
||||
y=y,
|
||||
sr=sr,
|
||||
y_noise=noise_clip,
|
||||
prop_decrease=0.95, # 降噪比例
|
||||
n_fft=1024,
|
||||
win_length=1024,
|
||||
hop_length=256,
|
||||
n_std_thresh_stationary=1.5,
|
||||
stationary=True
|
||||
)
|
||||
|
||||
# 记录原始音频的音量(RMS)
|
||||
original_rms = np.sqrt(np.mean(y**2))
|
||||
print(f"原始音频RMS: {original_rms:.4f}")
|
||||
# 音量归一化处理
|
||||
if normalize_volume:
|
||||
normalize_audio_volume(reduced_noise, original_rms, target_dbfs)
|
||||
|
||||
# 保存结果
|
||||
if output_path:
|
||||
sf.write(output_path, reduced_noise, sr)
|
||||
print(f"降噪后的音频已保存至: {output_path}")
|
||||
|
||||
if __name__ == "__main__":
|
||||
reduce_background_noise('test/TalkingQ_XQSN00001004_eba844b5.mp3', 'test/denoised2.mp3')
|
||||
Reference in New Issue
Block a user