Skip to content

Commit 5d78897

Browse files
Added "Octave" mode, smoothed spectrogram, created chromagram
1 parent 21699b6 commit 5d78897

17 files changed

+292
-63
lines changed

src/EMOTISCOPE_FIRMWARE.ino

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@
4848
#include "microphone.h" // ........ For gathering audio chunks from the microphone
4949
#include "vu.h" // ................ Tracks music loudness from moment to moment
5050
#include "goertzel.h" // .......... GDFT or God Damn Fast Transform is implemented here
51+
#include "key_detection.h"
5152
#include "tempo.h" // ............. Comupation of (and syncronization) to the music tempo
5253
#include "audio_debug.h" // ....... Print audio data over UART
5354
#include "screensaver.h" // ....... Colorful dots play on screen when no audio is present

src/EMOTISCOPE_FIRMWARE.ino.cpp

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
# 1 "C:\\Users\\conno\\AppData\\Local\\Temp\\tmplnu7fsj8"
2+
#include <Arduino.h>
3+
# 1 "C:/Users/conno/Emotiscope/src/EMOTISCOPE_FIRMWARE.ino"
4+
# 14 "C:/Users/conno/Emotiscope/src/EMOTISCOPE_FIRMWARE.ino"
5+
#define VERSION_MAJOR ( 1 )
6+
#define VERSION_MINOR ( 0 )
7+
#define VERSION_PATCH ( 0 )
8+
9+
10+
11+
12+
13+
14+
#include <PsychicHttp.h>
15+
#include <HTTPClient.h>
16+
#include <ESPmDNS.h>
17+
#include <Ticker.h>
18+
#include <WiFi.h>
19+
#include <esp_dsp.h>
20+
#include <esp_wifi.h>
21+
22+
23+
#include "secrets.h"
24+
#include "global_defines.h"
25+
#include "types.h"
26+
#include "profiler.h"
27+
#include "sliders.h"
28+
#include "toggles.h"
29+
#include "menu_toggles.h"
30+
#include "filesystem.h"
31+
#include "configuration.h"
32+
#include "utilities.h"
33+
#include "system.h"
34+
#include "touch.h"
35+
#include "indicator.h"
36+
#include "led_driver.h"
37+
#include "leds.h"
38+
#include "ui.h"
39+
#include "microphone.h"
40+
#include "vu.h"
41+
#include "goertzel.h"
42+
#include "key_detection.h"
43+
#include "tempo.h"
44+
#include "audio_debug.h"
45+
#include "screensaver.h"
46+
#include "standby.h"
47+
#include "lightshow_modes.h"
48+
#include "commands.h"
49+
#include "wireless.h"
50+
51+
52+
#include "cpu_core.h"
53+
#include "gpu_core.h"
54+
#include "web_core.h"
55+
56+
57+
#include "notes.h"
58+
59+
60+
#include "secrets.h"
61+
void loop();
62+
void loop_gpu(void *param);
63+
void setup();
64+
#line 75 "C:/Users/conno/Emotiscope/src/EMOTISCOPE_FIRMWARE.ino"
65+
void loop() {
66+
run_cpu();
67+
run_web();
68+
}
69+
70+
71+
void loop_gpu(void *param) {
72+
for (;;) {
73+
run_gpu();
74+
}
75+
}
76+
77+
78+
void setup() {
79+
80+
init_system();
81+
82+
83+
(void)xTaskCreatePinnedToCore(loop_gpu, "loop_gpu", 8192, NULL, 0, NULL, 0);
84+
}

