introduce
fmod is a very excellent c + + open source framework, this time through this framework to achieve QQ-like sound effects, sound effects of six kinds, normal, Laurie, uncle, thriller, funny, empty. As for more effects, I am interested in exploring them again. The routine is roughly the same.
Project Effect Diagram and Its Principle
Project adoption Fmod Open Source Library, a very simple and universal audio engine, can change the sound effect by processing the original sound. Here is the processing of the variable sound frequency.
- Sound: Play audio files directly
- Laurie: Eight degrees for audio
- Uncle: Reduce audio by eight degrees
- Thriller: Increase the Vibration of Audio
- Funny: Increase the speed of audio playback
- Echo: Increase Audio Echo
Function
If you could run the last fmod sample program in Android studio, there would be no big problem in this run.
The tool used for this time is android studio 2.3.3.
step
1. download fmod
To fmod Official website Register and download the Android version of fmod. Decompression. As follows
This time, the files under inc and lib in api/lowlevel package are used
2. New Android Project
Create a new Android project through as, for example, this time my project name is QQVoice_change
Then the armeabi, x86 files and their. so libraries under the lib package of api/lowlevel are copied to the libs directory of the project.
Copy the inc file and its file under the api/lowlevel package to the cpp directory of the project, and then complete the copy as shown in the figure.
Don't forget to compile fmod.jar into the project after copying it.
3. Modify build.gradle and MakeLists. TXT
Many people have died in compiling c/c++ file dynamic libraries in android studio, which requires gradle and maker programming to really understand. If you make a mistake in this step, you will find many mistakes in a compilation.
Modify Builde.gradle
1. Suppose ndk {} is not configured in build.gradle. Then, when compiled, the compiler will compile the so libraries of all platforms. Whereas only so files of armeabi and x86 are imported here, so when compiling so files of other platforms, so files of other platforms will not be found and errors will be reported. So you need to configure ndk {} in build.gradle.
If you do not configure ndk {} in build.gradle, you need to import so libraries for all platforms.
In this example, only so files of armeabi and x86 are imported, which will cause an error if compiled directly. So add the following code to build.gradle:
ndk {
abiFilters "armeabi","x86"
}
2. The so file is configured under the libs folder here, so it should be configured in build.gradle:
sourceSets.main {
jniLibs.srcDirs = ['libs']
jni.srcDirs = []
}
The modified build.gradle is as follows
android {
compileSdkVersion 26
buildToolsVersion "27.0.3"
defaultConfig {
applicationId "com.gxl.change"
minSdkVersion 15
targetSdkVersion 26
versionCode 1
versionName "1.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
externalNativeBuild {
cmake {
cppFlags ""
}
}
ndk {
abiFilters "armeabi","x86"
}
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
externalNativeBuild {
cmake {
path "CMakeLists.txt"
}
}
sourceSets.main {
jniLibs.srcDirs = ['libs']
jni.srcDirs = []
}
}
Modify CMakeLists.txt
Because fmod.so and fmodL.so are needed for compilation here, the CPP code for muting sound is placed in native-lib.cpp, and the muting sound is generated. so is called changeVoice, so CMakeLists.txt is as follows
# For more information about using CMake with Android Studio, read the # documentation: https://d.android.com/studio/projects/add-native-code.html # Sets the minimum version of CMake required to build the native library. cmake_minimum_required(VERSION 3.4.1) # Creates and names a library, sets it as either STATIC # or SHARED, and provides the relative paths to its source code. # You can define multiple libraries, and CMake builds them for you. # Gradle automatically packages shared libraries with your APK. #----------------------------------------- find_library( log-lib log ) set(my_lib_path ${CMAKE_SOURCE_DIR}/libs) # Add tripartite so Libraries add_library(libfmod SHARED IMPORTED ) # The Absolute Path of Naming Third Party Library set_target_properties( libfmod PROPERTIES IMPORTED_LOCATION ${my_lib_path}/${ANDROID_ABI}/libfmod.so ) add_library(libfmodL SHARED IMPORTED ) set_target_properties( libfmodL PROPERTIES IMPORTED_LOCATION ${my_lib_path}/${ANDROID_ABI}/libfmodL.so ) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=gnu++11") #-------------------------------- add_library( # Sets the name of the library. changeVoice # Sets the library as a shared library. SHARED # Provides a relative path to your source file(s). src/main/cpp/native-lib.cpp ) # Searches for a specified prebuilt library and stores the path as a # variable. Because CMake includes system libraries in the search path by # default, you only need to specify the name of the public NDK library # you want to add. CMake verifies that the library exists before # completing its build. # Specifies libraries CMake should link to your target library. You # can link multiple libraries, such as libraries you define in this # build script, prebuilt third-party libraries, or system libraries. #--------------------- # Import path, so that the folder can be found at compile time include_directories(src/main/cpp/inc) # Link three paths target_link_libraries( changeVoice libfmod libfmodL ${log-lib} )
You can look at this file more. After reading this file more, you will find that many c/c++ libraries run roughly the same way under as.
4. Achieving the function of changing sound
Create a new EffectUtils.java file to handle the murmur. The code is as follows
package com.gxl.change;
/**
* Created by Administrator on 2018/7/10/010.
*/
public class EffectUtils {
//Sound effect types
public static final int MODE_NORMAL = 0;//normal
public static final int MODE_LUOLI = 1;//Lolita
public static final int MODE_DASHU = 2;//uncle
public static final int MODE_JINGSONG = 3;//Thriller
public static final int MODE_GAOGUAI = 4;//Funny
public static final int MODE_KONGLING = 5;//Emptiness
/**
* Change of voice
* @param path Voice path
* @param type Types of voice change
*/
public static native void fix(String path,int type);
static
{
System.loadLibrary("fmodL");
System.loadLibrary("fmod");
System.loadLibrary("changeVoice");
}
}
Header files can be automatically generated to native-lib.cpp in Android studio version 2.2 or above.
5. Implementing Functions by c++.
Implementing logic in native-lib
#include <jni.h>
#include "inc/fmod.hpp"
#include <string>
#include <unistd.h>
using namespace FMOD;
#define MODE_NORMAL 0
#define MODE_LUOLI 1
#define MODE_DASHU 2
#define MODE_JINGSONG 3
#define MODE_GAOGUAI 4
#define MODE_KONGLING 5
#include <android/log.h>
#define LOGI(FORMAT, ...) __android_log_print(ANDROID_LOG_INFO,"jason",FORMAT,##__VA_ARGS__);
#define LOGE(FORMAT, ...) __android_log_print(ANDROID_LOG_ERROR,"jason",FORMAT,##__VA_ARGS__);
extern "C"
JNIEXPORT void JNICALL
Java_com_gxl_change_EffectUtils_fix(JNIEnv *env, jclass cls, jstring path_str, jint type) {
//Many of them are second-level pointers, but here you can define first-level pointers, and here you can achieve the same effect by reference.
System * system;
Sound * sound;
Channel *channel;
DSP *dsp;
bool playing= true;
float frequency=1;
//Initialization
System_Create(&system);
system->init(32, FMOD_INIT_NORMAL, NULL);
//Convert string to char*
const char* path=env->GetStringUTFChars(path_str,NULL);
//Create voice
system->createSound(path,FMOD_DEFAULT, 0, &sound);
try {
//Change the sound according to the type
switch (type) {
case MODE_NORMAL:
//Normal voice
system->playSound(sound, 0, false, &channel);
break;
case MODE_LUOLI:
//Lolita
//DSP digital signal process
//DSP - > Sound effects create predefined sound effects in fmod
//FMOD_DSP_TYPE_PITCHSHIFT dsp, a sound effect that promotes or reduces voice calls
system->createDSPByType(FMOD_DSP_TYPE_PITCHSHIFT, &dsp);
//Improving sound effects
dsp->setParameterFloat(FMOD_DSP_TYPE_PITCHSHIFT, 2.5);
//Play sound
system->playSound(sound, 0, false, &channel);
//Add channel to dsp
channel->addDSP(0, dsp);
break;
case MODE_DASHU:
//uncle
system->createDSPByType(FMOD_DSP_TYPE_PITCHSHIFT, &dsp);
//decrease sound
dsp->setParameterFloat(FMOD_DSP_PITCHSHIFT_PITCH, 0.8);
//Play sound
system->playSound(sound, 0, false, &channel);
//Add channel to dsp
channel->addDSP(0, dsp);
break;
case MODE_JINGSONG:
//Thriller
system->createDSPByType(FMOD_DSP_TYPE_TREMOLO, &dsp);
dsp->setParameterFloat(FMOD_DSP_TREMOLO_SKEW, 0.5);
system->playSound(sound, 0, false, &channel);
channel->addDSP(0, dsp);
break;
case MODE_GAOGUAI:
//Funny
//Speak faster
system->playSound(sound, 0, false, &channel);
//frequency's original sound speed
channel->getFrequency(&frequency);
frequency = frequency * 1.6;
channel->setFrequency(frequency);
LOGI("%s", "fix gaoguai");
break;
case MODE_KONGLING:
//Emptiness
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);
LOGI("%s", "fix kongling");
break;
default:
break;
}
}
catch (...){
//Catching anomalies
LOGE("%s","exception occurred");
}
system->update();
//Release resources
//The unit is microseconds.
//Decide whether or not to play every second
while(playing){
channel->isPlaying(&playing);
usleep(1000 * 1000);
}
//release
sound->release();
system->close();
system->release();
env->ReleaseStringUTFChars(path_str,path);
}
The above is about sound processing, you can see that the routine is roughly the same, the most difficult is to change the sound effect adjustment, if you need more sound effects, Baidu. I'm just going to knock out the example that the teacher gave me, and it's not clear how to change it into what kind of sound effect. Maybe you can refer to the examples in the source code. It may be troublesome.
6. Writing Interface Processing
Implementing Click Events in MainActivity.java
public class QQActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
FMOD.init(this);
setContentView(R.layout.activity_main);
}
public void mFix1(View btn) {
Toast.makeText(this, "Change of voice", Toast.LENGTH_SHORT).show();
String path = Environment.getExternalStorageDirectory().getAbsolutePath() + File.separatorChar + "gxl.wav";
EffectUtils.fix(path, EffectUtils.MODE_NORMAL);
Log.d("jason", "mFix");
}
public void mFix2(View btn) {
Toast.makeText(this, "Change of voice", Toast.LENGTH_SHORT).show();
String path = Environment.getExternalStorageDirectory().getAbsolutePath() + File.separatorChar + "gxl.wav";
EffectUtils.fix(path, EffectUtils.MODE_LUOLI);
Log.d("jason", "mFix");
}
public void mFix3(View btn) {
Toast.makeText(this, "Change of voice", Toast.LENGTH_SHORT).show();
String path = Environment.getExternalStorageDirectory().getAbsolutePath() + File.separatorChar + "gxl.wav";
EffectUtils.fix(path, EffectUtils.MODE_DASHU);
Log.d("jason", "mFix");
}
public void mFix4(View btn) {
Toast.makeText(this, "Change of voice", Toast.LENGTH_SHORT).show();
String path = Environment.getExternalStorageDirectory().getAbsolutePath() + File.separatorChar + "gxl.wav";
EffectUtils.fix(path, EffectUtils.MODE_JINGSONG);
Log.d("jason", "mFix");
}
public void mFix5(View btn) {
Toast.makeText(this, "Change of voice", Toast.LENGTH_SHORT).show();
String path = Environment.getExternalStorageDirectory().getAbsolutePath() + File.separatorChar + "gxl.wav";
EffectUtils.fix(path, EffectUtils.MODE_GAOGUAI);
Log.d("jason", "mFix");
}
public void mFix6(View btn) {
Toast.makeText(this, "Change of voice", Toast.LENGTH_SHORT).show();
String path = Environment.getExternalStorageDirectory().getAbsolutePath() + File.separatorChar + "gxl.wav";
EffectUtils.fix(path, EffectUtils.MODE_KONGLING);
Log.d("jason", "mFix");
}
@Override
protected void onDestroy() {
super.onDestroy();
FMOD.close();
}
}
The interface is as follows
activity_main.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:orientation="vertical"
android:background="#FFF"
android:paddingBottom="20dp" >
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:layout_marginTop="20dp">
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical">
<ImageView
android:id="@+id/btn_record"
style="@style/AudioImgStyle"
android:src="@drawable/record"
android:onClick="mFix1"/>
<TextView
style="@style/AudioTextStyle"
android:text="Original voice"/>
</LinearLayout>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical">
<ImageView
android:id="@+id/btn_luoli"
style="@style/AudioImgStyle"
android:src="@drawable/luoli"
android:onClick="mFix2"/>
<TextView
style="@style/AudioTextStyle"
android:text="Lolita"/>
</LinearLayout>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical">
<ImageView
android:id="@+id/btn_dashu"
style="@style/AudioImgStyle"
android:src="@drawable/dashu"
android:onClick="mFix3"/>
<TextView
style="@style/AudioTextStyle"
android:text="uncle"/>
</LinearLayout>
</LinearLayout>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:layout_marginTop="20dp">
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical">
<ImageView
android:id="@+id/btn_jingsong"
style="@style/AudioImgStyle"
android:src="@drawable/jingsong"
android:onClick="mFix4"/>
<TextView
style="@style/AudioTextStyle"
android:text="Thriller"/>
</LinearLayout>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical">
<ImageView
android:id="@+id/btn_gaoguai"
style="@style/AudioImgStyle"
android:src="@drawable/gaoguai"
android:onClick="mFix5"/>
<TextView
style="@style/AudioTextStyle"
android:text="Funny"/>
</LinearLayout>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical">
<ImageView
android:id="@+id/btn_kongling"
style="@style/AudioImgStyle"
android:src="@drawable/kongling"
android:onClick="mFix6"/>
<TextView
style="@style/AudioTextStyle"
android:text="Emptiness"/>
</LinearLayout>
</LinearLayout>
</LinearLayout>
</RelativeLayout>