关于pcm头部加44个字节转为wav格式的方法,请参照我前面写的博文。


关于soundtouc的下载,整理和修改方面的内容请参考iOS那篇博文,这里不再赘述了,其实只要将那个目录下的文件直接拷过来就可以用了。


下面重点介绍一下如何用NDK编译soundtouch。


1.  NDK的相关知识,请查看相关资料,如果有时间我会详细介绍。


2. 在你的工程根目录下,新建jni目录,然后将制作好的SoundTouch拷贝到jni下:




3.  找到STTypes.h头文件,将

#define ST_NO_EXCEPTION_HANDLING    1 原先的注释去掉,即启用这个宏定义,这样就不会使用c++的stdexcep相关的东西了,否则是编译不过去的,如下:




4. 编写Android.mk文件


5.  我们看到上面的Android.mk文件中有一个soundtouch_wapper.cpp,这个是用来连接java和本地c++的一个桥梁,即需要在这个文件中对底层的soundtouch调用进行封装。我们先编写java文件JNISoundTouch.java:


package com.example.soundtouchdemo;


publicclass JNISoundTouch {


publicnativevoid setSampleRate(int sampleRate);

publicnativevoid setChannels(int channel);

publicnativevoid setTempoChange(float newTempo);

publicnativevoid setPitchSemiTones(int newPitch);

publicnativevoid setRateChange(float newRate);

publicnativevoid putSamples(short[] samples, int len);

publicnativeshort[] receiveSamples();

static{

System.loadLibrary("soundtouch");

}

}


这里声明了很多native方法,表示是本地实现的,然后加载了一个叫着“soundtouch”的动态库。



6.    用javah 生成JNISoundTouch.java对应的JNI头文件,先cd到你工程的bin/class目录下


hejinlai_iMac:classes hejinlai$ pwd

/Users/hejinlai/Workspace/Android/SoundTouchDemo/bin/classes

hejinlai_iMac:classes hejinlai$


执行javah com.example.soundtouchdemo.JNISoundTouch生成对应的JNI头文件


hejinlai_iMac:classes hejinlai$ javah com.example.soundtouchdemo.JNISoundTouch

hejinlai_iMac:classes hejinlai$ ls -l

total 8

drwxr-xr-x  3 hejinlai  staff   102  6 19 11:32 com

-rw-r--r--  1 hejinlai  staff  1904  6 19 18:45 com_example_soundtouchdemo_JNISoundTouch.h

hejinlai_iMac:classes hejinlai$


7.    将生成的头文件的内容全部复制到soundtouch_wapper.cpp中,然后这个文件中对头文件生成的方法进行实现:


/* DO NOT EDIT THIS FILE - it is machine generated */

#include

/* Header for class com_example_soundtouchdemo_JNISoundTouch */

#ifndef _Included_com_example_soundtouchdemo_JNISoundTouch

#define _Included_com_example_soundtouchdemo_JNISoundTouch

#ifdef __cplusplus

