文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

啃论文俱乐部——移植Speexdsp到OpenHarmony标准系统(五)

2024-12-01 15:15

关注

​想了解更多关于开源的内容,请访问:​

​51CTO 开源基础软件社区​

​https://ost.51cto.com​

七、Speexdsp功能分析

speexdsp核心库分析

1、库实现方式

2、依赖分析

3、license以及版权

如下类型许可证可以引入到OpenHarmony项目中:

Apache License 2.0
Mulan Permissive Software License, Version 2
BSD 2-clause
BSD 3-clause
DOM4J License
PostgreSQL License
Eclipse Distribution License 1.0
MIT
ISC
ICU
University of Illinois/NCSA
W3C Software License
zlib/libpng
Academic Free License 3.0
Python Software Foundation License
Python Imaging Library Software License
Boost Software License Version 1.0
WTF Public License
UNICODE, INC. LICENSE AGREEMENT - DATA FILES AND SOFTWARE
Zope Public License 2.0

如下类型许可证不建议引入到OpenHarmony项目中:​

GNU GPL 1, 2, 3
GNU Affero GPL 3
GNU LGPL 2, 2.1, 3
QPL
Sleepycat License
Server Side Public License (SSPL) version 1
Code Project Open License (CPOL)
BSD-4-Clause/BSD-4-Clause (University of California-Specific)
Facebook BSD+Patents license
NPL 1.0/NPL 1.1
The Solipsistic Eclipse Public License
The "Don't Be A Dick" Public License
JSON License
Binary Code License (BCL)
Intel Simplified Software License
JSR-275 License
Microsoft Limited Public License
Amazon Software License (ASL)
Java SDK for Satori RTM license
Redis Source Available License (RSAL)
Booz Allen Public License
Creative Commons Non-Commercial
Sun Community Source License 3.0
Common Development and Distribution Licenses: CDDL 1.0 and CDDL 1.1
Common Public License: CPL 1.0
Eclipse Public License: EPL 1.0
IBM Public License: IPL 1.0
Mozilla Public Licenses: MPL 1.0, MPL 1.1, and MPL 2.0
Sun Public License: SPL 1.0
Open Software License 3.0
Erlang Public License
UnRAR License
SIL Open Font License
Ubuntu Font License Version 1.0
IPA Font License Agreement v1.0
Ruby License
Eclipse Public License 2.0: EPL 2.0

speexdsp的license以及版权内容如下:

Copyright 2002-2008   Xiph.org Foundation
Copyright 2002-2008 Jean-Marc Valin
Copyright 2005-2007 Analog Devices Inc.
Copyright 2005-2008 Commonwealth Scientific and Industrial Research
Organisation (CSIRO)
Copyright 1993, 2002, 2006 David Rowe
Copyright 2003 EpicGames
Copyright 1992-1994 Jutta Degener, Carsten Bormann
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
- Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
- Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
- Neither the name of the Xiph.org Foundation nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

4、最新一次版本

5、代码规模

linux系统提供了wc命令来统计文件的行数,统计当前目录下的所有文件行数,终端输入如下命令:

wc -l *

文件名

代码行数

arch.h

232

bfin.h

15

buffer.c

176

fftwrap.c

448

fftwrap.h

58

filterbank.c

227

filterbank.h

66

fixed_arm4.h

135

fixed_arm5e.h

160

fixed_bfin.h

141

fixed_debug.h

497

fixed_generic.h

106

jitter.c

839

kiss_fft.c

523

_kiss_fft_guts.h

160

kiss_fft.h

108

kiss_fftr.c

297

kiss_fftr.h

51

math_approx.h

332

mdf.c

1279

misc_bfin.h

56

os_support.h

169

preprocess.c

1215

pseudofloat.h

379

resample.c

1239

resample_neon.h

339

resample_sse.h

128

scal.c

293

smallft.c

1261

smallft.h

46

vorbis_psy.h

97

speex_buffer.h

68

speexdsp_config_types.h

12

speexdsp_types.h

126

speex_echo.h

170

speex_jitter.h

197

