音频demo:将PCM数据和Speex数据进行相互编解码

1、README

a. libspeex移植步骤

源码下载地址:https://xiph.org/downloads/ 或 https://www.speex.org/downloads/ 或 https://www.linuxfromscratch.org/blfs/view/svn/multimedia/speex.html

 tar xzf speex-1.2.1.tar.gzcd speex-1.2.1/./configure --prefix=$PWD/_installmake -j8make installstrip --strip-unneeded _install/lib/*
$ tree -h _install/
_install/
├── [4.0K]  include
│   └── [4.0K]  speex
│       ├── [6.5K]  speex_bits.h
│       ├── [4.9K]  speex_callbacks.h
│       ├── [ 203]  speex_config_types.h
│       ├── [ 14K]  speex.h
│       ├── [4.0K]  speex_header.h
│       ├── [3.6K]  speex_stereo.h
│       └── [3.5K]  speex_types.h
├── [4.0K]  lib
│   ├── [188K]  libspeex.a
│   ├── [1006]  libspeex.la
│   ├── [  17]  libspeex.so -> libspeex.so.1.5.2
│   ├── [  17]  libspeex.so.1 -> libspeex.so.1.5.2
│   ├── [ 98K]  libspeex.so.1.5.2
│   └── [4.0K]  pkgconfig
│       └── [ 358]  speex.pc
└── [4.0K]  share├── [4.0K]  aclocal│   └── [3.6K]  speex.m4└── [4.0K]  doc└── [4.0K]  speex└── [429K]  manual.pdf8 directories, 15 files
b. 说明
demo现状
  • 目前暂时没找到相关播放器直接播放spx格式文件;

  • 将demo编码生成的spx格式文件再通过demo解码生成pcm数据是能正常播放的;

  • 目前demo生成的spx格式文件是夹带着4个字节编码数据量大小,即:

    [spx数据长度(4字节)]+[spx编码数据(n字节)] + [spx数据长度(4字节)]+[spx编码数据(n字节)] + ...
    
关于speex格式的说明
  • Speex(音标[spi:ks])是一套开源免费的、无专利保护的、针对语音设计的音频压缩格式。
  • Speex编解码器已经被Opus编解码器淘汰,Speex还是可以继续使用,由于Opus比Speex在各方面都更好,所以鼓励大家切换到Opus,但是Opus只支持编码和解码,不支持噪音抑制、声学回音消除等其他处理功能。
  • 只支持8000Hz窄带(Narrow Band)、16000Hz宽带(Wide Band)、32000Hz超宽带(Ultra Wide Band)的三种带模式进行编解码,不支持其他采样频率。
  • 只支持单声道,不支持多声道。
  • 支持强化立体声编码(Intensity Stereo Encoding)。
  • 支持数据包丢失隐藏(Packet Loss Concealment、PLC)。
  • 支持固定比特率(Constant Bit Rate、CBR)。
  • 支持可变比特率(Variable Bit Rate、VBR)。
  • 支持平均比特率(Average Bit Rate、ABR)。
  • 支持非连续传输(Discontinuous transmission、DTX)。
  • 支持定点执行(Fixed-point implementation)。
  • 支持浮点执行(Floating-point implementation)。
  • 支持声学回音消除(Acoustic Echo Canceller、AEC)。
  • 支持残余回音消除(Residual Echo Canceller、REC)。
  • 支持噪音抑制(Noise Suppression、NS)。
  • 支持混响音消除(Dereverb)。
  • 支持自动增益控制(Automatic Gain Control、AGC)。
  • 支持语音活动检测(Voice Activity Detection、VAD)。
  • 支持多速率(multi-rate)。
  • 支持嵌入式(Embedded)。
  • 支持重采样(Resample)。
c. 使用方法
编译
$ make clean && make
rm -rf pcm2speex speex2pcm pcm2speex_gpt speex2pcm_gpt out*
gcc main_pcm2speex.c -I./include -lspeex -L./lib -lm -o pcm2speex
gcc main_speex2pcm.c -I./include -lspeex -L./lib -lm -o speex2pcm
gcc main_pcm2speex_gpt.c -I./include -lspeex -L./lib -lm -o pcm2speex_gpt
gcc main_speex2pcm_gpt.c -I./include -lspeex -L./lib -lm -o speex2pcm_gpt
编码
$ ./pcm2speex 
Usage: ./pcm2speex <in-pcm-file> <sample-rate> <out-spx-file>
examples: ./pcm2speex ./audio/test_8000_16_1.pcm  8000  out_8000.spx./pcm2speex ./audio/test_16000_16_1.pcm 16000 out_16000.spx
解码
$ ./speex2pcm 
Usage: ./speex2pcm <in-spx-file> <sample-rate> <out-pcm-file>
examples: ./speex2pcm out_8000.spx  8000  out_8000.pcm./speex2pcm out_16000.spx 16000 out_16000.pcm
d. 参考文章
  • speex 编码简介-CSDN博客

  • 音频编解码speex库的使用方法-CSDN博客

  • Speex详解(2019年09月25日更新) - 赤勇玄心行天道 - 博客园

e. demo目录架构
$ tree
.
├── audio
│   ├── test_16000_16_1.pcm
│   └── test_8000_16_1.pcm
├── docs
│   ├── speex 编码简介-CSDN博客.mhtml
│   ├── Speex详解(2019年09月25日更新) - 赤勇玄心行天道 - 博客园.pdf
│   └── 音频编解码speex库的使用方法-CSDN博客.pdf
├── include
│   └── speex
│       ├── speex_bits.h
│       ├── speex_callbacks.h
│       ├── speex_config_types.h
│       ├── speex.h
│       ├── speex_header.h
│       ├── speex_stereo.h
│       └── speex_types.h
├── lib
│   └── libspeex.a
├── main_pcm2speex.c
├── main_speex2pcm.c
├── Makefile
├── opensource
│   └── speex-1.2.1.tar.gz
├── README.md
└── reference_code├── blog_pcm2speex.c├── blog_speex2pcm.c├── gpt_pcm2speex.c└── gpt_speex2pcm.c

2、主要代码片段

main_pcm2speex.c
#include <speex/speex.h>
#include <stdio.h>
#include <stdlib.h>#include "speex/speex.h"/* 定义帧大小,对于窄带模式,帧大小通常是160 */
#define FRAME_SIZE 160int main(int argc, char **argv)
{char *in_pcm_file_name = NULL;FILE *fp_in_pcm = NULL;unsigned int sample_rate = 0;char *out_spx_file_name = NULL;FILE *fp_out_spx = NULL;short *pcm_buf = NULL;char *cbits = NULL;int nbBytes;int framesize = 0;/* 检查参数 */if(argc != 4){printf("Usage: \n""\t %s <in-pcm-file> <sample-rate> <out-spx-file>\n""examples: \n""\t %s ./audio/test_8000_16_1.pcm  8000  out_8000.spx\n""\t %s ./audio/test_16000_16_1.pcm 16000 out_16000.spx\n", argv[0], argv[0], argv[0]);return -1;}in_pcm_file_name = argv[1];sample_rate = atoi(argv[2]);out_spx_file_name = argv[3];const SpeexMode *speex_mode = NULL;switch(sample_rate){case 8000:speex_mode = &speex_nb_mode;break;case 16000:speex_mode = &speex_wb_mode;break;case 32000:speex_mode = &speex_uwb_mode;break;}/* 初始化编码器状态 */void *state = speex_encoder_init(speex_mode);/* 设置编码质量为8(15 kbps) */int quality = 8;speex_encoder_ctl(state, SPEEX_SET_QUALITY, &quality);speex_encoder_ctl(state, SPEEX_SET_SAMPLING_RATE, &sample_rate);speex_encoder_ctl(state, SPEEX_GET_FRAME_SIZE, &framesize);int bps = 0; // 只是用来打印一下speex_encoder_ctl(state, SPEEX_GET_BITRATE, &bps);printf("It will encode with [quality: %d, sample_rate: %d, framesize: %d, bps: %d].\n", quality, sample_rate, framesize, bps);fp_in_pcm = fopen(in_pcm_file_name, "rb");if (!fp_in_pcm) {printf("Error opening input file: %s\n", in_pcm_file_name);speex_encoder_destroy(state);return 1;}/* 打开输出文件,用于存储编码后的Speex数据 */fp_out_spx = fopen(out_spx_file_name, "wb");if (!fp_out_spx) {printf("Error opening output file\n");fclose(fp_in_pcm);speex_encoder_destroy(state);return 1;}pcm_buf = (short *)malloc(sizeof(short) * framesize);cbits = (char *)malloc(sizeof(char) * framesize * 1.25); // 多个1/4/* 初始化位处理结构 */SpeexBits bits;speex_bits_init(&bits);/* 循环读取、编码并写入数据 */while (1) {/* 读取一个16位/sample的音频帧 */size_t bytesRead = fread(pcm_buf, sizeof(short), framesize, fp_in_pcm);if (bytesRead != framesize) {if (feof(fp_in_pcm)) {break; // 文件结束} else {printf("Error reading input file\n");speex_bits_destroy(&bits);fclose(fp_out_spx);fclose(fp_in_pcm);speex_encoder_destroy(state);return 1;}}/* 重置位处理结构,以便编码新帧 */speex_bits_reset(&bits);/* 编码帧 */speex_encode_int(state, pcm_buf, &bits);/* 将位复制到字符数组中,以便写入 */nbBytes = speex_bits_write(&bits, cbits, 200);/* 写入帧大小 *//* LRM: 这里写入接下来编码的数据大小,这里记录方便后面解码知道要读多少,不是标准的spx文件格式 */fwrite(&nbBytes, sizeof(int), 1, fp_out_spx);/* 写入压缩数据 *//* LRM: 这里写入编码后的spx数据 */fwrite(cbits, 1, nbBytes, fp_out_spx);printf("[Speex Encode] pcm(%lu Bytes) -> spx(%d Bytes).\n", framesize * sizeof(short), nbBytes);}/* 清理资源 */speex_bits_destroy(&bits);fclose(fp_out_spx);fclose(fp_in_pcm);speex_encoder_destroy(state);free(pcm_buf);free(cbits);return 0;
}
main_speex2pcm.c
#include <speex/speex.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>int main(int argc, char **argv)
{char *in_spx_file_name = NULL;FILE *fp_in_spx = NULL;unsigned int sample_rate = 0;char *out_pcm_file_name = NULL;FILE *fp_out_pcm = NULL;char *speex_buffer = NULL;short *pcm_buffer = NULL;int framesize = 0;// 定义SpeexBits和编码状态变量SpeexBits bits;void *dec_state;/* 检查参数 */if(argc != 4){printf("Usage: \n""\t %s <in-spx-file> <sample-rate> <out-pcm-file>\n""examples: \n""\t %s out_8000.spx  8000  out_8000.pcm\n""\t %s out_16000.spx 16000 out_16000.pcm\n", argv[0], argv[0], argv[0]);return -1;}in_spx_file_name = argv[1];sample_rate = atoi(argv[2]);out_pcm_file_name = argv[3];const SpeexMode *speex_mode = NULL;switch(sample_rate){case 8000:speex_mode = &speex_nb_mode;break;case 16000:speex_mode = &speex_wb_mode;break;case 32000:speex_mode = &speex_uwb_mode;break;}// 初始化bitsspeex_bits_init(&bits);// 初始化编码状态,这里使用窄带模式dec_state = speex_decoder_init(speex_mode);speex_decoder_ctl(dec_state, SPEEX_SET_SAMPLING_RATE, &sample_rate);speex_decoder_ctl(dec_state, SPEEX_GET_FRAME_SIZE, &framesize);// 打开输入文件,这里假设输入文件是Speex编码的fp_in_spx = fopen(in_spx_file_name, "rb");if (!fp_in_spx) {printf("Error opening input file\n");return 1;}// 打开输出文件,用于存储解码后的PCM数据fp_out_pcm = fopen(out_pcm_file_name, "wb");if (!fp_out_pcm) {printf("Error opening output file\n");fclose(fp_in_spx);return 1;}speex_buffer = malloc(framesize); // 这是编码后的,空间足够了的pcm_buffer = (short *)malloc(sizeof(short) * framesize);// 循环读取、解码并写入文件while (1) {// 读取一帧Speex编码的数据#if 0int bytes_read = fread(&bits.bytes, 1, sizeof(bits.bytes), fp_in_spx);if (bytes_read == 0) {// 如果读取的字节数为0,表示文件结束break;}bits.nbytes = bytes_read;bits.nbBits = bytes_read * 8;#elseint spx_bytes = 0;int bytes_read = 0;/* LRM: 这里读出接下来的spx编码数据长度,对应于我们编码时写入的数据长度 */bytes_read = fread(&spx_bytes, 1, sizeof(spx_bytes), fp_in_spx);if (bytes_read == 0) {// 如果读取的字节数为0,表示文件结束printf("file end.\n");break;}printf("will read spx bytes: %d, ", spx_bytes);/* LRM: 这里读出编码后的spx数据 */bytes_read = fread(speex_buffer, 1, spx_bytes, fp_in_spx);if (bytes_read == 0) {// 如果读取的字节数为0,表示文件结束printf("file end(-1).\n");break;}printf("decode output pcm size: %lu\n", framesize * sizeof(short));// 将 Speex 数据填充到比特流结构体中speex_bits_read_from(&bits, speex_buffer, bytes_read);#endif// 解码speex_decode_int(dec_state, &bits, pcm_buffer);// 写入解码后的PCM数据fwrite(pcm_buffer, sizeof(short), framesize, fp_out_pcm);}// 清理资源fclose(fp_out_pcm);fclose(fp_in_spx);speex_bits_destroy(&bits);speex_decoder_destroy(dec_state);return 0;
}

