This repository was archived by the owner on Jun 4, 2020. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathProgram.cs
More file actions
156 lines (143 loc) · 5.74 KB
/
Copy pathProgram.cs
File metadata and controls
156 lines (143 loc) · 5.74 KB
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
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Numerics;
using System.Text;
using System.Threading.Tasks;
using CSCore;
using CSCore.Codecs.WAV;
using CSCore.SoundIn;
using CSCore.Streams;
using CSCore.DSP;
using MathNet.Numerics.IntegralTransforms;
namespace ArduinoControl
{
class Program
{
const int BufferSamples = 4096;
const int SampleSize = 4; // 2 shorts per sample
const int BufferSize = BufferSamples * SampleSize;
const int BRIGHTNESS_FACTOR = 1;
static void Main(string[] args)
{
short[] buffer = new short[BufferSamples];
int readOffset = 0;
ArduinoControl arduino = new ArduinoControl("COM3");
using (WasapiCapture capture = new WasapiCapture(false, CSCore.CoreAudioAPI.AudioClientShareMode.Exclusive, 0))
{
capture.Initialize();
//setup an eventhandler to receive the recorded data
capture.DataAvailable += (s, e) =>
{
int nNewSamples = e.ByteCount / SampleSize;
int nSamplesToFill = Math.Min(nNewSamples, BufferSamples - readOffset);
//save the recorded audio
WriteSamples(e.Data, 0, buffer, readOffset, nSamplesToFill);
WriteSamples(e.Data, nSamplesToFill * SampleSize, buffer, 0, nNewSamples - nSamplesToFill);
// update circular buffer position
int newReadOffset = (readOffset + nNewSamples) % BufferSamples;
// update arduino twice per buffer fill
if ((newReadOffset >= BufferSamples / 2 && readOffset < BufferSamples / 2) ||
(newReadOffset < BufferSamples / 2 && readOffset >= BufferSamples / 2))
{
// Compute Fourier transform of most recent window of audio data
Complex[] fourierSamples = (buffer.Skip(newReadOffset).Concat(buffer.Take(newReadOffset))).Select(x => new Complex(x, 0)).ToArray();
Fourier.Radix2Forward(fourierSamples, FourierOptions.Default);
// TODO: do stuff
Visualize(fourierSamples, arduino);
}
readOffset = newReadOffset;
};
// Record & update arduino until keypress
capture.Start();
Console.ReadKey();
capture.Stop();
}
}
static void WriteSamples(byte[] sampleBytes, int sourceOffset, short[] dest, int destOffset, int samplesToWrite)
{
for (var i = 0; i < samplesToWrite; i++)
{
dest[destOffset + i] = BitConverter.ToInt16(sampleBytes, sourceOffset + i * 2 * sizeof(short)); // skip every other sample
}
}
static void Visualize(Complex[] fourierOutput, ArduinoControl arduino)
{
Color vizColor = new Color(0, 0, 0);
for (int i = 0; i < fourierOutput.Length / 2; i++) // divide by 2 b/c nyquist limit
{
float freq = 44100 * i / fourierOutput.Length;
float power = (float)(fourierOutput[i].Real * fourierOutput[i].Real + fourierOutput[i].Imaginary * fourierOutput[i].Imaginary);
float note = midiNote(freq);
float h = note / 12;
float s = 1;
float l = power * BRIGHTNESS_FACTOR / (32768 * fourierOutput.Length);
AddColors(vizColor, ColorFromHSL(h, s, l));
}
arduino.sendCommand(String.Format("r:{0} g:{1} b:{2}", vizColor.r, vizColor.g, vizColor.b));
}
static float midiNote(float frequency)
{
return (float)(69 + 12 * Math.Log(frequency / 440, 2));
}
struct Color
{
public float r, g, b;
public Color(float r, float g, float b)
{
this.r = r;
this.g = g;
this.b = b;
}
}
static Color ColorFromHSL(float h, float s, float l)
{
float r = 0, g = 0, b = 0;
float temp1, temp2;
if (l == 0)
{
r = g = b = 0;
}
else
{
if (s == 0)
{
r = g = b = l;
}
else
{
temp2 = ((l <= 0.5f) ? l * (1.0f + s) : l + s - (l * s));
temp1 = 2.0f * l - temp2;
float[] t3 = new float[] { h + 1.0f / 3.0f, h, h - 1.0f / 3.0f };
float[] clr = new float[] { 0, 0, 0 };
for (int i = 0; i < 3; i++)
{
if (t3[i] < 0)
t3[i] += 1.0f;
if (t3[i] > 1)
t3[i] -= 1.0f;
if (6.0f * t3[i] < 1.0f)
clr[i] = temp1 + (temp2 - temp1) * t3[i] * 6.0f;
else if (2.0f * t3[i] < 1.0f)
clr[i] = temp2;
else if (3.0f * t3[i] < 2.0f)
clr[i] = (temp1 + (temp2 - temp1) * ((2.0f / 3.0f) - t3[i]) * 6.0f);
else
clr[i] = temp1;
}
r = clr[0];
g = clr[1];
b = clr[2];
}
}
return new Color(255 * r, 255 * g, 255 * b);
}
static void AddColors(Color a, Color b)
{
a.r += b.r;
a.g += b.g;
a.b += b.b;
}
}
}