博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Android 简单的录音静音降噪
阅读量:4165 次
发布时间:2019-05-26

本文共 3119 字,大约阅读时间需要 10 分钟。

需求:

客户反馈产品的录音里面很多杂音(因为我们把Codec的录音增益调至最大,且电路上没有专用的音频处理芯片、CPU直接接MIC(有包地))。在外壳、硬件不能修改的情况下,软件得想想办法尝试解决问题。

首先想到的是双麦降噪,原理大概是:一个主麦克风用来做通话,另一个收集环境噪音,对音频波形分析和相位操作,叠加到主麦克风的采样波形上,形成相位抵消,就降噪了。缺点是,两个麦克风不能距离太近,并且两个麦克风距离说话人的距离不能太远,太远了角度就很小了,根本无法分辨出来,另外,根据产品使用情况,上下麦克风各自都有几率称为主麦克风。所以实验测试出来的结果并没有很好。

考虑到录音噪音在有“人声”的时候是分辨不出来的、或者说影响很小,而在静音时有明显的环境噪声,因此想使用静音降噪的方法来规避问题。

本文只是简单的静音降噪,原理如下:考虑到启动录音时,要等待一段时间(比如0.5s)才会有人声,k可根据这0.5s时间来预测噪声的大小(阈值),然后以此为基础来检测“人声”的起始点。再人声到来时候,把所有音频数据设置为0,也就是做静音处理,所以这里叫静音降噪。而人声到来时,返回实际的音频数据(包括里面的噪声数据)。计算阈值的方法只是简单的求和平均。

下面代码在RK平台上hardware/alsa_sound/AudioStreamInALSA.cpp实现。

#define MUTE_NOISE_REDUCTION#ifdef MUTE_NOISE_REDUCTIONbool enable_reduction_noise = false;	//由属性sys.is.audiorecord.only控制int threshold_def = 0x400;	//默认阈值int threshold = 0;	//自适应噪声阈值int threshold_count = 0;	//计数,超过THRESHOLD_COUNT则使用threshold来检测“人声”#define THRESHOLD_COUNT 10#define MUTE_DELAY_COUNT 15		//播放人声后保留的音频帧数、不静音#define AUDIO_BUFFER_NUM 4		//缓存音频数据的帧数#define AUDIO_BUFFER_SIZE 1024	//一帧的音频数据大小char *audio_buffer[AUDIO_BUFFER_NUM];	//audio_buffer用于缓存音频数据char *audio_buffer_temp;	//用于交互音频数据int audio_buffer_pos=0;#endif#ifdef MUTE_NOISE_REDUCTION    {
unsigned int value = 0; int is_voice = 0; static int is_mute_delay_count; //ALOGE("in_begin_swip_num:%d in_begin_narrow_num=%d",in_begin_swip_num,in_begin_narrow_num); if(enable_reduction_noise && bytes > AUDIO_BUFFER_SIZE){
bytes = AUDIO_BUFFER_SIZE; } if(enable_reduction_noise){
unsigned char * buffer_temp=(unsigned char *)buffer; unsigned int total = 0; unsigned int total_count=0; unsigned int total_temp = 0; short data16; int j = 0; for(j=0; j
threshold_def){
is_voice++; //检测到人声 }else {
//is noise if(threshold_count == 0){
threshold = total_temp; }else{
threshold = (threshold+total_temp)/2; } threshold_count++; if(threshold_count >= THRESHOLD_COUNT){
threshold_def = threshold*2; //更新阈值,这里的2要对产品实验来确定。 threshold_count = THRESHOLD_COUNT; //此后一直用新阈值,直到停止录音 } } //is_mute_delay_count的意义是,如果前面播放了人声,那再停止说话之后继续保留MUTE_DELAY_COUNT的音频数据,这样不会“戛然而止”。 if( is_voice != 0 ){
is_mute_delay_count=MUTE_DELAY_COUNT; }else{
if(is_mute_delay_count != 0) is_mute_delay_count--; } //audio_buffer的意义:检测到人声,要返回说话前的一小段音频数据,否则声音从静音到人声有个POP声的跳跃。 //这里用audio_buffer来缓存AUDIO_BUFFER_NUM帧数据。 if(is_mute_delay_count == 0){
//Mute in order to remove noise memcpy(audio_buffer[audio_buffer_pos], (char *)buffer, bytes); //缓存音频 memset(buffer, 0, bytes); //返回静音数据 }else {
memcpy(audio_buffer_temp, (char *)buffer, bytes); memcpy((char *)buffer, audio_buffer[audio_buffer_pos], bytes); //返回旧的音频数据 memcpy(audio_buffer[audio_buffer_pos], (char *)audio_buffer_temp, bytes); //保存新的音频数据 } audio_buffer_pos++; if(audio_buffer_pos>=AUDIO_BUFFER_NUM) audio_buffer_pos=0; } }#endif

转载地址:http://emoxi.baihongyu.com/

你可能感兴趣的文章
OKR与CFR管理模式(二)-CFR与OKR的绩效管理
查看>>
Java多线程(3) - 多线程之死锁
查看>>
Java多线程(4) - 多线程之Volatile关键字、ThreadLocal、Atomic系列类、CAS
查看>>
Java多线程(5) - 多线程之线程通讯(一)(wait、notify、join、yield、sleep区别与应用)
查看>>
Java多线程(6) - 多线程之线程通讯(二)(wait与notify案例、守护线程)
查看>>
什么是项目管理?怎么管?(二)
查看>>
Java多线程(7) - 多线程之线程停止方式
查看>>
Java设计模式(1) - 单例设计模式多种写法
查看>>
Java设计模式(2) - 工厂设计模式
查看>>
Java多线程(8) - 同步(并发)类容器详解(CopyOnWrite容器、ConcurrentMap容器、Queue队列容器)
查看>>
Java设计模式(3) - 多线程并发设计模式 - Future设计模式
查看>>
Java设计模式(5) - 多线程并发设计模式 - 生产者-消费者设计模式多种写法
查看>>
Java多线程(9) - 多线程 - 线程池详解与使用示例
查看>>
Java多线程(10) - 多线程 - CountDownLatch、CyclicBarrier、Semaphore使用示例详解
查看>>
Java多线程(11) - 多线程 - 锁详解:重入锁、公平锁、非公平锁、读写锁、不可重入锁、自旋锁、独享锁、共享锁、互斥锁、悲观锁、乐观锁、分段锁、偏向锁、轻量级锁、重量级锁、CAS算法原理
查看>>
Java网络编程(10) - Netty网络编程常见问题与疑问
查看>>
设置Django连接到Google Cloud SQL(MYSQL)
查看>>
爬虫: 基于Node.js的强大爬虫,能直接发布抓取的文章哦
查看>>
Django学习笔记 扩展User模型
查看>>
Django资料总结
查看>>