Java jni调用nnom rnn-denoise 降噪
介绍:https://github.com/majianjia/nnom/blob/master/examples/rnn-denoise/README_CN.md
默认提供了一个wav的例子
#include <stdint.h>
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include <string.h>#include "nnom.h"
#include "denoise_weights.h"#include "mfcc.h"
#include "wav.h"// the bandpass filter coefficiences
#include "equalizer_coeff.h" #define NUM_FEATURES NUM_FILTER#define _MAX(x, y) (((x) > (y)) ? (x) : (y))
#define _MIN(x, y) (((x) < (y)) ? (x) : (y))#define NUM_CHANNELS 1
#define SAMPLE_RATE 16000
#define AUDIO_FRAME_LEN 512// audio buffer for input
float audio_buffer[AUDIO_FRAME_LEN] = {0};
int16_t audio_buffer_16bit[AUDIO_FRAME_LEN] = {0};// buffer for output
int16_t audio_buffer_filtered[AUDIO_FRAME_LEN/2] = { 0 };// mfcc features and their derivatives
float mfcc_feature[NUM_FEATURES] = { 0 };
float mfcc_feature_prev[NUM_FEATURES] = { 0 };
float mfcc_feature_diff[NUM_FEATURES] = { 0 };
float mfcc_feature_diff_prev[NUM_FEATURES] = { 0 };
float mfcc_feature_diff1[NUM_FEATURES] = { 0 };
// features for NN
float nn_features[64] = {0};
int8_t nn_features_q7[64] = {0};// NN results, which is the gains for each frequency band
float band_gains[NUM_FILTER] = {0};
float band_gains_prev[NUM_FILTER] = {0};// 0db gains coefficient
float coeff_b[NUM_FILTER][NUM_COEFF_PAIR] = FILTER_COEFF_B;
float coeff_a[NUM_FILTER][NUM_COEFF_PAIR] = FILTER_COEFF_A;
// dynamic gains coefficient
float b_[NUM_FILTER][NUM_COEFF_PAIR] = {0};// update the history
void y_h_update(float *y_h, uint32_t len)
{for (uint32_t i = len-1; i >0 ;i--)y_h[i] = y_h[i-1];
}// equalizer by multiple n order iir band pass filter.
// y[i] = b[0] * x[i] + b[1] * x[i - 1] + b[2] * x[i - 2] - a[1] * y[i - 1] - a[2] * y[i - 2]...
void equalizer(float* x, float* y, uint32_t signal_len, float *b, float *a, uint32_t num_band, uint32_t num_order)
{// the y history for each bandstatic float y_h[NUM_FILTER][NUM_COEFF_PAIR] = { 0 };static float x_h[NUM_COEFF_PAIR * 2] = { 0 };uint32_t num_coeff = num_order * 2 + 1;// i <= num_coeff (where historical x is involved in the first few points)// combine state and new data to get a continual x input. memcpy(x_h + num_coeff, x, num_coeff * sizeof(float));for (uint32_t i = 0; i < num_coeff; i++){y[i] = 0;for (uint32_t n = 0; n < num_band; n++){y_h_update(y_h[n], num_coeff);y_h[n][0] = b[n * num_coeff] * x_h[i+ num_coeff];for (uint32_t c = 1; c < num_coeff; c++)y_h[n][0] += b[n * num_coeff + c] * x_h[num_coeff + i - c] - a[n * num_coeff + c] * y_h[n][c];y[i] += y_h[n][0];}}// store the x for the state of next roundmemcpy(x_h, &x[signal_len - num_coeff], num_coeff * sizeof(float));// i > num_coeff; the rest data not involed the x historyfor (uint32_t i = num_coeff; i < signal_len; i++){y[i] = 0;for (uint32_t n = 0; n < num_band; n++){y_h_update(y_h[n], num_coeff);y_h[n][0] = b[n * num_coeff] * x[i];for (uint32_t c = 1; c < num_coeff; c++)y_h[n][0] += b[n * num_coeff + c] * x[i - c] - a[n * num_coeff + c] * y_h[n][c];y[i] += y_h[n][0];} }
}// set dynamic gains. Multiple gains x b_coeff
void set_gains(float *b_in, float *b_out, float* gains, uint32_t num_band, uint32_t num_order)
{uint32_t num_coeff = num_order * 2 + 1;for (uint32_t i = 0; i < num_band; i++)for (uint32_t c = 0; c < num_coeff; c++)b_out[num_coeff *i + c] = b_in[num_coeff * i + c] * gains[i]; // only need to set b.
}void quantize_data(float*din, int8_t *dout, uint32_t size, uint32_t int_bit)
{float limit = (1 << int_bit); for(uint32_t i=0; i<size; i++)dout[i] = (int8_t)(_MAX(_MIN(din[i], limit), -limit) / limit * 127);
}void log_values(float* value, uint32_t size, FILE* f)
{char line[16];for (uint32_t i = 0; i < size; i++) {snprintf(line, 16, "%f,", value[i]);fwrite(line, strlen(line), 1, f);}fwrite("\n", 2, 1, f);
}int main(int argc, char* argv[])
{wav_header_t wav_header; size_t size;char* input_file = "sample.wav";char* output_file = "filtered_sample.wav";FILE* src_file;FILE* des_file;char* log_file = "log.csv";FILE* flog = fopen(log_file, "wb");// if user has specify input and output files. if (argc > 1)input_file = argv[1];if (argc > 2)output_file = argv[2];src_file = fopen(input_file, "rb");des_file = fopen(output_file, "wb");if (src_file == NULL) {printf("Cannot open wav files, default input:'%s'\n", input_file);printf("Or use command to specify input file: xxx.exe [input.wav] [output.wav]\n");return -1;}if (des_file == NULL){fclose(src_file); return -1; }// read wav file header, copy it to the output file. fread(&wav_header, sizeof(wav_header), 1, src_file);fwrite(&wav_header, sizeof(wav_header), 1, des_file);// lets jump to the "data" chunk of the WAV file.if (strncmp(wav_header.datachunk_id, "data", 4)){wav_chunk_t chunk = { .size= wav_header.datachunk_size};// find the 'data' chunkdo {char* buf = malloc(chunk.size);fread(buf, chunk.size, 1, src_file);fwrite(buf, chunk.size, 1, des_file);free(buf);fread(&chunk, sizeof(wav_chunk_t), 1, src_file);fwrite(&chunk, sizeof(wav_chunk_t), 1, des_file);} while (strncmp(chunk.id, "data", 4));}// NNoM modelnnom_model_t *model = model = nnom_model_create();// 26 features, 0 offset, 26 bands, 512fft, 0 preempha, attached_energy_to_band0mfcc_t * mfcc = mfcc_create(NUM_FEATURES, 0, NUM_FEATURES, 512, 0, true);printf("\nProcessing file: %s\n", input_file);while(1) {// move buffer (50%) overlapping, move later 50% to the first 50, then fill memcpy(audio_buffer_16bit, &audio_buffer_16bit[AUDIO_FRAME_LEN/2], AUDIO_FRAME_LEN/2*sizeof(int16_t));// now read the new datasize = fread(&audio_buffer_16bit[AUDIO_FRAME_LEN / 2], AUDIO_FRAME_LEN / 2 * sizeof(int16_t), 1, src_file);if(size == 0)break;// get mfccmfcc_compute(mfcc, audio_buffer_16bit, mfcc_feature);//log_values(mfcc_feature, NUM_FEATURES, flog);// get the first and second derivative of mfccfor(uint32_t i=0; i< NUM_FEATURES; i++){mfcc_feature_diff[i] = mfcc_feature[i] - mfcc_feature_prev[i];mfcc_feature_diff1[i] = mfcc_feature_diff[i] - mfcc_feature_diff_prev[i];}memcpy(mfcc_feature_prev, mfcc_feature, NUM_FEATURES * sizeof(float));memcpy(mfcc_feature_diff_prev, mfcc_feature_diff, NUM_FEATURES * sizeof(float));// combine MFCC with derivatives memcpy(nn_features, mfcc_feature, NUM_FEATURES*sizeof(float));memcpy(&nn_features[NUM_FEATURES], mfcc_feature_diff, 10*sizeof(float));memcpy(&nn_features[NUM_FEATURES+10], mfcc_feature_diff1, 10*sizeof(float));//log_values(nn_features, NUM_FEATURES+20, flog);// quantise them using the same scale as training data (in keras), by 2^n. quantize_data(nn_features, nn_features_q7, NUM_FEATURES+20, 3);// run the mode with the new inputmemcpy(nnom_input_data, nn_features_q7, sizeof(nnom_input_data));model_run(model);// read the result, convert it back to float (q0.7 to float)for(int i=0; i< NUM_FEATURES; i++)band_gains[i] = (float)(nnom_output_data[i]) / 127.f;log_values(band_gains, NUM_FILTER, flog);// one more step, limit the change of gians, to smooth the speech, per RNNoise paperfor(int i=0; i< NUM_FEATURES; i++)band_gains[i] = _MAX(band_gains_prev[i]*0.8f, band_gains[i]); memcpy(band_gains_prev, band_gains, NUM_FEATURES *sizeof(float));// apply the dynamic gains to each frequency band. set_gains((float*)coeff_b, (float*)b_, band_gains, NUM_FILTER, NUM_ORDER);// convert 16bit to float for equalizerfor (int i = 0; i < AUDIO_FRAME_LEN/2; i++)audio_buffer[i] = audio_buffer_16bit[i + AUDIO_FRAME_LEN / 2] / 32768.f;// finally, we apply the equalizer to this audio frame to denoiseequalizer(audio_buffer, &audio_buffer[AUDIO_FRAME_LEN / 2], AUDIO_FRAME_LEN/2, (float*)b_,(float*)coeff_a, NUM_FILTER, NUM_ORDER);// convert the filtered signal back to int16for (int i = 0; i < AUDIO_FRAME_LEN / 2; i++)audio_buffer_filtered[i] = audio_buffer[i + AUDIO_FRAME_LEN / 2] * 32768.f *0.6f; // write the filtered frame to WAV file. fwrite(audio_buffer_filtered, 256*sizeof(int16_t), 1, des_file);}// print some model infomodel_io_format(model);model_stat(model);model_delete(model);fclose(flog);fclose(src_file);fclose(des_file);printf("\nNoisy signal '%s' has been de-noised by NNoM.\nThe output is saved to '%s'.\n", input_file, output_file);return 0;
}
去掉wav的信息就能解析pcm了
创建cmake 文件 编译dll
cmake_minimum_required(VERSION 3.10)project(RnnDenoise)set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED True)
include_directories(nnom-master/port/)
include_directories(nnom-master/inc/)
include_directories(nnom-master/examples/rnn-denoise/)
include_directories(D:/java/jdk1.8x64/include/)
include_directories(D:/java/jdk1.8x64/include/win32/)
set(EXPLICIT_SOURCESRnnDenoise.cnnom-master/examples/rnn-denoise/mfcc.c
)
file(GLOB_RECURSE SRC_FILES "nnom-master/src/*/*.c")
set(SOURCES ${EXPLICIT_SOURCES} ${SRC_FILES})add_library(RnnDenoise SHARED ${SOURCES})
java 库封装示例
package com.lilin.demoasr.nnom;public class RnnDenoise implements AutoCloseable{private long rnndenoise;public long getRnndenoise() {return rnndenoise;}public void setRnndenoise(long rnndenoise) {this.rnndenoise = rnndenoise;}private static final Object globalLock = new Object();/***https://github.com/majianjia/nnom/blob/master/examples/rnn-denoise/**** @throws Exception*/public RnnDenoise() throws Exception {synchronized (globalLock) {RnnLoad.load("RnnDenoise");}this.rnndenoise = createRnnDenoise0();}private static native long createRnnDenoise0();private native short[] denoise0(long rnndenoise,short[] var1);/*** 固定320 每次 可以修改c 改大* @param input* @return*/public short[] denoise(short[] input) {// synchronized (this) {return this.denoise0(this.rnndenoise ,input);// }}private native long destroyRnnDenoise0();public void close() {synchronized (this) {this.destroyRnnDenoise0();this.rnndenoise = 0L;}}public boolean isClosed() {synchronized (this) {return this.rnndenoise == 0L;}}
}
test:
public static void main (String[] args) {String sList []= new String[]{"G:\\work\\ai\\ZipEnhancer\\r1.pcm","C:\\Users\\\\lilin\\Desktop\\16k.pcm"};// String sList []= new String[]{"C:\\Users\\\\lilin\\Desktop\\16k.pcm"};List< Thread> lts= new ArrayList<>();for (int i = 0; i < sList.length; i++) {String file =sList[i];int finalI = i;lts.add(new Thread(new Runnable() {@Overridepublic void run() {try {RnnDenoise rnnDenoise = new RnnDenoise();System.out.println(rnnDenoise.getRnndenoise());FileInputStream f = new FileInputStream(file);FileOutputStream f1 = new FileOutputStream("C:\\Users\\\\lilin\\Desktop\\"+ finalI +".pcm");int n=0;byte[] z = new byte[640];while ((n = f.read(z)) != -1) {short [] sa = new short[320];ByteBuffer.wrap(z).order(ByteOrder.LITTLE_ENDIAN).asShortBuffer().get(sa);short[] denoisedAudio = rnnDenoise.denoise(sa);byte[] z1 = new byte[640];ByteBuffer.wrap(z1).order(ByteOrder.LITTLE_ENDIAN).asShortBuffer().put(denoisedAudio);f1.write(z1);}System.out.println(finalI+"end.");rnnDenoise.close();f1.close();}catch (Exception e){e.printStackTrace();}}}));}for (Thread y: lts ) {y.start();}for (Thread y: lts ) {try{ y.join();}catch (Exception e){e.printStackTrace();}}System.out.println("end...");}
}
nnom 默认的denoise_weights.h 是单例的无法同时创建多个实例 所以java无法在多线程使用, 可以自己更改下 主要涉及static变量和nnom_tensor_t 需要改用malloc的方式创建。
测试速度挺快的 ,几十分钟的很快降噪完成 ,也可以和freeswitch对接多路实时降噪 在识别,
如果模块或流程觉得麻烦可以到
https://item.taobao.com/item.htm?id=653611115230
视频教程yuexiajiayan的个人空间-yuexiajiayan个人主页-哔哩哔哩视频
相关文章:

Java jni调用nnom rnn-denoise 降噪
介绍:https://github.com/majianjia/nnom/blob/master/examples/rnn-denoise/README_CN.md 默认提供了一个wav的例子 #include <stdint.h> #include <stdlib.h> #include <stdio.h> #include <math.h> #include <string.h>#include …...

C++软件设计模式之状态模式
在C设计模式中,状态模式(State Pattern)是一种行为设计模式,它允许对象在内部状态改变时改变其行为,使对象看起来似乎修改了其类。状态模式的主要动机、意图和适用场合如下: 动机 在面向对象的设计中&…...

Microsoft Visual Studio中的/MT, /MTd,/MD,/MDd分别是什么意思?
1. /MT,/MTd,/MD,/MDd的含义 /MT,/MTd,/MD,/MDd是 Microsoft Visual C 编译器的运行时库链接选项。它们决定了程序如何链接 C 运行时库(CRT)。具体含义如下: /MT&#x…...

谷粒商城项目125-spring整合high-level-client
新年快乐! 致2025年还在努力学习的你! 你已经很努力了,今晚就让自己好好休息一晚吧! 在后端中选用哪种elasticsearch客户端? elasticsearch可以通过9200或者9300端口进行操作 1)9300:TCP spring-data-elasticsearch:transport-…...