speex_preprocess.h

219

speex_resampler.h

343

总行数

12207

功能分析

可以参考speexdsp提供的文档分析功能。

预处理器

预处理器被设计为在运行编码器之前在音频上使用。预处理器提供三个主要功能:

自适应抖动缓冲区

声学回声消除器

回声消除是为了提高远端质量。

重采样器

这个重采样器可以用于在任意两个速率之间进行转换(比率必须是有理数),并且可以控制质量/复杂性的权衡。

八、Speexdsp功能测试

测试逻辑

重采样功能

testresample.c源码分析如下:

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
//要使用重采样器,必须包含它的头文件speex_resampler.h:
#include "speex/speex_resampler.h"
//基本输入输出函数的声明
#include
////头文件中声明了一些数学函数和宏
#include

#include
//NN定义的是帧长度
#define NN 256
int main()
{
spx_uint32_t i;
short *in;
short *out;
float *fin, *fout;
int count = 0;
//对于每一个被重采样的流(流是一种抽象的概念,表示一连串的数据元素;流中的数据元素称为帧Frame。),有必要创建一个重采样状态:SpeexResamplerState *resampler;
//resampler = speex_resampler_init(nb_channels, input_rate, output_rate, quality, &err);
// nb_channels声道数量,这段测试程序要求输入的音频声道数量为1
// input_rate和output_rate指的是输入音频的采样率和输出音频的采样率。
// err错误码


SpeexResamplerState *st = speex_resampler_init(1, 8000, 12000, 10, NULL);

//96000是输入音频的采样率,44100是输出音频的采样率。单位为Hz
speex_resampler_set_rate(st, 96000, 44100);
speex_resampler_skip_zeros(st);

in = malloc(NN*sizeof(short));
out = malloc(2*NN*sizeof(short));
fin = malloc(NN*sizeof(float));
fout = malloc(2*NN*sizeof(float));
//while(1):这是一个死循环,一直在while里循环.
//调试代码时,为了检测一部分代码是否OK,可加测试点while(1),测试这段代码。
while (1)
{
spx_uint32_t in_len;
spx_uint32_t out_len;

fread(in, sizeof(short), NN, stdin);
//feof()是检测流上的文件结束符的函数,如果文件结束,则返回非0值,否则返回0
if (feof(stdin))
break;
for (i=0;i<NN;i++)
fin[i]=in[i];
in_len = NN;
out_len = 2*NN;

//实际的重采样是使用speex_resampler_process_int(resampler, channelID, in, &in_length, out, &out_length);
//其中"channelID"是输入的音频的声道。对于单声道,使用0。也可以同时处理多个通道。
//其中"in"指针指向所选通道的输入缓冲区的第一个样本,输出指向输出的第一个样本。
//in_length和out_length分别指定输入和输出缓冲区的大小。
speex_resampler_process_float(st, 0, fin, &in_len, fout, &out_len);
for (i=0;i<out_len;i++)
out[i]=floor(.5+fout[i]);


fwrite(out, sizeof(short), out_len, stdout);
count++;
}
speex_resampler_destroy(st);
//free函数接受一个指针,然后将指针指向的地址还给系统。(但它不会改变指针的指向,所以一般在free之后还要将指针置
空,不然你的这个指针就会变成野指针)
//一般来说,malloc函数应该和free函数成对出现,防止向系统要的内存太多系统不高兴。
free(in);
free(out);
free(fin);
free(fout);
return 0;
}

可以得知:

回声消除功能


#ifdef HAVE_CONFIG_H
#include "config.h"
#endif


#include "speex/speex_echo.h"

