Unreliable recording delay

TeensyPhonon

Active member
Yes it is me again and I am here due to a delay issue (again).

This time, I am concentrating on playing and recording sound with one Teensy (I am using a Teensy 4.1 with the SPH0645 I2S microphone and the MAX98357A I2S amp). I wrote a simple code to do this:

C++:
digitalWrite(0,LOW);

Q_in_L.begin();
Q_in_L.clear();

for (int i = 0; i < nfor; i++) {
    while(Q_in_L.available() < 1);

    sp_L = Q_out_L.getBuffer();
    memcpy(sp_L, &chirp[partitionsize * i], 2*partitionsize);
    Q_out_L.playBuffer();

    sp_L = Q_in_L.readBuffer();
    memcpy(&q15_buffer_L[partitionsize * i], sp_L, 2*partitionsize);
    Q_in_L.freeBuffer();
}

//uploading data to the PC
char conv[2];
for (int i = 0; i < nc; i++) {
    memcpy(conv, &q15_buffer_L[i], 2);
    Serial.write(conv, 2);
    if (i % Nflush == 1) {
        Serial.flush();
    }
}

digitalWrite(0, HIGH);
Q_in_L.end();
Q_in_L.clear();

I thought it worked perfectly, but it seems like, sometimes (like 1/100 or something), it introduces a random delay...

Here is a test where I emitted a chirp and observed the result 150 times (I correlated the received signal with the chirp to better see the delay).

delay_fig.png


It might seem okay for you, but I need to perform experiments where I need to do over 10,000 recordings like that, so it is really annoying...

I am using the bare minimum of the audio library:

C++:
AudioInputI2S            i2s_in;
AudioRecordQueue         Q_in_R;
AudioRecordQueue         Q_in_L;
AudioPlayQueue           Q_out_R;
AudioPlayQueue           Q_out_L;
AudioOutputI2S           i2s_out;
AudioConnection          patchCord1(i2s_in, 0, Q_in_L, 0);
AudioConnection          patchCord3(i2s_in, 1, Q_in_R, 0);
AudioConnection          patchCord7(Q_out_R, 0, i2s_out, 1);
AudioConnection          patchCord8(Q_out_L, 0, i2s_out, 0);

Really, all of that looks like dark magic to me.
 
The difference being, the "dark magic" does actually have some documentation: the Design Tool gives you information when you select an object. It is usually helpful and rarely inaccurate, though it can be a bit out of date. The Audio library page also has, and links to, much useful information.

You don't make it easy to understand your program when you supply only disconnected fragments - no-one can drop what you posted into the Arduino IDE, compile it, and try it. And it's almost 100% certain no-one will bother to guess what's missing, create it, and test it.

Unlabelled graph axes are also pretty unhelpful.

At a wild guess, you're getting out of sync with Q_in_L. You wait for it to have at least 1 item in it, then go off and do something completely unrelated, and only afterwards come back and take out the first item ... by which time, there could be two items in there. It's a queue, so you'll get the first audio block, but your output chirp might be one block out of sync. Bear in mind, audio interrupts happen at low priority every 2.9ms, so it's easy for e.g. USB code to get your synchronisation awry.

There's no real reason to feed Q_out_L one block at a time, since you apparently have the output data ready; start by queuing a few blocks, keep track, and stop feeding the output when you've run out of data.

You may find it's as simple as syncing up just after your Q_in_L.clear; line, by waiting for a Q_in_L block to become available and discarding it, before you enter the for loop.
 
Back
Top