Android下使用SoundTouch实现变声并转为wav格式播放(山寨汤姆猫)
2013-06-19 18:57
495 查看
关于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<jni.h>/* Header for class com_example_soundtouchdemo_JNISoundTouch */#ifndef _Included_com_example_soundtouchdemo_JNISoundTouch#define _Included_com_example_soundtouchdemo_JNISoundTouch#ifdef __cplusplusextern"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那个版本是差不多的,大家可以参考。
我把这个工程的源代码上传到附件中了,欢迎大家下载。
本文出自 “移动开发” 博客,请务必保留此出处http://ikinglai.blog.51cto.com/6220785/1225309
关于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<jni.h>/* Header for class com_example_soundtouchdemo_JNISoundTouch */#ifndef _Included_com_example_soundtouchdemo_JNISoundTouch#define _Included_com_example_soundtouchdemo_JNISoundTouch#ifdef __cplusplusextern"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那个版本是差不多的,大家可以参考。
我把这个工程的源代码上传到附件中了,欢迎大家下载。
本文出自 “移动开发” 博客,请务必保留此出处http://ikinglai.blog.51cto.com/6220785/1225309
相关文章推荐
- iOS下使用SoundTouch实现变声并转为wav格式进行播放(山寨汤姆猫完整版)
- [置顶] Android开发实战使用(VR技术实现360°全景视频播放功能)
- Android图片滚动,加入自动播放功能,使用自定义属性实现,霸气十足!
- Android中使用自定义的VideoController和MediaPlayer实现视频的窗口和全屏播放
- Android使用Service实现简单音乐播放实例
- Android 使用VideoView播放MP4的简单实现
- Android移动开发-使用VideoView播放视频的实现
- Android 使用 FFmpeg (二)——视屏流播放简单实现
- Android 学习笔记之SurfaceView的使用+如何实现视频播放...
- android 使用vitamio播放mkv文件实现音轨切换
- android 使用MediaPlayer实现视频播放
- Android使用PowerImageView实现播放强大的ImageView动画效果
- Android音频: 怎样使用AudioTrack播放一个WAV格式文件?
- Android图片滚动,加入自动播放功能,使用自定义属性实现,霸气十足!
- Android开发之使用VideoView实现视频的横屏播放、去除边框
- Android音频: 如何使用AudioTrack播放一个WAV格式文件?
- 【Android】使用Gallery组件实现图片播放预览
- 详解Android App中使用VideoView来实现视频播放的方法
- Android使用AIDL方式实现播放音乐案例
- Android视频播放框架Vitamio集成及使用MediaPlayer+SurfaceView、VideoView+MediaController实现播放网络视频