#include "speex/speex_preprocess.h"
#include
//stdlib 头文件即standard library标准库头文件
#include
// sys/types.h中文名称为基本系统 数据类型。在应用程序源文件中包含 以访问 _LP64 和 _ILP32 的定义
#include
//stat.h头文件,轻松获取文件属性
#include
//fcntl.h相关函数 open,fcntl,shutdown,unlink,fclose
#include
//NN是frame_size帧长度,TAIL是filter_length滤波器长度
#define NN 128
#define TAIL 1024
//当你需要程序带参数地启动的时候,就用int main(int argc, char *argv[])
int main(int argc, char **argv)
{
//FILE* 指针作为文件句柄,是文件访问的唯一标识,它由fopen函数创建,fopen打开文件成功,则返回一个有效的FILE*指针,否则返回空指针NULL //[nʌl]
FILE *echo_fd, *ref_fd, *e_fd;
short echo_buf[NN], ref_buf[NN], e_buf[NN];
SpeexEchoState *st;
SpeexPreprocessState *den;
//采样率为8000.单位为hz
int sampleRate = 8000;
if (argc != 4)
{
fprintf(stderr, "testecho mic_signal.sw speaker_signal.sw output.sw\n");
exit(1);
}
// fopen函数用于打开文件
echo_fd = fopen(argv[2], "rb");
ref_fd = fopen(argv[1], "rb");
e_fd = fopen(argv[3], "wb");
·
st = speex_echo_state_init(NN, TAIL);
den = speex_preprocess_state_init(NN, sampleRate);
speex_echo_ctl(st, SPEEX_ECHO_SET_SAMPLING_RATE, &sampleRate);

speex_preprocess_ctl(den, SPEEX_PREPROCESS_SET_ECHO_STATE, st);
while (!feof(ref_fd) && !feof(echo_fd))
{
fread(ref_buf, sizeof(short), NN, ref_fd);
fread(echo_buf, sizeof(short), NN, echo_fd);

speex_echo_cancellation(st, ref_buf, echo_buf, e_buf);
speex_preprocess_run(den, e_buf);
fwrite(e_buf, sizeof(short), NN, e_fd);
}
speex_echo_state_destroy(st);
//可以用以下方法消除回声抵消状态:speex_echo_state_destroy(echo_state);
speex_preprocess_state_destroy(den);
// fclose(FILE *fp) 一般地,fclose(fp)应与fopen配对使用,特别是含有写方式的文件,若不关闭,可能会造成文件数据丢失。
fclose(e_fd);
fclose(echo_fd);
fclose(ref_fd);
return 0;
}

预处理功能

testdenoise.c源码分析如下:

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
//使用预处理功能先#include "speex/speex_preprocess.h"
#include "speex/speex_preprocess.h"
#include
//定义NN为160
#define NN 160
int main()
{
short in[NN];
int i;

SpeexPreprocessState *st;
int count=0;
float f;

st = speex_preprocess_state_init(NN, 8000);


i=1; // i=1就是打开预处理器的降噪功能;i=2就是关闭降噪功能
speex_preprocess_ctl(st, SPEEX_PREPROCESS_SET_DENOISE, &i);


i=0; //
speex_preprocess_ctl(st, SPEEX_PREPROCESS_SET_AGC, &i);
i=8000;
speex_preprocess_ctl(st, SPEEX_PREPROCESS_SET_AGC_LEVEL, &i);

//reverberation removal混响消除
i=0;
speex_preprocess_ctl(st, SPEEX_PREPROCESS_SET_DEREVERB, &i);
f=.0;
speex_preprocess_ctl(st, SPEEX_PREPROCESS_SET_DEREVERB_DECAY, &f);
f=.0;
speex_preprocess_ctl(st, SPEEX_PREPROCESS_SET_DEREVERB_LEVEL, &f);

while (1)
{
int vad;

fread(in, sizeof(short), NN, stdin);

if (feof(stdin))
break;

//fwrite和fread是以记录为单位的I/O函数,fread和fwrite函数一般用于二进制文件的输入输出。
vad = speex_preprocess_run(st, in);

fwrite(in, sizeof(short), NN, stdout);
count++;
}
//预处理器状态可以通过以下方式销毁:speex_preprocess_state_destroy(preprocess_state);
speex_preprocess_state_destroy(st);
return 0;
}

抖动缓冲功能

当通过UDP或RTP传输语音(或任何相关内容)时,包可能会丢失,以不同的延迟到达,甚至乱序。