src/commands.h

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -133,13 +133,13 @@ void parse_command(uint32_t t_now_ms, command com) {
133133

134134
update_ui(UI_NEEDLE_EVENT, configuration.saturation);
135135
}
136-
else if (fastcmp(substring, "base_coat")) {
137-
// Get base_coat value
136+
else if (fastcmp(substring, "background")) {
137+
// Get background value
138138
load_substring_from_split_index(com.command, 2, substring, sizeof(substring));
139139
float setting_value = atof(substring);
140-
configuration.base_coat = setting_value;
140+
configuration.background = setting_value;
141141

142-
update_ui(UI_NEEDLE_EVENT, configuration.base_coat);
142+
update_ui(UI_NEEDLE_EVENT, configuration.background);
143143
}
144144
else if (fastcmp(substring, "bass")) {
145145
// Get bass value

src/configuration.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ config configuration = {
3030
0.00, // hue_range
3131
1.00, // speed
3232
1.00, // saturation
33-
0.00, // base_coat
33+
0.00, // background
3434
0.00, // bass
3535
0, // current_mode
3636
true, // mirror_mode
@@ -106,7 +106,7 @@ void sync_configuration_to_client() {
106106

107107
// base_coat
108108
memset(config_item_buffer, 0, 120);
109-
snprintf(config_item_buffer, 120, "new_config|base_coat|float|%.3f", configuration.base_coat);
109+
snprintf(config_item_buffer, 120, "new_config|background|float|%.3f", configuration.background);
110110
websocket_handler.sendAll(config_item_buffer);
111111

112112
// bass

src/cpu_core.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,11 @@ void run_cpu() {
2727

2828
uint32_t processing_start_us = micros();
2929

30-
// Calculate the magnitude of the currently studied frequency set
30+
// Calculate the magnitudes of the currently studied frequency set
3131
calculate_magnitudes(); // (goertzel.h)
32+
get_chromagram();
33+
34+
run_key_detection();
3235

3336
run_vu();
3437

src/goertzel.h

Lines changed: 45 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,12 @@ uint16_t max_goertzel_block_size = 0;
4242

4343
volatile bool magnitudes_locked = false;
4444

45-
float magnitudes[NUM_FREQS];
45+
float spectrogram[NUM_FREQS];
46+
float chromagram[12];
47+
48+
float spectrogram_smooth[NUM_FREQS] = { 0.0 };
49+
float spectrogram_average[12][NUM_FREQS];
50+
uint8_t spectrogram_average_index = 0;
4651

4752
void init_goertzel(uint16_t frequency_slot, float frequency, float bandwidth) {
4853
frequencies_musical[frequency_slot].block_size = SAMPLE_RATE / (bandwidth);
@@ -99,8 +104,12 @@ void init_goertzel_constants_musical() {
99104
void init_window_lookup() {
100105
for (uint16_t i = 0; i < 2048; i++) {
101106
float ratio = i / 4095.0;
102-
float weighing_factor = 0.54 * (1.0 - cos(TWOPI * ratio));
103-
//float weighing_factor = 0.3635819 - (0.4891775 * (cos(TWOPI * ratio))) + (0.1365995 * (cos(FOURPI * ratio))) - (0.0106411 * (cos(SIXPI * ratio)));
107+
108+
// Hamming window
109+
//float weighing_factor = 0.54 * (1.0 - cos(TWOPI * ratio));
110+
111+
// Blackman-Harris window
112+
float weighing_factor = 0.3635819 - (0.4891775 * (cos(TWOPI * ratio))) + (0.1365995 * (cos(FOURPI * ratio))) - (0.0106411 * (cos(SIXPI * ratio)));
104113

105114
window_lookup[i] = weighing_factor;
106115
window_lookup[4095 - i] = weighing_factor;
@@ -288,7 +297,22 @@ void calculate_magnitudes() {
288297
for (uint16_t i = 0; i < NUM_FREQS; i++) {
289298
// Apply the auto-scaler
290299
frequencies_musical[i].magnitude = clip_float(magnitudes_smooth[i] * autoranger_scale);
291-
magnitudes[i] = frequencies_musical[i].magnitude;
300+
spectrogram[i] = frequencies_musical[i].magnitude;
301+
}
302+
303+
spectrogram_average_index++;
304+
if(spectrogram_average_index >= 12){
305+
spectrogram_average_index = 0;
306+
}
307+
308+
for(uint16_t i = 0; i < NUM_FREQS; i++){
309+
spectrogram_average[spectrogram_average_index][i] = spectrogram[i];
310+
311+
spectrogram_smooth[i] = 0;
312+
for(uint16_t a = 0; a < 12; a++){
313+
spectrogram_smooth[i] += spectrogram_average[a][i];
314+
}
315+
spectrogram_smooth[i] /= 12.0;
292316
}
293317

294318
magnitudes_locked = false;
@@ -299,4 +323,21 @@ void start_noise_calibration() {
299323
Serial.println("Starting noise cal...");
300324
memset(noise_spectrum, 0, sizeof(float) * NUM_FREQS);
301325
noise_calibration_active_frames_remaining = NOISE_CALIBRATION_FRAMES;
326+
}
327+
328+
void get_chromagram(){
329+
memset(chromagram, 0, sizeof(float) * 12);
330+
331+
float max_val = 0.2;
332+
for(uint16_t i = 0; i < 60; i++){
333+
chromagram[ i % 12 ] += (spectrogram_smooth[i] / 5.0);
334+
335+
max_val = max(max_val, chromagram[ i % 12 ]);
336+
}
337+
338+
float auto_scale = 1.0 / max_val;
339+
340+
for(uint16_t i = 0; i < 12; i++){
341+
chromagram[i] *= auto_scale;
342+
}
302343
}

src/gpu_core.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ void run_gpu() {
4444
// If silence is detected, show a blue debug LED
4545
// leds[NUM_LEDS - 1] = add(leds[NUM_LEDS - 1], {0.0, 0.0, silence_level});
4646

47-
apply_base_coat();
47+
apply_background();
4848

4949
// Apply an incandescent LUT to reduce harsh blue tones
5050
apply_incandescent_filter(configuration.incandescent_filter); // (leds.h)
@@ -88,6 +88,9 @@ void run_gpu() {
8888

8989
clip_leds(); // (leds.h)
9090

91+
// Apply white balance
92+
multiply_CRGBF_array_by_LUT( leds, WHITE_BALANCE, NUM_LEDS );
93+
9194
// Quantize the image buffer with dithering,
9295
// output to the 8-bit LED strand
9396
transmit_leds();

src/key_detection.h

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
uint16_t musical_keys[24] = {
2+
// Major scales
3+
0b000010101101, // C major
4+
0b000011010110, // C# major
5+
0b000010110101, // D major
6+
0b000010101011, // Eb major
7+
0b000010110101, // E major
8+
0b000010101101, // F major
9+
0b000011010101, // F# major
10+
0b000010101110, // G major
11+
0b000011010101, // G# major
12+
0b000010101011, // A major
13+
0b000010110110, // Bb major
14+
0b000010101101, // B major
15+
16+
// Minor scales
17+
0b000010110110, // C minor
18+
0b000010101101, // C# minor
19+
0b000011011010, // D minor
20+
0b000010110101, // Eb minor
21+
0b000010101011, // E minor
22+
0b000010110110, // F minor
23+
0b000010101101, // F# minor
24+
0b000011010110, // G minor
25+
0b000010101101, // G# minor
26+
0b000011010101, // A minor
27+
0b000010101110, // Bb minor
28+
0b000011010101 // B minor
29+
};
30+
31+
float scale_confidence[24] = {
32+
0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, // Major
33+
0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 // Minor
34+
};
35+
36+
void run_key_detection(){
37+
float max_confidence = 0.01;
38+
for(uint16_t i = 0; i < 24; i++){
39+
float total_difference = 0.00000001;
40+
41+
for(uint16_t n = 0; n < 12; n++){
42+
float scale_note_value = (float)bitRead( musical_keys[i], n );
43+
float chromagram_value = chromagram[n];
44+
45+
total_difference += fabs(scale_note_value - chromagram_value);
46+
}
47+
48+
scale_confidence[i] = (total_difference / 5.0);
49+
50+
max_confidence = max(max_confidence, scale_confidence[i]);
51+
}
52+
53+
float auto_scale = 1.0 / max_confidence;
54+
55+
for(uint16_t i = 0; i < 24; i++){
56+
float confidence = scale_confidence[i] * auto_scale;
57+
CRGBF color = hsv(0.0, 1.0, confidence*confidence);
58+
59+
//leds[(i << 1) + 0] = color;
60+
//leds[(i << 1) + 1] = color;
61+
}
62+
}

src/leds.h

Lines changed: 19 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@
1818

1919
#define MAX_DOTS 192
2020

21+
CRGBF WHITE_BALANCE = { 1.0, 0.75, 0.60 };
22+
2123
typedef enum {
2224
UI_1, UI_2, UI_3, UI_4, UI_5, UI_6, UI_7, UI_8, UI_9, UI_10,
2325
UI_NEEDLE,
@@ -41,7 +43,7 @@ CRGBF leds_smooth[NUM_LEDS];
4143

4244
float rendered_debug_value = 0.0;
4345

44-
CRGBF incandescent_lookup = {1.0000, 0.4453, 0.1562};
46+
CRGBF incandescent_lookup = {1.0000*1.0000, 0.4453*0.4453, 0.1562*0.1562};
4547

4648
float note_colors[12] = {0.0000, 0.0833, 0.1666, 0.2499, 0.3333, 0.4166,
4749
0.4999, 0.5833, 0.6666, 0.7499, 0.8333, 0.9166};
@@ -471,36 +473,36 @@ void apply_brightness() {
471473
scale_CRGBF_array_by_constant(leds, brightness_val*brightness_val, NUM_LEDS);
472474
}
473475

474-
void apply_base_coat(){
475-
if(configuration.base_coat > 0.01){
476-
float base_coat_level = configuration.base_coat * 0.20; // Max 20% brightness
476+
void apply_background(){
477+
if(configuration.background > 0.01){
478+
float background_level = configuration.background * 0.20; // Max 20% brightness
477479

478480
if(configuration.mirror_mode == false){
479-
float base_coat_inv = (1.0-base_coat_level);
481+
float background_inv = (1.0-background_level);
480482
for(uint16_t i = 0; i < NUM_LEDS; i++){
481483
float progress = float(i) / NUM_LEDS;
482-
CRGBF base_coat_color = hsv(configuration.hue + (configuration.hue_range * progress), configuration.saturation, base_coat_level*base_coat_level);
483-
leds[i].r = leds[i].r * base_coat_inv + base_coat_color.r;
484-
leds[i].g = leds[i].g * base_coat_inv + base_coat_color.g;
485-
leds[i].b = leds[i].b * base_coat_inv + base_coat_color.b;
484+
CRGBF background_color = hsv(configuration.hue + (configuration.hue_range * progress), configuration.saturation, background_level*background_level);
485+
leds[i].r = leds[i].r * background_inv + background_color.r;
486+
leds[i].g = leds[i].g * background_inv + background_color.g;
487+
leds[i].b = leds[i].b * background_inv + background_color.b;
486488
}
487489
}
488490
else{
489-
float base_coat_inv = (1.0-base_coat_level);
491+
float background_inv = (1.0-background_level);
490492
for(uint16_t i = 0; i < (NUM_LEDS >> 1); i++){
491493
float progress = float(i) / (NUM_LEDS>>1);
492-
CRGBF base_coat_color = hsv(configuration.hue + (configuration.hue_range * progress), configuration.saturation, base_coat_level*base_coat_level);
494+
CRGBF background_color = hsv(configuration.hue + (configuration.hue_range * progress), configuration.saturation, background_level*background_level);
493495

494496
int16_t left_index = 63-i;
495497
int16_t right_index = 64+i;
496498

497-
leds[left_index].r = leds[left_index].r * base_coat_inv + base_coat_color.r;
498-
leds[left_index].g = leds[left_index].g * base_coat_inv + base_coat_color.g;
499-
leds[left_index].b = leds[left_index].b * base_coat_inv + base_coat_color.b;
499+
leds[left_index].r = leds[left_index].r * background_inv + background_color.r;
500+
leds[left_index].g = leds[left_index].g * background_inv + background_color.g;
501+
leds[left_index].b = leds[left_index].b * background_inv + background_color.b;
500502

501-
leds[right_index].r = leds[right_index].r * base_coat_inv + base_coat_color.r;
502-
leds[right_index].g = leds[right_index].g * base_coat_inv + base_coat_color.g;
503-
leds[right_index].b = leds[right_index].b * base_coat_inv + base_coat_color.b;
503+
leds[right_index].r = leds[right_index].r * background_inv + background_color.r;
504+
leds[right_index].g = leds[right_index].g * background_inv + background_color.g;
505+
leds[right_index].b = leds[right_index].b * background_inv + background_color.b;
504506
}
505507
}
506508
}

src/lightshow_modes.h

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212

1313
// The individual drawing functions for each mode are defined in these files:
1414
#include "lightshow_modes/spectrum.h"
15+
#include "lightshow_modes/octave.h"
1516
#include "lightshow_modes/metronome.h"
1617
#include "lightshow_modes/spectrum_beat.h"
1718
#include "lightshow_modes/hype.h"
@@ -25,10 +26,11 @@
2526
lightshow_mode lightshow_modes[] = {
2627
{ "Analog", &draw_analog }, // 0
2728
{ "Spectrum", &draw_spectrum }, // 1
28-
{ "Metronome", &draw_metronome }, // 2
29-
{ "Spectrum + Beat", &draw_spectrum_beat }, // 3
30-
{ "Hype", &draw_hype }, // 4
31-
{ "Bloom", &draw_bloom }, // 5
29+
{ "Octave", &draw_octave }, // 2
30+
{ "Metronome", &draw_metronome }, // 3
31+
{ "Spectrum + Beat", &draw_spectrum_beat }, // 4
32+
{ "Hype", &draw_hype }, // 5
33+
{ "Bloom", &draw_bloom }, // 6
3234

3335
//{ "Debug", &draw_debug },
3436
};

0 commit comments

Comments
 (0)