/
4_Full_Audio_Analyzer_HSVGradient.ino
203 lines (173 loc) · 5.32 KB
/
4_Full_Audio_Analyzer_HSVGradient.ino
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
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
#include <OctoWS2811.h>
#include <Audio.h>
#include <Wire.h>
#include <SD.h>
#include <SPI.h>
#include <SerialFlash.h>
// The display size
const unsigned int matrix_width = 15;
const unsigned int matrix_height = 8;
// These parameters adjust the vertical thresholds
const float maxLevel = 0.1; // 1.0 = max, lower is more "sensitive"
const float dynamicRange = 40.0; // total range to display, in decibels
const float linearBlend = 0.3; // useful range is 0 to 0.7
// OctoWS2811 objects
const int ledsPerPin = matrix_width * matrix_height / 8;
DMAMEM int displayMemory[ledsPerPin*6];
int drawingMemory[ledsPerPin*6];
const int config = WS2811_GRB | WS2811_800kHz;
//const int config = WS2811_GRB;
OctoWS2811 leds(ledsPerPin, displayMemory, drawingMemory, config);
// Audio library objects
AudioInputUSB usb1;
AudioAnalyzeFFT1024 fft;
AudioOutputI2S i2s1;
//AudioOutputUSB usb2;
//AudioConnection patchCord1(usb1, 0, usb2, 0);
AudioConnection patchCord2(usb1, 0, i2s1, 0);
AudioConnection patchCord4(usb1, 1, fft, 0);
// This array holds the volume level (0 to 1.0) for each
// vertical pixel to turn on. Computed in setup() using
// the 3 parameters above.
float thresholdVertical[matrix_height];
// This array specifies how many of the FFT frequency bin
// to use for each horizontal pixel. Because humans hear
// in octaves and FFT bins are linear, the low frequencies
// use a small number of bins, higher frequencies use more.
int frequencyBinsHorizontal[matrix_width] =
//{1,1,2,3,4,6,9,12,18,26,37,53,76,108,155};
{1,1,1,1,1,1,2,2,3,3,4,5,7,9,12};
// SUB BASS: 0-50
// BASS: 50-225
// MIDRANGE: 225-1600
// HIGHMIDS: 1800-5000
// HIGHFREQ: 5000-20000
// EACH BIN: 300
void setup() {
AudioMemory(20);
computeVerticalLevels();
leds.begin();
leds.show();
}
// Converts matrix display coordinates to
// index numbers OctoWS2811 requires.
unsigned int xy(unsigned int x, unsigned int y) {
return y * matrix_width + x;}
int yCurr[ matrix_width ];
int yTarg[ matrix_width ];
float level[ matrix_width ];
int Iter = 0;
byte r;
byte g;
byte b;
int COLOR[matrix_height] = {0xFFFFFF,0xFFFFFF,0xFFFFFF,0xFFFFFF,0xFFFFFF,0xFFFFFF,0xFFFFFF,0xFFFFFF};
int COLOR_CHANGE = 1;
int HUE = 0;
int BLANK = 0x000000;
void loop() {
unsigned long currentMillis = millis();
unsigned int x, y, freqBin;
// Cycle color if button pushed
if (COLOR_CHANGE == 1) {
//HUE = HUE + 60;
for (int i=0; i < matrix_height; i++) {
HSV_to_RGB(HUE+10*i, 100, 30, &r,&g,&b);
COLOR[i] = r*pow(16,4)+g*pow(16,2)+b;}
//COLOR_CHANGE = 0;
}
if (fft.available()) {
freqBin = 0;
// Determine a new destination height
for (x=0; x < matrix_width; x++) {
yCurr[x] = yTarg[x];
yTarg[x] = 0;
level[x] = fft.read(freqBin, freqBin + frequencyBinsHorizontal[x] - 1);
for (y=0; y < matrix_height; y++) {
if (level[x] > thresholdVertical[y]) {
yTarg[x] = yTarg[x] + 1;}
freqBin = freqBin + frequencyBinsHorizontal[x];
if (abs(yTarg[x] - yCurr[x]) > Iter) {
Iter = abs(yTarg[x] - yCurr[x]); }
}
}
// Make sure all below are lit
// Slide until yCurr = yTarg
for (int i=0; i < Iter; i++) {
for (x=0; x < matrix_width; x++) {
if (yCurr[x] < yTarg[x]) {
yCurr[x] = yCurr[x] + 1;
leds.setPixel(xy(x, yCurr[x]-1), COLOR[yCurr[x]-1]);}
else if (yCurr[x] > yTarg[x]) {
leds.setPixel(xy(x, yCurr[x]-1), BLANK);
yCurr[x] = yCurr[x] - 1;}
}
leds.show();
delay(10);
}
}
//leds.show();
}
// Vertical Level Computation Function
void computeVerticalLevels() {
unsigned int y;
float n, logLevel, linearLevel;
for (y=0; y < matrix_height; y++) {
n = (float)y / (float)(matrix_height - 1);
logLevel = pow10f(n * -1.0 * (dynamicRange / 20.0));
linearLevel = 1.0 - n;
linearLevel = linearLevel * linearBlend;
logLevel = logLevel * (1.0 - linearBlend);
thresholdVertical[y] = (logLevel + linearLevel) * maxLevel;
}
}
// HSV Function
void HSV_to_RGB(float h, float s, float v, byte *r, byte *g, byte *b){
int i;
float f,p,q,t;
h = max(0.0, min(360.0, h));
s = max(0.0, min(100.0, s));
v = max(0.0, min(100.0, v));
s /= 100;
v /= 100;
if(s == 0) {
// Achromatic (grey)
*r = *g = *b = round(v*255);
return;}
h /= 60; // sector 0 to 5
i = floor(h);
f = h - i; // factorial part of h
p = v * (1 - s);
q = v * (1 - s * f);
t = v * (1 - s * (1 - f));
switch(i) {
case 0:
*r = round(255*v);
*g = round(255*t);
*b = round(255*p);
break;
case 1:
*r = round(255*q);
*g = round(255*v);
*b = round(255*p);
break;
case 2:
*r = round(255*p);
*g = round(255*v);
*b = round(255*t);
break;
case 3:
*r = round(255*p);
*g = round(255*q);
*b = round(255*v);
break;
case 4:
*r = round(255*t);
*g = round(255*p);
*b = round(255*v);
break;
default: // case 5:
*r = round(255*v);
*g = round(255*p);
*b = round(255*q);
}
}