Analyzing audio and extract control values out of it

Hi,
I am having an audio signal which additionally to the music has three control signals embedded playing around 19 - 20 kHz. The signals are used to drive LED's that blink accordingly to the audio which is played (binaural beats). The blinking of the LED's and the audio have to be 100% in sync but I suppose this is an issue for dealing with later in the project.
I want to use an ESP 32 and I suppose there has to be some kind of FFT analysis done.
I am just wondering how to set it to "extract" the specific frequencies I am interested in

18200 Hz
18700 Hz
19200 Hz
19700 Hz
Thanks for helping :slight_smile:

The web search phrase "arduino tone detection" will turn up several possibilities to explore.

Hi. To detect your four specific frequencies the best method is to sample the audio at >40 kHz (Shannon–Hartley theorem) through the ADC, and then apply the Goertzel algorithm individually for each frequency because it is much faster and more efficient than a full FFT when you only care about a few tones; I gave you an example where the ESP32 samples the signal, runs Goertzel over blocks of 256 samples, measures the energy at each target frequency, compares it to a threshold, and triggers actions (like blinking LEDs) if a frequency is detected, ensuring near real-time response and very low latency suitable for synchronized audio-visual effects

#include <driver/adc.h>

#define SAMPLE_RATE  44100
#define BLOCK_SIZE   256

// Frequencies to detect
const float targetFreqs[] = {18200.0, 18700.0, 19200.0, 19700.0};
const int NUM_FREQS = sizeof(targetFreqs) / sizeof(targetFreqs[0]);

// ADC pin (adjust to your wiring)
const int ADC_PIN = 34;

// Threshold to consider the signal present
const float THRESHOLD = 5000.0;

// Storage for samples
int16_t samples[BLOCK_SIZE];

// Coefficients and state for Goertzel
float coeffs[NUM_FREQS];
float q1[NUM_FREQS];
float q2[NUM_FREQS];

void setup() {
  Serial.begin(115200);
  analogReadResolution(12); // ESP32 ADC is 12-bit
  
  // Precompute Goertzel coefficients
  for (int i = 0; i < NUM_FREQS; i++) {
    float normalizedFreq = targetFreqs[i] / SAMPLE_RATE;
    coeffs[i] = 2.0 * cos(2.0 * PI * normalizedFreq);
    q1[i] = 0;
    q2[i] = 0;
  }

  // Setup ADC if necessary
  adc1_config_width(ADC_WIDTH_BIT_12);
  adc1_config_channel_atten((adc1_channel_t)ADC1_CHANNEL_6, ADC_ATTEN_DB_11); // GPIO34 -> channel 6
}

void loop() {
  // 1. Collect a block of samples
  for (int i = 0; i < BLOCK_SIZE; i++) {
    samples[i] = analogRead(ADC_PIN) - 2048; // Center around 0
    delayMicroseconds(1000000 / SAMPLE_RATE);
  }

  // 2. Reset Goertzel state
  for (int f = 0; f < NUM_FREQS; f++) {
    q1[f] = 0;
    q2[f] = 0;
  }

  // 3. Process samples
  for (int i = 0; i < BLOCK_SIZE; i++) {
    for (int f = 0; f < NUM_FREQS; f++) {
      float q0 = coeffs[f] * q1[f] - q2[f] + samples[i];
      q2[f] = q1[f];
      q1[f] = q0;
    }
  }

  // 4. Compute magnitudes
  for (int f = 0; f < NUM_FREQS; f++) {
    float magnitude = q1[f]*q1[f] + q2[f]*q2[f] - q1[f]*q2[f]*coeffs[f];

    Serial.print("Freq ");
    Serial.print(targetFreqs[f]);
    Serial.print(" Hz: ");
    Serial.println(magnitude);

    if (magnitude > THRESHOLD) {
      Serial.print("-> Detected signal at ");
      Serial.print(targetFreqs[f]);
      Serial.println(" Hz");
      // You can blink your LEDs here based on 'f'
    }
  }

  delay(10); // Short delay to avoid overloading Serial
}
1 Like

Awesome, thank you so much for your help.

I am still waiting for the esp32 but can that example be modifyed easily to work with an audiostream the esp receives over bluetooth?
Thanks for helping
Jens

yes, it can be adapted to work with audio received over Bluetooth by using a Bluetooth A2DP sink library to receive PCM audio in real time through a callback, extracting the left channel samples, buffering them in blocks (e.g., 256 samples), and then running the same Goertzel processing logic on each block to detect the desired frequencies. Note that it eill have a greater latency tho

Be aware that some people can here signals that high so it will be very painful to listen to the music. My son is 43 and can still detect those sorts of frequencies and it is very painful.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.