嘯叫抑制(AFS)從算法仿真到工程源碼實現-第八節-系統搭建

一、概述

????????系統分為錄音模塊、數據處理模塊、播音模塊。錄音模塊和播音模塊使用alsa庫進行讀寫數據。各模塊為獨立進程處理,模塊之間使用命名管道進行數據的傳輸。數據處理模塊我們使用基于頻域的自適應濾波去嘯叫算法。

二、工程實現

2.1 系統流程圖

2.2 錄音模塊(從ALSA 讀數據)

#define ALSA_PCM_NEW_HW_PARAMS_API#include <alsa/asoundlib.h>
#include <stdio.h>
#define OUTPUT_PATH_NAME "/tmp/node2_to_node1.tmp"
#include <sys/types.h>
#include <sys/stat.h>
#include <stdlib.h>int main(int argc, char *argv[]) {long loops;int rc;int size;unsigned int val;int dir;char *buffer;snd_pcm_t *handle;snd_pcm_hw_params_t *params;snd_pcm_uframes_t frames;/*以錄制模式打開*//* Open PCM device for recording (capture). */rc = snd_pcm_open( &handle, "default", SND_PCM_STREAM_CAPTURE, 0);if (rc < 0) {fprintf(stderr, "unable to open pcm device");exit(EXIT_FAILURE);}/*分配一個參數對象*//* Allocate a hardware parameters object. */snd_pcm_hw_params_alloca(&params);/*初始化參數對象*//* Fill it in with default values. */rc = snd_pcm_hw_params_any(handle, params);if (rc < 0) {printf("Err\n");}/* Set the desired hardware parameters. *//*交錯模式*//* Interleaved mode */rc = snd_pcm_hw_params_set_access(handle, params,SND_PCM_ACCESS_RW_INTERLEAVED);if (rc < 0) {printf("Err\n");}/*PCM格式*//* Signed 16-bit little-endian format */rc = snd_pcm_hw_params_set_format(handle, params,SND_PCM_FORMAT_S16_LE);if (rc < 0) {printf("Err\n");}/*設置通道數*//* Two channels (stereo) */rc = snd_pcm_hw_params_set_channels(handle, params, 1);if (rc < 0) {printf("Err\n");}/*設置采樣率*//* 44100 bits/second sampling rate (CD quality) */val = 16000;rc = snd_pcm_hw_params_set_rate_near(handle, params,&val, &dir);if (rc < 0) {printf("Err\n");}/*沒周期的幀數*//* Set period size to 32 frames. */frames = 128;rc = snd_pcm_hw_params_set_period_size_near(handle,params, &frames, &dir);if (rc < 0) {printf("Err\n");}/* Write the parameters to the driver */rc = snd_pcm_hw_params(handle, params);if (rc < 0) {fprintf(stderr,"unable to set hw parameters: %s/n",snd_strerror(rc));exit(1);}/* Use a buffer large enough to hold one period */rc = snd_pcm_hw_params_get_period_size(params,&frames, &dir);if (rc < 0) {printf("Err\n");}size = frames * 2 * 1; /* 2 bytes/sample, 2 channels */buffer = (char *) malloc(size);/* We want to loop for 5 seconds */rc = snd_pcm_hw_params_get_period_time(params, &val, &dir);loops = 5000000 / val;//printf("====================:%d\n", frames);//printf("====================\n");printf("++++ start record!\n");FILE *fp = fopen("bak_record1.pcm", "wb");//mkfifo(OUTPUT_PATH_NAME, 0666);int fout = open(OUTPUT_PATH_NAME, O_WRONLY);while (loops > 0) {//loops--;rc = snd_pcm_readi(handle, buffer, frames);if (rc == -EPIPE) {/* EPIPE means overrun */fprintf(stderr, "overrun occurred/n");//把PCM流置于PREPARED狀態,這樣下次我們向該PCM流中數據時,它就能重新開始處理數據。snd_pcm_prepare(handle);} else if (rc < 0) {fprintf(stderr,"error from read: %s/n",snd_strerror(rc));} else if (rc != (int)frames) {fprintf(stderr, "short read, read %d frames/n", rc);}short *buf = (short*)buffer;for (int i = 0; i < frames; i++) {buf[i] *= atoi(argv[1]);}rc = fwrite(buffer, 1, size, fp);if (rc != size) {fprintf(stderr,"short write: wrote %d bytes/n", rc);break;}if (write(fout, buffer, size) <= 0) {break;}}//調用snd_pcm_drain把所有掛起沒有傳輸完的聲音樣本傳輸完全rc = snd_pcm_drain(handle);//關閉該音頻流,釋放之前動態分配的緩沖區,退出rc = snd_pcm_close(handle);free(buffer);fclose(fp);close(fout);return 0;
}

