From ffc0d35dfd2b0d565989c34fb25eb43146df975b Mon Sep 17 00:00:00 2001 From: KaiStevenson Date: Tue, 22 Nov 2022 16:09:08 -0800 Subject: init --- Program.cs | 106 +++++++++++++++++++++++++++++++++++++++++++ polyrhythm-identifier.csproj | 9 ++++ 2 files changed, 115 insertions(+) create mode 100644 Program.cs create mode 100644 polyrhythm-identifier.csproj diff --git a/Program.cs b/Program.cs new file mode 100644 index 0000000..ea47f54 --- /dev/null +++ b/Program.cs @@ -0,0 +1,106 @@ +using System; +using System.Linq; +using System.Threading.Tasks; + +namespace polyrhythm_identifier +{ + internal class Program + { + private const int sampleCount = 10; + private const float accuracySensitivity = 2; + + private static readonly (float f, string l)[] rhythms = new[] + { + (0.5f, "1/2"), + (0.667f, "2/3"), + (0.75f, "3/4"), + (1f, "1/1"), + (1.33f, "4/3"), + (1.5f, "3/2"), + (2f, "2/1") + }; + static void Main(string[] args) + { + var p = new Program(); + p.Loop(); + } + public void Loop() + { + Console.WriteLine("Use F & J to play a poly-rhythm"); + var l_Samples = new DateTime[sampleCount]; + int l_LastSampleIndex = 0; + var r_Samples = new DateTime[sampleCount]; + int r_LastSampleIndex = 0; + while (true) + { + var k = Console.ReadKey(true); + if (k.Key == ConsoleKey.F) + { + l_Samples[l_LastSampleIndex] = DateTime.Now; + l_LastSampleIndex = (l_LastSampleIndex + 1) % sampleCount; + } + else if (k.Key == ConsoleKey.J) + { + r_Samples[r_LastSampleIndex] = DateTime.Now; + r_LastSampleIndex = (r_LastSampleIndex + 1) % sampleCount; + } + Console.Clear(); + //L + var l_sTime = l_Samples[l_LastSampleIndex]; + var l_eTime = l_Samples[(l_LastSampleIndex + (sampleCount - 1)) % sampleCount]; + var l_span = (float)(l_eTime - l_sTime).TotalSeconds; + float l_bpmF = ((sampleCount - 1) / l_span) * 60; + int l_bpmI = (int)Math.Round(l_bpmF); + Console.WriteLine(String.Format("L: {0} bpm", l_bpmI)); + //R + var r_sTime = r_Samples[r_LastSampleIndex]; + var r_eTime = r_Samples[(r_LastSampleIndex + (sampleCount - 1)) % sampleCount]; + var r_span = (float)(r_eTime - r_sTime).TotalSeconds; + float r_bpmF = ((sampleCount - 1) / r_span) * 60; + int r_bpmI = (int)Math.Round(r_bpmF); + Console.WriteLine(String.Format("R: {0} bpm", r_bpmI)); + //fraction + if (l_bpmI > 0 && r_bpmI > 0) + { + var rawF = (float)l_bpmI / (float)r_bpmF; + var f = Math.Round(rawF, 2); + Console.WriteLine("F: " + f); + var nearestFractionMatch = rhythms.OrderBy(x => Math.Abs((long)x.f - rawF)).First(); + var nearest = rhythms.Select(p => new { Value = p, Difference = Math.Abs(p.f - rawF) }) + .OrderBy(p => p.Difference) + .First().Value; + + Console.WriteLine("Nearest match: " + nearest.l); + } + //accuracy + float[] l_intervals = new float[sampleCount - 1]; + float[] r_intervals = new float[sampleCount - 1]; + for (int i = 0; i < sampleCount - 1; i++) + { + var l_i = (i + l_LastSampleIndex) % sampleCount; + var r_i = (i + r_LastSampleIndex) % sampleCount; + l_intervals[i] = (float)(l_Samples[(l_i + 1) % sampleCount] - l_Samples[l_i]).TotalSeconds; + r_intervals[i] = (float)(r_Samples[(r_i + 1) % sampleCount] - r_Samples[r_i]).TotalSeconds; + } + var l_perfectInterval = l_span / (sampleCount - 1); + var l_worst_interval = l_intervals.Select(p => new { Value = p, Difference = Math.Abs(p - l_perfectInterval) }) + .OrderBy(p => p.Difference) + .Last().Value; + var l_diff = Math.Abs(l_perfectInterval - l_worst_interval); + var l_diffR = (l_perfectInterval - (l_diff * accuracySensitivity)) / l_perfectInterval; + var l_accuracy = l_diffR; + var r_perfectInterval = r_span / (sampleCount - 1); + var r_worst_interval = r_intervals.Select(p => new { Value = p, Difference = Math.Abs(p - r_perfectInterval) }) + .OrderBy(p => p.Difference) + .Last().Value; + var r_diff = Math.Abs(r_perfectInterval - r_worst_interval); + var r_diffR = (r_perfectInterval - (r_diff * accuracySensitivity)) / r_perfectInterval; + var r_accuracy = r_diffR; + + Console.WriteLine(String.Format("L accuracy: {0}%", Math.Clamp(Math.Round(l_accuracy * 100), 0, 120))); + Console.WriteLine(String.Format("R accuracy: {0}%", Math.Clamp(Math.Round(r_accuracy * 100), 0, 120))); + Console.WriteLine(String.Format("Total accuracy: {0}%", Math.Clamp(Math.Round(((r_accuracy + l_accuracy) / 2) * 100), 0, 120))); + } + } + } +} diff --git a/polyrhythm-identifier.csproj b/polyrhythm-identifier.csproj new file mode 100644 index 0000000..9d4f48b --- /dev/null +++ b/polyrhythm-identifier.csproj @@ -0,0 +1,9 @@ + + + + Exe + net5.0 + polyrhythm_identifier + + + -- cgit v1.3.1