首页 > 其他分享 >Speex的移植和简单使用

Speex的移植和简单使用

时间:2023-09-14 17:44:32浏览次数:36  
标签:Speex speex SPEEX int sp 移植 简单 id channel

前言 只是小白在学习过程中的记录,可能存在错误。。。 音频使用3A算法,Speex也支持。。 3A:声学回声消除(AEC)、背景噪声抑制(ANS)、自动增益控制(AGC)三种音频算法的合称 个人尝试之后发现,背景噪声消除效果较好,AEC和AGC似乎没什么用。。   一、speex、speexdsp的简单介绍 Speex:开源免费、无专利保护、针对语音而设计,支持音频编解码和3A算法处理 Speexdsp:就是在speex上提取的3A算法而已 官网:https://www.speex.org/ 下载源码:https://www.speex.org/downloads/ 手册:http://www.speex.org/docs/api/speex-api-reference/index.html http://maemo.org/api_refs/5.0/5.0-final/speex/group__SpeexPreprocessState.html   二、下载移植 1.下载 直接进入官网,选择需要的包进行下载即可   2.Linux下编译安装 Speex的编译安装和大部分开源包都是一样的,解压、配置、编译、安装   ./configure  --prefix="安装目录"  --host="安装平台(arm-linux)" --enable-shared  生成共享库 --enable-static  生成静态库 --enable-sse     支持使用SSE指令 CC= 需要使用的交叉编译链(注意此处要为绝对路径,否则编译失败)   ./configure --prefix="/home/y/workfile/speexdsp-install" --host="arm-linux" --enable-shared --enable-static --enable-sse CC=/opt/gcc-arm-8.3-2019.03-x86_64-arm-linux-gnueabihf/bin/arm-linux-gnueabihf-gcc     编译:make 安装:make install 生成文件存放与prefix指定目录下   同理可以编译安装speex speexdsp ogg   个人测试demo 更多的东西有待验证,以下只是个人使用的一部分   speex-demo.c //main函数参数一是原始pcm文件名,参数二是去噪后的pcm文件名   #ifdef HAVE_CONFIG_H #include "config.h" #endif   #include "speex_preprocess.h" #include <stdio.h> #include <string.h>   #define FRAME_SIZE   1024 //1152 #define FRAME_SAMPLERATE 32000 #define DENOISE_DB (-90)   int main(int argn, char* argv[]) { char* szInFilename = NULL; char* szOutFilename = NULL; FILE* pInFileHandle = NULL; FILE* pOutFileHandle = NULL;   short in[FRAME_SAMPLERATE];   int i; SpeexPreprocessState *st; int count=0; float f;   printf("starting....\r\n");   if(argn != 3){ printf("please input 2 parameters\r\n"); return -1; }   //memset((void*)empty, 0, sizeof(empty));   szInFilename = argv[1]; szOutFilename = argv[2];   pInFileHandle = fopen(szInFilename, "rb"); //打开原始文件 if(!pInFileHandle){ printf("open file %s error\r\n", szInFilename); return -2; }   pOutFileHandle = fopen(szOutFilename, "wb"); //转换后的文件 if(!pOutFileHandle){ printf("open file %s error\r\n", szOutFilename); fclose(pInFileHandle); return -3; } /** 创建预处理器 SpeexPreprocessState SpeexPreprocessState* preprocess_state = speex_preprocess_state_init(frame_size,sampling_rate); frame_size:每次的预处理数 sampling_rate:采样率 **/ st = speex_preprocess_state_init(FRAME_SIZE, FRAME_SAMPLERATE);   int denoise = 1; int noiseSuppress = DENOISE_DB; /**预处理属性设置,类似于ioctl,节省cpu**/ speex_preprocess_ctl(st, SPEEX_PREPROCESS_SET_DENOISE, &denoise); //去噪开关设置 1打开 2关闭 speex_preprocess_ctl(st, SPEEX_PREPROCESS_SET_NOISE_SUPPRESS, &noiseSuppress); //设置噪声的最大衰减值 i=0; //0 speex_preprocess_ctl(st, SPEEX_PREPROCESS_SET_AGC, &i); // Set maximal gain increase in dB/second (int32) i=8000; speex_preprocess_ctl(st, SPEEX_PREPROCESS_SET_AGC_LEVEL, &i); //AGC级别  Set preprocessor Automatic Gain Control level (float) i=0; //0 speex_preprocess_ctl(st, SPEEX_PREPROCESS_SET_DEREVERB, &i); //Set preprocessor dereverb state f=.0; speex_preprocess_ctl(st, SPEEX_PREPROCESS_SET_DEREVERB_DECAY, &f);//Set preprocessor dereverb decay f=.0; speex_preprocess_ctl(st, SPEEX_PREPROCESS_SET_DEREVERB_LEVEL, &f); //Set preprocessor dereverb level     int vad = 1; int vadProbStart = 80; int vadProbContinue = 65; speex_preprocess_ctl(st, SPEEX_PREPROCESS_SET_VAD, &vad); //静音检测 VAD 1on  2off speex_preprocess_ctl(st, SPEEX_PREPROCESS_SET_PROB_START , &vadProbStart); //设置VAD从静音到声音的概率 Set probability required for the VAD to go from silence to voice speex_preprocess_ctl(st, SPEEX_PREPROCESS_SET_PROB_CONTINUE, &vadProbContinue); //设置VAD保持语音状态所需的概率(整数百分比) Set probability required for the VAD to stay in the voice state (integer percent)   while (1) { int vad; int iLen = fread(in, sizeof(short), FRAME_SIZE, pInFileHandle); if(iLen <= 0){ break; }   if (feof(pInFileHandle)) //用feof()去判断文件是否结束,若结束,返回非零,若文档未结束,则返回零 break;   /** int speex_preprocess_run(SpeexPreprocessState *st, spx_int16_t *x); SpeexPreprocessState:预处理器  x:要处理的数据 大小要和init时相同 return: 1---语音  0---静音/噪音 **/ vad = speex_preprocess_run(st, in);   if(vad != 0){ printf("speech.\r\n"); fwrite(in, sizeof(short), FRAME_SIZE, pOutFileHandle); }else{ printf("slience############################\r\n"); fwrite(in, sizeof(short), FRAME_SIZE, pOutFileHandle); } count++; } /**销毁预处理器**/ speex_preprocess_state_destroy(st);         fclose(pInFileHandle); fclose(pOutFileHandle);   return 0; }   Makefile LIBDIR=./lib INCLUDEDIR=./include/speex SRCS=$(wildcard *.c)   TARGET = ./speex-demo   #HAVE_STDINT_H HAVE_CONFIG_H   CFLAGS += -Wall -O -g -D HAVE_CONFIG_H CFLAGS += -pthread -lm -O2 -lspeexdsp CFLAGS += -L $(LIBDIR) CFLAGS += -I $(INCLUDEDIR)   CC=arm-linux-gnueabihf-gcc   .PHONE : clean all   all:$(TARGET)   $(TARGET):$(SRCS) $(CC) $(CFLAGS) -o $@ $^       clean: @rm -f $(TARGET)   个人在工程中使用的部分代码 1.speexdsp.c   #include "speexdsp.h"   #ifdef HAVE_CONFIG_H #include "config.h" #endif   #include "speex_preprocess.h" #include "speex_echo.h"     #include <stdio.h> #include <string.h>   #define FRAME_SIZE   2048 //1152   #define IS_PRINT  0   #define FRAME_SIZE_MS 2048 //should correspond to 10-20 ms #define FILTER_LEN_MS 256 //32000*4/1000 //should generally correspond to 100-500 ms   #define SPEEX_NUM 10   #define DENOISE_DB (-90)   static int init_falg[SPEEX_NUM] = {0}; static int g_samplerate[SPEEX_NUM] = {0};   typedef struct { int DB_SWITCH; int NOISE_SUPPRESS; //降噪值 int AGC; int AGC_LEVEL; int DEREVERB; float F; }SPEEX_ARG_S;   SpeexPreprocessState *sp[SPEEX_NUM]; SpeexEchoState *echo_sp[SPEEX_NUM];   void * speexdsp_init_run(int channel_id,int data_size,int samplerate,AUDIO_CODEC_TYPE audio_type) { if(init_falg[channel_id]) return 0;   SPEEX_ARG_S speexArg = { .DB_SWITCH = 1,//是否打开噪音抑制 .NOISE_SUPPRESS=-100,//DENOISE_DB,//噪音的最大程度衰减的分贝值,负值 越小越强 .AGC = 0,//自动增益控制 .AGC_LEVEL=8000,//自动增益控制默认8000 .DEREVERB=1,//是否消除混响 .F=20};//消除混响的等级 消除混响的衰减   int ret = 0,i;   if(audio_type != AUDIO_CODEC_PCM) { speexdsp_destroy_resource(channel_id); sp[channel_id] = NULL; echo_sp[channel_id] = NULL; // ec = NULL; if(IS_PRINT)printf("#############NOT NOT NOT PCM channel_id[%d]!!!!!\n",channel_id); return NULL; } else if(g_samplerate[channel_id] != samplerate) { speexdsp_destroy_resource(channel_id); g_samplerate[channel_id] = samplerate; sp[channel_id] = NULL; echo_sp[channel_id] = NULL; // ec = NULL; if(IS_PRINT)printf("#############samplerate different different different:%d  channel_id[%d]!!!!!\n",samplerate,channel_id); } else { speexdsp_destroy_resource(channel_id); sp[channel_id] = NULL; if(IS_PRINT)printf("#############is is is is PCM channel_id[%d]!!!!!\n",channel_id); }     if(IS_PRINT)printf("----------------********---------------------samplerate:%d data_size:%d channel_id[%d]\n",samplerate,data_size,channel_id); sp[channel_id] = speex_preprocess_state_init(data_size, samplerate);   // i =1;//设置是否打开Speex预处理器句柄的残余回音消除,开启后应在回音消除后再进行预处理 // speex_echo_ctl(echo_sp[channel_id],SPEEX_PREPROCESS_SET_ECHO_STATE,&i); i = -40;//设置残余回音消除时,残余回音的最大程度衰减的分贝值 speex_preprocess_ctl(sp[channel_id],SPEEX_PREPROCESS_SET_ECHO_SUPPRESS,&i); i=-1;//设置残余回音消除时,接近末尾的残余回音的最大程度衰减的分贝值 speex_preprocess_ctl(sp[channel_id],SPEEX_PREPROCESS_SET_ECHO_SUPPRESS_ACTIVE,&i);   // speex_preprocess_ctl(sp[channel_id], SPEEX_PREPROCESS_SET_ECHO_STATE, echo_sp[channel_id]);   ret = speex_preprocess_ctl(sp[channel_id], SPEEX_PREPROCESS_SET_DENOISE, &speexArg.DB_SWITCH); if(ret < 0) printf("[SPEEXDSP] SPEEX_PREPROCESS_SET_DENOISE failed!!\n");   ret = speex_preprocess_ctl(sp[channel_id], SPEEX_PREPROCESS_SET_NOISE_SUPPRESS, &speexArg.NOISE_SUPPRESS); //设置降噪值 if(ret < 0) printf("SPEEX_PREPROCESS_SET_NOISE_SUPPRESS failed!!\n");   ret = speex_preprocess_ctl(sp[channel_id], SPEEX_PREPROCESS_SET_AGC, &speexArg.AGC); if(ret < 0) printf("SPEEX_PREPROCESS_SET_AGC failed!!\n");   ret = speex_preprocess_ctl(sp[channel_id], SPEEX_PREPROCESS_SET_AGC_LEVEL, &speexArg.AGC_LEVEL); if(ret < 0) printf("SPEEX_PREPROCESS_SET_AGC_LEVEL failed!!\n");   ret = speex_preprocess_ctl(sp[channel_id], SPEEX_PREPROCESS_SET_DEREVERB, &speexArg.DEREVERB); if(ret < 0) printf("SPEEX_PREPROCESS_SET_DEREVERB failed!!\n");   ret = speex_preprocess_ctl(sp[channel_id], SPEEX_PREPROCESS_SET_DEREVERB_DECAY, &speexArg.F); if(ret < 0) printf("SPEEX_PREPROCESS_SET_DEREVERB_DECAY failed!!\n");   ret = speex_preprocess_ctl(sp[channel_id], SPEEX_PREPROCESS_SET_DEREVERB_LEVEL, &speexArg.F); if(ret < 0) printf("SPEEX_PREPROCESS_SET_DEREVERB_LEVEL failed!!\n");   init_falg[channel_id] = 1; if(IS_PRINT)printf("-----------------------speex_preprocess_state_init--channel_id[%d]---OK OK OK-------------------------------------------\n",channel_id); return sp[channel_id]; }   int speexdsp_preprocess_audio(int channel_id,short *data) { if(!init_falg[channel_id] || sp[channel_id] == NULL) return 0;   if(sp[channel_id] == NULL){ printf("channel_id[%d] sp is NULL\n",channel_id); return -1; }     speex_preprocess_run(sp[channel_id], data);   // printf("speex_preprocess_run !\n");   return 0; }   int speexdsp_echo_cancellatio(int channel_id ,short *micro,short *speaker,short *out) { if(!init_falg[channel_id] || sp[channel_id] == NULL || echo_sp[channel_id] == NULL) return 0;   if(micro == NULL)printf("micro is NULL\n"); if(speaker == NULL)printf("speaker is NULL");   printf("#########speexdsp_echo_cancellatio\n"); speex_echo_cancellation(echo_sp[channel_id], micro, speaker, out);   return 0; }   int speexdsp_echo_play(int channel_id,short *frame) {   if(!init_falg[channel_id] || sp[channel_id] == NULL || echo_sp[channel_id] == NULL) return 0; speex_echo_playback(echo_sp[channel_id], frame); return 0; }   int speexdsp_echo_captrue(int channel_id,short *input_frame,short *output_frame) { if(!init_falg[channel_id] || sp[channel_id] == NULL || echo_sp[channel_id] == NULL) return 0; speex_echo_capture(echo_sp[channel_id], input_frame,output_frame); return 0; }     int speexdsp_destroy_resource(int channel_id) { if(!init_falg[channel_id]){ if(IS_PRINT)printf("-----------------------speexdsp_destroy_resource-----000000000000000000----channel_id[%d]-----------------\n",channel_id); return 0; }   if(echo_sp[channel_id] != NULL){ printf("*****************speex_echo_state_destroy******echo_sp[%d]********\n",channel_id); speex_echo_state_destroy(echo_sp[channel_id]); }   if(sp[channel_id] != NULL){ if(IS_PRINT)printf("*****************speexdsp_destroy_resource******channel_id[%d]********\n",channel_id); speex_preprocess_state_destroy(sp[channel_id]); sleep(1); } init_falg[channel_id] = 0; sp[channel_id] = NULL; echo_sp[channel_id] = NULL; if(IS_PRINT)printf("-----------------------speexdsp_destroy_resource----------channel_id[%d]-------------------------------------\n",channel_id); return 0; }     2.speexdsp.h   #ifndef SPEEXDSP_H__ #define SPEEXDSP_H__   typedef enum {     AUDIO_CODEC_PCM,     AUDIO_CODEC_G711A,     AUDIO_CODEC_G711U,     AUDIO_CODEC_MP3,     AUDIO_CODEC_AAC }AUDIO_CODEC_TYPE;      void * speexdsp_init_run(int channel_id,int data_size,int samplerate,AUDIO_CODEC_TYPE audio_type); int speexdsp_preprocess_audio(int channel_id,short *data); int speexdsp_destroy_resource(int channel_id);   #endif    

