Xiao MG24 Mic library - no samples captured at all

Hellp, I’m trying to run in Arduino Studio the Seed Arduino mic→ mic serial recording example, with minor modifications, together with the supplied python script, to try to capture 3 seconds of audio at 8kHz. The sketch runs, the python script captures the output, but the issue is, the script seemingly does not respect the timing specified in the mic_config_t mic_config struct.

As it is, my main buffer is 24000 bytes long:

#define SAMPLES 8000*3
int16_t recording_buf[SAMPLES];

and the mic_config_t struct is like that:

mic_config_t mic_config{
  .channel_cnt = 1,
  .sampling_rate = 8000,
  .buf_size = 1600,
  .debug_pin = LED_BUILTIN                
};

As far I understand, with these settings the ISR routine that transfer the captured samples from the internal buffer to my main buffer (which I will output to serial after capturing all samples) should take ~3 seconds to capture everything: for 8kHz, the ISR should be called 15 times: ((24000/8000) 1600), and each call should happen every 200ms ((1 sec / 8kHz) * 1600).

But it just finishes very quickly, in less than a second, and doesn’t capture all samples. It’s like its not respecting the interval to call the ISR (200ms between calls), filling the buffer almost instantly with noise.

Can someone please help to check the code (which is mainly Seeed’s code anyway), or have any experience with the <mic.h> library to see if there’s anything missing in the setup?

Thank you very much,

Luis.

Arduino sketch and python code supplied below.

Arduino:

#include <mic.h>
// Settings
#define DEBUG 1                 // Enable pin pulse during ISR  
#define SAMPLES 8000*3          // 3 seconds of audio @ 8kHz

// Define the DC Offset based on the ADC range (0 to 4000)
#define DC_OFFSET 1900

mic_config_t mic_config{
  .channel_cnt = 1,
  .sampling_rate = 8000,
  .buf_size = 1600,
  .debug_pin = LED_BUILTIN                
};

MG24_ADC_Class Mic(&mic_config);

int16_t recording_buf[SAMPLES];
volatile static bool record_ready = false;
volatile static bool recording    = false;
volatile static uint32_t idx = 0;
volatile static uint32_t vezes = 0;

volatile static unsigned long initialTime = 0;
volatile static unsigned long finalTime;

void setup() {
  Serial.begin(115200);
  while (!Serial) {delay(10);}

  Mic.set_callback(audio_rec_callback);

  if (!Mic.begin()) {
    Serial.println("init_fail");
    while (1);
  }
  Serial.println("init_ok");
}

void loop() { 
  // Wait for "init" command
  while(Serial.readString() != "init\n") {
  }
  Serial.println("init_ok");  


  // Wait for "rec" command
  while(Serial.readString() != "rec\n") {
  }

  idx = 0;             // Reset index
  recording = true;    // Start the recording process
  vezes = 0;

  // Wait for the callback to finish filling the buffer
  while(!record_ready) {
  }

  //Serial.print("Passed through record_ready=true "); Serial.print(vezes);       Serial.print(" times in ");
  //Serial.print(finalTime - initialTime); Serial.println(" ms.");

  // Data transfer section
  if (record_ready) {
    Serial.println("rec_ok");
    for (int i = 0; i < SAMPLES; i++) {
      Serial.println(recording_buf[i]);
    }
  Serial.println("fi");
  record_ready = false; 
  }
}

static void audio_rec_callback(uint16_t *buf, uint32_t buf_len) {
  if (recording) {
    vezes++;
    if (initialTime == 0) { initialTime=millis(); }
    for (uint32_t i = 0; i < buf_len; i++) {     
      recording_buf[idx] = (int16_t)((buf[i] - DC_OFFSET) * 16);
      idx++;
      if (idx >= SAMPLES) { 
        finalTime = millis();
        initialTime = 0;
        idx = 0; 
        record_ready = true;
        recording = false;
        break;
      } 
    }
  }
}

Python code:

import os, sys
import serial
import wave, struct
import logging
import argparse

logging.basicConfig(level=logging.INFO)

commands = [b"“, b"rec_ok”, b"init_ok", b"fi"]

sampleRate = 8000 # hertz
duration = 3 # seconds

def write_wav_data(raw_sound, filename):
logging.debug(raw_sound)

obj = wave.open(filename, 'w')
obj.setnchannels(1) # mono
obj.setsampwidth(2)
obj.setframerate(sampleRate)

for value in raw_sound:
    data = struct.pack('<h', value)
    obj.writeframesraw(data)
obj.close()

def main(args):
i = 1
ser = serial.Serial(args.port, args.baud_rate, timeout=1)
logging.info(‘Awaiting response from device’)

while True:
    ser.write(b"init\n")
    recv = ser.readline().rstrip()
    print(recv)
    if recv == b'init_ok':
        logging.info('Device init successful')            
        break
    if recv == b'init_fail':
        logging.error('Device init failed')
        sys.exit(0)

while True: 
    try:
        logging.info('READY') 

        input("Press Enter to continue...")
        ser.write(b"rec\n")
        logging.info('RECORDING')  
        recv = ""
        raw_sound = []
        while True:
            recv = ser.readline().rstrip()
            if recv == b"rec_ok":
                logging.info('RECORDING FINISHED') 
            if recv == b"fi":
                logging.info('TRANSFER FINISHED')
                break 
            if not recv in commands:
                raw_sound.append(int(recv))
                #print(int(recv))
            #logging.debug(recv)

        filename = args.filename + str(i) + ".wav"
        write_wav_data(raw_sound, filename)
        i += 1

    except KeyboardInterrupt:
        logging.info('Exiting script')            
        break

if name == ‘main’:

argparser = argparse.ArgumentParser(
    description='Record and save sound from device')

argparser.add_argument(
    '-p',
    '--port',
    help='port for connection to the device')

argparser.add_argument(
    '-b',
    '--baud_rate',
    default=115200,
    help='Connection baud rate')

argparser.add_argument(
    '-n',
    '--filename',
    default='sound',        
    help='Prefix for sound files')

args = argparser.parse_args()

main(args)