实时流式 PCM 音频降噪:基于 GTCRN 与 ONNX Runtime 的 C++ 实现

SAP 零售 FMS 物料主数据(一) SAP 零售 FMS 物料主数据(一) SAP 对于鞋服行业最新的解决方案-FMS(相当于原来的AFS+Retail);更偏向与零售; 商品主数据与原来的AFS大不相同,取消了原来的Grid的网格概念,取而代之的是变式;商品主数据维护也偏向于Retail的维护模式;事物代码也不是MM01而是MM41 /MM46; 在维护商品主数据前,需要与商品部沟通定义各种商品相关的规范如编码规则,大中小类 ,颜色库,尺码库等,此处不赘述; 创建商品需要确定哪些物料是变式物料,哪些是常规不带特性的单一物料;这决定了在创建商 阅读详情

让 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 音频流的场景

2026年软考高级网络规划设计师第三版备考笔记 删除了所有已退出主流应用、行业淘汰的技术内容,如 HDLC、xDSL、WiMAX、HSRP/GLBP 等,让教材内容更聚焦当下一线网络工程实际场景,剔除无效考点。 阅读详情

相关推荐

全志平台Sensor驱动移植实战:从点亮到调优的完整指南

本文详细介绍了在全志平台上进行Sensor驱动移植的全过程,从硬件引脚配置到软件参数调优,涵盖点亮、出图和调优三大阶段。重点解析了OV02B10传感器的I2C通信建立、上电时序调试和初始化参数配置等关键技术点,并提供了实用的调试技巧与问题排查指南,帮助开发者高效完成全志平台Sensor驱动移植工作。

weixin_28727975的博客 218

【STM32+MAX98357】MP3转PCM存入Flash并控制音频输出

针对MCU内存资源受限问题,可将资源预先烧录至外部Flash,此前《LVGL从外部Flash读取并显示图片:自定义解码器方案》已详细阐述图片资源的读取与显示方法。本文将以音频场景,介绍基于外部Flash的MP3音频播放输出控制方案。(1)将不同音频格式的文件转换成PCM文件。(2)将PCM音频数据写入外部Flash存储。(3)读取外部音频数据并控制播放。本方案针MCU内存不足问题,将MP3(或其他格式)解码得到的PCM裸音频数据预先烧录至外部SPI Flash。

YouziTech的博客 230

AI Agent Harness Engineering 创业PMF验证工具:用户满意度+留存率+业务指标监测表

在AI Agent创业的浪潮中,我们看到了无数产品如雨后春笋般涌现,但最终能够真正找到PMF并存活下来的却寥寥无几。根据CB Insights的数据,创业公司失败的首要原因(占42%)是"没有市场需求"——换句话说,就是没有找到PMF。AI Agent产品由于其特殊性(交互范式的变革、技术复杂度高、用户期望管理困难等),PMF验证变得更加具有挑战性。传统的SaaS产品PMF验证框架虽然有参考价值,但无法完全适用于AI Agent这种新型产品形态。

AI智能探索者的博客 329

口播视频唇形总对不上,Seedance 2.5在zeekeAI里同步

做口播或数字人视频时,唇形不同步是常见痛点。核心在于音频质量、动作控制与输入切分。建议使用ZEEKEAI等聚合平台,通过大模型清理音频、切段喂入Seedance 2.5,配合特写镜头、微动提示词和短句输入,实现精准唇形同步。关键:人控节奏,工具算像素,前期约束越细,成片越自然。

2601_96168718的博客 172

AstrBot插件开发全攻略:从零编写一个天气查询插件(Python实战)

本文提供了一份详细的AstrBot插件开发实战指南,手把手教你使用Python从零编写一个智能天气查询插件。内容涵盖插件系统核心设计、开发环境搭建、API调用与数据处理、自然语言交互实现以及插件打包发布全流程,帮助你快速掌握基于AstrBot框架的聊天机器人功能扩展技能。

weixin_29212867的博客 1082

11、rsa-目标主机支持RSA密钥交换【原理扫描】的漏洞

