(创建于2017/12/30)
1.编写native
package org.fmod.example;
public class EffectUtils {
//音效的类型
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("qq_voice");
}
}
2.进入src目录下,使用命令行生成头文件
javah 包名+类名
3.创建项目根目录下jni文件夹,将头文件拷贝进去
4.下载fmod源码,复制api中lowlevel中的inc中的头文件到jni目录下
5.复制fmod jar包到根目录下libs文件夹并添加依赖
6.复制需要的api平台的so文件到jni目录下
7.修改报错的地方,比如头文件的路径等问题
8.Android Tools -> Add native support 添加本地支持(在此之前,确认你的项目中已经配置了ndk相关的头文件目录支持,参考前边的笔记),填写你要生成的
so库的文件名,确认和loadLibrary中加载的(如qq_voice)保持一致
9.配置mk文件:
Android.mk
LOCAL_PATH := $(call my-dir)
//编译libfmod.so
include $(CLEAR_VARS)
LOCAL_MODULE := fmod
LOCAL_SRC_FILES := libfmod.so
include $(PREBUILT_SHARED_LIBRARY)
//编译libfmodL.so
include $(CLEAR_VARS)
LOCAL_MODULE := fmodL
LOCAL_SRC_FILES := libfmodL.so
include $(PREBUILT_SHARED_LIBRARY)
//编译我们自己写的c代码为so文件,并添加上边编译的so支持
include $(CLEAR_VARS)
LOCAL_MODULE := qq_voice
LOCAL_SRC_FILES := effect_fix.cpp
LOCAL_SHARED_LIBRARIES := fmod fmodL
//添加log支持
LOCAL_LDLIBS := -llog
//添加c++异常类支持
LOCAL_CPP_FEATURES := exceptions
include $(BUILD_SHARED_LIBRARY)
Application.mk
##支持C++异常处理,标准莫板块(针对string.h等头文件的处理,去掉了common.c之后,这个不再需要了,但是保留也没问题)
APP_STL := gnustl_static
10.不断的build project,直到所有异常解决编译成功
部分源码:
effect_fix.cpp
#include "org_fmod_example_EffectUtils.h"
#include "inc/fmod.hpp"
#include <stdlib.h>
#include <unistd.h>
#include <android/log.h>
#define LOGI(FORMAT,...) __android_log_print(ANDROID_LOG_INFO,"renzhenming",FORMAT,##__VA_ARGS__)
#define LOGE(FORMAT,...) __android_log_print(ANDROID_LOG_ERROR,"renzhenming",FORMAT,##__VA_ARGS__)
#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_EffectUtils_fix
(JNIEnv *env, jclass jcls, jstring path_jstr, jint type){
System *system;
FMOD_RESULT result;
Sound *sound;
Channel *channel;
DSP *dsp;
float frequency = 0;
bool isPlaying = true;
const char *media_path = env->GetStringUTFChars(path_jstr,NULL);
try {
//初始化
result = System_Create(&system);
result = system->init(32, FMOD_INIT_NORMAL, NULL);
//创建声音
//这里进坑了,写作下边的样子是无法播放的,正确的方式是第二行 因为sound如果是null,那么,播放的时候的sound也就是null,怎么播放呢
//result = system->createSound(media_path, FMOD_DEFAULT, 0, NULL);
LOGI("%s",media_path);
system->createSound(media_path, FMOD_DEFAULT, NULL, &sound);
switch(type){
case MODE_NORMAL:
//原生播放
result = system->playSound(sound, 0, false, &channel);
break;
case MODE_LUOLI:
//dsp -- 音效
//FMOD_DSP_TYPE_PITCHSHIFT 提升或者降低音调用的一种音效
system->createDSPByType(FMOD_DSP_TYPE_PITCHSHIFT,&dsp);
//设置音调的参数
dsp->setParameterFloat(FMOD_DSP_PITCHSHIFT_PITCH,2);
//播放(播放和添加channel的顺序必须是先播放,再添加,否则音效无法生效)
//猜测原因
//playSound之后并不是立即播放,而是在system->update();之后开始播放,
//playSound的作用是创造了一个sound载体一个channel载体,然后在这个载体基础上添加一系列的效果,所以,只能现有载体
//效果才有放置的位置,所以需要先play再添加
result = system->playSound(sound, 0, false, &channel);
//添加到channel
channel->addDSP(0,dsp);
break;
case MODE_DASHU:
//dsp -- 音效
//FMOD_DSP_TYPE_PITCHSHIFT 提升或者降低音调用的一种音效
system->createDSPByType(FMOD_DSP_TYPE_PITCHSHIFT,&dsp);
//设置音调的参数
dsp->setParameterFloat(FMOD_DSP_PITCHSHIFT_PITCH,0.6);
//播放(播放和添加channel的顺序必须是先播放,再添加,否则音效无法生效)
result = system->playSound(sound, 0, false, &channel);
//添加到channel
channel->addDSP(0,dsp);
break;
case MODE_GAOGUAI:
//提高说话的速度
result = system->playSound(sound, 0, false, &channel);
channel->getFrequency(&frequency);\
frequency = frequency*1.5;
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,2);
result = system->playSound(sound, 0, false, &channel);
channel->addDSP(0,dsp);
break;
case MODE_JINGSONG:
//紧张
system->createDSPByType(FMOD_DSP_TYPE_ECHO,&dsp);
dsp->setParameterFloat(FMOD_DSP_TREMOLO_SKEW,0.5);
result = system->playSound(sound, 0, false, &channel);
channel->addDSP(0,dsp);
break;
default:
break;
}
while(isPlaying){
channel->isPlaying(&isPlaying);
//<unistd.h>
//单位微秒,不断的睡眠保证声音播放完成之后再释放资源
usleep(1000*1000);
}
LOGI("%s","播放完成");
system->update();
} catch(...){
LOGE("%s","发生异常");
goto end;
}
goto end;
end:
env->ReleaseStringUTFChars(path_jstr,media_path);
result = sound->release();
system->close();
system->release();
}
QQActivity.java
package org.fmod.example;
import java.io.File;
import com.renzhenming.qq_voice.R;
import android.app.Activity;
import android.os.Bundle;
import android.os.Environment;
import android.util.Log;
import android.view.View;
public class QQActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
org.fmod.FMOD.init(this);
setContentView(R.layout.activity_main);
}
public void mFix(View view){
String path = Environment.getExternalStorageDirectory().getAbsolutePath() + File.separatorChar + "singing.wav";
Log.d("renzhenming", path);
switch (view.getId()) {
case R.id.btn_record:
EffectUtils.fix(path, EffectUtils.MODE_NORMAL);
Log.d("renzhenming", "MODE_NORMAL");
break;
case R.id.btn_luoli:
EffectUtils.fix(path, EffectUtils.MODE_LUOLI);
Log.d("renzhenming", "MODE_LUOLI");
break;
case R.id.btn_dashu:
EffectUtils.fix(path, EffectUtils.MODE_DASHU);
Log.d("renzhenming", "MODE_DASHU");
break;
case R.id.btn_jingsong:
EffectUtils.fix(path, EffectUtils.MODE_JINGSONG);
break;
case R.id.btn_gaoguai:
EffectUtils.fix(path, EffectUtils.MODE_GAOGUAI);
break;
case R.id.btn_kongling:
EffectUtils.fix(path, EffectUtils.MODE_KONGLING);
break;
default:
break;
}
}
@Override
protected void onDestroy(){
org.fmod.FMOD.close();
super.onDestroy();
}
}
EffectUtils.java
package org.fmod.example;
public class EffectUtils {
//音效的类型
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("qq_voice");
}
}
程序运行界面