2.3 播音模塊(數據寫入ALSA)

#define ALSA_PCM_NEW_HW_PARAMS_API#include <alsa/asoundlib.h>
#include <stdio.h>
#define OUTPUT_PATH_NAME "/tmp/node1_to_node2.tmp"
#include <sys/types.h>
#include <sys/stat.h>int main(int argc, char *argv[]) {long loops;int rc;int size;snd_pcm_t *handle;snd_pcm_hw_params_t *params;unsigned int val;int dir;snd_pcm_uframes_t frames;char *buffer;/* Open PCM device for playback. */rc = snd_pcm_open(&handle, "default",SND_PCM_STREAM_PLAYBACK, 0);if (rc < 0) {fprintf(stderr,"unable to open pcm device: %s/n",snd_strerror(rc));exit(1);}/*分配一個參數對象*//* Allocate a hardware parameters object. */snd_pcm_hw_params_alloca(&params);/*初始化參數對象*//* Fill it in with default values. */snd_pcm_hw_params_any(handle, params);/* Set the desired hardware parameters. *//*交錯模式*//* Interleaved mode */snd_pcm_hw_params_set_access(handle, params,SND_PCM_ACCESS_RW_INTERLEAVED);/*設置PCM格式*//* Signed 16-bit little-endian format */snd_pcm_hw_params_set_format(handle, params,SND_PCM_FORMAT_S16_LE);/*設置通道數*//* Two channels (stereo) */snd_pcm_hw_params_set_channels(handle, params, 1);/*設置采樣率*//* 44100 bits/second sampling rate (CD quality) */val = 16000;snd_pcm_hw_params_set_rate_near(handle, params,&val, &dir);/* Set period size to 32 frames. */frames = 128;snd_pcm_hw_params_set_period_size_near(handle,params, &frames, &dir);/* Write the parameters to the driver */rc = snd_pcm_hw_params(handle, params);if (rc < 0) {fprintf(stderr,"unable to set hw parameters: %s/n",snd_strerror(rc));exit(1);}/* Use a buffer large enough to hold one period */snd_pcm_hw_params_get_period_size(params, &frames, &dir);size = frames * 2 * 1; /* 2 bytes/sample, 2 channels */printf("size value:%d, frames value:%d\n", size, frames);buffer = (char *) malloc(size);/* We want to loop for 5 seconds */snd_pcm_hw_params_get_period_time(params,&val, &dir);/* 5 seconds in microseconds divided by* period time */loops = 5000000 / val;snd_pcm_prepare(handle);printf("====start\n");mkfifo(OUTPUT_PATH_NAME, 0666);	//FILE *fp = fopen(argv[1], "rb");FILE *fp = fopen("bak_play1.pcm", "wb");int fd = open(OUTPUT_PATH_NAME, O_RDONLY);while (loops > 0) {//loops--;//rc = read(0, buffer, size);//rc = fread(buffer, 1, size, fp);rc = read(fd, buffer, size);if (rc <= 0) {fprintf(stderr, "end of file on input/n");break;} else if (rc != size) {fprintf(stderr,"short read: read %d != %d bytes/n", rc, size);}rc = fwrite(buffer, 1, size, fp);if (rc <= 0) {break;}rc = snd_pcm_writei(handle, buffer, frames);if (rc == -EPIPE) {/* EPIPE means underrun */fprintf(stderr, "underrun occurred/n");//把PCM流置于PREPARED狀態,這樣下次我們向該PCM流中數據時,它就能重新開始處理數據。snd_pcm_prepare(handle); } else if (rc < 0) {fprintf(stderr,"error from writei: %s/n",snd_strerror(rc));}  else if (rc != (int)frames) {fprintf(stderr,"short write, write %d frames/n", rc);}}//調用snd_pcm_drain把所有掛起沒有傳輸完的聲音樣本傳輸完全snd_pcm_drain(handle);//關閉該音頻流,釋放之前動態分配的緩沖區,退出snd_pcm_close(handle);free(buffer);fclose(fp);close(fd);unlink(OUTPUT_PATH_NAME);return 0;
}

2.4 數據處理模塊

(1)時域實現(加O3)

