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
免责声明 本教程仅为合法的教学目的而准备,严禁用于任何形式的违法犯罪活动及其他商业行为,在使用本教程前,您应确保该行为符合当地的法律法规,继续阅读即表示您需自行承担所有操作的后果,如有异议,请立即停…...
数据链路层的主要功能是什么
数据链路层(OSI模型第2层)的核心功能是在相邻网络节点(如交换机、主机)间提供可靠的数据帧传输服务,主要职责包括: 🔑 核心功能详解: 帧封装与解封装 封装: 将网络层下发…...
基于Docker Compose部署Java微服务项目
一. 创建根项目 根项目(父项目)主要用于依赖管理 一些需要注意的点: 打包方式需要为 pom<modules>里需要注册子模块不要引入maven的打包插件,否则打包时会出问题 <?xml version"1.0" encoding"UTF-8…...
OpenPrompt 和直接对提示词的嵌入向量进行训练有什么区别
OpenPrompt 和直接对提示词的嵌入向量进行训练有什么区别 直接训练提示词嵌入向量的核心区别 您提到的代码: prompt_embedding = initial_embedding.clone().requires_grad_(True) optimizer = torch.optim.Adam([prompt_embedding...
Android第十三次面试总结(四大 组件基础)
Activity生命周期和四大启动模式详解 一、Activity 生命周期 Activity 的生命周期由一系列回调方法组成,用于管理其创建、可见性、焦点和销毁过程。以下是核心方法及其调用时机: onCreate() 调用时机:Activity 首次创建时调用。…...
【生成模型】视频生成论文调研
工作清单 上游应用方向:控制、速度、时长、高动态、多主体驱动 类型工作基础模型WAN / WAN-VACE / HunyuanVideo控制条件轨迹控制ATI~镜头控制ReCamMaster~多主体驱动Phantom~音频驱动Let Them Talk: Audio-Driven Multi-Person Conversational Video Generation速…...
Mysql中select查询语句的执行过程
目录 1、介绍 1.1、组件介绍 1.2、Sql执行顺序 2、执行流程 2.1. 连接与认证 2.2. 查询缓存 2.3. 语法解析(Parser) 2.4、执行sql 1. 预处理(Preprocessor) 2. 查询优化器(Optimizer) 3. 执行器…...
代码随想录刷题day30
1、零钱兑换II 给你一个整数数组 coins 表示不同面额的硬币,另给一个整数 amount 表示总金额。 请你计算并返回可以凑成总金额的硬币组合数。如果任何硬币组合都无法凑出总金额,返回 0 。 假设每一种面额的硬币有无限个。 题目数据保证结果符合 32 位带…...
Netty从入门到进阶(二)
二、Netty入门 1. 概述 1.1 Netty是什么 Netty is an asynchronous event-driven network application framework for rapid development of maintainable high performance protocol servers & clients. Netty是一个异步的、基于事件驱动的网络应用框架,用于…...
永磁同步电机无速度算法--基于卡尔曼滤波器的滑模观测器
一、原理介绍 传统滑模观测器采用如下结构: 传统SMO中LPF会带来相位延迟和幅值衰减,并且需要额外的相位补偿。 采用扩展卡尔曼滤波器代替常用低通滤波器(LPF),可以去除高次谐波,并且不用相位补偿就可以获得一个误差较小的转子位…...
大数据治理的常见方式
大数据治理的常见方式 大数据治理是确保数据质量、安全性和可用性的系统性方法,以下是几种常见的治理方式: 1. 数据质量管理 核心方法: 数据校验:建立数据校验规则(格式、范围、一致性等)数据清洗&…...
