4ef5cb95ea8e — Chris Cannam 6 years ago
Merge from the JNI branch
A => Android.mk +48 -0
@@ 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)
+

          
A => Makefile +14 -0
@@ 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

          
M README.txt +1 -1
@@ 6,7 6,7 @@ A simple beats-per-minute estimator for 
 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.
 

          
A => com/breakfastquay/minibpm/MiniBpm.java +118 -0
@@ 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");
+    }
+};
+
+
+    

          
M src/MiniBpm.cpp +5 -4
@@ 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 @@ public:
 	m_lfdf.clear();
 	m_hfdf.clear();
 	m_rms.clear();
+        m_candidates.clear();
 	m_partialFill = 0;
     }
 

          
@@ 506,13 507,13 @@ public:
 
 	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);

          
M src/MiniBpm.h +11 -3
@@ 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 @@ public:
     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 @@ public:
      * 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 @@ public:
      * 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<double> getTempoCandidates() const;
 

          
A => src/jni/MiniBpmJNI.cpp +205 -0
@@ 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 <jni.h>
+
+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<double> 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();
+}

          
M tests/TestMiniBpm.cpp +1 -1
@@ 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

          
M vamp/MiniBpmVamp.cpp +1 -1
@@ 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

          
M vamp/MiniBpmVamp.h +1 -1
@@ 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

          
M vamp/libmain.cpp +1 -1
@@ 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