音频自动增益 与 静音检测 算法 附完整C代码

内容预览:
  • 也不多做介绍,感兴趣的同学,翻翻 维基百科 ,补补课~
  • 例如,用静音检测 来做音频裁剪,或者搭配音频增益做一些音频增强...~
  •   若有其他相关问题或者需求也可以邮件联系俺探讨~

前面分享过一个算法《音频增益响度分析 ReplayGain 附完整C代码示例

主要用于评估一定长度音频的音量强度,

而分析之后,很多类似的需求,肯定是做音频增益,提高音量诸如此类做法。

不过在项目实测的时候,其实真的很难定标准,

到底在什么样的环境下,要增大音量,还是降低。

在通讯行业一般的做法就是采用静音检测,

一旦检测为静音或者噪音,则不做处理,反之通过一定的策略进行处理。

这里就涉及到两个算法,一个是静音检测,一个是音频增益。

增益其实没什么好说的,类似于数据归一化拉伸的做法。

静音检测 在WebRTC中 是采用计算GMM (Gaussian Mixture Model,高斯混合模型)进行特征提取的。

在很长一段时间里面,音频特征 有3个主要的方法,

GMM  ,Spectrogram (声谱图), MFCC 即 Mel-Frequency Cepstrum(Mel频率倒谱)

恕我直言,GMM 提取的特征,其鲁棒性 不如后两者。

也不多做介绍,感兴趣的同学,翻翻 维基百科 ,补补课。

当然在实际使用算法时,会由此延伸出来一些小技巧。

例如,用静音检测 来做音频裁剪,或者搭配音频增益做一些音频增强之类的操作。

自动增益在WebRTC 源代码文件是:analog_agc.c 和 digital_agc.c

静音检测 源代码文件是: webrtc_vad.c

这个命名,有一定的历史原因了。

经过梳理后,

增益算法为 agc.c agc.h

静音检测为 vad.c vad.h

增益算法的完整示例代码:

#include <stdio.h>
#include
<stdlib.h>
#include
<stdint.h>
//采用https://github.com/mackron/dr_libs/blob/master/dr_wav.h 解码
#define DR_WAV_IMPLEMENTATION
#include
"dr_wav.h"
#include
"agc.h"

#ifndef nullptr
#define nullptr 0
#endif

#ifndef MIN
#define MIN(A, B) ((A) < (B) ? (A) : (B))
#endif

//写wav文件
void wavWrite_int16(char *filename, int16_t *buffer, size_t sampleRate, size_t totalSampleCount) {
drwav_data_format format
= {};
format.container
= drwav_container_riff; // <-- drwav_container_riff = normal WAV files, drwav_container_w64 = Sony Wave64.
format.format = DR_WAVE_FORMAT_PCM; // <-- Any of the DR_WAVE_FORMAT_* codes.
format.channels = 1;
format.sampleRate
= (drwav_uint32) sampleRate;
format.bitsPerSample
= 16;
drwav
*pWav = drwav_open_file_write(filename, &format);
if (pWav) {
drwav_uint64 samplesWritten
= drwav_write(pWav, totalSampleCount, buffer);
drwav_uninit(pWav);
if (samplesWritten != totalSampleCount) {
fprintf(stderr,
"ERRORn");
exit(
1);
}
}
}

//读取wav文件
int16_t *wavRead_int16(char *filename, uint32_t *sampleRate, uint64_t *totalSampleCount) {
unsigned
int channels;
int16_t
*buffer = drwav_open_and_read_file_s16(filename, &channels, sampleRate, totalSampleCount);
if (buffer == nullptr) {
printf(
"读取wav文件失败.");
}
//仅仅处理单通道音频
if (channels != 1) {
drwav_free(buffer);
buffer
= nullptr;
*sampleRate = 0;
*totalSampleCount = 0;
}
return buffer;
}

//分割路径函数
void splitpath(const char *path, char *drv, char *dir, char *name, char *ext) {
const char *end;
const char *p;
const char *s;
if (path[0] && path[1] == ':') {
if (drv) {
*drv++ = *path++;
*drv++ = *path++;
*drv = '
0 条回复 A 作者 M 管理员
    所有的伟大,都源于一个勇敢的开始!
欢迎您,新朋友,感谢参与互动!欢迎您 {{author}},您在本站有{{commentsCount}}条评论