diff --git a/.vscode/settings.json b/.vscode/settings.json index f50da7f..001a902 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -23,6 +23,7 @@ "compare": "cpp", "span": "cpp", "random": "cpp", - "list": "cpp" + "list": "cpp", + "limits": "cpp" } } \ No newline at end of file diff --git a/src/commands.h b/src/commands.h index 76a5afe..6d70ae1 100644 --- a/src/commands.h +++ b/src/commands.h @@ -293,6 +293,7 @@ void parse_command(uint32_t t_now_ms, command com) { } else{ toggle_standby(); + broadcast("reload_config"); } } else if (fastcmp(substring, "button_hold")) { diff --git a/src/configuration.h b/src/configuration.h index 46db8c9..bd3e6d9 100644 --- a/src/configuration.h +++ b/src/configuration.h @@ -35,25 +35,25 @@ void load_config(){ configuration.softness = preferences.getFloat("softness", 0.25); // Color - configuration.color = preferences.getFloat("color", 0.90); + configuration.color = preferences.getFloat("color", 0.33); // Color Range configuration.color_range = preferences.getFloat("color_range", 0.00); // Warmth - configuration.warmth = preferences.getFloat("warmth", 0.50); + configuration.warmth = preferences.getFloat("warmth", 0.00); // Speed - configuration.speed = preferences.getFloat("speed", 0.75); + configuration.speed = preferences.getFloat("speed", 0.50); // Saturation - configuration.saturation = preferences.getFloat("saturation", 1.00); + configuration.saturation = preferences.getFloat("saturation", 0.75); // Background configuration.background = preferences.getFloat("background", 0.00); // Current Mode - configuration.current_mode = preferences.getInt("current_mode", 0); + configuration.current_mode = preferences.getInt("current_mode", 1); // Mirror Mode configuration.mirror_mode = preferences.getBool("mirror_mode", true); @@ -64,9 +64,6 @@ void load_config(){ // Temporal Dithering configuration.temporal_dithering = preferences.getBool("dithering", true); - // VU Floor - configuration.vu_floor = preferences.getFloat("vu_floor", 0.00); - // Reverse Color configuration.reverse_color_range = preferences.getBool("reverse_color", false); @@ -166,7 +163,6 @@ bool save_config() { preferences.putBool("mirror_mode", configuration.mirror_mode); preferences.putBool("screensaver", configuration.screensaver); preferences.putBool("dithering", configuration.temporal_dithering); - preferences.putFloat("vu_floor", configuration.vu_floor); preferences.putBool("reverse_color", configuration.reverse_color_range); preferences.putBool("auto_color", configuration.auto_color_cycle); diff --git a/src/goertzel.h b/src/goertzel.h index 02f319c..c7cf7f2 100644 --- a/src/goertzel.h +++ b/src/goertzel.h @@ -357,7 +357,6 @@ void calculate_magnitudes() { void start_noise_calibration() { Serial.println("Starting noise cal..."); memset(noise_spectrum, 0, sizeof(float) * NUM_FREQS); - configuration.vu_floor = 0.0; noise_calibration_wait_frames_remaining = NOISE_CALIBRATION_WAIT_FRAMES; noise_calibration_active_frames_remaining = NOISE_CALIBRATION_ACTIVE_FRAMES; } diff --git a/src/gpu_core.h b/src/gpu_core.h index fd8e740..781c9a8 100644 --- a/src/gpu_core.h +++ b/src/gpu_core.h @@ -60,11 +60,11 @@ void run_gpu() { apply_brightness(); - render_touches(); // (touch.h) - if( EMOTISCOPE_ACTIVE == false ){ run_standby(); } + + render_touches(); // (touch.h) // This value decays itself non linearly toward zero all the time, // *really* slowing down the LPF when it's set to 1.0. @@ -84,12 +84,12 @@ void run_gpu() { // The DMA and SIMD-style stuff inside the ESP32-S3 is some pretty crazy shit. float lpf_cutoff_frequency = 0.5 + (1.0-(sqrt(configuration.softness)))*14.5; lpf_cutoff_frequency = lpf_cutoff_frequency * (1.0 - lpf_drag) + 0.5 * lpf_drag; - //apply_image_lpf(lpf_cutoff_frequency); + apply_image_lpf(lpf_cutoff_frequency); //clip_leds(); apply_tonemapping(); - apply_frame_blending( configuration.softness ); + //apply_frame_blending( configuration.softness ); //apply_phosphor_decay( configuration.softness ); // Apply an incandescent LUT to reduce harsh blue tones @@ -98,6 +98,8 @@ void run_gpu() { // Apply white balance multiply_CRGBF_array_by_LUT( leds, WHITE_BALANCE, NUM_LEDS ); + apply_master_brightness(); + apply_gamma_correction(); // Quantize the image buffer with dithering, diff --git a/src/leds.h b/src/leds.h index 69dbfb4..f414bb5 100644 --- a/src/leds.h +++ b/src/leds.h @@ -448,7 +448,7 @@ void update_auto_color(){ static float color_momentum = 0.0; if(configuration.auto_color_cycle == true){ - float novelty = novelty_curve_normalized[NOVELTY_HISTORY_LENGTH - 1]; + float novelty = novelty_curve_normalized[NOVELTY_HISTORY_LENGTH - 1] * 0.75; novelty = novelty*novelty*novelty*novelty*novelty*novelty; color_momentum *= 0.95; @@ -462,6 +462,17 @@ void update_auto_color(){ }, __func__ ); } +void apply_master_brightness(){ + static float master_brightness = 0.0; + if(t_now_ms >= 1000){ + if(master_brightness < 1.0){ + master_brightness += 0.001; + } + } + + scale_CRGBF_array_by_constant(leds, clip_float(master_brightness), NUM_LEDS); +} + void apply_phosphor_decay(float strength){ static CRGBF phosphor_decay[NUM_LEDS]; static bool first_run = true; diff --git a/src/light_modes/active/analog.h b/src/light_modes/active/analog.h index 8e68409..3d6b007 100644 --- a/src/light_modes/active/analog.h +++ b/src/light_modes/active/analog.h @@ -13,7 +13,7 @@ void draw_analog(){ ); if(configuration.mirror_mode == true){ - dot_pos = 0.1 + dot_pos * 0.9; + dot_pos = 0.05 + dot_pos * 0.95; draw_dot(leds, NUM_RESERVED_DOTS+0, dot_color, 0.5 + (dot_pos* 0.5), 1.0); draw_dot(leds, NUM_RESERVED_DOTS+1, dot_color, 0.5 + (dot_pos*-0.5), 1.0); diff --git a/src/light_modes/active/hype.h b/src/light_modes/active/hype.h index 5ce392a..654e7be 100644 --- a/src/light_modes/active/hype.h +++ b/src/light_modes/active/hype.h @@ -20,10 +20,10 @@ void draw_hype() { float beat_color_odd = beat_sum_odd; float beat_color_even = beat_sum_even; - beat_sum_odd = sqrt(beat_color_odd); - beat_sum_even = sqrt(beat_color_even); + beat_sum_odd = sqrt(sqrt(beat_color_odd)); + beat_sum_even = sqrt(sqrt(beat_color_even)); - float strength = sqrt(sqrt(tempo_confidence)); + float strength = sqrt(tempo_confidence); CRGBF dot_color_odd = hsv( get_color_range_hue(beat_color_odd), @@ -41,11 +41,11 @@ void draw_hype() { beat_sum_even *= 0.5; } - draw_dot(leds, NUM_RESERVED_DOTS + 0, dot_color_odd, 1.0-beat_sum_odd, 0.1 + 0.9*strength); - draw_dot(leds, NUM_RESERVED_DOTS + 1, dot_color_even, 1.0-beat_sum_even, 0.1 + 0.9*strength); + draw_dot(leds, NUM_RESERVED_DOTS + 0, dot_color_odd, 1.0-beat_sum_odd, 0.1 + 0.8*strength); + draw_dot(leds, NUM_RESERVED_DOTS + 1, dot_color_even, 1.0-beat_sum_even, 0.1 + 0.8*strength); if(configuration.mirror_mode == true){ - draw_dot(leds, NUM_RESERVED_DOTS + 2, dot_color_odd, beat_sum_odd, 0.1 + 0.9*strength); - draw_dot(leds, NUM_RESERVED_DOTS + 3, dot_color_even, beat_sum_even, 0.1 + 0.9*strength); + draw_dot(leds, NUM_RESERVED_DOTS + 2, dot_color_odd, beat_sum_odd, 0.1 + 0.8*strength); + draw_dot(leds, NUM_RESERVED_DOTS + 3, dot_color_even, beat_sum_even, 0.1 + 0.8*strength); } } \ No newline at end of file diff --git a/src/light_modes/active/metronome.h b/src/light_modes/active/metronome.h index bdd180d..6cec9df 100644 --- a/src/light_modes/active/metronome.h +++ b/src/light_modes/active/metronome.h @@ -23,7 +23,7 @@ void draw_metronome() { metronome_width = 1.0; } - float dot_pos = clip_float( sine * (0.5*(sqrt(sqrt(contribution))) * metronome_width) + 0.5 ); + float dot_pos = clip_float( sine * (0.5*(sqrt((contribution))) * metronome_width) + 0.5 ); float opacity = clip_float(contribution*2.0); diff --git a/src/system.h b/src/system.h index 4b4d65e..1eeda51 100644 --- a/src/system.h +++ b/src/system.h @@ -89,6 +89,7 @@ void init_system() { extern void init_touch(); extern void init_noise_samples(); extern void init_floating_point_lookups(); + extern void init_vu(); init_hardware_version_pins(); // (hardware_version.h) init_serial(921600); // (system.h) @@ -106,6 +107,7 @@ void init_system() { init_noise_samples(); // (utilities.h) init_floating_point_lookups(); // (utilities.h) init_boot_button(); // (system.h) + init_vu(); // (vu.h) // Load sliders load_sliders_relevant_to_mode(configuration.current_mode); diff --git a/src/tempo.h b/src/tempo.h index 017fa72..4c39ac9 100644 --- a/src/tempo.h +++ b/src/tempo.h @@ -177,7 +177,7 @@ float calculate_magnitude_of_tempo(uint16_t tempo_bin) { float scale = (0.6 * progress) + 0.4; - normalized_magnitude *= scale; + //normalized_magnitude *= scale; }, __func__ ); return normalized_magnitude; diff --git a/src/touch.h b/src/touch.h index acb79f6..c78dc72 100644 --- a/src/touch.h +++ b/src/touch.h @@ -62,7 +62,7 @@ void read_touch(){ touch_readings[t] = touch_readings[t] * 0.9 + raw_touch_value * 0.1; // Smooth the input } - if(t_now_ms < 5000){ + if(t_now_ms < 2500){ for(uint8_t t = 0; t < 3; t++){ for(uint8_t i = 0; i < 50; i++){ touch_pins[t].touch_history[i] = touch_readings[t]; @@ -70,7 +70,7 @@ void read_touch(){ } } - if (t_now_ms - last_touch_read_time >= 100) { + if (t_now_ms - last_touch_read_time >= 50) { for(uint8_t t = 0; t < 3; t++){ if(touch_pins[t].touch_active == false){ touch_pins[t].touch_history[touch_history_index] = touch_readings[t]; @@ -140,6 +140,7 @@ void read_touch(){ } else if(touch_pins[t].pin == TOUCH_CENTER_PIN){ toggle_standby(); + broadcast("reload_config"); } else if(touch_pins[t].pin == TOUCH_RIGHT_PIN){ // nothing @@ -170,6 +171,7 @@ void read_touch(){ } else{ toggle_standby(); + broadcast("reload_config"); } } else if(touch_pins[t].pin == TOUCH_RIGHT_PIN){ @@ -205,15 +207,12 @@ void read_touch(){ save_config_delayed(); } else if(touch_pins[TOUCH_LEFT].touch_active == true && touch_pins[TOUCH_RIGHT].touch_active == true){ // both hands held - //printf("BOTH HANDS HELD\n"); - /* - configuration.mirror_mode = !configuration.mirror_mode; - - touch_pins[TOUCH_LEFT].hold_active = true; - touch_pins[TOUCH_RIGHT].hold_active = true; - touch_pins[TOUCH_LEFT].touch_active = false; - touch_pins[TOUCH_RIGHT].touch_active = false; - */ + static uint32_t last_mirror_mode_toggle = 0; + if(t_now_ms - last_mirror_mode_toggle >= 1000){ + configuration.mirror_mode = !configuration.mirror_mode; + save_config_delayed(); + last_mirror_mode_toggle = t_now_ms; + } } } diff --git a/src/types.h b/src/types.h index d2bf53c..7972983 100644 --- a/src/types.h +++ b/src/types.h @@ -159,7 +159,6 @@ struct config { bool mirror_mode; bool screensaver; bool temporal_dithering; - float vu_floor; bool auto_color_cycle; bool reverse_color_range; }; \ No newline at end of file diff --git a/src/vu.h b/src/vu.h index f8b207b..56c965b 100644 --- a/src/vu.h +++ b/src/vu.h @@ -1,16 +1,31 @@ -#define NUM_VU_AVERAGE_SAMPLES 4 +#define NUM_VU_LOG_SAMPLES 20 +#define NUM_VU_SMOOTH_SAMPLES 6 -extern uint32_t noise_calibration_active_frames_remaining; +float vu_log[NUM_VU_LOG_SAMPLES] = { 0 }; +uint16_t vu_log_index = 0; + +float vu_smooth[NUM_VU_SMOOTH_SAMPLES] = { 0 }; +uint16_t vu_smooth_index = 0; volatile float vu_level_raw = 0.0; volatile float vu_level = 0.0; volatile float vu_max = 0.0; +volatile float vu_floor = 0.0; + +uint32_t last_vu_log = 0; -float vu_history[NUM_VU_AVERAGE_SAMPLES] = { 0 }; -uint8_t vu_history_index = 0; +void init_vu(){ + for(uint8_t i = 0; i < NUM_VU_LOG_SAMPLES; i++){ + vu_log[i] = 0.0; + } + for(uint8_t i = 0; i < NUM_VU_SMOOTH_SAMPLES; i++){ + vu_smooth[i] = 0.0; + } +} void run_vu(){ profile_function([&]() { + // CALCULATE AMPLITUDE ------------------------------------------------ static float max_amplitude_cap = 0.0000001; float* samples = &sample_history[(SAMPLE_HISTORY_LENGTH-1) - CHUNK_SIZE]; @@ -19,17 +34,26 @@ void run_vu(){ float sample = samples[i]; float sample_abs = fabs(sample); - max_amplitude_now = max(max_amplitude_now, sample_abs*sample_abs); + max_amplitude_now = fmaxf(max_amplitude_now, sample_abs*sample_abs); } max_amplitude_now = clip_float(max_amplitude_now); - if(noise_calibration_active_frames_remaining == 0){ // Not calibrating - max_amplitude_now = clip_float(max_amplitude_now - configuration.vu_floor); - } - else{ // Calibrating - configuration.vu_floor = max(float(configuration.vu_floor), float(max_amplitude_now)); + // LOG AMPLITUDE FOR NOISE REMOVAL ------------------------------------ + if(t_now_ms - last_vu_log >= 1000){ + last_vu_log = t_now_ms; + vu_log[vu_log_index] = max_amplitude_now; + vu_log_index = (vu_log_index + 1) % NUM_VU_LOG_SAMPLES; + + float vu_sum = 0.0; + for(uint8_t i = 0; i < NUM_VU_LOG_SAMPLES; i++){ + vu_sum += vu_log[i]; + } + vu_floor = vu_sum / NUM_VU_LOG_SAMPLES; } + // SCALE OUTPUT ------------------------------------------------------- + max_amplitude_now = fmaxf(max_amplitude_now - vu_floor, 0.0f); + if(max_amplitude_now > max_amplitude_cap){ float distance = max_amplitude_now - max_amplitude_cap; max_amplitude_cap += (distance * 0.1); @@ -40,26 +64,25 @@ void run_vu(){ } max_amplitude_cap = clip_float(max_amplitude_cap); - if(max_amplitude_cap < 0.00005){ - max_amplitude_cap = 0.00005; + if(max_amplitude_cap < 0.000025){ + max_amplitude_cap = 0.000025; } - float auto_scale = 1.0 / max(max_amplitude_cap, 0.00001f); + float auto_scale = 1.0 / fmaxf(max_amplitude_cap, 0.00001f); vu_level_raw = clip_float(max_amplitude_now*auto_scale); - float mix_speed = 0.95; - vu_level = vu_level_raw * mix_speed + vu_level*(1.0-mix_speed); - - vu_history[vu_history_index] = vu_level; - vu_history_index = (vu_history_index + 1) % NUM_VU_AVERAGE_SAMPLES; + // SMOOTHING --------------------------------------------------------- + vu_smooth[vu_smooth_index] = vu_level_raw; + vu_smooth_index = (vu_smooth_index + 1) % NUM_VU_SMOOTH_SAMPLES; float vu_sum = 0.0; - for(uint8_t i = 0; i < NUM_VU_AVERAGE_SAMPLES; i++){ - vu_sum += vu_history[i]; + for(uint8_t i = 0; i < NUM_VU_SMOOTH_SAMPLES; i++){ + vu_sum += vu_smooth[i]; } - vu_level = vu_sum / NUM_VU_AVERAGE_SAMPLES; + vu_level = vu_sum / NUM_VU_SMOOTH_SAMPLES; + // MAX VALUE --------------------------------------------------------- vu_max = max(vu_max, vu_level); }, __func__); } \ No newline at end of file