Skip to content

Commit

Permalink
3.1.0 Upload
Browse files Browse the repository at this point in the history
  • Loading branch information
connornishijima committed Jan 30, 2023
1 parent 6d4628f commit 3534926
Show file tree
Hide file tree
Showing 12 changed files with 385 additions and 231 deletions.
68 changes: 45 additions & 23 deletions SENSORY_BRIDGE_FIRMWARE/GDFT.h
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,9 @@

// Obscure audio magic happens here
void IRAM_ATTR process_GDFT() {
static bool interlace_flip = false;
interlace_flip = !interlace_flip; // Switch field every frame on lower notes to save execution time

// Reset magnitude caps every frame
for (uint8_t i = 0; i < NUM_ZONES; i++) {
max_mags[i] = CONFIG.MAGNITUDE_FLOOR; // Higher than the average noise floor
Expand All @@ -71,26 +74,45 @@ void IRAM_ATTR process_GDFT() {
// Run GDFT (Goertzel-based Discrete Fourier Transform) with 64 frequencies
// Fixed-point code adapted from example here: https://sourceforge.net/p/freetel/code/HEAD/tree/misc/goertzal/goertzal.c
for (uint16_t i = 0; i < NUM_FREQS; i++) { // Run 64 times
int32_t q0, q1, q2;
int64_t mult;

q1 = 0;
q2 = 0;
bool field = bitRead(i, 0); // odd or even

// If note is part of field being rendered, is >= index 16, or is the first note
if (field == interlace_flip || i >= 16) {
int32_t q0, q1, q2;
int64_t mult;

q1 = 0;
q2 = 0;

float window_pos = 0.0;
for (uint16_t n = 0; n < frequencies[i].block_size; n++) { // Run Goertzel for "block_size" iterations
int32_t sample = 0;
sample = ((int32_t)sample_window[SAMPLE_HISTORY_LENGTH - 1 - n] * (int32_t)window_lookup[uint16_t(window_pos)]) >> 16;
mult = (int64_t)frequencies[i].coeff_q14 * (int64_t)q1;
q0 = (sample >> 6) + (mult >> 14) - q2;
q2 = q1;
q1 = q0;

window_pos += frequencies[i].window_mult;
}

for (uint16_t n = 0; n < frequencies[i].block_size; n++) { // Run Goertzel for "block_size" iterations
mult = (int64_t)frequencies[i].coeff_q14 * (int64_t)q1;
q0 = (sample_window[SAMPLE_HISTORY_LENGTH - 1 - n] >> 6) + (mult >> 14) - q2;
q2 = q1;
q1 = q0;
}
magnitudes[i] = q2 * q2 + q1 * q1 - ((int32_t)(mult >> 14)) * q2; // Calculate raw magnitudes

mult = (int64_t)frequencies[i].coeff_q14 * (int64_t)q1;
magnitudes[i] = q2 * q2 + q1 * q1 - ((int32_t)(mult >> 14)) * q2; // Calculate raw magnitudes
// Normalize output
magnitudes[i] *= float(frequencies[i].block_size_recip);

magnitudes[i] *= float(frequencies[i].block_size_recip); // Normalize output
// Scale magnitudes this way to help even out the response curve further
float prog = i / float(NUM_FREQS);
prog *= prog;
if (prog < 0.1) {
prog = 0.1;
}
magnitudes[i] *= prog;

if (magnitudes[i] < 0.0) { // Prevent negative values
magnitudes[i] = 0.0;
if (magnitudes[i] < 0.0) { // Prevent negative values
magnitudes[i] = 0.0;
}
}
}

Expand All @@ -112,7 +134,7 @@ void IRAM_ATTR process_GDFT() {
// Gather noise data if noise_complete == false
if (noise_complete == false) {
for (uint8_t i = 0; i < NUM_FREQS; i += 1) {
if (magnitudes[i] > noise_samples[i]) {
if (magnitudes[i] > noise_samples[i]) {
noise_samples[i] = magnitudes[i];
}
}
Expand All @@ -129,7 +151,7 @@ void IRAM_ATTR process_GDFT() {
// Apply noise reduction data, estimate max values
for (uint8_t i = 0; i < NUM_FREQS; i += 1) {
if (noise_complete == true) {
magnitudes[i] -= noise_samples[i] * 1.5; // Treat noise 1.5x louder than calibration
magnitudes[i] -= noise_samples[i] * 1.2; // Treat noise 1.2x louder than calibration
if (magnitudes[i] < 0.0) {
magnitudes[i] = 0.0;
}
Expand Down Expand Up @@ -214,12 +236,12 @@ void IRAM_ATTR process_GDFT() {
for (uint8_t i = 0; i < NUM_FREQS; i += 1) {
if (mag_targets[i] > mag_followers[i]) {
float delta = mag_targets[i] - mag_followers[i];
mag_followers[i] += delta * (smoothing_follower * 0.5);
mag_followers[i] += delta * (smoothing_follower * 0.45);
}

else if (mag_targets[i] < mag_followers[i]) {
float delta = mag_followers[i] - mag_targets[i];
mag_followers[i] -= delta * (smoothing_follower * 0.375);
mag_followers[i] -= delta * (smoothing_follower * 0.55);
}
}

Expand All @@ -228,11 +250,11 @@ void IRAM_ATTR process_GDFT() {
for (uint8_t i = 0; i < NUM_ZONES; i++) {
if (max_mags[i] > max_mags_followers[i]) {
float delta = max_mags[i] - max_mags_followers[i];
max_mags_followers[i] += delta * 0.075;
max_mags_followers[i] += delta * 0.05;
}
if (max_mags[i] < max_mags_followers[i]) {
float delta = max_mags_followers[i] - max_mags[i];
max_mags_followers[i] -= delta * 0.075;
max_mags_followers[i] -= delta * 0.05;
}
}

Expand Down Expand Up @@ -264,8 +286,8 @@ void IRAM_ATTR process_GDFT() {
mag_float = mag_float * (1.0 - smoothing_exp_average) + mag_float_last[i] * smoothing_exp_average;
mag_float_last[i] = mag_float;

mag_float *= CONFIG.GAIN;
if(mag_float > 1.0){
mag_float *= (CONFIG.GAIN);
if (mag_float > 1.0) {
mag_float = 1.0;
}

Expand Down
99 changes: 55 additions & 44 deletions SENSORY_BRIDGE_FIRMWARE/SENSORY_BRIDGE_FIRMWARE.ino
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@
---------------------------------------------------------------------*/

#define FIRMWARE_VERSION 30001 // Try "V" on the Serial port for this!
#define FIRMWARE_VERSION 30100 // Try "V" on the Serial port for this!
// Mm P M = Major version, m = Minor version, P = Patch version
// (i.e 3.5.4 would be 30504)

Expand Down Expand Up @@ -98,6 +98,9 @@ enum lightshow_modes {
// Setup, runs only one time ---------------------------------------------------------
void setup() {
init_system(); // (system.h) Initialize all hardware and arrays

// Create thread specifically for LED updates
xTaskCreatePinnedToCore(led_thread, "led_task", 4096, NULL, tskIDLE_PRIORITY + 1, &led_task, 1);
}

// Loop, runs forever after setup() --------------------------------------------------
Expand Down Expand Up @@ -142,13 +145,9 @@ void loop() {
lookahead_smoothing(); // (GDFT.h)
// Peek at upcoming frames to study/prevent flickering

function_id = 9;
render_leds(t_now_us); // (BELOW in this file)
// Convert the data we found into a beautiful show

function_id = 10;
function_id = 8;
log_fps(t_now_us); // (system.h)
// Log the current FPS
// Log the audio system FPS

if (debug_mode == true) {
function_id = 31;
Expand All @@ -158,46 +157,58 @@ void loop() {
yield(); // Otherwise the ESP32 will collapse into a black hole or something
}

// Run the lights! -------------------------------------------------------------------
void render_leds(uint32_t t_now_us) {
if (noise_complete == true) { // If we're not gathering ambient noise data
if (mode_transition_queued == true || noise_transition_queued == true) { // If transition queued
run_transition_fade(); // (led_utilities.h) Fade to black between modes
}
// Run the lights in their own thread! -------------------------------------------------------------
void led_thread(void* arg) {
while (true) {
if (led_thread_halt == false) {
if (noise_complete == true) { // If we're not gathering ambient noise data
if (mode_transition_queued == true || noise_transition_queued == true) { // If transition queued
run_transition_fade(); // (led_utilities.h) Fade to black between modes
}

// Based on the value of CONFIG.LIGHTSHOW_MODE, we call a
// different rendering function from lightshow_modes.h:

if (CONFIG.LIGHTSHOW_MODE == LIGHT_MODE_GDFT) {
light_mode_gdft(); // (lightshow_modes.h) GDFT spectrogram display
}
else if (CONFIG.LIGHTSHOW_MODE == LIGHT_MODE_GDFT_CHROMAGRAM) {
light_mode_gdft_chromagram(); // (lightshow_modes.h) GDFT chromagram display
}
else if (CONFIG.LIGHTSHOW_MODE == LIGHT_MODE_BLOOM) {
light_mode_bloom(false); // (lightshow_modes.h) Bloom Mode display
}
else if (CONFIG.LIGHTSHOW_MODE == LIGHT_MODE_BLOOM_FAST) {
light_mode_bloom(true); // (lightshow_modes.h) Bloom Mode display (faster)
}
else if (CONFIG.LIGHTSHOW_MODE == LIGHT_MODE_VU) {
light_mode_vu(); // (lightshow_modes.h) VU Mode display
}
else if (CONFIG.LIGHTSHOW_MODE == LIGHT_MODE_VU_DOT) {
light_mode_vu_dot(); // (lightshow_modes.h) VU Mode display (dot version)
}

if (CONFIG.MIRROR_ENABLED) { // Mirroring logic
// Don't scale Bloom Mode before mirroring
if (CONFIG.LIGHTSHOW_MODE != LIGHT_MODE_BLOOM && CONFIG.LIGHTSHOW_MODE != LIGHT_MODE_BLOOM_FAST) {
scale_image_to_half(); // (led_utilities.h) Image is now 50% height
}
shift_leds_up(64); // (led_utilities.h) Move image up one half
mirror_image_downwards(); // (led_utilities.h) Mirror downwards
}
} else {
noise_cal_led_readout(); // (noise_cal.h) Show the noise profile and progress during calibration
}

// Based on the value of CONFIG.LIGHTSHOW_MODE, we call a
// different rendering function from lightshow_modes.h:

if (CONFIG.LIGHTSHOW_MODE == LIGHT_MODE_GDFT) {
light_mode_gdft(); // (lightshow_modes.h) GDFT spectrogram display
}
else if (CONFIG.LIGHTSHOW_MODE == LIGHT_MODE_GDFT_CHROMAGRAM) {
light_mode_gdft_chromagram(); // (lightshow_modes.h) GDFT chromagram display
}
else if (CONFIG.LIGHTSHOW_MODE == LIGHT_MODE_BLOOM) {
light_mode_bloom(false); // (lightshow_modes.h) Bloom Mode display
}
else if (CONFIG.LIGHTSHOW_MODE == LIGHT_MODE_BLOOM_FAST) {
light_mode_bloom(true); // (lightshow_modes.h) Bloom Mode display (faster)
}
else if (CONFIG.LIGHTSHOW_MODE == LIGHT_MODE_VU) {
light_mode_vu(); // (lightshow_modes.h) VU Mode display
}
else if (CONFIG.LIGHTSHOW_MODE == LIGHT_MODE_VU_DOT) {
light_mode_vu_dot(); // (lightshow_modes.h) VU Mode display (dot version)
show_leds(); // This sends final RGB data to the LEDS (led_utilities.h)
LED_FPS = FastLED.getFPS();
}

if (CONFIG.MIRROR_ENABLED) { // Mirroring logic
// Don't scale Bloom Mode before mirroring
if (CONFIG.LIGHTSHOW_MODE != LIGHT_MODE_BLOOM && CONFIG.LIGHTSHOW_MODE != LIGHT_MODE_BLOOM_FAST) {
scale_image_to_half(); // (led_utilities.h) Image is now 50% height
}
shift_leds_up(64); // (led_utilities.h) Move image up one half
mirror_image_downwards(); // (led_utilities.h) Mirror downwards
if (CONFIG.LED_TYPE == LED_NEOPIXEL) {
vTaskDelay(1); // delay for 1ms to avoid hogging the CPU
}
else if (CONFIG.LED_TYPE == LED_DOTSTAR) { // More delay to compensate for faster LEDs
vTaskDelay(3); // delay for 3ms to avoid hogging the CPU
}
} else {
noise_cal_led_readout(); // (noise_cal.h) Show the noise profile and progress during calibration
}

show_leds(); // This sends final RGB data to the LEDS (led_utilities.h)
}
47 changes: 20 additions & 27 deletions SENSORY_BRIDGE_FIRMWARE/bridge_fs.h
Original file line number Diff line number Diff line change
Expand Up @@ -88,29 +88,10 @@ void load_config() {
config_buffer[i] = file.read();
}

// Temporary buffer is used to compare saved config version with this firmware versions' defaults.
// If a leftover config file version is a mismatch with the current firmware version, the config
// and noise_cal files need to be factory reset, to avoid reading potentially corrupt values
conf CONFIG_TEMP;
memcpy(&CONFIG_TEMP, config_buffer, sizeof(CONFIG_TEMP));
memcpy(&CONFIG, config_buffer, sizeof(CONFIG));

if (debug_mode) {
USBSerial.print("STORED VERSION IS: ");
USBSerial.println(CONFIG_TEMP.VERSION);

USBSerial.print("CURRENT VERSION IS: ");
USBSerial.println(CONFIG_DEFAULTS.VERSION);
}

if (CONFIG_TEMP.VERSION != CONFIG_DEFAULTS.VERSION) {
if(debug_mode){USBSerial.println("STORED CONFIG FILE IS OUTDATED!");}
//USBSerial.println("Factory resetting now to avoid potentially incompatible data!");
//save_backup_config();
//queue_factory_reset = true;
}
else {
memcpy(&CONFIG, &CONFIG_TEMP, sizeof(CONFIG_TEMP));
if(debug_mode){USBSerial.println("READ CONFIG SUCCESSFULLY");}
USBSerial.println("READ CONFIG SUCCESSFULLY");
}
}
file.close();
Expand All @@ -122,10 +103,14 @@ void load_config() {

// Save noise calibration to LittleFS
void save_ambient_noise_calibration() {
if(debug_mode){USBSerial.print("SAVING AMBIENT_NOISE PROFILE... ");}
if (debug_mode) {
USBSerial.print("SAVING AMBIENT_NOISE PROFILE... ");
}
File file = LittleFS.open("/noise_cal.bin", FILE_WRITE);
if (!file) {
if(debug_mode){USBSerial.println("Failed to open file for writing!");}
if (debug_mode) {
USBSerial.println("Failed to open file for writing!");
}
return;
}

Expand All @@ -144,15 +129,21 @@ void save_ambient_noise_calibration() {
}

file.close();
if(debug_mode){USBSerial.println("SAVE COMPLETE");}
if (debug_mode) {
USBSerial.println("SAVE COMPLETE");
}
}

// Load noise calibration from LittleFS
void load_ambient_noise_calibration() {
if(debug_mode){USBSerial.print("LOADING AMBIENT_NOISE PROFILE... ");}
if (debug_mode) {
USBSerial.print("LOADING AMBIENT_NOISE PROFILE... ");
}
File file = LittleFS.open("/noise_cal.bin", FILE_READ);
if (!file) {
if(debug_mode){USBSerial.println("Failed to open file for reading!");}
if (debug_mode) {
USBSerial.println("Failed to open file for reading!");
}
return;
}

Expand All @@ -169,7 +160,9 @@ void load_ambient_noise_calibration() {
}

file.close();
if(debug_mode){USBSerial.println("LOAD COMPLETE");}
if (debug_mode) {
USBSerial.println("LOAD COMPLETE");
}
}

// Initialize LittleFS
Expand Down
15 changes: 13 additions & 2 deletions SENSORY_BRIDGE_FIRMWARE/constants.h
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
// AUDIO #######################################################

#define SERIAL_BAUD 230400
#define DEFAULT_SAMPLE_RATE 24400
#define SAMPLE_HISTORY_LENGTH 2048
#define DEFAULT_SAMPLE_RATE 12200
#define SAMPLE_HISTORY_LENGTH 4096

// Don't change this unless you're willing to do a lot of other work on the code :/
#define NATIVE_RESOLUTION 128
Expand Down Expand Up @@ -46,6 +46,17 @@ const float notes[] = {

// OTHER #######################################################

const float dither_table[8] = {
0.125,
0.250,
0.375,
0.500,
0.625,
0.750,
0.875,
1.000
};

#define SWEET_SPOT_LEFT_CHANNEL 0
#define SWEET_SPOT_CENTER_CHANNEL 1
#define SWEET_SPOT_RIGHT_CHANNEL 2
Expand Down
Loading

0 comments on commit 3534926

Please sign in to comment.