音频自动增益 与 静音检测 算法 附完整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, "ERROR\n");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';}} else if (drv)*drv = '\0';for (end = path; *end && *end != ':';)end++;for (p = end; p > path && *--p != '\\' && *p != '/';)if (*p == '.') {end = p;break;}if (ext)for (s = end; (*ext = *s++);)ext++;for (p = end; p > path;)if (*--p == '\\' || *p == '/') {p++;break;}if (name) {for (s = p; s < end;)*name++ = *s++;*name = '\0';}if (dir) {for (s = path; s < p;)*dir++ = *s++;*dir = '\0';}
}int agcProcess(int16_t *buffer, uint32_t sampleRate, size_t samplesCount, int16_t agcMode) {if (buffer == nullptr) return -1;if (samplesCount == 0) return -1;WebRtcAgcConfig agcConfig;agcConfig.compressionGaindB = 9; // default 9 dBagcConfig.limiterEnable = 1; // default kAgcTrue (on)agcConfig.targetLevelDbfs = 3; // default 3 (-3 dBOv)int minLevel = 0;int maxLevel = 255;size_t samples = MIN(160, sampleRate / 100);if (samples == 0) return -1;const int maxSamples = 320;int16_t *input = buffer;size_t nTotal = (samplesCount / samples);void *agcInst = WebRtcAgc_Create();if (agcInst == NULL) return -1;int status = WebRtcAgc_Init(agcInst, minLevel, maxLevel, agcMode, sampleRate);if (status != 0) {printf("WebRtcAgc_Init fail\n");WebRtcAgc_Free(agcInst);return -1;}status = WebRtcAgc_set_config(agcInst, agcConfig);if (status != 0) {printf("WebRtcAgc_set_config fail\n");WebRtcAgc_Free(agcInst);return -1;}size_t num_bands = 1;int inMicLevel, outMicLevel = -1;int16_t out_buffer[maxSamples];int16_t *out16 = out_buffer;uint8_t saturationWarning = 1;                 //是否有溢出发生,增益放大以后的最大值超过了65536int16_t echo = 0;                                 //增益放大是否考虑回声影响for (int i = 0; i < nTotal; i++) {inMicLevel = 0;int nAgcRet = WebRtcAgc_Process(agcInst, (const int16_t *const *) &input, num_bands, samples,(int16_t *const *) &out16, inMicLevel, &outMicLevel, echo,&saturationWarning);if (nAgcRet != 0) {printf("failed in WebRtcAgc_Process\n");WebRtcAgc_Free(agcInst);return -1;}memcpy(input, out_buffer, samples * sizeof(int16_t));input += samples;}WebRtcAgc_Free(agcInst);return 1;
}void auto_gain(char *in_file, char *out_file) {//音频采样率uint32_t sampleRate = 0;//总音频采样数uint64_t inSampleCount = 0;int16_t *inBuffer = wavRead_int16(in_file, &sampleRate, &inSampleCount);//如果加载成功if (inBuffer != nullptr) {//  kAgcModeAdaptiveAnalog  模拟音量调节//  kAgcModeAdaptiveDigital 自适应增益//  kAgcModeFixedDigital 固定增益
        agcProcess(inBuffer, sampleRate, inSampleCount, kAgcModeAdaptiveDigital);wavWrite_int16(out_file, inBuffer, sampleRate, inSampleCount);free(inBuffer);}
}int main(int argc, char *argv[]) {printf("WebRTC Automatic Gain Control\n");printf("博客:http://cpuimage.cnblogs.com/\n");printf("音频自动增益\n");if (argc < 2)return -1;char *in_file = argv[1];char drive[3];char dir[256];char fname[256];char ext[256];char out_file[1024];splitpath(in_file, drive, dir, fname, ext);sprintf(out_file, "%s%s%s_out%s", drive, dir, fname, ext);auto_gain(in_file, out_file);printf("按任意键退出程序 \n");getchar();return 0;
}

 

 静音检测完整示例代码:

