FMOD的集成与运用
集成第三方 so库的步骤
- 1、到官网 下载对应的库文件
- 2、找到对应cpu架构的 库文件
- 3、把头文件、库文件放到项目对应目录里边
- 4、在gradle(指定CPU架构,Cmake CPU环境变量值)、cmake(第三方库文件链接到项目库文件里边)
- 5、在java、jni里边运用第三方库的api
记住了:Android便是linux的二次封装,所以假如要移植linux的 库到手机端,库是通用的。直接把 .so 库放到项目对应目录里边就好
------------------手机cpu架构指令集----------------------------------
arm64-v8a 实体手机 基本上便是 arm64-v8a
armeabi-v7a
armeabi
x86 模拟器,WindowsPhone(已经关闭)
FMOD 简介
fmod 是一个音效引擎库 www.fmod.com
游戏引擎 cocos2d unity3d 等 都是默许集成了 fmod来做音效, 由于 fmod是音效引擎库(C库)
FMOD 的运用就类似于你玩 调音师软件的流程,只是调音师能够直接运用,而FMOD经过api,让你能实现类似于调音师的功用 开端调音 pitch 腔调调理 默许:1.0 2.0萝莉 0.8大叔 0.5老头 tremolo 颤腔调理 默许:5 20.0明显颤抖了
模拟信号的声响是无法保存到电脑里边的,所以科学家就把 模拟信号转换成了数字信号,以便对数字信号的声响进行存储和处理(DSP-digital signal process 数字信号处理)
开端集成
整体流程概括
- 资源文件集成
- CMakeLists.txt 配置文件修正
- 导入头文件
- 导入库文件(C++的环境变量)
- 链接第三方库 到 咱们自己的库(libvoicechange.so)里边
- app/build.gradle 配置文件修正
- 指定CPU架构 Cmake中的本地库,例如:libnative-lib.so libvoicechange.so
- 指定CPU的架构 apk/lib/渠道
- 引进 app下 libs文件夹里边的 fmod.jar库
首先把对应的文件集成到项目目录里
修正 CMakeLists.txt
cmake_minimum_required(VERSION 3.22.1) # 表明最低支撑的cmake版本
project("voicechange")
# TODO 第一步:导入头文件
include_directories(inc) # CMakeLists.txt 目录下的inc文件夹 放头文件
# TODO 第二步:导入库文件(C++的环境变量)- 最新的办法,以前是 add_xxx(已淘汰)6.0以下才能够
# 环境变量的添加是追加的办法的:%JAVA_HOME%;%ANDROID_HOME%;path1;path2;
# CMAKE_SOURCE_DIR:取得当时CmakeLists.txt的途径
# CMAKE_ANDROID_ARCH_ABI:主动获取 四大渠道架构值 也能够在gradle里边进行指定
# 这个set的写法就相当于 path = path + CMAKE_CXX_FLAGS;
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -L${CMAKE_SOURCE_DIR}/../jniLibs/${CMAKE_ANDROID_ARCH_ABI}")
# 批量导入 一切的C++文件
#file(GLOB allCPP *.c *.h *.cpp)
# TODO 库名的规则: lib + 称号 + .so (lib .so 体系主动拼接的)
add_library( # Sets the name of the library.
voicechange #libvoicechange.so
SHARED #表明动态库 STATIC 表明静态库
native-lib.cpp
# ${allCPP} # 批量导入
)
# 相当于 var log-lib = log (liblog.so 库的途径)
find_library( # Sets the name of the path variable.
m-lib # 变量名
# Specifies the name of the NDK library that
# you want CMake to locate.
# 这里就相当于 定位到ndk的 liblog.so 库的途径
log #查找NDK的日志打印库
)
# TODO 第三步:链接第三方库 到 咱们自己的库(libvoicechange.so)里边
target_link_libraries( # Specifies the target library.
voicechange
# Links the target library to the log library
# included in the NDK.
${m-lib} # 链接m-lib库 到 咱们自己的库(libvoicechange.so)里边
fmod
fmodL
)
修正 app/build.gradle
android {
...
defaultConfig {
...
// TODO 第四步:指定CPU架构 Cmake中的本地库,例如:libnative-lib.so libvoicechange.so
externalNativeBuild{
cmake{
// cppFlags "" // 这样写,默许是支撑四大渠道
// 指定CPU架构是armeabi-v7a、x86
// 指定CMakeLists.txt里边的环境变量CMAKE_ANDROID_ARCH_ABI的值
// 【留意:这里只指定本地库到armeabi-v7a、x86】 这句代码 还不能决议apk生成
abiFilters ("armeabi-v7a", "x86")
}
// TODO 第五步:指定CPU的架构 apk/lib/渠道
// 下面代码不写,默许是四大CPU架构渠道
ndk{
// 指定CPU架构是armeabi-v7a、x86
// 【留意:这里只指定编译一切库到armeabi-v7a、x86进apk】
abiFilters ("armeabi-v7a", "x86")
}
}
}
...
externalNativeBuild {
cmake {
path file('src/main/cpp/CMakeLists.txt')
version '3.22.1'
}
}
...
}
dependencies {
implementation fileTree(dir: "libs", include: ["*.jar"])
...
// 引进 app下 libs文件夹里边的 fmod.jar库
implementation files('libs/fmod.jar')
...
}
FMOD api的运用
#include <jni.h>
#include <string>
// xxx.h: C的头文件
// xxx.hpp:C++的头文件
// xxx.h ----- xxx.c 一般对应的早期版本
// xxx.hpp -----xxx.cpp C++ NDK 今后基本上 C++多
// 声明 c的头文件,cpp的实现,这样的组合也是能够的。由于C++是兼容C的
#include <fmod.hpp>
#include <unistd.h>
using namespace FMOD;
#include "common_log.h"
#undef TYPE_YUANSHENG
#define TYPE_YUANSHENG 0
#undef TYPE_DASHU
#define TYPE_DASHU 1
#undef TYPE_LUOLI
#define TYPE_LUOLI 2
#undef TYPE_JINGSONG
#define TYPE_JINGSONG 3
#undef TYPE_GAOGUAI
#define TYPE_GAOGUAI 4
#undef TYPE_KONGLING
#define TYPE_KONGLING 5
extern "C"
JNIEXPORT void JNICALL
Java_com_hehe_voicechange_MainActivity_fmodPlaySound(JNIEnv *env, jobject thiz, jint type, jstring path) {
const char * _path = env->GetStringUTFChars(path, NULL);
// 声明指针
System * system;
Sound * sound;
Channel * channel;
DSP * dsp;
// TODO 第一步 创立体系
System_Create(&system);
// TODO 第二步 体系的初始化
//参1:最大音轨数,参2:体系初始化标记,参3:额定数据
system->init(32, FMOD_INIT_NORMAL, 0);
// TODO 第三步 创立声响
//参1:途径,参2:声响的初始化标记,参3:额定数据,参4:声响指针
system->createSound(_path, FMOD_DEFAULT, 0, &sound);
// TODO 第四步 播映声响 音轨 声响
//参1:声响,参2:分组音轨,参3:操控,参4:通道
system->playSound(sound, 0, false, &channel);
// TODO 第五步 添加特效
//pitch 腔调调理 默许:1.0 2.0萝莉 0.8大叔 0.5老头
//tremolo 颤腔调理 默许:5 20.0明显颤抖了
//ECHO 回音
jstring content = nullptr;
float frequency = 1.0f;
switch (type) {
case TYPE_DASHU:
content = env->NewStringUTF("大叔音效播映完结");
// 1、创立数字信号处理对象
system->createDSPByType(FMOD_DSP_TYPE_PITCHSHIFT, &dsp);
// 2、设置腔调值 0.8
dsp->setParameterFloat(0, 0.8f);
// 3、把音效添加到音轨里边去
channel->addDSP(0, dsp);
break;
case TYPE_LUOLI:
content = env->NewStringUTF("萝莉音效播映完结");
system->createDSPByType(FMOD_DSP_TYPE_PITCHSHIFT, &dsp);
dsp->setParameterFloat(0, 2.0f);
channel->addDSP(0, dsp);
break;
case TYPE_GAOGUAI:
// 搞怪小黄人音效,便是把音轨的频率调理了快慢
content = env->NewStringUTF("搞怪音效播映完结");
channel->getFrequency(&frequency); //获取当时帧率
channel->setFrequency(frequency*1.5f);// 修正帧率
break;
case TYPE_KONGLING:
system->createDSPByType(FMOD_DSP_TYPE_ECHO, &dsp);
dsp->setParameterFloat(FMOD_DSP_ECHO_DELAY, 200);// 回音延时 默许500
dsp->setParameterFloat(FMOD_DSP_ECHO_FEEDBACK, 10);// 回音衰减度 默许50
channel->addDSP(0, dsp);
break;
case TYPE_JINGSONG:
// ECHO 回音
system->createDSPByType(FMOD_DSP_TYPE_ECHO, &dsp);
dsp->setParameterFloat(FMOD_DSP_ECHO_DELAY, 300);// 回音延时 默许500
dsp->setParameterFloat(FMOD_DSP_ECHO_FEEDBACK, 10);// 回音衰减度 默许50
channel->addDSP(0, dsp); //音轨一
// pitch 腔调调理 默许:1.0 2.0萝莉 0.8大叔 0.5老头
system->createDSPByType(FMOD_DSP_TYPE_PITCHSHIFT, &dsp);
dsp->setParameterFloat(0, 0.8f);
channel->addDSP(1, dsp);//音轨二
// tremolo 颤腔调理 默许:5 20.0明显颤抖了
system->createDSPByType(FMOD_DSP_TYPE_TREMOLO, &dsp);
dsp->setParameterFloat(0, 20.0f);
channel->addDSP(2, dsp);//音轨三
}
bool isPlaying = 1;
while (isPlaying){
channel->isPlaying(&isPlaying);
usleep(1000*30); // 休眠30毫秒
}
printf("播映结束");
if (content){ // 通知java办法
jclass mainCls = env->GetObjectClass(thiz);
jmethodID mid = env->GetMethodID(mainCls, "soundEnd", "(Ljava/lang/String;)V");
env->CallVoidMethod(thiz, mid, content);
}
// 好习惯:开释资源
dsp->release();
sound->release();
system->close();
system->release();
env->ReleaseStringUTFChars(path, _path);
}