通过将 etcd 的 TLS 密钥交换算法从 RSA 升级为 ECDHE,可实现前向保密,彻底消除 “私钥泄露导致历史流量解密” 的风险。核心步骤是通过强制启用含ECDHE的套件,并禁用 RSA 密钥交换套件,同时建议升级到 TLS 1.2+ 并优化证书类型(优先 ECDSA)。这一配置符合云原生安全最佳实践,也是 Kubernetes 等依赖 etcd 的系统推荐的安全标准。生成临时密钥的具体步骤是什么?如何验证etcd是否已成功更新为ECDH密钥交换算法?配置临时密钥交换算法可能带来哪些性能影响。

xuebo1129927648的博客 1万+

Firefox 刷抖音网页版卡顿?修改一个 Media 参数,让视频切换更加流畅

这次优化让我发现,浏览器刷短视频时的卡顿不一定都是网络或网页前端的问题,也可能与浏览器自身的媒体处理机制有关。抖音网页版会同时处理多个视频播放器,而 Firefox 在 Windows 平台上对 DXVA 硬件解码器实例数量设置了默认上限。当视频信息流中的多个播放器占用解码器资源时,就可能影响后续视频的解码初始化。将默认值 8 调整为 16,可以尝试缓解这类并发解码器资源不足的问题。配置项修改前修改后816Windows 桌面版 Firefox。使用 Firefox 浏览抖音网页版。

binweisili的博客 482

提供一个微信投票刷票的js代码

最近几天,有个朋友找我去写一个脚本帮他 在微信上刷票、微信投票刷票,我大概看了一下,本次微信投票刷票其实就是根据微信的openid来限制,每个openid只能投三次票的限制。上图可以看出,其实只要openid,和toopenid即可,openid是自己的微信id,toopenid是投票对象的微信id,那我们定时修改openid即可给某一个人刷投票。把这段代码复制到浏览器F12之后的console里,直接回车即可开始微信投票刷票(刷新或关闭浏览器即可停止刷票)//生成随机的ip地址。

qq_858865388专业提供快速微信投票教程攻略和方法的博客 2万+

Spring AI 多模态实战(下):文生图 + TTS 语音合成(含 2.0 流式音频分片)

本文基于 Spring AI 2.0.1,实战文生图与TTS语音合成:通过ImageModel/ImagePrompt生成图片(返回URL或base64),用SpeechModel/SpeechPrompt实现文字转语音;重点介绍2.0流式音频分片技术,支持低延迟长文本播报;结合缓存、落盘、限流等策略控制生成成本,避免URL过期、音频格式错乱等常见坑点。附完整代码与踩坑指南,助力构建高效多模态应用。

weixin_43128865的博客 264

ASPICE学习笔记

ASPICE的全称是Automotive SPICE。

汽车电子软件领域知识分享 1355

路径规划 | 图解A*、Dijkstra、GBFS算法的异同(附C++/Python/Matlab仿真)

图解A*、Dijkstra、GBFS算法原理,分析三种算法异同,提供C++/Python/Matlab仿真实现

FRIGIDWINTER的博客 2万+

音频自动匹配歌词:本地音乐库元数据维护实践

实施顺序建议为:建立主库、统一命名、批量匹配、人工校验、权限分享、定期备份。工具选择上,SMB/WebDAV、Navidrome、Jellyfin 以及轻量文件管理服务各有适用场景,应结合访问方式、权限需求和维护成本评估。把文件组织好、把批量操作控制住、把备份习惯建立起来,歌词补全才能真正提升本地音乐库的可用性,而不是带来新的整理负担。音乐文件不常修改,但歌词、封面、播放列表和目录结构属于人工整理成果,丢失后恢复成本较高。更合理的顺序是:集中存放、统一命名、批量匹配、人工校验、权限管理、定期备份。

zxcvb153的博客 115

YOLOv11缝合改进Conv | SAConv在YOLOv11中的应用可切换空洞卷积与性能提升(附代码)

