# How to refer to the built in microphone?

**URL:** <https://forum.arduino.cc/t/how-to-refer-to-the-built-in-microphone/1277606>\
**Category:** Audio\
**Created:** [July 2, 2024, 2:08pm UTC](https://forum.arduino.cc/t/how-to-refer-to-the-built-in-microphone/1277606 "2024-07-02T14:08:04Z")\
**Posts on this page:** 20\
**Page:** 1

<div class="post-metadata">

**Author:** ![murosic](https://avatars.discourse-cdn.com/v4/letter/m/848f3c/32.png) [@murosic](https://forum.arduino.cc/u/murosic)\
**Post date:** [July 2, 2024, 2:08pm UTC](https://forum.arduino.cc/t/how-to-refer-to-the-built-in-microphone/1277606/1 "2024-07-02T14:08:04Z")

</div>

I am pretty new to Arduino and have this question:

I try to make an audio recorder with this library on an Arduino Nano 33 BLE Sense: [https://github.com/TMRh20/AutoAnalogAudio](https://github.com/TMRh20/AutoAnalogAudio)

Based on the example sketch called "SdAudioRecording", how can I make this work to use the built in microphone instead of expecting an external microphone on pin A0?

Current serial monitor output:  
After starting a recording:

```arduino
Start Recording: /test.wav

```

After stopping a recording:

```arduino
File contains no data, exiting
Recording Stopped

```

---

<div class="post-metadata">

**Author:** ![anon94801460](https://avatars.discourse-cdn.com/v4/letter/a/278dde/32.png) [@anon94801460](https://forum.arduino.cc/u/anon94801460)\
**Post date:** [July 2, 2024, 2:17pm UTC](https://forum.arduino.cc/t/how-to-refer-to-the-built-in-microphone/1277606/2 "2024-07-02T14:17:13Z")

</div>

I suggest to check whether Arduino LLC has provided example code and a library to access the built-in microphone on the Nano 33 BLE Sense, and start from there.

---

<div class="post-metadata">

**Author:** ![murosic](https://avatars.discourse-cdn.com/v4/letter/m/848f3c/32.png) [@murosic](https://forum.arduino.cc/u/murosic)\
**Post date:** [July 2, 2024, 2:27pm UTC](https://forum.arduino.cc/t/how-to-refer-to-the-built-in-microphone/1277606/3 "2024-07-02T14:27:29Z")

</div>

Thanks for your reply!  
I think that is this library: [https://docs.arduino.cc/learn/built-in-libraries/pdm/](https://docs.arduino.cc/learn/built-in-libraries/pdm/)

This library looks very spartan without the possibility to save audio on SD. That's why I looked for other libraries...

---

<div class="post-metadata">

**Author:** ![anon94801460](https://avatars.discourse-cdn.com/v4/letter/a/278dde/32.png) [@anon94801460](https://forum.arduino.cc/u/anon94801460)\
**Post date:** [July 2, 2024, 2:29pm UTC](https://forum.arduino.cc/t/how-to-refer-to-the-built-in-microphone/1277606/4 "2024-07-02T14:29:58Z")

</div>

The library shows you how to access the microphone.

You will have to add the code to write to SD.

---

<div class="post-metadata">

**Author:** ![murosic](https://avatars.discourse-cdn.com/v4/letter/m/848f3c/32.png) [@murosic](https://forum.arduino.cc/u/murosic)\
**Post date:** [July 2, 2024, 2:40pm UTC](https://forum.arduino.cc/t/how-to-refer-to-the-built-in-microphone/1277606/5 "2024-07-02T14:40:27Z")

</div>

Ok I am going to try that path, thanks again.

---

<div class="post-metadata">

**Author:** ![anon94801460](https://avatars.discourse-cdn.com/v4/letter/a/278dde/32.png) [@anon94801460](https://forum.arduino.cc/u/anon94801460)\
**Post date:** [July 2, 2024, 2:53pm UTC](https://forum.arduino.cc/t/how-to-refer-to-the-built-in-microphone/1277606/6 "2024-07-02T14:53:23Z")

</div>

Keep in mind that writing to SD is slow, and may not be able to keep up with the microphone.

It is very difficult to optimize code to achieve continuous, gap free recording of audio signals at a high rate. Double buffering is required and the microphone buffer size must be exact multiples of the SD block size (usually 512 bytes).

---

<div class="post-metadata">

**Author:** ![murosic](https://avatars.discourse-cdn.com/v4/letter/m/848f3c/32.png) [@murosic](https://forum.arduino.cc/u/murosic)\
**Post date:** [July 3, 2024, 8:43am UTC](https://forum.arduino.cc/t/how-to-refer-to-the-built-in-microphone/1277606/7 "2024-07-03T08:43:56Z")

</div>

In my case, I only want to take samples from max a few seconds so that could maybe help.

My thinking:

1. Create array with samples during recording
2. Convert to wav. eg: [c++ - WAV file from captured PCM sample data - Stack Overflow](https://stackoverflow.com/questions/1460007/wav-file-from-captured-pcm-sample-data)
3. Write wav to SD. Will try to use some of this code: [Simple Arduino Voice Recorder for Spy Bug Voice Recording](https://circuitdigest.com/microcontroller-projects/simple-arduino-voice-recorder-for-spy-bug-voice-recording)

---

<div class="post-metadata">

**Author:** ![murosic](https://avatars.discourse-cdn.com/v4/letter/m/848f3c/32.png) [@murosic](https://forum.arduino.cc/u/murosic)\
**Post date:** [July 10, 2024, 8:30am UTC](https://forum.arduino.cc/t/how-to-refer-to-the-built-in-microphone/1277606/8 "2024-07-10T08:30:17Z")

</div>

Hmm, I am struggling with how to get an array with recorded audio. The [PDM documentation](https://docs-content.arduino.cc/learn/built-in-libraries/pdm/) is very briefly, but apparently `PDM.read()` dumps recorded data in a buffer array. By testing I find that it doesn't add it to the buffer, but dumps it every time to the start of the array.

I am trying to get an array `audioSample[160000]`, that contains 10 seconds of audio. (the board has 256k RAM so I hope this is possible). At the moment I am first testing the principle with a smaller array.

This is the relevant piece of code:

```arduino
void recordAudio(){
  Serial.println("try to record audio");

  // configure the data receive callback
  PDM.onReceive(onPDMdata);

  // initialize PDM
  if (!PDM.begin(1, sampleRate)) {
    Serial.println("Failed to start PDM!");
    while (1);
  }
  delay(1000);
  PDM.end();
  processAudio();
  audioSamplesRead = 0;
}

void onPDMdata() {
  // query the number of bytes available
  int bytesAvailable = PDM.available();
  
  // read into the sample buffer
  PDM.read(audioSample, bytesAvailable);

  // 16-bit, 2 bytes per sample
  audioSamplesRead = bytesAvailable / 2;
}

```

Due to the linear process in C++ It looks like when the audio recording function is running, I can't run another function to collect the audio buffer to the audio sample if needed. In the above code I removed the buffer step, ultimately PDM.read should write to a buffer.

Any ideas how to approach this? While the project evolved, I now prefer not to use an SD-card but process the audio directly and remove it.

---

<div class="post-metadata">

**Author:** ![rsmls](https://avatars.discourse-cdn.com/v4/letter/r/5daacb/32.png) [@rsmls](https://forum.arduino.cc/u/rsmls)\
**Post date:** [July 10, 2024, 8:50am UTC](https://forum.arduino.cc/t/how-to-refer-to-the-built-in-microphone/1277606/9 "2024-07-10T08:50:22Z")

</div>

> [@murosic](#):
>
> This is the relevant piece of code:

Please post an entire sketch that demonstrates what you're doing. Too much context is missing from the snippet you posted to make sense of it.

> [@murosic](#):
>
> Due to the linear process in C++ It looks like when the audio recording function is running, I can't run another function to collect the audio buffer to the audio sample if needed.

What does this mean, exactly?

> [@murosic](#):
>
> process the audio directly

What kind of processing needs to take place? And what does 'directly' mean - after collecting, say, 10 seconds of audio, or in real time?

---

<div class="post-metadata">

**Author:** ![murosic](https://avatars.discourse-cdn.com/v4/letter/m/848f3c/32.png) [@murosic](https://forum.arduino.cc/u/murosic)\
**Post date:** [July 10, 2024, 9:21am UTC](https://forum.arduino.cc/t/how-to-refer-to-the-built-in-microphone/1277606/10 "2024-07-10T09:21:54Z")

</div>

Thanks @rsmls

This is the entire sketch until now:

```arduino
#include <PDM.h>
#include <Arduino_HS300x.h>

int sampleRate = 16000;

volatile int audioSamplesRead;
int audioSample[32000];

float temperature;
float humidity;

void setup() {
  Serial.begin(9600);
  while (!Serial);
  PDM.setBufferSize(1024);

  while (!Serial);

  if (!HS300x.begin()) {
    Serial.println("Failed to initialize humidity temperature sensor!");
    while (1);
  }
}

void loop() {
  Serial.println("run loop");
  temperature = HS300x.readTemperature();
  humidity = HS300x.readHumidity();
  recordAudio();
  delay(99999999);
}

void recordAudio(){
  Serial.println("try to record audio");

  // configure the data receive callback
  PDM.onReceive(onPDMdata);

  // initialize PDM
  if (!PDM.begin(1, sampleRate)) {
    Serial.println("Failed to start PDM!");
    while (1);
  }
  delay(1000);
  PDM.end();
  processAudio();
  audioSamplesRead = 0;
}

void onPDMdata() {
  // query the number of bytes available
  int bytesAvailable = PDM.available();
  
  // read into the sample buffer
  PDM.read(audioSample, bytesAvailable);

  // 16-bit, 2 bytes per sample
  audioSamplesRead = bytesAvailable / 2;
}

void processAudio(){
  sendValues();
}

void sendValues(){
  Serial.print("Temperature: ");
  Serial.println(temperature);
  Serial.print("Humidity: ");
  Serial.println(humidity);
  Serial.println("Audio: ");
  for (int i = 0; i < audioSamplesRead;i++){
    Serial.print("Iteration ");
    Serial.print(i);
    Serial.print(": ");
    Serial.println(audioSample[i]);
  }
  Serial.println();
}

```

About the lineair process: when you run this program, you will only see "Loop One" in the Serial Monitor.

```arduino
loopOne();
loopTwo();

int loopOne(){
  Serial.println("Loop One");
  loopOne();
}

int loopTwo(){
  Serial.println("Loop Two");
  loopTwo();
}

```

The audio processes that will take place is extracting the features to make a compact summary of the audio to send it. This can take place after the recording is finished.

---

<div class="post-metadata">

**Author:** ![murosic](https://avatars.discourse-cdn.com/v4/letter/m/848f3c/32.png) [@murosic](https://forum.arduino.cc/u/murosic)\
**Post date:** [July 10, 2024, 9:32am UTC](https://forum.arduino.cc/t/how-to-refer-to-the-built-in-microphone/1277606/11 "2024-07-10T09:32:00Z")

</div>

Oh I see that I made a mistake in sendValues().

This code does already more:

```arduino
void sendValues(){
  Serial.print("Temperature: ");
  Serial.println(temperature);
  Serial.print("Humidity: ");
  Serial.println(humidity);
  Serial.println("Audio: ");
  for (int i = 0; i < sizeof(audioSample);i++){
    Serial.print("Iteration ");
    Serial.print(i);
    Serial.print(": ");
    Serial.println(audioSample[i]);
  }
  Serial.println();
}

```

I will get back, one moment.

---

<div class="post-metadata">

**Author:** ![Grumpy\_Mike](https://dub1.discourse-cdn.com/arduino/user_avatar/forum.arduino.cc/grumpy_mike/32/213521_2.png) [@Grumpy\_Mike](https://forum.arduino.cc/u/Grumpy_Mike)\
**Post date:** [July 10, 2024, 9:50am UTC](https://forum.arduino.cc/t/how-to-refer-to-the-built-in-microphone/1277606/12 "2024-07-10T09:50:15Z")

</div>

The problem is that PDM stands for Pulse Density Modulation, it is nothing like a normal audio sample, which is why your code is failing.

Here is an example of how to visualise the signal on the serial monitor. Please use Arduino OS 1.8.19 as the OS 2.x has a rubbishly small size display on the serial plotter.

```arduino
/*
  This example reads audio data from the on-board PDM microphones, and prints
  out the samples to the Serial console. The Serial Plotter built into the
  Arduino IDE can be used to plot the audio data (Tools -> Serial Plotter)

  Circuit:
  - Arduino Nano 33 BLE board, or
  - Arduino Nano RP2040 Connect, or
  - Arduino Portenta H7 board plus Portenta Vision Shield

  This example code is in the public domain.
  hacked by Mike Cook to show blank when input is below 300
*/

#include <PDM.h>

// default number of output channels
static const char channels = 1;

// default PCM output frequency
static const int frequency = 16000;

// Buffer to read samples into, each sample is 16-bits
short sampleBuffer[512];

// Number of audio samples read
volatile int samplesRead;

void setup() {
  Serial.begin(9600);
  while (!Serial);

  // Configure the data receive callback
  PDM.onReceive(onPDMdata);

  // Optionally set the gain
  // Defaults to 20 on the BLE Sense and 24 on the Portenta Vision Shield
  // PDM.setGain(30);

  // Initialize PDM with:
  // - one channel (mono mode)
  // - a 16 kHz sample rate for the Arduino Nano 33 BLE Sense
  // - a 32 kHz or 64 kHz sample rate for the Arduino Portenta Vision Shield
  if (!PDM.begin(channels, frequency)) {
    Serial.println("Failed to start PDM!");
    while (1);
  }
}

void loop() {
  // Wait for samples to be read
  if (samplesRead) {

    // Print samples to the serial monitor or plotter
    if(sampleBuffer[0] > 300) {
    for (int i = 0; i < samplesRead; i++) {
      if(channels == 2) {
        Serial.print("L:");
        Serial.print(sampleBuffer[i]);
        Serial.print(" R:");
        i++;
      }
      Serial.println(sampleBuffer[i]);
     }
    }
    // Clear the read count
    samplesRead = 0;
  }
}

/**
 * Callback function to process the data from the PDM microphone.
 * NOTE: This callback is executed as part of an ISR.
 * Therefore using `Serial` to print messages inside this function isn't supported.
 * */
void onPDMdata() {
  // Query the number of available bytes
  int bytesAvailable = PDM.available();

  // Read into the sample buffer
  PDM.read(sampleBuffer, bytesAvailable);

  // 16-bit, 2 bytes per sample
  samplesRead = bytesAvailable / 2;
}
```

---

<div class="post-metadata">

**Author:** ![murosic](https://avatars.discourse-cdn.com/v4/letter/m/848f3c/32.png) [@murosic](https://forum.arduino.cc/u/murosic)\
**Post date:** [July 10, 2024, 10:01am UTC](https://forum.arduino.cc/t/how-to-refer-to-the-built-in-microphone/1277606/13 "2024-07-10T10:01:49Z")

</div>

@Grumpy_Mike I saw that example indeed, thanks. But what if I want to save the data in an array?  
interesting comment about it being PDM. So that sounds like a hassle to convert that to wav data? Sounds like I am not on the right track with this PDM module..

---

<div class="post-metadata">

**Author:** ![murosic](https://avatars.discourse-cdn.com/v4/letter/m/848f3c/32.png) [@murosic](https://forum.arduino.cc/u/murosic)\
**Post date:** [July 10, 2024, 10:16am UTC](https://forum.arduino.cc/t/how-to-refer-to-the-built-in-microphone/1277606/15 "2024-07-10T10:16:39Z")

</div>

Here is an example of the output, don't know yet wat to do with that 🤔

```arduino
Iteration 12081: 0
Iteration 12082: 0
Iteration 12083: 0
Iteration 12084: 0
Iteration 12085: 7624
Iteration 12086: 0
Iteration 12087: 0
Iteration 12088: 0
Iteration 12089: 0
Iteration 12090: 0
Iteration 12091: 0
Iteration 12092: 0
Iteration 12093: 0
Iteration 12094: 0
Iteration 12095: 7624
Iteration 12096: 7624
Iteration 12097: 0
Iteration 12098: 0
Iteration 12099: 536956244
Iteration 12100: 0
Iteration 12101: -497406299
Iteration 12102: -858993460
Iteration 12103: -858993460
Iteration 12104: -858993460
Iteration 12105: -858993460

```

---

<div class="post-metadata">

**Author:** ![rsmls](https://avatars.discourse-cdn.com/v4/letter/r/5daacb/32.png) [@rsmls](https://forum.arduino.cc/u/rsmls)\
**Post date:** [July 10, 2024, 12:24pm UTC](https://forum.arduino.cc/t/how-to-refer-to-the-built-in-microphone/1277606/16 "2024-07-10T12:24:42Z")

</div>

> [@murosic](#):
>
> About the lineair process: when you run this program, you will only see "Loop One" in the Serial Monitor

Unsurprisingly:

> [@murosic](#):
>
> `delay(99999999);`

---

<div class="post-metadata">

**Author:** ![anon94801460](https://avatars.discourse-cdn.com/v4/letter/a/278dde/32.png) [@anon94801460](https://forum.arduino.cc/u/anon94801460)\
**Post date:** [July 10, 2024, 2:03pm UTC](https://forum.arduino.cc/t/how-to-refer-to-the-built-in-microphone/1277606/17 "2024-07-10T14:03:51Z")

</div>

> [@murosic](#):
>
> But what if I want to save the data in an array?

The data already **are** in an array, internal to the PDM microphone library. You just need to copy them elsewhere.

Here is test code I wrote for the Adafruit Clue, which saves a short audio recording in SPI flash memory (acting like an SD card).

```arduino
//working 4/6/2024
// upped gain to 42 (default was 20, too quiet)
/*
  This example reads audio data from the on-board PDM microphone
  and saves to a QSPI flash file audio.dat
  // 2Mb flash = 2097152 bytes, 4096 512 byte blocks
*/

#include <Adafruit_Arcada.h>

Adafruit_Arcada arcada;
#include <PDM.h>
#define SAMPLES 1024

// buffer for audio samples, each sample is 16-bits
// setting a larger buffer avoids dropping audio samples
// writes to flash are slow!

int16_t sampleBuffer[SAMPLES];

// number of samples read
volatile int samplesRead;

File file;

void setup() {
  Serial.begin(115200);
  while (!Serial) yield();

  // configure the data receive callback
  PDM.onReceive(onPDMdata);

  if (!arcada.arcadaBegin()) {
    while (1);
  }
  //Arcada_FilesystemType
  arcada.filesysBegin(ARCADA_FILESYS_QSPI);

  file = arcada.open("/audio.dat", O_CREAT | O_WRITE);
  if (!file) {
    Serial.println("\r output file open failure");
    while (1) yield();
  }
  PDM.setBufferSize(2048); //bytes!
  // initialize PDM with:
  // - one channel (mono mode)
  // - a 16 kHz sample rate
  if (!PDM.begin(1, 16000)) {
    Serial.println("Failed to start PDM!");
    while (1) yield();
  }
  // optionally set the gain, defaults to 20
  PDM.setGain(42);
  Serial.println("recording");
}
int nframes = 250;

void loop() {
  // wait for samples to be read
  if (samplesRead) {
    int bytes_written = file.write((char *)sampleBuffer, 2*SAMPLES);
    // Serial.println(nframes);
    nframes--;
    if (nframes == 0 || bytes_written < 2*SAMPLES) { //done, or out of space on filesys
      file.close();
      Serial.println("stopped");
      arcada.filesysListFiles();
      Serial.flush();
      while (1) yield();
    }
    samplesRead = 0;
  }
}

void onPDMdata() { //callback
  // query the number of bytes available
  int bytesAvailable = PDM.available();
   // read into the sample buffer
  PDM.read(sampleBuffer, bytesAvailable);

  // 16-bit, 2 bytes per sample
  samplesRead = bytesAvailable / 2;
}

```

---

<div class="post-metadata">

**Author:** ![murosic](https://avatars.discourse-cdn.com/v4/letter/m/848f3c/32.png) [@murosic](https://forum.arduino.cc/u/murosic)\
**Post date:** [July 11, 2024, 12:22pm UTC](https://forum.arduino.cc/t/how-to-refer-to-the-built-in-microphone/1277606/18 "2024-07-11T12:22:30Z")

</div>

> [@anon94801460](#):
>
> Here is test code I wrote for the Adafruit Clue, which saves a short audio recording in SPI flash memory (acting like an SD card).

Thanks for sharing, I am working on it now with this as a start, and will post any outcome.

---

<div class="post-metadata">

**Author:** ![murosic](https://avatars.discourse-cdn.com/v4/letter/m/848f3c/32.png) [@murosic](https://forum.arduino.cc/u/murosic)\
**Post date:** [July 11, 2024, 12:26pm UTC](https://forum.arduino.cc/t/how-to-refer-to-the-built-in-microphone/1277606/19 "2024-07-11T12:26:22Z")

</div>

> [@rsmls](#):
>
> > [@murosic](#):
> >
> > About the lineair process: when you run this program, you will only see "Loop One" in the Serial Monitor
> 
> Unsurprisingly:
> 
> > [@murosic](#):
> >
> > `delay(99999999);`

That is another Sketch, I meant the fact that you can't run two looping functions the same time. I think that is solved by checking the recorded time in a while loop, something like this:

```arduino
void recordAudio(){

  // initialize PDM
  if (!PDM.begin(1, sampleRate)) {
    Serial.println("Failed to start PDM!");
    while (1);
  }
  delay(50); // To make shure the buffer is filled when the while loop starts

  while(audioSampleRead < 16000){
    if (samplesRead) {
      // Do stuff
    }
  }
  PDM.end();
  audioSamplesRead = 0;
  processAudio();
}

```

---

<div class="post-metadata">

**Author:** ![noweare](https://dub1.discourse-cdn.com/arduino/user_avatar/forum.arduino.cc/noweare/32/987856_2.png) [@noweare](https://forum.arduino.cc/u/noweare)\
**Post date:** [July 11, 2024, 12:33pm UTC](https://forum.arduino.cc/t/how-to-refer-to-the-built-in-microphone/1277606/20 "2024-07-11T12:33:42Z")

</div>

Check out Atomic14 video on youtube. He has code for the project on github. He uses an esp32 though. [Record and Playback Audio](https://www.youtube.com/watch?v=bVru6M862HY&t=2s&ab_channel=atomic14)

---

<div class="post-metadata">

**Author:** ![rsmls](https://avatars.discourse-cdn.com/v4/letter/r/5daacb/32.png) [@rsmls](https://forum.arduino.cc/u/rsmls)\
**Post date:** [July 11, 2024, 12:42pm UTC](https://forum.arduino.cc/t/how-to-refer-to-the-built-in-microphone/1277606/21 "2024-07-11T12:42:31Z")

</div>

> [@murosic](#):
>
> fact that you can't run two looping functions the same time. I think that is solved by checking the recorded time in a while loop, something like this:

Yeah, something like that. Not sure if that particular approach you posted is such a great idea, but it might work. In general terms, you might look into the concept of a 'state machine'. There's a particularly useful (IMO) example here: [State Machines and Arduino Implementation – Norwegian Creations](https://www.norwegiancreations.com/2017/03/state-machines-and-arduino-implementation/)

[Next page](https://forum.arduino.cc/t/how-to-refer-to-the-built-in-microphone/1277606.md?page=2)
