commit df2fe15d3fad657871fea75d1e4aead4c9c8b1cc
parent a98751f74deeb268d62fe35a8a81706d38632057
Author: gstraube <gstraube@mailbox.org>
Date: Thu, 25 May 2017 14:30:02 +0200
Find closest note to detected pitch and calculate the deviation in cent
Diffstat:
6 files changed, 114 insertions(+), 2 deletions(-)
diff --git a/app/build.gradle b/app/build.gradle
@@ -27,4 +27,5 @@ dependencies {
compile 'com.android.support:appcompat-v7:25.3.1'
compile 'com.android.support.constraint:constraint-layout:1.0.2'
testCompile 'junit:junit:4.12'
+ testCompile group: 'org.hamcrest', name: 'hamcrest-all', version: '1.3'
}
diff --git a/app/src/main/java/com/github/cythara/MainActivity.java b/app/src/main/java/com/github/cythara/MainActivity.java
@@ -8,6 +8,7 @@ import android.util.Log;
import android.widget.TextView;
import java.lang.ref.WeakReference;
+import java.util.Locale;
import be.tarsos.dsp.AudioDispatcher;
import be.tarsos.dsp.AudioEvent;
@@ -56,13 +57,19 @@ public class MainActivity extends AppCompatActivity {
float pitch = pitchDetectionResult.getPitch();
if (pitch != -1) {
+ PitchDifference pitchDifference = PitchComparator.retrieveNote(pitch);
+
+ String msg = String.format(Locale.US, "Closest: %s Diff: %f Freq: %f",
+ pitchDifference.closest.getGuitarString(),
+ pitchDifference.deviation, pitch);
+
Message message = new Message();
Bundle bundle = new Bundle();
- bundle.putString("pitch", String.valueOf(pitch));
+ bundle.putString("pitch", msg);
message.setData(bundle);
activity.updateHandler.sendMessage(message);
- Log.d("com.github.cythara", "Pitch: " + pitch);
+ Log.d("com.github.cythara", msg);
}
}
};
diff --git a/app/src/main/java/com/github/cythara/Note.java b/app/src/main/java/com/github/cythara/Note.java
@@ -0,0 +1,27 @@
+package com.github.cythara;
+
+enum Note {
+
+ E2("E", 82.41f),
+ A2("A", 110f),
+ D3("D", 146.83f),
+ G3("G", 196f),
+ B3("B", 246.94f),
+ E4("E", 329.63f);
+
+ private final String guitarString;
+ private final float frequency;
+
+ Note(String guitarString, float frequency) {
+ this.guitarString = guitarString;
+ this.frequency = frequency;
+ }
+
+ public String getGuitarString() {
+ return guitarString;
+ }
+
+ public float getFrequency() {
+ return frequency;
+ }
+}
diff --git a/app/src/main/java/com/github/cythara/PitchComparator.java b/app/src/main/java/com/github/cythara/PitchComparator.java
@@ -0,0 +1,34 @@
+package com.github.cythara;
+
+import java.util.Arrays;
+import java.util.Comparator;
+
+class PitchComparator {
+
+ static PitchDifference retrieveNote(float pitch) {
+ Note[] notes = Note.values();
+ Arrays.sort(notes, new Comparator<Note>() {
+ @Override
+ public int compare(Note o1, Note o2) {
+ return Float.compare(o1.getFrequency(), o2.getFrequency());
+ }
+ });
+
+ double minCentDifference = Float.POSITIVE_INFINITY;
+ Note closest = Note.E4;
+ for (Note note : notes) {
+ double centDifference = 1200d * log2(note.getFrequency() / pitch);
+
+ if (Math.abs(centDifference) < Math.abs(minCentDifference)) {
+ minCentDifference = centDifference;
+ closest = note;
+ }
+ }
+
+ return new PitchDifference(closest, minCentDifference);
+ }
+
+ private static double log2(float number) {
+ return Math.log(number) / Math.log(2);
+ }
+}
diff --git a/app/src/main/java/com/github/cythara/PitchDifference.java b/app/src/main/java/com/github/cythara/PitchDifference.java
@@ -0,0 +1,12 @@
+package com.github.cythara;
+
+class PitchDifference {
+
+ final Note closest;
+ final double deviation;
+
+ PitchDifference(Note closest, double deviation) {
+ this.closest = closest;
+ this.deviation = deviation;
+ }
+}
diff --git a/app/src/test/java/com/github/cythara/PitchComparatorTest.java b/app/src/test/java/com/github/cythara/PitchComparatorTest.java
@@ -0,0 +1,31 @@
+package com.github.cythara;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import static com.github.cythara.Note.*;
+import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.Matchers.closeTo;
+
+public class PitchComparatorTest {
+
+ @Test
+ public void retrieveNote() throws Exception {
+ Map<Float, PitchDifference> expectations = new HashMap<>();
+ expectations.put(20f, new PitchDifference(E2, 2451.3832933619105));
+ expectations.put(500f, new PitchDifference(E4, -721.296654095616));
+ expectations.put(197.67f, new PitchDifference(G3, -14.688333908767358));
+ expectations.put(128.415f, new PitchDifference(D3, 231.99964198777823));
+
+ for (Float pitch : expectations.keySet()) {
+ PitchDifference actual = PitchComparator.retrieveNote(pitch);
+ PitchDifference expected = expectations.get(pitch);
+
+ Assert.assertThat(actual.closest, is(expected.closest));
+ Assert.assertThat(actual.deviation, closeTo(expected.deviation, 0.001));
+ }
+ }
+}