#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 "vad.h"#ifndef nullptr
#define nullptr 0
#endif#ifndef MIN
#define  MIN(A, B)        ((A) < (B) ? (A) : (B))
#endif#ifndef MAX
#define  MAX(A, B)        ((A) > (B) ? (A) : (B))
#endif//读取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;
}int vadProcess(int16_t *buffer, uint32_t sampleRate, size_t samplesCount, int16_t vad_mode, int per_ms_frames) {if (buffer == nullptr) return -1;if (samplesCount == 0) return -1;// kValidRates : 8000, 16000, 32000, 48000// 10, 20 or 30 ms framesper_ms_frames = MAX(MIN(30, per_ms_frames), 10);size_t samples = sampleRate * per_ms_frames / 1000;if (samples == 0) return -1;int16_t *input = buffer;size_t nTotal = (samplesCount / samples);void *vadInst = WebRtcVad_Create();if (vadInst == NULL) return -1;int status = WebRtcVad_Init(vadInst);if (status != 0) {printf("WebRtcVad_Init fail\n");WebRtcVad_Free(vadInst);return -1;}status = WebRtcVad_set_mode(vadInst, vad_mode);if (status != 0) {printf("WebRtcVad_set_mode fail\n");WebRtcVad_Free(vadInst);return -1;}printf("Activity : \n");for (int i = 0; i < nTotal; i++) {int nVadRet = WebRtcVad_Process(vadInst, sampleRate, input, samples);if (nVadRet == -1) {printf("failed in WebRtcVad_Process\n");WebRtcVad_Free(vadInst);return -1;} else {// output resultprintf(" %d \t", nVadRet);}input += samples;}printf("\n");WebRtcVad_Free(vadInst);return 1;
}void vad(char *in_file) {//音频采样率uint32_t sampleRate = 0;//总音频采样数uint64_t inSampleCount = 0;int16_t *inBuffer = wavRead_int16(in_file, &sampleRate, &inSampleCount);//如果加载成功if (inBuffer != nullptr) {//    Aggressiveness mode (0, 1, 2, or 3)int16_t mode = 1;int per_ms = 30;vadProcess(inBuffer, sampleRate, inSampleCount, mode, per_ms);free(inBuffer);}
}int main(int argc, char *argv[]) {printf("WebRTC Voice Activity Detector\n");printf("博客:http://cpuimage.cnblogs.com/\n");printf("静音检测\n");if (argc < 2)return -1;char *in_file = argv[1];vad(in_file);printf("按任意键退出程序 \n");getchar();return 0;
}

自动增益项目地址:https://github.com/cpuimage/WebRTC_AGC

具体流程为: 

加载wav(拖放wav文件到可执行文件上)->增益处理->保存为_out.wav文件

 

静音检测项目地址:https://github.com/cpuimage/WebRTC_VAD

具体流程为: 

加载wav(拖放wav文件到可执行文件上)->输出静音检测结果

备注 :1 为非静音,0 为静音

 该注意的地方和参数,见代码注释。

用cmake即可进行编译示例代码,详情见CMakeLists.txt。

 

若有其他相关问题或者需求也可以邮件联系俺探讨。

邮箱地址是: 
gaozhihan@vip.qq.com

 

转载于:https://www.cnblogs.com/cpuimage/p/8908551.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/538845.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

python绘制饼状图图例_使用matplotlib的所有饼图的通用图例

图例只需调用一次&#xff0c;否则将显示7个不同的图例。我在下面展示了一个例子。请注意&#xff0c;您必须将自己的数据替换为ax.pie()&#xff1a;data1 (10,90) # some data to be plotted data2 (40,50) data3 (70,30) labels [Sending Data, Not Sending Data] #lege…

Android初始化本地数据库

原文&#xff1a;http://blog.csdn.net/itjavawfc/article/details/50860647 点击阅读原文 -------------------------------- 最近遇到一个需求&#xff0c;一个同学不会搭服务器&#xff0c;但是Android课程设计需要用到很多数据&#xff0c;这样就出现了一个问题&#xff0c…

jsp springmvc 视图解析器_springMVC配置jsp/html视图解析器

1、maven项目引入freemark相关jar包freemaker是以个模板引擎&#xff0c;可以根据提供的数据和创建好的模板,去自动的创建html静态页面。所以在返回html视图时可以用这个引擎结合数据生成html静态页面。org.springframeworkspring-context-support5.0.7.RELEASEorg.freemarkerf…

php设计模式原型模式,原型模式_设计模式_设计模式之原型模式 - Lane Blog

108Clicks: 6614 Date: 2014-04-21 21:48:35 Power By 李轩Lane原型模式提取重复功能&#xff0c;避免了程序员喜欢复制粘贴的坏习惯。设计模式中的原型模式就是&#xff0c;用原型实例指定创建对象的重力&#xff0c;通过拷贝这些原型来创建新的对象从一个对象再创建另外一个可…

Windows2003如何安装IIS和ftp

【开始】----【控制面板】----【添加或删除程序】 出现如下“添加或删除程序”界面&#xff0c;点击“添加/删除windows组件&#xff08;a&#xff09; ” 出现如下“window组件向导”界面 下拉“组件”栏目条&#xff0c;选择“应用程序服务器” 点击“应用程序服务器”下的“…

hadoop临时文件 jar包_hadoop之Mapper/reducer源码分析之二

若当前JobClient (0.22 hadoop) 运行在YARN.则job提交任务运行在YARNRunnerHadoop Yarn 框架原理及运作机制主要步骤作业提交作业初始化资源申请与任务分配任务执行具体步骤在运行作业之前&#xff0c;Resource Manager和Node Manager都已经启动&#xff0c;所以在上图中&#…

ANDROID:SHOWASACTION="NEVER"是做什么用的?

原文地址&#xff1a;http://www.cnblogs.com/android-joker/p/4478491.html 点击阅读原文 --------------------------------------------------------- 安卓开发项目文件中有一个目录叫做menu&#xff0c;里面有tybmain.xml item选项里有一句 android:showAsAction "…