3、demo下载地址(任选一个)

  • https://download.csdn.net/download/weixin_44498318/89525489
  • https://gitee.com/linriming/Audio_pcm_speex_enc_dec.git
  • https://github.com/linriming20/audio_pcm_speex_enc_dec.git

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/868795.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

政安晨:【Keras机器学习示例演绎】(五十三)—— 使用 TensorFlow 决策森林进行分类

目录 简介 设置 准备数据 定义数据集元数据 配置超参数 实施培训和评估程序 实验 1&#xff1a;使用原始特征的决策森林 检查模型 实验 2&#xff1a;目标编码决策森林 创建模型输入 使用目标编码实现特征编码 使用预处理器创建梯度提升树模型 训练和评估模型 实验…

社区6月月报 | Apache DolphinScheduler重要修复和优化记录

各位热爱Apache DolphinScheduler的小伙伴们&#xff0c;社区6月月报更新啦&#xff01;这里将记录Apache DolphinScheduler社区每月的重要更新&#xff0c;欢迎关注。 月度Merge Stars 感谢以下小伙伴上个月为Apache DolphinScheduler所做的精彩贡献&#xff08;排名不分先后…

矩阵式键盘最小需要多少个IO驱动

1. 概述 矩阵式键盘由于有其占用硬件资源少的优点有着极其广泛的应用&#xff0c;如PC键盘、电话按键、家用电器等等这类产品.矩阵键盘的基本原理如下所示&#xff08;仅是原理示例&#xff0c;实际实现上还会为每个按键加上防倒流的二极管解决“鬼影”问题&#xff09;&#x…

