estimated audio sound pressure

This commit is contained in:
Frank
2023-04-06 18:58:20 +02:00
parent b09077627e
commit 197e120e3b
3 changed files with 78 additions and 6 deletions

View File

@@ -232,6 +232,7 @@ static const float fftResultPink[MAX_PINK+1][NUM_GEQ_CHANNELS] = {
// globals and FFT Output variables shared with animations
static float FFT_MajorPeak = 1.0f; // FFT: strongest (peak) frequency
static float FFT_Magnitude = 0.0f; // FFT: volume (magnitude) of peak frequency
static float FFT_MajPeakSmth = 1.0f; // FFT: (peak) frequency, smooth
static uint8_t fftResult[NUM_GEQ_CHANNELS]= {0};// Our calculated freq. channel result table to be used by effects
#if defined(WLED_DEBUG) || defined(SR_DEBUG) || defined(SR_STATS)
static float fftTaskCycle = 0; // avg cycle time for FFT task
@@ -498,6 +499,7 @@ void FFTcode(void * parameter)
FFT.MajorPeak(&FFT_MajorPeak, &FFT_Magnitude); // let the effects know which freq was most dominant
#endif
FFT_MajorPeak = constrain(FFT_MajorPeak, 1.0f, 11025.0f); // restrict value to range expected by effects
FFT_MajPeakSmth = FFT_MajPeakSmth + 0.42 * (FFT_MajorPeak - FFT_MajPeakSmth); // I like this "swooping peak" look
} else { // skip second run --> clear fft results, keep peaks
memset(vReal, 0, sizeof(vReal));
@@ -918,6 +920,8 @@ class AudioReactive : public Usermod {
// variables used in effects
int16_t volumeRaw = 0; // either sampleRaw or rawSampleAgc depending on soundAgc
float my_magnitude =0.0f; // FFT_Magnitude, scaled by multAgc
float agcSensitivity = 128; // AGC sensitivity estimation, based on agc gain (multAgc). calculated by getSensitivity(). range 0..255
float soundPressure = 0; // Sound Pressure estimation, based on microphone raw readings. 0 ->5db, 255 ->105db
// used to feed "Info" Page
unsigned long last_UDPTime = 0; // time of last valid UDP sound sync datapacket
@@ -1228,6 +1232,53 @@ class AudioReactive : public Usermod {
} // getSample()
// current sensitivity, based on AGC gain (multAgc)
float getSensitivity()
{
// start with AGC gain factor
float tmpSound = multAgc;
// experimental: this gives you a calculated "real gain"
// if ((sampleAvg> 1.0) && (sampleReal > 0.05)) tmpSound = (float)sampleRaw / sampleReal; // calculate gain from sampleReal
// else tmpSound = ((float)sampleGain/40.0f * (float)inputLevel/128.0f) + 1.0f/16.0f; // silence --> use values from user settings
if (soundAgc == 0)
tmpSound = ((float)sampleGain/40.0f * (float)inputLevel/128.0f) + 1.0f/16.0f; // AGC off -> use non-AGC gain from presets
else
tmpSound /= (float)sampleGain/40.0f + 1.0f/16.0f; // AGC ON -> scale value so 1 = middle value
// scale to 0..255. Actually I'm not absolutely happy with this, but it works
if (tmpSound > 1.0) tmpSound = sqrtf(tmpSound);
if (tmpSound > 1.25) tmpSound = ((tmpSound-1.25f)/3.42f) +1.25f;
// we have a value now that should be between 0 and 4 (representing gain 1/16 ... 16.0)
return fminf(fmaxf(128.0*tmpSound -6.0f, 0), 255.0); // return scaled non-inverted value // "-6" to ignore values below 1/24
}
// estimate sound pressure, based on some assumptions :
// * sample max = 32676 -> Acoustic overload point --> 105db ==> 255
// * sample < squelch -> just above hearing level --> 5db ==> 0
// see https://en.wikipedia.org/wiki/Sound_pressure#Examples_of_sound_pressure
// use with I2S digital microphones. Expect stupid values for analog in, and with Line-In !!
float estimatePressure() {
// some constants
constexpr float logMinSample = 1.2237754316221f; // ln(3.4)
constexpr float sampleMin = 3.4f;
constexpr float logMaxSample = 10.1895683436f; // ln(32767 - 6144)
constexpr float sampleMax = 32767.0f - 6144.0f;
// take the max sample from last I2S batch.
float micSampleMax = fabsf(sampleReal); // from getSample() - nice results, however distorted by MicLev processing
//float micSampleMax = fabsf(micDataReal); // from FFTCode() - better source, but I'll do more testing before activating this
// make sure we are in expected ranges
if(micSampleMax <= sampleMin) return 0.0f;
if(micSampleMax >= sampleMax) return 255.0f;
// apply logarithmic scaling
float scaledvalue = logf(micSampleMax);
scaledvalue = (scaledvalue - logMinSample) / (logMaxSample - logMinSample); // 0...1
return fminf(fmaxf(256.0*scaledvalue, 0), 255.0); // scaled value
}
/* Limits the dynamics of volumeSmth (= sampleAvg or sampleAgc).
* does not affect FFTResult[] or volumeRaw ( = sample or rawSampleAgc)
*/
@@ -1422,12 +1473,12 @@ class AudioReactive : public Usermod {
// usermod exchangeable data
// we will assign all usermod exportable data here as pointers to original variables or arrays and allocate memory for pointers
um_data = new um_data_t;
um_data->u_size = 8;
um_data->u_size = 11;
um_data->u_type = new um_types_t[um_data->u_size];
um_data->u_data = new void*[um_data->u_size];
um_data->u_data[0] = &volumeSmth; //*used (New)
um_data->u_type[0] = UMT_FLOAT;
um_data->u_data[1] = &volumeRaw; // used (New)
um_data->u_data[1] = &volumeRaw; // used (New)
um_data->u_type[1] = UMT_UINT16;
um_data->u_data[2] = fftResult; //*used (Blurz, DJ Light, Noisemove, GEQ_base, 2D Funky Plank, Akemi)
um_data->u_type[2] = UMT_BYTE_ARR;
@@ -1435,12 +1486,18 @@ class AudioReactive : public Usermod {
um_data->u_type[3] = UMT_BYTE;
um_data->u_data[4] = &FFT_MajorPeak; //*used (Ripplepeak, Freqmap, Freqmatrix, Freqpixels, Freqwave, Gravfreq, Rocktaves, Waterfall)
um_data->u_type[4] = UMT_FLOAT;
um_data->u_data[5] = &my_magnitude; // used (New)
um_data->u_data[5] = &my_magnitude; // used (New)
um_data->u_type[5] = UMT_FLOAT;
um_data->u_data[6] = &maxVol; // assigned in effect function from UI element!!! (Puddlepeak, Ripplepeak, Waterfall)
um_data->u_type[6] = UMT_BYTE;
um_data->u_data[7] = &binNum; // assigned in effect function from UI element!!! (Puddlepeak, Ripplepeak, Waterfall)
um_data->u_type[7] = UMT_BYTE;
um_data->u_data[8] = &FFT_MajPeakSmth; // new
um_data->u_type[8] = UMT_FLOAT;
um_data->u_data[9] = &soundPressure; // used (New)
um_data->u_type[9] = UMT_FLOAT;
um_data->u_data[10] = &agcSensitivity; // used (New)
um_data->u_type[10] = UMT_FLOAT;
}
// Reset I2S peripheral for good measure
@@ -1666,6 +1723,16 @@ class AudioReactive : public Usermod {
if (soundAgc) my_magnitude *= multAgc;
if (volumeSmth < 1 ) my_magnitude = 0.001f; // noise gate closed - mute
// get AGC sensitivity and sound pressure
static unsigned long lastEstimate = 0;
if (millis() - lastEstimate > 12) {
lastEstimate = millis();
agcSensitivity = getSensitivity();
if (limiterOn)
soundPressure = soundPressure + 0.38f * (estimatePressure() - soundPressure); // dynamics limiter on -> some smoothing
else
soundPressure = soundPressure + 0.95f * (estimatePressure() - soundPressure); // dynamics limiter on -> raw value
}
limitSampleDynamics();
} // if (!disableSoundProcessing)

View File

@@ -5976,14 +5976,16 @@ static const char _data_FX_MODE_2DDRIFTROSE[] PROGMEM = "Drift Rose@Fade,Blur;;;
um_data_t *um_data;
if (usermods.getUMData(&um_data, USERMOD_ID_AUDIOREACTIVE)) {
volumeSmth = *(float*) um_data->u_data[0];
volumeRaw = *(float*) um_data->u_data[1];
volumeRaw = *(int16_t*) um_data->u_data[1];
fftResult = (uint8_t*) um_data->u_data[2];
samplePeak = *(uint8_t*) um_data->u_data[3];
FFT_MajorPeak = *(float*) um_data->u_data[4];
my_magnitude = *(float*) um_data->u_data[5];
maxVol = (uint8_t*) um_data->u_data[6]; // requires UI element (SEGMENT.customX?), changes source element
binNum = (uint8_t*) um_data->u_data[7]; // requires UI element (SEGMENT.customX?), changes source element
fftBin = (float*) um_data->u_data[8];
FFT_MajPeakSmth= *(float*) um_data->u_data[8]; // FFT Majorpeak smoothed
soundPressure = *(float*) um_data->u_data[9]; // sound pressure ( = logarithmic scale microphone input). Range 0...255
agcSensitivity = *(float*) um_data->u_data[10]; // current AGC gain, scaled to 0...255. use "255.0f - agcSensitivity" to get MIC input level
} else {
// add support for no audio data
um_data = simulateSound(SEGMENT.soundSim);

View File

@@ -423,7 +423,7 @@ um_data_t* simulateSound(uint8_t simulationId)
// NOTE!!!
// This may change as AudioReactive usermod may change
um_data = new um_data_t;
um_data->u_size = 8;
um_data->u_size = 11;
um_data->u_type = new um_types_t[um_data->u_size];
um_data->u_data = new void*[um_data->u_size];
um_data->u_data[0] = &volumeSmth;
@@ -434,6 +434,9 @@ um_data_t* simulateSound(uint8_t simulationId)
um_data->u_data[5] = &my_magnitude;
um_data->u_data[6] = &maxVol;
um_data->u_data[7] = &binNum;
um_data->u_data[8] = &FFT_MajorPeak; // dummy (samplePeak smoothed)
um_data->u_data[9] = &volumeSmth; // dummy (soundPressure)
um_data->u_data[10] = &volumeSmth; // dummy (agcSensitivity)
} else {
// get arrays from um_data
fftResult = (uint8_t*)um_data->u_data[2];