日期时间选择(设置禁用状态)
目录 1.element文档需要 2.禁用所有过去的时间 3.设置指定日期的禁用时间 <template><div class"block"><span class"demonstration">起始日期时刻为 12:00:00</span><el-date-pickerv-model"value1"type"dat…...

基于SpringBoot的题库管理系统的设计与实现(源码+SQL+LW+部署讲解)
文章目录 摘 要1. 第1章 选题背景及研究意义1.1 选题背景1.2 研究意义1.3 论文结构安排 2. 第2章 相关开发技术2.1 前端技术2.2 后端技术2.3 数据库技术 3. 第3章 可行性及需求分析3.1 可行性分析3.2 系统需求分析 4. 第4章 系统概要设计4.1 系统功能模块设计4.2 数据库设计 5.…...

钉钉h5微应用安卓报错error29 ios报错error3 加上报错52013,签名校验失败 (前端)
这两个都是应为 免登报错52013,签名校验失败 用户后端签名使用的url地址和前端访问地址需要严格一致,包括端口号。前端部分可以用alert显示出当前的location.href,后端部分请在签名的时候打印日志。 访问通过反向代理服务器、各种NAT等场景下…...

Vue.js组件开发-客户端如何限制刷新Token次数
在Vue.js组件开发中,限制刷新Token的次数是一个重要的安全措施,可以防止恶意用户或攻击者无限次尝试刷新Token。 客户端限制 在客户端,可以通过Vuex、localStorage或sessionStorage等存储机制来跟踪刷新Token的尝试次数。以下是一个基本的实…...

