项目演示

Github:https://github.com/AndroidHensen/NDKVoice

项目分析

项目采用Fmod开源库,一个非常简单通用的音频引擎,对原始声音进行音效的处理即可做出变声的效果,下面是变声音频的处理

  • 原声:直接播放音频文件
  • 萝莉:对音频提高八度
  • 大叔:对音频减低八度
  • 惊悚:增加音频的颤音
  • 搞笑:增加音频的播放速度
  • 空灵:增加音频的回音

环境配置

  1. 你的Android Studio在SDKManager中下载好ndk-build和cmake
  2. 百度fmod的官网,在DownLoad页面中,找到Android平台的源码进行下载,下载需要使用VPN或者联系客服

项目开始

1、创建一个新的项目,勾选包含C++

2、勾选C++11和C++的依赖库

3、找到下载好的fmod目录下,在api/lowlevel/lib中,将所有文件拷贝到你的项目的libs目录下

4、让项目添加对fmod.jar包的支持,fmod.jar右键Add As Libs

5、找到下载好的fmod目录下,在api/lowlevel/inc中,将所有文件拷贝到你的项目的cpp(jni folder)目录下

拷贝好后如下图

6、准备好一个音频文件放到assets文件夹中

7、配置app的gradle文件中的cmake和ndk

android {compileSdkVersion 25buildToolsVersion "25.0.3"defaultConfig {applicationId "com.handsome.ndkvoice"minSdkVersion 16targetSdkVersion 25versionCode 1versionName "1.0"testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"externalNativeBuild {cmake {cppFlags "-std=c++11 -frtti -fexceptions"abiFilters "armeabi","arm64-v8a","armeabi-v7a","x86"}}}buildTypes {release {minifyEnabled falseproguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'}}sourceSets.main {jniLibs.srcDirs = ['libs']jni.srcDirs = []}externalNativeBuild {cmake {path "CMakeLists.txt"}}
}

代码编写

1、我们创建一个Utils类,编写我们的fmod变声处理

public class Utils {//音效类型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;/*** 音效处理传2个值** @param path 音频文件路径* @param type 音频文件类型*/public native static void fix(String path, int type);static {System.loadLibrary("fmodL");System.loadLibrary("fmod");System.loadLibrary("sound");}
}

2、通过终端,javah我们的文件

3、将创建好的.h文件放进我们的cpp目录下,并创建sound.cpp

4、编写sound.cpp代码

#include "inc/fmod.hpp"
#include <stdlib.h>
#include <unistd.h>
#include  "com_handsome_ndkvoice_Utils.h"#include <jni.h>#include <android/log.h>
#define LOGI(FORMAT,...) __android_log_print(ANDROID_LOG_INFO,"zph",FORMAT,##__VA_ARGS__);
#define LOGE(FORMAT,...) __android_log_print(ANDROID_LOG_ERROR,"zph",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 5using namespace FMOD;JNIEXPORT void JNICALL Java_com_handsome_ndkvoice_Utils_fix(JNIEnv *env,jclass jcls, jstring path_jstr, jint type) {//声音引擎System *system;//声音Sound *sound;//数字处理(音效)DSP *dsp;//正在播放bool playing = true;//音乐轨道Channel *channel;//播放速度float frequency = 0;//音频地址const char* path_cstr = env->GetStringUTFChars(path_jstr, NULL);System_Create(&system);system->init(32, FMOD_INIT_NORMAL, NULL);try {//创建声音system->createSound(path_cstr, FMOD_DEFAULT, NULL, &sound);switch (type) {case MODE_NORMAL://原生播放system->playSound(sound, 0, false, &channel);break;case MODE_LUOLI://提升或者降低音调的一种音效system->createDSPByType(FMOD_DSP_TYPE_PITCHSHIFT, &dsp);//设置音调的参数dsp->setParameterFloat(FMOD_DSP_PITCHSHIFT_PITCH, 1.8);//添加进到channel,添加进轨道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->addDSP(0, dsp);break;case MODE_JINGSONG:system->createDSPByType(FMOD_DSP_TYPE_TREMOLO, &dsp);dsp->setParameterFloat(FMOD_DSP_TREMOLO_SKEW, 0.8);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 * 2;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;}} catch (...) {LOGE("%s", "发生异常");goto end;}system->update();//单位是微妙//每秒钟判断下是否是播放while (playing) {channel->isPlaying(&playing);usleep(1000);}goto end;//释放资源end: env->ReleaseStringUTFChars(path_jstr, path_cstr);sound->release();system->close();system->release();
}

