3483e8218958 — Chris Cannam 10 years ago
Make the app do something! (If not very much)
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);
     }
 }