基于RNN的音频降噪算法 (附完整C代码)
前几天无意间看到一个项目rnnoise。
项目地址: https://github.com/xiph/rnnoise
基于RNN的音频降噪算法。
采用的是 GRU/LSTM 模型。
阅读下训练代码,可惜的是作者没有提供数据训练集。
不过基本可以断定他采用的数据集里,肯定有urbansound8k。
urbansound8k 数据集地址:
https://serv.cusp.nyu.edu/projects/urbansounddataset/urbansound8k.html
也可以考虑采用用作者训练的模型来构建数据集的做法,不过即费事,也麻烦。
经过实测,降噪效果很不错,特别是在背景噪声比较严重的情况下。
不过作者仅仅提供 pcm 的代码示例,并且还只支持48K采样率,
( 明显是为了兼容其另一个 项目 opus)
在很多应用场景下,这很不方便。
尽管稍微有点麻烦,但是事在人为,花了点时间,稍作修改。
具体修改如下:
1.支持wav格式
采用dr_wav(https://github.com/mackron/dr_libs/blob/master/dr_wav.h)
2.支持全部采样率
采样率的处理问题,采用简单粗暴法,
详情请移步博主另一篇小文《简洁明了的插值音频重采样算法例子 (附完整C代码)》
3.增加CMake文件
4.增加测试用 示例音频sample.wav
取自(https://github.com/orctom/rnnoise-java)
贴上完整示例代码 :
#include <stdio.h> #include "rnnoise.h" #include <stdlib.h> #include <stdint.h> #define DR_WAV_IMPLEMENTATION #include "dr_wav.h" void wavWrite_int16(char *filename, int16_t *buffer, int sampleRate, uint32_t totalSampleCount) { drwav_data_format format; format.container = drwav_container_riff; format.format = DR_WAVE_FORMAT_PCM; format.channels = ; format.sampleRate = (drwav_uint32) sampleRate; format.bitsPerSample = ; 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(); } } } 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 == NULL) { fprintf(stderr, "ERROR\n"); exit(); } ) { drwav_free(buffer); buffer = NULL; *sampleRate = ; *totalSampleCount = ; } return buffer; } void splitpath(const char *path, char *drv, char *dir, char *name, char *ext) { const char *end; const char *p; const char *s; ] && path[] == ':') { 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'; } } void resampleData(const int16_t *sourceData, int32_t sampleRate, uint32_t srcSize, int16_t *destinationData, int32_t newSampleRate) { if (sampleRate == newSampleRate) { memcpy(destinationData, sourceData, srcSize * sizeof(int16_t)); return; } uint32_t last_pos = srcSize - ; uint32_t dstSize = (uint32_t) (srcSize * ((float) newSampleRate / sampleRate)); ; idx < dstSize; idx++) { float index = ((float) idx * sampleRate) / (newSampleRate); uint32_t p1 = (uint32_t) index; float coef = index - p1; uint32_t p2 = (p1 == last_pos) ? last_pos : p1 + ; destinationData[idx] = (int16_t) ((1.0f - coef) * sourceData[p1] + coef * sourceData[p2]); } } void f32_to_s16(int16_t *pOut, const float *pIn, size_t sampleCount) { if (pOut == NULL || pIn == NULL) { return; } ; i < sampleCount; ++i) { *pOut++ = (short) pIn[i]; } } void s16_to_f32(float *pOut, const int16_t *pIn, size_t sampleCount) { if (pOut == NULL || pIn == NULL) { return; } ; i < sampleCount; ++i) { *pOut++ = pIn[i]; } } void denoise_proc(int16_t *buffer, uint32_t buffen_len) { ; DenoiseState *st; st = rnnoise_create(); float patch_buffer[frame_size]; if (st != NULL) { uint32_t frames = buffen_len / frame_size; uint32_t lastFrame = buffen_len % frame_size; ; i < frames; ++i) { s16_to_f32(patch_buffer, buffer, frame_size); rnnoise_process_frame(st, patch_buffer, patch_buffer); f32_to_s16(buffer, patch_buffer, frame_size); buffer += frame_size; } ) { memset(patch_buffer, , frame_size * sizeof(float)); s16_to_f32(patch_buffer, buffer, lastFrame); rnnoise_process_frame(st, patch_buffer, patch_buffer); f32_to_s16(buffer, patch_buffer, lastFrame); } } rnnoise_destroy(st); } void rnnDeNoise(char *in_file, char *out_file) { uint32_t in_sampleRate = ; uint64_t in_size = ; int16_t *data_in = wavRead_int16(in_file, &in_sampleRate, &in_size); uint32_t out_sampleRate = ; uint32_t out_size = (uint32_t) (in_size * ((float) out_sampleRate / in_sampleRate)); int16_t *data_out = (int16_t *) malloc(out_size * sizeof(int16_t)); if (data_in != NULL && data_out != NULL) { resampleData(data_in, in_sampleRate, (uint32_t) in_size, data_out, out_sampleRate); denoise_proc(data_out, out_size); resampleData(data_out, out_sampleRate, (uint32_t) out_size, data_in, in_sampleRate); wavWrite_int16(out_file, data_in, in_sampleRate, (uint32_t) in_size); free(data_in); free(data_out); } else { if (data_in) free(data_in); if (data_out) free(data_out); } } int main(int argc, char **argv) { printf("Audio Noise Reduction\n"); printf("blog:http://tntmonks.cnblogs.com/\n"); printf("e-mail:gaozhihan@vip.qq.com\n"); ) ; ]; ]; ]; ]; ]; ]; splitpath(in_file, drive, dir, fname, ext); sprintf(out_file, "%s%s%s_out%s", drive, dir, fname, ext); rnnDeNoise(in_file, out_file); printf("press any key to exit.\n"); getchar(); ; }
不多写注释,直接看代码吧。
项目地址:https://github.com/cpuimage/rnnoise
示例具体流程为:
加载wav(拖放wav文件到可执行文件上)->重采样降噪->保存wav
若有其他相关问题或者需求也可以邮件联系俺探讨。
邮箱地址是:
gaozhihan@vip.qq.com
基于RNN的音频降噪算法 (附完整C代码)的更多相关文章
- 音频降噪算法 附完整C代码
降噪是音频图像算法中的必不可少的. 目的肯定是让图片或语音 更加自然平滑,简而言之,美化. 图像算法和音频算法 都有其共通点. 图像是偏向 空间 处理,例如图片中的某个区域. 图像很多时候是以二维数据 ...
- 基于傅里叶变换的音频重采样算法 (附完整c代码)
前面有提到音频采样算法: WebRTC 音频采样算法 附完整C++示例代码 简洁明了的插值音频重采样算法例子 (附完整C代码) 近段时间有不少朋友给我写过邮件,说了一些他们使用的情况和问题. 坦白讲, ...
- mser 最大稳定极值区域(文字区域定位)算法 附完整C代码
mser 的全称:Maximally Stable Extremal Regions 第一次听说这个算法时,是来自当时部门的一个同事, 提及到他的项目用它来做文字区域的定位,对这个算法做了一些优化. ...
- 单独编译和使用webrtc音频降噪模块(附完整源码+测试音频文件)
单独编译和使用webrtc音频增益模块(附完整源码+测试音频文件) 单独编译和使用webrtc音频回声消除模块(附完整源码+测试音频文件) webrtc的音频处理模块分为降噪ns,回音消除aec,回声 ...
- WebRTC 音频采样算法 附完整C++示例代码
之前有大概介绍了音频采样相关的思路,详情见<简洁明了的插值音频重采样算法例子 (附完整C代码)>. 音频方面的开源项目很多很多. 最知名的莫过于谷歌开源的WebRTC, 其中的音频模块就包 ...
- 音频自动增益 与 静音检测 算法 附完整C代码
前面分享过一个算法<音频增益响度分析 ReplayGain 附完整C代码示例> 主要用于评估一定长度音频的音量强度, 而分析之后,很多类似的需求,肯定是做音频增益,提高音量诸如此类做法. ...
- 音频自动增益 与 静音检测 算法 附完整C代码【转】
转自:https://www.cnblogs.com/cpuimage/p/8908551.html 前面分享过一个算法<音频增益响度分析 ReplayGain 附完整C代码示例> 主要用 ...
- 自动曝光修复算法 附完整C代码
众所周知, 图像方面的3A算法有: AF自动对焦(Automatic Focus)自动对焦即调节摄像头焦距自动得到清晰的图像的过程 AE自动曝光(Automatic Exposure)自动曝光的是为了 ...
- 磨皮美颜算法 附完整C代码
前言 2017年底时候写了这篇<集 降噪 美颜 虚化 增强 为一体的极速图像润色算法 附Demo程序> 这也算是学习过程中比较有成就感的一个算法. 自2015年做算法开始到今天,还有个把月 ...
随机推荐
- JavaScript的基本使用
一.JavaScript的简单介绍 JavaScript是一种属于网络的脚本语言(简称JS),已经被广泛用于Web应用开发,常用来为网页添加各式各样的动态功能,为用户提供更流畅美观的浏览效果.通常Ja ...
- 笔记-JS高级程序设计-基本概念篇
1:JS中的一切(变量,函数名和操作符)都是区分大小写的 2:标识符(变量,函数,属性的名字,以及函数的参数),第一个字符必须是字母,下划线,或者美元$,书写方式采用驼峰式,不能将关键字作为标识符. ...
- 学习ASP.NET Core Razor 编程系列一
一. 概述 .NET Core 1.0发布的时候就想进行学习的,不过根据微软的以往的发布规律1.0版可以认为是大众测试版,2.0才算稳定.现在2.1都已经发布了预览版,之前对其"不稳定&qu ...
- 【python学习笔记】6.抽象
[python学习笔记]6.抽象 创建函数: 使用def语句定义函数,不用声明参数类型,和返回值类型 def function_name(param1, param2): 'this is docum ...
- 利用Java泛型实现简单的泛型方法
问题:编写一个泛型方法add(),当传入不同数字类型的值时,能够进行加法运算,(如可以传入int.long.float.double类型,但要对传入的值做一定的限定,如必须是数字). 解决:利用泛型编 ...
- Attrib +s +a +h +r 隐藏文件原理与破解
制作了一个PE启动盘,不过这个启动盘不能深度隐藏,否则没效果,可以又想不让别人看见PE启动盘的一些内容,防止别人误删或者修改,于是就想找一种可以隐藏文件的方法,普通的隐藏文件的方法如下:
- Java 类文件结构
Java 诞生之时有句著名的宣传口号"Write Once, Run Anywhere.".但是,Java 语言本身不具备跨平台的能力,而是 JVM 提供了跨平台的能力. 事实上, ...
- FMDatabaseQueue 如何保证线程安全
这篇文章原来在用 Github Pages 搭建的博客上,现在决定重新用回博客园,所以把文章搬回来. FMDB 是 OC 针对 sqlite 的封装.在其文档的线程安全部分这样讲:同时从多个线程使用同 ...
- [Oracle] UNIX与Windows 2000上Oracle的差异(II)
作者:Ian Adam & David Stien, SAIC Ltd 日期:19-Dec-2003 出处:http://www.dbanotes.net翻译:Fenng 数据库启动与关闭 在 ...
- Node.JS开发环境准备
1.安装Nodejs的Windows包. 官网:http://nodejs.org/ 2.可以使用cmd运行nodejs项目,命令格式: node 文件名.js node 文件名 3.对于不熟悉的 ...