plectrum

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README | LICENSE

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:
Mapp/build.gradle | 1+
Mapp/src/main/java/com/github/cythara/MainActivity.java | 11+++++++++--
Aapp/src/main/java/com/github/cythara/Note.java | 27+++++++++++++++++++++++++++
Aapp/src/main/java/com/github/cythara/PitchComparator.java | 34++++++++++++++++++++++++++++++++++
Aapp/src/main/java/com/github/cythara/PitchDifference.java | 12++++++++++++
Aapp/src/test/java/com/github/cythara/PitchComparatorTest.java | 31+++++++++++++++++++++++++++++++
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)); + } + } +}