missing data when recording audio on raspberry pi pico

125 Views Asked by At

i wanted to record audio using max9814 and raspberry pi pico with micropython/circuitpython but when i recorded the data, some parts of it lose because it's trying to read the data and write the data into a .wav file and it can not hadle it simultaneously.

the circuit is like below:

RPI PICO MAX9814
GP26 OUT
3v3 VDD
GND GND

my code is below:


import board
import analogio
import time
import adafruit_wave
import struct
import storage

# storage.remount("/", readonly=False)

adc = analogio.AnalogIn(board.A0)
conversion_factor = 3.3/4096
buffer = []

f = adafruit_wave.open("audio.wav", "w")
f.setnchannels(1)
f.setsampwidth(2)
f.setframerate(8000)

def save(data):
    global f
    f.writeframes(bytearray(data))
    print("done")

try:
    while True:
        sample = adc.value * conversion_factor
        frame = bytearray(struct.pack('>H', int(sample)))
        buffer.extend(frame)
        
        if len(buffer) > 16000:
            save(buffer)
            buffer = []
            print("clear buffer")
except KeyboardInterrupt:
    print("closing")
    f.close()

How can i handle it?

1

There are 1 best solutions below

0
Novodis On

Alright, so here's the thing: your code's trying to do too much at once and the Pico can't keep up. The trick is to split the recording and saving parts so they don't step on each other's toes. You'll use threading to handle this. Micropython on the Pico doesn't support threading like full Python, but CircuitPython does something similar with asyncio. Here's a quick fix using asyncio to manage both tasks without them interfering with each other:

First, you gotta make sure your CircuitPython firmware is up to date because asyncio is kinda recent.

Then, tweak your setup like this:

import board
import analogio
import time
import struct
import audiocore
import audiobusio
import os
import asyncio

# Initialize ADC on GP26
adc = analogio.AnalogIn(board.GP26)
conversion_factor = 3.3 / 65536  # Adjusted for CircuitPython ADC range
buffer = bytearray(16000)  # Adjust the buffer size if needed
buffer_index = 0

# Setup for the WAV file
wav_filename = "audio.wav"
audio_settings = {"channels": 1, "bits": 16, "rate": 8000}

# This function records the audio
async def record_audio():
    global buffer, buffer_index
    while True:
        if buffer_index < len(buffer) - 2:
            sample = int(adc.value * conversion_factor * 32767)  # Scale sample to 16-bit range
            struct.pack_into(">H", buffer, buffer_index, sample)
            buffer_index += 2
        else:
            await asyncio.sleep(0)  # Yield control to save_audio

# This function saves the audio
async def save_audio():
    global buffer, buffer_index
    while True:
        if buffer_index >= len(buffer) - 2:
            with open(wav_filename, "ab") as f:  # Append binary data
                wav_header = audiocore.WaveFile(f, audio_settings)
                f.write(buffer[:buffer_index])
            buffer_index = 0  # Reset buffer index after saving
        await asyncio.sleep(0)  # Yield control to record_audio

# Main function to run both tasks
async def main():
    record_task = asyncio.create_task(record_audio())
    save_task = asyncio.create_task(save_audio())
    await asyncio.gather(record_task, save_task)

# Run the main function
asyncio.run(main())

This code sets up async functions for recording audio to a buffer and saving that buffer to a file once it's full. It then runs both tasks concurrently, so one can gather data while the other writes to the disk, preventing the loss you're experiencing. The asyncio.sleep(0) calls yield execution between tasks, allowing both to proceed without blocking each other.