Android OpenSL ES 开发:OpenSL ES利用SoundTouch实现PCM音频的变速和变调

原因

OpenSL ES 学习到如今已经知道 OpenSL ES 不只能播放和录制PCM音频数据,还能改变声音大小、设置左声道或右声道播放、还能变速播放,可谓是播放音频的王者。可是变速有一点很差的就是,虽然播放音频的速度变了,可是相应的音调也随之变了,这样的用户体验就不那么好了。因此就想到了用开源的SoundTouch来实现PCM音频变速和变调,OpenSL ES只是单纯的播放PCM数据就能够了。html

实现

一、移植SoundTouch(Android)

下载SoundTouch源码,当前最新是:v2.0.1git

在项目jni文件夹中建立include和SoundTouch文件夹,并把下载好的SoundTouch里面的include和SoundTouch的源码拷贝进去就能够了,目录结构以下:github

 二、用SoundTouch转码PCM源文件

 由于SoundTouch默认是float(32bit)格式的数据,这里须要先改为short(16bit)的格式。打开STTypes.h文件,修改以下代码:缓存

再注释掉下面这句,否则编译不经过(for x86模拟器):函数

这样SoundTouch里面处理PCM数据就是用的16bit的数据了。学习

三、SoundTouch使用流程

3.1 添加命名空间,并建立SoundTouch指针变量

using namespace soundtouch; SoundTouch *soundTouch;

3.2 设置SoundTouch参数

soundTouch = new SoundTouch(); soundTouch->setSampleRate(44100);//设置采样率,此处为44100,根据实际状况可变
    soundTouch->setChannels(2);//声道,此处为立体声
    soundTouch->setPitch(1);//变调不变速,如0.五、1.0、1.5等
    soundTouch->setTempo(1);//变速不变调,如0.五、1.0、2.0等 

3.3 向SoundTouch中传入获取到的PCM数据,使用:putSamples函数

size = fread(pcm_buffer, 1, 4096 * 2, pcmFile); soundTouch->putSamples((const SAMPLETYPE *) pcm_buffer, size / 4);

这里,pcm_buffer是u_int16_t *类型的,也就是说和SoundTouch处理的PCM数据位数是一致的(16bit),因此能够直接传入SoundTouch中。putSamples的第一个参数就是PCM数据指针,第二个参数是采样点的个数,因为是2声道16bit(2byte),因此PCM数据的采样点个数为:num = 大小(size)/ (2 * 2)。ui

3.4 获取SoundTouch输出的PCM数据:使用receiveSamples函数

num = soundTouch->receiveSamples(sd_buffer, size / 4);

这里,receiveSamples的第一个参数是SoundTouch(变速或变调)处理后的PCM数据存放的内存地址,第二个参数是可能的最大采样个数,能够和putSamples保持一致,其中sd_buffer是SAMPLETYPE * 类型的,记得要提早分配好内存大小,最后返回值就是SoundTouch处理后的PCM里面所包含的采样个数,因为可能有缓存,因此应循环读取receiveSamples,直到返回值为0为止。url

3.5 OpenSL ES播放SoundTouch处理后的PCM音频数据

(*pcmBufferQueue)->Enqueue(pcmBufferQueue, sd_buffer, size * 4);

因为size是采样个数,因此sd_buffer的大小是:size * 2(声道) * 2(16bit==2字节)。spa

这样,咱们听到的声音就是经过SoundTouch转码事后的了,如:变速不变调,变调不变速,变速又变调均可以本身设置。.net

思惟发散

FFmpeg解码获得的PCM数据(uint_8 *)利用SoundTouch转码

这里要处理的就是把uint_8 *(8bit)的数据转换成short(16bit)的数据格式。这里其实就是作bit的位运算,原理以下如:

转换代码以下:

for (int i = 0; i < size / 2 + 1; i++) { sd_buffer[i] = (pcm_buffer[i * 2] | (pcm_buffer[i * 2 + 1] << 8)); } soundTouch->putSamples((const SAMPLETYPE *) pcm_buffer, size / 4); 

后续操做和16bit的同样不变。

总结

虽然是简单的移植SoundTouch到Android来播放PCM数据,可是仍是让咱们了解到了数据在内存中怎么排列的,而后能够怎么操做最小单位的bit来达到咱们的要求。

参考资料

OpenSL ES利用SoundTouch实现PCM音频的变速和变调

参考源码

SoundTouch_OpenSL_Android 

相关文章
相关标签/搜索