soundtouch是一个能够实现对声音的变速、变调、同时变速变调可开源库,有c++编写,现在把他移植到了Android上开发“变声”应用。

本来是想实现提取人声音通过变调获得几乎相同的模拟人声音的功能,不过看起来这是一个比较难实现的功能了,这里先讨论一下已经移植到Android平台上面的soundtouch的几个参数:

  

参考ST提供的例子SoundStretch,初始化SoundTouch这个类:
m_SoundTouch.setSampleRate(sampleRate);//设置声音的采样频率
m_SoundTouch.setChannels(channels);//设置声音的声道
m_SoundTouch.setTempoChange(tempoDelta); //这个就是传说中的变速不变调
m_SoundTouch.setPitchSemiTones(pitchDelta);//设置声音的pitch
m_SoundTouch.setRateChange(rateDelta);//设置声音的速率
// quick是一个bool变量,USE_QUICKSEEK具体有什么用我暂时也不太清楚。
m_SoundTouch.setSetting(SETTING_USE_QUICKSEEK, quick);
// noAntiAlias是一个bool变量,USE_AA_FILTER具体有什么用我暂时也不太清楚。
m_SoundTouch.setSetting(SETTING_USE_AA_FILTER, !(noAntiAlias));
// speech也是一个bool变量,初步估计可能是没有音乐只有人声的时候,需要设置一下。
if (speech)
{
// use settings for speech processing
m_SoundTouch.setSetting(SETTING_SEQUENCE_MS, 40);
m_SoundTouch.setSetting(SETTING_SEEKWINDOW_MS, 15);
m_SoundTouch.setSetting(SETTING_OVERLAP_MS, 8);
fprintf(stderr, "Tune processing parameters for speech processing./n");
}
通过那么简单的几个函数调用,现在我们就可以感受一下ST的强大。通过SoundTouch类提

供的函数调用方法:
putSamples(sampleBuffer,nSamples);
第一个参数为一个指向PCM编码的一段音频数据的指针,第二个参数就是要处理多少个

sample也可以理解为多少帧。
需要注意的是,一般数据流都是字节流,也就是说,sample的大小和声道、位的声音参数

有关,假如sampleBuffer指针指向一个 长度为64bytes的一个PCM数据缓冲区,16位2声道

,那么实际上这里只存放了(16*2)/8=4bytes,64/4=16;16个sample,这是我们需要注意的

地方。m_SoundTouch.putSamples(sampleBuffer, nSamples);数据是传进去了,可是从哪

里接收处理过的音频数据呢?这个时候我们就要用SoundTouch提供的receiveSamples函数

调用方法。
uint receiveSamples(SAMPLETYPE *outBuffer, ///< Buffer where to copy output

samples.
uint maxSamples                    ///< How many samples to receive at max.
);他也是两个参数,第一个为接收数据的参数,第二个最大可以接收多少sample。
通过这段注释,大概明白receiveSamples这个函数不会在putSamples之后马上返回数据,

另外一方面有可能返回比maxSamples更多的数据,因此需要放在一个do…while(…)的循环里

面把他们都榨干。
// Read ready samples from SoundTouch processor & write them output file.
// NOTES:
// - 'receiveSamples' doesn't necessarily return any samples at all
//   during some rounds!
// - On the other hand, during some round 'receiveSamples' may have more
//   ready samples than would fit into 'sampleBuffer', and for this reason 
//   the 'receiveSamples' call is iterated for as many times as it
//   outputs samples.
do 
{
nSamples = m_SoundTouch.receiveSamples(sampleBuffer, buffSizeSamples);
//把sampleBuffer写入一个文件,或者填充进声卡的缓冲区,播放声音。
} while (nSamples != 0);