上一节我们知道了怎么去搭建QQ变声所需要的一些环境,今天我们就来真正的去实现QQ变声的效果了,废话不多说,我们开始撸码了
2121017-c565c61dd9833f5d.pngfmod 官网:https://www.fmod.com/studio
正文
根据上一篇讲的内容进行开发,要实现变声的效果该怎么去实现呢?其实在fmod里面提供了相应的例子,那就是effects.cpp,这里我们截取其中一段代码
/*
Create a System object and initialize
*/
result = FMOD::System_Create(&system);
result = system->init(32, FMOD_INIT_NORMAL, extradriverdata);
ERRCHECK(result);
result = system->getMasterChannelGroup(&mastergroup);
ERRCHECK(result);
result = system->createSound(Common_MediaPath("drumloop.wav"), FMOD_DEFAULT, 0, &sound);
ERRCHECK(result);
result = system->playSound(sound, 0, false, &channel);
ERRCHECK(result);
/*
Create some effects to play with
*/
result = system->createDSPByType(FMOD_DSP_TYPE_LOWPASS, &dsplowpass);
ERRCHECK(result);
result = system->createDSPByType(FMOD_DSP_TYPE_HIGHPASS, &dsphighpass);
ERRCHECK(result);
result = system->createDSPByType(FMOD_DSP_TYPE_ECHO, &dspecho);
ERRCHECK(result);
result = system->createDSPByType(FMOD_DSP_TYPE_FLANGE, &dspflange);
ERRCHECK(result);
/*
Add them to the master channel group. Each time an effect is added (to position 0) it pushes the others down the list.
*/
result = mastergroup->addDSP(0, dsplowpass);
ERRCHECK(result);
result = mastergroup->addDSP(0, dsphighpass);
ERRCHECK(result);
result = mastergroup->addDSP(0, dspecho);
ERRCHECK(result);
result = mastergroup->addDSP(0, dspflange);
ERRCHECK(result);
从上面的代码可以要想实现变声的效果需要进行一下几步
- fmod的初始化 调用System_Create方法对System进行初始化、调用init方法设置相应的通道个数
- 创建声音 调用createSound方法通过传入路径创建声音
- 创建DSP音效的类型 createDSPByType(大多都是fmod预定义的声音)
- 设置音调的参数 调用setParamster
- 播放声音 调用playSound
- 为相应的通道添加音效
ok,我们可以先看一下effects有啥效果,可以将Android.mk里面将play_sound.cpp改成effects.cpp然后进行运行即可
接下来我们就可以玩我们的QQ变声效果了,首先定义native方法
public native static void fix(String path, int type);
第一个参数代表路径,第二个参数代表着相应的类型,然后使用javah工具生成相应的.h文件
好了,开始定义我们的.cpp,为了要实现变声的效果我们需要将fmod.hpp include进来
#include "inc/fmod.hpp"
#include <stdlib.h>
#include <unistd.h>
#include "org_fmod_example_EffectUtils.h"
#include <android/log.h>
然后我们模仿着play_sound.cpp制作一个原生的效果
//初始化
System_Create(&system);
//第一个参数是通道 第二个参数是标志 第三个传NULL即可
system->init(32, FMOD_INIT_NORMAL, NULL);
//将jstring转化为char*
const char* path_cstr = env->GetStringUTFChars(path_jstr, NULL);
//创建声音
system->createSound(path_cstr, FMOD_DEFAULT, NULL, &sound);
//原生播放
system->playSound(sound, 0, false, &channel);
是不是特别的简单,cpp写好了,在java代码中也需要在onCreate方法里面调用FMOD的init方法以及在onDestroy里面调用FMOD的close方法
FMOD.init(this);
FMOD.close();
但是不能播放声音,这时候我们需要在播放和释放资源之间添加一个循环器用来不断的去判断是否播放,如果播放则休眠,没有播放则进行释放资源
while (playing) {
channel->isPlaying(&playing);
usleep(1000 * 1000);
}
注意代码里面的usleep里面的参数是微妙
接下来我们要实现萝莉等其他的效果就需要参考effects.cpp的实现模式了
system->createDSPByType(FMOD_DSP_TYPE_PITCHSHIFT, &dsp);
//设置音调的参数
dsp->setParameterFloat(FMOD_DSP_PITCHSHIFT_PITCH, 2.5);
system->playSound(sound, 0, false, &channel);
//添加到channel
channel->addDSP(0, dsp);
FMO_DSP_TYPE的类型是非常的多,具体的可以从单词便可以知道相应的功能,例如FMOD_DSP_TYPE_PITCHSHIFT就是设置音调的类型,下面的setParameterFloat参数就需要在fmod_dsp_effects.h里面进行查看
/*
[DESCRIPTION]
Parameter types for the FMOD_DSP_TYPE_PITCHSHIFT filter.
*/
typedef enum
{
FMOD_DSP_PITCHSHIFT_PITCH, /* (Type:float) - Pitch value. 0.5 to 2.0. Default = 1.0. 0.5 = one octave down, 2.0 = one octave up. 1.0 does not change the pitch. */
FMOD_DSP_PITCHSHIFT_FFTSIZE, /* (Type:float) - FFT window size. 256, 512, 1024, 2048, 4096. Default = 1024. Increase this to reduce 'smearing'. This effect is a warbling sound similar to when an mp3 is encoded at very low bitrates. */
FMOD_DSP_PITCHSHIFT_OVERLAP, /* (Type:float) - Removed. Do not use. FMOD now uses 4 overlaps and cannot be changed. */
FMOD_DSP_PITCHSHIFT_MAXCHANNELS /* (Type:float) - Maximum channels supported. 0 to 16. 0 = same as fmod's default output polyphony, 1 = mono, 2 = stereo etc. See remarks for more. Default = 0. It is suggested to leave at 0! */
} FMOD_DSP_PITCHSHIFT;
从注释里可以看出该枚举是FMOD_DSP_TYPE_PITCHSHIFT的参数类型,所以在index我们可以传下面的枚举,如FMOD_DSP_PITCHSHIFT_PITCH的类型是float类型,默认是1.0 当0.5的时候则下降一个8度 2.0则上升一个8度,根据这个可以设置音调的高低
最后就将dsp添加到通道channel里面就可以了,这里需要注意的是需要将addDsp方法放到playSound方法的后面,不然将没有任何效果
下面是其余几种的效果
case MODE_JINGSONG:
//惊悚
system->createDSPByType(FMOD_DSP_TYPE_TREMOLO, &dsp);
dsp->setParameterFloat(FMOD_DSP_TREMOLO_SKEW, 0.5f);
system->playSound(sound, 0, false, &channel);
channel->addDSP(0, dsp);
break;
case MODE_DASHU:
//大叔
system->createDSPByType(FMOD_DSP_TYPE_PITCHSHIFT, &dsp);
dsp->setParameterFloat(FMOD_DSP_PITCHSHIFT_PITCH, 0.8);
system->playSound(sound, 0, false, &channel);
//添加到channel
channel->addDSP(0, dsp);
break;
case MODE_GAOGUAI:
//搞怪
//提高说话的速度
system->playSound(sound, 0, false, &channel);
channel->getFrequency(&frequency);
frequency = frequency * 1.6;
channel->setFrequency(frequency);
break;
case MODE_KONGLING:
//空灵
system->createDSPByType(FMOD_DSP_TYPE_ECHO, &dsp);
dsp->setParameterFloat(FMOD_DSP_ECHO_DELAY, 300);
dsp->setParameterFloat(FMOD_DSP_ECHO_FEEDBACK, 20);
system->playSound(sound, 0, false, &channel);
channel->addDSP(0, dsp);
break;
FMOD_DSP_TYPE_TREMOLO具有颤音的类型,FMOD_DSP_TYPE_PITCHSHIFT具有音调的类型,FMOD_DSP_TYPE_ECHO具有回声的类型
在程序执行完毕之后需要释放资源
env->ReleaseStringUTFChars(path_jstr, path_cstr);
sound->release();
system->close();
system->release();
为了确保最后释放资源,我们可以在代码进行try{}catch(){},如果要加入异常判断,需要在Android.mk里面添加相应的特性
LOCAL_CPP_FEATURES := exceptions
最后附上一图
QQ图片20171107004059.png人贵在坚持,更重要的是我们一直都在坚持
网友评论