1.抖动缓冲区的目的是重新排序数据包,并缓冲足够长的时间,以便它们可以被发送以进行解码。

2.测试源文件testjitter.c,这个去抖动测试需要接收来自udp/rtp的网络语音数据,原生测试程序没有做到真正意义上的测试,从程序上看是告诉用户如何使用接口。

testjitter.c源码分析:

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#include "speex/speex_jitter.h"
#include
union jbpdata {

unsigned int idx;
//unsigned int是整数类型 ,存储大小为2 或 4 字节,值范围为0 到 65,535 或 0 到 4,294,967,295
//unsigned char的表示范围为0~255 此处定义了一个拥有四个元素的数组
unsigned char data[4];
};

void synthIn(JitterBufferPacket *in, int idx, int span) {
union jbpdata d;
d.idx = idx;

in->data = d.data;
in->len = sizeof(d);
in->timestamp = idx * 10;
in->span = span * 10;
in->sequence = idx;
in->user_data = 0;
}
void jitterFill(JitterBuffer *jb) {
char buffer[65536];
JitterBufferPacket in, out;
int i;
out.data = buffer;
jitter_buffer_reset(jb);
for(i=0;i<100;++i) {
synthIn(&in, i, 1);
jitter_buffer_put(jb, &in);
out.len = 65536;

//如果从不同的线程调用jitter_buffer_put()和jitter_buffer_get(),那么需要使用互斥锁来保护jitter缓冲区状态。
if (jitter_buffer_get(jb, &out, 10, NULL) != JITTER_BUFFER_OK) {
printf("Fill test failed iteration %d\n", i);
}
if (out.timestamp != i * 10) {
printf("Fill test expected %d got %d\n", i*10, out.timestamp);
}

jitter_buffer_tick(jb);
}
}

int main()
{
char buffer[65536];
JitterBufferPacket in, out;
int i;

JitterBuffer *jb = jitter_buffer_init(10);
out.data = buffer;

jitterFill(jb);
for(i=0;i<100;++i) {
out.len = 65536;
jitter_buffer_get(jb, &out, 10, NULL);
jitter_buffer_tick(jb);
}
synthIn(&in, 100, 1);
jitter_buffer_put(jb, &in);
out.len = 65536;
if (jitter_buffer_get(jb, &out, 10, NULL) != JITTER_BUFFER_OK) {
printf("Failed frozen sender resynchronize\n");
} else {
printf("Frozen sender: Jitter %d\n", out.timestamp - 100*10);
}
return 0;
}

测试步骤

编译pc端上的测试用的可执行程序

编译pc端的可执行程序:

gcc testdenoise.c -L /home/jiajiahao/Desktop/speexdsp-SpeexDSP-1.2.1/build/lib -o testdenoise -I /home/jiajiahao/Desktop/speexdsp-SpeexDSP-1.2.1/include -lm -lspeexdsp

其中:

将编译生成的库以及测试用的可执行文件推送到开发板上

hdc工具的使用 请参考用​​hdc工具在OpenHarmony3.2 上安装应用​​中的相关内容。

1.通过与ohos版本匹配的hdc_std工具,将编译生成的库以及测试用的可执行文件推送到开发板上。

hdc_std shell               
mount -o remount,rw / ## 重新加载系统为可读写
mkdir speexdsp ## 创建speexdsp目录存放测试用例
exit ## 退出开发板系统

2.将压缩包push到开发板。

hdc_std file speexdsp.tar /speexdsp

3.解压压缩包并将库文件拷贝到对应的目录

本次移植是基于openharmony标准系统3.2Beta1版本,是arm64位系统。

hdc_std shell              ## 进入开发板系统
cd speexdsp
tar -xvf speexdsp.tar
cp libspeexdsp_share.z.so /system/lib64/ ## 将库文件拷贝系统目录

执行测试程序、分析测试结果

分析测试结果需要使用到的音频处理软件是ocenaudio,下载地址:https://www.ocenaudio.com/en/。

①执行testresample可执行文件。