extern"C" {

#endif


#include"SoundTouch/SoundTouch.h"

#define BUFFER_SIZE 4096


soundtouch::SoundTouch mSoundTouch;



/*

* Class:     com_example_soundtouchdemo_JNISoundTouch

* Method:    setSampleRate

* Signature: (I)V

*/

JNIEXPORT void JNICALL Java_com_example_soundtouchdemo_JNISoundTouch_setSampleRate

 (JNIEnv *env, jobject obj, jint sampleRate)

{

mSoundTouch.setSampleRate(sampleRate);

}


/*

* Class:     com_example_soundtouchdemo_JNISoundTouch

* Method:    setChannels

* Signature: (I)V

*/

JNIEXPORT void JNICALL Java_com_example_soundtouchdemo_JNISoundTouch_setChannels

 (JNIEnv *env, jobject obj, jint channel)

{

mSoundTouch.setChannels(channel);

}


/*

* Class:     com_example_soundtouchdemo_JNISoundTouch

* Method:    setTempoChange

* Signature: (F)V

*/

JNIEXPORT void JNICALL Java_com_example_soundtouchdemo_JNISoundTouch_setTempoChange

 (JNIEnv *env, jobject obj, jfloat newTempo)

{

mSoundTouch.setTempoChange(newTempo);

}


/*

* Class:     com_example_soundtouchdemo_JNISoundTouch

* Method:    setPitchSemiTones

* Signature: (I)V

*/

JNIEXPORT void JNICALL Java_com_example_soundtouchdemo_JNISoundTouch_setPitchSemiTones

 (JNIEnv *env, jobject obj, jint pitch)

{

mSoundTouch.setPitchSemiTones(pitch);

}


/*

* Class:     com_example_soundtouchdemo_JNISoundTouch

* Method:    setRateChange

* Signature: (F)V

*/

JNIEXPORT void JNICALL Java_com_example_soundtouchdemo_JNISoundTouch_setRateChange

 (JNIEnv *env, jobject obj, jfloat newRate)

{

mSoundTouch.setRateChange(newRate);

}


/*

* Class:     com_example_soundtouchdemo_JNISoundTouch

* Method:    putSamples

* Signature: ([SI)V

*/

JNIEXPORT void JNICALL Java_com_example_soundtouchdemo_JNISoundTouch_putSamples

 (JNIEnv *env, jobject obj, jshortArray samples, jint len)

{

// 转换为本地数组

jshort *input_samples = env->GetShortArrayElements(samples, NULL);

mSoundTouch.putSamples(input_samples, len);

// 释放本地数组(避免内存泄露)

env->ReleaseShortArrayElements(samples, input_samples, 0);

}


/*

* Class:     com_example_soundtouchdemo_JNISoundTouch

* Method:    receiveSamples

* Signature: ([SI)I

*/

JNIEXPORT jshortArray JNICALL Java_com_example_soundtouchdemo_JNISoundTouch_receiveSamples

 (JNIEnv *env, jobject obj)

{

short buffer[BUFFER_SIZE];

int nSamples = mSoundTouch.receiveSamples(buffer, BUFFER_SIZE);


// 局部引用,创建一个short数组

jshortArray receiveSamples = env->NewShortArray(nSamples);

// 给short数组设置值

env->SetShortArrayRegion(receiveSamples, 0, nSamples, buffer);


return receiveSamples;

}


#ifdef __cplusplus

}

#endif

#endif


这里设计到很多JNI的相关知识,如果读者不是很了解,可以查找相应的资料。



8.  在命令行中,cd到所在工程的jni目录下,调用ndk-build进行编译生成动态库so文件:

hejinlai_iMac:jni hejinlai$ pwd

/Users/hejinlai/Workspace/Android/SoundTouchDemo/jni

hejinlai_iMac:jni hejinlai$ ndk-build

/Users/hejinlai/Android/android-ndk-r8c/build/core/add-application.mk:128: Android NDK: WARNING: APP_PLATFORM android-14 is larger than android:minSdkVersion 8 in /Users/hejinlai/Workspace/Android/SoundTouchDemo/AndroidManifest.xml    

Compile++ thumb  : soundtouch <= AAFilter.cpp

Compile++ thumb  : soundtouch <= BPMDetect.cpp

Compile++ thumb  : soundtouch <= cpu_detect_x86.cpp

Compile++ thumb  : soundtouch <= FIFOSampleBuffer.cpp

Compile++ thumb  : soundtouch <= FIRFilter.cpp

Compile++ thumb  : soundtouch <= mmx_optimized.cpp

Compile++ thumb  : soundtouch <= PeakFinder.cpp

Compile++ thumb  : soundtouch <= RateTransposer.cpp

SharedLibrary  : libsoundtouch.so

Install        : libsoundtouch.so => libs/armeabi/libsoundtouch.so

hejinlai_iMac:jni hejinlai$


9.  设置soundtouch的相关参数:


soundtouch.setSampleRate(16000);

soundtouch.setChannels(1);

soundtouch.setPitchSemiTones(10);

soundtouch.setRateChange(-0.7f);

soundtouch.setTempoChange(0.5f);


10.  调用soundtouch.putSamples方法将录音数据传递给soundtouch处理,然后在调用

soundtouch.receiveSamples方法得到处理后的数据


11. 给处理后的数据加上44个字节头部,转为wav格式,然后保存到sdcrad中:


WaveHeader header = new WaveHeader(fileLength);

byte[] headers = header.getHeader();

// 保存文件

FileOutputStream out = new FileOutputStream(Settings.recordingPath  + "soundtouch.wav");

out.write(headers);

for(byte[] bytes: wavDatas){

out.write(bytes);

}

out.close();


主要的步骤就是这些,这个运行的效果和iOS那个版本是差不多的,大家可以参考。

我把这个工程的源代码上传到附件中了,欢迎大家下载。