#include <sys/types.h>
#include <sys/stat.h>
#include <stdlib.h>
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>#define OUTPUT_PATH_NAME "/tmp/node1_to_node2.tmp"
#define INPUT_PATH_NAME "/tmp/node2_to_node1.tmp"int main() {if (access(INPUT_PATH_NAME, F_OK) != -1) {printf("File exists.\n");} else {mkfifo(INPUT_PATH_NAME, 0666);}int fin = open(INPUT_PATH_NAME, O_RDONLY);int fout = open(OUTPUT_PATH_NAME, O_WRONLY);int frames = 128;int size = frames * 2;char *buffer = (char *) malloc(size);int chunk_num = 5;float mu = 0.01;float *u = (float*) malloc(sizeof(float) * frames * chunk_num);float *w = (float*) malloc(sizeof(float) * frames * chunk_num);for (int i = 0; i < frames * chunk_num; i++) {u[i] = 0;w[i] = 0;}float *current_out_data = (float*) malloc(sizeof(float) * frames);float *current_data = (float*) malloc(sizeof(float) * frames);float *last_data = (float*) malloc(sizeof(float) * frames);short *out_data = (short*) malloc(sizeof(short) * frames);for (int i = 0; i < frames; i++) {current_out_data[i] = 0;current_data[i] = 0;last_data[i] = 0;out_data[i] = 0;}while (1) {int rc = read(fin, buffer, size);if (rc <= 0) {fprintf(stderr, "end of file on input/n");break;} else if (rc != size) {fprintf(stderr,"short read: read %d bytes/n", rc);} else {printf("read len: %d\n", rc);}short *input_data = (short*)buffer;//printf("current_data:");for (int i = 0; i < frames; i++) {current_data[i] = (float)(input_data[i]) / 32768.0;//printf(" %f", current_data[i]);}//printf("\n");//printf("current_out_data:");for (int i = 0; i < frames; i++) {memmove(u+1, u, sizeof(float)*(frames*chunk_num-1));u[0] = last_data[i];float uw = 0;float uu = 1e-6;for (int k = 0; k < frames*chunk_num; k++) {uw += u[k]*w[k];uu += u[k]*u[k];}current_out_data[i] = current_data[i] - uw;//printf(" (%f %f %f)", current_out_data[i], uw, uu);for (int k = 0; k < frames*chunk_num; k++) {w[k] = w[k] + mu * current_out_data[i] * u[k] / uu;}}//printf("\n");//printf("out_data:");for (int i = 0; i < frames; i++) {if (current_out_data[i] > 1.0) {current_out_data[i] = 1.0;} else if (current_out_data[i] < -1.0) {current_out_data[i] = -1.0;}out_data[i] = (short)((current_out_data[i]) * 32767.0);//printf(" %d", out_data[i]);}//printf("\n");for (int i = 0; i < frames; i++) {last_data[i] = current_data[i];}rc = write(fout, (char*)out_data, size);if (rc <= 0) {break;} else {printf("write len: %d\n", rc);}}close(fin);close(fout);free(buffer);free(u);free(w);free(current_out_data);free(current_data);free(last_data);free(out_data);unlink(INPUT_PATH_NAME);return 0;
}

(2)頻域實現(使用經典的頻域分塊自適應濾波aec算法)

#include <sys/types.h>
#include <sys/stat.h>
#include <stdlib.h>
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include "afs-api.h"#define NUM_FRAMES 128#define OUTPUT_PATH_NAME "/tmp/node1_to_node2.tmp"
#define INPUT_PATH_NAME "/tmp/node2_to_node1.tmp"int main() {if (access(INPUT_PATH_NAME, F_OK) != -1) {printf("File exists.\n");} else {mkfifo(INPUT_PATH_NAME, 0666);}int fin = open(INPUT_PATH_NAME, O_RDONLY);int fout = open(OUTPUT_PATH_NAME, O_WRONLY);int frames = NUM_FRAMES;int size = frames * 2;char *buffer = (char *) malloc(size);float *in_data_f = (float*) malloc(sizeof(float) * frames);float *out_data_f = (float*) malloc(sizeof(float) * frames);float *ref_data_f = (float*) malloc(sizeof(float) * frames);short *out_data_s = (short*) malloc(sizeof(short) * frames);for (int i = 0; i < frames; i++) {in_data_f[i] = 0;out_data_f[i] = 0;ref_data_f[i] = 0;out_data_s[i] = 0;}void *handle = api_create_afs_handle(NUM_FRAMES, 16000);api_start_afs(handle);while (1) {int rc = read(fin, buffer, size);if (rc <= 0) {fprintf(stderr, "end of file on input/n");break;} else if (rc != size) {fprintf(stderr,"short read: read %d bytes/n", rc);} else {printf("read len: %d\n", rc);}short *input_data = (short*)buffer;for (int i = 0; i < frames; i++) {in_data_f[i] = (float)(input_data[i]);}api_process_afs(handle, in_data_f, ref_data_f, out_data_f, NUM_FRAMES);for (int i = 0; i < frames; i++) {         out_data_s[i] = (short)((out_data_f[i])*1);if (out_data_s[i] > 32000) {out_data_s[i] = 32000;} else if (out_data_s[i] < -32000) {out_data_s[i] = -32000;}}for (int i = 0; i < frames; i++) {ref_data_f[i] = out_data_f[i];}rc = write(fout, (char*)out_data_s, size);if (rc <= 0) {break;} else {printf("write len: %d\n", rc);}}close(fin);close(fout);free(buffer);api_end_afs(handle);api_destroy_afs_handle(handle);free(in_data_f);free(out_data_f);free(ref_data_f);free(out_data_s);unlink(INPUT_PATH_NAME);return 0;
}