通过分析testresample.c源码可知:执行测试程序时输入一份采样率为96000Hz并且为单声道的音频时,经过重采样输出的音频采样率为44100Hz。

在pc端运行:

输入的音频为input.pcm,把它拷贝到testresample同目录下,并且新建空白文档命名为output.pcm。

打开终端执行如下命令:

chmod 777 testresample
./testresample < input.pcm > output.pcm

使用<符号指定输入文件,>符号指定输出文件。

输出的output.pcm采样率变为44100Hz,音频的波形图和声谱图如下:

在rk3568上运行:

这里测试testresample时,将一份与pc端同样的input.pcm和output.pcm拷贝至开发板speexdsp目录。

在开发板speexdsp目录执行语句如下:

chmod 777 testresample                  ## 添加可执行权限
./testresample < input.pcm > output.pcm

将开发板输出的output.pcm拷贝至pc端。

hdc_std file recv /speexdsp/output.pcm C:\Users\jjh\Desktop\

测试结果:经过重采样,pc端和rk3568开发板输出的output.pcm音频采样率都为44100Hz,两者运行测试程序testresample结果一致。

②执行testresample2可执行文件。

通过分析testresample2.c源码可知,执行测试程序时需要指定一份空白的单声道音频文件output.pcm。

测试testresample2时,需要把空白的单声道音频文件output.pcm拷贝至开发板speexdsp目录。

pc端运行:

执行语句如下:

./testresample2 > output.pcm

输出结果如下:

终端打印信息:

输出音频output.pcm波形图和声谱图如下:

rk3568开发板上运行:

执行语句如下:

./testresample2 > output.pcm

测试结果:输出一份不为空的output.pcm音频文件,并且在终端输出文本如下:

1000 0 1024 22 -> 1024 0                  
1100 0 1024 24 -> 1024 15
1200 0 1024 26 -> 926 26
1300 926 1122 31 -> 1048 31
1400 950 1098 33 -> 1032 33
...
...
...
127600 1024 1024 2723 -> 1024 2723
...
...
127900 1024 1024 2729 -> 1024 2729
128000 1024 1024 2731 -> 1024 2730

以最后一行"128000 1024 1024 2731 -> 1024 2730“”为例,其中128000为采样率(Hz);1024为一个编码单元采样点数(帧);1024为输入音频理论帧长;2731为输出音频理论帧长。"->"符号后的1024为经过重采样处理输入音频实际帧长,2730为输出音频实际帧长。

③执行testecho可执行文件。

测试testecho时,需要输入两份音频文件,同时需要指定一份输出的音频文件。

输入的两份音频一份为speaker.wav(麦克风收录的说话人语音信号+在房间多径反射的语音),另一份为micin.wav(麦克风收录的房间多径反射的语音)。

执行语句如下:

./testecho speaker.wav micin.wav testecho_output.wav

测试结果:对比输入的speaker.wav和输出testecho_output.wav的波形图和声谱图,回声已经被消除。pc端和rk3568开发板运行testecho可执行程序效果一致。

④执行testdenoise可执行文件。

通过分析testdenoise.c源码,执行测试程序时需要指定一份输入的不为空的8000Hz的input.pcm音频,并且需要指定一份空的输出的output.pcm音频。

rk3568上运行:

执行语句如下:

./testdenoise < input.pcm > output.pcm

测试结果:对比输入的input.pcm和输出的outpu.pcm的波形图和声谱图,噪声已经被消除。pc端和rk3568开发板运行testdenoise可执行程序效果一致。

⑤执行testjitter可执行文件。

通过分析testjitter.c源码,测试需要接收来自udp/rtp的网络语音数据,原生测试程序没有做到真正意义上的测试,从程序上看是告诉用户如何使用接口。

执行语句如下:

./testjitter

测试结果:终端打印出语句。

Frozen sender: Jitter 0

pc端和rk3568开发板运行testjitter可执行程序效果一致。

​想了解更多关于开源的内容,请访问:​

​51CTO 开源基础软件社区​

​https://ost.51cto.com​​。

来源:51CTO开源基础软件社区​​内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