FluxBench.AIShared project · read-only

I2S Sound Level Meter

ESP32 DevKit (WROOM-32)·Arduino C++·Updated Jul 27, 2026·by FluxBench TeamIncludes Lab + Schematic + PCB

An INMP441 MEMS microphone streams 16-bit audio into the ESP32 over I2S (SCK GPIO32, WS GPIO25, SD GPIO33). Every 100 ms the sketch reads a 256-sample block with the ESP-IDF i2s_read() driver, computes the RMS level, converts it to dBFS and lights a proportional 5-LED VU bar (2 green, 2 yellow, 1 red) while printing a matching serial bar graph. The simulator feeds the mic a synthetic ambient tone whose loudness slowly rises and falls, so the VU bar sweeps up and down just like a real room. Bundled Lab bench, schematic and routed PCB included.

sketch.ino
// I2S Sound Level Meter — INMP441 MEMS microphone + 5-LED VU bar
//
// The INMP441 streams 16-bit audio over I2S. Every 100 ms the sketch reads a
// block of samples, computes the RMS level, converts it to a dB-style value
// and lights a proportional bar of LEDs (2 green, 2 yellow, 1 red).
#include <driver/i2s.h>

#define I2S_SCK 32   // BCLK  — serial clock
#define I2S_WS  25   // LRCLK — word select
#define I2S_SD  33   // DOUT from the microphone

#define SAMPLE_RATE 16000
#define BLOCK_SIZE  256

const int ledPins[5] = {23, 22, 21, 19, 18}; // VU bar, quiet -> loud
int16_t samples[BLOCK_SIZE];

void setup() {
  Serial.begin(115200);
  for (int i = 0; i < 5; i++) {
    pinMode(ledPins[i], OUTPUT);
    digitalWrite(ledPins[i], LOW);
  }

  i2s_config_t cfg;
  cfg.mode = (i2s_mode_t)(I2S_MODE_MASTER | I2S_MODE_RX);
  cfg.sample_rate = SAMPLE_RATE;
  cfg.bits_per_sample = I2S_BITS_PER_SAMPLE_16BIT;
  cfg.channel_format = I2S_CHANNEL_FMT_ONLY_LEFT;
  cfg.communication_format = I2S_COMM_FORMAT_STAND_I2S;
  cfg.intr_alloc_flags = 0;
  cfg.dma_buf_count = 4;
  cfg.dma_buf_len = BLOCK_SIZE;
  i2s_driver_install(I2S_NUM_0, &cfg, 0, NULL);

  i2s_pin_config_t pins;
  pins.mck_io_num = I2S_PIN_NO_CHANGE;
  pins.bck_io_num = I2S_SCK;
  pins.ws_io_num = I2S_WS;
  pins.data_out_num = I2S_PIN_NO_CHANGE;
  pins.data_in_num = I2S_SD;
  i2s_set_pin(I2S_NUM_0, &pins);

  Serial.println("I2S sound level meter ready");
}

void loop() {
  size_t bytesRead = 0;
  i2s_read(I2S_NUM_0, samples, BLOCK_SIZE * 2, &bytesRead, 100);
  int n = bytesRead / 2;
  if (n == 0) { delay(10); return; }

  // RMS level of the block
  float sumSq = 0;
  for (int i = 0; i < n; i++) {
    float s = samples[i];
    sumSq += s * s;
  }
  float rms = sqrt(sumSq / n);

  // Rough dBFS (0 dB = full-scale 32768) mapped onto a 0-5 LED bar
  float db = 20.0 * log10(rms / 32768.0 + 0.0000001);
  float thresholds[5] = {-24.0, -21.5, -19.5, -17.5, -16.0};
  int bar = 0;
  for (int i = 0; i < 5; i++) {
    if (db >= thresholds[i]) bar = i + 1;
  }

  for (int i = 0; i < 5; i++) {
    digitalWrite(ledPins[i], i < bar ? HIGH : LOW);
  }

  Serial.print("RMS ");
  Serial.print(rms, 0);
  Serial.print("  ");
  Serial.print(db, 1);
  Serial.print(" dBFS  [");
  for (int i = 0; i < 5; i++) Serial.print(i < bar ? "#" : ".");
  Serial.println("]");

  delay(100);
}

Built with FluxBench.AI — the AI workbench for embedded projects.