2.5 效果

三、總結

? ? ? ? 本節搭建了一個完整的擴聲系統,解決了嘯叫問題,如大家還有什么疑問,可以留言或私信討論,由于篇幅限制,完整代碼可以進入https://t.zsxq.com/qgmoN?獲取。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/diannao/75753.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/75753.shtml
英文地址,請注明出處:http://en.pswp.cn/diannao/75753.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

HTML——什么是塊級元素,什么是內聯元素,有何區別

在 HTML 中&#xff0c;塊級元素&#xff08;Block-level element&#xff09;和內聯元素&#xff08;Inline element&#xff09;是兩種不同類型元素&#xff0c;它們在頁面布局和樣式應用方面有不同的行為和特性。 塊級元素&#xff08;Block-level element&#xff09; 塊級…

01 設計模式和設計原則

類設計原則&#xff1a; 單一職責原則&#xff08;Single Responsibility Principle&#xff0c;SRP&#xff09;&#xff1a;實現類要職責單一開閉原則&#xff08;Open Close Principle&#xff0c;OCP&#xff09;&#xff1a;對擴展開放&#xff0c;對修改關閉里氏替換原則…

【踩坑日記】springboot 打包后實現類無法找到

試過了所有改什么目錄 依賴 clean都以失敗告終 最后將實現類的文件名從Impl改成impl宣布成功 記得使用idea自帶的重構

項目-蒼穹外賣(十五) WebSocket+語音播報功能實現(來訂單+催單)

一、介紹 二、入門案例 配置類&#xff1a; package com.sky.config;import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.web.socket.server.standard.ServerEndpointExporter;/…

【Spring篇】Spring的生命周期

一、Bean 生命周期的核心階段 1. 實例化&#xff08;Instantiation&#xff09; ? 觸發時機&#xff1a;容器啟動時&#xff08;單例 Bean&#xff09;或請求時&#xff08;原型 Bean&#xff09;。 ? 實現方式&#xff1a; 通過反射&#xff08;Class.newInstance() 或構造…

Redis、Memcached應用場景對比

環境 Redis官方網站&#xff1a; Redis - The Real-time Data Platform Redis社區版本下載地址&#xff1a;Install Redis | Docs Memcached官方網站&#xff1a;memcached - a distributed memory object caching system Memcached下載地址&#xff1a;memcached - a dis…

kettle插件-mysql8數據庫插件

場景&#xff1a;群里有小伙伴反饋kettle 7.x版本不能自動連接mysql8&#xff0c;安排&#xff01;&#xff01;&#xff01; 1、將mysql8的驅動包mysql-connector-java-8.0.20.jar丟到kettle的lib目錄下&#xff0c;重啟spoon。 2、配置數據庫連接&#xff0c;提示驅動類不對…

【軟件測試】:軟件測試實戰

