Romain M.
Romain M.

Reputation: 95

Record sound with MAX9814 microphone amplifier and ESP32 on sd card using wav format

For a personal project, I need to record voice sample with a MAX9814 microphone using a esp32. The output pin of the microphone is linked to GPIO35 so I using internal ADC1 channel 7, CS pin of sd card module is wired up with GPIO5.

After reading documentation and Atomic14 explanation, I manage to write this code which therefore uses the I2S module :

#include <SPI.h>
#include <SD.h>
#include <rec-sound.h>
#include <driver/i2s.h>

// Configuration of the SD Card
const int chipSelect = 5;

// I2S Parameters
#define I2S_SAMPLE_RATE 16000
#define I2S_NUM_CHANNELS 1
#define I2S_BITS_PER_SAMPLE 16

#define RECORD_DURATION 3 // Duration in seconds

// Analog Microphone Settings - ADC1_CHANNEL_7 is GPIO35
#define ADC_MIC_CHANNEL ADC1_CHANNEL_7

// Header structure for wav file
struct wav_header {
  char riff[4];
  int32_t flength;
  char wave[4];
  char fmt[4];
  int32_t chunk_size;
  int16_t format_tag;
  int16_t num_chans;
  int32_t sample_rate;
  int32_t bytes_per_second;
  int16_t bytes_per_sample;
  int16_t bits_per_sample;
  char data[4];
  int32_t dlength;
};

const int header_length = sizeof(struct wav_header);

// File on the SD Card
File wavFile;

QueueHandle_t i2s_queue;

void writeWavHeader(File &file_inp){
  struct wav_header wavh;

  strncpy(wavh.riff, "RIFF", 4);
  strncpy(wavh.wave, "WAVE", 4);
  strncpy(wavh.fmt, "fmt ", 4);
  strncpy(wavh.data, "data", 4);

  wavh.chunk_size = 16;
  wavh.format_tag = 1;
  wavh.num_chans = 1;
  wavh.sample_rate = I2S_SAMPLE_RATE;
  wavh.bits_per_sample = I2S_BITS_PER_SAMPLE;
  wavh.bytes_per_second = wavh.sample_rate * wavh.bits_per_sample / 8 * wavh.num_chans;
  wavh.bytes_per_sample = wavh.bits_per_sample / 8 * wavh.num_chans;
  wavh.dlength = 0; // Will be updated later
  wavh.flength = 36 + wavh.dlength; // Will be updated later

  file_inp.write((byte*)&wavh, header_length);
}

void updateWavHeader(File &file) {
  uint32_t fileSize = file.size();
  uint32_t dataSize = fileSize - header_length;

  file.seek(4);
  file.write((byte*)&fileSize, 4); // Update flength

  file.seek(40);
  file.write((byte*)&dataSize, 4); // Update dlength
}

void setupI2S() {
  i2s_config_t i2s_config = {
    .mode = (i2s_mode_t)(I2S_MODE_MASTER | I2S_MODE_RX | I2S_MODE_ADC_BUILT_IN),
    .sample_rate = I2S_SAMPLE_RATE,
    .bits_per_sample = I2S_BITS_PER_SAMPLE_16BIT,
    .channel_format = I2S_CHANNEL_FMT_ONLY_LEFT,
    .communication_format = I2S_COMM_FORMAT_I2S_LSB,
    .intr_alloc_flags = ESP_INTR_FLAG_LEVEL1,
    .dma_buf_count = 4,
    .dma_buf_len = 1024,
    .use_apll = false,
    .tx_desc_auto_clear = false,
    .fixed_mclk = 0};

  //install and start i2s driver
  i2s_driver_install(I2S_NUM_0, &i2s_config, 4, &i2s_queue);

  //init ADC pad
  i2s_set_adc_mode(ADC_UNIT_1, ADC1_CHANNEL_7);

  // enable the ADC
  i2s_adc_enable(I2S_NUM_0);
}

void record_mic() {
  if (!SD.begin(chipSelect)) {
    Serial.println("Erreur d'initialisation de la carte SD!");
    while (1);
  }

  // Créer un nouveau fichier WAV
  wavFile = SD.open("/audio.wav", FILE_WRITE);
  if (!wavFile) {
    Serial.println("Erreur lors de la création du fichier WAV");
    return;
  }

  // Prepare WAV header without data size, which will be updated after saving
  writeWavHeader(wavFile);

  setupI2S();

  Serial.println("Début de l'enregistrement...");
  
  size_t bytes_read;
  int16_t i2s_samples[256]; // Buffer for I2S samples
  unsigned long startMillis = millis();

  while (millis() - startMillis < RECORD_DURATION * 1000) {
    i2s_read(I2S_NUM_0, i2s_samples, sizeof(i2s_samples), &bytes_read, portMAX_DELAY);
    wavFile.write((byte*)i2s_samples, bytes_read);
  }

  // Update the data size in the WAV header
  updateWavHeader(wavFile);

  wavFile.close();

  i2s_driver_uninstall(I2S_NUM_0);

  Serial.println("Enregistrement terminé.");
}

void delete_audio_file() {
  // Initialisation de la carte SD
  if (!SD.begin(chipSelect)) {
    Serial.println("Erreur d'initialisation de la carte SD!");
    while (1);
  }

  Serial.println("Carte SD initialisée.");

  // Supprimer le fichier audio
  if (SD.exists("/audio.wav")) {
    if (SD.remove("/audio.wav")) {
      Serial.println("Fichier audio.wav supprimé.");
    } else {
      Serial.println("Erreur lors de la suppression du fichier audio.wav.");
    }
  } else {
    Serial.println("Fichier audio.wav n'existe pas.");
  }
}

But unfortunately the sound file recorded on the SD card is inaudible, as you can see on Audacity: Capture of audacity

Moreover, it's a bit weird because the duration of the audio is close to 6 seconds while I defined 3 seconds in the code. It's possible that there is an issue in the writing of wav metadata, but I think a bad configuration of I2S is more likely.

Thank you in advance for your suggestions!

Upvotes: 0

Views: 433

Answers (0)

Related Questions