audio core improvements
* DC blocker: use higher quality filtering on boards with FPU (-S3 and classic esp32) * experimental: build option to increase audio task priority - reduces latency
This commit is contained in:
@@ -23,12 +23,25 @@
|
|||||||
#define FFT_PREFER_EXACT_PEAKS // use different FFT wndowing -> results in "sharper" peaks and less "leaking" into other frequencies
|
#define FFT_PREFER_EXACT_PEAKS // use different FFT wndowing -> results in "sharper" peaks and less "leaking" into other frequencies
|
||||||
//#define SR_STATS
|
//#define SR_STATS
|
||||||
|
|
||||||
|
#if !defined(FFTTASK_PRIORITY)
|
||||||
|
#define FFTTASK_PRIORITY 1 // standard: looptask prio
|
||||||
|
//#define FFTTASK_PRIORITY 2 // above looptask, below asyc_tcp
|
||||||
|
//#define FFTTASK_PRIORITY 4 // above asyc_tcp
|
||||||
|
#endif
|
||||||
|
|
||||||
#if !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C3)
|
#if !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C3)
|
||||||
// this applies "pink noise scaling" to FFT results before computing the major peak for effects.
|
// this applies "pink noise scaling" to FFT results before computing the major peak for effects.
|
||||||
// currently only for ESP32-S3 and classic ESP32, due to increased runtime
|
// currently only for ESP32-S3 and classic ESP32, due to increased runtime
|
||||||
#define FFT_MAJORPEAK_HUMAN_EAR
|
#define FFT_MAJORPEAK_HUMAN_EAR
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// high-resolution type for input filters
|
||||||
|
#if !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C3)
|
||||||
|
#define SR_HIRES_TYPE double // ESP32 and ESP32-S3 (with FPU) are fast enough to use "double"
|
||||||
|
#else
|
||||||
|
#define SR_HIRES_TYPE float // prefer faster type on slower boards (-S2, -C3)
|
||||||
|
#endif
|
||||||
|
|
||||||
// Comment/Uncomment to toggle usb serial debugging
|
// Comment/Uncomment to toggle usb serial debugging
|
||||||
// #define MIC_LOGGER // MIC sampling & sound input debugging (serial plotter)
|
// #define MIC_LOGGER // MIC sampling & sound input debugging (serial plotter)
|
||||||
// #define FFT_SAMPLING_LOG // FFT result debugging
|
// #define FFT_SAMPLING_LOG // FFT result debugging
|
||||||
@@ -250,9 +263,6 @@ static float sampleTime = 0; // avg (blocked) time for reading I2S sample
|
|||||||
static float lastFftCalc[NUM_GEQ_CHANNELS] = {0.0f}; // backup of last FFT channels (before postprocessing)
|
static float lastFftCalc[NUM_GEQ_CHANNELS] = {0.0f}; // backup of last FFT channels (before postprocessing)
|
||||||
static float fftCalc[NUM_GEQ_CHANNELS] = {0.0f}; // Try and normalize fftBin values to a max of 4096, so that 4096/16 = 256.
|
static float fftCalc[NUM_GEQ_CHANNELS] = {0.0f}; // Try and normalize fftBin values to a max of 4096, so that 4096/16 = 256.
|
||||||
static float fftAvg[NUM_GEQ_CHANNELS] = {0.0f}; // Calculated frequency channel results, with smoothing (used if dynamics limiter is ON)
|
static float fftAvg[NUM_GEQ_CHANNELS] = {0.0f}; // Calculated frequency channel results, with smoothing (used if dynamics limiter is ON)
|
||||||
#ifdef SR_DEBUG
|
|
||||||
static float fftResultMax[NUM_GEQ_CHANNELS] = {0.0f}; // A table used for testing to determine how our post-processing is working.
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if !defined(CONFIG_IDF_TARGET_ESP32C3)
|
#if !defined(CONFIG_IDF_TARGET_ESP32C3)
|
||||||
// audio source parameters and constant
|
// audio source parameters and constant
|
||||||
@@ -366,11 +376,11 @@ constexpr bool skipSecondFFT = false;
|
|||||||
static void runDCBlocker(uint_fast16_t numSamples, float *sampleBuffer) {
|
static void runDCBlocker(uint_fast16_t numSamples, float *sampleBuffer) {
|
||||||
constexpr float filterR = 0.990f; // around 40hz
|
constexpr float filterR = 0.990f; // around 40hz
|
||||||
static float xm1 = 0.0f;
|
static float xm1 = 0.0f;
|
||||||
static float ym1 = 0.0f;
|
static SR_HIRES_TYPE ym1 = 0.0f;
|
||||||
|
|
||||||
for (unsigned i=0; i < numSamples; i++) {
|
for (unsigned i=0; i < numSamples; i++) {
|
||||||
float value = sampleBuffer[i];
|
float value = sampleBuffer[i];
|
||||||
float filtered = value-xm1 + filterR*ym1;
|
SR_HIRES_TYPE filtered = (SR_HIRES_TYPE)(value-xm1) + filterR*ym1;
|
||||||
xm1 = value;
|
xm1 = value;
|
||||||
ym1 = filtered;
|
ym1 = filtered;
|
||||||
sampleBuffer[i] = filtered;
|
sampleBuffer[i] = filtered;
|
||||||
@@ -382,14 +392,21 @@ static void runDCBlocker(uint_fast16_t numSamples, float *sampleBuffer) {
|
|||||||
//
|
//
|
||||||
void FFTcode(void * parameter)
|
void FFTcode(void * parameter)
|
||||||
{
|
{
|
||||||
// DEBUGSR_PRINT("FFT started on core: "); DEBUGSR_PRINTLN(xPortGetCoreID()); // causes trouble on -S2
|
#ifdef SR_DEBUG
|
||||||
|
USER_FLUSH();
|
||||||
|
USER_PRINT("AR: "); USER_PRINT(pcTaskGetTaskName(NULL));
|
||||||
|
USER_PRINT(" task started on core "); USER_PRINT(xPortGetCoreID()); // causes trouble on -S2
|
||||||
|
USER_PRINT(" [prio="); USER_PRINT(uxTaskPriorityGet(NULL));
|
||||||
|
USER_PRINT(", min free stack="); USER_PRINT(uxTaskGetStackHighWaterMark(NULL));
|
||||||
|
USER_PRINTLN("]"); USER_FLUSH();
|
||||||
|
#endif
|
||||||
|
|
||||||
// see https://www.freertos.org/vtaskdelayuntil.html
|
// see https://www.freertos.org/vtaskdelayuntil.html
|
||||||
const TickType_t xFrequency = FFT_MIN_CYCLE * portTICK_PERIOD_MS;
|
const TickType_t xFrequency = FFT_MIN_CYCLE * portTICK_PERIOD_MS;
|
||||||
const TickType_t xFrequencyDouble = FFT_MIN_CYCLE * portTICK_PERIOD_MS * 2;
|
const TickType_t xFrequencyDouble = FFT_MIN_CYCLE * portTICK_PERIOD_MS * 2;
|
||||||
static bool isFirstRun = false;
|
static bool isFirstRun = false;
|
||||||
|
|
||||||
#ifdef FFT_MAJORPEAK_HUMAN_EAR
|
#ifdef FFT_MAJORPEAK_HUMAN_EAR
|
||||||
// pre-compute pink noise scaling table
|
// pre-compute pink noise scaling table
|
||||||
for(uint_fast16_t binInd = 0; binInd < samplesFFT; binInd++) {
|
for(uint_fast16_t binInd = 0; binInd < samplesFFT; binInd++) {
|
||||||
float binFreq = binInd * binWidth + binWidth/2.0f;
|
float binFreq = binInd * binWidth + binWidth/2.0f;
|
||||||
@@ -398,7 +415,7 @@ void FFTcode(void * parameter)
|
|||||||
pinkFactors[binInd] = sqrtf(binFreq) / pinkcenter;
|
pinkFactors[binInd] = sqrtf(binFreq) / pinkcenter;
|
||||||
}
|
}
|
||||||
pinkFactors[0] *= 0.5; // suppress 0-42hz bin
|
pinkFactors[0] *= 0.5; // suppress 0-42hz bin
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
TickType_t xLastWakeTime = xTaskGetTickCount();
|
TickType_t xLastWakeTime = xTaskGetTickCount();
|
||||||
for(;;) {
|
for(;;) {
|
||||||
@@ -1936,7 +1953,7 @@ class AudioReactive : public Usermod {
|
|||||||
"FFT", // Name of the task
|
"FFT", // Name of the task
|
||||||
5000, // Stack size in words
|
5000, // Stack size in words
|
||||||
NULL, // Task input parameter
|
NULL, // Task input parameter
|
||||||
1, // Priority of the task
|
FFTTASK_PRIORITY, // Priority of the task
|
||||||
&FFT_Task // Task handle
|
&FFT_Task // Task handle
|
||||||
, 0 // Core where the task should run
|
, 0 // Core where the task should run
|
||||||
);
|
);
|
||||||
|
|||||||
Reference in New Issue
Block a user