在本篇文章中,我们将深入探讨如何通过引入**SAConv**(Switchable Atrous Convolution,可切换空洞卷积)来优化YOLOv11网络结构,特别是在卷积操作方面的创新。我们会解析SAConv的核心原理和架构设计。

一键难忘的博客 948

视频美颜sdk的API设计会影响开发效率吗?

视频美颜SDK不仅需要具备优秀的图像处理能力,API接口设计同样会影响软件开发效率。本文从接口调用、参数配置、版本兼容、开发文档以及业务扩展等多个角度,分析API设计对视频美颜SDK集成和后期维护的实际影响,为直播APP、视频社交平台等项目的SDK选型与技术开发提供参考。

wanyuekeji的博客 191

文档:亲测可用解决vnc灰屏,黑屏,鼠标大黑叉情况

主要解决vnc-viewer灰屏,黑屏,鼠标大黑叉等现象,详细见文档。

数学建模模型总结

这是本人在两年内准备参加数学建模竞赛搜集到的模型资料,已经经过了本人的筛选和整理,希望能够对准备参加数学建模竞赛的学弟学妹们提供一些帮助!

直播APP如何实现美颜参数实时调节?视频美颜SDK交互机制解析

直播APP中的实时美颜功能是如何实现的?本文从视频美颜SDK的技术原理出发,详细解析磨皮、美白、瘦脸、滤镜等参数的实时调节机制,介绍APP与SDK之间的参数交互流程,以及线程协调、性能优化和设备兼容性等关键技术,为直播APP美颜功能开发与SDK接入提供参考。

wanyuekeji的博客 172

efm32 入门.pdf

本PDF共计22页,介绍的是操作驱动API,下载与否自己斟酌。

视频号数据怎么采?接入方式、字段范围与场景适配

视频号数据采集的技术难点不在“调哪个接口”,而在。官方API服务的是“经营与交易”闭环,返回的是直播记录、订单、售后等结构化实体,但播放完成率、互动明细、评论区内容这些内容分析赖以生存的字段,并不在官方接口的返回Schema里。这意味着任何技术方案的选择,本质上是。

城章科技 276

VB摄像头监控

该VB模块可对摄像头捕获的画面进行录像等,可在创建的窗口进行控制

本地化部署会议视频软件如何开展试点?试用范围、评估指标与推广步骤

试用范围覆盖真实差异,评估指标具有明确口径,推广过程具备放行和回退机制。对于政企、金融、医疗及信创项目,尤其要避免三个误区:把本地部署等同于合规,把演示并发等同于生产容量,把功能清单等同于可运维能力。如果正在准备试点,建议先整理一张“网络—终端—业务—故障”矩阵,再决定试用人数。

hz56789的博客 314

视频怎么翻译?英文视频转中文字幕、中文配音的在线教程(附双语字幕做法)

视频文件里没有文字,所谓视频翻译其实是“抽音频—语音识别—机器翻译—再合成”这条链路。本文先拆清楚这条链路和三层产物(文字稿、字幕文件、配音视频),指出真正的质量瓶颈在语音识别而不在翻译,并说明背景音乐、口音、多人抢话、专业术语各自会造成什么后果。实操部分给出云音雀视频翻译功能页的完整流程:上传视频、指定原语言与目标语言、提交任务、到转换记录下载结果,同时提示文件24小时后自动删除。最后列出8个高频坑,以及字幕断行、时间轴校对的具体做法,适合外语访谈、课程、海外分发等场景。

qq370409341的博客 512

监控视频脱敏的追踪漂移与ID撞号陷阱

转场后遮罩活到新画面——人物离场加硬切后,遮罩还盖在新画面上约1.3秒。隐私窗口期——遮罩淡入期间(建轨首帧alpha只有1/3),加上按fps抽样(25fps素材每80ms采一帧),人脸露出后约130~160ms没被完全覆盖。ID撞号导致整段不输出——追踪器重启后track id从1重新编号,老轨还在段数据里。检查清单:导出前确认遮挡层时间范围覆盖全部检测轨,验证音频通道数量与原始素材一致,转场区域手动复核遮罩是否干净。工程上的核心问题不在识别本身,而在多目标追踪在场景切换时的行为控制。