Windows下编译OpenSSL静态库

目录 1. 版本与下载地址 2. 下载与安装VS2015 3. 下载与安装Perl 4. 测试ActivePerl是否安装正确 5. 下载OpenSSL 6. 编译32位OpenSSL静态库 6.1 解压openssl-1.0.2l.tar.gz 6.2 打开VS2015 x86本机工具命令提示符 6.3 输入命令进入到openssl的目录中 6.4 执行配置命…

完美解决AttributeError: ‘DataFrame‘ object has no attribute ‘ix‘的正确解决方法,亲测有效!!!

完美解决AttributeError: ‘DataFrame’ object has no attribute ix’的正确解决方法&#xff0c;亲测有效&#xff01;&#xff01;&#xff01; 亲测有效 完美解决AttributeError: DataFrame object has no attribute ix的正确解决方法&#xff0c;亲测有效&#xff01;&…

(十五)GLM库对矩阵操作

GLM简单使用 glm是一个开源的对矩阵运算的库&#xff0c;下载地址&#xff1a; https://github.com/g-truc/glm/releases 直接包含其头文件即可使用&#xff1a; #include <glad/glad.h>//glad必须在glfw头文件之前包含 #include <GLFW/glfw3.h> #include <io…

Spring 集成测试指南

在软件开发中&#xff0c;集成测试是一种重要的测试方法&#xff0c;用于验证应用程序各个模块之间的协同工作是否正常。Spring 提供了强大的 Spring Test 模块&#xff0c;以及 MockMvc 工具来进行 HTTP 请求的模拟和验证。本文将介绍如何在 Spring 中进行集成测试&#xff0c…

