some cleanup and re-grouping of variables
- put variables with same context next to each other. - removed a few vars that are not needed any more. - replaced "16" by a more descriptive constant
This commit is contained in:
parent
cf46564c67
commit
5c792eb869
@ -85,14 +85,11 @@ const float agcSampleSmooth[AGC_NUM_PRESETS] = { 1/12.f, 1/6.f, 1/16.f}; //
|
|||||||
static AudioSource *audioSource = nullptr;
|
static AudioSource *audioSource = nullptr;
|
||||||
static volatile bool disableSoundProcessing = false; // if true, sound processing (FFT, filters, AGC) will be suspended. "volatile" as its shared between tasks.
|
static volatile bool disableSoundProcessing = false; // if true, sound processing (FFT, filters, AGC) will be suspended. "volatile" as its shared between tasks.
|
||||||
|
|
||||||
|
// audioreactive variables shared with FFT task
|
||||||
static float micDataReal = 0.0f; // MicIn data with full 24bit resolution - lowest 8bit after decimal point
|
static float micDataReal = 0.0f; // MicIn data with full 24bit resolution - lowest 8bit after decimal point
|
||||||
static float sampleReal = 0.0f; // "sampleRaw" as float, to provide bits that are lost otherwise (before amplification by sampleGain or inputLevel). Needed for AGC.
|
|
||||||
static float multAgc = 1.0f; // sample * multAgc = sampleAgc. Our AGC multiplier
|
static float multAgc = 1.0f; // sample * multAgc = sampleAgc. Our AGC multiplier
|
||||||
|
static float sampleAvg = 0.0f; // Smoothed Average sample - sampleAvg < 1 means "quiet" (simple noise gate)
|
||||||
|
|
||||||
static int16_t sampleRaw = 0; // Current sample. Must only be updated ONCE!!! (amplified mic value by sampleGain and inputLevel)
|
|
||||||
static int16_t rawSampleAgc = 0; // not smoothed AGC sample
|
|
||||||
static float sampleAvg = 0.0f; // Smoothed Average sampleRaw
|
|
||||||
static float sampleAgc = 0.0f; // Smoothed AGC sample
|
|
||||||
|
|
||||||
////////////////////
|
////////////////////
|
||||||
// Begin FFT Code //
|
// Begin FFT Code //
|
||||||
@ -105,21 +102,23 @@ static float sampleAgc = 0.0f; // Smoothed AGC sample
|
|||||||
#endif
|
#endif
|
||||||
#include "arduinoFFT.h"
|
#include "arduinoFFT.h"
|
||||||
|
|
||||||
// FFT Variables
|
// FFT Output variables shared with animations
|
||||||
|
#define NUM_GEQ_CHANNELS 16 // number of frequency channels. Don't change !!
|
||||||
|
static float FFT_MajorPeak = 1.0f; // FFT: strongest (peak) frequency
|
||||||
|
static float FFT_Magnitude = 0.0f; // FFT: magintude peak frequency
|
||||||
|
static uint8_t fftResult[NUM_GEQ_CHANNELS]= {0};// Our calculated freq. channel result table to be used by effects
|
||||||
|
|
||||||
|
// FFT Constants
|
||||||
constexpr uint16_t samplesFFT = 512; // Samples in an FFT batch - This value MUST ALWAYS be a power of 2
|
constexpr uint16_t samplesFFT = 512; // Samples in an FFT batch - This value MUST ALWAYS be a power of 2
|
||||||
constexpr uint16_t samplesFFT_2 = 256; // meaningfull part of FFT results - only the "lower half" contains useful information.
|
constexpr uint16_t samplesFFT_2 = 256; // meaningfull part of FFT results - only the "lower half" contains useful information.
|
||||||
|
|
||||||
static float FFT_MajorPeak = 1.0f;
|
|
||||||
static float FFT_Magnitude = 0.0f;
|
|
||||||
|
|
||||||
// These are the input and output vectors. Input vectors receive computed results from FFT.
|
// These are the input and output vectors. Input vectors receive computed results from FFT.
|
||||||
static float vReal[samplesFFT] = {0.0f};
|
static float vReal[samplesFFT] = {0.0f}; // FFT sample inputs / freq output - these are our raw result bins
|
||||||
static float vImag[samplesFFT] = {0.0f};
|
static float vImag[samplesFFT] = {0.0f}; // imaginary parts
|
||||||
static float fftBin[samplesFFT_2] = {0.0f};
|
static float fftBin[samplesFFT_2] = {0.0f};
|
||||||
|
|
||||||
// the following are observed values, supported by a bit of "educated guessing"
|
// the following are observed values, supported by a bit of "educated guessing"
|
||||||
//#define FFT_DOWNSCALE 0.65f // 20kHz - downscaling factor for FFT results - "Flat-Top" window @20Khz, old freq channels
|
//#define FFT_DOWNSCALE 0.65f // 20kHz - downscaling factor for FFT results - "Flat-Top" window @20Khz, old freq channels
|
||||||
|
|
||||||
#define FFT_DOWNSCALE 0.46f // downscaling factor for FFT results - for "Flat-Top" window @22Khz, new freq channels
|
#define FFT_DOWNSCALE 0.46f // downscaling factor for FFT results - for "Flat-Top" window @22Khz, new freq channels
|
||||||
#define LOG_256 5.54517744
|
#define LOG_256 5.54517744
|
||||||
|
|
||||||
@ -129,12 +128,11 @@ static float windowWeighingFactors[samplesFFT] = {0.0f};
|
|||||||
|
|
||||||
// Try and normalize fftBin values to a max of 4096, so that 4096/16 = 256.
|
// Try and normalize fftBin values to a max of 4096, so that 4096/16 = 256.
|
||||||
// Oh, and bins 0,1,2 are no good, so we'll zero them out.
|
// Oh, and bins 0,1,2 are no good, so we'll zero them out.
|
||||||
static float fftCalc[16] = {0.0f};
|
static float fftCalc[NUM_GEQ_CHANNELS] = {0.0f};
|
||||||
static uint8_t fftResult[16] = {0}; // Our calculated result table, which we feed to the animations.
|
static float fftAvg[NUM_GEQ_CHANNELS] = {0.0f}; // Calculated frequency channel results, with smoothing (used if dynamics limiter is ON)
|
||||||
#ifdef SR_DEBUG
|
#ifdef SR_DEBUG
|
||||||
static float fftResultMax[16] = {0.0f}; // A table used for testing to determine how our post-processing is working.
|
static float fftResultMax[NUM_GEQ_CHANNELS] = {0.0f}; // A table used for testing to determine how our post-processing is working.
|
||||||
#endif
|
#endif
|
||||||
static float fftAvg[16] = {0.0f};
|
|
||||||
|
|
||||||
#ifdef WLED_DEBUG
|
#ifdef WLED_DEBUG
|
||||||
static unsigned long fftTime = 0;
|
static unsigned long fftTime = 0;
|
||||||
@ -142,7 +140,7 @@ static unsigned long sampleTime = 0;
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Table of multiplication factors so that we can even out the frequency response.
|
// Table of multiplication factors so that we can even out the frequency response.
|
||||||
static float fftResultPink[16] = { 1.70f, 1.71f, 1.73f, 1.78f, 1.68f, 1.56f, 1.55f, 1.63f, 1.79f, 1.62f, 1.80f, 2.06f, 2.47f, 3.35f, 6.83f, 9.55f };
|
static float fftResultPink[NUM_GEQ_CHANNELS] = { 1.70f, 1.71f, 1.73f, 1.78f, 1.68f, 1.56f, 1.55f, 1.63f, 1.79f, 1.62f, 1.80f, 2.06f, 2.47f, 3.35f, 6.83f, 9.55f };
|
||||||
|
|
||||||
// Create FFT object
|
// Create FFT object
|
||||||
#ifdef UM_AUDIOREACTIVE_USE_NEW_FFT
|
#ifdef UM_AUDIOREACTIVE_USE_NEW_FFT
|
||||||
@ -292,14 +290,14 @@ void FFTcode(void * parameter)
|
|||||||
// don't use the last bins from 216 to 255. They are usually contaminated by aliasing (aka noise)
|
// don't use the last bins from 216 to 255. They are usually contaminated by aliasing (aka noise)
|
||||||
#endif
|
#endif
|
||||||
} else { // noise gate closed - just decay old values
|
} else { // noise gate closed - just decay old values
|
||||||
for (int i=0; i < 16; i++) {
|
for (int i=0; i < NUM_GEQ_CHANNELS; i++) {
|
||||||
fftCalc[i] *= 0.85f; // decay to zero
|
fftCalc[i] *= 0.85f; // decay to zero
|
||||||
if (fftCalc[i] < 4.0f) fftCalc[i] = 0.0f;
|
if (fftCalc[i] < 4.0f) fftCalc[i] = 0.0f;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// post-processing of frequency channels (pink noise adjustment, AGC, smooting, scaling)
|
// post-processing of frequency channels (pink noise adjustment, AGC, smooting, scaling)
|
||||||
for (int i=0; i < 16; i++) {
|
for (int i=0; i < NUM_GEQ_CHANNELS; i++) {
|
||||||
|
|
||||||
if (sampleAvg > 1) { // noise gate open
|
if (sampleAvg > 1) { // noise gate open
|
||||||
// Adjustment for frequency curves.
|
// Adjustment for frequency curves.
|
||||||
@ -378,9 +376,8 @@ void FFTcode(void * parameter)
|
|||||||
fftTime = (fftTimeInMillis*3 + fftTime*7)/10; // smooth
|
fftTime = (fftTimeInMillis*3 + fftTime*7)/10; // smooth
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
} // for(;;)ever
|
||||||
} // for(;;)
|
} // FFTcode() task end
|
||||||
} // FFTcode()
|
|
||||||
|
|
||||||
|
|
||||||
//class name. Use something descriptive and leave the ": public Usermod" part :)
|
//class name. Use something descriptive and leave the ": public Usermod" part :)
|
||||||
@ -453,39 +450,41 @@ class AudioReactive : public Usermod {
|
|||||||
double FFT_MajorPeak; // 08 Bytes
|
double FFT_MajorPeak; // 08 Bytes
|
||||||
};
|
};
|
||||||
|
|
||||||
WiFiUDP fftUdp;
|
|
||||||
|
|
||||||
// set your config variables to their boot default value (this can also be done in readFromConfig() or a constructor if you prefer)
|
// set your config variables to their boot default value (this can also be done in readFromConfig() or a constructor if you prefer)
|
||||||
bool enabled = false;
|
bool enabled = false;
|
||||||
bool initDone = false;
|
bool initDone = false;
|
||||||
|
|
||||||
const uint16_t delayMs = 10; // I don't want to sample too often and overload WLED
|
// variables for UDP sound sync
|
||||||
|
WiFiUDP fftUdp; // UDP object for sound sync (from WiFi UDP, not Async UDP!)
|
||||||
|
bool udpSyncConnected = false;// UDP connection status -> true if connected to multicast group
|
||||||
|
unsigned long lastTime = 0; // last time of running UDP Microphone Sync
|
||||||
|
const uint16_t delayMs = 10; // I don't want to sample too often and overload WLED
|
||||||
|
uint16_t audioSyncPort= 11988;// default port for UDP sound sync
|
||||||
|
|
||||||
|
// used for AGC
|
||||||
|
int last_soundAgc = -1; // used to detect AGC mode change (for resetting AGC internal error buffers)
|
||||||
|
double control_integrated = 0.0; // persistent across calls to agcAvg(); "integrator control" = accumulated error
|
||||||
|
|
||||||
|
// variables used by getSample() and agcAvg()
|
||||||
|
int16_t micIn = 0; // Current sample starts with negative values and large values, which is why it's 16 bit signed
|
||||||
|
double sampleMax = 0.0; // Max sample over a few seconds. Needed for AGC controler.
|
||||||
|
float micLev = 0.0f; // Used to convert returned value to have '0' as minimum. A leveller
|
||||||
|
float expAdjF = 0.0f; // Used for exponential filter.
|
||||||
|
float sampleReal = 0.0f; // "sampleRaw" as float, to provide bits that are lost otherwise (before amplification by sampleGain or inputLevel). Needed for AGC.
|
||||||
|
int16_t sampleRaw = 0; // Current sample. Must only be updated ONCE!!! (amplified mic value by sampleGain and inputLevel)
|
||||||
|
int16_t rawSampleAgc = 0; // not smoothed AGC sample
|
||||||
|
float sampleAgc = 0.0f; // Smoothed AGC sample
|
||||||
|
|
||||||
// variables used in effects
|
// variables used in effects
|
||||||
uint8_t maxVol = 10; // Reasonable value for constant volume for 'peak detector', as it won't always trigger (deprecated)
|
|
||||||
uint8_t binNum = 8; // Used to select the bin for FFT based beat detection (deprecated)
|
|
||||||
bool samplePeak = 0; // Boolean flag for peak. Responding routine must reset this flag
|
|
||||||
float volumeSmth = 0.0f; // either sampleAvg or sampleAgc depending on soundAgc; smoothed sample
|
float volumeSmth = 0.0f; // either sampleAvg or sampleAgc depending on soundAgc; smoothed sample
|
||||||
int16_t volumeRaw = 0; // either sampleRaw or rawSampleAgc depending on soundAgc
|
int16_t volumeRaw = 0; // either sampleRaw or rawSampleAgc depending on soundAgc
|
||||||
float my_magnitude =0.0f; // FFT_Magnitude, scaled by multAgc
|
float my_magnitude =0.0f; // FFT_Magnitude, scaled by multAgc
|
||||||
|
// peak detection
|
||||||
bool udpSamplePeak = 0; // Boolean flag for peak. Set at the same tiem as samplePeak, but reset by transmitAudioData
|
uint8_t maxVol = 10; // Reasonable value for constant volume for 'peak detector', as it won't always trigger (deprecated)
|
||||||
int16_t micIn = 0; // Current sample starts with negative values and large values, which is why it's 16 bit signed
|
uint8_t binNum = 8; // Used to select the bin for FFT based beat detection (deprecated)
|
||||||
double sampleMax = 0.0; // Max sample over a few seconds. Needed for AGC controler.
|
bool samplePeak = false; // Boolean flag for peak. Responding routine may reset this flag. Auto-reset after strip.getMinShowDelay()
|
||||||
uint32_t timeOfPeak = 0;
|
bool udpSamplePeak = false; // Boolean flag for peak. Set at the same tiem as samplePeak, but reset by transmitAudioData
|
||||||
unsigned long lastTime = 0; // last time of running UDP Microphone Sync
|
unsigned long timeOfPeak = 0; // time of last sample peak detection
|
||||||
float micLev = 0.0f; // Used to convert returned value to have '0' as minimum. A leveller
|
|
||||||
float expAdjF = 0.0f; // Used for exponential filter.
|
|
||||||
|
|
||||||
bool udpSyncConnected = false;
|
|
||||||
uint16_t audioSyncPort = 11988;
|
|
||||||
|
|
||||||
// used for AGC
|
|
||||||
uint8_t lastMode = 0; // last known effect mode
|
|
||||||
int last_soundAgc = -1;
|
|
||||||
double control_integrated = 0.0; // persistent across calls to agcAvg(); "integrator control" = accumulated error
|
|
||||||
unsigned long last_update_time = 0;
|
|
||||||
unsigned long last_kick_time = 0;
|
|
||||||
uint8_t last_user_inputLevel = 0;
|
|
||||||
|
|
||||||
// used to feed "Info" Page
|
// used to feed "Info" Page
|
||||||
unsigned long last_UDPTime = 0; // time of last valid UDP sound sync datapacket
|
unsigned long last_UDPTime = 0; // time of last valid UDP sound sync datapacket
|
||||||
@ -525,7 +524,7 @@ class AudioReactive : public Usermod {
|
|||||||
|
|
||||||
#ifdef FFT_SAMPLING_LOG
|
#ifdef FFT_SAMPLING_LOG
|
||||||
#if 0
|
#if 0
|
||||||
for(int i=0; i<16; i++) {
|
for(int i=0; i<NUM_GEQ_CHANNELS; i++) {
|
||||||
Serial.print(fftResult[i]);
|
Serial.print(fftResult[i]);
|
||||||
Serial.print("\t");
|
Serial.print("\t");
|
||||||
}
|
}
|
||||||
@ -551,11 +550,11 @@ class AudioReactive : public Usermod {
|
|||||||
|
|
||||||
int maxVal = minimumMaxVal;
|
int maxVal = minimumMaxVal;
|
||||||
int minVal = 0;
|
int minVal = 0;
|
||||||
for(int i = 0; i < 16; i++) {
|
for(int i = 0; i < NUM_GEQ_CHANNELS; i++) {
|
||||||
if(fftResult[i] > maxVal) maxVal = fftResult[i];
|
if(fftResult[i] > maxVal) maxVal = fftResult[i];
|
||||||
if(fftResult[i] < minVal) minVal = fftResult[i];
|
if(fftResult[i] < minVal) minVal = fftResult[i];
|
||||||
}
|
}
|
||||||
for(int i = 0; i < 16; i++) {
|
for(int i = 0; i < NUM_GEQ_CHANNELS; i++) {
|
||||||
Serial.print(i); Serial.print(":");
|
Serial.print(i); Serial.print(":");
|
||||||
Serial.printf("%04ld ", map(fftResult[i], 0, (scaleValuesFromCurrentMaxVal ? maxVal : defaultScalingFromHighValue), (mapValuesToPlotterSpace*i*scalingToHighValue)+0, (mapValuesToPlotterSpace*i*scalingToHighValue)+scalingToHighValue-1));
|
Serial.printf("%04ld ", map(fftResult[i], 0, (scaleValuesFromCurrentMaxVal ? maxVal : defaultScalingFromHighValue), (mapValuesToPlotterSpace*i*scalingToHighValue)+0, (mapValuesToPlotterSpace*i*scalingToHighValue)+scalingToHighValue-1));
|
||||||
}
|
}
|
||||||
@ -795,7 +794,7 @@ class AudioReactive : public Usermod {
|
|||||||
udpSamplePeak = false; // Reset udpSamplePeak after we've transmitted it
|
udpSamplePeak = false; // Reset udpSamplePeak after we've transmitted it
|
||||||
transmitData.reserved1 = 0;
|
transmitData.reserved1 = 0;
|
||||||
|
|
||||||
for (int i = 0; i < 16; i++) {
|
for (int i = 0; i < NUM_GEQ_CHANNELS; i++) {
|
||||||
transmitData.fftResult[i] = (uint8_t)constrain(fftResult[i], 0, 254);
|
transmitData.fftResult[i] = (uint8_t)constrain(fftResult[i], 0, 254);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -855,7 +854,7 @@ class AudioReactive : public Usermod {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//These values are only available on the ESP32
|
//These values are only available on the ESP32
|
||||||
for (int i = 0; i < 16; i++) fftResult[i] = receivedPacket->fftResult[i];
|
for (int i = 0; i < NUM_GEQ_CHANNELS; i++) fftResult[i] = receivedPacket->fftResult[i];
|
||||||
|
|
||||||
my_magnitude = fmaxf(receivedPacket->FFT_Magnitude, 0.0f);
|
my_magnitude = fmaxf(receivedPacket->FFT_Magnitude, 0.0f);
|
||||||
FFT_Magnitude = my_magnitude;
|
FFT_Magnitude = my_magnitude;
|
||||||
@ -1036,7 +1035,6 @@ class AudioReactive : public Usermod {
|
|||||||
|
|
||||||
// Only run the sampling code IF we're not in Receive mode or realtime mode
|
// Only run the sampling code IF we're not in Receive mode or realtime mode
|
||||||
if (!(audioSyncEnabled & 0x02) && !disableSoundProcessing) {
|
if (!(audioSyncEnabled & 0x02) && !disableSoundProcessing) {
|
||||||
bool agcEffect = false;
|
|
||||||
if (soundAgc > AGC_NUM_PRESETS) soundAgc = 0; // make sure that AGC preset is valid (to avoid array bounds violation)
|
if (soundAgc > AGC_NUM_PRESETS) soundAgc = 0; // make sure that AGC preset is valid (to avoid array bounds violation)
|
||||||
|
|
||||||
unsigned long t_now = millis(); // remember current time
|
unsigned long t_now = millis(); // remember current time
|
||||||
@ -1138,7 +1136,7 @@ class AudioReactive : public Usermod {
|
|||||||
memset(fftCalc, 0, sizeof(fftCalc));
|
memset(fftCalc, 0, sizeof(fftCalc));
|
||||||
memset(fftAvg, 0, sizeof(fftAvg));
|
memset(fftAvg, 0, sizeof(fftAvg));
|
||||||
memset(fftResult, 0, sizeof(fftResult));
|
memset(fftResult, 0, sizeof(fftResult));
|
||||||
for(int i=(init?0:1); i<16; i+=2) fftResult[i] = 16; // make a tiny pattern
|
for(int i=(init?0:1); i<NUM_GEQ_CHANNELS; i+=2) fftResult[i] = 16; // make a tiny pattern
|
||||||
inputLevel = 128; // resset level slider to default
|
inputLevel = 128; // resset level slider to default
|
||||||
|
|
||||||
if (init && FFT_Task) {
|
if (init && FFT_Task) {
|
||||||
|
Loading…
Reference in New Issue
Block a user