atomic14 / esp32_sdcard_audio

A simple example that shows how to record a WAV file to an SD Card on the ESP32
MIT License
115 stars 39 forks source link

Issue recording with Analog microphone #17

Open tuneado opened 1 year ago

tuneado commented 1 year ago

Hey there Thanks for this project its been very helpful and insightful so far.

I managed to adapt the project to the Arduino's SD library and got the recording workig with the MEM's microphone.. but when i hook up a MAX9814 analog mic my recording gets super slow(aprox 4x longer) i think this has to do with the bit resolution of the recording or something but im fairly 'newbie' to programing. Thats why im asking you for help

The two recordings top - analog mic (4x the size of the bottom one) bottom - mems microphone

Screenshot (15)

Gaai commented 1 year ago

Could you post all the changes you made? The code would give more insight in what could be happening than a picture of audacity waveforms. That's the result not the cause.

tuneado commented 1 year ago

Could you post all the changes you made? The code would give more insight in what could be happening than a picture of audacity waveforms. That's the result not the cause.

Hey there Gaai thanks for the reply.

Apart from changing some fo the pins (with no issues on that) and transitioning to the sd library using the #9 theres not much ive changed but here is the code for: WAVFileWritter.cpp

#include "WAVFileWriter.h"

static const char *TAG = "WAV";

WAVFileWriter::WAVFileWriter(File fp, int sample_rate)
{
  m_fp = fp;
  m_header.sample_rate = sample_rate;
  // write out the header - we'll fill in some of the blanks later
  m_fp.write((uint8_t *) &m_header, sizeof(m_header));
  m_file_size = sizeof(wav_header_t);
}

void WAVFileWriter::write(int16_t *samples, int count)
{
  // write the samples and keep track of the file size so far
  uint8_t* sampleBytes = (uint8_t*)samples;
  m_fp.write(sampleBytes, sizeof(int16_t) * count);
  m_file_size += sizeof(int16_t) * count;
}

void WAVFileWriter::finish()
{
  // now fill in the header with the correct information and write it again
  m_header.data_bytes = m_file_size - sizeof(wav_header_t);
  m_header.wav_size = m_file_size - 8;
  m_fp.seek(0);
  m_fp.write((uint8_t *) &m_header, sizeof(m_header));
}

WAVFileWritter.h

#pragma once

#include "FS.h"
#include "WAVFile.h"

class WAVFileWriter
{
private:
  int m_file_size;

  File m_fp;
  wav_header_t m_header;

public:
  WAVFileWriter(File fp, int sample_rate);
  void start();
  void write(int16_t *samples, int count);
  void finish();
};

ADCSAMPLER.cpp

#include "ADCSampler.h"

ADCSampler::ADCSampler(adc_unit_t adcUnit, adc1_channel_t adcChannel, const i2s_config_t &i2s_config) : I2SSampler(I2S_NUM_0, i2s_config)
{
    m_adcUnit = adcUnit;
    m_adcChannel = adcChannel;
}

void ADCSampler::configureI2S()
{
    //init ADC pad
    i2s_set_adc_mode(m_adcUnit, m_adcChannel);
    // enable the adc
    i2s_adc_enable(m_i2sPort);
}

void ADCSampler::unConfigureI2S()
{
    // make sure ot do this or the ADC is locked
    i2s_adc_disable(m_i2sPort);
}

int ADCSampler::read(int16_t *samples, int count)
{
    // read from i2s
    size_t bytes_read = 0;
    i2s_read(m_i2sPort, samples, sizeof(int16_t) * count, &bytes_read, portMAX_DELAY);
    int samples_read = bytes_read / sizeof(int16_t);
    for (int i = 0; i < samples_read; i++)
    {
        //samples[i] = (2048 - (uint16_t(samples[i]) & 0xfff)) * 15;
        samples[i] = (2048 - (uint16_t(samples[i]) & 0xfff)) * 15;
    }
    return samples_read;
}

ADCSampler.h

#pragma once

#include "I2SSampler.h"

class ADCSampler : public I2SSampler
{
private:
    adc_unit_t m_adcUnit;
    adc1_channel_t m_adcChannel;

protected:
    void configureI2S();
    void unConfigureI2S();

public:
    ADCSampler(adc_unit_t adc_unit, adc1_channel_t adc_channel, const i2s_config_t &i2s_config);
    virtual int read(int16_t *samples, int count);
};
Gaai commented 1 year ago

