Reputation: 11
I'm working on a project that requires saving audio files from Arduino NANO 33 BLE, to create a dataset with EdgeImpulse, first of all, I can not use integrated webUSB to save audio directly on EdgeImpulse because I need to associate that audio file to a video that save locally, after that I analyze the video for associate the audio with a specific class based on the video.
My first try was to use the example file (PDMSerialPlotter) to save sampling, but if I saves the sampling received by the terminal using this python function:
def serial_import_from_arduino(time_str,serial_port_name):
ser = serial.Serial(serial_port_name, 115200) # Create Serial link
prefisso = "audio/"
file_name = prefisso + time_str + ".json"
file = open(file_name,"w")
for x in range(sample): # sample = # of samples to save
cc=str(ser.readline())
print(cc)
file.write(cc[2:][:-5])
file.write(",")
file.close()
to run this script it should have lasted 5 seconds because the microphone sampling is 16khz and the sample variable is 16k * 5 but the script runs for about 22 seconds(in this time I counted from 1 to 22), for the upload I set the sampling rate at 16khz on EdgeImpulse the audio length is 5 seconds but the audio is speeded up.
So my opinion is that the Serial.print() is not fast enough to save 16khz sampling (16bit)
Searching online I found that, the function Serial.print() converts the data to ASCII code and send it, this process can waste some time, so I made a simple Arduino code that sends just a number with Serial.write() function (that should not convert data, but can sand just 1 byte for times) this code:
void setup() {
Serial.begin(115200);
while(!Serial);
}
byte value = 255;
void loop() {
Serial.write(value);
}
And I analyzed the Serial with a Python script that reads 2 bytes (16bit) save it on a file, and count how many sample save in a second: import serial import time
ser = serial.Serial("COM3", 115200) # Create Serial link
value = 0
file = open("audio/file.txt","w")
start_time = time.time()
print(start_time)
while(time.time()-start_time < 1 ):
value = value + 1
file.write(str(ser.read(1)))
file.write(",")
file.close()
print(value)
If I take 2 bytes in 1 secods saves [5700-5800] samples, but I need 16000 in a second.
My second attempt was to save samples locally on Arduino and transfer them later all at once, the problem is that I cannot save audio with a length longer than about 6 seconds because I fill the Arduino memory, and my project requires audio longer than 6 seconds, possibly I would like to record audio continuously or at least for 30-60 min
please help me!
Upvotes: 0
Views: 749
Reputation: 11
I found a way! Just save data in a buffer, a buffer that must be uint8_t type, so at 1 Byte, for my case, I just scroll my buffer at 2 Bytes and use this code to divide the data:
if (samplesRead) {
for (int i = 0; i < samplesRead; i=i+1) {
sampleBuffer_8bit[sb_index] = (sampleBuffer[i] >> 8) & 0xFF;
sb_index ++;
sampleBuffer_8bit[sb_index] = (sampleBuffer[i] & 0xFF);
sb_index ++;
}
in this way I can use the code that follows to send an array of data, that must be at 8 bit (1 byte) all at once
SerialUSB.write(sampleBuffer_8bit,sb_index);
I used SerialUSB but also Serial should work fine, I think.
Upvotes: 1