让 AI 降噪走进实时通信!本项目实现了基于 GTCRN 模型的流式 PCM 音频降噪,支持 C++ 高性能推理与 Java JNI 调用。
在实时语音通信、会议系统或直播场景中,背景噪音往往是影响体验的罪魁祸首。本项目基于超轻量级语音增强模型 GTCRN,利用 ONNX Runtime 进行推理加速,实现了对麦克风流式数据的实时降噪处理。
🚀 项目亮点
⚡ 实时流式处理:专为实时场景设计,支持对麦克风输入的 PCM 数据流进行逐帧(Frame-by-Frame)降噪,低延迟。
🧠 轻量级 AI 模型:采用 GTCRN 模型(ICASSP 2024),专为低计算资源设计,仅需 48.2K 参数,在 CPU 上也能跑出惊人的实时率(RTF 0.07)。
🛠️ 纯 C++ 高性能实现:核心逻辑使用 C++ 编写,结合 ONNX Runtime 推理引擎,性能强劲。
☕ 友好的 Java 接口:提供了完整的 JNI 封装示例,Java 开发者可以轻松调用底层 C++ 能力,无缝集成到 Android 或后端服务中。
🔧 依赖极简:核心依赖仅为 ONNX Runtime 和 KissFFT,易于编译和部署。
🛠️ 技术栈与依赖
本项目主要依赖以下开源库,请确保环境已配置好:
GTCRN 模型: 基于 https://github.com/Xiaobin-Rong/gtcrn 的 ONNX 模型(16k 采样率)。
ONNX Runtime: 微软的高性能推理引擎 https://github.com/microsoft/onnxruntime。
KissFFT: 轻量级 FFT 库 https://github.com/mborgerding/kissfft。
KissFFT 编译指令:
make KISSFFT_DATATYPE=float KISSFFT_STATIC=1 KISSFFT_TOOLS=0 all
1.C++ 编译与运行
项目提供了完整的 C++ 实现 (gtcrn_ok.cpp),您可以直接使用 g++ 进行编译。
编译命令:
g++ -O2 -std=c++17 -I./kissfft-master -I./onnxruntime-linux/include \
gtcrn_ok.cpp kissfft-master/libkissfft-float.a \
-L./onnxruntime-linux/lib -lonnxruntime -lm -lpthread -o gtcrn_ok
2.运行:
./gtcrn_ok
注:运行结果与 Python 版本的 test_ok.py 保持一致,验证了实现的准确性。
☕ Java

