android fmod,Android ndk开发:fmod语音学习(二)

在上一篇文章中,介绍以及搭建了FMOD的Android示例,这篇文章是在上一篇文章的基础上写的。所以建议首先读一下我的这篇文章。

本文使用FMOD来实现变声效果,直接使用《Android ndk开发:fmod语音学习(一)》这篇文章建立的FMOD的Android示例上添加变声效果。

上图就是项目的界面,可以看到,本节要实现的变声效果,包括大叔、萝莉等等。接下来实战开始。

1、编写本地方法

VoiceUtils.java

public class VoiceUtils {

public static final int MODE_NORMAL = 0;

public static final int MODE_LUOLI = 1;

public static final int MODE_DASHU = 2;

public static final int MODE_JINGSONG = 3;

public static final int MODE_GAOGUAI = 4;

public static final int MODE_KONGLING = 5;

/**

*

* @param path 语言的路径

* @param type 声音类型类型

*/

public native static void fix(String path, int type);

static {

System.loadLibrary("fmodL");

System.loadLibrary("fmod");

System.loadLibrary("Voice");

}

}

2、使用Javah 编译头文件

org_fmod_example_VoiceUtils.h

/* DO NOT EDIT THIS FILE - it is machine generated */

#include

/* Header for class org_fmod_example_VoiceUtils */

#ifndef _Included_org_fmod_example_VoiceUtils

#define _Included_org_fmod_example_VoiceUtils

#ifdef __cplusplus

extern "C" {

#endif

/*

* Class:     org_fmod_example_VoiceUtils

* Method:    fix

* Signature: (Ljava/lang/String;I)V

*/

JNIEXPORT void JNICALL Java_org_fmod_example_VoiceUtils_fix

(JNIEnv *, jclass, jstring, jint);

#ifdef __cplusplus

}

#endif

#endif

3、新建fix.cpp文件

4、更改Android.mk文件

LOCAL_PATH := $(call my-dir)

LOCAL_C_INCLUDES := $(LOCAL_PATH)/*.cpp

include $(CLEAR_VARS)

LOCAL_MODULE := fmod

LOCAL_SRC_FILES := libfmod.so

include $(PREBUILT_SHARED_LIBRARY)

include $(CLEAR_VARS)

LOCAL_MODULE := fmodL

LOCAL_SRC_FILES := libfmodL.so

include $(PREBUILT_SHARED_LIBRARY)

include $(CLEAR_VARS)

LOCAL_MODULE    := Voice

LOCAL_SRC_FILES := fix.cpp

LOCAL_SHARED_LIBRARIES := fmod fmodL

include $(BUILD_SHARED_LIBRARY)

主要将LOCAL_SRC_FILES指向fix.cpp

5、新建Activity,实现页面逻辑

布局:

android:layout_width="match_parent"

android:layout_height="match_parent"

android:padding="20dp"

android:orientation="vertical" >

android:id="@+id/yuan_sheng"

android:layout_marginTop="10dp"

android:layout_width="match_parent"

android:layout_height="wrap_content"

android:text="原声"/>

android:id="@+id/luo_li"

android:layout_marginTop="10dp"

android:layout_width="match_parent"

android:layout_height="wrap_content"

android:text="萝莉"/>

android:id="@+id/da_shu"

android:layout_marginTop="10dp"

android:layout_width="match_parent"

android:layout_height="wrap_content"

android:text="大叔"/>

android:id="@+id/jing_song"

android:layout_marginTop="10dp"

android:layout_width="match_parent"

android:layout_height="wrap_content"

android:text="惊悚"/>

android:id="@+id/gao_guai"

android:layout_marginTop="10dp"

android:layout_width="match_parent"

android:layout_height="wrap_content"

android:text="搞怪"/>

android:id="@+id/kong_ling"

android:layout_marginTop="10dp"

android:layout_width="match_parent"

android:layout_height="wrap_content"

android:text="空灵"/>

VoiceActivity:

public class VoiceActivity extends Activity{

private String path;

@Override

protected void onCreate(Bundle savedInstanceState) {

// TODO Auto-generated method stub

FMOD.init(this);

super.onCreate(savedInstanceState);

setContentView(R.layout.voice_layout);

this.findViewById(R.id.yuan_sheng).setOnClickListener(mClickListener);

this.findViewById(R.id.luo_li).setOnClickListener(mClickListener);

this.findViewById(R.id.da_shu).setOnClickListener(mClickListener);

this.findViewById(R.id.jing_song).setOnClickListener(mClickListener);

this.findViewById(R.id.gao_guai).setOnClickListener(mClickListener);

this.findViewById(R.id.kong_ling).setOnClickListener(mClickListener);

path = Environment.getExternalStorageDirectory().getAbsolutePath() + File.separatorChar + "testvoice.wav";

}

/**

* 点击监听器

*/