深入解析ROC曲线及其应用

深入解析ROC曲线及其应用 什么是ROC曲线&#xff1f; ROC曲线&#xff08;Receiver Operating Characteristic Curve&#xff09;&#xff0c;即受试者工作特征曲线&#xff0c;是一种用于评估分类模型性能的工具。它通过展示真阳性率&#xff08;TPR&#xff09;与假阳性率&…

免费制作GIF和实时网络监控工具

ScreenToGif 不允许你们还不知道的一款免费且实用好用的GIF动画制作工具软件。可以实时对区域窗口录制、编辑录制多功能模块&#xff0c;操作简单。 支持自定义增减重复帧数、调整循环播放次数、调整播放速度及删除重复帧。 支持对帧做二次编辑&#xff0c;可进行帧翻转、缩放…

政安晨【零基础玩转各类开源AI项目】基于Ubuntu系统部署ComfyUI:功能最强大、模块化程度最高的Stable Diffusion图形用户界面和后台

目录 ComfyUI的特性介绍 开始安装 做点准备工作 在Conda虚拟环境中进行 依赖项的安装 运行 政安晨的个人主页&#xff1a;政安晨 欢迎 &#x1f44d;点赞✍评论⭐收藏 收录专栏: 零基础玩转各类开源AI项目 希望政安晨的博客能够对您有所裨益&#xff0c;如有不足之处&…