标签:Speex,speex,SPEEX,int,sp,移植,简单,id,channel
From: https://www.cnblogs.com/kn-zheng/p/17703019.html

相关文章

  • 【代码分享】PHP对接网易易盾活体检测代码风险,简单粗暴实现
    在一些日常应用中,有些敏感数据或者功能,需要用到对应真实本人进行业务操作,所以我们就会用到活体实人认证的功能,在对接过程中,发现网易易盾的较为好用,现在把实现代码贴出来,本案例仅提供数据端,前端模板大家可以自行设置接入步骤第一步注册网易易盾账号,进行业务申请获取参数所需......
  • 进程 线程 协程 简单介绍
    一、进程1.1进程可看做是正在执行的程序进程需要一定的资源(如CPU、时间、内存、文件和I/O设备)来完成其任务。这些资源在创建进程或者执行进程时被分配。1.2进程的组成有:PCB、程序段、数据段。PCB(进程控制块,processcontrolblock):保存进程运行期间相关的数据,是进程存在......
  • Git日常简单命令一览
    总结一些常用的git操作命令,并不断更新...1、个人信息配置:gitconfig--globaluser.name"shensy"  //修改用户名[email protected] //修改邮箱gitconfig--list //查看个人信息2、clone:gitclonessh://[email protected]/~/abc/projectname.g......
  • js简单的倒计时器~~⏰
    1.效果图2.html部分3.逻辑部分3.1获取当前时间,时间差//获取当前时间vardate=newDate();varnow=date.getTime();//设置截止时间varstr="2023/9/1412:28:34";varendDate=newDate(str);varend=......
  • 简单DOS命令 快捷键总结
    ALT+F4关闭窗口win+R打开指令外加CMDCTRL+A全选CTRL+C复制CTRL+Z撤销CTRL+Y恢复CTRL+F打开搜索CTRL+h替换CTRL+N打开新窗口CTRL+S保存CTRL+W关闭界面CTRL+P打印CTRL+滚轮自由放大CTRL++放大CTRL+shift+N开文件夹shift+delete删除文件CTRL+shift+esc任务管理器或ctrl+Alt+.win+......
  • RBFS简单理解
    论文引用Sharma,DishaandSanjayKumarDubey.“ComparativeStudyofRBFS&ARBFSAlgorithm.”IOSRJournalofComputerEngineering10(2013):105-110.前言论文中的伪代码可能有错误贴一份写的比较清楚点的帖子算法思路在h函数保证一致性的情况下,第一次扩展到n时......
  • ansible-playbook简单了解
    1.playbook简介playbook是ansible用于配置,部署,和管理节点的剧本。2.playbook格式playbook由YAML语言编写。3.playbook执行过程1.将以编排好的任务集(ansible单条命令集合)写进playbook2.通过ansible-playbook命令分拆任务集逐条执行ansible命令,按预定规则逐条执行4.playbook......
  • 数据响应的简单实现
    JavaScript数据响应是一种重要的前端开发概念,是指在应用程序中的数据发生变化时,能够自动更新与这些数据相关的用户界面(UI)部分的能力,它有助于构建交互性强、用户体验良好的Web应用程序。我们来总结一下目前可以简单实现JavaScript中的数据响应的方法。使用框架像Vue.js和......
  • terraform简单的开始-安装和一些配置
    terraform的安装:官方下载:浏览器打开terraform官方主页https://www.terraform.io/点击DownloadTerraform跳转到程序下载页面:找到自己对应的操作系统,按照操作系统选择安装terraform的方式:linux为例:我有一台rockylinux工作主机也是直接参照官方文档安装的:terraform--v......
  • spring-websocket 简单使用
    之前自己基于netty实现了websocket协议,实现单聊以及群聊。这里记录下spring封装的spring-websocket使用方式。1.后端1.pom<projectxmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation......