NDK开发——Android Studio+CMake实现QQ变声效果
项目演示
Github:https://github.com/AndroidHensen/NDKVoice
项目分析
项目采用Fmod开源库,一个非常简单通用的音频引擎,对原始声音进行音效的处理即可做出变声的效果,下面是变声音频的处理
- 原声:直接播放音频文件
- 萝莉:对音频提高八度
- 大叔:对音频减低八度
- 惊悚:增加音频的颤音
- 搞笑:增加音频的播放速度
- 空灵:增加音频的回音
环境配置
- 你的Android Studio在SDKManager中下载好ndk-build和cmake
- 百度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下载的例子,播放声音的代码和增加音效的代码来编写的
大概的流程
- 创建fmod的系统:System_Create(&system);
- 系统进行初始化:system->init(32, FMOD_INIT_NORMAL, NULL);
- 创建音频:system->createSound(path_cstr, FMOD_DEFAULT, NULL, &sound);
- 创建不同类型的音效:system->createDSPByType(FMOD_DSP_TYPE_PITCHSHIFT, &dsp);
- 播放声音:system->playSound(sound, 0, false, &channel);
- 将音效加入声音中:channel->addDSP(0, dsp);
- 关闭资源:end部分
NDK开发——Android Studio+CMake实现QQ变声效果相关推荐
- 08.Eclipse下Ndk开发(使用fmod实现QQ变声功能)
(创建于2017/12/30) 1.编写native package org.fmod.example;public class EffectUtils {//音效的类型public static f ...
- android fmod,Android利用Fmod仿QQ变声音效
看到QQ一些变声音效,这些声音效果可以采用SoundTouch,Fmod去处理.这篇文章我们用Fmod去实现变声音效的处理.fmod官网https://www.fmod.com/,fmod Ex 声音 ...
- Android NDK开发——Android studio使用JNI调用OpenCV处理图像
前言 这里要演示的是使用Android studio 做APP开发,使用JNI与C++交互的demo. 一.创建工程 1.创建一个Native C++工程. 2.命令工程和指定交互语言. 3.指定C+ ...
- Android 开发之 QQ变声功能实现
1.简介 在QQ中我们使用到的一个功能就是变声,QQ是使用FMOD实现的,那么同样的我们也使用FMOD让自己的应用可以变音 2.FMOD简介 fmod Ex 声音系统是为游戏开发者准备的革命性音频引擎 ...
- NDK 在 Android studio如何使用(Android studio NDK)
其实这个东西入门的话.直接在官网查找demo再结合文档就能间接了解如何构建是最快捷的. 这里提供一下官网和demo的地址. 官网的NDK在Android studio的搭建:http://tools. ...
- android studio socket 失败,Android应用开发Android Studio建立Socket连接失败解决方法
本文将带你了解Android应用开发Android Studio建立Socket连接失败解决方法,希望本文对大家学Android有所帮助. < Android Studio建立Socket连接失 ...
- android studio获取数字签名,Android应用开发Android Studio数字签名打包apk图文步骤教程...
本文将带你了解Android应用开发Android Studio数字签名打包apk图文步骤教程,希望本文对大家学Android有所帮助. Android Studio数字签名打包release版apk ...
- android修改用户名和密码错误,Android应用开发Android Studio 修改用户名、密码、URL等操作教程...
本文将带你了解Android应用开发Android Studio 修改用户名.密码.URL等操作教程,希望本文对大家学Android有所帮助. 修改用户名.密码: 在AndroidStudio的ter ...
- android登录操作代码,Android Studio实现第三方QQ登录操作代码
来看看效果图吧 实现QQ登录了, 新建一个项目工程 ,然后把我们刚才下载的SDK解压将jar文件夹中的jar包拷贝到我们的项目libs中 导入一个下面架包就可以 项目结构如下 打开我们的清单文件And ...
最新文章
- Linux下su与su -命令的区别
- 索引原理,查询机制(转)
- maven jetty/tomcat/wildfly plugin部署应用到本地容器
- 图解LanHelper 使用
- globalmem设备代码分析
- TextView跑步灯效果及在特殊情况下无效的解决方案
- 10 个你可能还不知道 VS Code 使用技巧
- 史海峰:万字长文剖析技术人如何成长
- Maven服务器的使用之Maven桌面项目和Maven Web项目的创建
- HACMP环境修改IP的方法
- Google 员工公开 Windows 10 零日漏洞隐藏 Bug!
- redis 如何查看某个库的key_如何发现 Redis 热点 Key ,解决方案有哪些?
- android 下载网络图片并缓存
- Java循环练习: 有1、2、3、4四个数字,能组成多少个无重复数字的三位数?都是多少?...
- 最新王通《搜索排名引爆点》课值得学习吗
- eclipse新建JSP页面报错:Multiple annotations found at this line解决方法
- imagebutton图片缩放
- 《勋伯格和声学》读书笔记(八):转调
- BI 及其相关技术概览
- Redis(2) redis-cli 客户端操作Redis - 常用命令大全