summaryrefslogtreecommitdiff
path: root/Program.cs
blob: ea47f54643380f66a97935ea9ef94ce7116fa029 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
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)));
            }
        }
    }
}