How to record audio and save it to wav file using Electret Mic Amp - MAX9814?

argon
Tags: #<Tag:0x00007fe224484320>

#41

Okay thank you for the info. :grin:


#42

Hi @ScruffR, if i want to change the click button into a tactile switch (pull down resistor), which part of my firmware should i change? Can you briefly explain on how the firmware makes the MODE button becoming the button input?

What I try to do is to add this:

int button = A2;
int buttonstate;

void setup(){
pinMode(button,INPUT);
}

void loop(){
buttonstate = digitalRead(button)
  if(buttonstate = HIGH){
  switch(state) {
	case STATE_WAITING:
		state = STATE_CONNECT;
		break;

	case STATE_RUNNING:
		state = STATE_FINISH;
		break;
  }
}

Something like that. Is it possible? Thank you


#43

BTN is set as pinMode(BTN, INPUT_PULLUP) by the device OS.
If you want another pin you’d need to set pinMode(button, INPUT_PULLDOWN) (unless you have an external pull up)

And you’d have to debounce and slow down your button reading otherwise one press will trigger multiple times.

BTW, you’d need a double equality sign (==) not a single one which would be an assignment.


#46

Thanks for the advice, I did it! I managed to make my tactile switch as the toggle.
However, I noticed that whenever I unplug the argon and plug back it in, i cannot record the audio and gives me this error

0000173223 [app] WARN: opening rec0001.pcm for write failed

However, after i reflash the code, it will be able to record the audio.

This is my new code that I came out with, reference from your code. The hope of this code is that

  1. The audio recording name will be in PCM file and the name will be audio.pcm.
  2. If unplug and plug back again, it will still be able to record the audio again.
  3. There is only 1 data present in the SD card, if i press the record button again when there is audio.pcm in the SD card, the new recording will overwrite the data in the old audio.pcm.

I was able to make 1 file only to the SD card. Then, if I didn’t unplug, i’m able to overwrite the data if i press the tactile switch again. If i unplug, i need to reflash in order for me to record again. Here is the code:

/*
 * Project mic4
 * Description: PCM filed, with single file name
 * Author:
 * Date:
 */

#include <SdFat.h>
#include <ADCDMAGen3_RK.h>
#define SD_CS_PIN SS

SYSTEM_THREAD(ENABLED);

SerialLogHandler logHandler;

const int button = A2;
int buttonState = LOW;
int lastButtonState;
unsigned long lastDebounceTime = 0;
unsigned long debounceDelay = 50;

const  int        SAMPLE_PIN              = A0;
const  size_t     SAMPLE_FREQ             = 16000; // Hz
const  size_t     SAMPLES_IN_BUFFER       = 1024;
const  uint32_t   MAX_RECORDING_LENGTH_MS = 10000; // milliseconds

nrf_saadc_value_t *bufferReady            = 0;
nrf_saadc_value_t buffer0[SAMPLES_IN_BUFFER];
nrf_saadc_value_t buffer1[SAMPLES_IN_BUFFER];

ADCDMAGen3 adc;

void myBufferCallback(nrf_saadc_value_t *buf, size_t size);

SdFat             sd;
File              myFile;

int               fileCount               = 0;
uint32_t          recordingStart;
enum              State { STATE_WAITING, STATE_CONNECT, STATE_RUNNING, STATE_FINISH };
State             state                   = STATE_WAITING;

// setup() runs once, when the device is first turned on.
void setup() {
  Serial.begin(9600);
  pinMode(D7, OUTPUT);
  pinMode(button, INPUT);

    ret_code_t err = adc
	.withSampleFreqHz(SAMPLE_FREQ)
	.withDoubleBuffer(SAMPLES_IN_BUFFER, buffer0, buffer1)
	.withSamplePin(A0)
	.withBufferCallback(myBufferCallback)
	.init();
  Log.info("adc.init %lu", err);

  if (sd.begin(SD_CS_PIN)) 
    Log.info("SD initialised");
  else
    Log.warn("failed to open card");

}

void loop() {
    int reading = digitalRead(button);

  // check to see if you just pressed the button
  // (i.e. the input went from LOW to HIGH), and you've waited long enough
  // since the last press to ignore any noise:

  // If the switch changed, due to noise or pressing:
  if (reading != lastButtonState) {
    // reset the debouncing timer
    lastDebounceTime = millis();
  }

  if ((millis() - lastDebounceTime) > debounceDelay) {
    // whatever the reading is at, it's been there for longer than the debounce
    // delay, so take it as the actual current state:

    // if the button state has changed:
    if (reading != buttonState) {
      buttonState = reading;

      if (buttonState == HIGH) {
        switch(state) 
        {
          case STATE_WAITING:
          state = STATE_CONNECT;
          break;

          case STATE_RUNNING:
          state = STATE_FINISH;
          break;
        }
      }
    }
  }
  // save the reading. Next time through the loop, it'll be the lastButtonState:
  lastButtonState = reading;

  switch(state)
  {
    case STATE_WAITING:
    
    break;


    case STATE_CONNECT:
    {
      myFile = sd.open("audio.pcm", FILE_WRITE); 
      if (myFile) 
      {
        digitalWrite(D7, HIGH);
	      Log.info("Writing to audio.pcm");
		    recordingStart = millis();
        adc.start();
        state = STATE_RUNNING;
      }
      else
      {
        Log.warn("opening audio.wav for write failed");
		    state = STATE_WAITING;
      }
    }
    break;

    case STATE_RUNNING:
    if (bufferReady)
    {
	    int16_t *samples = (int16_t*)bufferReady;
	    bufferReady = 0;
	    for (unsigned int i = 0; i < SAMPLES_IN_BUFFER; i++) 
      {
	      samples[i] -= 2048;  // transpose 0 .. +4095 to -2048 .. +2047 
	      samples[i] <<= 4;    // 12bit -> 16bit
	    }

      int count = myFile.write((uint8_t *)samples, SAMPLES_IN_BUFFER * 2);
      if (count == SAMPLES_IN_BUFFER * 2)
		    Log.info("%d samples written", count/2);
		  else 
      {
  		  Log.warn("error writing %d", count/2);
		    state = STATE_FINISH;
      }
    }

    if (millis() - recordingStart >= MAX_RECORDING_LENGTH_MS) 
    {
		  state = STATE_FINISH;
    }
    break;

    case STATE_FINISH:
		digitalWrite(D7, LOW);
		adc.stop();
		Log.info("stopping");

    myFile.close();
		state = STATE_WAITING;
		break;
  }
}

void myBufferCallback(nrf_saadc_value_t *buf, size_t size) {
  bufferReady = buf;
}

Thank you for your help for the past few days!


#47

My code above does allow for multiple files (per session - restarting at 0001 after a reset) and creates WAV files.

The only issue I couldn’t get to the bottom yet is immediately after you take out the SD and put it back in, the first initialisation of the SD card fails but after a mere reset it works as expected.

If you want to avoid overwriting existing recordings you’d need to first scan what file names are already taken and then use that as starting index for subsequent recordings.


#48

I want to overwrite the data. Meaning i just need 1 audio file. But the thing is after i recorded, i unplugged and plug back in again, when i press the button, it gives me

0000173223 [app] WARN: opening rec0001.pcm for write failed

I tried using your code but your code also does the same thing. After I unplugged the argon from my computer and plug it back in, it will gives me the same error unless if i reflash the whole thing.


#49

I guess that’s due to FILE_WRITE. Hence I’m using O_RDWR | O_CREAT | O_TRUNC instead.


#50

It’s still gives me the same error after I plug the argon out from my computer and plug it back in.


#51

Hi ScruffR, hope you doing well. Thanks for the help for the past days. I found out something. I noticed that if i press reset after i replug the argon it can work! Do you know any codes that can auto reset after the argon is plugged back in?

I tried System.reset() into my void setup, however if my board start blinking white. Tried to search in the particle website, none of the information show me what does blinking white means. I assume it blinks white because it keeps repeating the System.reset(). I thought if i put at void setup it only went inside once.


#52

That’s right - it executes setup() only once per system start :wink:
But when you call System.reset() you do restart the system, so you should only call it conditionally when you detect a problem.


#53

Ahh now its logical. Then is there any way to auto reset the device after i plug the argon back in? I don’t know why pressing the reset button can work but replug the argon won’t work. By right is the same thing right? hahaha


#54

Yes, …

… or another possible condition could be based on the System.resetReason().

That’s what I meant when I previously said

(apparently replugging the entire system suffers the same issue)

But one difference between cold power-up and reset is that the 3.3V rail - which supplies the SD card - stays powered across a reset but does (obviously) not so when cold-booted or un-/replugging the SD.


#55

Thank you very much, finally I can record my mic without problem!