M .hgsubstate +1 -1
@@ 1,1 1,1 @@
-54b259b2941f80d9de812b22f19071e6761c2042 jni/minibpm
+5ed32cdbacc72fdb4fa828e862a57614d1e50d19 jni/minibpm
M README +4 -0
@@ 13,6 13,10 @@ Android-specific Java code here is absol
should refer to in your own work. This is simply an illustration of
the use of the JNI (Android NDK) interface.
+In fact, the application has an empty user interface: all it does is
+estimate the tempo of an audio file that is bundled into the app as a
+resource, and send the results to the logger (use adb logcat to view).
+
To build:
$ ndk-build
M res/layout/main.xml +0 -10
@@ 3,14 3,4 @@
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal">
- <Button
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="@string/button_play"
- android:onClick="play"/>
- <Button
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="@string/button_stop"
- android:onClick="stop"/>
</LinearLayout>
M res/raw/a.raw +0 -0
M res/values/strings.xml +0 -2
@@ 1,6 1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="app_name">MiniBpmExampleActivity</string>
- <string name="button_play">Play</string>
- <string name="button_stop">Stop</string>
</resources>
M src/com/breakfastquay/minibpm/MiniBpm.java +3 -1
@@ 67,7 67,9 @@ public class MiniBpm
public native 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.)
*/
public native int getBeatsPerBar();
M src/com/breakfastquay/minibpmexample/MiniBpmExampleActivity.java +44 -0
@@ 12,6 12,8 @@ import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.io.IOException;
+import java.nio.ByteBuffer;
+
import com.breakfastquay.minibpm.MiniBpm;
public class MiniBpmExampleActivity extends Activity
@@ 22,6 24,48 @@ public class MiniBpmExampleActivity exte
{
super.onCreate(savedInstanceState);
+ try {
+ InputStream audio = getResources().openRawResource(R.raw.a);
+ ByteArrayOutputStream ostr = new ByteArrayOutputStream(audio.available());
+ byte[] buf = new byte[1024];
+ int r;
+ while ((r = audio.read(buf)) >= 0) ostr.write(buf, 0, r);
+ byte[] raw = ostr.toByteArray();
+
+ // We assume raw is interleaved 2-channel 16-bit PCM
+ int channels = 2;
+ int frames = raw.length / (channels * 2);
+ int rate = 44100;
+
+ float[] insamples = new float[frames];
+
+ ByteBuffer bb = ByteBuffer.wrap(raw).order(null);
+
+ for (int i = 0; i < frames; ++i) {
+ for (int c = 0; c < channels; ++c) {
+ short val = bb.getShort();
+ insamples[i] += ((float)val / 32768) / channels;
+ }
+ }
+
+ long start = System.currentTimeMillis();
+
+ MiniBpm mbpm = new MiniBpm(rate);
+ double tempo = mbpm.estimateTempoOfSamples(insamples, 0, frames);
+ double[] candidates = mbpm.getTempoCandidates();
+ mbpm.dispose();
+
+ long end = System.currentTimeMillis();
+ double t = (double)(end - start) / 1000;
+
+ Log.d("MiniBpm", "estimated tempo of " + frames + "-frame stereo track as " + tempo + "bpm in " + t + "s (processing " + (frames / t) + "fps)");
+ Log.d("MiniBpm", "candidate tempi follow...");
+ for (int i = 0; i < candidates.length; ++i) {
+ Log.d("MiniBpm", "candidate " + i + ": " + candidates[i]);
+ }
+
+ } catch (IOException e) { }
+
setContentView(R.layout.main);
}
}