Skip to content

Commit

Permalink
BROKEN VERSION: Emotiscope now acquires audio with a 2x sampling rate…
Browse files Browse the repository at this point in the history
…, Goertzel/DFT calculations still use old 12800Hz sample rate
  • Loading branch information
connornishijima committed Jun 7, 2024
1 parent ca9a67a commit 5693bfa
Show file tree
Hide file tree
Showing 6 changed files with 54 additions and 46 deletions.
12 changes: 5 additions & 7 deletions data/js/connection.js
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
Expand All @@ -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
Expand Down Expand Up @@ -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++ ){
Expand All @@ -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"){
Expand Down
3 changes: 2 additions & 1 deletion src/configuration.h
Original file line number Diff line number Diff line change
Expand Up @@ -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");
Expand Down
45 changes: 27 additions & 18 deletions src/goertzel.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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) {
Expand All @@ -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
Expand Down Expand Up @@ -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() {
Expand Down Expand Up @@ -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;
Expand All @@ -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() {
Expand Down Expand Up @@ -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;
Expand All @@ -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);
// ----------------------------------------------------------------------------------
}
Expand Down Expand Up @@ -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
Expand Down
18 changes: 9 additions & 9 deletions src/microphone.h
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand All @@ -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
Expand Down Expand Up @@ -81,32 +81,32 @@ 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;
new_samples[i+3] = min(max((((int32_t)new_samples_raw[i+3]) >> 14) + 7000, (int32_t)-131072), (int32_t)131072) - 360;
}

// 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;
Expand Down
18 changes: 9 additions & 9 deletions src/utilities.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
4 changes: 2 additions & 2 deletions src/vu.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down

0 comments on commit 5693bfa

Please sign in to comment.