要想本身写一个变声的函数或者库出来,谈何容易,因此采用了你们广泛采用的库SoundTouch。java
该库能够实现改变声音的速度,节拍,音调(这个最重要,能够把声音的音调调高调低,使之变成男生女生,能够参照汤姆猫)ios
使用的思路为把整个库放到不一样平台的底层,使用时只需包含头文件soundtouch.h便可.c++
SoundTouch类提供了许多方法,其中最重要的就是setPitch,setRate这几个调节声音参数的方法,具体使用时自行设置参数。api
可是在使用前须要预先设置一下其中的几个函数的参数以下:数组
1
2
3
4
5
6
|
mSoundTouchInstance->setSetting(SETTING_USE_QUICKSEEK, 0);
mSoundTouchInstance->setSetting(SETTING_USE_AA_FILTER, !(0));
mSoundTouchInstance->setSetting(SETTING_AA_FILTER_LENGTH, 32);
mSoundTouchInstance->setSetting(SETTING_SEQUENCE_MS, 40);
mSoundTouchInstance->setSetting(SETTING_SEEKWINDOW_MS, 16);
mSoundTouchInstance->setSetting(SETTING_OVERLAP_MS, 8);
|
而后设置须要的参数缓存
1
2
3
4
5
|
mSoundTouchInstance->setChannels(2);
mSoundTouchInstance->setSampleRate(8000);
mSoundTouchInstance->setPitch(2);
|
这里解释一下音频处理的几个参数,很重要。网络
声道:channals,能够是单声道和双声道,分别对应1,2函数
采样率:SampleRate 8000-44100不等,通常是经常使用的几个值,安卓里面好像44100是全部设备都支持的,因此设置成44100比较保险吧spa
每一个声道的位数:bitsPerChannel 通常设置为16线程
每一个帧的声道数 ChannelsPerFrame 对于pcm数据来讲,这个是1
还有几个参数,对于安卓和ios可能说法不太同样,以上几个是都要用到的,比较重要,必须得掌握
2.Android中实现变声
由于项目要求录音要实时播放,因此须要采用读取音频数据流(PCM格式)来播放,采用的api是AudioRecorder和AudioTrack。
具体的使用方法相关资料较多,官方文档也比较详细。大体思路就是先初始化:
//initilize
trbusize=AudioTrack.getMinBufferSize(RECORDER_SAMPLERATE,AudioFormat.CHANNEL_OUT_STEREO, AudioFormat.ENCODING_PCM_16BIT); mAudioTrack = new AudioTrack(AudioManager.STREAM_MUSIC,RECORDER_SAMPLERATE, AudioFormat.CHANNEL_IN_STEREO, AudioFormat.ENCODING_PCM_16BIT, trbusize, AudioTrack.MODE_STREAM); rebusize = AudioRecord.getMinBufferSize(RECORDER_SAMPLERATE, AudioFormat.CHANNEL_IN_STEREO,AudioFormat.ENCODING_PCM_16BIT); mAudioRecord= new AudioRecord(MediaRecorder.AudioSource.MIC,RECORDER_SAMPLERATE,AudioFormat.CHANNEL_IN_STEREO, AudioFormat.ENCODING_PCM_16BIT, rebusize);
这里由于不一样设备支持的参数可能不一样,须要是能够写一个循环把全部可能的参数全试一遍。
以后是录音和播放,能够分别放到两个线程里面。通常来讲都是把录音数据保存到文件中,而后再进行播放,这样能够应付通常的录音需求。但不足之处在于,录音时间久了,文件会很大,若是在网络上实时播放的话这样确定不行。解决方法就是将录音的数据传到一个缓冲区,而后播放时直接从缓冲区取走数据便可。这个缓冲区能够考虑用循环队列或者在java里面能够直接用一个LinkedList实现。
而后是变声部分,安卓里面要想用c++库的话,只能经过jni来实现,能够写几个函数。
while(isInstancePlaying){ if(l<21){ byte[] mbyte=new byte[64]; mAudioRecord.read(mbyte,0,64); SoundTouch.getSoundTouch().putSamples(mbyte,0,INPUT_LENGTH); SoundTouch.getSoundTouch().setPitchSemiTones(pitchTone); SoundTouch.getSoundTouch().receiveSamples(mbyte,INPUT_LENGTH); byteArray.add(mbyte); l=byteArray.size(); } else{ mAudioTrack.write(byteArray.getFirst(),0,64); byteArray.removeFirst(); l=byteArray.size(); }
代码中有三个函数putSamples,setPitchSemiTones,receiveSamples.这三个都是native方法,在SoundTouch库中分别经过SoundTouch类提供的对应函数实现,比较简单,经过这几个函数便可实现声音的变声。
l变量是LinkedList(代码中的byteArray)的长度,当小于20时添加到byteArray的末尾,同时AudioTrack不断读取数组中的第一个元素来播放而后删除该元素。
最后播放完要记得释放mAudioTrack和mAudioRecorder。经过stop和release方法实现。
3.IOS实现变声
由于本人以前没接触过ios因此作起来遇到了很多问题,还好最后解决了。
ios里面的音频处理比起安卓来讲感受要麻烦一些,用到的核心api就是AudioQueue,正在使用以前必定要好好理解一下它的原理,跟安卓不一样的是ios播放和录音都是用的这个api。就至关于它一个东西实现了安卓中AudioRecorder和AudioTrack的功能,只不过在播放和录音过程当中内部的流程有所变化。
核心思想:
Audio里面有自带的一个队列,首先用户建立若干个(3-6个左右都行)缓冲器用来装填音频数据,在自带队列中播放或录音完后使用用户自定义的回调函数进行处理,使得缓冲器可以被从新利用,而且能够在回调函数中实现用户自定义的一些功能,好比变声,写入文件等等操做。官方给了说明图比较详细,须要着重理解一下。
首先是录音的流程图:
而后是播放的流程图:
如何变声呢?
ios的变声不须要安卓的jni,由于oc语言能够和c++混编,因此这点相对来讲要简单许多。流程以下:
首先在你的程序中实例化一个SoundTouch类,而后在初始化时将它的参数设置好(setSetting),以后在上面所述的回调函数里面就能够将录音获得的数据流进行处理而后选择保存到文件或者直接播放。思路就是这样,可是里面的函数的参数相对仍是比较繁琐的,前面原理没理解的话这边就很难作下去了。
实时播放?
思路同Android,能够写一个循环队列用来缓存音频数据,而后边录音往里面传数据边播放,跟安卓不一样的是这些操做须要放到相应的回调函数里面来实现,有个简单的办法是在录音的回调函数里面直接播放pcm数据。由于数据是一块一块的进来的,每使用完一次缓冲器才会调用一次回调函数,能够直接在回调函数里面进行播放。
以上就是两个平台上实现录音和实时播放的简单介绍,这里面的东西仍是蛮多的,值得深刻研究。