diff --git a/data/js/connection.js b/data/js/connection.js index 48460f2..31f64c8 100644 --- a/data/js/connection.js +++ b/data/js/connection.js @@ -57,12 +57,14 @@ function parse_emotiscope_packet(packet){ let config_length = 4; let num_config_items = num_sections / config_length; + // Iterate through all config items for( let j = 0; j < num_config_items; j++ ){ let item_name = sections[j*config_length+0]; let item_type = sections[j*config_length+1]; let item_ui_type = sections[j*config_length+2]; let item_value = sections[j*config_length+3]; - + + // Convert item value to correct type if(item_type == "i32"){ item_value = parseInt(item_value); } @@ -73,6 +75,7 @@ function parse_emotiscope_packet(packet){ item_value = parseFloat(item_value); } + // Clean up item name for use as a key let item_name_clean = item_name.replace(/\s+/g, '_').toLowerCase(); // if key already exists, update the value @@ -117,7 +120,7 @@ function parse_emotiscope_packet(packet){ "Mirror Mode", "Reverse Color Range", "Auto Color Cycle", - ] + ]; // Spawn all settings not already in the gallery, in the correct order for( let j = 0; j < setting_order.length; j++ ){ @@ -142,11 +145,6 @@ function parse_emotiscope_packet(packet){ } } - // Update all settings in the gallery - for( let j = 0; j < setting_gallery.length; j++ ){ - //setting_gallery[j].draw(); - } - set_ui_locked_state(false); } else if(chunk_name == "modes"){ diff --git a/src/configuration.h b/src/configuration.h index 521855d..e425718 100644 --- a/src/configuration.h +++ b/src/configuration.h @@ -102,7 +102,8 @@ void load_config(){ strcpy(configuration.background.ui_type_string, "s"); configuration.background.type = f32; configuration.background.ui_type = ui_type_slider; - configuration.background.value.f32 = preferences.getFloat(configuration.background.name, 0.25); + configuration.background.value.f32 = 0.0; + //configuration.background.value.f32 = preferences.getFloat(configuration.background.name, 0.25); // Current Mode strcpy(configuration.current_mode.name, "current_mode"); diff --git a/src/goertzel.h b/src/goertzel.h index 9c88c74..152d337 100644 --- a/src/goertzel.h +++ b/src/goertzel.h @@ -26,16 +26,6 @@ Functions related to the computation and post-processing of the Goertzel Algorit const float notes[] = { 55.0, 56.635235, 58.27047, 60.00294, 61.73541, 63.5709, 65.40639, 67.351025, 69.29566, 71.355925, 73.41619, 75.59897, 77.78175, 80.09432, 82.40689, 84.856975, 87.30706, 89.902835, 92.49861, 95.248735, 97.99886, 100.91253, 103.8262, 106.9131, 110.0, 113.27045, 116.5409, 120.00585, 123.4708, 127.1418, 130.8128, 134.70205, 138.5913, 142.71185, 146.8324, 151.19795, 155.5635, 160.18865, 164.8138, 169.71395, 174.6141, 179.80565, 184.9972, 190.49745, 195.9977, 201.825, 207.6523, 213.82615, 220.0, 226.54095, 233.0819, 240.0118, 246.9417, 254.28365, 261.6256, 269.4041, 277.1826, 285.4237, 293.6648, 302.3959, 311.127, 320.3773, 329.6276, 339.4279, 349.2282, 359.6113, 369.9944, 380.9949, 391.9954, 403.65005, 415.3047, 427.65235, 440.0, 453.0819, 466.1638, 480.02355, 493.8833, 508.5672, 523.2511, 538.8082, 554.3653, 570.8474, 587.3295, 604.79175, 622.254, 640.75455, 659.2551, 678.8558, 698.4565, 719.22265, 739.9888, 761.98985, 783.9909, 807.30015, 830.6094, 855.3047, 880.0, 906.16375, 932.3275, 960.04705, 987.7666, 1017.1343, 1046.502, 1077.6165, 1108.731, 1141.695, 1174.659, 1209.5835, 1244.508, 1281.509, 1318.51, 1357.7115, 1396.913, 1438.4455, 1479.978, 1523.98, 1567.982, 1614.6005, 1661.219, 1710.6095, 1760.0, 1812.3275, 1864.655, 1920.094, 1975.533, 2034.269, 2093.005, 2155.233, 2217.461, 2283.3895, 2349.318, 2419.167, 2489.016, 2563.018, 2637.02, 2715.4225, 2793.825, 2876.8905, 2959.956, 3047.96, 3135.964, 3229.2005, 3322.437, 3421.2185, 3520.0, 3624.655, 3729.31, 3840.1875, 3951.065, 4068.537, 4186.009, 4310.4655, 4434.922, 4566.779, 4698.636, 4838.334, 4978.032, 5126.0365, 5274.041, 5430.8465, 5587.652, 5753.7815, 5919.911, 6095.919, 6271.927, 6458.401, 6644.875, 6842.4375, 7040.0, 7249.31, 7458.62, 7680.375, 7902.13, 8137.074, 8372.018, 8620.931, 8869.844, 9133.558, 9397.272, 9676.668, 9956.064, 10252.072, 10548.08, 10861.69, 11175.3, 11507.56, 11839.82, 12191.835, 12543.85, 12916.8, 13289.75, 13684.875, 14080.0, 14498.62, 14917.24, 15360.75, 15804.26, 16274.145, 16744.03, 17241.855, 17739.68, 18267.11, 18794.54, 19353.36, 19912.18, 20504.17, 21096.16, 21723.38, 22350.6, 23015.12, 23679.64, 24383.67, 25087.7, 25833.6, 26579.5, 27369.75, 28160.0, 28997.24, 29834.48, 30721.5, 31608.52, 32548.295, 33488.07, 34483.72, 35479.37, 36534.225, 37589.08, 38706.665, 39824.25, 41008.285, 42192.32, 43446.76, 44701.2, 46030.24, 47359.28, 48767.34, 50175.4, 51667.2}; -float full_spectrum_frequencies[64] = { - 50.0, 150.79, 251.59, 352.38, 453.17, 553.97, 654.76, 755.56, - 856.35, 957.14, 1057.94, 1158.73, 1259.52, 1360.32, 1461.11, 1561.90, - 1662.70, 1763.49, 1864.29, 1965.08, 2065.87, 2166.67, 2267.46, 2368.25, - 2469.05, 2569.84, 2670.63, 2771.43, 2872.22, 2973.02, 3073.81, 3174.60, - 3275.40, 3376.19, 3476.98, 3577.78, 3678.57, 3779.37, 3880.16, 3980.95, - 4081.75, 4182.54, 4283.33, 4384.13, 4484.92, 4585.71, 4686.51, 4787.30, - 4888.10, 4988.89, 5089.68, 5190.48, 5291.27, 5392.06, 5492.86, 5593.65, - 5694.44, 5795.24, 5896.03, 5996.83, 6097.62, 6198.41, 6299.21, 6400.0}; - float window_lookup[4096]; uint32_t noise_calibration_wait_frames_remaining = 0; @@ -54,9 +44,24 @@ float spectrogram_smooth[NUM_FREQS] = { 0.0 }; float spectrogram_average[NUM_SPECTROGRAM_AVERAGE_SAMPLES][NUM_FREQS]; uint8_t spectrogram_average_index = 0; +float a_weighting_lut[NUM_FREQS] = { 0.0 }; + +float calc_a_weighting( float frequency ) { + float f2 = frequency*frequency; + + return 1.5 * 1.2588966 * 148840000 * f2*f2 / + ((f2 + 424.36) * sqrt((f2 + 11599.29) * (f2 + 544496.41)) * (f2 + 148840000)); +} + +void init_a_weighting_lut(){ + for(uint16_t i = 0; i < NUM_FREQS; i++){ + a_weighting_lut[i] = calc_a_weighting( frequencies_musical[i].target_freq ) * 0.5 + 0.5; + } +} + void init_goertzel(uint16_t frequency_slot, float frequency, float bandwidth) { // Calculate the block size based on the desired bandwidth - frequencies_musical[frequency_slot].block_size = SAMPLE_RATE / (bandwidth); + frequencies_musical[frequency_slot].block_size = (SAMPLE_RATE*0.5) / (bandwidth); // Adjust the block size to be divisible by 4 while (frequencies_musical[frequency_slot].block_size % 4 != 0) { @@ -75,7 +80,7 @@ void init_goertzel(uint16_t frequency_slot, float frequency, float bandwidth) { frequencies_musical[frequency_slot].window_step = 4096.0 / frequencies_musical[frequency_slot].block_size; // Calculate the coefficients for the goertzel algorithm - float k = (int)(0.5 + ((frequencies_musical[frequency_slot].block_size * frequencies_musical[frequency_slot].target_freq) / SAMPLE_RATE)); + float k = (int)(0.5 + ((frequencies_musical[frequency_slot].block_size * frequencies_musical[frequency_slot].target_freq) / (SAMPLE_RATE*0.5))); float w = (2.0 * PI * k) / frequencies_musical[frequency_slot].block_size; float cosine = cos(w); //float sine = sin(w); // Unused since phase info is not needed @@ -110,6 +115,8 @@ void init_goertzel_constants_musical() { init_goertzel(i, frequencies_musical[i].target_freq, neighbor_distance_hz * 4.0); } + + init_a_weighting_lut(); } void init_window_lookup() { @@ -189,10 +196,10 @@ float calculate_magnitude_of_bin(uint16_t bin_number) { float coeff = frequencies_musical[bin_number].coeff; float window_step = frequencies_musical[bin_number].window_step; - float* sample_ptr = &sample_history[(SAMPLE_HISTORY_LENGTH - 1) - block_size]; + float* sample_ptr = &sample_history[(SAMPLE_HISTORY_LENGTH - 1) - block_size*2]; for (uint16_t i = 0; i < block_size; i++) { - float windowed_sample = sample_ptr[i] * window_lookup[uint32_t(window_pos)]; + float windowed_sample = sample_ptr[i*2] * window_lookup[uint32_t(window_pos)]; float q0 = coeff * q1 - q2 + windowed_sample; q2 = q1; q1 = q0; @@ -211,7 +218,7 @@ float calculate_magnitude_of_bin(uint16_t bin_number) { }, __func__ ); - return sqrt(normalized_magnitude * scale); + return (normalized_magnitude * scale); } void calculate_magnitudes() { @@ -254,7 +261,7 @@ void calculate_magnitudes() { bool interlace_field_now = ((i % 2) == 0); if (interlace_field_now == interlacing_frame_field) { // Get raw magnitude of frequency - magnitudes_raw[i] = calculate_magnitude_of_bin(i); // fast_mode enabled (downsampled audio) + magnitudes_raw[i] = calculate_magnitude_of_bin(i) * a_weighting_lut[i]; // Noise filtering ------------------------------------------------------------------ float avg_val = 0.0; @@ -266,6 +273,8 @@ void calculate_magnitudes() { noise_floor[i] = noise_floor[i] * 0.99 + avg_val * 0.01; + noise_floor[i] = 0.0; + magnitudes_noise_filtered[i] = max(magnitudes_raw[i] - noise_floor[i], 0.0f); // ---------------------------------------------------------------------------------- } @@ -303,8 +312,8 @@ void calculate_magnitudes() { } // Set a minimum "floor" to auto-range for, below this we don't auto-range anymore - if (max_val_smooth < 0.0025) { - max_val_smooth = 0.0025; + if (max_val_smooth < 0.0000025) { + max_val_smooth = 0.0000025; } // Calculate auto-ranging scale diff --git a/src/microphone.h b/src/microphone.h index 9228cf3..5573680 100644 --- a/src/microphone.h +++ b/src/microphone.h @@ -21,7 +21,7 @@ Functions for reading and storing data acquired by the I2S microphone #define I2S_DIN_PIN 37 #define CHUNK_SIZE 64 -#define SAMPLE_RATE 12800 +#define SAMPLE_RATE 12800*2 #define SAMPLE_HISTORY_LENGTH 4096 @@ -42,7 +42,7 @@ void init_i2s_microphone(){ // Configuration for the I2S standard mode, suitable for the SPH0645 microphone i2s_std_config_t std_cfg = { - .clk_cfg = I2S_STD_CLK_DEFAULT_CONFIG(12800), // BCLK frequency for a 2kHz sample rate (64 * 2kHz) + .clk_cfg = I2S_STD_CLK_DEFAULT_CONFIG(SAMPLE_RATE), // BCLK frequency for a 2kHz sample rate (64 * 2kHz) .slot_cfg = { .data_bit_width = I2S_DATA_BIT_WIDTH_32BIT, // Data bit width as 24 bits .slot_bit_width = I2S_SLOT_BIT_WIDTH_32BIT, // Slot width as 32 bits to accommodate data @@ -81,20 +81,20 @@ void init_i2s_microphone(){ void acquire_sample_chunk() { profile_function([&]() { // Buffer to hold audio samples - uint32_t new_samples_raw[CHUNK_SIZE]; - float new_samples[CHUNK_SIZE]; + uint32_t new_samples_raw[CHUNK_SIZE*2]; + float new_samples[CHUNK_SIZE*2]; // Read audio samples into int32_t buffer, but **only when emotiscope is active** if( EMOTISCOPE_ACTIVE == true ){ size_t bytes_read = 0; - i2s_channel_read(rx_handle, new_samples_raw, CHUNK_SIZE*sizeof(uint32_t), &bytes_read, portMAX_DELAY); + i2s_channel_read(rx_handle, new_samples_raw, CHUNK_SIZE*2*sizeof(uint32_t), &bytes_read, portMAX_DELAY); } else{ - memset(new_samples_raw, 0, sizeof(uint32_t) * CHUNK_SIZE); + memset(new_samples_raw, 0, sizeof(uint32_t) * CHUNK_SIZE * 2); } // Clip the sample value if it's too large, cast to floats - for (uint16_t i = 0; i < CHUNK_SIZE; i+=4) { + for (uint16_t i = 0; i < CHUNK_SIZE*2; i+=4) { new_samples[i+0] = min(max((((int32_t)new_samples_raw[i+0]) >> 14) + 7000, (int32_t)-131072), (int32_t)131072) - 360; new_samples[i+1] = min(max((((int32_t)new_samples_raw[i+1]) >> 14) + 7000, (int32_t)-131072), (int32_t)131072) - 360; new_samples[i+2] = min(max((((int32_t)new_samples_raw[i+2]) >> 14) + 7000, (int32_t)-131072), (int32_t)131072) - 360; @@ -102,11 +102,11 @@ void acquire_sample_chunk() { } // Convert audio from "18-bit" float range to -1.0 to 1.0 range - dsps_mulc_f32(new_samples, new_samples, CHUNK_SIZE, recip_scale, 1, 1); + dsps_mulc_f32(new_samples, new_samples, CHUNK_SIZE*2, recip_scale, 1, 1); // Add new chunk to audio history waveform_locked = true; - shift_and_copy_arrays(sample_history, SAMPLE_HISTORY_LENGTH, new_samples, CHUNK_SIZE); + shift_and_copy_arrays(sample_history, SAMPLE_HISTORY_LENGTH, new_samples, CHUNK_SIZE*2); // Used to sync GPU to this when needed waveform_locked = false; diff --git a/src/utilities.h b/src/utilities.h index cc600aa..4dd7401 100644 --- a/src/utilities.h +++ b/src/utilities.h @@ -149,15 +149,15 @@ float IRAM_ATTR interpolate(float index, float* array, uint16_t array_size) { return (1 - index_f_frac) * left_val + index_f_frac * right_val; } -void shift_and_copy_arrays(float history_array[], size_t history_size, const float new_array[], size_t new_size) { - profile_function([&]() { - // Use memmove to shift the history array - memmove(history_array, history_array + new_size, - (history_size - new_size) * sizeof(float)); - - // Use memcpy to copy the new array into the vacant space - memcpy(history_array + history_size - new_size, new_array, new_size * sizeof(float)); - }, __func__ ); +inline void shift_and_copy_arrays(float history_array[], size_t history_size, const float new_array[], size_t new_size) { + //profile_function([&]() { + // Use memmove to shift the history array + memmove(history_array, history_array + new_size, + (history_size - new_size) * sizeof(float)); + + // Use memcpy to copy the new array into the vacant space + memcpy(history_array + history_size - new_size, new_array, new_size * sizeof(float)); + //}, __func__ ); } // Function to shift array contents to the left diff --git a/src/vu.h b/src/vu.h index 1d0054f..1a1af06 100644 --- a/src/vu.h +++ b/src/vu.h @@ -27,10 +27,10 @@ void run_vu(){ profile_function([&]() { // CALCULATE AMPLITUDE ------------------------------------------------ static float max_amplitude_cap = 0.0000001; - float* samples = &sample_history[(SAMPLE_HISTORY_LENGTH-1) - CHUNK_SIZE]; + float* samples = &sample_history[(SAMPLE_HISTORY_LENGTH-1) - CHUNK_SIZE*2]; float max_amplitude_now = 0.000001; - for(uint16_t i = 0; i < CHUNK_SIZE; i++){ + for(uint16_t i = 0; i < CHUNK_SIZE; i+=2){ float sample = samples[i]; float sample_abs = fabs(sample);