JNI 集成方案
为了方便 Java 生态的开发者,项目提供了 JNI 封装思路。您可以编写一个 GTCRN 类来加载 native 库,实现 Java 与 C++ 的交互。
核心 Java 封装代码示例:
public class GTCRN {
// 加载 native 库 (Windows: Gtcrn.dll, Linux: libGtcrn.so)
static {
System.loadLibrary("gtcrn");
}
// Native 方法声明
private static native long nativeCreate(String modelPath);
private static native short[] nativeDenoise(long handle, short[] audioInput);
private static native void nativeDestroy(long handle);
private long nativeHandle;
public GTCRN(String modelPath) {
nativeHandle = nativeCreate(modelPath);
if (nativeHandle == 0) throw new RuntimeException("Failed to initialize GTCRN native engine");
}
/**
* 处理一帧音频数据
* @param audioInput 长度至少为 256 的 short 数组
* @return 处理后的 256 个采样点
*/
public short[] denoise(short[] audioInput) {
if (nativeHandle == 0) throw new IllegalStateException("Native engine not initialized");
return nativeDenoise(nativeHandle, audioInput);
}
public void destroy() {
if (nativeHandle != 0) {
nativeDestroy(nativeHandle);
nativeHandle = 0;
}
}
}
Java 调用示例(流式处理 PCM):
public static void main(String[] args) throws Exception{
System.out.println("当前工作目录是: " + System.getProperty("user.dir"));
String inputPcmPath = "G:/test/sample.pcm";
String outputPcmPath = "C:\\Users\\lilin\\Desktop\\output_clean.pcm";
// 1. 初始化 GTCRN 降噪引擎
System.out.println("正在加载 GTCRN 模型...");
GTCRN denoiser = new GTCRN( "G:\\work\\ai\\ok\\SpeechDenoiser-main\\16k\\gtcrn-main\\stream\\onnx_models\\gtcrn_simple.onnx"); // 内部会自动调用 nativeCreate()
System.out.println("模型加载成功!开始流式处理...");
long startTime = System.currentTimeMillis();
long totalProcessedBytes = 0;
// 2. 使用 try-with-resources 确保文件流自动关闭
try (FileInputStream fis = new FileInputStream(inputPcmPath);
FileOutputStream fos = new FileOutputStream(outputPcmPath)) {
// 分配固定大小的字节缓冲区 (512 bytes)
byte[] byteBuffer = new byte[FRAME_SIZE_BYTES];
int bytesRead;
int gg=0;
// 3. 核心:循环读取文件,每次读取一帧 (512字节)
while ((bytesRead = readFully(fis, byteBuffer)) > 0) {gg++;
System.out.println(gg);
// --- A. 字节转 Short (处理小端序 & 尾帧补零) ---
short[] inputFrame = new short[FRAME_SIZE_SAMPLES];
// 将读取到的有效字节放入 ByteBuffer
ByteBuffer bb = ByteBuffer.wrap(byteBuffer, 0, bytesRead)
.order(ByteOrder.LITTLE_ENDIAN);
// 将有效字节转为 short
int validSamples = bytesRead / 2;
for (int i = 0; i < validSamples; i++) {
inputFrame[i] = bb.getShort();
}
// 如果是最后一帧且不足 256 个采样点,数组剩余部分默认就是 0 (自动补零)
// --- B. 调用 JNI 进行单帧降噪 ---
short[] outputFrame = denoiser.denoise(inputFrame);
// --- C. Short 转字节并写入文件 ---
// 准备输出的字节数组 (只转换有效的采样点,丢弃补零产生的尾部数据)
byte[] outputBytes = new byte[validSamples * 2];
ByteBuffer outBb = ByteBuffer.wrap(outputBytes)
.order(ByteOrder.LITTLE_ENDIAN);
for (int i = 0; i < validSamples; i++) {
outBb.putShort(outputFrame[i]);
}
// 写入输出文件
fos.write(outputBytes);
totalProcessedBytes += bytesRead;
}
} catch (FileNotFoundException e) {
System.err.println("找不到输入文件: " + new File(inputPcmPath).getAbsolutePath());
} catch (IOException e) {
System.err.println("文件读写异常: " + e.getMessage());
} finally {
// 4. 释放 C++ 层资源
denoiser.destroy();
System.out.println("模型资源已释放。");
}
// 打印统计信息
long endTime = System.currentTimeMillis();
double durationSec = (totalProcessedBytes / 2.0) / 16000.0; // 假设 16kHz 采样率
System.out.printf("处理完成!共处理 %.2f 秒音频,耗时: %d ms (RTF: %.2f)%n",
durationSec, (endTime - startTime),
(endTime - startTime) / (durationSec * 1000.0));
System.out.println("降噪后的 PCM 已保存至: " + new File(outputPcmPath).getAbsolutePath());
}
测试结果对比:

📂 项目地址
代码已完全开源,欢迎 Star 和 Fork!
实时流式 PCM 音频降噪:基于 GTCRN 与 ONNX Runtime 的 C++ 实现
💡 适用场景:
在线会议软件的背景噪音抑制
智能音箱的语音唤醒前处理
直播推流的音频美化
任何需要实时处理 16k PCM 音频流的场景
218



被折叠的 条评论
为什么被折叠?