There 's a few things that don't add up to me. uint8_t* sampleBytes = (uint8_t*)samples; m_fp.write((uint8_t *) &m_header, sizeof(m_header));

While samples is uint16_t.

Original WAVFileWriter: void WAVFileWriter::write(int16_t *samples, int count) { // write the samples and keep track of the file size so far fwrite(samples, sizeof(int16_t), count, m_fp); m_file_size += sizeof(int16_t) * count; }

I2SMEMS (config.h: 32bit): i2s_read(m_i2sPort, raw_samples, sizeof(int32_t) * count, &bytes_read, portMAX_DELAY); int samples_read = bytes_read / sizeof(int32_t); for (int i = 0; i < samples_read; i++) { samples[i] = (raw_samples[i] & 0xFFFFFFF0) >> 11; }

ADC (config.h 16bit): i2s_read(m_i2sPort, samples, sizeof(int16_t) * count, &bytes_read, portMAX_DELAY); int samples_read = bytes_read / sizeof(int16_t); for (int i = 0; i < samples_read; i++) { samples[i] = (2048 - (uint16_t(samples[i]) & 0xfff)) * 15; }

Also how did you bias your input? 
tuneado commented 1 year ago

There 's a few things that don't add up to me. uint8_t* sampleBytes = (uint8_t*)samples; m_fp.write((uint8_t *) &m_header, sizeof(m_header));

While samples is uint16_t.

Also how did you bias your input? 

yeah i think everything is ok with my input. i really think the issue relies on the sample units like you said. im gonna review it and ill give you an update

tuneado commented 1 year ago

There 's a few things that don't add up to me. uint8_t* sampleBytes = (uint8_t*)samples; m_fp.write((uint8_t *) &m_header, sizeof(m_header));

While samples is uint16_t.

Original WAVFileWriter: void WAVFileWriter::write(int16_t *samples, int count) { // write the samples and keep track of the file size so far fwrite(samples, sizeof(int16_t), count, m_fp); m_file_size += sizeof(int16_t) * count; }

i got this part of the code from a reply to issue #9 @

valentasn commented 1 year ago

@tuneado I had a completely different one. Recorded voice was super fast x2 or x3 times faster than normal. I'm using MEMS microphone INMP441 module.

image

Spend some time to figure this out, and fixed function now looks like this:

int I2SMEMSSampler::read(int16_t samples, int count) { // read from i2s int16_t raw_samples = (int16_t ) malloc(sizeof(int16_t) count); size_t bytes_read = 0; i2s_read(m_i2sPort, raw_samples, sizeof(int16_t) count, &bytes_read, portMAX_DELAY); int samples_read = bytes_read / sizeof(int16_t); for (int i = 0; i < samples_read; i++) { samples[i] = (1024 - (uint16_t(raw_samples[i]) & 0xFFFFFFF0)) 15; } free(raw_samples); return samples_read; }

Apparently value "15" is a gain of sound amplification. 1024 - dma_buf_len.

Adding my i2s config:

// i2s config for reading from I2S i2s_config_t i2s_mic_Config = { .mode = (i2s_mode_t)(I2S_MODE_MASTER | I2S_MODE_RX), .sample_rate = (uint32_t) SAMPLE_RATE, // 40000 .bits_per_sample = I2S_BITS_PER_SAMPLE_16BIT, .channel_format = I2S_CHANNEL_FMT_ONLY_LEFT, .communication_format = (i2s_comm_format_t) I2S_COMM_FORMAT_STAND_I2S, .intr_alloc_flags = 0, .dma_buf_count = 4, .dma_buf_len = 1024, .use_apll = 0, .tx_desc_auto_clear = true, .fixed_mclk = 0 };

You are right to point out that issue relies on the sample units. Thank you!

DJprasenjit commented 3 months ago

Hey there Thanks for this project its been very helpful and insightful so far.

I managed to adapt the project to the Arduino's SD library and got the recording workig with the MEM's microphone.. but when i hook up a MAX9814 analog mic my recording gets super slow(aprox 4x longer) i think this has to do with the bit resolution of the recording or something but im fairly 'newbie' to programing. Thats why im asking you for help

The two recordings top - analog mic (4x the size of the bottom one) bottom - mems microphone

Screenshot (15)

hello. I wanted to use PDM microphone. Please tell me how to do