Mysssone的博客 180

联犀 Go SIMD 实战:视频转码从 16.5ms 到 5.46ms

联犀Go视频转码实战:在352×288测试流中单帧单核CPU耗时从16.5ms到5.46ms,区分SIMD、代码及编码策略的综合收益。保留测试条件、压测结果与适用边界。

QQ603785348的博客 317

AI智能美妆如何适应不同面部特征?视频美颜SDK技术解析

AI智能美妆正在推动视频美颜技术向个性化方向发展。面对不同用户的脸型、眼型、唇形及肤色差异,视频美颜SDK如何通过人脸检测、关键点识别、动态追踪和实时渲染实现精准适配?本文从核心技术原理、不同面部特征的妆容适配方式,以及实际应用场景等方面展开解析,帮助开发者了解AI智能美妆的技术实现与发展趋势。

q1031691172的博客 354

远程会诊产品设计复盘:音视频架构拆解与四大避坑

思路,形成分层结构:- 省级/区域远程医疗平台- 地市级会诊中心- 县级医院会诊节点- 乡镇卫生院、社区卫生中心接入点- 医生端、专家端、移动端、会诊室终端这套"省-市-县-乡-村"五级联动的架构,特别适合医共体、医联体和专科联盟类项目。产品经理要重点验收的是"医生能不能放大、缩放、多帧对比",而不是"能不能传个文件"。真正有价值的建设方案,从来不是堆功能,而是围绕医疗流程,把系统架构、业务对接、网络能力、安全合规和运营机制作为一个整体来设计——这也是产品经理在这个领域最大的价值所在。

cloudroom888的博客 235

Gemini Omni 1.2 Flash发布:视频10秒变15秒、720p降价30%

发布日期:2026-11-06Gemini Omni 1.2 Flash是Google于2026年11月发布的视频生成模型,支持原生15秒视频、多轮对话编辑和更强的参考素材遵循。Google公告发布于北京时间11月6日凌晨,官网标注日期为11月5日。相比Omni 1.1,新版把最长片段从10秒延长至15秒,720p视频单价降至每秒0.07美元,降幅30%。这次更新还涉及生成之后的修改:换背景、调光线、替换产品,可以围绕同一条视频继续提出要求。

aidoudoulong的博客 371

实时互动、直播、点播:音视频SDK选型的技术逻辑

在远程办公、在线教育、文娱电商、政务民生等数字化业务中,音视频能力已经成为多数互联网应用的基础设施。行业内目前形成了实时互动、直播、点播三种主流业务形态,三者在技术架构、传输逻辑与技术指标上差异明显。对研发团队和技术决策者来说,先分清业务属于哪种形态,再据此匹配音视频SDK与传输方案,可以直接影响研发周期、开发成本和终端体验。本文拆解三类业务形态的技术特征、核心指标与选型逻辑,并补充相关的传输原理,供选型时参考。## 一、实时互动:低延迟双向交互的技术体系实时互动的本质,是在双方或多方之间建立低延迟、高稳定

YWamy的博客 141

直播上课+课后回放,音视频流媒体直播/点播系统EasyDSS直播/点播帮健身房搭建线上健身

助力场馆打造轻量化、可复用的线上健身教学资源。

EasyDSS官方技术博客 174

FPGA基于ADV7182解码PAL视频,Video Processing Subsystem去隔行,提供6套工程源码和技术支持

FPGA基于ADV7182解码PAL视频,Video Processing Subsystem去隔行,提供6套工程源码和技术支持

qq_41667729的博客 264
上一篇: FreeSWITCH mod_av GPU 硬件加速版 (AI 优化)
下一篇: Waveshare ESP32-S3-Touch-AMOLED-1.8 智能手表固件 (Rust 版)
java_lilin
博客等级 码龄14年 364粉丝 124原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值