吴恩达ex3_Wu-Enda机器学习编程作业Python实现EX3,吴恩达,machinelearning,python,ex3nn

# -*- coding: utf-8 -*-"""Created on Wed Jul 1 20:28:57 2020author: cheetah023"""import numpy as npimport matplotlib.pyplot as pltimport scipy.io as sciimport random as ra#函数定义def sigmoid(X):return 1 /(1 np.exp(-X))def pr…

php数组验证用户名密码,求个php数组验证问题,在线等

现在有这么一个数组,是属性表Array([0] > Array([list_attr_id] > 30[list_attr_name] > 颜色[list_attr_attr] > 黑色|白色|金色[list_attr_price] > 0|10.1|20[list_attr_shop_id] > 28)[1] > Array([list_attr_id] > 31[list_attr_name] > 规格[…

基于python的视频监控系统_Python实现微信监控报警系统

概述: 本文主要分享一下博主在学习wxpy 的过程中开发的一个小程序。博主在最近有一个监控报警的需求需要完成&#xff0c;然后刚好在学习wxpy 这个东西&#xff0c;因此很巧妙的将工作和学习联系在一起。 博文中主要使用到的技术设计到Python&#xff0c;Redis&#xff0c;以及…

python 编码文件json.loads json.dumps

python 编码文件json.loads json.dumps import yaml d {name: 张三, age: 1} print d jd json.dumps(d, ensure_asciiFalse, encodingutf-8)) ud json.loads(jd, encodingutf-8) print ud ud yaml.safe_load(jd, encodingutf-8) print udposted on 2018-04-23 15:18 秦瑞It…

getActionBar()报空指针异常

调用 getActionBar()的Activity类 public class WlanListActivity extends AppCompatActivity 在使用getActionBar("标题内容")的时候报空指针。 原因是要用AppCompatActivity类里的getSupportActionBar()

python 类中定义列表_Python3中的自定义列表类,具有

我想用python3编写一个自定义列表类&#xff0c;就像在这个问题How would I create a custom list class in python?中一样&#xff0c;但与该问题不同&#xff0c;我想实现__get__和{}方法。虽然我的类与list类似&#xff0c;但是这些方法背后隐藏着一些神奇的操作。所以我想…

红黑树与平衡二叉树_百图详解红黑树,想不理解都难

之前在公司组内分享了红黑树的工作原理&#xff0c;今天把它整理下发出来&#xff0c;希望能对大家有所帮助&#xff0c;对自己也算是一个知识点的总结。这篇文章算是我写博客写公众号以来画图最多的一篇文章了&#xff0c;没有之一&#xff0c;我希望尽可能多地用图片来形象地…

linux 父子进程结束,Linux下让父进程结束后,子进程自动结束

在多进程编程的时候&#xff0c;经常会遇到这样的情况。父进程创建了一堆子进程&#xff0c;当遇到错误或者操作失误的时候把父进程关闭了&#xff0c;但是子进程还在跑&#xff0c;不得不一个一个地杀死子进程&#xff0c;或者使用ps,grep,awk,kill来配合批量杀死。之前在写 x…

android:showAsAction 无效

我想要的效果 但actionbar上的搜索菜单不显示 在androidstudio里&#xff0c;android:showAsAction"always"标红 根据提示&#xff0c;需要加入 xmlns:app"http://schemas.android.com/apk/res-auto" 加入后依然无效 正确的加入方式是&#xff1a;

Exchange_Server_2013在Windows_2008_R2部署

Exchange Server 2013可以部署在Windows Server 2012的平台&#xff0c;也可以部署在Windows Server 2008 R2的平台。如果部署在Windows Server 2008 R2平台要求操作系统版本为Windows Server 2008 R2 SP1的版本。如下拓扑图&#xff1a;在本架构中有两台服务器&#xff0c;都安…

建立副本名称冲突_包的建立(一)

这次的内容&#xff0c;涉及到 R 语言包的建立。事实上&#xff0c;CRAN 提供的官方参考指南&#xff0c;并不适合快速阅读&#xff0c;且内容繁杂。比较适合作为后期提高的 教材。而 http://r-pkgs.had.co.nz/ 上 的教程则更适合作为 R 包编写的帮助指南。这里&#xff0c;仅仅…

Android 多选列表

原文&#xff1a;http://blog.csdn.net/wljun739/article/details/37655209 点击阅读原文 ----------------------------------------------------------- 1、activity_main.xml[java] view plaincopy<LinearLayout xmlns:android"http://schemas.android.com/apk/res/…

python自带的编辑器怎么换行_Python3基础 print 自带换行功能

镇场诗&#xff1a; ———大梦谁觉&#xff0c;水月中建博客。百千磨难&#xff0c;才知世事无常。 ———今持佛语&#xff0c;技术无量愿学。愿尽所学&#xff0c;铸一良心博客。 —————————————————————————————————————————— 1 …