Linux上安装jdk
在线环境的话,通过命令下载,离线环境的话,组要自行去oracle官网下载后上传 wget --no-check-certificate --no-cookies --header "Cookie: oraclelicenseaccept-securebackup-cookie" http://download.oracle.com/otn-pub/java/jd…...

Ardunio BLE keyboard 库的使用
为了开发一个 ardunio 的蓝牙选歌器,网络上普遍推荐使用: https://github.com/T-vK/ESP32-BLE-Keyboard 结果搞了好几天,就是不行。最后发现,下面两点非常重要: 使用 NimBle-ardunio 库这个库目前是2.1.2 ÿ…...

django --递归查询评论
表数据 树状结构 action(methods(GET, ), detailFalse) def get_info_pinglun(self, request, *args, **kwargs) -> Response:根据评论id查所有回复params wenxian_pinglun_id --> 评论id;wenxian_pinglun_id self.request.GET.get(wenxian_pinglun_id)results se…...

【开源免费】基于SpringBoot+Vue.JS音乐网站(JAVA毕业设计)
本文项目编号 T 109 ,文末自助获取源码 \color{red}{T109,文末自助获取源码} T109,文末自助获取源码 目录 一、系统介绍二、数据库设计三、配套教程3.1 启动教程3.2 讲解视频3.3 二次开发教程 四、功能截图五、文案资料5.1 选题背景5.2 国内…...

