summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKaiStevenson <kai@kaistevenson.com>2022-11-22 16:09:08 -0800
committerKaiStevenson <kai@kaistevenson.com>2022-11-22 16:09:08 -0800
commitffc0d35dfd2b0d565989c34fb25eb43146df975b (patch)
tree80558d89a17df9f70fc59f3c17b947d99172aeb3
-rw-r--r--Program.cs106
-rw-r--r--polyrhythm-identifier.csproj9
2 files changed, 115 insertions, 0 deletions
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 @@
+<Project Sdk="Microsoft.NET.Sdk">
+
+ <PropertyGroup>
+ <OutputType>Exe</OutputType>
+ <TargetFramework>net5.0</TargetFramework>
+ <RootNamespace>polyrhythm_identifier</RootNamespace>
+ </PropertyGroup>
+
+</Project>