private OnClickListener mClickListener = new OnClickListener() {

@Override

public void onClick(View v) {

// TODO Auto-generated method stub

switch (v.getId()) {

case R.id.yuan_sheng:

VoiceUtils.fix(path, VoiceUtils.MODE_NORMAL);

break;

case R.id.luo_li:

VoiceUtils.fix(path, VoiceUtils.MODE_LUOLI);

break;

case R.id.da_shu:

VoiceUtils.fix(path, VoiceUtils.MODE_DASHU);

break;

case R.id.jing_song:

VoiceUtils.fix(path, VoiceUtils.MODE_JINGSONG);

break;

case R.id.gao_guai:

VoiceUtils.fix(path, VoiceUtils.MODE_GAOGUAI);

break;

case R.id.kong_ling:

VoiceUtils.fix(path, VoiceUtils.MODE_KONGLING);

break;

default:

break;

}

}

};

@Override

protected void onDestroy() {

super.onDestroy();

FMOD.close();

};

}

根据按钮点击来调用本地方法。

6、fix.cpp实现头文件方法

这是最重要的一步,根据type类型来实现不同的变声效果。

#include "inc/fmod.hpp"

#include "common.h"

#include

#include

#include "org_fmod_example_VoiceUtils.h";

#define MODE_NORMAL 0

#define MODE_LUOLI 1

#define MODE_DASHU 2

#define MODE_JINGSONG 3

#define MODE_GAOGUAI 4

#define MODE_KONGLING 5

using namespace FMOD;

JNIEXPORT void JNICALL Java_org_fmod_example_VoiceUtils_fix

(JNIEnv *env, jclass jcls, jstring path_jstr, jint type){

System     *system;

Sound      *sound;

Channel    *channel = 0;

bool isplay = true;

DSP *dsp;

float frequency = 0;

//  char *path = env->GetStringUTFChars(path_jstr,NULL);

const char* path = env->GetStringUTFChars(path_jstr,NULL);

System_Create(&system);//创建

system->init(32, FMOD_INIT_NORMAL, NULL);//初始化

//创建声音

system->createSound(path, FMOD_DEFAULT, 0, &sound);

switch(type){

case MODE_NORMAL:

//原生播放

system->playSound(sound, 0, false, &channel);

break;

case MODE_LUOLI:

/**

* DSP:digital signal process

* FMOD_DSP_TYPE_PITCHSHIFT dsp,提升或者降低音调用的一种音效

*/

system->createDSPByType(FMOD_DSP_TYPE_PITCHSHIFT,&dsp);

//设置音调的参数,创建fmod中预定义好的音效

dsp->setParameterFloat(FMOD_DSP_PITCHSHIFT_PITCH,2.0);

system->playSound(sound, 0, false, &channel);

//添加到channel

channel->addDSP(0,dsp);

break;

case MODE_DASHU:

//      (FMOD_DSP_TYPE type, DSP **dsp);

system->createDSPByType(FMOD_DSP_TYPE_PITCHSHIFT,&dsp);

dsp->setParameterFloat(FMOD_DSP_PITCHSHIFT_PITCH,0.5);

//      (Sound *sound, ChannelGroup *channelgroup, bool paused, Channel **channel);

system->playSound(sound,0,false,&channel);

//       (int index, DSP *dsp);

channel->addDSP(0,dsp);

break;

case MODE_JINGSONG:

system->createDSPByType(FMOD_DSP_TYPE_TREMOLO,&dsp);

//-1.0~1.0

dsp->setParameterFloat(FMOD_DSP_TREMOLO_SKEW,0.3);

system->playSound(sound,0,false,&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;

default:

break;

}

system->update();

//单位是微秒,每秒钟判断下是否在播放

while(isplay){

channel->isPlaying(&isplay);

usleep(1000*1000);

}

env->ReleaseStringUTFChars(path_jstr,path);

sound->release();

system->close();

system->release();

}

using namespace FMOD使用命名空间FMOD, 主要是方便命名空间FMOD的方法调用,不需要每次调用都要加上FMOD::。基本上读者可以看注释就明白使用了,无需多言。

实现变声,主要是使用DSP,给DSP设置不同的参数类型可以得到不同的音效。最后将 DSP添加到channel声道中。

打开fmod_dsp_effects.h文件可以看到又非常多DSP类型。

DSP设置音效也有很多种

这些音效和类型都有注释说明,用户根据需求去做不一样的变声效果。

关于开始播放声音:实际上使用system->update();才开始播放声音。

while(isplay){

channel->isPlaying(&isplay);

usleep(1000*1000);

}

env->ReleaseStringUTFChars(path_jstr,path);

sound->release();

system->close();

system->release();

每隔一秒钟访问下是否播放结束,直到声音播放结束才释放内存。

运行项目,体验变声效果。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值