SUBSTRING_INDEX()在MySQL中的用法
语法: SUBSTRING_INDEX() 是 MySQL 中的一个字符串函数,它返回一个字符串,该字符串包含从字符串的开始或结束到指定的子字符串出现指定次数为止的部分。这个函数的语法如下: SUBSTRING_INDEX(string, delimiter, count)string&a…...

对45家“AI+安全”产品/方案的分析
一. 关键洞察 “AI+安全”创新非常活跃,一片百家争鸣之势,赛道选择上,以事件分诊Incident Triage、 安全辅助Security Copilots、自动化Automation三者为主为主,这充分反映了当前安全运营的主要需求,在产品理念选择上以 AI 和 自动化为主,这确实又切合上了在关键…...

Oracle Dataguard(主库为 Oracle 11g 单节点)配置详解(1):Oracle Dataguard 概述
Oracle Dataguard(主库为 Oracle 11g 单节点)配置详解(1):Oracle Dataguard 概述 目录 Oracle Dataguard(主库为 Oracle 11g 单节点)配置详解(1):Oracle Data…...

Pycharm 中 virtualenv、pipenv、conda 虚拟环境的用法
文章目录 前言虚拟环境的通俗介绍虚拟环境和非虚拟环境该怎么选?通过 Virtualenv 方式创建虚拟环境通过 Pipenv 方式创建虚拟环境通过 Conda 方式创建虚拟环境前言 在网上找了好一些资料,发现介绍 Pycharm 虚拟环境的不多,查了一些资料,并做个总结。 本文主要是介绍 Pycha…...