5、配置cmake文件

cmake_minimum_required(VERSION 3.4.1)find_library( # Sets the name of the path variable.log-liblog )set(distribution_DIR ${CMAKE_SOURCE_DIR}/libs)add_library( fmodSHAREDIMPORTED )
set_target_properties( fmodPROPERTIES IMPORTED_LOCATION${distribution_DIR}/${ANDROID_ABI}/libfmod.so )
add_library( fmodLSHAREDIMPORTED )
set_target_properties( fmodLPROPERTIES IMPORTED_LOCATION${distribution_DIR}/${ANDROID_ABI}/libfmodL.so )
add_library( soundSHAREDsrc/main/cpp/sound.cpp )include_directories(src/main/cpp/inc)target_link_libraries( sound fmod fmodL${log-lib} )

6、编写我们的Activity,对每个类型处理点击事件并调用本地方法

public class MainActivity extends AppCompatActivity implements View.OnClickListener {private ExecutorService fixedThreadPool;private PlayerThread playerThread;private String path = "file:///android_asset/hensen.mp3";private int type;private LinearLayout normal, luoli, dashu, jingsong, gaoguai, kongling;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);normal = (LinearLayout) findViewById(R.id.normal);luoli = (LinearLayout) findViewById(R.id.luoli);dashu = (LinearLayout) findViewById(R.id.dashu);jingsong = (LinearLayout) findViewById(R.id.jingsong);gaoguai = (LinearLayout) findViewById(R.id.gaoguai);kongling = (LinearLayout) findViewById(R.id.kongling);normal.setOnClickListener(this);luoli.setOnClickListener(this);dashu.setOnClickListener(this);jingsong.setOnClickListener(this);gaoguai.setOnClickListener(this);kongling.setOnClickListener(this);fixedThreadPool = Executors.newFixedThreadPool(1);FMOD.init(this);}class PlayerThread implements Runnable {@Overridepublic void run() {Utils.fix(path, type);}}@Overridepublic void onClick(View v) {switch (v.getId()) {case R.id.normal:type = Utils.MODE_NORMAL;break;case R.id.luoli:type = Utils.MODE_LUOLI;break;case R.id.dashu:type = Utils.MODE_DASHU;break;case R.id.jingsong:type = Utils.MODE_JINGSONG;break;case R.id.gaoguai:type = Utils.MODE_GAOGUAI;break;case R.id.kongling:type = Utils.MODE_KONGLING;break;}playerThread = new PlayerThread();fixedThreadPool.execute(playerThread);}@Overrideprotected void onDestroy() {super.onDestroy();FMOD.close();}
}

过程分析

  • cmake文件的分析
  • 实现变声代码过程的分析

一、cmake文件分析

1、声明cmake版本

cmake_minimum_required(VERSION 3.4.1)

2、设置一个路径变量,指向我们的libs目录,也就是fmod.jar和so库的目录

set(distribution_DIR ${CMAKE_SOURCE_DIR}/libs)

3、添加我们需要的fmod、fmodL、sound的库

add_library( fmodSHAREDIMPORTED )
set_target_properties( fmodPROPERTIES IMPORTED_LOCATION${distribution_DIR}/${ANDROID_ABI}/libfmod.so )
add_library( fmodLSHAREDIMPORTED )
set_target_properties( fmodLPROPERTIES IMPORTED_LOCATION${distribution_DIR}/${ANDROID_ABI}/libfmodL.so )
add_library( soundSHAREDsrc/main/cpp/sound.cpp )

这里是通过我们刚才设置的libs目录下,和对应的Gradle设置的架构进行匹配,找到libfmod.so文件

${distribution_DIR}/${ANDROID_ABI}/libfmod.so

Gradle设置的架构在这个地方

二、实现变声代码过程的分析

这里的实现主要是阅读fmod下载的例子,播放声音的代码和增加音效的代码来编写的

大概的流程

  1. 创建fmod的系统:System_Create(&system);
  2. 系统进行初始化:system->init(32, FMOD_INIT_NORMAL, NULL);
  3. 创建音频:system->createSound(path_cstr, FMOD_DEFAULT, NULL, &sound);
  4. 创建不同类型的音效:system->createDSPByType(FMOD_DSP_TYPE_PITCHSHIFT, &dsp);
  5. 播放声音:system->playSound(sound, 0, false, &channel);
  6. 将音效加入声音中:channel->addDSP(0, dsp);
  7. 关闭资源:end部分