2.1 【入门篇】Cortex M芯片与内核

一,Cortex M芯片简介 Cortex M系列芯片是ARM公司设计的一系列微控制器(MCU),广泛用于嵌入式系统。Cortex M系列芯片主要分为以下几种型号,每种型号都有其独特的特点和应用场景: Cortex-M0和M0+: 特点:这是Cortex M系列中最基本、最低功耗的型号,设计简单,适合成本敏…

昇思训练营打卡第二十天(CycleGAN图像风格迁移互换)

CycleGAN&#xff08;循环生成对抗网络&#xff09;是一种生成对抗网络&#xff08;GAN&#xff09;&#xff0c;它能够在没有成对训练样本的情况下&#xff0c;将一种风格的图片转换成另一种风格。CycleGAN通常用于图像到图像的转换任务&#xff0c;比如将马的图片转换成斑马的…

PHP 高级过滤器

PHP 高级过滤器 PHP 是一种广泛使用的开源服务器端脚本语言,特别适用于网页开发。在处理用户输入和数据交互时,安全性是一个重要的考虑因素。PHP 提供了一套强大的过滤器扩展,用于验证和净化数据。本文将深入探讨 PHP 的高级过滤器功能,包括其使用方法、优势以及在开发中的…

从数字化营销与运营视角:看流量效果的数据分析

基于数据打通的“全链路”营销是当下的“时髦”&#xff0c;应用它的前提是什么&#xff1f;深度营销和运营的关键数据如何获得&#xff1f;如何利用数据进行更精准的营销投放&#xff1f;如何利用数据优化投放的效果&#xff1f;如何促进消费者的转化&#xff0c;以及激活留存…

Java中的多线程并发编程:深入探索与最佳实践

引言 在当今的高性能计算环境中&#xff0c;多线程并发编程成为了软件设计的核心。Java&#xff0c;作为一门成熟且广泛使用的语言&#xff0c;提供了强大的多线程支持。然而&#xff0c;高效地利用这一特性并非易事&#xff0c;它需要对线程的生命周期、同步机制、以及并发工…

IDEA启动tomcat之后控制台出现中文乱码问题

方法1&#xff1a; 第一步&#xff1a;file--setting--Editor--File Encodings 注意页面中全部改为UTF-8&#xff0c;然后apply再ok 第二步&#xff1a;Run--Edit Configuration&#xff0c;将VM options输入以下值&#xff1a; -Dfile.encodingUTF-8 还是一样先apply再ok …

bdeaver mysql忘记localhost密码修改密码添加用户

描述 bdeaver可以连接当前的localhost数据库&#xff0c;但不知道数据库密码是什么。用这个再建一个用户&#xff0c;用来连接数据库 解决 1、在当前的数据库localhost右键&#xff0c;创建-用户 设置这个用户&#xff0c;密码 加权限 2、连接 用新的账号密码去连接&#x…

千古雄文《渔樵问对》原文、译文、解析

邵雍《渔樵问对》&#xff1a;开悟奇文&#xff0c;揭示世界的终极意义 【邵雍《渔樵问对》&#xff1a;开悟奇文&#xff0c;揭示世界的终极意义】 邵雍&#xff08;1011年1月21日&#xff0d;1077年7月27日&#xff0c;宋真宗大中祥符四年十二月二十五日戌时生至神宗熙宁十…

华华给月月出题

题目链接 (a*b)^c (a^c)*(b^c)&#xff0c;我们将合数素数幂分解&#xff0c;然后我们只要处理每个素数的幂&#xff0c;就可以处理出所以合数的幂。 代码&#xff1a; #include<bits/stdc.h> using namespace std; using ll long long; #define fi first #define s…

代谢组数据分析一:代谢组数据准备

介绍 该数据集是来自于Zeybel 2022年发布的文章_Multiomics Analysis Reveals the Impact of Microbiota on Host Metabolism in Hepatic Steatosis_ [@zeybel2022multiomics],它包含了多种组学数据,如: 微生物组(粪便和口腔) 宿主人体学指标 宿主临床学指标 宿主血浆代谢…