UNI-APP弹窗
组件代码 <template><view><!-- 蒙版 --><view class"mask" click"close()" v-show"tanchuang"></view><!-- 弹窗 --><view class"pop" :style"{height:height*0.8 px,top:tanchuang?…...

【大模型实战篇】LLaMA Factory微调ChatGLM-4-9B模型
1. 背景介绍 虽然现在大模型微调的文章很多,但纸上得来终觉浅,大模型微调的体感还是需要自己亲自上手实操过,才能有一些自己的感悟和直觉。这次我们选择使用llama_factory来微调chatglm-4-9B大模型。 之前微调我们是用两块3090GPU显卡&…...

【Cesium】三、实现开场动画效果
文章目录 实现效果实现方法实现代码组件化 实现效果 实现方法 Cesium官方提供了Camera的flyTo方法实现了飞向目的地的动画效果。 官方API:传送门 这里只需要用到目的地(destination)和持续时间(duration)这两个参数…...

#渗透测试#红蓝攻防#红队打点web服务突破口总结01
免责声明 本教程仅为合法的教学目的而准备,严禁用于任何形式的违法犯罪活动及其他商业行为,在使用本教程前,您应确保该行为符合当地的法律法规,继续阅读即表示您需自行承担所有操作的后果,如有异议,请立即停…...

