From 35d6a12a229191221983849643de2d0a7d10e2a2 Mon Sep 17 00:00:00 2001 From: Volker Fischer Date: Sat, 15 Jun 2024 09:54:06 +0200 Subject: [PATCH] apply clang format --- edrumulus.cpp | 1085 +++++++++++++++++++++++------------------------- edrumulus.h | 971 +++++++++++++++++++++++-------------------- edrumulus.ino | 550 ++++++++++++------------ hardware.cpp | 593 +++++++++++++------------- hardware.h | 232 +++++------ parameters.cpp | 9 +- teensy_name.c | 28 +- 7 files changed, 1744 insertions(+), 1724 deletions(-) diff --git a/edrumulus.cpp b/edrumulus.cpp index 49089fd..eea7dc1 100644 --- a/edrumulus.cpp +++ b/edrumulus.cpp @@ -17,16 +17,15 @@ #include "edrumulus.h" - Edrumulus::Edrumulus() { // initializations - overload_LED_on_time = round ( overload_LED_on_time_s * Fs ); - error_LED_blink_time = round ( error_LED_blink_time_s * Fs ); - dc_offset_est_len = round ( dc_offset_est_len_s * Fs ); - samplerate_max_cnt = round ( samplerate_max_cnt_len_s * Fs ); - dc_offset_min_limit = round ( ADC_MAX_RANGE / 2 - ADC_MAX_RANGE * dc_offset_max_rel_error ); - dc_offset_max_limit = round ( ADC_MAX_RANGE / 2 + ADC_MAX_RANGE * dc_offset_max_rel_error ); + overload_LED_on_time = round(overload_LED_on_time_s * Fs); + error_LED_blink_time = round(error_LED_blink_time_s * Fs); + dc_offset_est_len = round(dc_offset_est_len_s * Fs); + samplerate_max_cnt = round(samplerate_max_cnt_len_s * Fs); + dc_offset_min_limit = round(ADC_MAX_RANGE / 2 - ADC_MAX_RANGE * dc_offset_max_rel_error); + dc_offset_max_limit = round(ADC_MAX_RANGE / 2 + ADC_MAX_RANGE * dc_offset_max_rel_error); overload_LED_cnt = 0; error_LED_cnt = 0; status_is_overload = false; @@ -39,7 +38,7 @@ Edrumulus::Edrumulus() #else spike_cancel_level = 0; // default #endif - cancel_num_samples = ( cancel_time_ms * Fs ) / 1000; + cancel_num_samples = (cancel_time_ms * Fs) / 1000; cancel_cnt = 0; cancel_MIDI_velocity = 1; cancel_pad_index = 0; @@ -51,18 +50,17 @@ Edrumulus::Edrumulus() // calculate DC offset IIR1 low pass filter parameters, see // http://www.tsdconseil.fr/tutos/tuto-iir1-en.pdf: gamma = exp(-Ts/tau) - dc_offset_iir_gamma = exp ( - 1.0f / ( Fs * dc_offset_iir_tau_seconds ) ); + dc_offset_iir_gamma = exp(-1.0f / (Fs * dc_offset_iir_tau_seconds)); dc_offset_iir_one_minus_gamma = 1.0f - dc_offset_iir_gamma; } - -void Edrumulus::setup ( const int conf_num_pads, - const int* conf_analog_pins, - const int* conf_analog_pins_rim_shot ) +void Edrumulus::setup(const int conf_num_pads, + const int* conf_analog_pins, + const int* conf_analog_pins_rim_shot) { - number_pads = min ( conf_num_pads, MAX_NUM_PADS ); + number_pads = min(conf_num_pads, MAX_NUM_PADS); - for ( int i = 0; i < number_pads; i++ ) + for (int i = 0; i < number_pads; i++) { // set the pad GIOP pin numbers analog_pin[i][0] = conf_analog_pins[i]; @@ -70,36 +68,36 @@ void Edrumulus::setup ( const int conf_num_pads, number_inputs[i] = conf_analog_pins_rim_shot[i] >= 0 ? 2 : 1; // setup the pad - pad[i].setup ( Fs ); + pad[i].setup(Fs); } // setup the ESP32 specific object, this has to be done after assigning the analog // pin numbers and before using the analog read function (as in the DC offset estimator) - edrumulus_hardware.setup ( Fs, - number_pads, - number_inputs, - analog_pin ); + edrumulus_hardware.setup(Fs, + number_pads, + number_inputs, + analog_pin); // estimate the DC offset for all inputs float dc_offset_sum[MAX_NUM_PADS][MAX_NUM_PAD_INPUTS]; - for ( int k = 0; k < dc_offset_est_len; k++ ) + for (int k = 0; k < dc_offset_est_len; k++) { - edrumulus_hardware.capture_samples ( number_pads, - number_inputs, - analog_pin, - sample_org ); + edrumulus_hardware.capture_samples(number_pads, + number_inputs, + analog_pin, + sample_org); - for ( int i = 0; i < number_pads; i++ ) + for (int i = 0; i < number_pads; i++) { - for ( int j = 0; j < number_inputs[i]; j++ ) + for (int j = 0; j < number_inputs[i]; j++) { - if ( k == 0 ) + if (k == 0) { // initial value dc_offset_sum[i][j] = sample_org[i][j]; } - else if ( k == dc_offset_est_len - 1 ) + else if (k == dc_offset_est_len - 1) { // we are done, calculate the DC offset now dc_offset[i][j] = dc_offset_sum[i][j] / dc_offset_est_len; @@ -114,75 +112,71 @@ void Edrumulus::setup ( const int conf_num_pads, } } - void Edrumulus::process() { -/* -// TEST for debugging: take samples from Octave, process and return result to Octave -if ( Serial.available() > 0 ) -{ - static int m = micros(); if ( micros() - m > 500000 ) pad[0].set_velocity_threshold ( 14.938 ); m = micros(); // 17 dB threshold - float fIn[2]; fIn[0] = Serial.parseFloat(); fIn[1] = 0.0f;//Serial.parseFloat(); - bool peak_found_debug, is_rim_shot_debug, is_choke_on_debug, is_choke_off_debug; - int midi_velocity_debug, midi_pos_debug; - float y = pad[0].process_sample ( fIn, false, peak_found_debug, midi_velocity_debug, midi_pos_debug, is_rim_shot_debug, is_choke_on_debug, is_choke_off_debug ); - Serial.println ( y, 7 ); -} -return; -*/ - + /* + // TEST for debugging: take samples from Octave, process and return result to Octave + if ( Serial.available() > 0 ) + { + static int m = micros(); if ( micros() - m > 500000 ) pad[0].set_velocity_threshold ( 14.938 ); m = micros(); // 17 dB threshold + float fIn[2]; fIn[0] = Serial.parseFloat(); fIn[1] = 0.0f;//Serial.parseFloat(); + bool peak_found_debug, is_rim_shot_debug, is_choke_on_debug, is_choke_off_debug; + int midi_velocity_debug, midi_pos_debug; + float y = pad[0].process_sample ( fIn, false, peak_found_debug, midi_velocity_debug, midi_pos_debug, is_rim_shot_debug, is_choke_on_debug, is_choke_off_debug ); + Serial.println ( y, 7 ); + } + return; + */ // Query samples ------------------------------------------------------------- // note that this is a blocking function - edrumulus_hardware.capture_samples ( number_pads, - number_inputs, - analog_pin, - sample_org ); - -/* -// TEST for plotting all captures samples in the serial plotter (but with low sampling rate) -String serial_print; -for ( int i = 0; i < number_pads; i++ ) -{ - //if ( !pad[i].get_is_control() ) + edrumulus_hardware.capture_samples(number_pads, + number_inputs, + analog_pin, + sample_org); + + /* + // TEST for plotting all captures samples in the serial plotter (but with low sampling rate) + String serial_print; + for ( int i = 0; i < number_pads; i++ ) { - for ( int j = 0; j < number_inputs[i]; j++ ) + //if ( !pad[i].get_is_control() ) { - serial_print += String ( sample_org[i][j] ) + "\t"; + for ( int j = 0; j < number_inputs[i]; j++ ) + { + serial_print += String ( sample_org[i][j] ) + "\t"; + } } } -} -Serial.println ( serial_print ); -*/ - + Serial.println ( serial_print ); + */ // Process samples ----------------------------------------------------------- - for ( int i = 0; i < number_pads; i++ ) + for (int i = 0; i < number_pads; i++) { int* sample_org_pad = sample_org[i]; peak_found[i] = false; control_found[i] = false; - if ( pad[i].get_is_control() ) + if (pad[i].get_is_control()) { // process sample for control input - pad[i].process_control_sample ( sample_org_pad, control_found[i], midi_ctrl_value[i], - peak_found[i], midi_velocity[i] ); + pad[i].process_control_sample(sample_org_pad, control_found[i], midi_ctrl_value[i], peak_found[i], midi_velocity[i]); } else { // prepare samples for processing - for ( int j = 0; j < number_inputs[i]; j++ ) + for (int j = 0; j < number_inputs[i]; j++) { - const bool is_rim_switch_input = ( j == 1 ) && pad[i].get_is_rim_switch(); // rim is always on second channel + const bool is_rim_switch_input = (j == 1) && pad[i].get_is_rim_switch(); // rim is always on second channel // overload detection: check for the lowest/largest possible ADC range values with noise consideration - if ( sample_org_pad[j] >= ( ADC_MAX_RANGE - ADC_MAX_NOISE_AMPL ) ) + if (sample_org_pad[j] >= (ADC_MAX_RANGE - ADC_MAX_NOISE_AMPL)) { overload_LED_cnt = overload_LED_on_time; overload_detected[j] = 2; } - else if ( sample_org_pad[j] <= ADC_MAX_NOISE_AMPL - 1 ) + else if (sample_org_pad[j] <= ADC_MAX_NOISE_AMPL - 1) { overload_LED_cnt = overload_LED_on_time; overload_detected[j] = 1; @@ -195,7 +189,7 @@ Serial.println ( serial_print ); // update DC offset by using an IIR1 low pass filter (but disable update if // rim switch input is on to avoid the DC offset is incorrect in case the switch is // held for a while by the user) - if ( !( is_rim_switch_input && pad[i].get_is_rim_switch_on() ) ) + if (!(is_rim_switch_input && pad[i].get_is_rim_switch_on())) { dc_offset[i][j] = dc_offset_iir_gamma * dc_offset[i][j] + dc_offset_iir_one_minus_gamma * sample_org_pad[j]; } @@ -204,24 +198,24 @@ Serial.println ( serial_print ); sample[j] = sample_org_pad[j] - dc_offset[i][j]; // ADC spike cancellation (do not use spike cancellation for rim switches since they have short peaks) - if ( ( spike_cancel_level > 0 ) && !is_rim_switch_input ) + if ((spike_cancel_level > 0) && !is_rim_switch_input) { - edrumulus_hardware.cancel_ADC_spikes ( sample[j], overload_detected[j], i, j, spike_cancel_level ); + edrumulus_hardware.cancel_ADC_spikes(sample[j], overload_detected[j], i, j, spike_cancel_level); } } // process sample - if ( any_coupling_used && // note: short-cut for speed optimization of normal non-coupling mode - ( ( ( coupled_pad_idx_primary >= 0 ) && ( ( i == coupled_pad_idx_secondary ) || ( i == coupled_pad_idx_primary ) ) ) || - ( ( coupled_pad_idx_rim_primary >= 0 ) && ( ( i == coupled_pad_idx_rim_secondary ) || ( i == coupled_pad_idx_rim_primary ) ) ) ) ) + if (any_coupling_used && // note: short-cut for speed optimization of normal non-coupling mode + (((coupled_pad_idx_primary >= 0) && ((i == coupled_pad_idx_secondary) || (i == coupled_pad_idx_primary))) || + ((coupled_pad_idx_rim_primary >= 0) && ((i == coupled_pad_idx_rim_secondary) || (i == coupled_pad_idx_rim_primary))))) { // special case: couple pad inputs for multiple head sensor capturing (assume that both pads have dual-inputs) - if ( ( i == coupled_pad_idx_primary ) || ( i == coupled_pad_idx_secondary ) ) + if ((i == coupled_pad_idx_primary) || (i == coupled_pad_idx_secondary)) { - if ( ( ( coupled_pad_idx_primary < coupled_pad_idx_secondary ) && ( i == coupled_pad_idx_primary ) ) || - ( ( coupled_pad_idx_secondary < coupled_pad_idx_primary ) && ( i == coupled_pad_idx_secondary ) ) ) + if (((coupled_pad_idx_primary < coupled_pad_idx_secondary) && (i == coupled_pad_idx_primary)) || + ((coupled_pad_idx_secondary < coupled_pad_idx_primary) && (i == coupled_pad_idx_secondary))) { - stored_sample_coupled_head[0] = sample[0]; // store 1st input + stored_sample_coupled_head[0] = sample[0]; // store 1st input stored_sample_coupled_head[1] = sample[1]; stored_overload_detected_coupled_head[0] = overload_detected[0]; // store 2nd input stored_overload_detected_coupled_head[1] = overload_detected[1]; @@ -230,9 +224,9 @@ Serial.println ( serial_print ); { // combine samples and process pad coupled_pad_idx_primary which is the primary coupled pad, // new "sample" layout: sum, rim, 1st head, 2nd head, 3rd head - if ( coupled_pad_idx_primary > coupled_pad_idx_secondary ) + if (coupled_pad_idx_primary > coupled_pad_idx_secondary) { - sample[2] = sample[0]; // 1st head (note that rim is already at correct place) + sample[2] = sample[0]; // 1st head (note that rim is already at correct place) overload_detected[2] = overload_detected[0]; sample[3] = stored_sample_coupled_head[0]; // 2nd head overload_detected[3] = stored_overload_detected_coupled_head[0]; @@ -241,30 +235,27 @@ Serial.println ( serial_print ); } else { - sample[3] = sample[0]; // 2nd head + sample[3] = sample[0]; // 2nd head overload_detected[3] = overload_detected[0]; - sample[4] = sample[1]; // 3rd head + sample[4] = sample[1]; // 3rd head overload_detected[4] = overload_detected[1]; sample[1] = stored_sample_coupled_head[1]; // rim (no overload_detected used for rim) sample[2] = stored_sample_coupled_head[0]; // 1st head overload_detected[2] = stored_overload_detected_coupled_head[0]; } - sample[0] = ( sample[2] + sample[3] + sample[4] ) / 3; // sum is on channel 0 + sample[0] = (sample[2] + sample[3] + sample[4]) / 3; // sum is on channel 0 - pad[coupled_pad_idx_primary].process_sample ( sample, 5, overload_detected, - peak_found[coupled_pad_idx_primary], midi_velocity[coupled_pad_idx_primary], - midi_pos[coupled_pad_idx_primary], rim_state[coupled_pad_idx_primary], - is_choke_on[coupled_pad_idx_primary], is_choke_off[coupled_pad_idx_primary] ); + pad[coupled_pad_idx_primary].process_sample(sample, 5, overload_detected, peak_found[coupled_pad_idx_primary], midi_velocity[coupled_pad_idx_primary], midi_pos[coupled_pad_idx_primary], rim_state[coupled_pad_idx_primary], is_choke_on[coupled_pad_idx_primary], is_choke_off[coupled_pad_idx_primary]); } } // special case: couple pad inputs for two-rim sensor capturing - if ( ( i == coupled_pad_idx_rim_primary ) || ( i == coupled_pad_idx_rim_secondary ) ) + if ((i == coupled_pad_idx_rim_primary) || (i == coupled_pad_idx_rim_secondary)) { - if ( ( ( coupled_pad_idx_rim_primary < coupled_pad_idx_rim_secondary ) && ( i == coupled_pad_idx_rim_primary ) ) || - ( ( coupled_pad_idx_rim_secondary < coupled_pad_idx_rim_primary ) && ( i == coupled_pad_idx_rim_secondary ) ) ) + if (((coupled_pad_idx_rim_primary < coupled_pad_idx_rim_secondary) && (i == coupled_pad_idx_rim_primary)) || + ((coupled_pad_idx_rim_secondary < coupled_pad_idx_rim_primary) && (i == coupled_pad_idx_rim_secondary))) { - stored_sample_coupled_rim[0] = sample[0]; // store 1st input + stored_sample_coupled_rim[0] = sample[0]; // store 1st input stored_sample_coupled_rim[1] = sample[1]; stored_overload_detected_coupled_rim[0] = overload_detected[0]; // store 2nd input stored_overload_detected_coupled_rim[1] = overload_detected[1]; @@ -273,7 +264,7 @@ Serial.println ( serial_print ); { // combine samples and process pad coupled_pad_idx_rim_primary which is the primary coupled pad, // new "sample" layout: 1st head, 1st rim, 2nd rim - if ( coupled_pad_idx_rim_primary > coupled_pad_idx_rim_secondary ) + if (coupled_pad_idx_rim_primary > coupled_pad_idx_rim_secondary) { sample[2] = stored_sample_coupled_rim[0]; // 1st head/rim are at correct place, copy 2nd rim } @@ -285,40 +276,34 @@ Serial.println ( serial_print ); overload_detected[0] = stored_overload_detected_coupled_rim[0]; } - pad[coupled_pad_idx_rim_primary].process_sample ( sample, 3, overload_detected, - peak_found[coupled_pad_idx_rim_primary], midi_velocity[coupled_pad_idx_rim_primary], - midi_pos[coupled_pad_idx_rim_primary], rim_state[coupled_pad_idx_rim_primary], - is_choke_on[coupled_pad_idx_rim_primary], is_choke_off[coupled_pad_idx_rim_primary] ); + pad[coupled_pad_idx_rim_primary].process_sample(sample, 3, overload_detected, peak_found[coupled_pad_idx_rim_primary], midi_velocity[coupled_pad_idx_rim_primary], midi_pos[coupled_pad_idx_rim_primary], rim_state[coupled_pad_idx_rim_primary], is_choke_on[coupled_pad_idx_rim_primary], is_choke_off[coupled_pad_idx_rim_primary]); } } } else { // normal case: process samples directly - pad[i].process_sample ( sample, number_inputs[i], overload_detected, - peak_found[i], midi_velocity[i], midi_pos[i], - rim_state[i], is_choke_on[i], is_choke_off[i] ); + pad[i].process_sample(sample, number_inputs[i], overload_detected, peak_found[i], midi_velocity[i], midi_pos[i], rim_state[i], is_choke_on[i], is_choke_off[i]); } } } - // Cross talk cancellation --------------------------------------------------- - for ( int i = 0; i < number_pads; i++ ) + for (int i = 0; i < number_pads; i++) { - if ( peak_found[i] ) + if (peak_found[i]) { // reset cancellation count if conditions are met - if ( ( cancel_cnt == 0 ) || ( ( cancel_cnt > 0 ) && ( midi_velocity[i] > cancel_MIDI_velocity ) ) ) + if ((cancel_cnt == 0) || ((cancel_cnt > 0) && (midi_velocity[i] > cancel_MIDI_velocity))) { cancel_cnt = cancel_num_samples; cancel_MIDI_velocity = midi_velocity[i]; cancel_pad_index = i; } - else if ( ( cancel_cnt > 0 ) && ( cancel_pad_index != i ) ) + else if ((cancel_cnt > 0) && (cancel_pad_index != i)) { // check if current pad is to be cancelled - if ( cancel_MIDI_velocity * pad[i].get_cancellation_factor() > midi_velocity[i] ) + if (cancel_MIDI_velocity * pad[i].get_cancellation_factor() > midi_velocity[i]) { peak_found[i] = false; } @@ -326,35 +311,33 @@ Serial.println ( serial_print ); } } - if ( cancel_cnt > 0 ) + if (cancel_cnt > 0) { cancel_cnt--; } - // Overload detection: keep LED on for a while ------------------------------- - if ( overload_LED_cnt > 0 ) + if (overload_LED_cnt > 0) { overload_LED_cnt--; - status_is_overload = ( overload_LED_cnt > 0 ); + status_is_overload = (overload_LED_cnt > 0); } - // Sampling rate and DC offset check ----------------------------------------- // (i.e. if CPU is overloaded, the sample rate will drop which is bad) - if ( samplerate_prev_micros_cnt >= samplerate_max_cnt ) + if (samplerate_prev_micros_cnt >= samplerate_max_cnt) { const unsigned long samplerate_cur_micros = micros(); -// TEST check the measured sampling rate -//Serial.println ( 1.0f / ( samplerate_cur_micros - samplerate_prev_micros ) * samplerate_max_cnt * 1e6f, 7 ); + // TEST check the measured sampling rate + // Serial.println ( 1.0f / ( samplerate_cur_micros - samplerate_prev_micros ) * samplerate_max_cnt * 1e6f, 7 ); // do not update status if micros() has wrapped around (at about 70 minutes) and if // we have the very first measurement after start (previous micros set to 0) - if ( ( samplerate_prev_micros != 0 ) && ( samplerate_cur_micros - samplerate_prev_micros > 0 ) ) + if ((samplerate_prev_micros != 0) && (samplerate_cur_micros - samplerate_prev_micros > 0)) { // set error flag if sample rate deviation is too large - status_is_error = ( abs ( 1.0f / ( samplerate_cur_micros - samplerate_prev_micros ) * samplerate_max_cnt * 1e6f - Fs ) > samplerate_max_error_Hz ); + status_is_error = (abs(1.0f / (samplerate_cur_micros - samplerate_prev_micros) * samplerate_max_cnt * 1e6f - Fs) > samplerate_max_error_Hz); } samplerate_prev_micros_cnt = 0; @@ -362,15 +345,15 @@ Serial.println ( serial_print ); // DC offset check dc_offset_error_channel = -1; // invalidate for "no DC offset error" case - for ( int i = 0; i < number_pads; i++ ) + for (int i = 0; i < number_pads; i++) { - if ( !pad[i].get_is_control() ) + if (!pad[i].get_is_control()) { - for ( int j = 0; j < number_inputs[i]; j++ ) + for (int j = 0; j < number_inputs[i]; j++) { const float& cur_dc_offset = dc_offset[i][j]; -//Serial.println ( String ( i ) + ", " + String ( cur_dc_offset ) ); // TEST for plotting all DC offsets - if ( ( cur_dc_offset < dc_offset_min_limit ) || ( cur_dc_offset > dc_offset_max_limit ) ) + // Serial.println ( String ( i ) + ", " + String ( cur_dc_offset ) ); // TEST for plotting all DC offsets + if ((cur_dc_offset < dc_offset_min_limit) || (cur_dc_offset > dc_offset_max_limit)) { status_is_error = true; dc_offset_error_channel = i + 32 * j; // 0 to 31: input 0, 32 to 63: input 1 @@ -383,8 +366,7 @@ Serial.println ( serial_print ); error_LED_cnt++; } - -void Edrumulus::set_coupled_pad_idx ( const int pad_idx, const int new_idx ) +void Edrumulus::set_coupled_pad_idx(const int pad_idx, const int new_idx) { // There are two modes supported: // 1. Coupled head sensor mode, i.e., we have three head piezo sensors and one rim sensor. @@ -395,54 +377,53 @@ void Edrumulus::set_coupled_pad_idx ( const int pad_idx, const int new_idx ) // Case 1. requires two dual-pad inputs and Case 2. requires one dual-pad and one single pad input. // NOTE that coupling is only enabled if the pad type match and coupling is either OFF or this // is the pad which is currently using coupling. - if ( new_idx < MAX_NUM_PADS ) + if (new_idx < MAX_NUM_PADS) { - if ( pad[pad_idx].get_pad_type() == PDA120LS ) + if (pad[pad_idx].get_pad_type() == PDA120LS) { // Case 1. --------------------------------------------------------------- - if ( ( coupled_pad_idx_primary < 0 ) || ( pad_idx == coupled_pad_idx_primary ) ) + if ((coupled_pad_idx_primary < 0) || (pad_idx == coupled_pad_idx_primary)) { // special case: always set coupled pad index parameter regardless if it is valid // or not to avoid issues in the GUI but if the index is invalid (i.e., no two inputs // available), do not enable the coupling - pad[pad_idx].set_coupled_pad_idx ( new_idx ); + pad[pad_idx].set_coupled_pad_idx(new_idx); const int cur_idx = number_inputs[new_idx] > 1 ? new_idx : 0 /* 0 disables coupling */; coupled_pad_idx_primary = cur_idx > 0 ? pad_idx : -1; // primary set to -1 switches coupling OFF coupled_pad_idx_secondary = cur_idx; - pad[pad_idx].set_head_sensor_coupling ( cur_idx > 0 ); + pad[pad_idx].set_head_sensor_coupling(cur_idx > 0); } } - else if ( ( pad[pad_idx].get_pad_type() == CY6 ) || - ( pad[pad_idx].get_pad_type() == CY8 ) || - ( pad[pad_idx].get_pad_type() == CY5 ) ) + else if ((pad[pad_idx].get_pad_type() == CY6) || + (pad[pad_idx].get_pad_type() == CY8) || + (pad[pad_idx].get_pad_type() == CY5)) { // Case 2. --------------------------------------------------------------- - if ( ( coupled_pad_idx_rim_primary < 0 ) || ( pad_idx == coupled_pad_idx_rim_primary ) ) + if ((coupled_pad_idx_rim_primary < 0) || (pad_idx == coupled_pad_idx_rim_primary)) { - pad[pad_idx].set_coupled_pad_idx ( new_idx ); + pad[pad_idx].set_coupled_pad_idx(new_idx); coupled_pad_idx_rim_primary = new_idx > 0 ? pad_idx : -1; // primary set to -1 switches coupling OFF coupled_pad_idx_rim_secondary = new_idx; - pad[pad_idx].set_use_second_rim ( new_idx > 0 ); + pad[pad_idx].set_use_second_rim(new_idx > 0); } } - any_coupling_used = ( coupled_pad_idx_primary >= 0 ) || ( coupled_pad_idx_rim_primary >= 0 ); + any_coupling_used = (coupled_pad_idx_primary >= 0) || (coupled_pad_idx_rim_primary >= 0); } } - // ----------------------------------------------------------------------------- // Pad ------------------------------------------------------------------------- // ----------------------------------------------------------------------------- -void Edrumulus::Pad::setup ( const int conf_Fs ) +void Edrumulus::Pad::setup(const int conf_Fs) { // set essential parameters Fs = conf_Fs; - init_delay_value = static_cast ( init_delay_value_s * conf_Fs ); + init_delay_value = static_cast(init_delay_value_s * conf_Fs); // initialize with default pad type and other defaults - set_pad_type ( PD6 ); + set_pad_type(PD6); midi_note = 127; midi_note_rim = 127; midi_note_open = 127; @@ -451,11 +432,10 @@ void Edrumulus::Pad::setup ( const int conf_Fs ) use_head_sensor_coupling = false; use_second_rim = false; init_delay_cnt = 0; // note that it resets value of set_pad_type above - initialize(); // do very first initialization without delay + initialize(); // do very first initialization without delay } - -void Edrumulus::Pad::set_pad_type ( const Epadtype new_pad_type ) +void Edrumulus::Pad::set_pad_type(const Epadtype new_pad_type) { // apply new pad type and set all parameters to the default values for that pad type pad_settings.pad_type = new_pad_type; @@ -464,56 +444,54 @@ void Edrumulus::Pad::set_pad_type ( const Epadtype new_pad_type ) sched_init(); } - void Edrumulus::Pad::manage_delayed_initialization() { // manage delayed initialization (make sure only one initialization for multiple quick settings changes) - if ( init_delay_cnt > 0 ) + if (init_delay_cnt > 0) { init_delay_cnt--; - if ( init_delay_cnt == 0 ) + if (init_delay_cnt == 0) { initialize(); } } } - void Edrumulus::Pad::initialize() { // in case we have a coupled sensor pad, the number of head sensors is 4, where 3 sensor signals and one sum number_head_sensors = use_head_sensor_coupling ? 4 : 1; // 1 or 4 head sensor inputs // set algorithm parameters - const float threshold_db = 20 * log10 ( ADC_MAX_NOISE_AMPL ) - 16.0f + pad_settings.velocity_threshold; // threshold range considering the maximum ADC noise level - threshold = pow ( 10.0f, threshold_db / 10 ); // linear power threshold - first_peak_diff_thresh = pow ( 10.0f, pad_settings.first_peak_diff_thresh_db / 10 ); // difference allowed between first peak and later peak in scan time - scan_time = round ( pad_settings.scan_time_ms * 1e-3f * Fs ); // scan time from first detected peak - pre_scan_time = round ( pad_settings.pre_scan_time_ms * 1e-3f * Fs ); - total_scan_time = scan_time + pre_scan_time; // includes pre-scan time - mask_time = round ( pad_settings.mask_time_ms * 1e-3f * Fs ); // mask time (e.g. 10 ms) - decay_len1 = round ( pad_settings.decay_len1_ms * 1e-3f * Fs ); // decay time 1 (e.g. 250 ms) - decay_len2 = round ( pad_settings.decay_len2_ms * 1e-3f * Fs ); // decay time 2 (e.g. 250 ms) - decay_len3 = round ( pad_settings.decay_len3_ms * 1e-3f * Fs ); // decay time 3 (e.g. 250 ms) + const float threshold_db = 20 * log10(ADC_MAX_NOISE_AMPL) - 16.0f + pad_settings.velocity_threshold; // threshold range considering the maximum ADC noise level + threshold = pow(10.0f, threshold_db / 10); // linear power threshold + first_peak_diff_thresh = pow(10.0f, pad_settings.first_peak_diff_thresh_db / 10); // difference allowed between first peak and later peak in scan time + scan_time = round(pad_settings.scan_time_ms * 1e-3f * Fs); // scan time from first detected peak + pre_scan_time = round(pad_settings.pre_scan_time_ms * 1e-3f * Fs); + total_scan_time = scan_time + pre_scan_time; // includes pre-scan time + mask_time = round(pad_settings.mask_time_ms * 1e-3f * Fs); // mask time (e.g. 10 ms) + decay_len1 = round(pad_settings.decay_len1_ms * 1e-3f * Fs); // decay time 1 (e.g. 250 ms) + decay_len2 = round(pad_settings.decay_len2_ms * 1e-3f * Fs); // decay time 2 (e.g. 250 ms) + decay_len3 = round(pad_settings.decay_len3_ms * 1e-3f * Fs); // decay time 3 (e.g. 250 ms) decay_len = decay_len1 + decay_len2 + decay_len3; - decay_fact = pow ( 10.0f, pad_settings.decay_fact_db / 10 ); - decay_mask_fact = pow ( 10.0f, pad_settings.mask_time_decay_fact_db / 10 ); + decay_fact = pow(10.0f, pad_settings.decay_fact_db / 10); + decay_mask_fact = pow(10.0f, pad_settings.mask_time_decay_fact_db / 10); const float decay_grad1 = pad_settings.decay_grad_fact1 / Fs; // decay gradient factor 1 const float decay_grad2 = pad_settings.decay_grad_fact2 / Fs; // decay gradient factor 2 const float decay_grad3 = pad_settings.decay_grad_fact3 / Fs; // decay gradient factor 3 x_sq_hist_len = total_scan_time; overload_hist_len = x_sq_hist_len; - decay_est_delay = round ( pad_settings.decay_est_delay_ms * 1e-3f * Fs ); - decay_est_len = round ( pad_settings.decay_est_len_ms * 1e-3f * Fs ); - decay_est_fact = pow ( 10.0f, pad_settings.decay_est_fact_db / 10 ); - rim_shot_threshold = pow ( 10.0f, ( static_cast ( pad_settings.rim_shot_threshold ) - 44 ) / 10 ); // linear rim shot threshold - rim_shot_window_len = round ( pad_settings.rim_shot_window_len_ms * 1e-3f * Fs ); // window length (e.g. 5 ms) - rim_shot_boost = pow ( 10.0f, static_cast ( pad_settings.rim_shot_boost ) / 40 ); // boost / 4 -> dB value - rim_switch_threshold = -pow ( 10.0f, pad_settings.rim_shot_threshold / 10.0f ); // rim switch linear threshold, where 10^(31/10)=1259 which is approx 4096/3 (10 bit ADC) - rim_switch_on_cnt_thresh = round ( 10.0f * 1e-3f * Fs ); // number of on samples until we detect a choke - rim_max_power_low_limit = ADC_MAX_NOISE_AMPL * ADC_MAX_NOISE_AMPL / 31.0f; // lower limit on detected rim power, 15 dB below max noise amplitude + decay_est_delay = round(pad_settings.decay_est_delay_ms * 1e-3f * Fs); + decay_est_len = round(pad_settings.decay_est_len_ms * 1e-3f * Fs); + decay_est_fact = pow(10.0f, pad_settings.decay_est_fact_db / 10); + rim_shot_threshold = pow(10.0f, (static_cast(pad_settings.rim_shot_threshold) - 44) / 10); // linear rim shot threshold + rim_shot_window_len = round(pad_settings.rim_shot_window_len_ms * 1e-3f * Fs); // window length (e.g. 5 ms) + rim_shot_boost = pow(10.0f, static_cast(pad_settings.rim_shot_boost) / 40); // boost / 4 -> dB value + rim_switch_threshold = -pow(10.0f, pad_settings.rim_shot_threshold / 10.0f); // rim switch linear threshold, where 10^(31/10)=1259 which is approx 4096/3 (10 bit ADC) + rim_switch_on_cnt_thresh = round(10.0f * 1e-3f * Fs); // number of on samples until we detect a choke + rim_max_power_low_limit = ADC_MAX_NOISE_AMPL * ADC_MAX_NOISE_AMPL / 31.0f; // lower limit on detected rim power, 15 dB below max noise amplitude x_rim_hist_len = x_sq_hist_len + rim_shot_window_len; - cancellation_factor = static_cast ( pad_settings.cancellation ) / 31.0f; // cancellation factor: range of 0.0..1.0 + cancellation_factor = static_cast(pad_settings.cancellation) / 31.0f; // cancellation factor: range of 0.0..1.0 ctrl_history_len_half = ctrl_history_len / 2; max_num_overloads = 3; // maximum allowed number of overloaded samples until the overload special case is activated @@ -521,8 +499,8 @@ void Edrumulus::Pad::initialize() // The sensitivity parameter shall be in the range of 0..31. This range should then be mapped to the // maximum possible dynamic where sensitivity of 31 means that we have no dynamic at all and 0 means // that we use the full possible ADC range. - const float max_velocity_range_db = 20 * log10 ( ADC_MAX_RANGE / 2 ) - threshold_db; - const float velocity_range_db = max_velocity_range_db * ( 32 - pad_settings.velocity_sensitivity ) / 32; + const float max_velocity_range_db = 20 * log10(ADC_MAX_RANGE / 2) - threshold_db; + const float velocity_range_db = max_velocity_range_db * (32 - pad_settings.velocity_sensitivity) / 32; // Consider MIDI curve (taken from RyoKosaka HelloDrum-arduino-Library: int HelloDrum::curve() function) // by calculating three parameters: velocity_factor * x ^ velocity_exponent + velocity_offset. @@ -532,64 +510,63 @@ void Edrumulus::Pad::initialize() // ( 126 / ( pow ( curve_param, 126 ) - 1 ) ) * ( pow ( curve_param, i - 1 ) - 1 ) + 1. // After applying some calculations (see calc_midi_curve_parameters.pdf), we get the following parameters: float curve_param = 1.018f; // this curve parameter comes close to what Roland is doing for "linear" - switch ( pad_settings.curve_type ) + switch (pad_settings.curve_type) { - case EXP1: curve_param *= 1.012f; break; - case EXP2: curve_param *= 1.017f; break; - case LOG1: curve_param *= 0.995f; break; - case LOG2: curve_param *= 0.987f; break; + case EXP1: curve_param *= 1.012f; break; + case EXP2: curve_param *= 1.017f; break; + case LOG1: curve_param *= 0.995f; break; + case LOG2: curve_param *= 0.987f; break; default: /* LINEAR, nothing to do */ break; } - velocity_factor = 126.0f / ( ( pow ( curve_param, 126.0f ) - 1 ) * curve_param * - pow ( threshold, 1270.0f / velocity_range_db * log10 ( curve_param ) ) ); + velocity_factor = 126.0f / ((pow(curve_param, 126.0f) - 1) * curve_param * + pow(threshold, 1270.0f / velocity_range_db * log10(curve_param))); - velocity_exponent = 1270.0f / velocity_range_db * log10 ( curve_param ); - velocity_offset = 1.0f - 126.0f / ( pow ( curve_param, 126.0f ) - 1 ); + velocity_exponent = 1270.0f / velocity_range_db * log10(curve_param); + velocity_offset = 1.0f - 126.0f / (pow(curve_param, 126.0f) - 1); // The positional sensing MIDI assignment parameters are dependent on, e.g., the filter design // parameters and cannot easily be derived from the ADC properties as is done for the velocity. // Based on the measurement results with the PD120 pad, we tryed to derive some meaningful parameter ranges. - const float pos_threshold_db = pad_settings.pos_threshold; // gives us a threshold range of 0..31 dB - pos_threshold = pow ( 10.0f, pos_threshold_db / 10 ); // linear power threshold - const float max_pos_range_db = 11; // dB (found by analyzing pd120_pos_sense2.wav test signal) - pos_range_db = max_pos_range_db * ( 32 - pad_settings.pos_sensitivity ) / 32; + const float pos_threshold_db = pad_settings.pos_threshold; // gives us a threshold range of 0..31 dB + pos_threshold = pow(10.0f, pos_threshold_db / 10); // linear power threshold + const float max_pos_range_db = 11; // dB (found by analyzing pd120_pos_sense2.wav test signal) + pos_range_db = max_pos_range_db * (32 - pad_settings.pos_sensitivity) / 32; // positional sensing for rim shots MIDI assignment parameters - const float rim_pos_threshold_db = pad_settings.rim_pos_threshold - 40; // gives us a threshold range of -40..-9 dB - rim_pos_threshold = pow ( 10.0f, rim_pos_threshold_db / 10 ); // linear power threshold - const float max_rim_pos_range_db = 11; // db (found by testing with PD-80R) - rim_pos_range_db = max_rim_pos_range_db * ( 32 - pad_settings.rim_pos_sensitivity ) / 32; + const float rim_pos_threshold_db = pad_settings.rim_pos_threshold - 40; // gives us a threshold range of -40..-9 dB + rim_pos_threshold = pow(10.0f, rim_pos_threshold_db / 10); // linear power threshold + const float max_rim_pos_range_db = 11; // db (found by testing with PD-80R) + rim_pos_range_db = max_rim_pos_range_db * (32 - pad_settings.rim_pos_sensitivity) / 32; // control MIDI assignment gives us a range of 410-2867 (FD-8: 3300-0, VH-12: 2200-1900 (press: 1770)) - control_threshold = pad_settings.pos_threshold / 31.0f * ( 0.6f * ADC_MAX_RANGE ) + ( 0.1f * ADC_MAX_RANGE ); - control_range = ( ADC_MAX_RANGE - control_threshold ) * ( 32 - pad_settings.pos_sensitivity ) / 32; + control_threshold = pad_settings.pos_threshold / 31.0f * (0.6f * ADC_MAX_RANGE) + (0.1f * ADC_MAX_RANGE); + control_range = (ADC_MAX_RANGE - control_threshold) * (32 - pad_settings.pos_sensitivity) / 32; // hi-hat pedal stomp action parameters - ctrl_velocity_range_fact = pow ( 10.0f, pad_settings.velocity_sensitivity / 10.0f ); // linear range of 1..1259 - ctrl_velocity_threshold = pow ( 10.0f, pad_settings.velocity_threshold / 3.0f / 10.0f ) - 1; // linear range of 0..10 + ctrl_velocity_range_fact = pow(10.0f, pad_settings.velocity_sensitivity / 10.0f); // linear range of 1..1259 + ctrl_velocity_threshold = pow(10.0f, pad_settings.velocity_threshold / 3.0f / 10.0f) - 1; // linear range of 0..10 // positional sensing low-pass filter properties // moving average cut off frequency approximation according to: // https://dsp.stackexchange.com/questions/9966/what-is-the-cut-off-frequency-of-a-moving-average-filter const float lp_cutoff_norm = pad_settings.pos_low_pass_cutoff / Fs; - lp_filt_len = round ( sqrt ( 0.196202f + lp_cutoff_norm * lp_cutoff_norm ) / lp_cutoff_norm ); - if ( ( lp_filt_len % 2 ) == 0 ) + lp_filt_len = round(sqrt(0.196202f + lp_cutoff_norm * lp_cutoff_norm) / lp_cutoff_norm); + if ((lp_filt_len % 2) == 0) { lp_filt_len++; // make sure we have an odd length } - const int lp_half_len = ( lp_filt_len - 1 ) / 2; + const int lp_half_len = (lp_filt_len - 1) / 2; x_low_hist_len = x_sq_hist_len + lp_filt_len; // clipping compensation initialization length_ampmap = 0; - for ( int i = 0; i < max_length_ampmap; i++ ) + for (int i = 0; i < max_length_ampmap; i++) { - const float amp_map_val = pow ( 10.0f, ( i * pad_settings.clip_comp_ampmap_step ) * - ( i * pad_settings.clip_comp_ampmap_step ) ); + const float amp_map_val = pow(10.0f, (i * pad_settings.clip_comp_ampmap_step) * (i * pad_settings.clip_comp_ampmap_step)); // never to higher than 5 but at least two values - if ( ( length_ampmap < 2 ) || ( amp_map_val <= 5.0f ) ) + if ((length_ampmap < 2) || (amp_map_val <= 5.0f)) { amplification_mapping[i] = amp_map_val; length_ampmap++; @@ -597,41 +574,44 @@ void Edrumulus::Pad::initialize() } // pre-calculate equations needed for 3 sensor get position function - get_pos_x0 = 0.433f; get_pos_y0 = 0.25f; // sensor 0 position - get_pos_x1 = 0.0; get_pos_y1 = -0.5f; // sensor 1 position - get_pos_x2 = -0.433f; get_pos_y2 = 0.25f; // sensor 2 position - get_pos_rim_radius = 0.75f; // rim radius + get_pos_x0 = 0.433f; + get_pos_y0 = 0.25f; // sensor 0 position + get_pos_x1 = 0.0; + get_pos_y1 = -0.5f; // sensor 1 position + get_pos_x2 = -0.433f; + get_pos_y2 = 0.25f; // sensor 2 position + get_pos_rim_radius = 0.75f; // rim radius get_pos_x0_sq_plus_y0_sq = get_pos_x0 * get_pos_x0 + get_pos_y0 * get_pos_y0; - get_pos_a1 = 2 * ( get_pos_x0 - get_pos_x1 ); - get_pos_b1 = 2 * ( get_pos_y0 - get_pos_y1 ); - get_pos_a2 = 2 * ( get_pos_x0 - get_pos_x2 ); - get_pos_b2 = 2 * ( get_pos_y0 - get_pos_y2 ); - get_pos_div1_fact = 1.0f / ( get_pos_a1 * get_pos_b2 - get_pos_a2 * get_pos_b1 ); - get_pos_div2_fact = 1.0f / ( get_pos_a2 * get_pos_b1 - get_pos_a1 * get_pos_b2 ); + get_pos_a1 = 2 * (get_pos_x0 - get_pos_x1); + get_pos_b1 = 2 * (get_pos_y0 - get_pos_y1); + get_pos_a2 = 2 * (get_pos_x0 - get_pos_x2); + get_pos_b2 = 2 * (get_pos_y0 - get_pos_y2); + get_pos_div1_fact = 1.0f / (get_pos_a1 * get_pos_b2 - get_pos_a2 * get_pos_b1); + get_pos_div2_fact = 1.0f / (get_pos_a2 * get_pos_b1 - get_pos_a1 * get_pos_b2); // allocate and initialize memory for vectors and initialize scalars - allocate_initialize ( &rim_bp_filt_b, bp_filt_len ); // rim band-pass filter coefficients b - allocate_initialize ( &rim_bp_filt_a, bp_filt_len - 1 ); // rim band-pass filter coefficients a - allocate_initialize ( &decay, decay_len ); // memory for decay function - allocate_initialize ( &lp_filt_b, lp_filt_len ); // memory for low-pass filter coefficients - allocate_initialize ( &ctrl_hist, ctrl_history_len ); // memory for Hi-Hat control pad hit detection + allocate_initialize(&rim_bp_filt_b, bp_filt_len); // rim band-pass filter coefficients b + allocate_initialize(&rim_bp_filt_a, bp_filt_len - 1); // rim band-pass filter coefficients a + allocate_initialize(&decay, decay_len); // memory for decay function + allocate_initialize(&lp_filt_b, lp_filt_len); // memory for low-pass filter coefficients + allocate_initialize(&ctrl_hist, ctrl_history_len); // memory for Hi-Hat control pad hit detection prev_ctrl_value = 0; multiple_sensor_cnt = 0; - for ( int in = 0; in < number_head_sensors; in++ ) + for (int in = 0; in < number_head_sensors; in++) { SSensor& s = sSensor[in]; - s.x_sq_hist.initialize ( x_sq_hist_len ); // memory for sqr(x) history - s.overload_hist.initialize ( overload_hist_len ); // memory for overload detection status - s.x_low_hist.initialize ( x_low_hist_len ); // memory for low-pass filter result - s.x_rim_switch_hist.initialize ( rim_shot_window_len ); // memory for rim switch detection - s.x_sec_rim_switch_hist.initialize ( rim_shot_window_len ); // memory for second rim switch detection - allocate_initialize ( &s.bp_filt_hist_x, bp_filt_len ); // band-pass filter x-signal history - allocate_initialize ( &s.bp_filt_hist_y, bp_filt_len - 1 ); // band-pass filter y-signal history - allocate_initialize ( &s.lp_filt_hist, lp_filt_len ); // memory for low-pass filter input - allocate_initialize ( &s.rim_bp_hist_x, bp_filt_len ); // rim band-pass filter x-signal history - allocate_initialize ( &s.rim_bp_hist_y, bp_filt_len - 1 ); // rim band-pass filter y-signal history - allocate_initialize ( &s.x_rim_hist, x_rim_hist_len ); // memory for rim shot detection + s.x_sq_hist.initialize(x_sq_hist_len); // memory for sqr(x) history + s.overload_hist.initialize(overload_hist_len); // memory for overload detection status + s.x_low_hist.initialize(x_low_hist_len); // memory for low-pass filter result + s.x_rim_switch_hist.initialize(rim_shot_window_len); // memory for rim switch detection + s.x_sec_rim_switch_hist.initialize(rim_shot_window_len); // memory for second rim switch detection + allocate_initialize(&s.bp_filt_hist_x, bp_filt_len); // band-pass filter x-signal history + allocate_initialize(&s.bp_filt_hist_y, bp_filt_len - 1); // band-pass filter y-signal history + allocate_initialize(&s.lp_filt_hist, lp_filt_len); // memory for low-pass filter input + allocate_initialize(&s.rim_bp_hist_x, bp_filt_len); // rim band-pass filter x-signal history + allocate_initialize(&s.rim_bp_hist_y, bp_filt_len - 1); // rim band-pass filter y-signal history + allocate_initialize(&s.x_rim_hist, x_rim_hist_len); // memory for rim shot detection s.was_above_threshold = false; s.is_overloaded_state = false; @@ -657,13 +637,13 @@ void Edrumulus::Pad::initialize() } // calculate positional sensing low-pass filter coefficients - for ( int i = 0; i < lp_filt_len; i++ ) + for (int i = 0; i < lp_filt_len; i++) { - if ( i < lp_half_len ) + if (i < lp_half_len) { - lp_filt_b[i] = ( 0.5f + i * 0.5f / lp_half_len ) / lp_filt_len; + lp_filt_b[i] = (0.5f + i * 0.5f / lp_half_len) / lp_filt_len; } - else if ( i == lp_half_len ) + else if (i == lp_half_len) { lp_filt_b[i] = 1.0f / lp_filt_len; } @@ -674,131 +654,127 @@ void Edrumulus::Pad::initialize() } // calculate the decay curve - for ( int i = 0; i < decay_len1; i++ ) + for (int i = 0; i < decay_len1; i++) { - decay[i] = pow ( 10.0f, -i / 10.0f * decay_grad1 ); + decay[i] = pow(10.0f, -i / 10.0f * decay_grad1); } - const float decay_fact1 = pow ( 10.0f, -decay_len1 / 10.0f * decay_grad1 ); - for ( int i = 0; i < decay_len2; i++ ) + const float decay_fact1 = pow(10.0f, -decay_len1 / 10.0f * decay_grad1); + for (int i = 0; i < decay_len2; i++) { - decay[decay_len1 + i] = decay_fact1 * pow ( 10.0f, -i / 10.0f * decay_grad2 ); + decay[decay_len1 + i] = decay_fact1 * pow(10.0f, -i / 10.0f * decay_grad2); } - const float decay_fact2 = decay_fact1 * pow ( 10.0f, -decay_len2 / 10.0f * decay_grad2 ); - for ( int i = 0; i < decay_len3; i++ ) + const float decay_fact2 = decay_fact1 * pow(10.0f, -decay_len2 / 10.0f * decay_grad2); + for (int i = 0; i < decay_len3; i++) { - decay[decay_len1 + decay_len2 + i] = decay_fact2 * pow ( 10.0f, -i / 10.0f * decay_grad3 ); + decay[decay_len1 + decay_len2 + i] = decay_fact2 * pow(10.0f, -i / 10.0f * decay_grad3); } // select rim shot signal band-pass filter coefficients - if ( pad_settings.rim_use_low_freq_bp ) + if (pad_settings.rim_use_low_freq_bp) { - for ( int i = 0; i < bp_filt_len - 1; i++ ) + for (int i = 0; i < bp_filt_len - 1; i++) { rim_bp_filt_a[i] = rim_bp_low_freq_a[i]; } - for ( int i = 0; i < bp_filt_len; i++ ) + for (int i = 0; i < bp_filt_len; i++) { rim_bp_filt_b[i] = rim_bp_low_freq_b[i]; } } else { - for ( int i = 0; i < bp_filt_len - 1; i++ ) + for (int i = 0; i < bp_filt_len - 1; i++) { rim_bp_filt_a[i] = rim_bp_high_freq_a[i]; } - for ( int i = 0; i < bp_filt_len; i++ ) + for (int i = 0; i < bp_filt_len; i++) { rim_bp_filt_b[i] = rim_bp_high_freq_b[i]; } } } - -float Edrumulus::Pad::process_sample ( const float* input, - const int input_len, - const int* overload_detected, - bool& peak_found, - int& midi_velocity, - int& midi_pos, - Erimstate& rim_state, - bool& is_choke_on, - bool& is_choke_off ) +float Edrumulus::Pad::process_sample(const float* input, + const int input_len, + const int* overload_detected, + bool& peak_found, + int& midi_velocity, + int& midi_pos, + Erimstate& rim_state, + bool& is_choke_on, + bool& is_choke_off) { // initialize return parameters and configuration parameters - peak_found = false; - midi_velocity = 0; - midi_pos = 0; - rim_state = NO_RIM; - is_choke_on = false; - is_choke_off = false; - const bool pos_sense_is_used = pad_settings.pos_sense_is_used && ( number_head_sensors == 1 ); // can be applied directly without calling initialize() - const bool rim_shot_is_used = pad_settings.rim_shot_is_used && ( input_len > 1 ); // can be applied directly without calling initialize() - const bool pos_sense_inverted = pad_settings.pos_invert; // can be applied directly without calling initialize() - float x_filt = 0.0f; // needed for debugging - float cur_decay = 1; // needed for debugging, initialization value (0 dB) only used for debugging - bool sensor0_has_results = false; + peak_found = false; + midi_velocity = 0; + midi_pos = 0; + rim_state = NO_RIM; + is_choke_on = false; + is_choke_off = false; + const bool pos_sense_is_used = pad_settings.pos_sense_is_used && (number_head_sensors == 1); // can be applied directly without calling initialize() + const bool rim_shot_is_used = pad_settings.rim_shot_is_used && (input_len > 1); // can be applied directly without calling initialize() + const bool pos_sense_inverted = pad_settings.pos_invert; // can be applied directly without calling initialize() + float x_filt = 0.0f; // needed for debugging + float cur_decay = 1; // needed for debugging, initialization value (0 dB) only used for debugging + bool sensor0_has_results = false; manage_delayed_initialization(); - for ( int head_sensor_cnt = 0; head_sensor_cnt < number_head_sensors; head_sensor_cnt++ ) + for (int head_sensor_cnt = 0; head_sensor_cnt < number_head_sensors; head_sensor_cnt++) { const int in = head_sensor_cnt == 0 ? 0 : head_sensor_cnt + 1; // exclude rim input - SSensor& s = sSensor[head_sensor_cnt]; - FastWriteFIFO& s_x_sq_hist = s.x_sq_hist; // shortcut for speed optimization - int& first_peak_delay = s.sResults.first_peak_delay; // use value in result struct - bool first_peak_found = false; - int peak_delay = 0; + SSensor& s = sSensor[head_sensor_cnt]; + FastWriteFIFO& s_x_sq_hist = s.x_sq_hist; // shortcut for speed optimization + int& first_peak_delay = s.sResults.first_peak_delay; // use value in result struct + bool first_peak_found = false; + int peak_delay = 0; first_peak_delay++; // increment first peak delay for each new sample (wraps only after some hours which is uncritical) // square input signal and store in FIFO buffer - s_x_sq_hist.add ( input[in] * input[in] ); - s.overload_hist.add ( overload_detected[in] ); - + s_x_sq_hist.add(input[in] * input[in]); + s.overload_hist.add(overload_detected[in]); // Calculate peak detection --------------------------------------------------- // IIR band-pass filter - update_fifo ( input[in], bp_filt_len, s.bp_filt_hist_x ); + update_fifo(input[in], bp_filt_len, s.bp_filt_hist_x); float sum_b = 0.0f; float sum_a = 0.0f; - for ( int i = 0; i < bp_filt_len; i++ ) + for (int i = 0; i < bp_filt_len; i++) { sum_b += s.bp_filt_hist_x[i] * bp_filt_b[i]; } - for ( int i = 0; i < bp_filt_len - 1; i++ ) + for (int i = 0; i < bp_filt_len - 1; i++) { sum_a += s.bp_filt_hist_y[i] * bp_filt_a[i]; } x_filt = sum_b - sum_a; - update_fifo ( x_filt, bp_filt_len - 1, s.bp_filt_hist_y ); + update_fifo(x_filt, bp_filt_len - 1, s.bp_filt_hist_y); x_filt = x_filt * x_filt; // calculate power of filter result - // exponential decay assumption float x_filt_decay = x_filt; - if ( s.decay_back_cnt > 0 ) + if (s.decay_back_cnt > 0) { // subtract decay (with clipping at zero) cur_decay = s.decay_scaling * decay[decay_len - s.decay_back_cnt]; x_filt_decay = x_filt - cur_decay; s.decay_back_cnt--; - if ( x_filt_decay < 0.0f ) + if (x_filt_decay < 0.0f) { x_filt_decay = 0.0f; } } - // during the mask time we apply a constant value to the decay way above the // detected peak to avoid missing a loud hit which is preceeded with a very // low volume hit which mask period would delete the loud hit - if ( ( s.mask_back_cnt > 0 ) && ( s.mask_back_cnt <= mask_time ) ) + if ((s.mask_back_cnt > 0) && (s.mask_back_cnt <= mask_time)) { - if ( x_filt > s.max_mask_x_filt_val * decay_mask_fact ) + if (x_filt > s.max_mask_x_filt_val * decay_mask_fact) { s.was_above_threshold = false; // reset the peak detection (note that x_filt_decay is always > threshold now) x_filt_decay = x_filt; // remove decay subtraction @@ -809,16 +785,15 @@ float Edrumulus::Pad::process_sample ( const float* input, } } - // threshold test - if ( ( ( x_filt_decay > threshold ) || s.was_above_threshold ) ) + if (((x_filt_decay > threshold) || s.was_above_threshold)) { // initializations at the time when the signal was above threshold for the // first time for the current peak - if ( !s.was_above_threshold ) + if (!s.was_above_threshold) { - s.decay_pow_est_start_cnt = max ( 1, decay_est_delay - x_filt_delay + 1 ); - s.scan_time_cnt = max ( 1, scan_time - x_filt_delay ); + s.decay_pow_est_start_cnt = max(1, decay_est_delay - x_filt_delay + 1); + s.scan_time_cnt = max(1, scan_time - x_filt_delay); s.mask_back_cnt = scan_time + mask_time; s.decay_back_cnt = 0; // reset in case it was active from previous peak s.max_x_filt_val = x_filt; // initialize maximum value with first value @@ -833,13 +808,13 @@ float Edrumulus::Pad::process_sample ( const float* input, // search from above threshold to corrected scan+mask time for highest peak in // filtered signal (needed for decay power estimation) - if ( x_filt > s.max_x_filt_val ) + if (x_filt > s.max_x_filt_val) { s.max_x_filt_val = x_filt; } // search from above threshold in scan time region needed for decay mask factor - if ( ( s.mask_back_cnt > mask_time ) && ( x_filt > s.max_mask_x_filt_val ) ) + if ((s.mask_back_cnt > mask_time) && (x_filt > s.max_mask_x_filt_val)) { s.max_mask_x_filt_val = x_filt; } @@ -848,19 +823,19 @@ float Edrumulus::Pad::process_sample ( const float* input, s.mask_back_cnt--; // end condition of scan time - if ( s.scan_time_cnt == 0 ) + if (s.scan_time_cnt == 0) { // climb to the maximum of the first peak (using the unfiltered signal) first_peak_found = false; s.first_peak_val = s_x_sq_hist[x_sq_hist_len - total_scan_time]; int first_peak_idx = 0; - for ( int idx = 1; idx < total_scan_time; idx++ ) + for (int idx = 1; idx < total_scan_time; idx++) { const float cur_x_sq_hist_val = s_x_sq_hist[x_sq_hist_len - total_scan_time + idx]; const float prev_x_sq_hist_val = s_x_sq_hist[x_sq_hist_len - total_scan_time + idx - 1]; - if ( ( s.first_peak_val < cur_x_sq_hist_val ) && !first_peak_found ) + if ((s.first_peak_val < cur_x_sq_hist_val) && !first_peak_found) { s.first_peak_val = cur_x_sq_hist_val; first_peak_idx = idx; @@ -870,7 +845,7 @@ float Edrumulus::Pad::process_sample ( const float* input, first_peak_found = true; // check if there is a much larger first peak - if ( ( prev_x_sq_hist_val > cur_x_sq_hist_val ) && ( s.first_peak_val * first_peak_diff_thresh < prev_x_sq_hist_val ) ) + if ((prev_x_sq_hist_val > cur_x_sq_hist_val) && (s.first_peak_val * first_peak_diff_thresh < prev_x_sq_hist_val)) { s.first_peak_val = prev_x_sq_hist_val; first_peak_idx = idx - 1; @@ -880,26 +855,26 @@ float Edrumulus::Pad::process_sample ( const float* input, // calculate sub-sample first peak value using simplified metric: // m = (x_sq[2] - x_sq[0]) / (x_sq[1] - x_sq[0]) -> sub_sample = m * m / 2 - if ( number_head_sensors > 1 ) + if (number_head_sensors > 1) { s.sResults.first_peak_sub_sample = 0.0; // in case no sub-sample value can be calculated const int cur_index = x_sq_hist_len - total_scan_time + first_peak_idx; - if ( ( cur_index > 0 ) && ( cur_index < x_sq_hist_len - 1 ) ) + if ((cur_index > 0) && (cur_index < x_sq_hist_len - 1)) { - if ( s_x_sq_hist[cur_index - 1] > s_x_sq_hist[cur_index + 1] ) + if (s_x_sq_hist[cur_index - 1] > s_x_sq_hist[cur_index + 1]) { // sample left of main peak is bigger than right sample - const float sub_sample_metric = ( s_x_sq_hist[cur_index - 1] - s_x_sq_hist[cur_index + 1] ) / - ( s_x_sq_hist[cur_index] - s_x_sq_hist[cur_index + 1] ); + const float sub_sample_metric = (s_x_sq_hist[cur_index - 1] - s_x_sq_hist[cur_index + 1]) / + (s_x_sq_hist[cur_index] - s_x_sq_hist[cur_index + 1]); s.sResults.first_peak_sub_sample = sub_sample_metric * sub_sample_metric / 2; } else { // sample right of main peak is bigger than left sample - const float sub_sample_metric = ( s_x_sq_hist[cur_index + 1] - s_x_sq_hist[cur_index - 1] ) / - ( s_x_sq_hist[cur_index] - s_x_sq_hist[cur_index - 1] ); + const float sub_sample_metric = (s_x_sq_hist[cur_index + 1] - s_x_sq_hist[cur_index - 1]) / + (s_x_sq_hist[cur_index] - s_x_sq_hist[cur_index - 1]); s.sResults.first_peak_sub_sample = -sub_sample_metric * sub_sample_metric / 2; } @@ -909,9 +884,9 @@ float Edrumulus::Pad::process_sample ( const float* input, // get the maximum velocity in the scan time using the unfiltered signal s.peak_val = 0.0f; int peak_velocity_idx = 0; - for ( int i = 0; i < scan_time; i++ ) + for (int i = 0; i < scan_time; i++) { - if ( s_x_sq_hist[x_sq_hist_len - scan_time + i] > s.peak_val ) + if (s_x_sq_hist[x_sq_hist_len - scan_time + i] > s.peak_val) { s.peak_val = s_x_sq_hist[x_sq_hist_len - scan_time + i]; peak_velocity_idx = i; @@ -919,45 +894,44 @@ float Edrumulus::Pad::process_sample ( const float* input, } // peak detection results - peak_delay = scan_time - ( peak_velocity_idx + 1 ); - first_peak_delay = total_scan_time - ( first_peak_idx + 1 ); + peak_delay = scan_time - (peak_velocity_idx + 1); + first_peak_delay = total_scan_time - (first_peak_idx + 1); first_peak_found = true; // for special case signal only increments, the peak found would be false -> correct this s.was_peak_found = true; - // Overload correction ---------------------------------------------------- // if the first peak is overloaded, use this position as the maximum peak - int peak_velocity_idx_ovhist = peak_velocity_idx; + int peak_velocity_idx_ovhist = peak_velocity_idx; const int first_peak_velocity_idx_in_overload_history = overload_hist_len - total_scan_time + first_peak_idx; - if ( s.overload_hist[first_peak_velocity_idx_in_overload_history] > 0.0f ) + if (s.overload_hist[first_peak_velocity_idx_in_overload_history] > 0.0f) { // overwrite peak value and index in history s.peak_val = s_x_sq_hist[x_sq_hist_len - total_scan_time + first_peak_idx]; peak_velocity_idx_ovhist = scan_time - x_sq_hist_len + first_peak_idx; } - float right_neighbor, left_neighbor; + float right_neighbor, left_neighbor; const int peak_velocity_idx_in_overload_history = overload_hist_len - scan_time + peak_velocity_idx_ovhist; const int peak_velocity_idx_in_x_sq_hist = x_sq_hist_len - scan_time + peak_velocity_idx_ovhist; - int number_overloaded_samples = 1; // we check for overload history at peak position is > 0 below -> start with one - bool left_neighbor_ok = true; // initialize with ok - bool right_neighbor_ok = true; // initialize with ok + int number_overloaded_samples = 1; // we check for overload history at peak position is > 0 below -> start with one + bool left_neighbor_ok = true; // initialize with ok + bool right_neighbor_ok = true; // initialize with ok // check overload status and correct the peak if necessary - if ( s.overload_hist[peak_velocity_idx_in_overload_history] > 0.0f ) + if (s.overload_hist[peak_velocity_idx_in_overload_history] > 0.0f) { // NOTE: the static_cast is a workaround for the ESP32 compiler issue: "unknown opcode or format name 'lsiu'" // run to the right to find same overloads int cur_idx = peak_velocity_idx_in_overload_history; int cur_idx_x_sq = peak_velocity_idx_in_x_sq_hist; - while ( ( cur_idx < overload_hist_len - 1 ) && ( static_cast ( s.overload_hist[cur_idx] ) == static_cast ( s.overload_hist[cur_idx + 1] ) ) ) + while ((cur_idx < overload_hist_len - 1) && (static_cast(s.overload_hist[cur_idx]) == static_cast(s.overload_hist[cur_idx + 1]))) { cur_idx++; cur_idx_x_sq++; number_overloaded_samples++; } - if ( cur_idx_x_sq + 1 < x_sq_hist_len ) + if (cur_idx_x_sq + 1 < x_sq_hist_len) { right_neighbor = s_x_sq_hist[cur_idx_x_sq + 1]; } @@ -969,13 +943,13 @@ float Edrumulus::Pad::process_sample ( const float* input, // run to the left to find same overloads cur_idx = peak_velocity_idx_in_overload_history; cur_idx_x_sq = peak_velocity_idx_in_x_sq_hist; - while ( ( cur_idx > 1 ) && ( static_cast ( s.overload_hist[cur_idx] ) == static_cast ( s.overload_hist[cur_idx - 1] ) ) ) + while ((cur_idx > 1) && (static_cast(s.overload_hist[cur_idx]) == static_cast(s.overload_hist[cur_idx - 1]))) { cur_idx--; cur_idx_x_sq--; number_overloaded_samples++; } - if ( cur_idx_x_sq - 1 >= 0 ) + if (cur_idx_x_sq - 1 >= 0) { left_neighbor = s_x_sq_hist[cur_idx_x_sq - 1]; } @@ -984,126 +958,124 @@ float Edrumulus::Pad::process_sample ( const float* input, left_neighbor_ok = false; } - s.is_overloaded_state = ( number_overloaded_samples > max_num_overloads ); + s.is_overloaded_state = (number_overloaded_samples > max_num_overloads); // clipping compensation (see tools/misc/clipping_compensation.m) - const float peak_val_sqrt = sqrt ( s.peak_val ); - float mean_neighbor = peak_val_sqrt; // if no neighbor can be calculated, use safest value, i.e., lowest resulting correction + const float peak_val_sqrt = sqrt(s.peak_val); + float mean_neighbor = peak_val_sqrt; // if no neighbor can be calculated, use safest value, i.e., lowest resulting correction - if ( left_neighbor_ok && right_neighbor_ok ) + if (left_neighbor_ok && right_neighbor_ok) { - mean_neighbor = ( sqrt ( left_neighbor ) + sqrt ( right_neighbor ) ) / 2.0f; + mean_neighbor = (sqrt(left_neighbor) + sqrt(right_neighbor)) / 2.0f; } - else if ( left_neighbor_ok ) + else if (left_neighbor_ok) { - mean_neighbor = sqrt ( left_neighbor ); // only left neighbor available + mean_neighbor = sqrt(left_neighbor); // only left neighbor available } - else if ( right_neighbor_ok ) + else if (right_neighbor_ok) { - mean_neighbor = sqrt ( right_neighbor ); // only right neighbor available + mean_neighbor = sqrt(right_neighbor); // only right neighbor available } - const float a_low = amplification_mapping[min ( length_ampmap - 2, number_overloaded_samples )]; - const float a_high = amplification_mapping[min ( length_ampmap - 1, number_overloaded_samples + 1 )]; + const float a_low = amplification_mapping[min(length_ampmap - 2, number_overloaded_samples)]; + const float a_high = amplification_mapping[min(length_ampmap - 1, number_overloaded_samples + 1)]; const float a_diff = a_high - a_low; const float a_diff_abs = a_diff * peak_val_sqrt / a_low; - float neighbor_to_limit_abs = mean_neighbor - ( peak_val_sqrt - a_diff_abs ); - neighbor_to_limit_abs = max ( 0.0f, min ( a_diff_abs, neighbor_to_limit_abs ) ); + float neighbor_to_limit_abs = mean_neighbor - (peak_val_sqrt - a_diff_abs); + neighbor_to_limit_abs = max(0.0f, min(a_diff_abs, neighbor_to_limit_abs)); const float amplification_compensation = a_low + neighbor_to_limit_abs / a_diff_abs * a_diff; - s.peak_val *= amplification_compensation * amplification_compensation; -/* -String overload_string = ""; -for ( int ov_cnt = 0; ov_cnt < overload_hist_len; ov_cnt++ ) -{ - overload_string += String ( s.overload_hist[ov_cnt] ) + " "; -} -Serial.println ( overload_string ); -Serial.println ( String ( peak_velocity_idx_in_x_sq_hist ) + " " + - String ( x_sq_hist_len ) + " " + String ( peak_velocity_idx_in_overload_history ) + " " + - String ( overload_hist_len ) + " " + String ( first_peak_idx ) ); -Serial.println ( String ( sqrt ( left_neighbor ) ) + " " + String ( sqrt ( right_neighbor ) ) + " " + - String ( number_overloaded_samples ) + " " + String ( mean_neighbor ) + " " + - String ( mean_neighbor - ( peak_val_sqrt - a_diff_abs ) ) + " " + String ( neighbor_to_limit_abs ) + " " + - String ( amplification_compensation ) + " " + String ( sqrt ( s.peak_val ) ) ); -*/ + s.peak_val *= amplification_compensation * amplification_compensation; + /* + String overload_string = ""; + for ( int ov_cnt = 0; ov_cnt < overload_hist_len; ov_cnt++ ) + { + overload_string += String ( s.overload_hist[ov_cnt] ) + " "; + } + Serial.println ( overload_string ); + Serial.println ( String ( peak_velocity_idx_in_x_sq_hist ) + " " + + String ( x_sq_hist_len ) + " " + String ( peak_velocity_idx_in_overload_history ) + " " + + String ( overload_hist_len ) + " " + String ( first_peak_idx ) ); + Serial.println ( String ( sqrt ( left_neighbor ) ) + " " + String ( sqrt ( right_neighbor ) ) + " " + + String ( number_overloaded_samples ) + " " + String ( mean_neighbor ) + " " + + String ( mean_neighbor - ( peak_val_sqrt - a_diff_abs ) ) + " " + String ( neighbor_to_limit_abs ) + " " + + String ( amplification_compensation ) + " " + String ( sqrt ( s.peak_val ) ) ); + */ } } // end condition of mask time - if ( s.mask_back_cnt == 0 ) + if (s.mask_back_cnt == 0) { - s.decay_back_cnt = decay_len; // per definition decay starts right after mask time + s.decay_back_cnt = decay_len; // per definition decay starts right after mask time s.decay_scaling = decay_fact * s.max_x_filt_val; // take maximum of filtered signal in scan+mask time s.was_above_threshold = false; } } - // decay power estimation - if ( s.decay_pow_est_start_cnt > 0 ) + if (s.decay_pow_est_start_cnt > 0) { s.decay_pow_est_start_cnt--; // end condition - if ( s.decay_pow_est_start_cnt == 0 ) + if (s.decay_pow_est_start_cnt == 0) { s.decay_pow_est_cnt = decay_est_len; // now the power estimation can start } } - if ( s.decay_pow_est_cnt > 0 ) + if (s.decay_pow_est_cnt > 0) { s.decay_pow_est_sum += x_filt; // sum up the powers in pre-defined interval s.decay_pow_est_cnt--; // end condition - if ( s.decay_pow_est_cnt == 0 ) + if (s.decay_pow_est_cnt == 0) { - const float decay_power = s.decay_pow_est_sum / decay_est_len; // calculate average power - s.decay_pow_est_sum = 0.0f; // we have to reset the sum for the next calculation - s.decay_scaling = min ( s.decay_scaling, decay_est_fact * decay_power ); // adjust the decay curve + const float decay_power = s.decay_pow_est_sum / decay_est_len; // calculate average power + s.decay_pow_est_sum = 0.0f; // we have to reset the sum for the next calculation + s.decay_scaling = min(s.decay_scaling, decay_est_fact * decay_power); // adjust the decay curve } } - // Calculate positional sensing ----------------------------------------------- - if ( pos_sense_is_used ) + if (pos_sense_is_used) { // low pass filter of the input signal and store results in a FIFO - update_fifo ( input[in], lp_filt_len, s.lp_filt_hist ); + update_fifo(input[in], lp_filt_len, s.lp_filt_hist); float x_low = 0.0f; - for ( int i = 0; i < lp_filt_len; i++ ) + for (int i = 0; i < lp_filt_len; i++) { - x_low += ( s.lp_filt_hist[i] * lp_filt_b[i] ); + x_low += (s.lp_filt_hist[i] * lp_filt_b[i]); } - s.x_low_hist.add ( x_low * x_low ); + s.x_low_hist.add(x_low * x_low); // start condition of delay process to fill up the required buffers - if ( first_peak_found && ( !s.was_pos_sense_ready ) && ( s.pos_sense_cnt == 0 ) ) + if (first_peak_found && (!s.was_pos_sense_ready) && (s.pos_sense_cnt == 0)) { // a peak was found, we now have to start the delay process to fill up the // required buffer length for our metric - s.pos_sense_cnt = max ( 1, lp_filt_len - first_peak_delay ); - s.x_low_hist_idx = x_low_hist_len - lp_filt_len - max ( 0, first_peak_delay - lp_filt_len + 1 ); + s.pos_sense_cnt = max(1, lp_filt_len - first_peak_delay); + s.x_low_hist_idx = x_low_hist_len - lp_filt_len - max(0, first_peak_delay - lp_filt_len + 1); } - if ( s.pos_sense_cnt > 0 ) + if (s.pos_sense_cnt > 0) { s.pos_sense_cnt--; // end condition - if ( s.pos_sense_cnt == 0 ) + if (s.pos_sense_cnt == 0) { // the buffers are filled, now calculate the metric float peak_energy_low = 0.0f; - for ( int i = 0; i < lp_filt_len; i++ ) + for (int i = 0; i < lp_filt_len; i++) { - peak_energy_low = max ( peak_energy_low, s.x_low_hist[s.x_low_hist_idx + i] ); + peak_energy_low = max(peak_energy_low, s.x_low_hist[s.x_low_hist_idx + i]); } - if ( pos_sense_inverted ) + if (pos_sense_inverted) { // add offset (dB) to get to similar range as non-inverted metric s.pos_sense_metric = peak_energy_low / s.first_peak_val * 10000.0f; @@ -1118,38 +1090,37 @@ Serial.println ( String ( sqrt ( left_neighbor ) ) + " " + String ( sqrt ( right } } - // Calculate rim shot/choke detection ----------------------------------------- - if ( rim_shot_is_used ) + if (rim_shot_is_used) { - if ( get_is_rim_switch() ) + if (get_is_rim_switch()) { // as a quick hack we re-use the length parameter for the switch on detection - const bool rim_switch_on = ( input[1] < rim_switch_threshold ); - s.x_rim_switch_hist.add ( rim_switch_on ); + const bool rim_switch_on = (input[1] < rim_switch_threshold); + s.x_rim_switch_hist.add(rim_switch_on); - if ( use_second_rim && ( input_len > 2 ) ) + if (use_second_rim && (input_len > 2)) { // the second rim signal is on third input signal - s.x_sec_rim_switch_hist.add ( input[2] < rim_switch_threshold ); + s.x_sec_rim_switch_hist.add(input[2] < rim_switch_threshold); } // at the end of the scan time search the history buffer for any switch on - if ( s.was_peak_found ) + if (s.was_peak_found) { s.rim_state = NO_RIM; int num_neighbor_switch_on = 0; - for ( int i = 0; i < rim_shot_window_len; i++ ) + for (int i = 0; i < rim_shot_window_len; i++) { - if ( s.x_rim_switch_hist[i] > 0 ) + if (s.x_rim_switch_hist[i] > 0) { num_neighbor_switch_on++; // On the ESP32, we had seen crosstalk between head/rim inputs. To avoid that the interference // signal from the head triggers the rim, we check that we have at least two neighbor samples // above the rim threshold (the switch keeps on longer than the piezo signal) - if ( num_neighbor_switch_on >= 2 ) + if (num_neighbor_switch_on >= 2) { s.rim_state = RIM_SHOT; } @@ -1161,18 +1132,18 @@ Serial.println ( String ( sqrt ( left_neighbor ) ) + " " + String ( sqrt ( right } // support second rim switch (usually the bell on a ride cymbal) - if ( use_second_rim ) + if (use_second_rim) { int num_neighbor_second_switch_on = 0; - for ( int i = 0; i < rim_shot_window_len; i++ ) + for (int i = 0; i < rim_shot_window_len; i++) { - if ( s.x_sec_rim_switch_hist[i] > 0 ) + if (s.x_sec_rim_switch_hist[i] > 0) { num_neighbor_second_switch_on++; // (see comment above for normal rim switch regarding this condition) - if ( num_neighbor_second_switch_on >= 2 ) + if (num_neighbor_second_switch_on >= 2) { // re-use rim-only enum for second rim switch, overwrites RIM_SHOT state s.rim_state = RIM_ONLY; @@ -1189,14 +1160,14 @@ Serial.println ( String ( sqrt ( left_neighbor ) ) + " " + String ( sqrt ( right } // choke detection - if ( rim_switch_on ) + if (rim_switch_on) { s.rim_switch_on_cnt++; } else { // if choke switch on was detected, send choke off message now - if ( s.rim_switch_on_cnt > rim_switch_on_cnt_thresh ) + if (s.rim_switch_on_cnt > rim_switch_on_cnt_thresh) { is_choke_off = true; } @@ -1205,7 +1176,7 @@ Serial.println ( String ( sqrt ( left_neighbor ) ) + " " + String ( sqrt ( right } // only send choke on message once we detected a choke (i.e. do not test for ">" threshold but for "==") - if ( s.rim_switch_on_cnt == rim_switch_on_cnt_thresh ) + if (s.rim_switch_on_cnt == rim_switch_on_cnt_thresh) { is_choke_on = true; } @@ -1213,52 +1184,52 @@ Serial.println ( String ( sqrt ( left_neighbor ) ) + " " + String ( sqrt ( right else { // band-pass filter the rim signal (two types are supported) - update_fifo ( input[1], bp_filt_len, s.rim_bp_hist_x ); + update_fifo(input[1], bp_filt_len, s.rim_bp_hist_x); float sum_b = 0.0f; float sum_a = 0.0f; - for ( int i = 0; i < bp_filt_len; i++ ) + for (int i = 0; i < bp_filt_len; i++) { sum_b += s.rim_bp_hist_x[i] * rim_bp_filt_b[i]; } - for ( int i = 0; i < bp_filt_len - 1; i++ ) + for (int i = 0; i < bp_filt_len - 1; i++) { sum_a += s.rim_bp_hist_y[i] * rim_bp_filt_a[i]; } float x_rim_bp = sum_b - sum_a; - update_fifo ( x_rim_bp, bp_filt_len - 1, s.rim_bp_hist_y ); + update_fifo(x_rim_bp, bp_filt_len - 1, s.rim_bp_hist_y); x_rim_bp = x_rim_bp * x_rim_bp; // calculate power of filter result - update_fifo ( x_rim_bp, x_rim_hist_len, s.x_rim_hist ); + update_fifo(x_rim_bp, x_rim_hist_len, s.x_rim_hist); // start condition of delay process to fill up the required buffers - if ( s.was_peak_found && ( !s.was_rim_shot_ready ) && ( s.rim_shot_cnt == 0 ) ) + if (s.was_peak_found && (!s.was_rim_shot_ready) && (s.rim_shot_cnt == 0)) { // a peak was found, we now have to start the delay process to fill up the // required buffer length for our metric - s.rim_shot_cnt = max ( 1, rim_shot_window_len - peak_delay ); - s.x_rim_hist_idx = x_rim_hist_len - rim_shot_window_len - max ( 0, peak_delay - rim_shot_window_len + 1 ); + s.rim_shot_cnt = max(1, rim_shot_window_len - peak_delay); + s.x_rim_hist_idx = x_rim_hist_len - rim_shot_window_len - max(0, peak_delay - rim_shot_window_len + 1); } - if ( s.rim_shot_cnt > 0 ) + if (s.rim_shot_cnt > 0) { s.rim_shot_cnt--; // end condition - if ( s.rim_shot_cnt == 0 ) + if (s.rim_shot_cnt == 0) { // the buffers are filled, now calculate the metric float rim_max_pow = 0; - for ( int i = 0; i < rim_shot_window_len; i++ ) + for (int i = 0; i < rim_shot_window_len; i++) { - rim_max_pow = max ( rim_max_pow, s.x_rim_hist[s.x_rim_hist_idx + i] ); + rim_max_pow = max(rim_max_pow, s.x_rim_hist[s.x_rim_hist_idx + i]); } - const float rim_metric = rim_max_pow / s.peak_val; - const bool is_rim_shot = ( rim_metric > rim_shot_threshold ) && ( rim_max_pow > rim_max_power_low_limit ); - s.rim_state = is_rim_shot ? RIM_SHOT : NO_RIM; - s.rim_shot_cnt = 0; - s.was_rim_shot_ready = true; + const float rim_metric = rim_max_pow / s.peak_val; + const bool is_rim_shot = (rim_metric > rim_shot_threshold) && (rim_max_pow > rim_max_power_low_limit); + s.rim_state = is_rim_shot ? RIM_SHOT : NO_RIM; + s.rim_shot_cnt = 0; + s.was_rim_shot_ready = true; // rim power is assumed to be constant for each rim shot but distance to center mounted piezo // will change power and therefore the rim metric can be used for positional sensing for rim shots @@ -1270,32 +1241,32 @@ Serial.println ( String ( sqrt ( left_neighbor ) ) + " " + String ( sqrt ( right // check for all estimations are ready and we can set the peak found flag and // return all results - if ( s.was_peak_found && ( !pos_sense_is_used || s.was_pos_sense_ready ) && ( !rim_shot_is_used || s.was_rim_shot_ready ) ) + if (s.was_peak_found && (!pos_sense_is_used || s.was_pos_sense_ready) && (!rim_shot_is_used || s.was_rim_shot_ready)) { // apply rim shot velocity boost -// TODO rim shot boost is only supported for single head sensors pads -> support multiple head sensor pads, too - if ( ( s.rim_state == RIM_SHOT ) && ( number_head_sensors == 1 ) ) + // TODO rim shot boost is only supported for single head sensors pads -> support multiple head sensor pads, too + if ((s.rim_state == RIM_SHOT) && (number_head_sensors == 1)) { s.peak_val *= rim_shot_boost; } // calculate the MIDI velocity value with clipping to allowed MIDI value range - int current_midi_velocity = static_cast ( velocity_factor * pow ( s.peak_val * ADC_noise_peak_velocity_scaling, velocity_exponent ) + velocity_offset ); - current_midi_velocity = max ( 1, min ( 127, current_midi_velocity ) ); + int current_midi_velocity = static_cast(velocity_factor * pow(s.peak_val * ADC_noise_peak_velocity_scaling, velocity_exponent) + velocity_offset); + current_midi_velocity = max(1, min(127, current_midi_velocity)); // positional sensing MIDI mapping with clipping to allowed MIDI value range - int current_midi_pos = static_cast ( ( 10 * log10 ( s.pos_sense_metric / pos_threshold ) / pos_range_db ) * 127 ); - current_midi_pos = max ( 0, min ( 127, current_midi_pos ) ); + int current_midi_pos = static_cast((10 * log10(s.pos_sense_metric / pos_threshold) / pos_range_db) * 127); + current_midi_pos = max(0, min(127, current_midi_pos)); // positional sensing must be adjusted if a rim shot is detected (note that this must be done BEFORE the MIDI clipping!) - if ( s.rim_state != NO_RIM ) + if (s.rim_state != NO_RIM) { // positional sensing for rim shots (no rim only and side stick) is only supported for rim piezos - if ( ( s.rim_state == RIM_SHOT ) && !get_is_rim_switch() ) + if ((s.rim_state == RIM_SHOT) && !get_is_rim_switch()) { // rim shot positional sensing MIDI mapping with clipping to allowed MIDI value range - current_midi_pos = static_cast ( ( 10 * log10 ( s.rim_pos_sense_metric / rim_pos_threshold ) / rim_pos_range_db ) * 127 ); - current_midi_pos = max ( 0, min ( 127, current_midi_pos ) ); + current_midi_pos = static_cast((10 * log10(s.rim_pos_sense_metric / rim_pos_threshold) / rim_pos_range_db) * 127); + current_midi_pos = max(0, min(127, current_midi_pos)); } else { @@ -1305,12 +1276,12 @@ Serial.println ( String ( sqrt ( left_neighbor ) ) + " " + String ( sqrt ( right // in case of signal clipping, we cannot use the positional sensing results (overloads will // only happen if the strike is located near the middle of the pad) - if ( s.is_overloaded_state ) + if (s.is_overloaded_state) { current_midi_pos = 0; // set to middle position } - if ( number_head_sensors == 1 ) + if (number_head_sensors == 1) { // normal case: only one head sensor -> use detection results directly midi_velocity = current_midi_velocity; @@ -1324,7 +1295,7 @@ Serial.println ( String ( sqrt ( left_neighbor ) ) + " " + String ( sqrt ( right s.sResults.midi_pos = current_midi_pos; s.sResults.rim_state = s.rim_state; - if ( head_sensor_cnt == 0 ) + if (head_sensor_cnt == 0) { sensor0_has_results = true; } @@ -1337,66 +1308,64 @@ Serial.println ( String ( sqrt ( left_neighbor ) ) + " " + String ( sqrt ( right } } - // Multiple head sensor management ---------------------------------------------- -// TODO do not use hard coded "17" at the three places here but define a pad specific value and use that instead -// -> use that value also for definition of max_sensor_sample_diff -const int sensor_distance_factor = 17; -// -// TODO put number somewhere else -const int max_sensor_sample_diff = 20; // 2.5 ms at 8 kHz sampling rate -// -// TODO calculate phase and return it with a special MIDI command -// -// TODO implement positional sensing if only two head sensor peaks are available - - if ( number_head_sensors > 1 ) + // TODO do not use hard coded "17" at the three places here but define a pad specific value and use that instead + // -> use that value also for definition of max_sensor_sample_diff + const int sensor_distance_factor = 17; + // + // TODO put number somewhere else + const int max_sensor_sample_diff = 20; // 2.5 ms at 8 kHz sampling rate + // + // TODO calculate phase and return it with a special MIDI command + // + // TODO implement positional sensing if only two head sensor peaks are available + + if (number_head_sensors > 1) { // start condition of delay process to query all head sensor results - if ( sensor0_has_results && ( multiple_sensor_cnt == 0 ) ) + if (sensor0_has_results && (multiple_sensor_cnt == 0)) { multiple_sensor_cnt = max_sensor_sample_diff; } // special case with multiple head sensors - if ( multiple_sensor_cnt > 0 ) + if (multiple_sensor_cnt > 0) { multiple_sensor_cnt--; // end condition - if ( multiple_sensor_cnt == 0 ) + if (multiple_sensor_cnt == 0) { + // TODO quick hack tests + int number_sensors_with_results = 0; + int head_sensor_idx_highest_velocity = 0; + int max_velocity = 0; + int velocity_sum = 0; + int sensor0_first_peak_delay = sSensor[0].sResults.first_peak_delay; + + for (int head_sensor_cnt = 1; head_sensor_cnt < number_head_sensors; head_sensor_cnt++) // do not use sensor 0 + { + if (abs(sSensor[head_sensor_cnt].sResults.first_peak_delay - sensor0_first_peak_delay) < max_sensor_sample_diff) + { + number_sensors_with_results++; + velocity_sum += sSensor[head_sensor_cnt].sResults.midi_velocity; -// TODO quick hack tests -int number_sensors_with_results = 0; -int head_sensor_idx_highest_velocity = 0; -int max_velocity = 0; -int velocity_sum = 0; -int sensor0_first_peak_delay = sSensor[0].sResults.first_peak_delay; - -for ( int head_sensor_cnt = 1; head_sensor_cnt < number_head_sensors; head_sensor_cnt++ ) // do not use sensor 0 -{ - if ( abs ( sSensor[head_sensor_cnt].sResults.first_peak_delay - sensor0_first_peak_delay ) < max_sensor_sample_diff ) - { - number_sensors_with_results++; - velocity_sum += sSensor[head_sensor_cnt].sResults.midi_velocity; - - if ( sSensor[head_sensor_cnt].sResults.midi_velocity > max_velocity ) - { - max_velocity = sSensor[head_sensor_cnt].sResults.midi_velocity; - head_sensor_idx_highest_velocity = head_sensor_cnt; - } - } -} + if (sSensor[head_sensor_cnt].sResults.midi_velocity > max_velocity) + { + max_velocity = sSensor[head_sensor_cnt].sResults.midi_velocity; + head_sensor_idx_highest_velocity = head_sensor_cnt; + } + } + } - if ( number_sensors_with_results == 3 ) + if (number_sensors_with_results == 3) { // calculate time delay differences - const float diff_1_0 = -( ( sSensor[2].sResults.first_peak_delay + sSensor[2].sResults.first_peak_sub_sample ) - - ( sSensor[1].sResults.first_peak_delay + sSensor[1].sResults.first_peak_sub_sample ) ); - const float diff_2_0 = -( ( sSensor[3].sResults.first_peak_delay + sSensor[3].sResults.first_peak_sub_sample ) - - ( sSensor[1].sResults.first_peak_delay + sSensor[1].sResults.first_peak_sub_sample ) ); + const float diff_1_0 = -((sSensor[2].sResults.first_peak_delay + sSensor[2].sResults.first_peak_sub_sample) - + (sSensor[1].sResults.first_peak_delay + sSensor[1].sResults.first_peak_sub_sample)); + const float diff_2_0 = -((sSensor[3].sResults.first_peak_delay + sSensor[3].sResults.first_peak_sub_sample) - + (sSensor[1].sResults.first_peak_delay + sSensor[1].sResults.first_peak_sub_sample)); // get_position function from pos_det.py // see: https://math.stackexchange.com/questions/3373011/how-to-solve-this-system-of-hyperbola-equations @@ -1405,10 +1374,10 @@ for ( int head_sensor_cnt = 1; head_sensor_cnt < number_head_sensors; head_senso const float r2 = diff_2_0 / sensor_distance_factor; const float c1 = r1 * r1 + get_pos_x0_sq_plus_y0_sq - get_pos_x1 * get_pos_x1 - get_pos_y1 * get_pos_y1; const float c2 = r2 * r2 + get_pos_x0_sq_plus_y0_sq - get_pos_x2 * get_pos_x2 - get_pos_y2 * get_pos_y2; - const float d1 = ( 2 * r1 * get_pos_b2 - 2 * r2 * get_pos_b1 ) * get_pos_div1_fact; - const float e1 = ( c1 * get_pos_b2 - c2 * get_pos_b1 ) * get_pos_div1_fact; - const float d2 = ( 2 * r1 * get_pos_a2 - 2 * r2 * get_pos_a1 ) * get_pos_div2_fact; - const float e2 = ( c1 * get_pos_a2 - c2 * get_pos_a1 ) * get_pos_div2_fact; + const float d1 = (2 * r1 * get_pos_b2 - 2 * r2 * get_pos_b1) * get_pos_div1_fact; + const float e1 = (c1 * get_pos_b2 - c2 * get_pos_b1) * get_pos_div1_fact; + const float d2 = (2 * r1 * get_pos_a2 - 2 * r2 * get_pos_a1) * get_pos_div2_fact; + const float e2 = (c1 * get_pos_a2 - c2 * get_pos_a1) * get_pos_div2_fact; const float d_e1_x0 = e1 - get_pos_x0; const float d_e2_y0 = e2 - get_pos_y0; const float a = d1 * d1 + d2 * d2 - 1; @@ -1416,96 +1385,90 @@ for ( int head_sensor_cnt = 1; head_sensor_cnt < number_head_sensors; head_senso const float c = d_e1_x0 * d_e1_x0 + d_e2_y0 * d_e2_y0; // two solutions to the quadratic equation, only one solution seems to always be correct - const float r_2 = ( -b - sqrt ( b * b - 4 * a * c ) ) / ( 2 * a ); + const float r_2 = (-b - sqrt(b * b - 4 * a * c)) / (2 * a); const float x = d1 * r_2 + e1; const float y = d2 * r_2 + e2; - float r = sqrt ( x * x + y * y ); + float r = sqrt(x * x + y * y); -// TEST -//Serial.println ( String ( x ) + "," + String ( y ) + ",1000.0," ); + // TEST + // Serial.println ( String ( x ) + "," + String ( y ) + ",1000.0," ); // clip calculated radius to rim radius - if ( ( r > get_pos_rim_radius ) || ( isnan ( r ) ) ) + if ((r > get_pos_rim_radius) || (isnan(r))) { r = get_pos_rim_radius; } const int max_abs_diff = r * sensor_distance_factor; -// TEST use maximum offset for middle from each sensor pair -//const int diff_2_1 = -( ( sSensor[3].sResults.first_peak_delay + sSensor[3].sResults.first_peak_sub_sample ) - -// ( sSensor[2].sResults.first_peak_delay + sSensor[2].sResults.first_peak_sub_sample ) ); -//Serial.println ( String ( diff_1_0 ) + "," + String ( diff_2_0 ) + "," + String ( diff_2_1 ) + "," ); -//const int max_abs_diff = ( max ( max ( abs ( diff_1_0 ), abs ( diff_2_0 ) ), abs ( diff_2_1 ) ) ); + // TEST use maximum offset for middle from each sensor pair + // const int diff_2_1 = -( ( sSensor[3].sResults.first_peak_delay + sSensor[3].sResults.first_peak_sub_sample ) - + // ( sSensor[2].sResults.first_peak_delay + sSensor[2].sResults.first_peak_sub_sample ) ); + // Serial.println ( String ( diff_1_0 ) + "," + String ( diff_2_0 ) + "," + String ( diff_2_1 ) + "," ); + // const int max_abs_diff = ( max ( max ( abs ( diff_1_0 ), abs ( diff_2_0 ) ), abs ( diff_2_1 ) ) ); - midi_pos = min ( 127, max ( 0, pad_settings.pos_sensitivity * ( max_abs_diff - pad_settings.pos_threshold ) ) ); + midi_pos = min(127, max(0, pad_settings.pos_sensitivity * (max_abs_diff - pad_settings.pos_threshold))); // use average MIDI velocity midi_velocity = velocity_sum / number_sensors_with_results; -//rim_state = sSensor[head_sensor_idx_highest_velocity].sResults.rim_state; -// TEST use second highest velocity sensor for rim shot detection -if ( head_sensor_idx_highest_velocity == 1 ) -{ - if ( sSensor[2].sResults.midi_velocity > sSensor[3].sResults.midi_velocity ) - { - rim_state = sSensor[2].sResults.rim_state; - } - else - { - rim_state = sSensor[3].sResults.rim_state; - } -} -else if ( head_sensor_idx_highest_velocity == 2 ) -{ - if ( sSensor[1].sResults.midi_velocity > sSensor[3].sResults.midi_velocity ) - { - rim_state = sSensor[1].sResults.rim_state; - } - else - { - rim_state = sSensor[3].sResults.rim_state; - } -} -else -{ - if ( sSensor[1].sResults.midi_velocity > sSensor[2].sResults.midi_velocity ) - { - rim_state = sSensor[1].sResults.rim_state; - } - else - { - rim_state = sSensor[2].sResults.rim_state; - } -} - -} -else if ( ( number_sensors_with_results == 2 ) || ( number_sensors_with_results == 1 ) ) -{ - -// TODO -midi_pos = 0; - -// TEST use average MIDI velocity -midi_velocity = velocity_sum / number_sensors_with_results; -rim_state = sSensor[head_sensor_idx_highest_velocity].sResults.rim_state; - -} -else -{ - -// TODO -midi_pos = 0; - -// TEST -midi_velocity = sSensor[0].sResults.midi_velocity; -rim_state = sSensor[0].sResults.rim_state; + // rim_state = sSensor[head_sensor_idx_highest_velocity].sResults.rim_state; + // TEST use second highest velocity sensor for rim shot detection + if (head_sensor_idx_highest_velocity == 1) + { + if (sSensor[2].sResults.midi_velocity > sSensor[3].sResults.midi_velocity) + { + rim_state = sSensor[2].sResults.rim_state; + } + else + { + rim_state = sSensor[3].sResults.rim_state; + } + } + else if (head_sensor_idx_highest_velocity == 2) + { + if (sSensor[1].sResults.midi_velocity > sSensor[3].sResults.midi_velocity) + { + rim_state = sSensor[1].sResults.rim_state; + } + else + { + rim_state = sSensor[3].sResults.rim_state; + } + } + else + { + if (sSensor[1].sResults.midi_velocity > sSensor[2].sResults.midi_velocity) + { + rim_state = sSensor[1].sResults.rim_state; + } + else + { + rim_state = sSensor[2].sResults.rim_state; + } + } + } + else if ((number_sensors_with_results == 2) || (number_sensors_with_results == 1)) + { + // TODO + midi_pos = 0; -} -peak_found = true; + // TEST use average MIDI velocity + midi_velocity = velocity_sum / number_sensors_with_results; + rim_state = sSensor[head_sensor_idx_highest_velocity].sResults.rim_state; + } + else + { + // TODO + midi_pos = 0; + // TEST + midi_velocity = sSensor[0].sResults.midi_velocity; + rim_state = sSensor[0].sResults.rim_state; + } + peak_found = true; // reset the first_peak_delay since this is our marker if a peak was in the interval - for ( int head_sensor_cnt = 1; head_sensor_cnt < number_head_sensors; head_sensor_cnt++ ) // do not use sensor 0 + for (int head_sensor_cnt = 1; head_sensor_cnt < number_head_sensors; head_sensor_cnt++) // do not use sensor 0 { sSensor[head_sensor_cnt].sResults.first_peak_delay = max_sensor_sample_diff; } @@ -1513,72 +1476,72 @@ peak_found = true; } } - DEBUG_ADD_VALUES ( input[0] * input[0], x_filt, sSensor[0].scan_time_cnt > 0 ? 0.5 : sSensor[0].mask_back_cnt > 0 ? 0.2 : cur_decay, threshold ); + DEBUG_ADD_VALUES(input[0] * input[0], x_filt, sSensor[0].scan_time_cnt > 0 ? 0.5 : sSensor[0].mask_back_cnt > 0 ? 0.2 + : cur_decay, + threshold); return x_filt; // here, you can return debugging values for verification with Ocatve } -void Edrumulus::Pad::process_control_sample ( const int* input, - bool& change_found, - int& midi_ctrl_value, - bool& peak_found, - int& midi_velocity ) +void Edrumulus::Pad::process_control_sample(const int* input, + bool& change_found, + int& midi_ctrl_value, + bool& peak_found, + int& midi_velocity) { manage_delayed_initialization(); // map the input value to the MIDI range - int cur_midi_ctrl_value = ( ( ADC_MAX_RANGE - input[0] - control_threshold ) / control_range * 127 ); - cur_midi_ctrl_value = max ( 0, min ( 127, cur_midi_ctrl_value ) ); - + int cur_midi_ctrl_value = ((ADC_MAX_RANGE - input[0] - control_threshold) / control_range * 127); + cur_midi_ctrl_value = max(0, min(127, cur_midi_ctrl_value)); // Detect pedal stomp -------------------------------------------------------- - update_fifo ( cur_midi_ctrl_value, ctrl_history_len, ctrl_hist ); + update_fifo(cur_midi_ctrl_value, ctrl_history_len, ctrl_hist); // to cope with ADC noise, we use a moving average filter for noise reduction float prev_ctrl_average = 0.0f; float cur_ctrl_average = 0.0f; - for ( int i = 0; i < ctrl_history_len_half; i++ ) + for (int i = 0; i < ctrl_history_len_half; i++) { - prev_ctrl_average += ctrl_hist[i]; // use first half for previous value - cur_ctrl_average += ctrl_hist[i + ctrl_history_len_half]; // use second half for current value + prev_ctrl_average += ctrl_hist[i]; // use first half for previous value + cur_ctrl_average += ctrl_hist[i + ctrl_history_len_half]; // use second half for current value } prev_ctrl_average /= ctrl_history_len_half; - cur_ctrl_average /= ctrl_history_len_half; + cur_ctrl_average /= ctrl_history_len_half; // check if we just crossed the transition from open to close - if ( ( prev_ctrl_average < hi_hat_is_open_MIDI_threshold ) && - ( cur_ctrl_average >= hi_hat_is_open_MIDI_threshold ) ) + if ((prev_ctrl_average < hi_hat_is_open_MIDI_threshold) && + (cur_ctrl_average >= hi_hat_is_open_MIDI_threshold)) { // calculate the gradient which is the measure for the pedal stomp velocity - const float ctrl_gradient = ( cur_ctrl_average - prev_ctrl_average ) / ctrl_history_len_half; + const float ctrl_gradient = (cur_ctrl_average - prev_ctrl_average) / ctrl_history_len_half; // only send MIDI note for pedal stomp if we are above the given threshold - if ( ctrl_gradient > ctrl_velocity_threshold ) + if (ctrl_gradient > ctrl_velocity_threshold) { // map curve difference (gradient) to velocity - midi_velocity = min ( 127, max ( 1, static_cast ( ( ctrl_gradient - ctrl_velocity_threshold ) * ctrl_velocity_range_fact ) ) ); + midi_velocity = min(127, max(1, static_cast((ctrl_gradient - ctrl_velocity_threshold) * ctrl_velocity_range_fact))); peak_found = true; // reset the history after a detection to suppress multiple detections - for ( int i = 0; i < ctrl_history_len; i++ ) + for (int i = 0; i < ctrl_history_len; i++) { ctrl_hist[i] = hi_hat_is_open_MIDI_threshold; } } } - // Introduce hysteresis to avoid sending too many MIDI control messages ------ change_found = false; - if ( ( cur_midi_ctrl_value > ( prev_ctrl_value + control_midi_hysteresis ) ) || - ( cur_midi_ctrl_value < ( prev_ctrl_value - control_midi_hysteresis ) ) ) + if ((cur_midi_ctrl_value > (prev_ctrl_value + control_midi_hysteresis)) || + (cur_midi_ctrl_value < (prev_ctrl_value - control_midi_hysteresis))) { // clip border values to max/min - if ( cur_midi_ctrl_value < control_midi_hysteresis ) + if (cur_midi_ctrl_value < control_midi_hysteresis) { midi_ctrl_value = 0; } - else if ( cur_midi_ctrl_value > 127 - control_midi_hysteresis ) + else if (cur_midi_ctrl_value > 127 - control_midi_hysteresis) { midi_ctrl_value = 127; } diff --git a/edrumulus.h b/edrumulus.h index 33d0a3d..08b5a00 100644 --- a/edrumulus.h +++ b/edrumulus.h @@ -17,81 +17,79 @@ #pragma once -#define VERSION_MAJOR 0 -#define VERSION_MINOR 9 +#define VERSION_MAJOR 0 +#define VERSION_MINOR 9 //#define USE_SERIAL_DEBUG_PLOTTING #include "Arduino.h" #include "edrumulus_hardware.h" - // Utility functions ----------------------------------------------------------------- -inline void update_fifo ( const float input, - const int fifo_length, - float* fifo_memory ) +inline void update_fifo(const float input, + const int fifo_length, + float* fifo_memory) { // move all values in the history one step back and put new value on the top - for ( int i = 0; i < fifo_length - 1; i++ ) + for (int i = 0; i < fifo_length - 1; i++) { fifo_memory[i] = fifo_memory[i + 1]; } fifo_memory[fifo_length - 1] = input; } -inline void allocate_initialize ( float** array_memory, - const int array_length ) +inline void allocate_initialize(float** array_memory, + const int array_length) { // (delete and) allocate memory - if ( *array_memory != nullptr ) + if (*array_memory != nullptr) { - delete[] *array_memory; + delete[] * array_memory; } *array_memory = new float[array_length]; // initialization values - for ( int i = 0; i < array_length; i++ ) + for (int i = 0; i < array_length; i++) { - ( *array_memory )[i] = 0.0f; + (*array_memory)[i] = 0.0f; } } class FastWriteFIFO { -public: - void initialize ( const int len ) + public: + void initialize(const int len) { pointer = 0; fifo_length = len; - allocate_initialize ( &fifo_memory, len ); + allocate_initialize(&fifo_memory, len); } - void add ( const float input ) + void add(const float input) { // write new value and increment data pointer with wrap around fifo_memory[pointer] = input; - pointer = ( pointer + 1 ) % fifo_length; + pointer = (pointer + 1) % fifo_length; } - const float operator[] ( const int index ) + const float operator[](const int index) { - return fifo_memory[( pointer + index ) % fifo_length]; + return fifo_memory[(pointer + index) % fifo_length]; } -protected: + protected: float* fifo_memory = nullptr; - int pointer; - int fifo_length; + int pointer; + int fifo_length; }; - // Edrumulus ------------------------------------------------------------------------- class Edrumulus { -public: + public: enum Epadtype // note that the enums need assigned integers for MIDI settings transfer { PD120 = 0, @@ -144,475 +142,544 @@ class Edrumulus Edrumulus(); // call this function during the Setup function of the main program - void setup ( const int conf_num_pads, - const int* conf_analog_pins, - const int* conf_analog_pins_rim_shot ); + void setup(const int conf_num_pads, + const int* conf_analog_pins, + const int* conf_analog_pins_rim_shot); // call the process function during the main loop void process(); // after calling the process function, query the results for each configured pad - bool get_peak_found ( const int pad_idx ) { return peak_found[pad_idx]; } - bool get_choke_on_found ( const int pad_idx ) { return !pad[pad_idx].get_is_control() && is_choke_on[pad_idx]; } - bool get_choke_off_found ( const int pad_idx ) { return !pad[pad_idx].get_is_control() && is_choke_off[pad_idx]; } - bool get_control_found ( const int pad_idx ) { return pad[pad_idx].get_is_control() && control_found[pad_idx]; } - int get_midi_velocity ( const int pad_idx ) { return midi_velocity[pad_idx]; } - int get_midi_pos ( const int pad_idx ) { return midi_pos[pad_idx]; } - int get_midi_note ( const int pad_idx ) { return - rim_state[pad_idx] == RIM_SHOT ? pad[pad_idx].get_midi_note_rim() : - rim_state[pad_idx] == RIM_ONLY ? pad[pad_idx].get_midi_note_open_rim() : - rim_state[pad_idx] == RIM_SIDE_STICK ? pad[pad_idx].get_midi_note_open() : pad[pad_idx].get_midi_note(); } - int get_midi_note_norm ( const int pad_idx ) { return pad[pad_idx].get_midi_note(); } - int get_midi_note_rim ( const int pad_idx ) { return pad[pad_idx].get_midi_note_rim(); } - int get_midi_note_open ( const int pad_idx ) { return rim_state[pad_idx] == RIM_SHOT ? pad[pad_idx].get_midi_note_open_rim() : pad[pad_idx].get_midi_note_open(); } - int get_midi_note_open_norm ( const int pad_idx ) { return pad[pad_idx].get_midi_note_open(); } - int get_midi_note_open_rim ( const int pad_idx ) { return pad[pad_idx].get_midi_note_open_rim(); } - int get_midi_ctrl_ch ( const int pad_idx ) { return pad[pad_idx].get_midi_ctrl_ch(); } - int get_midi_ctrl_value ( const int pad_idx ) { return midi_ctrl_value[pad_idx]; } - bool get_midi_ctrl_is_open ( const int pad_idx ) { return midi_ctrl_value[pad_idx] < Pad::hi_hat_is_open_MIDI_threshold; } + bool get_peak_found(const int pad_idx) { return peak_found[pad_idx]; } + bool get_choke_on_found(const int pad_idx) { return !pad[pad_idx].get_is_control() && is_choke_on[pad_idx]; } + bool get_choke_off_found(const int pad_idx) { return !pad[pad_idx].get_is_control() && is_choke_off[pad_idx]; } + bool get_control_found(const int pad_idx) { return pad[pad_idx].get_is_control() && control_found[pad_idx]; } + int get_midi_velocity(const int pad_idx) { return midi_velocity[pad_idx]; } + int get_midi_pos(const int pad_idx) { return midi_pos[pad_idx]; } + int get_midi_note(const int pad_idx) { return rim_state[pad_idx] == RIM_SHOT ? pad[pad_idx].get_midi_note_rim() : rim_state[pad_idx] == RIM_ONLY ? pad[pad_idx].get_midi_note_open_rim() + : rim_state[pad_idx] == RIM_SIDE_STICK ? pad[pad_idx].get_midi_note_open() + : pad[pad_idx].get_midi_note(); } + int get_midi_note_norm(const int pad_idx) { return pad[pad_idx].get_midi_note(); } + int get_midi_note_rim(const int pad_idx) { return pad[pad_idx].get_midi_note_rim(); } + int get_midi_note_open(const int pad_idx) { return rim_state[pad_idx] == RIM_SHOT ? pad[pad_idx].get_midi_note_open_rim() : pad[pad_idx].get_midi_note_open(); } + int get_midi_note_open_norm(const int pad_idx) { return pad[pad_idx].get_midi_note_open(); } + int get_midi_note_open_rim(const int pad_idx) { return pad[pad_idx].get_midi_note_open_rim(); } + int get_midi_ctrl_ch(const int pad_idx) { return pad[pad_idx].get_midi_ctrl_ch(); } + int get_midi_ctrl_value(const int pad_idx) { return midi_ctrl_value[pad_idx]; } + bool get_midi_ctrl_is_open(const int pad_idx) { return midi_ctrl_value[pad_idx] < Pad::hi_hat_is_open_MIDI_threshold; } // configure the pads - void set_pad_type ( const int pad_idx, const Epadtype new_pad_type ) { set_coupled_pad_idx ( pad_idx, 0 /* disable possible previous coupling first */ ); pad[pad_idx].set_pad_type ( new_pad_type ); } - Epadtype get_pad_type ( const int pad_idx ) { return pad[pad_idx].get_pad_type(); } - void set_velocity_threshold ( const int pad_idx, const int new_threshold ) { pad[pad_idx].set_velocity_threshold ( new_threshold ); } - int get_velocity_threshold ( const int pad_idx ) { return pad[pad_idx].get_velocity_threshold(); } - void set_velocity_sensitivity ( const int pad_idx, const int new_velocity ) { pad[pad_idx].set_velocity_sensitivity ( new_velocity ); } - int get_velocity_sensitivity ( const int pad_idx ) { return pad[pad_idx].get_velocity_sensitivity(); } - void set_pos_threshold ( const int pad_idx, const int new_threshold ) { pad[pad_idx].set_pos_threshold ( new_threshold ); } - int get_pos_threshold ( const int pad_idx ) { return pad[pad_idx].get_pos_threshold(); } - void set_pos_sensitivity ( const int pad_idx, const int new_velocity ) { pad[pad_idx].set_pos_sensitivity ( new_velocity ); } - int get_pos_sensitivity ( const int pad_idx ) { return pad[pad_idx].get_pos_sensitivity(); } - void set_rim_pos_threshold ( const int pad_idx, const int new_threshold ) { pad[pad_idx].set_rim_pos_threshold ( new_threshold ); } - int get_rim_pos_threshold ( const int pad_idx ) { return pad[pad_idx].get_rim_pos_threshold(); } - void set_rim_pos_sensitivity ( const int pad_idx, const int new_velocity ) { pad[pad_idx].set_rim_pos_sensitivity ( new_velocity ); } - int get_rim_pos_sensitivity ( const int pad_idx ) { return pad[pad_idx].get_rim_pos_sensitivity(); } - void set_mask_time ( const int pad_idx, const int new_time ) { pad[pad_idx].set_mask_time ( new_time ); } - int get_mask_time ( const int pad_idx ) { return pad[pad_idx].get_mask_time(); } - void set_rim_shot_threshold ( const int pad_idx, const int new_threshold ) { pad[pad_idx].set_rim_shot_threshold ( new_threshold ); } - int get_rim_shot_threshold ( const int pad_idx ) { return pad[pad_idx].get_rim_shot_threshold(); } - void set_rim_shot_boost ( const int pad_idx, const int new_boost ) { pad[pad_idx].set_rim_shot_boost ( new_boost ); } - int get_rim_shot_boost ( const int pad_idx ) { return pad[pad_idx].get_rim_shot_boost(); } - void set_curve ( const int pad_idx, const Ecurvetype new_curve ) { pad[pad_idx].set_curve ( new_curve ); } - Ecurvetype get_curve ( const int pad_idx ) { return pad[pad_idx].get_curve(); } - void set_cancellation ( const int pad_idx, const int new_cancel ) { pad[pad_idx].set_cancellation ( new_cancel ); } - int get_cancellation ( const int pad_idx ) { return pad[pad_idx].get_cancellation(); } - void set_coupled_pad_idx ( const int pad_idx, const int new_idx ); - int get_coupled_pad_idx ( const int pad_idx ) { return pad[pad_idx].get_coupled_pad_idx(); } - - void set_midi_notes ( const int pad_idx, const int new_midi_note, const int new_midi_note_rim ) { pad[pad_idx].set_midi_notes ( new_midi_note, new_midi_note_rim ); } - void set_midi_note_norm ( const int pad_idx, const int new_midi_note ) { pad[pad_idx].set_midi_note ( new_midi_note ); } - void set_midi_note_rim ( const int pad_idx, const int new_midi_note_rim ) { pad[pad_idx].set_midi_note_rim ( new_midi_note_rim ); } - void set_midi_notes_open ( const int pad_idx, const int new_midi_note, const int new_midi_note_rim ) { pad[pad_idx].set_midi_notes_open ( new_midi_note, new_midi_note_rim ); } - void set_midi_note_open_norm ( const int pad_idx, const int new_midi_note) { pad[pad_idx].set_midi_note_open ( new_midi_note ); } - void set_midi_note_open_rim ( const int pad_idx, const int new_midi_note_rim ) { pad[pad_idx].set_midi_note_open_rim ( new_midi_note_rim ); } - void set_midi_ctrl_ch ( const int pad_idx, const int new_midi_ctrl_ch ) { pad[pad_idx].set_midi_ctrl_ch ( new_midi_ctrl_ch ); } - void set_rim_shot_is_used ( const int pad_idx, const bool new_is_used ) { pad[pad_idx].set_rim_shot_is_used ( new_is_used ); } - bool get_rim_shot_is_used ( const int pad_idx ) { return pad[pad_idx].get_rim_shot_is_used(); } - void set_pos_sense_is_used ( const int pad_idx, const bool new_is_used ) { pad[pad_idx].set_pos_sense_is_used ( new_is_used ); } - bool get_pos_sense_is_used ( const int pad_idx ) { return pad[pad_idx].get_pos_sense_is_used(); } - - void set_spike_cancel_level ( const int new_level ) { spike_cancel_level = new_level; } - int get_spike_cancel_level () { return spike_cancel_level; } + void set_pad_type(const int pad_idx, const Epadtype new_pad_type) + { + set_coupled_pad_idx(pad_idx, 0 /* disable possible previous coupling first */); + pad[pad_idx].set_pad_type(new_pad_type); + } + Epadtype get_pad_type(const int pad_idx) { return pad[pad_idx].get_pad_type(); } + void set_velocity_threshold(const int pad_idx, const int new_threshold) { pad[pad_idx].set_velocity_threshold(new_threshold); } + int get_velocity_threshold(const int pad_idx) { return pad[pad_idx].get_velocity_threshold(); } + void set_velocity_sensitivity(const int pad_idx, const int new_velocity) { pad[pad_idx].set_velocity_sensitivity(new_velocity); } + int get_velocity_sensitivity(const int pad_idx) { return pad[pad_idx].get_velocity_sensitivity(); } + void set_pos_threshold(const int pad_idx, const int new_threshold) { pad[pad_idx].set_pos_threshold(new_threshold); } + int get_pos_threshold(const int pad_idx) { return pad[pad_idx].get_pos_threshold(); } + void set_pos_sensitivity(const int pad_idx, const int new_velocity) { pad[pad_idx].set_pos_sensitivity(new_velocity); } + int get_pos_sensitivity(const int pad_idx) { return pad[pad_idx].get_pos_sensitivity(); } + void set_rim_pos_threshold(const int pad_idx, const int new_threshold) { pad[pad_idx].set_rim_pos_threshold(new_threshold); } + int get_rim_pos_threshold(const int pad_idx) { return pad[pad_idx].get_rim_pos_threshold(); } + void set_rim_pos_sensitivity(const int pad_idx, const int new_velocity) { pad[pad_idx].set_rim_pos_sensitivity(new_velocity); } + int get_rim_pos_sensitivity(const int pad_idx) { return pad[pad_idx].get_rim_pos_sensitivity(); } + void set_mask_time(const int pad_idx, const int new_time) { pad[pad_idx].set_mask_time(new_time); } + int get_mask_time(const int pad_idx) { return pad[pad_idx].get_mask_time(); } + void set_rim_shot_threshold(const int pad_idx, const int new_threshold) { pad[pad_idx].set_rim_shot_threshold(new_threshold); } + int get_rim_shot_threshold(const int pad_idx) { return pad[pad_idx].get_rim_shot_threshold(); } + void set_rim_shot_boost(const int pad_idx, const int new_boost) { pad[pad_idx].set_rim_shot_boost(new_boost); } + int get_rim_shot_boost(const int pad_idx) { return pad[pad_idx].get_rim_shot_boost(); } + void set_curve(const int pad_idx, const Ecurvetype new_curve) { pad[pad_idx].set_curve(new_curve); } + Ecurvetype get_curve(const int pad_idx) { return pad[pad_idx].get_curve(); } + void set_cancellation(const int pad_idx, const int new_cancel) { pad[pad_idx].set_cancellation(new_cancel); } + int get_cancellation(const int pad_idx) { return pad[pad_idx].get_cancellation(); } + void set_coupled_pad_idx(const int pad_idx, const int new_idx); + int get_coupled_pad_idx(const int pad_idx) { return pad[pad_idx].get_coupled_pad_idx(); } + + void set_midi_notes(const int pad_idx, const int new_midi_note, const int new_midi_note_rim) { pad[pad_idx].set_midi_notes(new_midi_note, new_midi_note_rim); } + void set_midi_note_norm(const int pad_idx, const int new_midi_note) { pad[pad_idx].set_midi_note(new_midi_note); } + void set_midi_note_rim(const int pad_idx, const int new_midi_note_rim) { pad[pad_idx].set_midi_note_rim(new_midi_note_rim); } + void set_midi_notes_open(const int pad_idx, const int new_midi_note, const int new_midi_note_rim) { pad[pad_idx].set_midi_notes_open(new_midi_note, new_midi_note_rim); } + void set_midi_note_open_norm(const int pad_idx, const int new_midi_note) { pad[pad_idx].set_midi_note_open(new_midi_note); } + void set_midi_note_open_rim(const int pad_idx, const int new_midi_note_rim) { pad[pad_idx].set_midi_note_open_rim(new_midi_note_rim); } + void set_midi_ctrl_ch(const int pad_idx, const int new_midi_ctrl_ch) { pad[pad_idx].set_midi_ctrl_ch(new_midi_ctrl_ch); } + void set_rim_shot_is_used(const int pad_idx, const bool new_is_used) { pad[pad_idx].set_rim_shot_is_used(new_is_used); } + bool get_rim_shot_is_used(const int pad_idx) { return pad[pad_idx].get_rim_shot_is_used(); } + void set_pos_sense_is_used(const int pad_idx, const bool new_is_used) { pad[pad_idx].set_pos_sense_is_used(new_is_used); } + bool get_pos_sense_is_used(const int pad_idx) { return pad[pad_idx].get_pos_sense_is_used(); } + + void set_spike_cancel_level(const int new_level) { spike_cancel_level = new_level; } + int get_spike_cancel_level() { return spike_cancel_level; } // error and overload handling (implement blinking LED for error using error_LED_blink_time) - bool get_status_is_error() { return status_is_error && ( ( error_LED_cnt % error_LED_blink_time ) < ( error_LED_blink_time / 2 ) ); } - bool get_status_is_overload() { return status_is_overload; } - int get_status_dc_offset_error_channel() { return dc_offset_error_channel; } + bool get_status_is_error() { return status_is_error && ((error_LED_cnt % error_LED_blink_time) < (error_LED_blink_time / 2)); } + bool get_status_is_overload() { return status_is_overload; } + int get_status_dc_offset_error_channel() { return dc_offset_error_channel; } // persistent settings storage - void write_setting ( const int pad_index, const int address, const byte value ) { edrumulus_hardware.write_setting ( pad_index, address, value ); } - byte read_setting ( const int pad_index, const int address ) { return edrumulus_hardware.read_setting ( pad_index, address ); } + void write_setting(const int pad_index, const int address, const byte value) { edrumulus_hardware.write_setting(pad_index, address, value); } + byte read_setting(const int pad_index, const int address) { return edrumulus_hardware.read_setting(pad_index, address); } -protected: + protected: class Pad { - public: - void setup ( const int conf_Fs ); - - float process_sample ( const float* input, - const int input_len, - const int* overload_detected, - bool& peak_found, - int& midi_velocity, - int& midi_pos, - Erimstate& rim_state, - bool& is_choke_on, - bool& is_choke_off ); - - void process_control_sample ( const int* input, - bool& change_found, - int& midi_ctrl_value, - bool& peak_found, - int& midi_velocity ); - - void set_pad_type ( const Epadtype new_pad_type ); - Epadtype get_pad_type() { return pad_settings.pad_type; } - void set_midi_notes ( const int new_midi_note, const int new_midi_note_rim ) { midi_note = new_midi_note; midi_note_rim = new_midi_note_rim; } - void set_midi_notes_open ( const int new_midi_note, const int new_midi_note_rim ) { midi_note_open = new_midi_note; midi_note_open_rim = new_midi_note_rim; } - void set_midi_note ( const int new_midi_note ) { midi_note = new_midi_note; } - int get_midi_note () { return midi_note; } - void set_midi_note_rim ( const int new_midi_note_rim ) { midi_note_rim = new_midi_note_rim; } - int get_midi_note_rim () { return midi_note_rim; } - void set_midi_note_open ( const int new_midi_note ) { midi_note_open = new_midi_note; } - int get_midi_note_open () { return midi_note_open; } - void set_midi_note_open_rim ( const int new_midi_note_rim ) { midi_note_open_rim = new_midi_note_rim; } - int get_midi_note_open_rim () { return midi_note_open_rim; } - void set_midi_ctrl_ch ( const int new_midi_ctrl_ch ) { midi_ctrl_ch = new_midi_ctrl_ch; } - int get_midi_ctrl_ch () { return midi_ctrl_ch; } - void set_rim_shot_is_used ( const bool new_is_used ) { pad_settings.rim_shot_is_used = new_is_used; } - bool get_rim_shot_is_used () { return pad_settings.rim_shot_is_used; } - void set_pos_sense_is_used ( const bool new_is_used ) { pad_settings.pos_sense_is_used = new_is_used; } - bool get_pos_sense_is_used () { return pad_settings.pos_sense_is_used; } - - void set_velocity_threshold ( const int new_threshold ) { pad_settings.velocity_threshold = new_threshold; sched_init(); } - int get_velocity_threshold () { return pad_settings.velocity_threshold; } - void set_velocity_sensitivity ( const int new_velocity ) { pad_settings.velocity_sensitivity = new_velocity; sched_init(); } - int get_velocity_sensitivity () { return pad_settings.velocity_sensitivity; } - void set_pos_threshold ( const int new_threshold ) { pad_settings.pos_threshold = new_threshold; sched_init(); } - int get_pos_threshold () { return pad_settings.pos_threshold; } - void set_pos_sensitivity ( const int new_velocity ) { pad_settings.pos_sensitivity = new_velocity; sched_init(); } - int get_pos_sensitivity () { return pad_settings.pos_sensitivity; } - void set_rim_pos_threshold ( const int new_threshold ) { pad_settings.rim_pos_threshold = new_threshold; sched_init(); } - int get_rim_pos_threshold () { return pad_settings.rim_pos_threshold; } - void set_rim_pos_sensitivity ( const int new_velocity ) { pad_settings.rim_pos_sensitivity = new_velocity; sched_init(); } - int get_rim_pos_sensitivity () { return pad_settings.rim_pos_sensitivity; } - void set_mask_time ( const int new_time_ms ) { pad_settings.mask_time_ms = new_time_ms; sched_init(); } - int get_mask_time () { return pad_settings.mask_time_ms; } - void set_rim_shot_threshold ( const int new_threshold ) { pad_settings.rim_shot_threshold = new_threshold; sched_init(); } - int get_rim_shot_threshold () { return pad_settings.rim_shot_threshold; } - void set_rim_shot_boost ( const int new_boost ) { pad_settings.rim_shot_boost = new_boost; sched_init(); } - int get_rim_shot_boost () { return pad_settings.rim_shot_boost; } - void set_curve ( const Ecurvetype new_curve ) { pad_settings.curve_type = new_curve; sched_init(); } - Ecurvetype get_curve () { return pad_settings.curve_type; } - void set_cancellation ( const int new_cancel ) { pad_settings.cancellation = new_cancel; sched_init(); } - int get_cancellation () { return pad_settings.cancellation; } - void set_coupled_pad_idx ( const int new_idx ) { pad_settings.coupled_pad_idx = new_idx; sched_init(); } - int get_coupled_pad_idx () { return pad_settings.coupled_pad_idx; } - void set_head_sensor_coupling ( const bool new_coupling ) { use_head_sensor_coupling = new_coupling; sched_init(); } - void set_use_second_rim ( const bool new_sec_rim ) { use_second_rim = new_sec_rim; sched_init(); } - - float get_cancellation_factor() { return cancellation_factor; } - bool get_is_control() { return pad_settings.is_control; } - bool get_is_rim_switch() { return pad_settings.is_rim_switch; } - bool get_is_rim_switch_on() { return sSensor[0].rim_switch_on_cnt > 0; } - - // definitions which can be used outside the pad class, too - static const int control_midi_hysteresis = ADC_MAX_NOISE_AMPL / 2; // MIDI hysteresis for the controller to suppress noise - static const int hi_hat_is_open_MIDI_threshold = 100; // MIDI values smaller than the limit value are "open hi-hat" - - protected: - struct Epadsettings - { - Epadtype pad_type; - int velocity_threshold; // 0..31 - int velocity_sensitivity; // 0..31, high values give higher sensitivity - int mask_time_ms; // 0..31 (ms) - int pos_threshold; // 0..31 - int pos_sensitivity; // 0..31, high values give higher sensitivity - int rim_pos_threshold; // 0..31 - int rim_pos_sensitivity; // 0..31, high values give higher sensitivity - int rim_shot_threshold; // 0..31 - int rim_shot_boost; // 0..31 - int cancellation; // 0..31 - int coupled_pad_idx; // 0..[number of pads - 1] - bool is_control; // whether it is a normal pad or a hi-hat control pedal - bool is_rim_switch; // whether the pad supports rim/egde sensor based on a physical switch (i.e. no piezo) - bool pos_sense_is_used; // switches positional sensing support on or off - bool rim_shot_is_used; // switches rim shot detection on or off - Ecurvetype curve_type; - float first_peak_diff_thresh_db; - float scan_time_ms; - float pre_scan_time_ms; - float mask_time_decay_fact_db; - float decay_est_delay_ms; - float decay_est_len_ms; - float decay_est_fact_db; - float decay_fact_db; - float decay_len1_ms, decay_len2_ms, decay_len3_ms; - float decay_grad_fact1, decay_grad_fact2, decay_grad_fact3; - float pos_low_pass_cutoff; - bool pos_invert; - bool rim_use_low_freq_bp; - float rim_shot_window_len_ms; - float clip_comp_ampmap_step; - }; - - void apply_preset_pad_settings(); - void manage_delayed_initialization(); - void initialize(); // this function should not be called directly but use sched_init() instead - void sched_init() { init_delay_cnt = init_delay_value; }; // schedule initialization function (for delayed initialization) - const float init_delay_value_s = 0.2; // init delay value in seconds - static const int max_length_ampmap = 20; // maxmimum number of amplification mappings for clipping compensation - static const int ctrl_history_len = 10; // (MUST BE AN EVEN VALUE) control history length; the longer, the more noise reduction but more delay - - // band-pass filter coefficients (they are constant and must not be changed) - const int bp_filt_len = 5; - const float bp_filt_a[4] = { 0.6704579059531744f, -2.930427216820138f, 4.846289804288025f, -3.586239808116909f }; - const float bp_filt_b[5] = { 0.01658193166930305f, 0.0f, -0.0331638633386061f, 0.0f, 0.01658193166930305f }; - const float rim_bp_low_freq_a[4] = { 0.8008026466657076f, -3.348944421626415f, 5.292099516163272f, -3.743650976941178f }; - const float rim_bp_low_freq_b[5] = { 0.005542717210280682f, 0.0f, -0.01108543442056136f, 0.0f, 0.005542717210280682f }; - const float rim_bp_high_freq_a[4] = { 0.8008026466657077f, -3.021126408169798f, 4.637919662489649f, -3.377196335768073f }; - const float rim_bp_high_freq_b[5] = { 0.00554271721028068f, 0.0f, -0.01108543442056136f, 0.0f, 0.00554271721028068f }; - const int x_filt_delay = 5; - - // ADC noise scaling after band-pass filtering (e.g., for the Teensy ADC the noise has high - // energy at high frequencies which are cut by the band-pass filter) -> hardware dependend parameter + public: + void setup(const int conf_Fs); + + float process_sample(const float* input, + const int input_len, + const int* overload_detected, + bool& peak_found, + int& midi_velocity, + int& midi_pos, + Erimstate& rim_state, + bool& is_choke_on, + bool& is_choke_off); + + void process_control_sample(const int* input, + bool& change_found, + int& midi_ctrl_value, + bool& peak_found, + int& midi_velocity); + + void set_pad_type(const Epadtype new_pad_type); + Epadtype get_pad_type() { return pad_settings.pad_type; } + void set_midi_notes(const int new_midi_note, const int new_midi_note_rim) + { + midi_note = new_midi_note; + midi_note_rim = new_midi_note_rim; + } + void set_midi_notes_open(const int new_midi_note, const int new_midi_note_rim) + { + midi_note_open = new_midi_note; + midi_note_open_rim = new_midi_note_rim; + } + void set_midi_note(const int new_midi_note) { midi_note = new_midi_note; } + int get_midi_note() { return midi_note; } + void set_midi_note_rim(const int new_midi_note_rim) { midi_note_rim = new_midi_note_rim; } + int get_midi_note_rim() { return midi_note_rim; } + void set_midi_note_open(const int new_midi_note) { midi_note_open = new_midi_note; } + int get_midi_note_open() { return midi_note_open; } + void set_midi_note_open_rim(const int new_midi_note_rim) { midi_note_open_rim = new_midi_note_rim; } + int get_midi_note_open_rim() { return midi_note_open_rim; } + void set_midi_ctrl_ch(const int new_midi_ctrl_ch) { midi_ctrl_ch = new_midi_ctrl_ch; } + int get_midi_ctrl_ch() { return midi_ctrl_ch; } + void set_rim_shot_is_used(const bool new_is_used) { pad_settings.rim_shot_is_used = new_is_used; } + bool get_rim_shot_is_used() { return pad_settings.rim_shot_is_used; } + void set_pos_sense_is_used(const bool new_is_used) { pad_settings.pos_sense_is_used = new_is_used; } + bool get_pos_sense_is_used() { return pad_settings.pos_sense_is_used; } + + void set_velocity_threshold(const int new_threshold) + { + pad_settings.velocity_threshold = new_threshold; + sched_init(); + } + int get_velocity_threshold() { return pad_settings.velocity_threshold; } + void set_velocity_sensitivity(const int new_velocity) + { + pad_settings.velocity_sensitivity = new_velocity; + sched_init(); + } + int get_velocity_sensitivity() { return pad_settings.velocity_sensitivity; } + void set_pos_threshold(const int new_threshold) + { + pad_settings.pos_threshold = new_threshold; + sched_init(); + } + int get_pos_threshold() { return pad_settings.pos_threshold; } + void set_pos_sensitivity(const int new_velocity) + { + pad_settings.pos_sensitivity = new_velocity; + sched_init(); + } + int get_pos_sensitivity() { return pad_settings.pos_sensitivity; } + void set_rim_pos_threshold(const int new_threshold) + { + pad_settings.rim_pos_threshold = new_threshold; + sched_init(); + } + int get_rim_pos_threshold() { return pad_settings.rim_pos_threshold; } + void set_rim_pos_sensitivity(const int new_velocity) + { + pad_settings.rim_pos_sensitivity = new_velocity; + sched_init(); + } + int get_rim_pos_sensitivity() { return pad_settings.rim_pos_sensitivity; } + void set_mask_time(const int new_time_ms) + { + pad_settings.mask_time_ms = new_time_ms; + sched_init(); + } + int get_mask_time() { return pad_settings.mask_time_ms; } + void set_rim_shot_threshold(const int new_threshold) + { + pad_settings.rim_shot_threshold = new_threshold; + sched_init(); + } + int get_rim_shot_threshold() { return pad_settings.rim_shot_threshold; } + void set_rim_shot_boost(const int new_boost) + { + pad_settings.rim_shot_boost = new_boost; + sched_init(); + } + int get_rim_shot_boost() { return pad_settings.rim_shot_boost; } + void set_curve(const Ecurvetype new_curve) + { + pad_settings.curve_type = new_curve; + sched_init(); + } + Ecurvetype get_curve() { return pad_settings.curve_type; } + void set_cancellation(const int new_cancel) + { + pad_settings.cancellation = new_cancel; + sched_init(); + } + int get_cancellation() { return pad_settings.cancellation; } + void set_coupled_pad_idx(const int new_idx) + { + pad_settings.coupled_pad_idx = new_idx; + sched_init(); + } + int get_coupled_pad_idx() { return pad_settings.coupled_pad_idx; } + void set_head_sensor_coupling(const bool new_coupling) + { + use_head_sensor_coupling = new_coupling; + sched_init(); + } + void set_use_second_rim(const bool new_sec_rim) + { + use_second_rim = new_sec_rim; + sched_init(); + } + + float get_cancellation_factor() { return cancellation_factor; } + bool get_is_control() { return pad_settings.is_control; } + bool get_is_rim_switch() { return pad_settings.is_rim_switch; } + bool get_is_rim_switch_on() { return sSensor[0].rim_switch_on_cnt > 0; } + + // definitions which can be used outside the pad class, too + static const int control_midi_hysteresis = ADC_MAX_NOISE_AMPL / 2; // MIDI hysteresis for the controller to suppress noise + static const int hi_hat_is_open_MIDI_threshold = 100; // MIDI values smaller than the limit value are "open hi-hat" + + protected: + struct Epadsettings + { + Epadtype pad_type; + int velocity_threshold; // 0..31 + int velocity_sensitivity; // 0..31, high values give higher sensitivity + int mask_time_ms; // 0..31 (ms) + int pos_threshold; // 0..31 + int pos_sensitivity; // 0..31, high values give higher sensitivity + int rim_pos_threshold; // 0..31 + int rim_pos_sensitivity; // 0..31, high values give higher sensitivity + int rim_shot_threshold; // 0..31 + int rim_shot_boost; // 0..31 + int cancellation; // 0..31 + int coupled_pad_idx; // 0..[number of pads - 1] + bool is_control; // whether it is a normal pad or a hi-hat control pedal + bool is_rim_switch; // whether the pad supports rim/egde sensor based on a physical switch (i.e. no piezo) + bool pos_sense_is_used; // switches positional sensing support on or off + bool rim_shot_is_used; // switches rim shot detection on or off + Ecurvetype curve_type; + float first_peak_diff_thresh_db; + float scan_time_ms; + float pre_scan_time_ms; + float mask_time_decay_fact_db; + float decay_est_delay_ms; + float decay_est_len_ms; + float decay_est_fact_db; + float decay_fact_db; + float decay_len1_ms, decay_len2_ms, decay_len3_ms; + float decay_grad_fact1, decay_grad_fact2, decay_grad_fact3; + float pos_low_pass_cutoff; + bool pos_invert; + bool rim_use_low_freq_bp; + float rim_shot_window_len_ms; + float clip_comp_ampmap_step; + }; + + void apply_preset_pad_settings(); + void manage_delayed_initialization(); + void initialize(); // this function should not be called directly but use sched_init() instead + void sched_init() { init_delay_cnt = init_delay_value; }; // schedule initialization function (for delayed initialization) + const float init_delay_value_s = 0.2; // init delay value in seconds + static const int max_length_ampmap = 20; // maxmimum number of amplification mappings for clipping compensation + static const int ctrl_history_len = 10; // (MUST BE AN EVEN VALUE) control history length; the longer, the more noise reduction but more delay + + // band-pass filter coefficients (they are constant and must not be changed) + const int bp_filt_len = 5; + const float bp_filt_a[4] = {0.6704579059531744f, -2.930427216820138f, 4.846289804288025f, -3.586239808116909f}; + const float bp_filt_b[5] = {0.01658193166930305f, 0.0f, -0.0331638633386061f, 0.0f, 0.01658193166930305f}; + const float rim_bp_low_freq_a[4] = {0.8008026466657076f, -3.348944421626415f, 5.292099516163272f, -3.743650976941178f}; + const float rim_bp_low_freq_b[5] = {0.005542717210280682f, 0.0f, -0.01108543442056136f, 0.0f, 0.005542717210280682f}; + const float rim_bp_high_freq_a[4] = {0.8008026466657077f, -3.021126408169798f, 4.637919662489649f, -3.377196335768073f}; + const float rim_bp_high_freq_b[5] = {0.00554271721028068f, 0.0f, -0.01108543442056136f, 0.0f, 0.00554271721028068f}; + const int x_filt_delay = 5; + + // ADC noise scaling after band-pass filtering (e.g., for the Teensy ADC the noise has high + // energy at high frequencies which are cut by the band-pass filter) -> hardware dependend parameter #ifdef TEENSYDUINO - const float ADC_noise_peak_velocity_scaling = 1.0f / 6.0f; + const float ADC_noise_peak_velocity_scaling = 1.0f / 6.0f; #else -// TODO set the correct value for the ESP32 hardware -> as a first approximation, use the Teensy value... -const float ADC_noise_peak_velocity_scaling = 1.0f / 6.0f; + // TODO set the correct value for the ESP32 hardware -> as a first approximation, use the Teensy value... + const float ADC_noise_peak_velocity_scaling = 1.0f / 6.0f; #endif - float* decay = nullptr; - float* lp_filt_b = nullptr; - float* rim_bp_filt_a = nullptr; - float* rim_bp_filt_b = nullptr; - float* ctrl_hist = nullptr; - - struct SResults - { - int midi_velocity; - int midi_pos; - int first_peak_delay; - float first_peak_sub_sample; - Erimstate rim_state; - }; - - struct SSensor - { - FastWriteFIFO x_sq_hist; - FastWriteFIFO overload_hist; - FastWriteFIFO x_low_hist; - FastWriteFIFO x_rim_switch_hist; - FastWriteFIFO x_sec_rim_switch_hist; - float* bp_filt_hist_x = nullptr; - float* bp_filt_hist_y = nullptr; - float* lp_filt_hist = nullptr; - float* rim_bp_hist_x = nullptr; - float* rim_bp_hist_y = nullptr; - float* x_rim_hist = nullptr; - - int mask_back_cnt; - int decay_back_cnt; - int scan_time_cnt; - float max_x_filt_val; - float max_mask_x_filt_val; - float first_peak_val; - float peak_val; - bool was_above_threshold; - bool was_peak_found; - bool was_pos_sense_ready; - bool was_rim_shot_ready; - bool is_overloaded_state; - float decay_scaling; - int decay_pow_est_start_cnt; - int decay_pow_est_cnt; - float decay_pow_est_sum; - int pos_sense_cnt; - int x_low_hist_idx; - int x_rim_hist_idx; - int rim_switch_on_cnt; - int rim_shot_cnt; - Erimstate rim_state; - float pos_sense_metric; - float rim_pos_sense_metric; - SResults sResults; - }; - - SSensor sSensor[MAX_NUM_PAD_INPUTS]; - bool use_head_sensor_coupling; - bool use_second_rim; - int Fs; - int number_inputs; - int number_head_sensors; - int init_delay_cnt; - int init_delay_value; - int overload_hist_len; - int max_num_overloads; - int length_ampmap; - float amplification_mapping[max_length_ampmap]; - int scan_time; - int pre_scan_time; - int total_scan_time; - int decay_len, decay_len1, decay_len2, decay_len3; - int mask_time; - int x_sq_hist_len; - float threshold; - float velocity_factor; - float velocity_exponent; - float velocity_offset; - float pos_threshold; - float pos_range_db; - float rim_pos_threshold; - float rim_pos_range_db; - float control_threshold; - float control_range; - float first_peak_diff_thresh; - int decay_est_delay; - int decay_est_len; - float decay_est_fact; - float decay_fact; - float decay_mask_fact; - int x_rim_hist_len; - int rim_shot_window_len; - float rim_shot_threshold; - float rim_shot_boost; - float rim_switch_threshold; - int rim_switch_on_cnt_thresh; - int lp_filt_len; - int x_low_hist_len; - Epadsettings pad_settings; - int midi_note; - int midi_note_rim; - int midi_note_open; - int midi_note_open_rim; - int midi_ctrl_ch; - int ctrl_history_len_half; - float ctrl_velocity_threshold; - float ctrl_velocity_range_fact; - int prev_ctrl_value; - float cancellation_factor; - float rim_max_power_low_limit; - int multiple_sensor_cnt; - float get_pos_x0; - float get_pos_y0; - float get_pos_x1; - float get_pos_y1; - float get_pos_x2; - float get_pos_y2; - float get_pos_x0_sq_plus_y0_sq; - float get_pos_a1; - float get_pos_b1; - float get_pos_a2; - float get_pos_b2; - float get_pos_div1_fact; - float get_pos_div2_fact; - float get_pos_rim_radius; - - // real-time debugging support + float* decay = nullptr; + float* lp_filt_b = nullptr; + float* rim_bp_filt_a = nullptr; + float* rim_bp_filt_b = nullptr; + float* ctrl_hist = nullptr; + + struct SResults + { + int midi_velocity; + int midi_pos; + int first_peak_delay; + float first_peak_sub_sample; + Erimstate rim_state; + }; + + struct SSensor + { + FastWriteFIFO x_sq_hist; + FastWriteFIFO overload_hist; + FastWriteFIFO x_low_hist; + FastWriteFIFO x_rim_switch_hist; + FastWriteFIFO x_sec_rim_switch_hist; + float* bp_filt_hist_x = nullptr; + float* bp_filt_hist_y = nullptr; + float* lp_filt_hist = nullptr; + float* rim_bp_hist_x = nullptr; + float* rim_bp_hist_y = nullptr; + float* x_rim_hist = nullptr; + + int mask_back_cnt; + int decay_back_cnt; + int scan_time_cnt; + float max_x_filt_val; + float max_mask_x_filt_val; + float first_peak_val; + float peak_val; + bool was_above_threshold; + bool was_peak_found; + bool was_pos_sense_ready; + bool was_rim_shot_ready; + bool is_overloaded_state; + float decay_scaling; + int decay_pow_est_start_cnt; + int decay_pow_est_cnt; + float decay_pow_est_sum; + int pos_sense_cnt; + int x_low_hist_idx; + int x_rim_hist_idx; + int rim_switch_on_cnt; + int rim_shot_cnt; + Erimstate rim_state; + float pos_sense_metric; + float rim_pos_sense_metric; + SResults sResults; + }; + + SSensor sSensor[MAX_NUM_PAD_INPUTS]; + bool use_head_sensor_coupling; + bool use_second_rim; + int Fs; + int number_inputs; + int number_head_sensors; + int init_delay_cnt; + int init_delay_value; + int overload_hist_len; + int max_num_overloads; + int length_ampmap; + float amplification_mapping[max_length_ampmap]; + int scan_time; + int pre_scan_time; + int total_scan_time; + int decay_len, decay_len1, decay_len2, decay_len3; + int mask_time; + int x_sq_hist_len; + float threshold; + float velocity_factor; + float velocity_exponent; + float velocity_offset; + float pos_threshold; + float pos_range_db; + float rim_pos_threshold; + float rim_pos_range_db; + float control_threshold; + float control_range; + float first_peak_diff_thresh; + int decay_est_delay; + int decay_est_len; + float decay_est_fact; + float decay_fact; + float decay_mask_fact; + int x_rim_hist_len; + int rim_shot_window_len; + float rim_shot_threshold; + float rim_shot_boost; + float rim_switch_threshold; + int rim_switch_on_cnt_thresh; + int lp_filt_len; + int x_low_hist_len; + Epadsettings pad_settings; + int midi_note; + int midi_note_rim; + int midi_note_open; + int midi_note_open_rim; + int midi_ctrl_ch; + int ctrl_history_len_half; + float ctrl_velocity_threshold; + float ctrl_velocity_range_fact; + int prev_ctrl_value; + float cancellation_factor; + float rim_max_power_low_limit; + int multiple_sensor_cnt; + float get_pos_x0; + float get_pos_y0; + float get_pos_x1; + float get_pos_y1; + float get_pos_x2; + float get_pos_y2; + float get_pos_x0_sq_plus_y0_sq; + float get_pos_a1; + float get_pos_b1; + float get_pos_a2; + float get_pos_b2; + float get_pos_div1_fact; + float get_pos_div2_fact; + float get_pos_rim_radius; + + // real-time debugging support #ifdef USE_SERIAL_DEBUG_PLOTTING -# ifdef TEENSYDUINO // MIDI+Serial possible with the Teensy - static const int debug_buffer_size = 500; -# else -# undef USE_MIDI // only MIDI or Serial possible with the ESP32 - static const int debug_buffer_size = 400; // smaller size needed for ESP32 -# endif - static const int number_debug_buffers = 4; - int debug_buffer_idx = 0; - int debug_out_cnt = 0; - float debug_buffer[number_debug_buffers][debug_buffer_size]; - - void DEBUG_ADD_VALUES ( const float value0, - const float value1, - const float value2, - const float value3 ) +# ifdef TEENSYDUINO // MIDI+Serial possible with the Teensy + static const int debug_buffer_size = 500; +# else +# undef USE_MIDI // only MIDI or Serial possible with the ESP32 + static const int debug_buffer_size = 400; // smaller size needed for ESP32 +# endif + static const int number_debug_buffers = 4; + int debug_buffer_idx = 0; + int debug_out_cnt = 0; + float debug_buffer[number_debug_buffers][debug_buffer_size]; + + void DEBUG_ADD_VALUES(const float value0, + const float value1, + const float value2, + const float value3) + { + debug_buffer[0][debug_buffer_idx] = value0; + debug_buffer[1][debug_buffer_idx] = value1; + debug_buffer[2][debug_buffer_idx] = value2; + debug_buffer[3][debug_buffer_idx] = value3; + debug_buffer_idx++; + + if (debug_buffer_idx == debug_buffer_size) { - debug_buffer[0][debug_buffer_idx] = value0; - debug_buffer[1][debug_buffer_idx] = value1; - debug_buffer[2][debug_buffer_idx] = value2; - debug_buffer[3][debug_buffer_idx] = value3; - debug_buffer_idx++; - - if ( debug_buffer_idx == debug_buffer_size ) - { - debug_buffer_idx = 0; - } + debug_buffer_idx = 0; + } - if ( debug_out_cnt == 1 ) + if (debug_out_cnt == 1) + { + String serial_print; + for (int i = debug_buffer_idx; i < debug_buffer_idx + debug_buffer_size; i++) { - String serial_print; - for ( int i = debug_buffer_idx; i < debug_buffer_idx + debug_buffer_size; i++ ) + for (int j = 0; j < number_debug_buffers; j++) { - for ( int j = 0; j < number_debug_buffers; j++ ) - { - serial_print += String ( 10.0f * log10 ( max ( 1e-3f, debug_buffer[j][i % debug_buffer_size] ) ) ) + "\t"; - } - serial_print += "\n"; + serial_print += String(10.0f * log10(max(1e-3f, debug_buffer[j][i % debug_buffer_size]))) + "\t"; } - Serial.println ( serial_print ); - } - - if ( debug_out_cnt > 0 ) - { - debug_out_cnt--; + serial_print += "\n"; } + Serial.println(serial_print); } - void DEBUG_START_PLOTTING() + if (debug_out_cnt > 0) { - // set debug count to have the peak shortly after the start of the range - debug_out_cnt = debug_buffer_size - debug_buffer_size / 4; + debug_out_cnt--; } + } + + void DEBUG_START_PLOTTING() + { + // set debug count to have the peak shortly after the start of the range + debug_out_cnt = debug_buffer_size - debug_buffer_size / 4; + } #else - void DEBUG_ADD_VALUES ( const float, const float, const float, const float ) {} - void DEBUG_START_PLOTTING() {} + void DEBUG_ADD_VALUES(const float, const float, const float, const float) + { + } + void DEBUG_START_PLOTTING() {} #endif }; // constant definitions - const int Fs = 8000; // this is the most fundamental system parameter: system sampling rate - const float dc_offset_est_len_s = 1.25f; // length of initial DC offset estimation in seconds - const int samplerate_max_cnt_len_s = 1.25f; // time interval for sampling rate estimation in seconds - const int samplerate_max_error_Hz = 200; // tolerate a sample rate deviation of 200 Hz - const float dc_offset_max_rel_error = 0.25f; // DC offset limit from ADC middle position, where offset is defined relative to ADC maximum value - const int cancel_time_ms = 30; // on same stand approx. 10 ms + some margin (20 ms) - const float overload_LED_on_time_s = 0.25f; // minimum overload LED on time (e.g., 250 ms) - const float error_LED_blink_time_s = 0.25f; // LED blink time on error (e.g., 250 ms) + const int Fs = 8000; // this is the most fundamental system parameter: system sampling rate + const float dc_offset_est_len_s = 1.25f; // length of initial DC offset estimation in seconds + const int samplerate_max_cnt_len_s = 1.25f; // time interval for sampling rate estimation in seconds + const int samplerate_max_error_Hz = 200; // tolerate a sample rate deviation of 200 Hz + const float dc_offset_max_rel_error = 0.25f; // DC offset limit from ADC middle position, where offset is defined relative to ADC maximum value + const int cancel_time_ms = 30; // on same stand approx. 10 ms + some margin (20 ms) + const float overload_LED_on_time_s = 0.25f; // minimum overload LED on time (e.g., 250 ms) + const float error_LED_blink_time_s = 0.25f; // LED blink time on error (e.g., 250 ms) #ifdef ESP_PLATFORM // for ESP we have a coupling of ADC inputs so that a hi-hat control pedal movement may // influence the DC offset of some pad inputs, therefore we need to adapt faster to // compensate for this - const int dc_offset_iir_tau_seconds = 5; // DC offset update IIR filter tau in seconds + const int dc_offset_iir_tau_seconds = 5; // DC offset update IIR filter tau in seconds #else const int dc_offset_iir_tau_seconds = 30; // DC offset update IIR filter tau in seconds #endif Edrumulus_hardware edrumulus_hardware; - int number_pads; - bool any_coupling_used; - int coupled_pad_idx_primary; - int coupled_pad_idx_secondary; - int coupled_pad_idx_rim_primary; - int coupled_pad_idx_rim_secondary; - int number_inputs[MAX_NUM_PADS]; - int analog_pin[MAX_NUM_PADS][MAX_NUM_PAD_INPUTS]; - float sample[MAX_NUM_PAD_INPUTS]; - float stored_sample_coupled_head[MAX_NUM_PAD_INPUTS]; - float stored_sample_coupled_rim[MAX_NUM_PAD_INPUTS]; - int overload_detected[MAX_NUM_PAD_INPUTS]; - int stored_overload_detected_coupled_head[MAX_NUM_PAD_INPUTS]; - int stored_overload_detected_coupled_rim[MAX_NUM_PAD_INPUTS]; - double dc_offset[MAX_NUM_PADS][MAX_NUM_PAD_INPUTS]; // must be double type for IIR filter - int sample_org[MAX_NUM_PADS][MAX_NUM_PAD_INPUTS]; - int dc_offset_est_len; - float dc_offset_iir_gamma; - float dc_offset_iir_one_minus_gamma; - int spike_cancel_level; - int overload_LED_cnt; - int overload_LED_on_time; - int error_LED_cnt; - int error_LED_blink_time; - bool status_is_overload; - bool status_is_error; - int dc_offset_error_channel; - int samplerate_max_cnt; - int samplerate_prev_micros_cnt; - unsigned long samplerate_prev_micros; - int dc_offset_min_limit; - int dc_offset_max_limit; - Pad pad[MAX_NUM_PADS]; - bool peak_found[MAX_NUM_PADS]; - bool control_found[MAX_NUM_PADS]; - int midi_velocity[MAX_NUM_PADS]; - int midi_pos[MAX_NUM_PADS]; - int midi_ctrl_value[MAX_NUM_PADS]; - Erimstate rim_state[MAX_NUM_PADS]; - bool is_choke_on[MAX_NUM_PADS]; - bool is_choke_off[MAX_NUM_PADS]; - int cancel_num_samples; - int cancel_cnt; - int cancel_MIDI_velocity; - int cancel_pad_index; + int number_pads; + bool any_coupling_used; + int coupled_pad_idx_primary; + int coupled_pad_idx_secondary; + int coupled_pad_idx_rim_primary; + int coupled_pad_idx_rim_secondary; + int number_inputs[MAX_NUM_PADS]; + int analog_pin[MAX_NUM_PADS][MAX_NUM_PAD_INPUTS]; + float sample[MAX_NUM_PAD_INPUTS]; + float stored_sample_coupled_head[MAX_NUM_PAD_INPUTS]; + float stored_sample_coupled_rim[MAX_NUM_PAD_INPUTS]; + int overload_detected[MAX_NUM_PAD_INPUTS]; + int stored_overload_detected_coupled_head[MAX_NUM_PAD_INPUTS]; + int stored_overload_detected_coupled_rim[MAX_NUM_PAD_INPUTS]; + double dc_offset[MAX_NUM_PADS][MAX_NUM_PAD_INPUTS]; // must be double type for IIR filter + int sample_org[MAX_NUM_PADS][MAX_NUM_PAD_INPUTS]; + int dc_offset_est_len; + float dc_offset_iir_gamma; + float dc_offset_iir_one_minus_gamma; + int spike_cancel_level; + int overload_LED_cnt; + int overload_LED_on_time; + int error_LED_cnt; + int error_LED_blink_time; + bool status_is_overload; + bool status_is_error; + int dc_offset_error_channel; + int samplerate_max_cnt; + int samplerate_prev_micros_cnt; + unsigned long samplerate_prev_micros; + int dc_offset_min_limit; + int dc_offset_max_limit; + Pad pad[MAX_NUM_PADS]; + bool peak_found[MAX_NUM_PADS]; + bool control_found[MAX_NUM_PADS]; + int midi_velocity[MAX_NUM_PADS]; + int midi_pos[MAX_NUM_PADS]; + int midi_ctrl_value[MAX_NUM_PADS]; + Erimstate rim_state[MAX_NUM_PADS]; + bool is_choke_on[MAX_NUM_PADS]; + bool is_choke_off[MAX_NUM_PADS]; + int cancel_num_samples; + int cancel_cnt; + int cancel_MIDI_velocity; + int cancel_pad_index; }; diff --git a/edrumulus.ino b/edrumulus.ino index 22dff26..03e9517 100644 --- a/edrumulus.ino +++ b/edrumulus.ino @@ -21,37 +21,36 @@ // For older prototypes or custom implementations, simply change the GPIO numbers in the table below // to match your hardware (note that the GPIO assignment of Prototype 2 is the same as Prototype 4). // analog pins setup: snare | kick | hi-hat | hi-hat-ctrl | crash | tom1 | ride | tom2 | tom3 -static int analog_pins4[] = { 36, 33, 32, 25, 34, 39, 27, 12, 15 }; -static int analog_pins_rimshot4[] = { 35, -1, 26, -1, 14, -1, 13, -1, -1 }; +static int analog_pins4[] = {36, 33, 32, 25, 34, 39, 27, 12, 15}; +static int analog_pins_rimshot4[] = {35, -1, 26, -1, 14, -1, 13, -1, -1}; // if you want to use less number of pads, simply adjust number_pads4 value -//const int number_pads4 = sizeof ( analog_pins4 ) / sizeof ( int ); // example: use all inputs defined in analog_pins4 +// const int number_pads4 = sizeof ( analog_pins4 ) / sizeof ( int ); // example: use all inputs defined in analog_pins4 const int number_pads4 = 8; // example: do not use tom3 and shrink number of pads from 9 to 8 -//const int number_pads4 = 1; // example: just one single pad - +// const int number_pads4 = 1; // example: just one single pad #include "edrumulus.h" #ifdef USE_MIDI -# ifdef ESP_PLATFORM -# include -# ifdef USE_TINYUSB -# include - Adafruit_USBD_MIDI usb_midi; - MIDI_CREATE_INSTANCE(Adafruit_USBD_MIDI, usb_midi, MIDI); -# else - MIDI_CREATE_DEFAULT_INSTANCE(); +# ifdef ESP_PLATFORM +# include +# ifdef USE_TINYUSB +# include +Adafruit_USBD_MIDI usb_midi; +MIDI_CREATE_INSTANCE(Adafruit_USBD_MIDI, usb_midi, MIDI); +# else +MIDI_CREATE_DEFAULT_INSTANCE(); +# endif +# define MYMIDI MIDI +# define MIDI_CONTROL_CHANGE_TYPE midi::ControlChange +# define MIDI_SEND_AFTER_TOUCH sendAfterTouch +# define MIDI_SERIAL 38400 +# endif +# ifdef TEENSYDUINO +# define MYMIDI usbMIDI +# define MIDI_CONTROL_CHANGE_TYPE usbMIDI.ControlChange +# define MIDI_SEND_AFTER_TOUCH sendAfterTouchPoly # endif -# define MYMIDI MIDI -# define MIDI_CONTROL_CHANGE_TYPE midi::ControlChange -# define MIDI_SEND_AFTER_TOUCH sendAfterTouch -# define MIDI_SERIAL 38400 -# endif -# ifdef TEENSYDUINO -# define MYMIDI usbMIDI -# define MIDI_CONTROL_CHANGE_TYPE usbMIDI.ControlChange -# define MIDI_SEND_AFTER_TOUCH sendAfterTouchPoly -# endif #endif // local variables and defines @@ -59,103 +58,101 @@ Edrumulus edrumulus; const int midi_channel = 10; // default for edrums is 10 const int hihat_pad_idx = 2; // this definition should not be changed const int hihatctrl_pad_idx = 3; // this definition should not be changed -int number_pads = number_pads4; // initialization value, may be overwritten by get_prototype_pins() -int status_LED_pin = 0; // initialization value, will be set in get_prototype_pins() -bool is_status_LED_on = false; // initialization value -int selected_pad = 0; // initialization value +int number_pads = number_pads4; // initialization value, may be overwritten by get_prototype_pins() +int status_LED_pin = 0; // initialization value, will be set in get_prototype_pins() +bool is_status_LED_on = false; // initialization value +int selected_pad = 0; // initialization value void setup() { // get the pin-to-pad assignments int* analog_pins = analog_pins4; // initialize with the default setup int* analog_pins_rimshot = analog_pins_rimshot4; // initialize with the default setup - const int prototype = Edrumulus_hardware::get_prototype_pins ( &analog_pins, - &analog_pins_rimshot, - &number_pads, - &status_LED_pin ); + const int prototype = Edrumulus_hardware::get_prototype_pins(&analog_pins, + &analog_pins_rimshot, + &number_pads, + &status_LED_pin); // initialize GPIO port for status LED and set it to on during setup - pinMode ( status_LED_pin, OUTPUT ); - digitalWrite ( status_LED_pin, HIGH ); + pinMode(status_LED_pin, OUTPUT); + digitalWrite(status_LED_pin, HIGH); -#if defined ( USE_SERIAL_DEBUG_PLOTTING ) && defined ( ESP_PLATFORM ) - number_pads = min ( number_pads, 7 ); // only max. 7 pads are supported for ESP32 serial debug plotting +#if defined(USE_SERIAL_DEBUG_PLOTTING) && defined(ESP_PLATFORM) + number_pads = min(number_pads, 7); // only max. 7 pads are supported for ESP32 serial debug plotting #endif #ifdef USE_MIDI -# ifdef USE_TINYUSB - TinyUSBDevice.setProductDescriptor ( "Edrumulus" ); -# endif +# ifdef USE_TINYUSB + TinyUSBDevice.setProductDescriptor("Edrumulus"); +# endif MYMIDI.begin(); #endif #ifdef MIDI_SERIAL - if ( prototype == 5 ) + if (prototype == 5) { - Serial.begin ( 115200 ); // faster communication on prototype 5 + Serial.begin(115200); // faster communication on prototype 5 } else { - Serial.begin ( MIDI_SERIAL ); + Serial.begin(MIDI_SERIAL); } #else - Serial.begin ( 115200 ); + Serial.begin(115200); #endif - edrumulus.setup ( number_pads, analog_pins, analog_pins_rimshot ); + edrumulus.setup(number_pads, analog_pins, analog_pins_rimshot); read_settings(); - digitalWrite ( status_LED_pin, LOW ); // set board LED to low right after setup is done + digitalWrite(status_LED_pin, LOW); // set board LED to low right after setup is done } - void preset_settings() { // default MIDI note assignments - edrumulus.set_midi_notes ( 0, 38, 40 ); // snare - edrumulus.set_midi_notes ( 1, 36, 36 ); // kick - edrumulus.set_midi_notes ( hihat_pad_idx, 22 /*42*/, 22 ); - edrumulus.set_midi_notes_open ( hihat_pad_idx, 26 /*46*/, 26 ); - edrumulus.set_midi_notes ( hihatctrl_pad_idx, 44, 44 ); // Hi-Hat pedal hit - edrumulus.set_midi_notes ( 4, 49, 55 ); // crash - edrumulus.set_midi_notes ( 5, 48, 50 ); // tom 1 - edrumulus.set_midi_notes ( 6, 51, 53 /*59*/ ); // ride (edge: 59, bell: 53) - edrumulus.set_midi_notes ( 7, 45, 47 ); // tom 2 - edrumulus.set_midi_notes ( 8, 43, 58 ); // tom 3 + edrumulus.set_midi_notes(0, 38, 40); // snare + edrumulus.set_midi_notes(1, 36, 36); // kick + edrumulus.set_midi_notes(hihat_pad_idx, 22 /*42*/, 22); + edrumulus.set_midi_notes_open(hihat_pad_idx, 26 /*46*/, 26); + edrumulus.set_midi_notes(hihatctrl_pad_idx, 44, 44); // Hi-Hat pedal hit + edrumulus.set_midi_notes(4, 49, 55); // crash + edrumulus.set_midi_notes(5, 48, 50); // tom 1 + edrumulus.set_midi_notes(6, 51, 53 /*59*/); // ride (edge: 59, bell: 53) + edrumulus.set_midi_notes(7, 45, 47); // tom 2 + edrumulus.set_midi_notes(8, 43, 58); // tom 3 // default drum kit setup - edrumulus.set_pad_type ( 0, Edrumulus::PD8 ); // snare - edrumulus.set_pad_type ( 1, Edrumulus::KD7 ); // kick - edrumulus.set_pad_type ( 2, Edrumulus::PD6 ); // Hi-Hat - edrumulus.set_pad_type ( 3, Edrumulus::FD8 ); // Hi-Hat-ctrl - edrumulus.set_pad_type ( 4, Edrumulus::CY6 ); // crash - edrumulus.set_pad_type ( 5, Edrumulus::TP80 ); // tom 1 - edrumulus.set_pad_type ( 6, Edrumulus::CY8 ); // ride - edrumulus.set_pad_type ( 7, Edrumulus::TP80 ); // tom 2 - edrumulus.set_pad_type ( 8, Edrumulus::TP80 ); // tom 3 + edrumulus.set_pad_type(0, Edrumulus::PD8); // snare + edrumulus.set_pad_type(1, Edrumulus::KD7); // kick + edrumulus.set_pad_type(2, Edrumulus::PD6); // Hi-Hat + edrumulus.set_pad_type(3, Edrumulus::FD8); // Hi-Hat-ctrl + edrumulus.set_pad_type(4, Edrumulus::CY6); // crash + edrumulus.set_pad_type(5, Edrumulus::TP80); // tom 1 + edrumulus.set_pad_type(6, Edrumulus::CY8); // ride + edrumulus.set_pad_type(7, Edrumulus::TP80); // tom 2 + edrumulus.set_pad_type(8, Edrumulus::TP80); // tom 3 } - void loop() { // this function is blocking at the system sampling rate edrumulus.process(); // status LED handling - if ( edrumulus.get_status_is_overload() || edrumulus.get_status_is_error() ) + if (edrumulus.get_status_is_overload() || edrumulus.get_status_is_error()) { - if ( !is_status_LED_on ) + if (!is_status_LED_on) { - digitalWrite ( status_LED_pin, HIGH ); + digitalWrite(status_LED_pin, HIGH); is_status_LED_on = true; #ifdef USE_MIDI - if ( edrumulus.get_status_is_error() ) + if (edrumulus.get_status_is_error()) { const int dc_offset_error_channel = edrumulus.get_status_dc_offset_error_channel(); - if ( dc_offset_error_channel >= 0 ) + if (dc_offset_error_channel >= 0) { - MYMIDI.sendNoteOff ( 125, 64 + dc_offset_error_channel, 1 ); // > 63 means DC offset error and pad/input index is coded in one value + MYMIDI.sendNoteOff(125, 64 + dc_offset_error_channel, 1); // > 63 means DC offset error and pad/input index is coded in one value } else { - MYMIDI.sendNoteOff ( 125, 1, 1 ); // 1 means to set error state + MYMIDI.sendNoteOff(125, 1, 1); // 1 means to set error state } } #endif @@ -163,392 +160,389 @@ void loop() } else { - if ( is_status_LED_on ) + if (is_status_LED_on) { - digitalWrite ( status_LED_pin, LOW ); + digitalWrite(status_LED_pin, LOW); is_status_LED_on = false; #ifdef USE_MIDI - MYMIDI.sendNoteOff ( 125, 0, 1 ); // 0 means that all errors are cleared + MYMIDI.sendNoteOff(125, 0, 1); // 0 means that all errors are cleared #endif } } #ifdef USE_MIDI // send MIDI note to drum synthesizer - for ( int pad_idx = 0; pad_idx < number_pads; pad_idx++ ) + for (int pad_idx = 0; pad_idx < number_pads; pad_idx++) { - if ( edrumulus.get_peak_found ( pad_idx ) ) + if (edrumulus.get_peak_found(pad_idx)) { // get current MIDI note and velocity (maybe note will be overwritten later on) - const int midi_velocity = edrumulus.get_midi_velocity ( pad_idx ); - int midi_note = edrumulus.get_midi_note ( pad_idx ); + const int midi_velocity = edrumulus.get_midi_velocity(pad_idx); + int midi_note = edrumulus.get_midi_note(pad_idx); // send midi positional control message if positional sensing is enabled for the current pad - if ( edrumulus.get_pos_sense_is_used ( pad_idx ) ) + if (edrumulus.get_pos_sense_is_used(pad_idx)) { - const int midi_pos = edrumulus.get_midi_pos ( pad_idx ); - MYMIDI.sendControlChange ( 16, midi_pos, midi_channel ); // positional sensing + const int midi_pos = edrumulus.get_midi_pos(pad_idx); + MYMIDI.sendControlChange(16, midi_pos, midi_channel); // positional sensing } // send Hi-Hat control message right before each Hi-Hat pad hit - if ( pad_idx == hihat_pad_idx ) + if (pad_idx == hihat_pad_idx) { - const int midi_ctrl_ch = edrumulus.get_midi_ctrl_ch ( hihatctrl_pad_idx ); - const int midi_ctrl_value = edrumulus.get_midi_ctrl_value ( hihatctrl_pad_idx ); - const bool hi_hat_is_open = edrumulus.get_midi_ctrl_is_open ( hihatctrl_pad_idx ); - MYMIDI.sendControlChange ( midi_ctrl_ch, midi_ctrl_value, midi_channel ); + const int midi_ctrl_ch = edrumulus.get_midi_ctrl_ch(hihatctrl_pad_idx); + const int midi_ctrl_value = edrumulus.get_midi_ctrl_value(hihatctrl_pad_idx); + const bool hi_hat_is_open = edrumulus.get_midi_ctrl_is_open(hihatctrl_pad_idx); + MYMIDI.sendControlChange(midi_ctrl_ch, midi_ctrl_value, midi_channel); // if Hi-Hat is open, overwrite MIDI note - if ( hi_hat_is_open ) + if (hi_hat_is_open) { - midi_note = edrumulus.get_midi_note_open ( pad_idx ); + midi_note = edrumulus.get_midi_note_open(pad_idx); } } - MYMIDI.sendNoteOn ( midi_note, midi_velocity, midi_channel ); // (note, velocity, channel) - MYMIDI.sendNoteOff ( midi_note, 0, midi_channel ); // we need a note off + MYMIDI.sendNoteOn(midi_note, midi_velocity, midi_channel); // (note, velocity, channel) + MYMIDI.sendNoteOff(midi_note, 0, midi_channel); // we need a note off } - if ( edrumulus.get_control_found ( pad_idx ) ) + if (edrumulus.get_control_found(pad_idx)) { - const int midi_ctrl_ch = edrumulus.get_midi_ctrl_ch ( pad_idx ); - const int midi_ctrl_value = edrumulus.get_midi_ctrl_value ( pad_idx ); - MYMIDI.sendControlChange ( midi_ctrl_ch, midi_ctrl_value, midi_channel ); + const int midi_ctrl_ch = edrumulus.get_midi_ctrl_ch(pad_idx); + const int midi_ctrl_value = edrumulus.get_midi_ctrl_value(pad_idx); + MYMIDI.sendControlChange(midi_ctrl_ch, midi_ctrl_value, midi_channel); } - if ( edrumulus.get_choke_on_found ( pad_idx ) ) + if (edrumulus.get_choke_on_found(pad_idx)) { // special case: if MIDI note open rim is set to zero, we use NoteOn instead of aftertouch // for cymbal choke (#85), where the MIDI note for NoteOn is defined by MIDI note open norm - if ( edrumulus.get_midi_note_open_rim ( pad_idx ) == 0 ) + if (edrumulus.get_midi_note_open_rim(pad_idx) == 0) { // special case: if grabbed edge found, we send a MIDI NoteOn - const int midi_choke_noteon = edrumulus.get_midi_note_open_norm ( pad_idx ); - MYMIDI.sendNoteOn ( midi_choke_noteon, 127, midi_channel ); - MYMIDI.sendNoteOff ( midi_choke_noteon, 0, midi_channel ); // we need a note off + const int midi_choke_noteon = edrumulus.get_midi_note_open_norm(pad_idx); + MYMIDI.sendNoteOn(midi_choke_noteon, 127, midi_channel); + MYMIDI.sendNoteOff(midi_choke_noteon, 0, midi_channel); // we need a note off } else { // if grabbed edge found, polyphonic aftertouch at 127 is transmitted for all notes of the pad - MYMIDI.MIDI_SEND_AFTER_TOUCH ( edrumulus.get_midi_note_norm ( pad_idx ), 127, midi_channel ); - MYMIDI.MIDI_SEND_AFTER_TOUCH ( edrumulus.get_midi_note_rim ( pad_idx ), 127, midi_channel ); - MYMIDI.MIDI_SEND_AFTER_TOUCH ( edrumulus.get_midi_note_open_norm ( pad_idx ), 127, midi_channel ); - MYMIDI.MIDI_SEND_AFTER_TOUCH ( edrumulus.get_midi_note_open_rim ( pad_idx ), 127, midi_channel ); + MYMIDI.MIDI_SEND_AFTER_TOUCH(edrumulus.get_midi_note_norm(pad_idx), 127, midi_channel); + MYMIDI.MIDI_SEND_AFTER_TOUCH(edrumulus.get_midi_note_rim(pad_idx), 127, midi_channel); + MYMIDI.MIDI_SEND_AFTER_TOUCH(edrumulus.get_midi_note_open_norm(pad_idx), 127, midi_channel); + MYMIDI.MIDI_SEND_AFTER_TOUCH(edrumulus.get_midi_note_open_rim(pad_idx), 127, midi_channel); } } - else if ( edrumulus.get_choke_off_found ( pad_idx ) ) + else if (edrumulus.get_choke_off_found(pad_idx)) { // if released edge found, polyphonic aftertouch at 0 is transmitted for all notes of the pad - MYMIDI.MIDI_SEND_AFTER_TOUCH ( edrumulus.get_midi_note_norm ( pad_idx ), 0, midi_channel ); - MYMIDI.MIDI_SEND_AFTER_TOUCH ( edrumulus.get_midi_note_rim ( pad_idx ), 0, midi_channel ); - MYMIDI.MIDI_SEND_AFTER_TOUCH ( edrumulus.get_midi_note_open_norm ( pad_idx ), 0, midi_channel ); - MYMIDI.MIDI_SEND_AFTER_TOUCH ( edrumulus.get_midi_note_open_rim ( pad_idx ), 0, midi_channel ); + MYMIDI.MIDI_SEND_AFTER_TOUCH(edrumulus.get_midi_note_norm(pad_idx), 0, midi_channel); + MYMIDI.MIDI_SEND_AFTER_TOUCH(edrumulus.get_midi_note_rim(pad_idx), 0, midi_channel); + MYMIDI.MIDI_SEND_AFTER_TOUCH(edrumulus.get_midi_note_open_norm(pad_idx), 0, midi_channel); + MYMIDI.MIDI_SEND_AFTER_TOUCH(edrumulus.get_midi_note_open_rim(pad_idx), 0, midi_channel); } } // receiving MIDI messages to change the pad settings: edrumuluscontrol.m -> loopMIDI -> Hairless MIDI - if ( MYMIDI.read ( midi_channel ) ) + if (MYMIDI.read(midi_channel)) { - if ( MYMIDI.getType() == MIDI_CONTROL_CHANGE_TYPE ) + if (MYMIDI.getType() == MIDI_CONTROL_CHANGE_TYPE) { const int controller = MYMIDI.getData1(); const int value = MYMIDI.getData2(); // controller 102: pad type - if ( controller == 102 ) + if (controller == 102) { - edrumulus.set_pad_type ( selected_pad, static_cast ( value ) ); - edrumulus.write_setting ( selected_pad, 0, value ); + edrumulus.set_pad_type(selected_pad, static_cast(value)); + edrumulus.write_setting(selected_pad, 0, value); // on a pad type change, return all parameters of the selected pad - confirm_setting ( controller, value, true ); + confirm_setting(controller, value, true); } // controller 103: threshold - if ( controller == 103 ) + if (controller == 103) { - edrumulus.set_velocity_threshold ( selected_pad, value ); - edrumulus.write_setting ( selected_pad, 1, value ); - confirm_setting ( controller, value, false ); + edrumulus.set_velocity_threshold(selected_pad, value); + edrumulus.write_setting(selected_pad, 1, value); + confirm_setting(controller, value, false); } // controller 104: sensitivity - if ( controller == 104 ) + if (controller == 104) { - edrumulus.set_velocity_sensitivity ( selected_pad, value ); - edrumulus.write_setting ( selected_pad, 2, value ); - confirm_setting ( controller, value, false ); + edrumulus.set_velocity_sensitivity(selected_pad, value); + edrumulus.write_setting(selected_pad, 2, value); + confirm_setting(controller, value, false); } // controller 105: positional sensing threshold - if ( controller == 105 ) + if (controller == 105) { - edrumulus.set_pos_threshold ( selected_pad, value ); - edrumulus.write_setting ( selected_pad, 3, value ); - confirm_setting ( controller, value, false ); + edrumulus.set_pos_threshold(selected_pad, value); + edrumulus.write_setting(selected_pad, 3, value); + confirm_setting(controller, value, false); } // controller 106: positional sensing sensitivity - if ( controller == 106 ) + if (controller == 106) { - edrumulus.set_pos_sensitivity ( selected_pad, value ); - edrumulus.write_setting ( selected_pad, 4, value ); - confirm_setting ( controller, value, false ); + edrumulus.set_pos_sensitivity(selected_pad, value); + edrumulus.write_setting(selected_pad, 4, value); + confirm_setting(controller, value, false); } // controller 107: rim shot threshold - if ( controller == 107 ) + if (controller == 107) { - edrumulus.set_rim_shot_threshold ( selected_pad, value ); - edrumulus.write_setting ( selected_pad, 5, value ); - confirm_setting ( controller, value, false ); + edrumulus.set_rim_shot_threshold(selected_pad, value); + edrumulus.write_setting(selected_pad, 5, value); + confirm_setting(controller, value, false); } // controller 108: select pad - if ( ( controller == 108 ) && ( value < MAX_NUM_PADS ) ) + if ((controller == 108) && (value < MAX_NUM_PADS)) { selected_pad = value; // on a pad selection, return all parameters of the selected pad - confirm_setting ( controller, value, true ); + confirm_setting(controller, value, true); } // controller 109: MIDI curve type - if ( controller == 109 ) + if (controller == 109) { - edrumulus.set_curve ( selected_pad, static_cast ( value ) ); - edrumulus.write_setting ( selected_pad, 6, value ); - confirm_setting ( controller, value, false ); + edrumulus.set_curve(selected_pad, static_cast(value)); + edrumulus.write_setting(selected_pad, 6, value); + confirm_setting(controller, value, false); } // controller 110: spike cancellation level - if ( controller == 110 ) + if (controller == 110) { - edrumulus.set_spike_cancel_level ( value ); - edrumulus.write_setting ( number_pads, 0, value ); - confirm_setting ( controller, value, false ); + edrumulus.set_spike_cancel_level(value); + edrumulus.write_setting(number_pads, 0, value); + confirm_setting(controller, value, false); } // controller 111: enable/disable rim shot and positional sensing support - if ( controller == 111 ) + if (controller == 111) { - switch ( value ) + switch (value) { case 0: - edrumulus.set_rim_shot_is_used ( selected_pad, false ); - edrumulus.write_setting ( selected_pad, 7, false ); - edrumulus.set_pos_sense_is_used ( selected_pad, false ); - edrumulus.write_setting ( selected_pad, 8, false ); + edrumulus.set_rim_shot_is_used(selected_pad, false); + edrumulus.write_setting(selected_pad, 7, false); + edrumulus.set_pos_sense_is_used(selected_pad, false); + edrumulus.write_setting(selected_pad, 8, false); break; case 1: - edrumulus.set_rim_shot_is_used ( selected_pad, true ); - edrumulus.write_setting ( selected_pad, 7, true ); - edrumulus.set_pos_sense_is_used ( selected_pad, false ); - edrumulus.write_setting ( selected_pad, 8, false ); + edrumulus.set_rim_shot_is_used(selected_pad, true); + edrumulus.write_setting(selected_pad, 7, true); + edrumulus.set_pos_sense_is_used(selected_pad, false); + edrumulus.write_setting(selected_pad, 8, false); break; case 2: - edrumulus.set_rim_shot_is_used ( selected_pad, false ); - edrumulus.write_setting ( selected_pad, 7, false ); - edrumulus.set_pos_sense_is_used ( selected_pad, true ); - edrumulus.write_setting ( selected_pad, 8, true ); + edrumulus.set_rim_shot_is_used(selected_pad, false); + edrumulus.write_setting(selected_pad, 7, false); + edrumulus.set_pos_sense_is_used(selected_pad, true); + edrumulus.write_setting(selected_pad, 8, true); break; case 3: - edrumulus.set_rim_shot_is_used ( selected_pad, true ); - edrumulus.write_setting ( selected_pad, 7, true ); - edrumulus.set_pos_sense_is_used ( selected_pad, true ); - edrumulus.write_setting ( selected_pad, 8, true ); + edrumulus.set_rim_shot_is_used(selected_pad, true); + edrumulus.write_setting(selected_pad, 7, true); + edrumulus.set_pos_sense_is_used(selected_pad, true); + edrumulus.write_setting(selected_pad, 8, true); break; } - confirm_setting ( controller, value, false ); + confirm_setting(controller, value, false); } // controller 112: normal MIDI note - if ( controller == 112 ) + if (controller == 112) { - edrumulus.set_midi_note_norm ( selected_pad, value ); - edrumulus.write_setting ( selected_pad, 9, value ); - confirm_setting ( controller, value, false ); + edrumulus.set_midi_note_norm(selected_pad, value); + edrumulus.write_setting(selected_pad, 9, value); + confirm_setting(controller, value, false); } // controller 113: MIDI note for rim - if ( controller == 113 ) + if (controller == 113) { - edrumulus.set_midi_note_rim ( selected_pad, value ); - edrumulus.write_setting ( selected_pad, 10, value ); - confirm_setting ( controller, value, false ); + edrumulus.set_midi_note_rim(selected_pad, value); + edrumulus.write_setting(selected_pad, 10, value); + confirm_setting(controller, value, false); } // controller 114: cross talk cancellation - if ( controller == 114 ) + if (controller == 114) { - edrumulus.set_cancellation ( selected_pad, value ); - edrumulus.write_setting ( selected_pad, 11, value ); - confirm_setting ( controller, value, false ); + edrumulus.set_cancellation(selected_pad, value); + edrumulus.write_setting(selected_pad, 11, value); + confirm_setting(controller, value, false); } // controller 115: apply preset settings and store these to the EEPROM - if ( controller == 115 ) + if (controller == 115) { preset_settings(); write_all_settings(); - confirm_setting ( controller, value, false ); + confirm_setting(controller, value, false); } // controller 116: normal MIDI note open (Hi-Hat) - if ( controller == 116 ) + if (controller == 116) { - edrumulus.set_midi_note_open_norm ( selected_pad, value ); - edrumulus.write_setting ( selected_pad, 12, value ); - confirm_setting ( controller, value, false ); + edrumulus.set_midi_note_open_norm(selected_pad, value); + edrumulus.write_setting(selected_pad, 12, value); + confirm_setting(controller, value, false); } // controller 117: MIDI note open (Hi-Hat) for rim - if ( controller == 117 ) + if (controller == 117) { - edrumulus.set_midi_note_open_rim ( selected_pad, value ); - edrumulus.write_setting ( selected_pad, 13, value ); - confirm_setting ( controller, value, false ); + edrumulus.set_midi_note_open_rim(selected_pad, value); + edrumulus.write_setting(selected_pad, 13, value); + confirm_setting(controller, value, false); } // controller 118: mask time - if ( controller == 118 ) + if (controller == 118) { - edrumulus.set_mask_time ( selected_pad, value ); - edrumulus.write_setting ( selected_pad, 14, value ); - confirm_setting ( controller, value, false ); + edrumulus.set_mask_time(selected_pad, value); + edrumulus.write_setting(selected_pad, 14, value); + confirm_setting(controller, value, false); } // controller 119: rim shot boost - if ( controller == 119 ) + if (controller == 119) { - edrumulus.set_rim_shot_boost ( selected_pad, value ); - edrumulus.write_setting ( selected_pad, 15, value ); - confirm_setting ( controller, value, false ); + edrumulus.set_rim_shot_boost(selected_pad, value); + edrumulus.write_setting(selected_pad, 15, value); + confirm_setting(controller, value, false); } // controller 120: pad coupling - if ( controller == 120 ) + if (controller == 120) { - edrumulus.set_coupled_pad_idx ( selected_pad, value ); - edrumulus.write_setting ( selected_pad, 16, value ); - confirm_setting ( controller, value, false ); + edrumulus.set_coupled_pad_idx(selected_pad, value); + edrumulus.write_setting(selected_pad, 16, value); + confirm_setting(controller, value, false); } // controller 121: rim positional sensing threshold - if ( controller == 121 ) + if (controller == 121) { - edrumulus.set_rim_pos_threshold ( selected_pad, value ); - edrumulus.write_setting ( selected_pad, 17, value ); - confirm_setting ( controller, value, false ); + edrumulus.set_rim_pos_threshold(selected_pad, value); + edrumulus.write_setting(selected_pad, 17, value); + confirm_setting(controller, value, false); } // controller 122: rim positional sensing sensitivity - if ( controller == 122 ) + if (controller == 122) { - edrumulus.set_rim_pos_sensitivity ( selected_pad, value ); - edrumulus.write_setting ( selected_pad, 18, value ); - confirm_setting ( controller, value, false ); + edrumulus.set_rim_pos_sensitivity(selected_pad, value); + edrumulus.write_setting(selected_pad, 18, value); + confirm_setting(controller, value, false); } } } #endif } - #ifdef USE_MIDI // give feedback to the controller GUI via MIDI Note Off -void confirm_setting ( const int controller, - const int value, - const bool send_all ) +void confirm_setting(const int controller, + const int value, + const bool send_all) { - if ( send_all ) + if (send_all) { // return all parameters of the selected pad - MYMIDI.sendNoteOff ( 102, static_cast ( edrumulus.get_pad_type ( selected_pad ) ), 1 ); - MYMIDI.sendNoteOff ( 103, edrumulus.get_velocity_threshold ( selected_pad ), 1 ); - MYMIDI.sendNoteOff ( 104, edrumulus.get_velocity_sensitivity ( selected_pad ), 1 ); - MYMIDI.sendNoteOff ( 105, edrumulus.get_pos_threshold ( selected_pad ), 1 ); - MYMIDI.sendNoteOff ( 106, edrumulus.get_pos_sensitivity ( selected_pad ), 1 ); - MYMIDI.sendNoteOff ( 107, edrumulus.get_rim_shot_threshold ( selected_pad ), 1 ); - MYMIDI.sendNoteOff ( 108, selected_pad, 1 ); - MYMIDI.sendNoteOff ( 109, static_cast ( edrumulus.get_curve ( selected_pad ) ), 1 ); - MYMIDI.sendNoteOff ( 110, edrumulus.get_spike_cancel_level(), 1 ); - MYMIDI.sendNoteOff ( 111, edrumulus.get_rim_shot_is_used ( selected_pad ) + 2 * edrumulus.get_pos_sense_is_used ( selected_pad ), 1 ); - MYMIDI.sendNoteOff ( 112, edrumulus.get_midi_note_norm ( selected_pad ), 1 ); - MYMIDI.sendNoteOff ( 113, edrumulus.get_midi_note_rim ( selected_pad ), 1 ); - MYMIDI.sendNoteOff ( 114, edrumulus.get_cancellation ( selected_pad ), 1 ); - MYMIDI.sendNoteOff ( 116, edrumulus.get_midi_note_open_norm ( selected_pad ), 1 ); - MYMIDI.sendNoteOff ( 117, edrumulus.get_midi_note_open_rim ( selected_pad ), 1 ); - MYMIDI.sendNoteOff ( 118, edrumulus.get_mask_time ( selected_pad ), 1 ); - MYMIDI.sendNoteOff ( 119, edrumulus.get_rim_shot_boost ( selected_pad ), 1 ); - MYMIDI.sendNoteOff ( 120, edrumulus.get_coupled_pad_idx ( selected_pad ), 1 ); - MYMIDI.sendNoteOff ( 121, edrumulus.get_rim_pos_threshold ( selected_pad ), 1 ); - MYMIDI.sendNoteOff ( 122, edrumulus.get_rim_pos_sensitivity ( selected_pad ), 1 ); + MYMIDI.sendNoteOff(102, static_cast(edrumulus.get_pad_type(selected_pad)), 1); + MYMIDI.sendNoteOff(103, edrumulus.get_velocity_threshold(selected_pad), 1); + MYMIDI.sendNoteOff(104, edrumulus.get_velocity_sensitivity(selected_pad), 1); + MYMIDI.sendNoteOff(105, edrumulus.get_pos_threshold(selected_pad), 1); + MYMIDI.sendNoteOff(106, edrumulus.get_pos_sensitivity(selected_pad), 1); + MYMIDI.sendNoteOff(107, edrumulus.get_rim_shot_threshold(selected_pad), 1); + MYMIDI.sendNoteOff(108, selected_pad, 1); + MYMIDI.sendNoteOff(109, static_cast(edrumulus.get_curve(selected_pad)), 1); + MYMIDI.sendNoteOff(110, edrumulus.get_spike_cancel_level(), 1); + MYMIDI.sendNoteOff(111, edrumulus.get_rim_shot_is_used(selected_pad) + 2 * edrumulus.get_pos_sense_is_used(selected_pad), 1); + MYMIDI.sendNoteOff(112, edrumulus.get_midi_note_norm(selected_pad), 1); + MYMIDI.sendNoteOff(113, edrumulus.get_midi_note_rim(selected_pad), 1); + MYMIDI.sendNoteOff(114, edrumulus.get_cancellation(selected_pad), 1); + MYMIDI.sendNoteOff(116, edrumulus.get_midi_note_open_norm(selected_pad), 1); + MYMIDI.sendNoteOff(117, edrumulus.get_midi_note_open_rim(selected_pad), 1); + MYMIDI.sendNoteOff(118, edrumulus.get_mask_time(selected_pad), 1); + MYMIDI.sendNoteOff(119, edrumulus.get_rim_shot_boost(selected_pad), 1); + MYMIDI.sendNoteOff(120, edrumulus.get_coupled_pad_idx(selected_pad), 1); + MYMIDI.sendNoteOff(121, edrumulus.get_rim_pos_threshold(selected_pad), 1); + MYMIDI.sendNoteOff(122, edrumulus.get_rim_pos_sensitivity(selected_pad), 1); // NOTE: 125 reserved for error message - MYMIDI.sendNoteOff ( 126, VERSION_MINOR, 1 ); - MYMIDI.sendNoteOff ( 127, VERSION_MAJOR, 1 ); + MYMIDI.sendNoteOff(126, VERSION_MINOR, 1); + MYMIDI.sendNoteOff(127, VERSION_MAJOR, 1); } else { // return only the given parameter - MYMIDI.sendNoteOff ( controller, value, 1 ); // can be checked, e.g., in the log file + MYMIDI.sendNoteOff(controller, value, 1); // can be checked, e.g., in the log file } } #endif - void read_settings() { - for ( int i = 0; i < number_pads; i++ ) + for (int i = 0; i < number_pads; i++) { // NOTE that it is important that set_pad_type() is called first because it resets all other parameters - edrumulus.set_pad_type ( i, static_cast ( edrumulus.read_setting ( i, 0 ) ) ); - edrumulus.set_velocity_threshold ( i, edrumulus.read_setting ( i, 1 ) ); - edrumulus.set_velocity_sensitivity ( i, edrumulus.read_setting ( i, 2 ) ); - edrumulus.set_pos_threshold ( i, edrumulus.read_setting ( i, 3 ) ); - edrumulus.set_pos_sensitivity ( i, edrumulus.read_setting ( i, 4 ) ); - edrumulus.set_rim_shot_threshold ( i, edrumulus.read_setting ( i, 5 ) ); - edrumulus.set_curve ( i, static_cast ( edrumulus.read_setting ( i, 6 ) ) ); - edrumulus.set_rim_shot_is_used ( i, edrumulus.read_setting ( i, 7 ) ); - edrumulus.set_pos_sense_is_used ( i, edrumulus.read_setting ( i, 8 ) ); - edrumulus.set_midi_note_norm ( i, edrumulus.read_setting ( i, 9 ) ); - edrumulus.set_midi_note_rim ( i, edrumulus.read_setting ( i, 10 ) ); - edrumulus.set_cancellation ( i, edrumulus.read_setting ( i, 11 ) ); - edrumulus.set_midi_note_open_norm ( i, edrumulus.read_setting ( i, 12 ) ); - edrumulus.set_midi_note_open_rim ( i, edrumulus.read_setting ( i, 13 ) ); - edrumulus.set_mask_time ( i, edrumulus.read_setting ( i, 14 ) ); - edrumulus.set_rim_shot_boost ( i, edrumulus.read_setting ( i, 15 ) ); - edrumulus.set_coupled_pad_idx ( i, edrumulus.read_setting ( i, 16 ) ); - edrumulus.set_rim_pos_threshold ( i, edrumulus.read_setting ( i, 17 ) ); - edrumulus.set_rim_pos_sensitivity ( i, edrumulus.read_setting ( i, 18 ) ); + edrumulus.set_pad_type(i, static_cast(edrumulus.read_setting(i, 0))); + edrumulus.set_velocity_threshold(i, edrumulus.read_setting(i, 1)); + edrumulus.set_velocity_sensitivity(i, edrumulus.read_setting(i, 2)); + edrumulus.set_pos_threshold(i, edrumulus.read_setting(i, 3)); + edrumulus.set_pos_sensitivity(i, edrumulus.read_setting(i, 4)); + edrumulus.set_rim_shot_threshold(i, edrumulus.read_setting(i, 5)); + edrumulus.set_curve(i, static_cast(edrumulus.read_setting(i, 6))); + edrumulus.set_rim_shot_is_used(i, edrumulus.read_setting(i, 7)); + edrumulus.set_pos_sense_is_used(i, edrumulus.read_setting(i, 8)); + edrumulus.set_midi_note_norm(i, edrumulus.read_setting(i, 9)); + edrumulus.set_midi_note_rim(i, edrumulus.read_setting(i, 10)); + edrumulus.set_cancellation(i, edrumulus.read_setting(i, 11)); + edrumulus.set_midi_note_open_norm(i, edrumulus.read_setting(i, 12)); + edrumulus.set_midi_note_open_rim(i, edrumulus.read_setting(i, 13)); + edrumulus.set_mask_time(i, edrumulus.read_setting(i, 14)); + edrumulus.set_rim_shot_boost(i, edrumulus.read_setting(i, 15)); + edrumulus.set_coupled_pad_idx(i, edrumulus.read_setting(i, 16)); + edrumulus.set_rim_pos_threshold(i, edrumulus.read_setting(i, 17)); + edrumulus.set_rim_pos_sensitivity(i, edrumulus.read_setting(i, 18)); } - edrumulus.set_spike_cancel_level ( edrumulus.read_setting ( number_pads, 0 ) ); + edrumulus.set_spike_cancel_level(edrumulus.read_setting(number_pads, 0)); } - void write_all_settings() { - for ( int i = 0; i < number_pads; i++ ) + for (int i = 0; i < number_pads; i++) { - edrumulus.write_setting ( i, 0, edrumulus.get_pad_type ( i ) ); - edrumulus.write_setting ( i, 1, edrumulus.get_velocity_threshold ( i ) ); - edrumulus.write_setting ( i, 2, edrumulus.get_velocity_sensitivity ( i ) ); - edrumulus.write_setting ( i, 3, edrumulus.get_pos_threshold ( i ) ); - edrumulus.write_setting ( i, 4, edrumulus.get_pos_sensitivity ( i ) ); - edrumulus.write_setting ( i, 5, edrumulus.get_rim_shot_threshold ( i ) ); - edrumulus.write_setting ( i, 6, edrumulus.get_curve ( i ) ); - edrumulus.write_setting ( i, 7, edrumulus.get_rim_shot_is_used ( i ) ); - edrumulus.write_setting ( i, 8, edrumulus.get_pos_sense_is_used ( i ) ); - edrumulus.write_setting ( i, 9, edrumulus.get_midi_note_norm ( i ) ); - edrumulus.write_setting ( i, 10, edrumulus.get_midi_note_rim ( i ) ); - edrumulus.write_setting ( i, 11, edrumulus.get_cancellation ( i ) ); - edrumulus.write_setting ( i, 12, edrumulus.get_midi_note_open_norm ( i ) ); - edrumulus.write_setting ( i, 13, edrumulus.get_midi_note_open_rim ( i ) ); - edrumulus.write_setting ( i, 14, edrumulus.get_mask_time ( i ) ); - edrumulus.write_setting ( i, 15, edrumulus.get_rim_shot_boost ( i ) ); - edrumulus.write_setting ( i, 16, edrumulus.get_coupled_pad_idx ( i ) ); - edrumulus.write_setting ( i, 17, edrumulus.get_rim_pos_threshold ( i ) ); - edrumulus.write_setting ( i, 18, edrumulus.get_rim_pos_sensitivity ( i ) ); + edrumulus.write_setting(i, 0, edrumulus.get_pad_type(i)); + edrumulus.write_setting(i, 1, edrumulus.get_velocity_threshold(i)); + edrumulus.write_setting(i, 2, edrumulus.get_velocity_sensitivity(i)); + edrumulus.write_setting(i, 3, edrumulus.get_pos_threshold(i)); + edrumulus.write_setting(i, 4, edrumulus.get_pos_sensitivity(i)); + edrumulus.write_setting(i, 5, edrumulus.get_rim_shot_threshold(i)); + edrumulus.write_setting(i, 6, edrumulus.get_curve(i)); + edrumulus.write_setting(i, 7, edrumulus.get_rim_shot_is_used(i)); + edrumulus.write_setting(i, 8, edrumulus.get_pos_sense_is_used(i)); + edrumulus.write_setting(i, 9, edrumulus.get_midi_note_norm(i)); + edrumulus.write_setting(i, 10, edrumulus.get_midi_note_rim(i)); + edrumulus.write_setting(i, 11, edrumulus.get_cancellation(i)); + edrumulus.write_setting(i, 12, edrumulus.get_midi_note_open_norm(i)); + edrumulus.write_setting(i, 13, edrumulus.get_midi_note_open_rim(i)); + edrumulus.write_setting(i, 14, edrumulus.get_mask_time(i)); + edrumulus.write_setting(i, 15, edrumulus.get_rim_shot_boost(i)); + edrumulus.write_setting(i, 16, edrumulus.get_coupled_pad_idx(i)); + edrumulus.write_setting(i, 17, edrumulus.get_rim_pos_threshold(i)); + edrumulus.write_setting(i, 18, edrumulus.get_rim_pos_sensitivity(i)); } - edrumulus.write_setting ( number_pads, 0, edrumulus.get_spike_cancel_level() ); + edrumulus.write_setting(number_pads, 0, edrumulus.get_spike_cancel_level()); } diff --git a/hardware.cpp b/hardware.cpp index d97fb87..f93e1b4 100644 --- a/hardware.cpp +++ b/hardware.cpp @@ -25,32 +25,30 @@ Edrumulus_hardware::Edrumulus_hardware() edrumulus_hardware_pointer = this; } - // ----------------------------------------------------------------------------- // Teensy 4.0/4.1/3.6 ---------------------------------------------------------- // ----------------------------------------------------------------------------- #ifdef TEENSYDUINO -int Edrumulus_hardware::get_prototype_pins ( int** analog_pins, - int** analog_pins_rimshot, - int* number_pins, - int* status_LED_pin ) +int Edrumulus_hardware::get_prototype_pins(int** analog_pins, + int** analog_pins_rimshot, + int* number_pins, + int* status_LED_pin) { // analog pins setup: snare | kick | hi-hat | hi-hat-ctrl | crash | tom1 | ride | tom2 | tom3 - static int analog_pins1[] = { A10, A11, A12, A13, A1, A6, A4, A5 }; - static int analog_pins_rimshot1[] = { A9, -1, A0, -1, A3, A8, A2, A7 }; - *analog_pins = analog_pins1; - *analog_pins_rimshot = analog_pins_rimshot1; - *number_pins = sizeof ( analog_pins1 ) / sizeof ( int ); - *status_LED_pin = BOARD_LED_PIN; + static int analog_pins1[] = {A10, A11, A12, A13, A1, A6, A4, A5}; + static int analog_pins_rimshot1[] = {A9, -1, A0, -1, A3, A8, A2, A7}; + *analog_pins = analog_pins1; + *analog_pins_rimshot = analog_pins_rimshot1; + *number_pins = sizeof(analog_pins1) / sizeof(int); + *status_LED_pin = BOARD_LED_PIN; return 0; } - -void Edrumulus_hardware::setup ( const int conf_Fs, - const int number_pads, - const int number_inputs[], - int analog_pin[][MAX_NUM_PAD_INPUTS] ) +void Edrumulus_hardware::setup(const int conf_Fs, + const int number_pads, + const int number_inputs[], + int analog_pin[][MAX_NUM_PAD_INPUTS]) { // set essential parameters Fs = conf_Fs; @@ -58,32 +56,32 @@ void Edrumulus_hardware::setup ( const int conf_Fs, // create linear vectors containing the pin information for each pad and pad-input total_number_inputs = 0; // we use it as a counter, too - for ( int i = 0; i < number_pads; i++ ) + for (int i = 0; i < number_pads; i++) { - for ( int j = 0; j < number_inputs[i]; j++ ) + for (int j = 0; j < number_inputs[i]; j++) { // store pin number in vector input_pin[total_number_inputs] = analog_pin[i][j]; total_number_inputs++; -#if defined(ARDUINO_TEENSY40) || defined(ARDUINO_TEENSY41) // Teensy 4.0/4.1 specific code +# if defined(ARDUINO_TEENSY40) || defined(ARDUINO_TEENSY41) // Teensy 4.0/4.1 specific code // disable MIMXRT1062DVL6A "keeper" on all Teensy 4.0/4.1 ADC input pins // NOTE: pinMode() needs absolute pin numbers, e.g. 0 for A0 will not work - pinMode ( analog_pin[i][j], INPUT_DISABLE ); -#endif + pinMode(analog_pin[i][j], INPUT_DISABLE); +# endif } } // set the ADC properties: averaging 8 samples with high speed sampling gives // us the best compromise between ADC speed and spike protection - adc_obj.adc0->setResolution ( 12 ); // we want to get the full ADC resolution of the Teensy 4.0 - adc_obj.adc0->setAveraging ( 8 ); - adc_obj.adc0->setConversionSpeed ( ADC_CONVERSION_SPEED::HIGH_SPEED ); - adc_obj.adc0->setSamplingSpeed ( ADC_SAMPLING_SPEED::HIGH_SPEED ); - adc_obj.adc1->setResolution ( 12 ); // we want to get the full ADC resolution of the Teensy 4.0 - adc_obj.adc1->setAveraging ( 8 ); - adc_obj.adc1->setConversionSpeed ( ADC_CONVERSION_SPEED::HIGH_SPEED ); - adc_obj.adc1->setSamplingSpeed ( ADC_SAMPLING_SPEED::HIGH_SPEED ); + adc_obj.adc0->setResolution(12); // we want to get the full ADC resolution of the Teensy 4.0 + adc_obj.adc0->setAveraging(8); + adc_obj.adc0->setConversionSpeed(ADC_CONVERSION_SPEED::HIGH_SPEED); + adc_obj.adc0->setSamplingSpeed(ADC_SAMPLING_SPEED::HIGH_SPEED); + adc_obj.adc1->setResolution(12); // we want to get the full ADC resolution of the Teensy 4.0 + adc_obj.adc1->setAveraging(8); + adc_obj.adc1->setConversionSpeed(ADC_CONVERSION_SPEED::HIGH_SPEED); + adc_obj.adc1->setSamplingSpeed(ADC_SAMPLING_SPEED::HIGH_SPEED); // wait for ADC calibration to complete adc_obj.adc0->wait_for_cal(); @@ -93,53 +91,49 @@ void Edrumulus_hardware::setup ( const int conf_Fs, timer_ready = false; // prepare timer at a rate of given sampling rate - myTimer.begin ( on_timer, 1000000 / Fs ); // here we define the sampling rate (1 MHz / Fs) + myTimer.begin(on_timer, 1000000 / Fs); // here we define the sampling rate (1 MHz / Fs) } - -void Edrumulus_hardware::write_setting ( const int pad_index, - const int address, - const byte value ) +void Edrumulus_hardware::write_setting(const int pad_index, + const int address, + const byte value) { - EEPROM.update ( pad_index * MAX_NUM_SET_PER_PAD + address, value ); + EEPROM.update(pad_index * MAX_NUM_SET_PER_PAD + address, value); } - -byte Edrumulus_hardware::read_setting ( const int pad_index, - const int address ) +byte Edrumulus_hardware::read_setting(const int pad_index, + const int address) { - return EEPROM.read ( pad_index * MAX_NUM_SET_PER_PAD + address ); + return EEPROM.read(pad_index * MAX_NUM_SET_PER_PAD + address); } - void Edrumulus_hardware::on_timer() { // tell the main loop that a sample can be read by setting the flag (semaphore) edrumulus_hardware_pointer->timer_ready = true; } - -void Edrumulus_hardware::capture_samples ( const int number_pads, - const int number_inputs[], - int analog_pin[][MAX_NUM_PAD_INPUTS], - int sample_org[][MAX_NUM_PAD_INPUTS] ) +void Edrumulus_hardware::capture_samples(const int number_pads, + const int number_inputs[], + int analog_pin[][MAX_NUM_PAD_INPUTS], + int sample_org[][MAX_NUM_PAD_INPUTS]) { // wait for the timer to get the correct sampling rate when reading the analog value - while ( !timer_ready ) delayMicroseconds ( 5 ); + while (!timer_ready) delayMicroseconds(5); timer_ready = false; // it is important to reset the flag here // read the ADC samples - for ( int i = 0; i < total_number_inputs; i++ ) + for (int i = 0; i < total_number_inputs; i++) { - input_sample[i] = adc_obj.analogRead ( input_pin[i] ); + input_sample[i] = adc_obj.analogRead(input_pin[i]); } // copy captured samples in pad buffer int input_cnt = 0; - for ( int i = 0; i < number_pads; i++ ) + for (int i = 0; i < number_pads; i++) { - for ( int j = 0; j < number_inputs[i]; j++ ) + for (int j = 0; j < number_inputs[i]; j++) { sample_org[i][j] = input_sample[input_cnt++]; } @@ -148,72 +142,75 @@ void Edrumulus_hardware::capture_samples ( const int number_pads, #endif - // ----------------------------------------------------------------------------- // ESP32 Dual Core ------------------------------------------------------------- // ----------------------------------------------------------------------------- #ifdef ESP_PLATFORM -void Edrumulus_hardware::write_setting ( const int pad_index, - const int address, - const byte value ) +void Edrumulus_hardware::write_setting(const int pad_index, + const int address, + const byte value) { - const char* key = String ( pad_index * MAX_NUM_SET_PER_PAD + address ).c_str(); - settings.putUChar ( key, value ); + const char* key = String(pad_index * MAX_NUM_SET_PER_PAD + address).c_str(); + settings.putUChar(key, value); } -byte Edrumulus_hardware::read_setting ( const int pad_index, - const int address ) +byte Edrumulus_hardware::read_setting(const int pad_index, + const int address) { - const char* key = String ( pad_index * MAX_NUM_SET_PER_PAD + address ).c_str(); - return settings.getUChar ( key, 0 ); + const char* key = String(pad_index * MAX_NUM_SET_PER_PAD + address).c_str(); + return settings.getUChar(key, 0); } -int Edrumulus_hardware::get_prototype_pins ( int** analog_pins, - int** analog_pins_rimshot, - int* number_pins, - int* status_LED_pin ) +int Edrumulus_hardware::get_prototype_pins(int** analog_pins, + int** analog_pins_rimshot, + int* number_pins, + int* status_LED_pin) { -#ifdef CONFIG_IDF_TARGET_ESP32 +# ifdef CONFIG_IDF_TARGET_ESP32 // Definition: // - Pin 5 is "input enabled, pull-up resistor" -> if read value is 1, we know that we have a // legacy or custom board. Boards which support the identification set this pin to low. // - Pin 18, 19, 22, 23 define a 4 bit sequence which identifies the prototype hardware. // NOTE: avoid ESP32 GPIO 25/26 for piezo inputs since they are DAC pins which cause an incorrect DC offset // estimation and DC offset drift which makes the spike cancellation algorithm not working correctly - pinMode ( 5, INPUT ); + pinMode(5, INPUT); // check support of protoype board identification - if ( digitalRead ( 5 ) == 0 ) + if (digitalRead(5) == 0) { // read the identification bit field and check the states - pinMode ( 18, INPUT ); const int bit1 = digitalRead ( 18 ); - pinMode ( 19, INPUT ); const int bit2 = digitalRead ( 19 ); - pinMode ( 22, INPUT ); const int bit3 = digitalRead ( 22 ); - pinMode ( 23, INPUT ); const int bit4 = digitalRead ( 23 ); - - if ( ( bit1 == 0 ) && ( bit2 == 0 ) && ( bit3 == 0 ) && ( bit4 == 0 ) ) + pinMode(18, INPUT); + const int bit1 = digitalRead(18); + pinMode(19, INPUT); + const int bit2 = digitalRead(19); + pinMode(22, INPUT); + const int bit3 = digitalRead(22); + pinMode(23, INPUT); + const int bit4 = digitalRead(23); + + if ((bit1 == 0) && (bit2 == 0) && (bit3 == 0) && (bit4 == 0)) { // Prototype 5: 0, 0, 0, 0 ----------------------------------------------- - // analog pins setup: snare | kick | hi-hat | hi-hat-ctrl | crash | tom1 | ride | tom2 | tom3 - static int analog_pins5[] = { 12, 2, 33, 4, 34, 15, 35, 27, 32 }; - static int analog_pins_rimshot5[] = { 14, -1, 26, -1, 36, 13, 25, -1, -1 }; - *analog_pins = analog_pins5; - *analog_pins_rimshot = analog_pins_rimshot5; - *number_pins = sizeof ( analog_pins5 ) / sizeof ( int ); - *status_LED_pin = 21; // LED is connected to IO21 on prototype 5 + // analog pins setup: snare | kick | hi-hat | hi-hat-ctrl | crash | tom1 | ride | tom2 | tom3 + static int analog_pins5[] = {12, 2, 33, 4, 34, 15, 35, 27, 32}; + static int analog_pins_rimshot5[] = {14, -1, 26, -1, 36, 13, 25, -1, -1}; + *analog_pins = analog_pins5; + *analog_pins_rimshot = analog_pins_rimshot5; + *number_pins = sizeof(analog_pins5) / sizeof(int); + *status_LED_pin = 21; // LED is connected to IO21 on prototype 5 return 5; } - else if ( ( bit1 > 0 ) && ( bit2 == 0 ) && ( bit3 == 0 ) && ( bit4 == 0 ) ) + else if ((bit1 > 0) && (bit2 == 0) && (bit3 == 0) && (bit4 == 0)) { // Prototype 6: 1, 0, 0, 0 ----------------------------------------------- - // analog pins setup: snare | kick | hi-hat | hi-hat-ctrl | crash | tom1 | ride | tom2 | tom3 - static int analog_pins6[] = { 36, 33, 32, 25, 34, 39, 27, 12, 15 }; - static int analog_pins_rimshot6[] = { 35, -1, 26, -1, 14, -1, 13, -1, -1 }; - *analog_pins = analog_pins6; - *analog_pins_rimshot = analog_pins_rimshot6; - *number_pins = sizeof ( analog_pins6 ) / sizeof ( int ); - *status_LED_pin = BOARD_LED_PIN; + // analog pins setup: snare | kick | hi-hat | hi-hat-ctrl | crash | tom1 | ride | tom2 | tom3 + static int analog_pins6[] = {36, 33, 32, 25, 34, 39, 27, 12, 15}; + static int analog_pins_rimshot6[] = {35, -1, 26, -1, 14, -1, 13, -1, -1}; + *analog_pins = analog_pins6; + *analog_pins_rimshot = analog_pins_rimshot6; + *number_pins = sizeof(analog_pins6) / sizeof(int); + *status_LED_pin = BOARD_LED_PIN; return 6; } } @@ -221,42 +218,41 @@ int Edrumulus_hardware::get_prototype_pins ( int** analog_pins, // default: assume that analog pins are set outside this function, only update board LED pin *status_LED_pin = BOARD_LED_PIN; return 4; -#else // CONFIG_IDF_TARGET_ESP32S3 - // analog pins setup: snare | kick | hi-hat | hi-hat-ctrl | crash | tom1 | ride | tom2 | tom3 - static int analog_pins_s3[] = { 4, 6, 7, 9, 10, 12, 13, 15, 16 }; - static int analog_pins_rimshot_s3[] = { 5, -1, 8, -1, 11, -1, 14, -1, -1 }; - *analog_pins = analog_pins_s3; - *analog_pins_rimshot = analog_pins_rimshot_s3; - *number_pins = sizeof ( analog_pins_s3 ) / sizeof ( int ); - *status_LED_pin = BOARD_LED_PIN; +# else // CONFIG_IDF_TARGET_ESP32S3 + // analog pins setup: snare | kick | hi-hat | hi-hat-ctrl | crash | tom1 | ride | tom2 | tom3 + static int analog_pins_s3[] = {4, 6, 7, 9, 10, 12, 13, 15, 16}; + static int analog_pins_rimshot_s3[] = {5, -1, 8, -1, 11, -1, 14, -1, -1}; + *analog_pins = analog_pins_s3; + *analog_pins_rimshot = analog_pins_rimshot_s3; + *number_pins = sizeof(analog_pins_s3) / sizeof(int); + *status_LED_pin = BOARD_LED_PIN; return 4; -#endif +# endif } - -void Edrumulus_hardware::setup ( const int conf_Fs, - const int number_pads, - const int number_inputs[], - int analog_pin[][MAX_NUM_PAD_INPUTS] ) +void Edrumulus_hardware::setup(const int conf_Fs, + const int number_pads, + const int number_inputs[], + int analog_pin[][MAX_NUM_PAD_INPUTS]) { // set essential parameters Fs = conf_Fs; char preferences_namespace[16] = "Edrumulus"; - settings.begin ( preferences_namespace, false ); + settings.begin(preferences_namespace, false); // create linear vectors containing the pin/ADC information for each pad and pad-input bool input_is_used[MAX_NUM_PADS * MAX_NUM_PAD_INPUTS]; - int input_adc[MAX_NUM_PADS * MAX_NUM_PAD_INPUTS]; + int input_adc[MAX_NUM_PADS * MAX_NUM_PAD_INPUTS]; total_number_inputs = 0; // we use it as a counter, too - for ( int i = 0; i < number_pads; i++ ) + for (int i = 0; i < number_pads; i++) { - for ( int j = 0; j < number_inputs[i]; j++ ) + for (int j = 0; j < number_inputs[i]; j++) { // store pin number in vector and identify ADC number for each pin input_pin[total_number_inputs] = analog_pin[i][j]; - input_adc[total_number_inputs] = ( digitalPinToAnalogChannel ( analog_pin[i][j] ) >= 10 ); // channel < 10 -> ADC1, channel >= 10 -> ADC2 - input_is_used[total_number_inputs] = false; // initialization needed for ADC pairs identification + input_adc[total_number_inputs] = (digitalPinToAnalogChannel(analog_pin[i][j]) >= 10); // channel < 10 -> ADC1, channel >= 10 -> ADC2 + input_is_used[total_number_inputs] = false; // initialization needed for ADC pairs identification total_number_inputs++; } } @@ -264,17 +260,17 @@ void Edrumulus_hardware::setup ( const int conf_Fs, // find ADC pairs, i.e., one pin uses ADC1 and the other uses ADC2 num_pin_pairs = 0; // we use it as a counter, too -#ifdef CONFIG_IDF_TARGET_ESP32 - for ( int i = 0; i < total_number_inputs - 1; i++ ) +# ifdef CONFIG_IDF_TARGET_ESP32 + for (int i = 0; i < total_number_inputs - 1; i++) { - if ( !input_is_used[i] ) + if (!input_is_used[i]) { - for ( int j = total_number_inputs - 1; j > i; j-- ) + for (int j = total_number_inputs - 1; j > i; j--) { // check for different ADCs: 0+0=0, 1+0=1 (pair), 0+1=1 (pair), 1+1=2 - if ( !input_is_used[j] && ( input_adc[i] + input_adc[j] == 1 ) ) + if (!input_is_used[j] && (input_adc[i] + input_adc[j] == 1)) { - if ( input_adc[i] == 0 ) + if (input_adc[i] == 0) { adc1_index[num_pin_pairs] = i; adc2_index[num_pin_pairs] = j; @@ -286,10 +282,10 @@ void Edrumulus_hardware::setup ( const int conf_Fs, } // create the mask bit needed for SENS_SAR1_EN_PAD and SENS_SAR2_EN_PAD - const int8_t channel_adc1 = digitalPinToAnalogChannel ( input_pin[adc1_index[num_pin_pairs]] ); - const int8_t channel_adc2 = digitalPinToAnalogChannel ( input_pin[adc2_index[num_pin_pairs]] ) - 10; - channel_adc1_bitval[num_pin_pairs] = ( 1 << channel_adc1 ); - channel_adc2_bitval[num_pin_pairs] = ( 1 << channel_adc2 ); + const int8_t channel_adc1 = digitalPinToAnalogChannel(input_pin[adc1_index[num_pin_pairs]]); + const int8_t channel_adc2 = digitalPinToAnalogChannel(input_pin[adc2_index[num_pin_pairs]]) - 10; + channel_adc1_bitval[num_pin_pairs] = (1 << channel_adc1); + channel_adc2_bitval[num_pin_pairs] = (1 << channel_adc2); num_pin_pairs++; input_is_used[i] = true; @@ -299,14 +295,14 @@ void Edrumulus_hardware::setup ( const int conf_Fs, } } } -#endif +# endif // find remaining single pins which we cannot create an ADC pair with num_pin_single = 0; // we use it as a counter, too - for ( int i = 0; i < total_number_inputs; i++ ) + for (int i = 0; i < total_number_inputs; i++) { - if ( !input_is_used[i] ) + if (!input_is_used[i]) { single_index[num_pin_single] = i; num_pin_single++; @@ -321,81 +317,77 @@ void Edrumulus_hardware::setup ( const int conf_Fs, // create task pinned to core 0 for creating the timer interrupt so that the // timer function is not running in our working core 1 -#ifdef CONFIG_IDF_TARGET_ESP32 - xTaskCreatePinnedToCore ( start_timer_core0_task, "start_timer_core0_task", 800, this, 1, NULL, 0 ); -#else // CONFIG_IDF_TARGET_ESP32S3 - xTaskCreatePinnedToCore ( start_timer_core0_task, "start_timer_core0_task", 1000, this, 1, NULL, 0 ); -#endif +# ifdef CONFIG_IDF_TARGET_ESP32 + xTaskCreatePinnedToCore(start_timer_core0_task, "start_timer_core0_task", 800, this, 1, NULL, 0); +# else // CONFIG_IDF_TARGET_ESP32S3 + xTaskCreatePinnedToCore(start_timer_core0_task, "start_timer_core0_task", 1000, this, 1, NULL, 0); +# endif } - void Edrumulus_hardware::setup_timer() { // prepare timer at a rate of given sampling rate - timer = timerBegin ( 0, 80, true ); // prescaler of 80 (i.e. below we have 1 MHz instead of 80 MHz) - timerAttachInterrupt ( timer, &on_timer, true ); - timerAlarmWrite ( timer, 1000000 / Fs, true ); // here we define the sampling rate (1 MHz / Fs) - timerAlarmEnable ( timer ); + timer = timerBegin(0, 80, true); // prescaler of 80 (i.e. below we have 1 MHz instead of 80 MHz) + timerAttachInterrupt(timer, &on_timer, true); + timerAlarmWrite(timer, 1000000 / Fs, true); // here we define the sampling rate (1 MHz / Fs) + timerAlarmEnable(timer); } - -void Edrumulus_hardware::start_timer_core0_task ( void* param ) +void Edrumulus_hardware::start_timer_core0_task(void* param) { - reinterpret_cast ( param )->setup_timer(); + reinterpret_cast(param)->setup_timer(); // tasks must not return: forever loop with delay to keep watchdog happy - for ( ; ; ) + for (;;) { - delay ( 1000 ); + delay(1000); } } - void IRAM_ATTR Edrumulus_hardware::on_timer() { // first read the ADC pairs samples - for ( int i = 0; i < edrumulus_hardware_pointer->num_pin_pairs; i++ ) + for (int i = 0; i < edrumulus_hardware_pointer->num_pin_pairs; i++) { - edrumulus_hardware_pointer->my_analogRead_parallel ( - edrumulus_hardware_pointer->channel_adc1_bitval[i], - edrumulus_hardware_pointer->channel_adc2_bitval[i], - edrumulus_hardware_pointer->input_sample[edrumulus_hardware_pointer->adc1_index[i]], - edrumulus_hardware_pointer->input_sample[edrumulus_hardware_pointer->adc2_index[i]] ); + edrumulus_hardware_pointer->my_analogRead_parallel( + edrumulus_hardware_pointer->channel_adc1_bitval[i], + edrumulus_hardware_pointer->channel_adc2_bitval[i], + edrumulus_hardware_pointer->input_sample[edrumulus_hardware_pointer->adc1_index[i]], + edrumulus_hardware_pointer->input_sample[edrumulus_hardware_pointer->adc2_index[i]]); } // second read the single ADC samples - for ( int i = 0; i < edrumulus_hardware_pointer->num_pin_single; i++ ) + for (int i = 0; i < edrumulus_hardware_pointer->num_pin_single; i++) { edrumulus_hardware_pointer->input_sample[edrumulus_hardware_pointer->single_index[i]] = - edrumulus_hardware_pointer->my_analogRead ( edrumulus_hardware_pointer->input_pin[edrumulus_hardware_pointer->single_index[i]] ); + edrumulus_hardware_pointer->my_analogRead(edrumulus_hardware_pointer->input_pin[edrumulus_hardware_pointer->single_index[i]]); } // tell the main loop that a sample can be processed by setting the semaphore static BaseType_t xHigherPriorityTaskWoken = pdFALSE; - xSemaphoreGiveFromISR ( edrumulus_hardware_pointer->timer_semaphore, &xHigherPriorityTaskWoken ); + xSemaphoreGiveFromISR(edrumulus_hardware_pointer->timer_semaphore, &xHigherPriorityTaskWoken); - if ( xHigherPriorityTaskWoken == pdTRUE ) + if (xHigherPriorityTaskWoken == pdTRUE) { portYIELD_FROM_ISR(); } } - -void Edrumulus_hardware::capture_samples ( const int number_pads, - const int number_inputs[], - int analog_pin[][MAX_NUM_PAD_INPUTS], - int sample_org[][MAX_NUM_PAD_INPUTS] ) +void Edrumulus_hardware::capture_samples(const int number_pads, + const int number_inputs[], + int analog_pin[][MAX_NUM_PAD_INPUTS], + int sample_org[][MAX_NUM_PAD_INPUTS]) { // wait for the timer to get the correct sampling rate when reading the analog value - if ( xSemaphoreTake ( timer_semaphore, portMAX_DELAY ) == pdTRUE ) + if (xSemaphoreTake(timer_semaphore, portMAX_DELAY) == pdTRUE) { // copy captured samples in pad buffer int input_cnt = 0; - for ( int i = 0; i < number_pads; i++ ) + for (int i = 0; i < number_pads; i++) { - for ( int j = 0; j < number_inputs[i]; j++ ) + for (int j = 0; j < number_inputs[i]; j++) { sample_org[i][j] = input_sample[input_cnt++]; } @@ -403,238 +395,241 @@ void Edrumulus_hardware::capture_samples ( const int number_pads, } } - // Since arduino-esp32 library version 1.0.5, the analogRead was changed to use the IDF interface // which made the analogRead function so slow that we cannot use that anymore for Edrumulus: // https://github.com/espressif/arduino-esp32/issues/4973, https://github.com/espressif/arduino-esp32/pull/3377 // As a workaround, we had to write our own analogRead function. void Edrumulus_hardware::init_my_analogRead() { -#ifdef CONFIG_IDF_TARGET_ESP32 +# ifdef CONFIG_IDF_TARGET_ESP32 // if the GIOP 25/26 are used, we have to set the DAC to 0 to get correct DC offset // estimates and reduce the number of large spikes dac_i2s_enable(); - dac_output_enable ( DAC_CHANNEL_1 ); - dac_output_voltage ( DAC_CHANNEL_1, 0 ); - dac_output_disable ( DAC_CHANNEL_1 ); - dac_output_enable ( DAC_CHANNEL_2 ); - dac_output_voltage ( DAC_CHANNEL_2, 0 ); - dac_output_disable ( DAC_CHANNEL_2 ); + dac_output_enable(DAC_CHANNEL_1); + dac_output_voltage(DAC_CHANNEL_1, 0); + dac_output_disable(DAC_CHANNEL_1); + dac_output_enable(DAC_CHANNEL_2); + dac_output_voltage(DAC_CHANNEL_2, 0); + dac_output_disable(DAC_CHANNEL_2); dac_i2s_disable(); // set attenuation of 11 dB - WRITE_PERI_REG ( SENS_SAR_ATTEN1_REG, 0x0FFFFFFFF ); - WRITE_PERI_REG ( SENS_SAR_ATTEN2_REG, 0x0FFFFFFFF ); + WRITE_PERI_REG(SENS_SAR_ATTEN1_REG, 0x0FFFFFFFF); + WRITE_PERI_REG(SENS_SAR_ATTEN2_REG, 0x0FFFFFFFF); // set both ADCs to 12 bit resolution using 8 cycles and 1 sample - SET_PERI_REG_BITS ( SENS_SAR_READ_CTRL_REG, SENS_SAR1_SAMPLE_CYCLE, 8, SENS_SAR1_SAMPLE_CYCLE_S ); // cycles - SET_PERI_REG_BITS ( SENS_SAR_READ_CTRL2_REG, SENS_SAR2_SAMPLE_CYCLE, 8, SENS_SAR2_SAMPLE_CYCLE_S ); - SET_PERI_REG_BITS ( SENS_SAR_READ_CTRL_REG, SENS_SAR1_SAMPLE_NUM, 0, SENS_SAR1_SAMPLE_NUM_S ); // # samples - SET_PERI_REG_BITS ( SENS_SAR_READ_CTRL2_REG, SENS_SAR2_SAMPLE_NUM, 0, SENS_SAR2_SAMPLE_NUM_S ); - SET_PERI_REG_BITS ( SENS_SAR_READ_CTRL_REG, SENS_SAR1_CLK_DIV, 1, SENS_SAR1_CLK_DIV_S ); // clock div - SET_PERI_REG_BITS ( SENS_SAR_READ_CTRL2_REG, SENS_SAR2_CLK_DIV, 1, SENS_SAR2_CLK_DIV_S ); - SET_PERI_REG_BITS ( SENS_SAR_START_FORCE_REG, SENS_SAR1_BIT_WIDTH, 3, SENS_SAR1_BIT_WIDTH_S ); // width - SET_PERI_REG_BITS ( SENS_SAR_READ_CTRL_REG, SENS_SAR1_SAMPLE_BIT, 3, SENS_SAR1_SAMPLE_BIT_S ); - SET_PERI_REG_BITS ( SENS_SAR_START_FORCE_REG, SENS_SAR2_BIT_WIDTH, 3, SENS_SAR2_BIT_WIDTH_S ); - SET_PERI_REG_BITS ( SENS_SAR_READ_CTRL2_REG, SENS_SAR2_SAMPLE_BIT, 3, SENS_SAR2_SAMPLE_BIT_S ); + SET_PERI_REG_BITS(SENS_SAR_READ_CTRL_REG, SENS_SAR1_SAMPLE_CYCLE, 8, SENS_SAR1_SAMPLE_CYCLE_S); // cycles + SET_PERI_REG_BITS(SENS_SAR_READ_CTRL2_REG, SENS_SAR2_SAMPLE_CYCLE, 8, SENS_SAR2_SAMPLE_CYCLE_S); + SET_PERI_REG_BITS(SENS_SAR_READ_CTRL_REG, SENS_SAR1_SAMPLE_NUM, 0, SENS_SAR1_SAMPLE_NUM_S); // # samples + SET_PERI_REG_BITS(SENS_SAR_READ_CTRL2_REG, SENS_SAR2_SAMPLE_NUM, 0, SENS_SAR2_SAMPLE_NUM_S); + SET_PERI_REG_BITS(SENS_SAR_READ_CTRL_REG, SENS_SAR1_CLK_DIV, 1, SENS_SAR1_CLK_DIV_S); // clock div + SET_PERI_REG_BITS(SENS_SAR_READ_CTRL2_REG, SENS_SAR2_CLK_DIV, 1, SENS_SAR2_CLK_DIV_S); + SET_PERI_REG_BITS(SENS_SAR_START_FORCE_REG, SENS_SAR1_BIT_WIDTH, 3, SENS_SAR1_BIT_WIDTH_S); // width + SET_PERI_REG_BITS(SENS_SAR_READ_CTRL_REG, SENS_SAR1_SAMPLE_BIT, 3, SENS_SAR1_SAMPLE_BIT_S); + SET_PERI_REG_BITS(SENS_SAR_START_FORCE_REG, SENS_SAR2_BIT_WIDTH, 3, SENS_SAR2_BIT_WIDTH_S); + SET_PERI_REG_BITS(SENS_SAR_READ_CTRL2_REG, SENS_SAR2_SAMPLE_BIT, 3, SENS_SAR2_SAMPLE_BIT_S); // some other initializations - SET_PERI_REG_MASK ( SENS_SAR_READ_CTRL_REG, SENS_SAR1_DATA_INV ); - SET_PERI_REG_MASK ( SENS_SAR_READ_CTRL2_REG, SENS_SAR2_DATA_INV ); - SET_PERI_REG_MASK ( SENS_SAR_MEAS_START1_REG, SENS_MEAS1_START_FORCE_M ); // SAR ADC1 controller (in RTC) is started by SW - SET_PERI_REG_MASK ( SENS_SAR_MEAS_START1_REG, SENS_SAR1_EN_PAD_FORCE_M ); // SAR ADC1 pad enable bitmap is controlled by SW - SET_PERI_REG_MASK ( SENS_SAR_MEAS_START2_REG, SENS_MEAS2_START_FORCE_M ); // SAR ADC2 controller (in RTC) is started by SW - SET_PERI_REG_MASK ( SENS_SAR_MEAS_START2_REG, SENS_SAR2_EN_PAD_FORCE_M ); // SAR ADC2 pad enable bitmap is controlled by SW - CLEAR_PERI_REG_MASK ( SENS_SAR_MEAS_WAIT2_REG, SENS_FORCE_XPD_SAR_M ); // force XPD_SAR=0, use XPD_FSM - SET_PERI_REG_BITS ( SENS_SAR_MEAS_WAIT2_REG, SENS_FORCE_XPD_AMP, 0x2, SENS_FORCE_XPD_AMP_S ); // force XPD_AMP=0 - CLEAR_PERI_REG_MASK ( SENS_SAR_MEAS_CTRL_REG, 0xfff << SENS_AMP_RST_FB_FSM_S ); // clear FSM - SET_PERI_REG_BITS ( SENS_SAR_MEAS_WAIT1_REG, SENS_SAR_AMP_WAIT1, 0x1, SENS_SAR_AMP_WAIT1_S ); - SET_PERI_REG_BITS ( SENS_SAR_MEAS_WAIT1_REG, SENS_SAR_AMP_WAIT2, 0x1, SENS_SAR_AMP_WAIT2_S ); - SET_PERI_REG_BITS ( SENS_SAR_MEAS_WAIT2_REG, SENS_SAR_AMP_WAIT3, 0x1, SENS_SAR_AMP_WAIT3_S ); - while ( GET_PERI_REG_BITS2 ( SENS_SAR_SLAVE_ADDR1_REG, 0x7, SENS_MEAS_STATUS_S ) != 0 ); + SET_PERI_REG_MASK(SENS_SAR_READ_CTRL_REG, SENS_SAR1_DATA_INV); + SET_PERI_REG_MASK(SENS_SAR_READ_CTRL2_REG, SENS_SAR2_DATA_INV); + SET_PERI_REG_MASK(SENS_SAR_MEAS_START1_REG, SENS_MEAS1_START_FORCE_M); // SAR ADC1 controller (in RTC) is started by SW + SET_PERI_REG_MASK(SENS_SAR_MEAS_START1_REG, SENS_SAR1_EN_PAD_FORCE_M); // SAR ADC1 pad enable bitmap is controlled by SW + SET_PERI_REG_MASK(SENS_SAR_MEAS_START2_REG, SENS_MEAS2_START_FORCE_M); // SAR ADC2 controller (in RTC) is started by SW + SET_PERI_REG_MASK(SENS_SAR_MEAS_START2_REG, SENS_SAR2_EN_PAD_FORCE_M); // SAR ADC2 pad enable bitmap is controlled by SW + CLEAR_PERI_REG_MASK(SENS_SAR_MEAS_WAIT2_REG, SENS_FORCE_XPD_SAR_M); // force XPD_SAR=0, use XPD_FSM + SET_PERI_REG_BITS(SENS_SAR_MEAS_WAIT2_REG, SENS_FORCE_XPD_AMP, 0x2, SENS_FORCE_XPD_AMP_S); // force XPD_AMP=0 + CLEAR_PERI_REG_MASK(SENS_SAR_MEAS_CTRL_REG, 0xfff << SENS_AMP_RST_FB_FSM_S); // clear FSM + SET_PERI_REG_BITS(SENS_SAR_MEAS_WAIT1_REG, SENS_SAR_AMP_WAIT1, 0x1, SENS_SAR_AMP_WAIT1_S); + SET_PERI_REG_BITS(SENS_SAR_MEAS_WAIT1_REG, SENS_SAR_AMP_WAIT2, 0x1, SENS_SAR_AMP_WAIT2_S); + SET_PERI_REG_BITS(SENS_SAR_MEAS_WAIT2_REG, SENS_SAR_AMP_WAIT3, 0x1, SENS_SAR_AMP_WAIT3_S); + while (GET_PERI_REG_BITS2(SENS_SAR_SLAVE_ADDR1_REG, 0x7, SENS_MEAS_STATUS_S) != 0) + ; // configure all pins to analog read - for ( int i = 0; i < total_number_inputs; i++ ) + for (int i = 0; i < total_number_inputs; i++) { - pinMode ( input_pin[i], ANALOG ); + pinMode(input_pin[i], ANALOG); } -#else // CONFIG_IDF_TARGET_ESP32S3 +# else // CONFIG_IDF_TARGET_ESP32S3 int cur_sample; - for ( int channel = 0; channel < 10; channel++ ) // 10 channels per ADC + for (int channel = 0; channel < 10; channel++) // 10 channels per ADC { // configure the attenuation and let the get_raw() do all the ADC initialization for us... - adc1_config_channel_atten ( static_cast ( channel ), ADC_ATTEN_DB_11 ); - adc2_config_channel_atten ( static_cast ( channel ), ADC_ATTEN_DB_11 ); - adc1_get_raw ( static_cast ( channel ) ); - adc2_get_raw ( static_cast ( channel ), ADC_WIDTH_BIT_12, &cur_sample ); + adc1_config_channel_atten(static_cast(channel), ADC_ATTEN_DB_11); + adc2_config_channel_atten(static_cast(channel), ADC_ATTEN_DB_11); + adc1_get_raw(static_cast(channel)); + adc2_get_raw(static_cast(channel), ADC_WIDTH_BIT_12, &cur_sample); } adc_power_on(); -#endif +# endif } - -uint16_t Edrumulus_hardware::my_analogRead ( const uint8_t pin ) +uint16_t Edrumulus_hardware::my_analogRead(const uint8_t pin) { - const int8_t channel = digitalPinToAnalogChannel ( pin ); + const int8_t channel = digitalPinToAnalogChannel(pin); - if ( channel > 9 ) + if (channel > 9) { const int8_t channel_modified = channel - 10; -#ifdef CONFIG_IDF_TARGET_ESP32 - CLEAR_PERI_REG_MASK ( SENS_SAR_MEAS_START2_REG, SENS_MEAS2_START_SAR_M ); - SET_PERI_REG_BITS ( SENS_SAR_MEAS_START2_REG, SENS_SAR2_EN_PAD, ( 1 << channel_modified ), SENS_SAR2_EN_PAD_S ); - SET_PERI_REG_MASK ( SENS_SAR_MEAS_START2_REG, SENS_MEAS2_START_SAR_M ); - while ( GET_PERI_REG_MASK ( SENS_SAR_MEAS_START2_REG, SENS_MEAS2_DONE_SAR ) == 0 ); - return GET_PERI_REG_BITS2 ( SENS_SAR_MEAS_START2_REG, SENS_MEAS2_DATA_SAR, SENS_MEAS2_DATA_SAR_S ); -#else // CONFIG_IDF_TARGET_ESP32S3 +# ifdef CONFIG_IDF_TARGET_ESP32 + CLEAR_PERI_REG_MASK(SENS_SAR_MEAS_START2_REG, SENS_MEAS2_START_SAR_M); + SET_PERI_REG_BITS(SENS_SAR_MEAS_START2_REG, SENS_SAR2_EN_PAD, (1 << channel_modified), SENS_SAR2_EN_PAD_S); + SET_PERI_REG_MASK(SENS_SAR_MEAS_START2_REG, SENS_MEAS2_START_SAR_M); + while (GET_PERI_REG_MASK(SENS_SAR_MEAS_START2_REG, SENS_MEAS2_DONE_SAR) == 0) + ; + return GET_PERI_REG_BITS2(SENS_SAR_MEAS_START2_REG, SENS_MEAS2_DATA_SAR, SENS_MEAS2_DATA_SAR_S); +# else // CONFIG_IDF_TARGET_ESP32S3 SENS.sar_meas2_ctrl2.meas2_start_sar = 0; - SENS.sar_meas2_ctrl2.sar2_en_pad = ( 1 << channel_modified ); + SENS.sar_meas2_ctrl2.sar2_en_pad = (1 << channel_modified); SENS.sar_meas2_ctrl2.meas2_start_sar = 1; - while ( !SENS.sar_meas2_ctrl2.meas2_done_sar ); - return HAL_FORCE_READ_U32_REG_FIELD ( SENS.sar_meas2_ctrl2, meas2_data_sar ); -#endif + while (!SENS.sar_meas2_ctrl2.meas2_done_sar) + ; + return HAL_FORCE_READ_U32_REG_FIELD(SENS.sar_meas2_ctrl2, meas2_data_sar); +# endif } else { -#ifdef CONFIG_IDF_TARGET_ESP32 - CLEAR_PERI_REG_MASK ( SENS_SAR_MEAS_START1_REG, SENS_MEAS1_START_SAR_M ); - SET_PERI_REG_BITS ( SENS_SAR_MEAS_START1_REG, SENS_SAR1_EN_PAD, ( 1 << channel ), SENS_SAR1_EN_PAD_S ); - SET_PERI_REG_MASK ( SENS_SAR_MEAS_START1_REG, SENS_MEAS1_START_SAR_M ); - while ( GET_PERI_REG_MASK ( SENS_SAR_MEAS_START1_REG, SENS_MEAS1_DONE_SAR ) == 0 ); - return GET_PERI_REG_BITS2 ( SENS_SAR_MEAS_START1_REG, SENS_MEAS1_DATA_SAR, SENS_MEAS1_DATA_SAR_S ); -#else // CONFIG_IDF_TARGET_ESP32S3 +# ifdef CONFIG_IDF_TARGET_ESP32 + CLEAR_PERI_REG_MASK(SENS_SAR_MEAS_START1_REG, SENS_MEAS1_START_SAR_M); + SET_PERI_REG_BITS(SENS_SAR_MEAS_START1_REG, SENS_SAR1_EN_PAD, (1 << channel), SENS_SAR1_EN_PAD_S); + SET_PERI_REG_MASK(SENS_SAR_MEAS_START1_REG, SENS_MEAS1_START_SAR_M); + while (GET_PERI_REG_MASK(SENS_SAR_MEAS_START1_REG, SENS_MEAS1_DONE_SAR) == 0) + ; + return GET_PERI_REG_BITS2(SENS_SAR_MEAS_START1_REG, SENS_MEAS1_DATA_SAR, SENS_MEAS1_DATA_SAR_S); +# else // CONFIG_IDF_TARGET_ESP32S3 SENS.sar_meas1_ctrl2.meas1_start_sar = 0; - SENS.sar_meas1_ctrl2.sar1_en_pad = ( 1 << channel ); + SENS.sar_meas1_ctrl2.sar1_en_pad = (1 << channel); SENS.sar_meas1_ctrl2.meas1_start_sar = 1; - while ( !SENS.sar_meas1_ctrl2.meas1_done_sar ); - return HAL_FORCE_READ_U32_REG_FIELD ( SENS.sar_meas1_ctrl2, meas1_data_sar ); -#endif + while (!SENS.sar_meas1_ctrl2.meas1_done_sar) + ; + return HAL_FORCE_READ_U32_REG_FIELD(SENS.sar_meas1_ctrl2, meas1_data_sar); +# endif } } - -void Edrumulus_hardware::my_analogRead_parallel ( const uint32_t channel_adc1_bitval, - const uint32_t channel_adc2_bitval, - uint16_t& out_adc1, - uint16_t& out_adc2 ) +void Edrumulus_hardware::my_analogRead_parallel(const uint32_t channel_adc1_bitval, + const uint32_t channel_adc2_bitval, + uint16_t& out_adc1, + uint16_t& out_adc2) { -#ifdef CONFIG_IDF_TARGET_ESP32 +# ifdef CONFIG_IDF_TARGET_ESP32 // start ADC1 - CLEAR_PERI_REG_MASK ( SENS_SAR_MEAS_START1_REG, SENS_MEAS1_START_SAR_M ); - SET_PERI_REG_BITS ( SENS_SAR_MEAS_START1_REG, SENS_SAR1_EN_PAD, channel_adc1_bitval, SENS_SAR1_EN_PAD_S ); - SET_PERI_REG_MASK ( SENS_SAR_MEAS_START1_REG, SENS_MEAS1_START_SAR_M ); + CLEAR_PERI_REG_MASK(SENS_SAR_MEAS_START1_REG, SENS_MEAS1_START_SAR_M); + SET_PERI_REG_BITS(SENS_SAR_MEAS_START1_REG, SENS_SAR1_EN_PAD, channel_adc1_bitval, SENS_SAR1_EN_PAD_S); + SET_PERI_REG_MASK(SENS_SAR_MEAS_START1_REG, SENS_MEAS1_START_SAR_M); // start ADC2 - CLEAR_PERI_REG_MASK ( SENS_SAR_MEAS_START2_REG, SENS_MEAS2_START_SAR_M ); - SET_PERI_REG_BITS ( SENS_SAR_MEAS_START2_REG, SENS_SAR2_EN_PAD, channel_adc2_bitval, SENS_SAR2_EN_PAD_S ); - SET_PERI_REG_MASK ( SENS_SAR_MEAS_START2_REG, SENS_MEAS2_START_SAR_M ); + CLEAR_PERI_REG_MASK(SENS_SAR_MEAS_START2_REG, SENS_MEAS2_START_SAR_M); + SET_PERI_REG_BITS(SENS_SAR_MEAS_START2_REG, SENS_SAR2_EN_PAD, channel_adc2_bitval, SENS_SAR2_EN_PAD_S); + SET_PERI_REG_MASK(SENS_SAR_MEAS_START2_REG, SENS_MEAS2_START_SAR_M); // wait for ADC1 and read value - while ( GET_PERI_REG_MASK ( SENS_SAR_MEAS_START1_REG, SENS_MEAS1_DONE_SAR ) == 0 ); - out_adc1 = GET_PERI_REG_BITS2 ( SENS_SAR_MEAS_START1_REG, SENS_MEAS1_DATA_SAR, SENS_MEAS1_DATA_SAR_S ); + while (GET_PERI_REG_MASK(SENS_SAR_MEAS_START1_REG, SENS_MEAS1_DONE_SAR) == 0) + ; + out_adc1 = GET_PERI_REG_BITS2(SENS_SAR_MEAS_START1_REG, SENS_MEAS1_DATA_SAR, SENS_MEAS1_DATA_SAR_S); // wait for ADC2 and read value - while ( GET_PERI_REG_MASK ( SENS_SAR_MEAS_START2_REG, SENS_MEAS2_DONE_SAR ) == 0 ); - out_adc2 = GET_PERI_REG_BITS2 ( SENS_SAR_MEAS_START2_REG, SENS_MEAS2_DATA_SAR, SENS_MEAS2_DATA_SAR_S ); -#endif + while (GET_PERI_REG_MASK(SENS_SAR_MEAS_START2_REG, SENS_MEAS2_DONE_SAR) == 0) + ; + out_adc2 = GET_PERI_REG_BITS2(SENS_SAR_MEAS_START2_REG, SENS_MEAS2_DATA_SAR, SENS_MEAS2_DATA_SAR_S); +# endif } #endif - // ----------------------------------------------------------------------------- // Common hardware functions --------------------------------------------------- // ----------------------------------------------------------------------------- -void Edrumulus_hardware::cancel_ADC_spikes ( float& signal, - int& overload_detected, - const int pad_index, - const int input_channel_index, - const int level ) +void Edrumulus_hardware::cancel_ADC_spikes(float& signal, + int& overload_detected, + const int pad_index, + const int input_channel_index, + const int level) { // remove single/dual sample spikes by checking if right before and right after the // detected spike(s) we only have noise and no useful signal (since the ESP32 spikes // mostly are on just one or two sample(s)) const int max_peak_threshold = 150; // maximum assumed ESP32 spike amplitude - const float signal_org = signal; - signal = prev_input4[pad_index][input_channel_index]; // normal return value in case no spike was detected - const int overload_detected_org = overload_detected; - overload_detected = prev_overload4[pad_index][input_channel_index]; // normal return value in case no spike was detected - const float input_abs = abs ( signal_org ); - Espikestate input_state = ST_OTHER; // initialization value, might be overwritten + const float signal_org = signal; + signal = prev_input4[pad_index][input_channel_index]; // normal return value in case no spike was detected + const int overload_detected_org = overload_detected; + overload_detected = prev_overload4[pad_index][input_channel_index]; // normal return value in case no spike was detected + const float input_abs = abs(signal_org); + Espikestate input_state = ST_OTHER; // initialization value, might be overwritten - if ( input_abs < ADC_MAX_NOISE_AMPL ) + if (input_abs < ADC_MAX_NOISE_AMPL) { input_state = ST_NOISE; } - else if ( ( signal_org < max_peak_threshold ) && ( signal_org > 0 ) ) + else if ((signal_org < max_peak_threshold) && (signal_org > 0)) { input_state = ST_SPIKE_HIGH; } - else if ( ( signal_org > -max_peak_threshold ) && ( signal_org < 0 ) ) + else if ((signal_org > -max_peak_threshold) && (signal_org < 0)) { input_state = ST_SPIKE_LOW; } // check for single high spike sample case - if ( ( ( prev5_input_state[pad_index][input_channel_index] == ST_NOISE ) || ( prev5_input_state[pad_index][input_channel_index] == ST_SPIKE_LOW ) ) && - ( prev4_input_state[pad_index][input_channel_index] == ST_SPIKE_HIGH ) && - ( ( prev3_input_state[pad_index][input_channel_index] == ST_NOISE ) || ( prev3_input_state[pad_index][input_channel_index] == ST_SPIKE_LOW ) ) ) + if (((prev5_input_state[pad_index][input_channel_index] == ST_NOISE) || (prev5_input_state[pad_index][input_channel_index] == ST_SPIKE_LOW)) && + (prev4_input_state[pad_index][input_channel_index] == ST_SPIKE_HIGH) && + ((prev3_input_state[pad_index][input_channel_index] == ST_NOISE) || (prev3_input_state[pad_index][input_channel_index] == ST_SPIKE_LOW))) { signal = 0.0f; // remove single spike } // check for single low spike sample case - if ( ( ( prev5_input_state[pad_index][input_channel_index] == ST_NOISE ) || ( prev5_input_state[pad_index][input_channel_index] == ST_SPIKE_HIGH ) ) && - ( prev4_input_state[pad_index][input_channel_index] == ST_SPIKE_LOW ) && - ( ( prev3_input_state[pad_index][input_channel_index] == ST_NOISE ) || ( prev3_input_state[pad_index][input_channel_index] == ST_SPIKE_HIGH ) ) ) + if (((prev5_input_state[pad_index][input_channel_index] == ST_NOISE) || (prev5_input_state[pad_index][input_channel_index] == ST_SPIKE_HIGH)) && + (prev4_input_state[pad_index][input_channel_index] == ST_SPIKE_LOW) && + ((prev3_input_state[pad_index][input_channel_index] == ST_NOISE) || (prev3_input_state[pad_index][input_channel_index] == ST_SPIKE_HIGH))) { signal = 0.0f; // remove single spike } - if ( level >= 2 ) + if (level >= 2) { // check for two sample spike case - if ( ( ( prev5_input_state[pad_index][input_channel_index] == ST_NOISE ) || ( prev5_input_state[pad_index][input_channel_index] == ST_SPIKE_LOW ) ) && - ( prev4_input_state[pad_index][input_channel_index] == ST_SPIKE_HIGH ) && - ( prev3_input_state[pad_index][input_channel_index] == ST_SPIKE_HIGH ) && - ( ( prev2_input_state[pad_index][input_channel_index] == ST_NOISE ) || ( prev2_input_state[pad_index][input_channel_index] == ST_SPIKE_LOW ) ) ) + if (((prev5_input_state[pad_index][input_channel_index] == ST_NOISE) || (prev5_input_state[pad_index][input_channel_index] == ST_SPIKE_LOW)) && + (prev4_input_state[pad_index][input_channel_index] == ST_SPIKE_HIGH) && + (prev3_input_state[pad_index][input_channel_index] == ST_SPIKE_HIGH) && + ((prev2_input_state[pad_index][input_channel_index] == ST_NOISE) || (prev2_input_state[pad_index][input_channel_index] == ST_SPIKE_LOW))) { signal = 0.0f; // remove two sample spike prev_input3[pad_index][input_channel_index] = 0.0f; // remove two sample spike } - + // check for two sample low spike case - if ( ( ( prev5_input_state[pad_index][input_channel_index] == ST_NOISE ) || ( prev5_input_state[pad_index][input_channel_index] == ST_SPIKE_HIGH ) ) && - ( prev4_input_state[pad_index][input_channel_index] == ST_SPIKE_LOW ) && - ( prev3_input_state[pad_index][input_channel_index] == ST_SPIKE_LOW ) && - ( ( prev2_input_state[pad_index][input_channel_index] == ST_NOISE ) || ( prev2_input_state[pad_index][input_channel_index] == ST_SPIKE_HIGH ) ) ) + if (((prev5_input_state[pad_index][input_channel_index] == ST_NOISE) || (prev5_input_state[pad_index][input_channel_index] == ST_SPIKE_HIGH)) && + (prev4_input_state[pad_index][input_channel_index] == ST_SPIKE_LOW) && + (prev3_input_state[pad_index][input_channel_index] == ST_SPIKE_LOW) && + ((prev2_input_state[pad_index][input_channel_index] == ST_NOISE) || (prev2_input_state[pad_index][input_channel_index] == ST_SPIKE_HIGH))) { signal = 0.0f; // remove two sample spike prev_input3[pad_index][input_channel_index] = 0.0f; // remove two sample spike } } - if ( level >= 3 ) + if (level >= 3) { // check for three sample high spike case - if ( ( ( prev5_input_state[pad_index][input_channel_index] == ST_NOISE ) || ( prev5_input_state[pad_index][input_channel_index] == ST_SPIKE_LOW ) ) && - ( prev4_input_state[pad_index][input_channel_index] == ST_SPIKE_HIGH ) && - ( prev3_input_state[pad_index][input_channel_index] == ST_SPIKE_HIGH ) && - ( prev2_input_state[pad_index][input_channel_index] == ST_SPIKE_HIGH ) && - ( ( prev1_input_state[pad_index][input_channel_index] == ST_NOISE ) || ( prev1_input_state[pad_index][input_channel_index] == ST_SPIKE_LOW ) ) ) + if (((prev5_input_state[pad_index][input_channel_index] == ST_NOISE) || (prev5_input_state[pad_index][input_channel_index] == ST_SPIKE_LOW)) && + (prev4_input_state[pad_index][input_channel_index] == ST_SPIKE_HIGH) && + (prev3_input_state[pad_index][input_channel_index] == ST_SPIKE_HIGH) && + (prev2_input_state[pad_index][input_channel_index] == ST_SPIKE_HIGH) && + ((prev1_input_state[pad_index][input_channel_index] == ST_NOISE) || (prev1_input_state[pad_index][input_channel_index] == ST_SPIKE_LOW))) { signal = 0.0f; // remove three sample spike prev_input3[pad_index][input_channel_index] = 0.0f; // remove three sample spike prev_input2[pad_index][input_channel_index] = 0.0f; // remove three sample spike } - + // check for three sample low spike case - if ( ( ( prev5_input_state[pad_index][input_channel_index] == ST_NOISE ) || ( prev5_input_state[pad_index][input_channel_index] == ST_SPIKE_HIGH ) ) && - ( prev4_input_state[pad_index][input_channel_index] == ST_SPIKE_LOW ) && - ( prev3_input_state[pad_index][input_channel_index] == ST_SPIKE_LOW ) && - ( prev2_input_state[pad_index][input_channel_index] == ST_SPIKE_LOW ) && - ( ( prev1_input_state[pad_index][input_channel_index] == ST_NOISE ) || ( prev1_input_state[pad_index][input_channel_index] == ST_SPIKE_HIGH ) ) ) + if (((prev5_input_state[pad_index][input_channel_index] == ST_NOISE) || (prev5_input_state[pad_index][input_channel_index] == ST_SPIKE_HIGH)) && + (prev4_input_state[pad_index][input_channel_index] == ST_SPIKE_LOW) && + (prev3_input_state[pad_index][input_channel_index] == ST_SPIKE_LOW) && + (prev2_input_state[pad_index][input_channel_index] == ST_SPIKE_LOW) && + ((prev1_input_state[pad_index][input_channel_index] == ST_NOISE) || (prev1_input_state[pad_index][input_channel_index] == ST_SPIKE_HIGH))) { signal = 0.0f; // remove three sample spike prev_input3[pad_index][input_channel_index] = 0.0f; // remove three sample spike @@ -642,29 +637,29 @@ void Edrumulus_hardware::cancel_ADC_spikes ( float& signal, } } - if ( level >= 4 ) + if (level >= 4) { // check for four sample high spike case - if ( ( ( prev5_input_state[pad_index][input_channel_index] == ST_NOISE ) || ( prev5_input_state[pad_index][input_channel_index] == ST_SPIKE_LOW ) ) && - ( prev4_input_state[pad_index][input_channel_index] == ST_SPIKE_HIGH ) && - ( prev3_input_state[pad_index][input_channel_index] == ST_SPIKE_HIGH ) && - ( prev2_input_state[pad_index][input_channel_index] == ST_SPIKE_HIGH ) && - ( prev1_input_state[pad_index][input_channel_index] == ST_SPIKE_HIGH ) && - ( ( input_state == ST_NOISE ) || ( input_state == ST_SPIKE_LOW ) ) ) + if (((prev5_input_state[pad_index][input_channel_index] == ST_NOISE) || (prev5_input_state[pad_index][input_channel_index] == ST_SPIKE_LOW)) && + (prev4_input_state[pad_index][input_channel_index] == ST_SPIKE_HIGH) && + (prev3_input_state[pad_index][input_channel_index] == ST_SPIKE_HIGH) && + (prev2_input_state[pad_index][input_channel_index] == ST_SPIKE_HIGH) && + (prev1_input_state[pad_index][input_channel_index] == ST_SPIKE_HIGH) && + ((input_state == ST_NOISE) || (input_state == ST_SPIKE_LOW))) { signal = 0.0f; // remove four sample spike prev_input3[pad_index][input_channel_index] = 0.0f; // remove four sample spike prev_input2[pad_index][input_channel_index] = 0.0f; // remove four sample spike prev_input1[pad_index][input_channel_index] = 0.0f; // remove four sample spike } - + // check for four sample low spike case - if ( ( ( prev5_input_state[pad_index][input_channel_index] == ST_NOISE ) || ( prev5_input_state[pad_index][input_channel_index] == ST_SPIKE_HIGH ) ) && - ( prev4_input_state[pad_index][input_channel_index] == ST_SPIKE_LOW ) && - ( prev3_input_state[pad_index][input_channel_index] == ST_SPIKE_LOW ) && - ( prev2_input_state[pad_index][input_channel_index] == ST_SPIKE_LOW ) && - ( prev1_input_state[pad_index][input_channel_index] == ST_SPIKE_LOW ) && - ( ( input_state == ST_NOISE ) || ( input_state == ST_SPIKE_HIGH ) ) ) + if (((prev5_input_state[pad_index][input_channel_index] == ST_NOISE) || (prev5_input_state[pad_index][input_channel_index] == ST_SPIKE_HIGH)) && + (prev4_input_state[pad_index][input_channel_index] == ST_SPIKE_LOW) && + (prev3_input_state[pad_index][input_channel_index] == ST_SPIKE_LOW) && + (prev2_input_state[pad_index][input_channel_index] == ST_SPIKE_LOW) && + (prev1_input_state[pad_index][input_channel_index] == ST_SPIKE_LOW) && + ((input_state == ST_NOISE) || (input_state == ST_SPIKE_HIGH))) { signal = 0.0f; // remove four sample spike prev_input3[pad_index][input_channel_index] = 0.0f; // remove four sample spike @@ -688,13 +683,13 @@ void Edrumulus_hardware::cancel_ADC_spikes ( float& signal, // adjust the latency of the algorithm according to the spike cancellation // level, i.e., the higher the level, the higher the latency - if ( level >= 3 ) + if (level >= 3) { prev1_input_state[pad_index][input_channel_index] = input_state; prev_input1[pad_index][input_channel_index] = signal_org; prev_overload1[pad_index][input_channel_index] = overload_detected_org; } - else if ( level >= 2 ) + else if (level >= 2) { prev2_input_state[pad_index][input_channel_index] = input_state; prev_input2[pad_index][input_channel_index] = signal_org; diff --git a/hardware.h b/hardware.h index e896509..16e0875 100644 --- a/hardware.h +++ b/hardware.h @@ -28,62 +28,62 @@ enum Espikestate ST_OTHER }; -#define MAX_NUM_PADS 12 // a maximum of 12 pads are supported -#define MAX_NUM_PAD_INPUTS 5 // a maximum of 5 sensors per pad is supported (where one is rim and one is the sum of three) -#define MAX_EEPROM_SIZE 512 // bytes (Teensy 4.0: max 1024 bytes) -#define MAX_NUM_SET_PER_PAD 30 // maximum number of settings which can be stored per pad - +#define MAX_NUM_PADS 12 // a maximum of 12 pads are supported +#define MAX_NUM_PAD_INPUTS 5 // a maximum of 5 sensors per pad is supported (where one is rim and one is the sum of three) +#define MAX_EEPROM_SIZE 512 // bytes (Teensy 4.0: max 1024 bytes) +#define MAX_NUM_SET_PER_PAD 30 // maximum number of settings which can be stored per pad // ----------------------------------------------------------------------------- // Teensy 4.0/4.1 -------------------------------------------------------------- // ----------------------------------------------------------------------------- #ifdef TEENSYDUINO -#include "EEPROM.h" -#include +# include + +# include "EEPROM.h" -#define BOARD_LED_PIN 13 // pin number of the LED on the Teensy 4.0 board -#define ADC_MAX_RANGE 4096 // Teensy 4.0/4.1 ADC has 12 bits -> 0..4095 -#define ADC_MAX_NOISE_AMPL 8 // highest assumed ADC noise amplitude in the ADC input range unit (measured) +# define BOARD_LED_PIN 13 // pin number of the LED on the Teensy 4.0 board +# define ADC_MAX_RANGE 4096 // Teensy 4.0/4.1 ADC has 12 bits -> 0..4095 +# define ADC_MAX_NOISE_AMPL 8 // highest assumed ADC noise amplitude in the ADC input range unit (measured) class Edrumulus_hardware { -public: + public: Edrumulus_hardware(); - static int get_prototype_pins ( int** analog_pins, - int** analog_pins_rimshot, - int* number_pins, - int* status_LED_pin ); + static int get_prototype_pins(int** analog_pins, + int** analog_pins_rimshot, + int* number_pins, + int* status_LED_pin); - void setup ( const int conf_Fs, - const int number_pads, - const int number_inputs[], - int analog_pin[][MAX_NUM_PAD_INPUTS] ); + void setup(const int conf_Fs, + const int number_pads, + const int number_inputs[], + int analog_pin[][MAX_NUM_PAD_INPUTS]); - void capture_samples ( const int number_pads, - const int number_inputs[], - int analog_pin[][MAX_NUM_PAD_INPUTS], - int sample_org[][MAX_NUM_PAD_INPUTS] ); + void capture_samples(const int number_pads, + const int number_inputs[], + int analog_pin[][MAX_NUM_PAD_INPUTS], + int sample_org[][MAX_NUM_PAD_INPUTS]); - void cancel_ADC_spikes ( float& signal, - int& overload_detected, - const int pad_index, - const int input_channel_index, - const int level ); + void cancel_ADC_spikes(float& signal, + int& overload_detected, + const int pad_index, + const int input_channel_index, + const int level); - void write_setting ( const int pad_index, const int address, const byte value ); - byte read_setting ( const int pad_index, const int address ); + void write_setting(const int pad_index, const int address, const byte value); + byte read_setting(const int pad_index, const int address); -protected: - int Fs; + protected: + int Fs; IntervalTimer myTimer; - static void on_timer(); + static void on_timer(); volatile bool timer_ready; - ADC adc_obj; + ADC adc_obj; - int total_number_inputs; - int input_pin[MAX_NUM_PADS * MAX_NUM_PAD_INPUTS]; + int total_number_inputs; + int input_pin[MAX_NUM_PADS * MAX_NUM_PAD_INPUTS]; uint16_t input_sample[MAX_NUM_PADS * MAX_NUM_PAD_INPUTS]; Espikestate prev1_input_state[MAX_NUM_PADS][MAX_NUM_PAD_INPUTS]; @@ -91,108 +91,108 @@ class Edrumulus_hardware Espikestate prev3_input_state[MAX_NUM_PADS][MAX_NUM_PAD_INPUTS]; Espikestate prev4_input_state[MAX_NUM_PADS][MAX_NUM_PAD_INPUTS]; Espikestate prev5_input_state[MAX_NUM_PADS][MAX_NUM_PAD_INPUTS]; - float prev_input1[MAX_NUM_PADS][MAX_NUM_PAD_INPUTS]; - float prev_input2[MAX_NUM_PADS][MAX_NUM_PAD_INPUTS]; - float prev_input3[MAX_NUM_PADS][MAX_NUM_PAD_INPUTS]; - float prev_input4[MAX_NUM_PADS][MAX_NUM_PAD_INPUTS]; - int prev_overload1[MAX_NUM_PADS][MAX_NUM_PAD_INPUTS]; - int prev_overload2[MAX_NUM_PADS][MAX_NUM_PAD_INPUTS]; - int prev_overload3[MAX_NUM_PADS][MAX_NUM_PAD_INPUTS]; - int prev_overload4[MAX_NUM_PADS][MAX_NUM_PAD_INPUTS]; + float prev_input1[MAX_NUM_PADS][MAX_NUM_PAD_INPUTS]; + float prev_input2[MAX_NUM_PADS][MAX_NUM_PAD_INPUTS]; + float prev_input3[MAX_NUM_PADS][MAX_NUM_PAD_INPUTS]; + float prev_input4[MAX_NUM_PADS][MAX_NUM_PAD_INPUTS]; + int prev_overload1[MAX_NUM_PADS][MAX_NUM_PAD_INPUTS]; + int prev_overload2[MAX_NUM_PADS][MAX_NUM_PAD_INPUTS]; + int prev_overload3[MAX_NUM_PADS][MAX_NUM_PAD_INPUTS]; + int prev_overload4[MAX_NUM_PADS][MAX_NUM_PAD_INPUTS]; }; #endif - // ----------------------------------------------------------------------------- // ESP32 Dual Core ------------------------------------------------------------- // ----------------------------------------------------------------------------- #ifdef ESP_PLATFORM -#include -#include "soc/sens_reg.h" -#include "driver/adc.h" -#ifdef CONFIG_IDF_TARGET_ESP32 -# include "driver/dac.h" -#else // CONFIG_IDF_TARGET_ESP32S3 -# include "hal/adc_hal.h" -#endif +# include -#define BOARD_LED_PIN 2 // pin number of the LED on the ESP32 board -#define ADC_MAX_RANGE 4096 // ESP32 ADC has 12 bits -> 0..4095 -#define ADC_MAX_NOISE_AMPL 8 // highest assumed ADC noise amplitude in the ADC input range unit (measured) +# include "driver/adc.h" +# include "soc/sens_reg.h" +# ifdef CONFIG_IDF_TARGET_ESP32 +# include "driver/dac.h" +# else // CONFIG_IDF_TARGET_ESP32S3 +# include "hal/adc_hal.h" +# endif + +# define BOARD_LED_PIN 2 // pin number of the LED on the ESP32 board +# define ADC_MAX_RANGE 4096 // ESP32 ADC has 12 bits -> 0..4095 +# define ADC_MAX_NOISE_AMPL 8 // highest assumed ADC noise amplitude in the ADC input range unit (measured) class Edrumulus_hardware { -public: + public: Edrumulus_hardware(); - static int get_prototype_pins ( int** analog_pins, - int** analog_pins_rimshot, - int* number_pins, - int* status_LED_pin ); - - void setup ( const int conf_Fs, - const int number_pads, - const int number_inputs[], - int analog_pin[][MAX_NUM_PAD_INPUTS] ); - - void capture_samples ( const int number_pads, - const int number_inputs[], - int analog_pin[][MAX_NUM_PAD_INPUTS], - int sample_org[][MAX_NUM_PAD_INPUTS] ); - - void cancel_ADC_spikes ( float& signal, - int& overload_detected, - const int pad_index, - const int input_channel_index, - const int level ); - - void write_setting ( const int pad_index, const int address, const byte value ); - byte read_setting ( const int pad_index, const int address ); - -protected: - int Fs; - Preferences settings; + static int get_prototype_pins(int** analog_pins, + int** analog_pins_rimshot, + int* number_pins, + int* status_LED_pin); + + void setup(const int conf_Fs, + const int number_pads, + const int number_inputs[], + int analog_pin[][MAX_NUM_PAD_INPUTS]); + + void capture_samples(const int number_pads, + const int number_inputs[], + int analog_pin[][MAX_NUM_PAD_INPUTS], + int sample_org[][MAX_NUM_PAD_INPUTS]); + + void cancel_ADC_spikes(float& signal, + int& overload_detected, + const int pad_index, + const int input_channel_index, + const int level); + + void write_setting(const int pad_index, const int address, const byte value); + byte read_setting(const int pad_index, const int address); + + protected: + int Fs; + Preferences settings; volatile SemaphoreHandle_t timer_semaphore; - hw_timer_t* timer = nullptr; - static void IRAM_ATTR on_timer(); - static void start_timer_core0_task ( void* param ); - - void setup_timer(); - void init_my_analogRead(); - uint16_t my_analogRead ( const uint8_t pin ); - void my_analogRead_parallel ( const uint32_t channel_adc1_bitval, - const uint32_t channel_adc2_bitval, - uint16_t& out_adc1, - uint16_t& out_adc2 ); - - int total_number_inputs; - int input_pin[MAX_NUM_PADS * MAX_NUM_PAD_INPUTS]; - uint16_t input_sample[MAX_NUM_PADS * MAX_NUM_PAD_INPUTS]; - - int num_pin_pairs; - int adc1_index[MAX_NUM_PADS * MAX_NUM_PAD_INPUTS]; - int adc2_index[MAX_NUM_PADS * MAX_NUM_PAD_INPUTS]; - uint32_t channel_adc1_bitval[MAX_NUM_PADS * MAX_NUM_PAD_INPUTS]; - uint32_t channel_adc2_bitval[MAX_NUM_PADS * MAX_NUM_PAD_INPUTS]; - - int num_pin_single; - int single_index[MAX_NUM_PADS * MAX_NUM_PAD_INPUTS]; + hw_timer_t* timer = nullptr; + static void IRAM_ATTR on_timer(); + static void start_timer_core0_task(void* param); + + void setup_timer(); + void init_my_analogRead(); + uint16_t my_analogRead(const uint8_t pin); + void my_analogRead_parallel(const uint32_t channel_adc1_bitval, + const uint32_t channel_adc2_bitval, + uint16_t& out_adc1, + uint16_t& out_adc2); + + int total_number_inputs; + int input_pin[MAX_NUM_PADS * MAX_NUM_PAD_INPUTS]; + uint16_t input_sample[MAX_NUM_PADS * MAX_NUM_PAD_INPUTS]; + + int num_pin_pairs; + int adc1_index[MAX_NUM_PADS * MAX_NUM_PAD_INPUTS]; + int adc2_index[MAX_NUM_PADS * MAX_NUM_PAD_INPUTS]; + uint32_t channel_adc1_bitval[MAX_NUM_PADS * MAX_NUM_PAD_INPUTS]; + uint32_t channel_adc2_bitval[MAX_NUM_PADS * MAX_NUM_PAD_INPUTS]; + + int num_pin_single; + int single_index[MAX_NUM_PADS * MAX_NUM_PAD_INPUTS]; Espikestate prev1_input_state[MAX_NUM_PADS][MAX_NUM_PAD_INPUTS]; Espikestate prev2_input_state[MAX_NUM_PADS][MAX_NUM_PAD_INPUTS]; Espikestate prev3_input_state[MAX_NUM_PADS][MAX_NUM_PAD_INPUTS]; Espikestate prev4_input_state[MAX_NUM_PADS][MAX_NUM_PAD_INPUTS]; Espikestate prev5_input_state[MAX_NUM_PADS][MAX_NUM_PAD_INPUTS]; - float prev_input1[MAX_NUM_PADS][MAX_NUM_PAD_INPUTS]; - float prev_input2[MAX_NUM_PADS][MAX_NUM_PAD_INPUTS]; - float prev_input3[MAX_NUM_PADS][MAX_NUM_PAD_INPUTS]; - float prev_input4[MAX_NUM_PADS][MAX_NUM_PAD_INPUTS]; - int prev_overload1[MAX_NUM_PADS][MAX_NUM_PAD_INPUTS]; - int prev_overload2[MAX_NUM_PADS][MAX_NUM_PAD_INPUTS]; - int prev_overload3[MAX_NUM_PADS][MAX_NUM_PAD_INPUTS]; - int prev_overload4[MAX_NUM_PADS][MAX_NUM_PAD_INPUTS]; + float prev_input1[MAX_NUM_PADS][MAX_NUM_PAD_INPUTS]; + float prev_input2[MAX_NUM_PADS][MAX_NUM_PAD_INPUTS]; + float prev_input3[MAX_NUM_PADS][MAX_NUM_PAD_INPUTS]; + float prev_input4[MAX_NUM_PADS][MAX_NUM_PAD_INPUTS]; + int prev_overload1[MAX_NUM_PADS][MAX_NUM_PAD_INPUTS]; + int prev_overload2[MAX_NUM_PADS][MAX_NUM_PAD_INPUTS]; + int prev_overload3[MAX_NUM_PADS][MAX_NUM_PAD_INPUTS]; + int prev_overload4[MAX_NUM_PADS][MAX_NUM_PAD_INPUTS]; }; #endif diff --git a/parameters.cpp b/parameters.cpp index 5a1b3a1..5f0d600 100644 --- a/parameters.cpp +++ b/parameters.cpp @@ -17,7 +17,6 @@ #include "edrumulus.h" - void Edrumulus::Pad::apply_preset_pad_settings() { // apply PRESET settings (might be overwritten by pad-specific properties) @@ -57,7 +56,7 @@ void Edrumulus::Pad::apply_preset_pad_settings() pad_settings.rim_shot_window_len_ms = 3.5f; // pad specific parameter: window length for rim shot detection pad_settings.clip_comp_ampmap_step = 0.08f; // pad specific parameter: clipping compensation amplitude mapping step, conservative value from PD80R as default - switch ( pad_settings.pad_type ) + switch (pad_settings.pad_type) { // Mesh pads --------------------------------------------------------------- case PD120: // dual trigger @@ -167,7 +166,6 @@ void Edrumulus::Pad::apply_preset_pad_settings() pad_settings.velocity_sensitivity = 3; break; - // Rubber pads ------------------------------------------------------------- case PD5: // single trigger pad_settings.scan_time_ms = 4.0f; @@ -223,7 +221,6 @@ void Edrumulus::Pad::apply_preset_pad_settings() pad_settings.pos_low_pass_cutoff = 300.0f; break; - // Kick drum pads ---------------------------------------------------------- case KD7: // single trigger pad_settings.velocity_threshold = 11; @@ -280,7 +277,6 @@ void Edrumulus::Pad::apply_preset_pad_settings() pad_settings.curve_type = LOG2; break; - // Cymbal pads ------------------------------------------------------------- case CY5: // dual trigger pad_settings.is_rim_switch = true; @@ -325,7 +321,7 @@ void Edrumulus::Pad::apply_preset_pad_settings() break; case VH12: // dual trigger -// TODO if the Hi-Hat is open just a little bit, we get double triggers + // TODO if the Hi-Hat is open just a little bit, we get double triggers pad_settings.is_rim_switch = true; pad_settings.velocity_sensitivity = 5; pad_settings.rim_shot_threshold = 23; @@ -380,7 +376,6 @@ void Edrumulus::Pad::apply_preset_pad_settings() pad_settings.velocity_sensitivity = 6; break; - // Hi-hat controllers ------------------------------------------------------ case FD8: pad_settings.is_control = true; diff --git a/teensy_name.c b/teensy_name.c index 0c4fe24..cdbd03f 100644 --- a/teensy_name.c +++ b/teensy_name.c @@ -17,22 +17,28 @@ #ifdef TEENSYDUINO -#include +# include // define the name of the Teensy USB MIDI device showing up in the operating system -#define MANUFACTURER_NAME {'v', 'o', 'f', 'i', ' ', 't', 'e', 'c'} -#define MANUFACTURER_NAME_LEN 8 -#define PRODUCT_NAME {'E', 'd', 'r', 'u', 'm', 'u', 'l', 'u', 's'} -#define PRODUCT_NAME_LEN 9 +# define MANUFACTURER_NAME \ + { \ + 'v', 'o', 'f', 'i', ' ', 't', 'e', 'c' \ + } +# define MANUFACTURER_NAME_LEN 8 +# define PRODUCT_NAME \ + { \ + 'E', 'd', 'r', 'u', 'm', 'u', 'l', 'u', 's' \ + } +# define PRODUCT_NAME_LEN 9 struct usb_string_descriptor_struct usb_string_manufacturer_name = { - 2 + MANUFACTURER_NAME_LEN * 2, - 3, - MANUFACTURER_NAME }; + 2 + MANUFACTURER_NAME_LEN * 2, + 3, + MANUFACTURER_NAME}; struct usb_string_descriptor_struct usb_string_product_name = { - 2 + PRODUCT_NAME_LEN * 2, - 3, - PRODUCT_NAME }; + 2 + PRODUCT_NAME_LEN * 2, + 3, + PRODUCT_NAME}; #endif