# HG changeset patch # User Chris Cannam # Date 1401450723 -3600 # Fri May 30 12:52:03 2014 +0100 # Node ID 4ef5cb95ea8e930f0170ac040529fcbd1218a64c # Parent cb5ecba01ea0557c0ee1e2c17723e24fce5b2387 # Parent 5ed32cdbacc72fdb4fa828e862a57614d1e50d19 Merge from the JNI branch diff --git a/Android.mk b/Android.mk new file mode 100644 --- /dev/null +++ b/Android.mk @@ -0,0 +1,48 @@ + +LOCAL_MODULE := minibpm +LOCAL_MODULE_FILENAME := libminibpm-jni + +LOCAL_C_INCLUDES := $(LOCAL_PATH)/minibpm/src + +MINIBPM_PATH := minibpm +MINIBPM_SRC_PATH := $(MINIBPM_PATH)/src + +MINIBPM_JNI_FILES := \ + $(MINIBPM_SRC_PATH)/jni/MiniBpmJNI.cpp + +MINIBPM_SRC_FILES := \ + $(MINIBPM_SRC_PATH)/MiniBpm.cpp + +LOCAL_SRC_FILES += \ + $(MINIBPM_JNI_FILES) \ + $(MINIBPM_SRC_FILES) + +LOCAL_CFLAGS_DEBUG := \ + -g \ + -mfloat-abi=softfp + +LOCAL_CFLAGS_RELEASE := \ + -O3 \ + -mfpu=neon \ + -mfloat-abi=softfp \ + -ffast-math \ + -ftree-vectorize \ + -ftree-vect-loop-version \ + -freciprocal-math \ + -fsingle-precision-constant \ + -D__ARM_ARCH_7__ + +LOCAL_CFLAGS := \ + -Wall \ + -I$(MINIBPM_SRC_PATH) \ + -DNO_EXCEPTIONS \ + $(LOCAL_CFLAGS_RELEASE) + +LOCAL_LDLIBS += -llog + +TARGET_ARCH_ABI := armeabi-v7a +LOCAL_ARM_MODE := arm +LOCAL_ARM_NEON := true + +include $(BUILD_SHARED_LIBRARY) + diff --git a/Makefile b/Makefile new file mode 100644 --- /dev/null +++ b/Makefile @@ -0,0 +1,14 @@ + +CXXFLAGS := -O3 -Wall + +default: libminibpm.a test + +libminibpm.a: src/MiniBpm.o + ar cr $@ $^ + ranlib $@ + +test: + $(MAKE) -C tests + +clean: + rm -f libminibpm.a src/MiniBpm.o diff --git a/README.txt b/README.txt --- a/README.txt +++ b/README.txt @@ -6,7 +6,7 @@ implemented in C++ with few external dependencies. Written by Chris Cannam, chris.cannam@breakfastquay.com. -Copyright 2012 Particular Programs Ltd. +Copyright 2012-2014 Particular Programs Ltd. See http://breakfastquay.com/minibpm/ for more information. diff --git a/com/breakfastquay/minibpm/MiniBpm.java b/com/breakfastquay/minibpm/MiniBpm.java new file mode 100644 --- /dev/null +++ b/com/breakfastquay/minibpm/MiniBpm.java @@ -0,0 +1,118 @@ +/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ + +/* + MiniBPM + A fixed-tempo BPM estimator for music audio + Copyright 2012-2014 Particular Programs Ltd. + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. See the file + COPYING included with this distribution for more information. + + Alternatively, if you have a valid commercial licence for MiniBPM + obtained by agreement with the copyright holders, you may + redistribute and/or modify it under the terms described in that + licence. + + If you wish to distribute code using MiniBPM under terms other + than those of the GNU General Public License, you must obtain a + valid commercial licence before doing so. +*/ + +package com.breakfastquay.minibpm; + +/** + * A fixed-tempo BPM estimator. This Java wrapper currently provides + * only the single-shot API from the C++ library. + * + * A single channel of audio only may be supplied (multi-channel is + * not supported). To process multi-channel audio, average the + * channels first. + */ +public class MiniBpm +{ + public MiniBpm(int sampleRate) { + handle = 0; + initialise(sampleRate); + } + + /** + * Call this to dispose of the tempo estimator after use. You must + * do so after you have finished using this estimator object, as + * the Java garbage collector cannot collect the native object. + */ + public native void dispose(); + + /** + * Set the range of valid tempi. The default is 55-190bpm. + */ + public native void setBPMRange(double min, double max); + + /** + * Get the current minimum supported tempo. + */ + public native double getBPMMin(); + + /** + * Get the current maximum supported tempo. + */ + public native double getBPMMax(); + + /** + * Set the number of beats per bar, if known. If unknown, leave at + * the default (which is 4). + */ + public native void setBeatsPerBar(int bpb); + + /** + * Get the current number of beats per bar. (This simply returns + * the value set by setBeatsPerBar, which is a hint to the tempo + * estimator: the estimator does not estimate meter.) + */ + public native int getBeatsPerBar(); + + /** + * Return the estimated tempo in bpm of the music audio in the + * given sequence of samples. nsamples contains the number of + * samples, starting at the given offset in the given input + * array. If the tempo cannot be estimated because the clip is too + * short, return 0. + * + * The input samples are expected to be in the range [-1,1]. + * + * If you wish to subsequently obtain a tempo estimate of a + * different clip, you must call reset() before calling this + * function again. (This is so that the data that is available to + * be returned from getTempoCandidates can be cleared.) + */ + public native double estimateTempoOfSamples(float[] input, + int offset, int nsamples); + + /** + * Return all candidate tempi for the last tempo estimation that + * was carried out, in order of likelihood (best first). The value + * returned from estimateTempoOfSamples will therefore be the + * first in the returned sequence. Calling reset() will clear this + * information. + */ + public native double[] getTempoCandidates(); + + /** + * Prepare the object to carry out another tempo estimation on a + * new audio clip. You can either call this between uses, or + * simply destroy this object and construct a new one. + */ + public native void reset(); + + private native void initialise(int sampleRate); + private long handle; + + static { + System.loadLibrary("minibpm-jni"); + } +}; + + + diff --git a/src/MiniBpm.cpp b/src/MiniBpm.cpp --- a/src/MiniBpm.cpp +++ b/src/MiniBpm.cpp @@ -3,7 +3,7 @@ /* MiniBPM A fixed-tempo BPM estimator for music audio - Copyright 2012 Particular Programs Ltd. + Copyright 2012-2014 Particular Programs Ltd. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as @@ -461,6 +461,7 @@ m_lfdf.clear(); m_hfdf.clear(); m_rms.clear(); + m_candidates.clear(); m_partialFill = 0; } @@ -506,13 +507,13 @@ zero(acf, acfLength); - acfcalc.acfUnityNormalised(m_lfdf.data(), temp); + acfcalc.acfUnityNormalised(&m_lfdf[0], temp); for (int i = 0; i < acfLength; ++i) acf[i] += temp[i]; - acfcalc.acfUnityNormalised(m_hfdf.data(), temp); + acfcalc.acfUnityNormalised(&m_hfdf[0], temp); for (int i = 0; i < acfLength; ++i) acf[i] += temp[i] * 0.5; - acfcalc.acfUnityNormalised(m_rms.data(), temp); + acfcalc.acfUnityNormalised(&m_rms[0], temp); for (int i = 0; i < acfLength; ++i) acf[i] += temp[i] * 0.1; int minlag = Autocorrelation::bpmToLag(m_maxbpm, hopsPerSec); diff --git a/src/MiniBpm.h b/src/MiniBpm.h --- a/src/MiniBpm.h +++ b/src/MiniBpm.h @@ -3,7 +3,7 @@ /* MiniBPM A fixed-tempo BPM estimator for music audio - Copyright 2012 Particular Programs Ltd. + Copyright 2012-2014 Particular Programs Ltd. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as @@ -70,7 +70,9 @@ void setBeatsPerBar(int bpb); /** - * Get the current number of beats per bar. + * Get the current number of beats per bar. (This simply returns + * the value set by setBeatsPerBar, which is a hint to the tempo + * estimator: the estimator does not estimate meter.) */ int getBeatsPerBar() const; @@ -84,6 +86,11 @@ * calls followed by an estimateTempo() call. Do not call both * process() and estimateTempoOfSamples() on the same estimator * object. + * + * If you wish to subsequently obtain a tempo estimate of a + * different clip, you must call reset() before calling this + * function again. (This is so that the data that is available to + * be returned from getTempoCandidates can be cleared.) */ double estimateTempoOfSamples(const float *samples, int nsamples); @@ -106,7 +113,8 @@ * Return all candidate tempi for the last tempo estimation that * was carried out, in order of likelihood (best first). The value * returned from estimateTempo or estimateTempoOfSamples will - * therefore be the first in the returned sequence. + * therefore be the first in the returned sequence. Calling + * reset() will clear this information. */ std::vector getTempoCandidates() const; diff --git a/src/jni/MiniBpmJNI.cpp b/src/jni/MiniBpmJNI.cpp new file mode 100644 --- /dev/null +++ b/src/jni/MiniBpmJNI.cpp @@ -0,0 +1,205 @@ +/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ + +/* + MiniBPM + A fixed-tempo BPM estimator for music audio + Copyright 2012-2014 Particular Programs Ltd. + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. See the file + COPYING included with this distribution for more information. + + Alternatively, if you have a valid commercial licence for MiniBPM + obtained by agreement with the copyright holders, you may + redistribute and/or modify it under the terms described in that + licence. + + If you wish to distribute code using MiniBPM under terms other + than those of the GNU General Public License, you must obtain a + valid commercial licence before doing so. +*/ + +#include "MiniBpm.h" + +#include + +using namespace breakfastquay; + +extern "C" { +/* + * Class: com_breakfastquay_minibpm_MiniBpm + * Method: dispose + * Signature: ()V + */ +JNIEXPORT void JNICALL Java_com_breakfastquay_minibpm_MiniBpm_dispose + (JNIEnv *, jobject); + +/* + * Class: com_breakfastquay_minibpm_MiniBpm + * Method: setBPMRange + * Signature: (DD)V + */ +JNIEXPORT void JNICALL Java_com_breakfastquay_minibpm_MiniBpm_setBPMRange + (JNIEnv *, jobject, jdouble, jdouble); + +/* + * Class: com_breakfastquay_minibpm_MiniBpm + * Method: getBPMMin + * Signature: ()D + */ +JNIEXPORT jdouble JNICALL Java_com_breakfastquay_minibpm_MiniBpm_getBPMMin + (JNIEnv *, jobject); + +/* + * Class: com_breakfastquay_minibpm_MiniBpm + * Method: getBPMMax + * Signature: ()D + */ +JNIEXPORT jdouble JNICALL Java_com_breakfastquay_minibpm_MiniBpm_getBPMMax + (JNIEnv *, jobject); + +/* + * Class: com_breakfastquay_minibpm_MiniBpm + * Method: setBeatsPerBar + * Signature: (I)V + */ +JNIEXPORT void JNICALL Java_com_breakfastquay_minibpm_MiniBpm_setBeatsPerBar + (JNIEnv *, jobject, jint); + +/* + * Class: com_breakfastquay_minibpm_MiniBpm + * Method: getBeatsPerBar + * Signature: ()I + */ +JNIEXPORT jint JNICALL Java_com_breakfastquay_minibpm_MiniBpm_getBeatsPerBar + (JNIEnv *, jobject); + +/* + * Class: com_breakfastquay_minibpm_MiniBpm + * Method: estimateTempoOfSamples + * Signature: ([FII)D + */ +JNIEXPORT jdouble JNICALL Java_com_breakfastquay_minibpm_MiniBpm_estimateTempoOfSamples + (JNIEnv *, jobject, jfloatArray, jint, jint); + +/* + * Class: com_breakfastquay_minibpm_MiniBpm + * Method: getTempoCandidates + * Signature: ()[D + */ +JNIEXPORT jdoubleArray JNICALL Java_com_breakfastquay_minibpm_MiniBpm_getTempoCandidates + (JNIEnv *, jobject); + +/* + * Class: com_breakfastquay_minibpm_MiniBpm + * Method: reset + * Signature: ()V + */ +JNIEXPORT void JNICALL Java_com_breakfastquay_minibpm_MiniBpm_reset + (JNIEnv *, jobject); + +/* + * Class: com_breakfastquay_minibpm_MiniBpm + * Method: initialise + * Signature: (I)V + */ +JNIEXPORT void JNICALL Java_com_breakfastquay_minibpm_MiniBpm_initialise + (JNIEnv *, jobject, jint); + + +} + +MiniBPM * +getMiniBPM(JNIEnv *env, jobject obj) +{ + jclass c = env->GetObjectClass(obj); + jfieldID fid = env->GetFieldID(c, "handle", "J"); + jlong handle = env->GetLongField(obj, fid); + return (MiniBPM *)handle; +} + +void +setMiniBPM(JNIEnv *env, jobject obj, MiniBPM *minibpm) +{ + jclass c = env->GetObjectClass(obj); + jfieldID fid = env->GetFieldID(c, "handle", "J"); + jlong handle = (jlong)minibpm; + env->SetLongField(obj, fid, handle); +} + +JNIEXPORT void JNICALL +Java_com_breakfastquay_minibpm_MiniBpm_initialise(JNIEnv *env, jobject obj, jint sampleRate) +{ + setMiniBPM(env, obj, new MiniBPM(sampleRate)); +} + +JNIEXPORT void JNICALL +Java_com_breakfastquay_minibpm_MiniBpm_dispose(JNIEnv *env, jobject obj) +{ + delete getMiniBPM(env, obj); + setMiniBPM(env, obj, 0); +} + +JNIEXPORT void JNICALL +Java_com_breakfastquay_minibpm_MiniBpm_setBPMRange(JNIEnv *env, jobject obj, jdouble min, jdouble max) +{ + getMiniBPM(env, obj)->setBPMRange(min, max); +} + +JNIEXPORT jdouble JNICALL +Java_com_breakfastquay_minibpm_MiniBpm_getBPMMin(JNIEnv *env, jobject obj) +{ + double min, max; + getMiniBPM(env, obj)->getBPMRange(min, max); + return min; +} + +JNIEXPORT jdouble JNICALL +Java_com_breakfastquay_minibpm_MiniBpm_getBPMMax(JNIEnv *env, jobject obj) +{ + double min, max; + getMiniBPM(env, obj)->getBPMRange(min, max); + return max; +} + +JNIEXPORT void JNICALL +Java_com_breakfastquay_minibpm_MiniBpm_setBeatsPerBar(JNIEnv *env, jobject obj, jint bpb) +{ + getMiniBPM(env, obj)->setBeatsPerBar(bpb); +} + +JNIEXPORT jint JNICALL +Java_com_breakfastquay_minibpm_MiniBpm_getBeatsPerBar(JNIEnv *env, jobject obj) +{ + return getMiniBPM(env, obj)->getBeatsPerBar(); +} + +JNIEXPORT jdouble JNICALL +Java_com_breakfastquay_minibpm_MiniBpm_estimateTempoOfSamples(JNIEnv *env, jobject obj, jfloatArray data, jint offset, jint n) +{ + float *arr = env->GetFloatArrayElements(data, 0); + + double estimate = + getMiniBPM(env, obj)->estimateTempoOfSamples(arr + offset, n); + + env->ReleaseFloatArrayElements(data, arr, 0); + + return estimate; +} + +JNIEXPORT jdoubleArray JNICALL +Java_com_breakfastquay_minibpm_MiniBpm_getTempoCandidates(JNIEnv *env, jobject obj) +{ + std::vector candidates = getMiniBPM(env, obj)->getTempoCandidates(); + jdoubleArray out = env->NewDoubleArray(candidates.size()); + env->SetDoubleArrayRegion(out, 0, candidates.size(), &candidates[0]); + return out; +} + +JNIEXPORT void JNICALL +Java_com_breakfastquay_minibpm_MiniBpm_reset(JNIEnv *env, jobject obj) +{ + getMiniBPM(env, obj)->reset(); +} diff --git a/tests/TestMiniBpm.cpp b/tests/TestMiniBpm.cpp --- a/tests/TestMiniBpm.cpp +++ b/tests/TestMiniBpm.cpp @@ -3,7 +3,7 @@ /* MiniBPM A fixed-tempo BPM estimator for music audio - Copyright 2012 Particular Programs Ltd. + Copyright 2012-2014 Particular Programs Ltd. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as diff --git a/vamp/MiniBpmVamp.cpp b/vamp/MiniBpmVamp.cpp --- a/vamp/MiniBpmVamp.cpp +++ b/vamp/MiniBpmVamp.cpp @@ -3,7 +3,7 @@ /* MiniBPM A fixed-tempo BPM estimator for music audio - Copyright 2012 Particular Programs Ltd. + Copyright 2012-2014 Particular Programs Ltd. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as diff --git a/vamp/MiniBpmVamp.h b/vamp/MiniBpmVamp.h --- a/vamp/MiniBpmVamp.h +++ b/vamp/MiniBpmVamp.h @@ -3,7 +3,7 @@ /* MiniBPM A fixed-tempo BPM estimator for music audio - Copyright 2012 Particular Programs Ltd. + Copyright 2012-2014 Particular Programs Ltd. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as diff --git a/vamp/libmain.cpp b/vamp/libmain.cpp --- a/vamp/libmain.cpp +++ b/vamp/libmain.cpp @@ -3,7 +3,7 @@ /* MiniBPM A fixed-tempo BPM estimator for music audio - Copyright 2012 Particular Programs Ltd. + Copyright 2012-2014 Particular Programs Ltd. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as