适用于项目经理的跨团队协作实践:Atlassian Jira与Confluence集成
适用于项目经理的跨团队协作实践:Atlassian Jira与Confluence集成 现代项目经理的核心职责是提供可视性、保持团队一致,并确保团队拥有交付出色工作所需的资源。在过去几年中,由于分布式团队的需求不断增加,项目经理这一角色已迅速…...

智能家居体验大变革 博联 AI 方案让智能不再繁琐
1. 全球AI技术发展背景及智能家居市场趋势 人工智能(AI)技术的飞速发展正在推动全球各行业的数字化转型。国际电信联盟与德勤联合发布《人工智能向善影响》报告指出,全球94%的商界领袖认为,人工智能技术对于其企业在未来5年内的发…...

云计算与服务是什么
云计算与服务是一个广泛而深入的话题,涵盖了云计算的基本概念、特点、服务类型以及应用场景等多个方面。以下是对云计算与服务的详细解析: ### 一、云计算的基本概念 云计算是一种基于互联网的计算方式,它通过动态易扩展且虚拟化的资源&…...

接口测试面试题
接口测试在软件测试中占据重要位置,无论是功能测试还是性能测试,接口的稳定性至关重要。以下总结了一些常见的接口测试面试题,帮助你从容应对面试挑战! 面试官常说:“接口测试是测试的重头戏,了解接口的设计…...

【Cesium】六、实现鹰眼地图(三维)与主图联动效果
文章目录 一、前言二、效果三、实现方法2.1 思路2.2 方法2.3 使用 App.vue 一、前言 上一篇文章:【Cesium】五、地图实现鹰眼效果(三维),虽然实现了3D 的鸟瞰图效果,但是只有鸟瞰图跟着 主地图在动,如果 在…...

ESLint+Prettier的配置
ESLintPrettier的配置 安装插件 在settings.json中写下配置 {// tab自动转换标签"emmet.triggerExpansionOnTab": true,"workbench.colorTheme": "Default Dark","editor.tabSize": 2,"editor.fontSize": …...

4.微服务灰度发布落地实践(消息队列增强)
文章目录 前言问题分析消息队列特性分析kafkarocketmqrabbitmq 发布订阅公共抽象发送端订阅端 前言 消息队列是一种用于在应用程序的不同组件或系统之间传递消息的通信机制。它通过将消息存储在一个队列中,确保消息能够可靠地从发送方传递到接收方,即使…...

【从零开始入门unity游戏开发之——C#篇35】C#自定义类实现Sort自定义排序
文章目录 一、List<T>自带的排序方法1、List<T>调用Sort()排序2、 能够使用 Sort() 方法进行排序的本质 二、自定义类的排序1、通过实现泛型IComparable<T> 接口(1)示例(2)直接调用 int 类型的 CompareTo 方法进…...

音频进阶学习九——离散时间傅里叶变换DTFT
文章目录 前言一、DTFT的解释1.DTFT公式2.DTFT右边释义1) 复指数 e − j ω n e^{-j\omega n} e−jωn2)序列与复指数相乘 x [ n ] ∗ e − j ω n x[n]*e^{-j\omega n} x[n]∗e−jωn复指数序列复数的共轭正交正交集 3)复指数序列求和 3.DTF…...

连接github和ai的桥梁:GitIngest
Git ingest GitIngest - 将任何 Github 仓库转变为适合 LLM 的友好型提示文本 (https://github.com/cyclotruc/gitingest) 输入 Github 地址或者名称,GitIngest 就会提供该仓库的总结、目录结构、仓库内容的文本内容 你可以复制这些文本与 AI 大模型更好地对话...