Record audio with digital I2S MEMS microphone and store audio as wav file on PC

I would like to use a digital I2S microphone to record audio and store it as wav on a PC, preferably over serial connection. I have tried this with the boards ESP32 dev kit v1, MKR Wifi 1010 and Adafruit Feather M0 in combination with the microphones SPH0645 or INMP441, but never succeeded.

Here are the exemplary codes for the use of the ESP32 dev kit v1 with the SPH0645 from Adafruit (Overview | Adafruit I2S MEMS Microphone Breakout | Adafruit Learning System).

Arduino:


const i2s_port_t I2S_PORT = I2S_NUM_0;

void setup() {
  Serial.begin(115200);
  Serial.println("Configuring I2S...");

  const i2s_config_t i2s_config = {
    .mode = i2s_mode_t(I2S_MODE_MASTER | I2S_MODE_RX),
    .sample_rate = 16000,
    .bits_per_sample = I2S_BITS_PER_SAMPLE_32BIT,
    .channel_format = I2S_CHANNEL_FMT_ONLY_RIGHT,
    .communication_format = i2s_comm_format_t(I2S_COMM_FORMAT_I2S | I2S_COMM_FORMAT_I2S_MSB),
    .intr_alloc_flags = ESP_INTR_FLAG_LEVEL1,
    .dma_buf_count = 8, // Increased buffer count
    .dma_buf_len = 64   // Increased buffer length
};

  const i2s_pin_config_t pin_config = {
    .bck_io_num = 33,   // BCKL
    .ws_io_num = 25,    // LRCL
    .data_out_num = -1, // not used (only for speakers)
    .data_in_num = 32   // DOUT
  };

  esp_err_t err = i2s_driver_install(I2S_PORT, &i2s_config, 0, NULL);
  if (err != ESP_OK) {
    Serial.printf("Failed installing driver: %d\n", err);
    while (true);
  }

  err = i2s_set_pin(I2S_PORT, &pin_config);
  if (err != ESP_OK) {
    Serial.printf("Failed setting pin: %d\n", err);
    while (true);
  }

  Serial.println("I2S driver installed.");
}

void loop() {
  // Wait for the start command from the Python script
  if (Serial.available() > 0) {
    char command = Serial.read();
    if (command == 's') { // Start command received
      int duration = 10; // Recording duration in seconds
      int sample_rate = 16000; // Same as the ESP32 sample rate
      int samples_to_send = duration * sample_rate;
      
      for (int i = 0; i < samples_to_send; i++) {
        int32_t sample = 0;
        size_t bytes_read;
        i2s_read(I2S_PORT, &sample, 4, &bytes_read, portMAX_DELAY); // no timeout
        if (bytes_read > 0) {
          sample >>= 14;
          int16_t out = sample;
          Serial.println(out);
        }
      }
      Serial.write('e'); // Send an end signal to the Python script
    }
  }
}


Python code:

import datetime
import wave

# open a serial connection to the Arduino
ser = serial.Serial('COM16', 115200)

# ask the user for the length of the audio in seconds
length = int(input("Enter the length of the recording in seconds: "))

# get the current date and time
now = datetime.datetime.now()

# create a filename with a datetimestamp
filename = "recording_{}.wav".format(now.strftime("%Y-%m-%d_%H-%M-%S"))

# set the WAV file parameters
channels = 1
sample_width = 2 # 2 bytes per sample
sample_rate = 16000

# open a file for writing the audio data
with wave.open(filename, 'wb') as f:
    # set the WAV file parameters
    f.setnchannels(channels)
    f.setsampwidth(sample_width)
    f.setframerate(sample_rate)

    # read audio data from the serial port and write it to the file
    for i in range(length*sample_rate):
        data = ser.read(2)
        if data:
            f.writeframes(data)

# close the serial connection
ser.close()

print("Recording saved as {}".format(filename))

The above setup with the ESP32 dev kit v1 and the SPH0645 results in a wav file with the correct file structure (44 byte header etc.) but a signal that doesn't show the expected amplitudes and spectrogram features. It rather looks interrupted and distorted (see image).

Has anyone tried this and could help me figure out the correct hardware and code setup to achieve a successful recording?

Cheers!

You didn't say, in what way. In other words, you didn't give us any problem report.

Also, you report using various different hardware. Yet you post only one sketch. Which hardware does it belong to?

Did you test the different functions of each configuration using only simple test sketches, such as library examples? For the microphone, for example?

FYI, "exemplary" means roughly, "excellent". Did you mean, "example" codes?

Thanks for the response. I edited my questions a bit. I use exemplary in a less popular sense - sorry. https://www.merriam-webster.com/dictionary/exemplary

How do you know what to expect?

If you play back the recording as audio, does it sound like the original signal?

No, it doesn't. I would expect a continuous background noise and a set of signals characteristic for percussive sounds.

Get one thing working at a time, using simple, easy to interpret tests.

Test the recording process by calculating an audio frequency (e.g. 1 kHz) sine wave as data, and make sure that is recorded faithfully.

Test the microphone using your PC as an audio sine wave signal generator (lots of free programs available for that) and just LOOK at the raw waveform.

Thanks for the suggestions. Using such a reference is certainly a good idea.
I stumbled over the use of the SPIFFS filesystem for more efficient data handling:
e.g. ThatProject/ESP32_INMP441_RECORDING.ino at master · 0015/ThatProject · GitHub

Do I understand that you want to digitize analog audio and then send the digital results to a PC where it will be converted back to analog and then redigitized to a WAV file?

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