NDK开发——Android Studio+CMake实现QQ变声效果相关推荐

  1. 08.Eclipse下Ndk开发(使用fmod实现QQ变声功能)

    (创建于2017/12/30) 1.编写native package org.fmod.example;public class EffectUtils {//音效的类型public static f ...

  2. android fmod,Android利用Fmod仿QQ变声音效

    看到QQ一些变声音效,这些声音效果可以采用SoundTouch,Fmod去处理.这篇文章我们用Fmod去实现变声音效的处理.fmod官网https://www.fmod.com/,fmod Ex 声音 ...

  3. Android NDK开发——Android studio使用JNI调用OpenCV处理图像

    前言 这里要演示的是使用Android studio 做APP开发,使用JNI与C++交互的demo. 一.创建工程 1.创建一个Native C++工程. 2.命令工程和指定交互语言. 3.指定C+ ...

  4. Android 开发之 QQ变声功能实现

    1.简介 在QQ中我们使用到的一个功能就是变声,QQ是使用FMOD实现的,那么同样的我们也使用FMOD让自己的应用可以变音 2.FMOD简介 fmod Ex 声音系统是为游戏开发者准备的革命性音频引擎 ...

  5. NDK 在 Android studio如何使用(Android studio NDK)

    其实这个东西入门的话.直接在官网查找demo再结合文档就能间接了解如何构建是最快捷的. 这里提供一下官网和demo的地址. 官网的NDK在Android studio的搭建:http://tools. ...

  6. android studio socket 失败,Android应用开发Android Studio建立Socket连接失败解决方法

    本文将带你了解Android应用开发Android Studio建立Socket连接失败解决方法,希望本文对大家学Android有所帮助. < Android Studio建立Socket连接失 ...

  7. android studio获取数字签名,Android应用开发Android Studio数字签名打包apk图文步骤教程...

    本文将带你了解Android应用开发Android Studio数字签名打包apk图文步骤教程,希望本文对大家学Android有所帮助. Android Studio数字签名打包release版apk ...

  8. android修改用户名和密码错误,Android应用开发Android Studio 修改用户名、密码、URL等操作教程...

    本文将带你了解Android应用开发Android Studio 修改用户名.密码.URL等操作教程,希望本文对大家学Android有所帮助. 修改用户名.密码: 在AndroidStudio的ter ...

  9. android登录操作代码,Android Studio实现第三方QQ登录操作代码

    来看看效果图吧 实现QQ登录了, 新建一个项目工程 ,然后把我们刚才下载的SDK解压将jar文件夹中的jar包拷贝到我们的项目libs中 导入一个下面架包就可以 项目结构如下 打开我们的清单文件And ...

最新文章

  1. Linux下su与su -命令的区别
  2. 索引原理,查询机制(转)
  3. maven jetty/tomcat/wildfly plugin部署应用到本地容器
  4. 图解LanHelper 使用
  5. globalmem设备代码分析
  6. TextView跑步灯效果及在特殊情况下无效的解决方案
  7. 10 个你可能还不知道 VS Code 使用技巧
  8. 史海峰:万字长文剖析技术人如何成长
  9. Maven服务器的使用之Maven桌面项目和Maven Web项目的创建
  10. HACMP环境修改IP的方法
  11. Google 员工公开 Windows 10 零日漏洞隐藏 Bug!
  12. redis 如何查看某个库的key_如何发现 Redis 热点 Key ,解决方案有哪些?
  13. android 下载网络图片并缓存
  14. Java循环练习: 有1、2、3、4四个数字,能组成多少个无重复数字的三位数?都是多少?...
  15. 最新王通《搜索排名引爆点》课值得学习吗
  16. eclipse新建JSP页面报错:Multiple annotations found at this line解决方法
  17. imagebutton图片缩放
  18. 《勋伯格和声学》读书笔记(八):转调
  19. BI 及其相关技术概览
  20. Redis(2) redis-cli 客户端操作Redis - 常用命令大全

热门文章

  1. HackRF实现GPS欺骗教程
  2. 零信任架构和访问控制模型ABAC
  3. UVa11549 Calculator Conundrum
  4. 手机sar值_手机SAR值仪器测试全过程
  5. response导出html到word
  6. 突变点检测:带突变的趋势描述测试过程
  7. 支付宝618红包怎么领?怎么用?
  8. .NET Core中的使用Kestrel服务器理解
  9. sja1000 中断_SJA1000的错误中断处理
  10. 前端 - 查找关键词 - 高亮 - 软考 - 程序员 - 简单编程算法计算