前一段时间要做一个自动匹配与跑步节奏相适应的音乐播放器的应用。找了很久发现了十分良心的soundtouch开源库。
这个应用的步频判断部分是使用pedometer开源应用进行提取改造的。具体可以参考我相关的博客。
一、关于SoundTouch开源库
下面为官网,可以进行参考。
http://www.surina.net/soundtouch/index.html
该库主要提供了wav格式的音频处理和节奏检测,包含以下几个功能。
1.重新设定歌曲的bpm改变歌曲速度。
2.改变歌曲的音调二不改变速度。
3.直接加速或者减速使得音调和速度同时改变。
4.检测歌曲的bpm(beat per minute)
网站提供了两种资源的下载,一种是可执行文件soundstrech演示项目,可以使用命令行来运行子,一种是源代码,源码中有一个android的demo,需要先按照其中的readme进行cygwin-ndk编译以后才能生成so库在android上面运行,这是下文讲的重点。
先用可执行文件在命令行下面做了一个测试,发现其准确率和windows下的很准确切快速的mixMeister相当。而且是c/c++库,速度可观。
(之前找到了scala库,使用最高模式准确率达到mixMeister,但是速度感人,一首歌在pc上要1分钟左右能完成检测。感兴趣可以参见https://github.com/mziccard/scala-audio-file)
二、关于JNI编程
该库的文档十分亲民,一个是根目录下的readme,另一个是android-lib下面的readme。后者几乎是一个jni的快速入门。
这个库的主要思想是讲c代码编译成so共享库,然后通过jni的方式在java代码里面调用。工程里面有现成的make文件(配置要编译的文件,生成的参数和目标等等配置),我们只需要直接编译就可以了。
这里简述一下:
1.安装cygwin(一个windows下的linux模拟环境),确保下载了gnu的make.exe。如果忘记了后面用到的时候回提示。
2.配置home路径下的.bash_profile文件。(注意这里要使用vi或者vim进行编辑而不要在window环境中进行编辑,否则换行符无法识别。)把NDK路径加入进“linux”环境变量。
3.进入android-lib下的jni文件夹,发现有两个mk文件和一个cpp。mk文件里面就含有编译的配置信息。cpp是我们的编译目标,里面引用了一些这个文件夹之外的其他目录的库,不只是我们看到的这个。
4.在cygwin下进入这个目录。输入命令行 $NDK/ndk-build 。这里面$NDK的意思就是直接引用之前在.bash_profile里面配置的环境变量。ndk-build是ndk目录下的一个可执行文件。他会自动根据mk文件中的 设置来编译。
5.接着命令行中开始出现编译的过程。会生成arm armv7 等4个平台的so,在jni同级的libs文件夹里面的平台子文件里面。
6.直接在eclipse(或者as,需要进一步设置,因为原工程是按照eclipse配置的)import这个工程。包含so的libs文件夹会被包含进来。这时候连上手机直接运行就可以了。
我们会发现demo只使用了设定pitch和tempo生成新音乐的接口。而没有使用bpm检测的接口。这时候我们可以手动输入路径或者修改代码调用系统文件浏览器选择歌曲进行修改。
系统文件浏览器代码请参考我的文章:
http://blog.csdn.net/wallezhe/article/details/51614985
三、动手创建新的接口
这里面因为我对于jni的掌握还没有足够熟练,所以我注意模仿原来的函数。这里挑几点说一下:
1.参数的个数和函数的形式,使用javah命令的主要目的是获得接口的形式,.h文件在时机编译的时候并没有作用,只要有实现了接口的cpp文件就可以被java调用。如果足够熟练可以直接按照Java_包名_类名_方法名 的形式直接进行编写。而如果使用这种方式要注意参数的个数。无论有无java的实际参数传入,都是要传入c++代码JNIEnv *env, jobject thiz这两种类型的参数。前者是一个作为java类型和c桥梁的一个对象,可以调用其中的一些函数。后者至今没发现什么用处。但是一定要留出其位置。然后才是时机传入的参数。最好使用javah生成以防错误。
2.传入参数的形式。涉及到java类型和c++类型的转换。java传入的String对应的C++应该是jstring类型,而函数里面可能还会使用env->的方法将其转化为constant char*的类型。而float会编程c++里面的jfloat类型。具体请参照规范和手册。
3.返回值的形式要响应地转换回来,尤其是字符串需要调用env的方法进行转换。
4.重新编译一下,以为可能没有ide的提示,所以一些拼写错误或者忘记include的文件,按照cygwin里面的提示补充好就可以了。
5.将生成的新的so文件导入,修改一下android的ui显示,使得返回的float可以显示出来。
下面是我添加过的jni目录下的c++代码,以及java代码。这里面native 的java方法都是private声明然后使用public的驱壳进行调用是个不错的注意,如果出现问题方便进行修改以及一些native方法的组合。
四、效果
每首歌在android上也大概只需要不到8秒就可以识别完毕,同样非常准确。
下面的开发就是写一个数据库保存路径,文件名以及bpm的值。以及一个文件浏览器的添加入口。以及修改根据步频的播放机制就可以了。
五、展望
其实利用这个库可以开发一个一首歌实时根据步频调整播放速度的东西。
当然步频超过某一个范围应该直接滤掉。
1.变生成边播放。
2.播放的过程中以某一项为参照继续生成,其实以原来的文件就可以了。并直接切换。
3.可以实现,怎样调优使之节省资源就是很重要的了。
///
/// Example Interface class for SoundTouch native compilation
///