2026/4/17 4:47:59
网站建设
项目流程
网站首页的功能,小白建站软件,贵阳市做网站的公司有哪些,10个产品设计成功案例前言#xff1a;大家好#xff0c;在上一篇文章里面#xff0c;我们已经把webrtc的apm降噪工程代码已经移植到rk3568上#xff0c;今天就开始从最简单的音频降噪NS工程代码来学习音频降噪的原理。噪声的分类#xff1a;在讲解代码实践之前#xff0c;首先我们需要了解噪声…前言大家好在上一篇文章里面我们已经把webrtc的apm降噪工程代码已经移植到rk3568上今天就开始从最简单的音频降噪NS工程代码来学习音频降噪的原理。噪声的分类在讲解代码实践之前首先我们需要了解噪声的分类虽然我们都知道噪声是啥但是在不同场景的噪声处理的手段会有差异。噪声分两大类1、稳态噪声Stationary Noise2、非稳态噪声Non-stationary Noise稳态噪声稳态噪声就是“长期存在、变化缓慢的噪声”它的能量谱频谱随时间变化很小。常见例子比如说噪声类型是否稳态解释空调噪声稳态“呼呼”持续不变风扇噪声稳态基本恒定频率电脑电流声稳态高频持续“滋滋”车内发动机怠速稳态频谱变化缓慢服务器机房噪声稳态持续背景噪声这些噪声通常频谱平滑能量分布稳定变化极小非稳态噪声指短时突发、变化快、频谱不稳定的噪声它的能量和频谱随时间剧烈变化。 比如说噪声类型是否非稳态原因键盘敲击声非稳态高瞬态能量门关上的“砰”非稳态爆发式冲击撞击、敲桌子非稳态极短时冲击波塑料袋、纸张摩擦非稳态随机频率变化讲话中的爆破音P/K瞬态高频瞬态声儿童尖叫声变化快非周期不稳定特点瞬态transient不可预测持续时间极短几毫秒能量突发式增大对于这种非稳态噪声处理是比较难处理的在后续的文章里面我们再详细介绍这块。常见降噪处理算法和处理流程介绍噪声处理一句话来说就是把语音信号里面的噪声去除掉留下纯净的语音信号即可。常见的语音降噪算法有我这里介绍的是单通道的处理算法而且是大概概括一下本篇文章暂时不做详细的介绍1、谱减法2、维纳滤波法3、基于最大似然(ML)、最大后验(MAP)、最小均方估计(MMSE)的统计模型法4、贝叶斯估计法5、基于特征值和奇异值分解的子空间法6、音频机器学习模型代表算法RNNoise实用、轻量级 DTLN高质量 DeepFilterNet SEGAN DeepConv-TasNet DemucsRNNoise(基于RNN实时降噪)开源地址https://github.com/xiph/rnnoise?utm_sourcechatgpt.comDTLN(基于双信号转换 LSTM 网络),开源地址:https://github.com/breizhn/DTLN?utm_sourcechatgpt.comDeepFilterNet(深度多帧过滤器实时优化),开源地址https://github.com/Rikorose/DeepFilterNet?utm_sourcechatgpt.comwebrtc降噪处理流程在讲解webrtc中的降噪代码之前我们要先了解一下webrtc中降噪的总体流程1、帧分割10 ms2、Hann 窗函数3、FFT分为几个 sub-band4、噪声能量估计Min-statistics 或 MCRA5、计算 SNR信噪比6、计算 Wiener 增益gain SNR / (SNR 1)7、应用增益 低 SNR吵噪→ 小增益 高 SNR有人声→ 保留语音8、iFFT9、重建时域信号10ms PCM → FFT → 噪声估计 → Wiener 增益 → 降噪频谱 → iFFT → 重建 PCM帧分割10msFrame Splitting为什么要分帧这个肯定是第一眼看到你很疑惑原因如下音频信号是连续的流但降噪算法尤其频域算法必须一次处理一小段。为什么 10ms因为语音信号 10ms 内基本视为“平稳”stationaryFFT 需要固定窗口长度10ms 延迟几乎听不出来实时处理用分帧就是把“长波形”切成一页页的小段来处理。WebRTC 规定这个是原文// APM processes audio in chunks of about 10 ms. See GetFrameSize() for // details. static constexpr int kChunkSizeMs 10; // Returns floor(sample_rate_hz/100): the number of samples per channel used // as input and output to the audio processing module in calls to // ProcessStream, ProcessReverseStream, AnalyzeReverseStream, and // GetLinearAecOutput. // // This is exactly 10 ms for sample rates divisible by 100. For example: // - 48000 Hz (480 samples per channel), // - 44100 Hz (441 samples per channel), // - 16000 Hz (160 samples per channel). // // Sample rates not divisible by 100 are received/produced in frames of // approximately 10 ms. For example: // - 22050 Hz (220 samples per channel, or ~9.98 ms per frame), // - 11025 Hz (110 samples per channel, or ~9.98 ms per frame). // These nondivisible sample rates yield lower audio quality compared to // multiples of 100. Internal resampling to 10 ms frames causes a simulated // clock drift effect which impacts the performance of (for example) echo // cancellation. static int GetFrameSize(int sample_rate_hz) { return sample_rate_hz / 100; }APMAudio Processing Module音频处理模块以约 10 毫秒为一个音频块来进行处理。具体细节请参阅 GetFrameSize() 函数。kChunkSizeMs 10每个处理块的固定时长为 10 毫秒。GetFrameSize() 的作用 返回 floor(sample_rate_hz / 100) 的结果。 这个值表示在调用以下 APM 函数时每个声道要输入 / 输出的采样点数量ProcessStream() ProcessReverseStream() AnalyzeReverseStream() GetLinearAecOutput()如果采样率能够被 100 整除那么计算出来的值就与 10ms 的音频长度完全一致。比如48000 Hz → 每声道 480 个采样点等于 10ms44100 Hz → 每声道 441 个采样点等于 10ms16000 Hz → 每声道 160 个采样点等于 10ms如果采样率不能被 100 整除那么得到的帧长度只是“接近” 10ms而不是严格 10ms。比如22050 Hz → 每声道 220 个采样点≈ 9.98ms11025 Hz → 每声道 110 个采样点≈ 9.98ms这些不能整除 100 的采样率相比那些整百采样率会导致更低的音频处理质量。 因为 APM 内部必须将其重采样为严格 10ms 的帧长度这会产生一种类似“时钟漂移clock drift”的效应并且会影响某些算法的性能例如回声消除 Echo Cancellation。GetFrameSize() 的具体实现非常简单 只返回 sample_rate_hz / 100也即采样率除以 100。这个结果就是 10 毫秒音频所包含的采样点数量。static int GetFrameSize(int sample_rate_hz) { return sample_rate_hz / 100; }其他环节我们详细来看源代码来解读这里暂时介绍第一个。webrtc降噪代码工程下面是一个最简单的降噪代码工程// Build AudioProcessing rtc::scoped_refptrwebrtc::AudioProcessing apm webrtc::AudioProcessingBuilder().Create(); webrtc::AudioProcessing::Config cfg apm-GetConfig(); cfg.high_pass_filter.enabled opt.hpf; cfg.noise_suppression.enabled true; // Map NS level if (opt.ns low) cfg.noise_suppression.level webrtc::AudioProcessing::Config::NoiseSuppression::kLow; elseif (opt.ns moderate) cfg.noise_suppression.level webrtc::AudioProcessing::Config::NoiseSuppression::kModerate; else cfg.noise_suppression.level webrtc::AudioProcessing::Config::NoiseSuppression::kHigh; // AGC2 (recommended over AGC1 for most apps) cfg.gain_controller2.enabled opt.agc2; cfg.gain_controller2.adaptive_digital.enabled opt.agc2; // VAD //cfg.voice_detection.enabled opt.vad; // AEC (disabled in this file-only demo; left here for reference) cfg.echo_canceller.enabled false; // 瞬态抑制 cfg.transient_suppression.enabled true; // 语音检测 //cfg.voice_detection.enabled true; apm-ApplyConfig(cfg); // 1) 创建并配置 VAD VadInst* vad nullptr; WebRtcVad_Create(); WebRtcVad_Init(vad); // 模式0~3越大越“激进/敏感” WebRtcVad_set_mode(vad, 2); const int sample_rate (int)in.sample_rate; const size_t channels in.channels; const size_t frame_samples static_castsize_t(sample_rate / 100); // 10 ms const size_t total_samples in.samples.size(); webrtc::StreamConfig input_cfg(sample_rate, channels); webrtc::StreamConfig output_cfg(sample_rate, channels); std::vectorint16_t out; out.reserve(total_samples); size_t frames_with_voice 0, total_frames 0; for (size_t pos 0; pos total_samples; pos frame_samples * channels) { size_t remaining total_samples - pos; size_t this_frame std::min(frame_samples * channels, remaining); std::vectorint16_t frame(frame_samples * channels, 0); std::memcpy(frame.data(), in.samples.data() pos, this_frame * sizeof(int16_t)); // In-place process int err apm-ProcessStream(frame.data(), input_cfg, output_cfg, frame.data()); if (err ! 0) throw std::runtime_error(AudioProcessing::ProcessStream failed); if (opt.vad) { auto stats apm-GetStatistics(); // voice_detected is optional in stats if (stats.voice_detected *stats.voice_detected) frames_with_voice; total_frames; } out.insert(out.end(), frame.begin(), frame.end()); }官方也有给一个demo学习但是他不是降噪的工程我上面是代码基于这个改造得到的在讲解代码之前我们先简单来看AudioProcessing降噪结构定义// Enables background noise suppression. struct NoiseSuppression { bool enabled false; enum Level { kLow, kModerate, kHigh, kVeryHigh }; Level level kModerate; bool analyze_linear_aec_output_when_available false; } noise_suppression;有了这个基础之后我们开始介绍一下上面的代码整个代码处理流程原始 PCM ↓ 分帧10ms ↓ APM 加工包含高通 降噪 AGC2 瞬态抑制 ↓ WebRTC Spectral Noise Suppression维纳滤波降噪 ↓ 可选VAD 检测是否有人声 ↓ 输出降噪后的 PCM1、AudioProcessingAPM是 WebRTC 音频处理的总控模块rtc::scoped_refptrwebrtc::AudioProcessing apm webrtc::AudioProcessingBuilder().Create();AudioProcessing内部包括模块有模块功能HPF高通去低频噪声风噪、低频嗡声NS噪声抑制频域维纳滤波AEC回声消除你这里关闭了AGC1/AGC2自动增益控制响度一致VAD语音检测TS瞬态噪声抑制键盘敲击声目前代码开通的模块高通滤波降噪NSAGC2瞬态抑制击键/碰撞噪声处理2、开启高通滤波器cfg.high_pass_filter.enabled opt.hpf;//这里赋值为ture高通滤波器的定义/* 高通滤波器在 APM 中是非常重要的基础模块主要用来 去除低频轰鸣声风声、空调声、道路噪声 去掉麦克风/电源带来的 50/60Hz 嗡声 降低 DC offset直流偏置 提升 Voice Activity Detection (VAD) 的准确性WebRTC 的高通滤波器通常是 90 Hz左右截止频率。 Input PCM ↓ [HighPassFilter] ← 你这段配置控制的就是这一步 ↓ Echo Cancellation (AEC) ↓ Noise Suppression (NS) ↓ Automatic Gain Control (AGC) ↓ Output PCM */ struct HighPassFilter { bool enabled false;//是否启用高通滤波器 /* 决定高通滤波器作用在哪个频带。如果为 true默认高通滤波器对整段信号进行处理full-band也就是说 所有频率范围的输入信号都经过 HPF → 再进入 APM 其它模块。 如果为 false高通滤波只应用在音频的“底层带宽”即低带通常是 窄带8kHz 或 16kHz 的部分段 apply_in_full_band 的含义是 true在整个 full-band 上应用 HPF即对原始全频率信号做一次高通然后再做分带 false只对某一个子带通常是低频/主带应用 HPF其他高频带不单独再滤 */ bool apply_in_full_band true; } high_pass_filter;3、开启降噪Noise Suppressioncfg.noise_suppression.enabled true;4、设置降噪强度low / moderate / highif (opt.ns low) cfg.noise_suppression.level kLow; else if (opt.ns moderate) cfg.noise_suppression.level kModerate; else cfg.noise_suppression.level kHigh;level降噪力度声音效果low最轻保真度最高moderate中等默认会议最佳high强降噪有人声变“干”风险very high暴力降噪强噪环境用5、开启 AGC2自动增益控制 2cfg.gain_controller2.enabled opt.agc2; cfg.gain_controller2.adaptive_digital.enabled opt.agc2;AGC2 特点完全数字化不需要硬件支持自动让音量保持稳定适合嵌入式系统、录音文件处理作用防止声音忽大忽小增强较小的语音提高降噪后音质AGC2 与 NS 配合可以达到 专业会议级降噪音质。6、开启瞬态噪声抑制键盘/撞击噪声cfg.transient_suppression.enabled true;TS 模块专门处理键盘敲击物件掉落咔哒声爆音鼠标点按它能去除这种 “瞬间高能量” 的噪声。不过这个未来可能是被抛弃官方后期不会维护这个模块估计对于处理非稳态噪声处理效果不是很好暂时没有测试后面有测试再和大家说。7、ApplyConfig — 把设置应用到 APM 内部apm-ApplyConfig(cfg);执行这个之后HPF、NS、AGC2、TS 都被开启APM 内部会创建对应模块初始化 FFT、噪声估计器、滤波器等这是开始降噪前必要的一步。8、准备分帧WebRTC 统一使用 10msconst size_t frame_samples sample_rate / 100; // 10ms9、10ms 循环核心处理过程for (pos0; pos total_samples; pos frame_samples * channels) { ... apm-ProcessStream(frame.data(), input_cfg, output_cfg, frame.data()); ... }ProcessStream 内部执行哪些降噪算法Raw PCM ↓ High Pass Filter高通 ↓ Noise Suppression频域降噪 ↓ Transient Suppression瞬态噪声抑制 ↓ AGC2自适应增益 限幅器 ↓ Output PCM-10、可选统计 VAD语音检测auto stats apm-GetStatistics(); if (stats.voice_detected *stats.voice_detected) frames_with_voice;WebRTC 内部会用能量判断频谱判断多带语音概率来判断是否为语音帧。可用于静音检测录音分析语音触发自动剪辑无声片段总结上面每一个流程会比较复杂暂时我们没有看到里面具体是怎么实现所以后期我们后面深入去追webrtc APM的源码来学习下期内容我们来放到板端进行测试一下效果是怎样的