1. ?動化實施步驟 1.1 編寫web測試?例 1.2 ?動化測試腳本開發 common public class AutotestUtils {public static EdgeDriver driver;// 創建驅動對象public static EdgeDriver createDriver(){// 驅動對象已經創建好了 / 沒有創建if( driver null){driver new EdgeDr…

深度學習入門1 基于Python的理論與實現

torch.unsqueeze()將一維數據變為二維數據&#xff0c;torch只能處理二維數據 tensor不能反向&#xff0c;variable可以反向。variable.data.numpy()轉換為numpy 第3章 神經網絡 實現softmax函數時的注意事項&#xff1a;為防止e的指數運算造成溢出 矩陣的第 0 維是列方向,第…

解決 Pentaho Kettle 插件集成中的 NoSuchMethodError: ContextFactory.enterContext() 錯誤

解決 Pentaho Kettle 插件集成中的 NoSuchMethodError: ContextFactory.enterContext() 錯誤 在使用 Pentaho Data Integration&#xff08;也稱為 Kettle&#xff09;進行數據集成和ETL開發時&#xff0c;開發者可能會遇到各種依賴沖突和技術挑戰。本文將詳細介紹一個常見的錯…

第 五 章:優化算法_《C++性能優化指南》_notes

優化算法 第五章重難點詳解與代碼實戰編譯與測試說明第五章核心知識點整理重難點梳理 第一部分&#xff1a;多選題&#xff08;10道&#xff09;第二部分&#xff1a;設計題&#xff08;5道&#xff09;答案與詳解多選題答案&#xff1a; 設計題參考實現&#xff08;以題目2為例…

多版本PHP開發環境配置教程:WAMPServer下MySQL/Apache/MariaDB版本安裝與切換

提示&#xff1a;文章寫完后&#xff0c;目錄可以自動生成&#xff0c;如何生成可參考右邊的幫助文檔 文章目錄 前言一、版本切換指南總結 前言 由于有幾個項目分別使用到PHP7.0 和7.4以及8.0版本&#xff0c;設置mysql也會根據PHP版本使用不同的版本&#xff0c;于是開始研究…

2024年數維杯數學建模C題天然氣水合物資源量評價解題全過程論文及程序

2024年數維杯數學建模 C題 天然氣水合物資源量評價 原題再現&#xff1a; 天然氣水合物&#xff08;Natural Gas Hydrate/Gas Hydrate&#xff09;即可燃冰&#xff0c;是天然氣與水在高壓低溫條件下形成的類冰狀結晶物質&#xff0c;因其外觀像冰&#xff0c;遇火即燃&#…

階段一:Java基礎語法

目標&#xff1a;掌握Java的基本語法&#xff0c;理解變量、數據類型、運算符、控制結構等。 1. Java開發環境搭建 安裝JDK配置環境變量編寫第一個Java程序 代碼示例&#xff1a; // HelloWorld.java public class HelloWorld { // 定義類名為 HelloWorldpublic static vo…

從0到1,解鎖Ant Design X的無限可能

Ant Design X 是什么&#xff1f; 在人工智能飛速發展的當下&#xff0c;AI 驅動的界面已成為軟件開發的重要趨勢。而 Ant Design X 正是順應這一趨勢&#xff0c;于 2024 年應運而生的一款遵循 Ant Design 設計體系的 React UI 庫&#xff0c;它旨在幫助開發者輕松打造 AI 驅…

Graphpad Prism for Mac醫學繪圖

Graphpad Prism for Mac醫學繪圖 文章目錄 Graphpad Prism for Mac醫學繪圖一、介紹二、效果三、下載 一、介紹 GraphPad Prism for Mac是一款功能強大、易于使用的科學和統計分析軟件&#xff0c;適用于各種類型的數據處理和可視化需求。無論您是進行基礎研究、臨床試驗還是學…

mysqloracledb2 (uuid函數)

項目場景&#xff1a; 創建一個32位的UUID 問題描述 原因分析&#xff1a; 解決方案&#xff1a; mysql內置UUID函數 SELECT UUID(); SELECT UUID_SHORT();oracle內置UUID函數 SELECT sys_guid() FROM dual;db2&#xff0c;模擬UUID函數 SELECT TEST || substr (CONCAT…

Android實踐開發制作小猴子摘桃小游戲

Android實踐制作小猴子摘桃小游戲 實踐素材項目源文件獲取&#xff1a;Android可能存在版本差異項目如果不能正確運行&#xff0c;可以使用里面的素材自己構建項目Android實踐制作小猴子摘桃小游戲Android實踐制作小猴子摘桃小游戲https://mp.weixin.qq.com/s/jNU_hVfj9xklsil…

Postman 下載文件指南:如何請求 Excel/PDF 文件?

在 Postman 中進行 Excel/PDF 文件的請求下載和導出&#xff0c;以下是簡明的步驟&#xff0c;幫助你輕松完成任務。首先&#xff0c;我們將從新建接口開始&#xff0c;逐步引導你完成整個過程。 Postman 請求下載/導出 excel/pdf 文件教程

重要重要!!fisher矩陣是怎么計算和更新的,以及計算過程中參數的物理含義

fisher矩陣是怎么計算和更新的,以及計算過程中參數的物理含義 Fisher信息矩陣(Fisher Information Matrix, FIM)用于衡量模型參數估計的不確定性,其計算和更新在統計學、機器學習和優化中具有重要作用。以下是其計算和更新的關鍵步驟: 一、Fisher矩陣的計算 定義 Fisher…