Queue Audio object and i2c issue

danixdj

Well-known member
Queue Audio object and i2c issue

Hi, i have a stranger issue with the queue audio object and i2c components in my T4 and Audio Shield rev D project.

When begin the queue while a i2c display (or multiplexer or anything) is working the audio stream is stopped and the queue object don't works.
Looks like a freeze..

In this sketch the freezing appears when I press the button and disappears when I release the button.

If I stop the i2c stream (removing display line in loop) the queue object works fine.

I can't understand what's happening.

Code:
#include <Bounce2.h>
#include <Audio.h>
#include <Wire.h>
#include <SPI.h>
#include <SD.h>
#include <SerialFlash.h>
#include <Adafruit_SSD1306.h>
#include <Adafruit_GFX.h>

AudioInputI2S            line_in;           //xy=156,246
AudioAnalyzePeak         peak1;          //xy=590,456
AudioRecordQueue         queue_left;         //xy=484,188
AudioRecordQueue         queue_right;         //xy=498,241
AudioOutputI2S           i2s2;           //xy=682,409
AudioConnection          patchCord1(line_in, 0, queue_left, 0);
AudioConnection          patchCord2(line_in, 1, queue_right, 0);
AudioConnection          patchCord3(line_in, 0, peak1, 0);
AudioConnection          patchCord4(line_in, 0, i2s2,0);
AudioConnection          patchCord5(line_in, 0, i2s2, 1);
AudioControlSGTL5000     sgtl5000_1;

#define BOUNCE_LOCK_OUT
Bounce button1 = Bounce(9, 5);

#define OLED_RESET -1
Adafruit_SSD1306 display(OLED_RESET);

void setup() {

button1.attach( 9, INPUT_PULLUP );
display.begin(SSD1306_SWITCHCAPVCC, 0x3C);
AudioMemory(60);
sgtl5000_1.enable();

}

void loop() {
display.clearDisplay();
button1.update();
if (button1.fell()) {queue_left.begin(); queue_right.begin();}
if (button1.rose()) {queue_right.end(); queue_left.end();
                     queue_left.clear();queue_right.clear();}
if (peak1.available()) {display.setCursor(35,25); display.setTextSize(2); display.setTextColor(WHITE); display.print(peak1.read());}
display.display();
}

can you help me?

Thank u
 
You aren't doing anything with the queued buffers when you press the button. You need to at least check if a buffer is available and, if so, read it (if you're going to process that data) and then free it.

Clearing the display every time through the loop function takes up a lot of time. You should clear it once in setup and then arrange the data display so that you only overwrite the part(s) that need updating.

Pete
 
At the very least, you need to free the buffers. Add this in the loop function:
Code:
  if(queue_left.available() > 0) {
    queue_left.freeBuffer();
  }
  if(queue_right.available() > 0) {
    queue_right.freeBuffer();
  }

Pete
 
At the very least, you need to free the buffers. Add this in the loop function:
Code:
  if(queue_left.available() > 0) {
    queue_left.freeBuffer();
  }
  if(queue_right.available() > 0) {
    queue_right.freeBuffer();
  }

Pete

This code is only an example, my real project works fine for record and play BUT not if a i2c stream is active…
It’s not a problem of buffer but something else..
 
I can't debug what I can't see, but at a guess I'd say you are doing the same kind of thing as in this example code. You aren't handling the display efficiently and ensuring that audio buffers are processed in a timely manner.

Pete
 
The display is an example, I have the same issue with a multiplexer (instead of the display), like MCP23017.
If a put a simply mcp.digitalRead(0) (for only one pin) the queue goest to freeze.

I can add a lot of objects, functions, activities and all works fine but if I have a i2c stream I have a freeze when queue_left.begin().

i can't understand why...
 
At the very least, you need to free the buffers. Add this in the loop function:
Code:
  if(queue_left.available() > 0) {
    queue_left.freeBuffer();
  }
  if(queue_right.available() > 0) {
    queue_right.freeBuffer();
  }

Pete

Added and I have the same issue :(

Code:
#include <Bounce2.h>
#include <Audio.h>
#include <Wire.h>
#include <SPI.h>
#include <SD.h>
#include <SerialFlash.h>

AudioInputI2S            line_in;           //xy=156,246
AudioAnalyzePeak         peak1;          //xy=590,456
AudioRecordQueue         queue_left;         //xy=484,188
AudioRecordQueue         queue_right;         //xy=498,241
AudioOutputI2S           i2s2;           //xy=682,409
AudioConnection          patchCord1(line_in, 0, queue_left, 0);
AudioConnection          patchCord2(line_in, 1, queue_right, 0);
AudioConnection          patchCord3(line_in, 0, peak1, 0);
AudioConnection          patchCord4(line_in, 0, i2s2,0);
AudioConnection          patchCord5(line_in, 0, i2s2, 1);
AudioControlSGTL5000     sgtl5000_1;


#include <Adafruit_SSD1306.h>
#include <Adafruit_GFX.h>

#define BOUNCE_LOCK_OUT
Bounce button1 = Bounce(9, 5);

#define OLED_RESET -1
Adafruit_SSD1306 display(OLED_RESET);

void setup() {

button1.attach( 9, INPUT_PULLUP );
display.begin(SSD1306_SWITCHCAPVCC, 0x3C);
AudioMemory(60);
sgtl5000_1.enable();


}

void loop() {

// your suggestion
 if(queue_left.available() > 0) {
    queue_left.freeBuffer();
  }
  if(queue_right.available() > 0) {
    queue_right.freeBuffer();
  }

//----

display.clearDisplay();
button1.update();
if (button1.fell()) {queue_left.begin(); queue_right.begin();}
if (button1.rose()) {queue_right.end(); queue_left.end();
                     queue_left.clear();queue_right.clear();}
if (peak1.available()) {display.setCursor(35,25); display.setTextSize(2); display.setTextColor(WHITE); display.print(peak1.read());}
display.display();
}
 
Try this:
Code:
#include <Bounce2.h>
#include <Audio.h>
#include <Wire.h>
#include <SPI.h>
#include <SD.h>
#include <SerialFlash.h>

AudioInputI2S            line_in;           //xy=156,246
AudioAnalyzePeak         peak1;          //xy=590,456
AudioRecordQueue         queue_left;         //xy=484,188
AudioRecordQueue         queue_right;         //xy=498,241
AudioOutputI2S           i2s2;           //xy=682,409
AudioConnection          patchCord1(line_in, 0, queue_left, 0);
AudioConnection          patchCord2(line_in, 1, queue_right, 0);
AudioConnection          patchCord3(line_in, 0, peak1, 0);
AudioConnection          patchCord4(line_in, 0, i2s2,0);
AudioConnection          patchCord5(line_in, 0, i2s2, 1);
AudioControlSGTL5000     sgtl5000_1;


#include <Adafruit_SSD1306.h>
#include <Adafruit_GFX.h>

#define BOUNCE_LOCK_OUT
Bounce button1 = Bounce(9, 5);

#define OLED_RESET -1
Adafruit_SSD1306 display(OLED_RESET);

void setup()
{

  button1.attach( 9, INPUT_PULLUP );
  display.begin(SSD1306_SWITCHCAPVCC, 0x3C);
  AudioMemory(60);
  sgtl5000_1.enable();

  display.clearDisplay();
  display.setTextSize(2);
  display.setTextColor(WHITE);
}

void loop()
{
// your suggestion
  while(queue_left.available() > 0) {
    queue_left.freeBuffer();
  }
  while(queue_right.available() > 0) {
    queue_right.freeBuffer();
  }

//----
  button1.update();
  if (button1.fell()) {
    queue_left.begin();
    queue_right.begin();
  }
  if (button1.rose()) {
    queue_right.end(); queue_left.end();
    queue_left.clear(); queue_right.clear();
  }
  if (peak1.available()) {
    display.setCursor(35,25);
    char t_peak[16];
    sprintf("%5.3f",peak1.read);
    display.print(t_peak);
    display.display();
  }
}
I've changed the test for queue availability from "if" to "while" so that if there's more than one buffer available it will process them right away.
I use sprintf to format the number the same way so that when it is displayed, it always takes up the same number of characters on the display. Then you don't need to keep erasing the whole screen - only the characters that have changed need to be rewritten.
Also put the .display() inside the if statement - it doesn't need to be called if nothing has changed.



Pete
 
Nothing... the same issue..

The CPU is 0.12% ...is a T4, I don't think that is too busy, there is something wrong in the queue object about i2c, not what we do with queue data I think..

Thanks Pete for your help, it's very appreciated! :)
Is there anything else i can try?
 
If u want to try the sketch it works without a display connected, you need a button and audio in out...
 
This has nothing to do with I2C.
AHA! When you enable the queue, not only must you free the buffer, but first you MUST read it even if you do nothing with the data.

Try this in loop:
Code:
  if(queue_left.available() > 0) {
    queue_left.readBuffer();
    queue_left.freeBuffer();
  }
  if(queue_right.available() > 0) {
    queue_right.readBuffer();
    queue_right.freeBuffer();
  }

and I should've at least compiled my code before posting it. Then I would have noticed that this sprintf will compile:
Code:
    sprintf(t_peak,"%5.3f",peak1.read());

Pete
 
Thanks Pete, now the button for queue works but only because your code don't update anything on display...

using the readBuffer() it seems to work, I'll update you soon ..

Thank u
 
With this code in loop all the data of queue are unusable so it's not a solution :(

Code:
if(queue_left.available() > 0) {
    queue_left.readBuffer();
    queue_left.freeBuffer();
  }
  if(queue_right.available() > 0) {
    queue_right.readBuffer();
    queue_right.freeBuffer();
  }

This is what I do with the queue:

Code:
void startRecording(byte sel) {
  rec_target = sel;
  int16_t rec_count = 0;;
  address = (bankstart[rec_target] / 2) + foffset;
  queue_left.begin();
  queue_right.begin();

}



void continueRecording() {
  byte q1a = queue_left.available();
  byte q2a = queue_right.available();

  if (q1a == 1 && q2a == 1) {

    int16_t buffer_in_left[(getsize * 4) + 10];
    int16_t buffer_in_right[(getsize * 4) + 10];
    int16_t buffer_out[(getsize * 2) + 10];

    memcpy(buffer_in_left, queue_left.readBuffer(), getsize);
    memcpy(buffer_in_right, queue_right.readBuffer(), getsize);

    queue_left.freeBuffer();
    queue_right.freeBuffer();
    
    for (uint32_t i = 0; i < getsize; i ++) {
      uint16_t j = i * 2;
      buffer_out[j] = buffer_in_left[i];
      buffer_out[j + 1] = buffer_in_right[i];
    }


void stopRecording() {
  samplelen[rec_target] = ((address) - ((bankstart[rec_target] / 2) + foffset)) / 2;
  save_sample_length(rec_target, samplelen[rec_target]);
  queue_right.end();
  queue_left.end();

  while (queue_left.available() > 0) {
    queue_left.freeBuffer();
    queue_left.clear();
    queue_right.freeBuffer();
    queue_right.clear();
  }

I can't find something wrong, i'm using "read" and "free buffer" but when there is a i2c communication goes to feeze
 
Code:
  if (q1a == 1 && q2a == 1) {
It would be safer to do this:
Code:
  if (q1a > 0 && q2a > 0) {

What is the value of "getsize"? You have some inconsistent declarations involving getsize which don't make sense.

Code:
    memcpy(buffer_in_left, queue_left.readBuffer(), getsize);
    memcpy(buffer_in_right, queue_right.readBuffer(), getsize);

An audio buffer is 256 bytes (unless you've meddled with the audio library code) and so getsize should be 256 otherwise these copies will either not copy enough or will copy too much from the buffer.

Code:
    int16_t buffer_in_left[(getsize * 4) + 10];
    int16_t buffer_in_right[(getsize * 4) + 10];
    int16_t buffer_out[(getsize * 2) + 10];

This is where the inconsistency comes in. If getsize is the correct value (256) to copy the audio buffers, then these declarations will allocate much more than is required for the left and right buffers.

I haven't used .end and .clear but I think this isn't quite right.
Code:
  queue_right.end();
  queue_left.end();

  while (queue_left.available() > 0) {
    queue_left.freeBuffer();
    queue_left.clear();
    queue_right.freeBuffer();
    queue_right.clear();
  }

The documentation of clear() implies that it empties the buffers so in stopRecording() you should only need:
Code:
  queue_right.end();
  queue_left.end();
  queue_right.clear();
  queue_left.clear();

But if you want to be sure the buffers are gone you can add this:
Code:
  while (queue_left.available() > 0) {
    queue_left.readBuffer();
    queue_left.freeBuffer();
  }
  while (queue_right.available() > 0) {
    queue_right.readBuffer();
    queue_right.freeBuffer();
  }

As far as the freezing is concerned, you must ensure that, while you are recording, you call continueRecording() at least every 2.9 milliseconds to ensure that the buffers are processed in a timely manner.

In the continueRecording() function, once you have interleaved the left and right channel samples, what do you do with buffer_out? Write it to an SD card?

Pete
 
Thanks Pete, your suggestions are very helpful... I'm solved!!! :)

getsize is #define getsize AUDIO_BLOCK_SAMPLES*2
and adding AudioMemory(256); all works fine!!
 
Hey guys.
Could you please help me get to work queue record and play with audio shield RevD and Teensy4.1. I wrote very simple code for pseudo octaver , but I can't get audio from queue record and send it to octaver function and to the output.
I just got clean signal without effect.
The code below is really simple, I have done more advanced effects but I used different hardware with 12bit DAC. I just want migrate to the audio shield because quality.
First of all I need get to work queues with octaver. If someone have suggestions i will be grateful


Code:
IntervalTimer timer;
#include <Audio.h>
#include <Wire.h>
#include <SPI.h>
#include <SD.h>
#include <SerialFlash.h>

// GUItool: begin automatically generated code
AudioInputI2S            i2s1Record;           //xy=609,170
AudioMixer4              mixer1;         //xy=754,183
AudioPlayQueue           queuePlay;         //xy=876,410
AudioRecordQueue         queueRecord;         //xy=897,184
AudioMixer4              mixer2;         //xy=1032,429
AudioOutputI2S           i2s2Play;           //xy=1216,429
AudioConnection          patchCord1(i2s1Record, 0, mixer1, 0);
AudioConnection          patchCord2(i2s1Record, 1, mixer1, 1);
AudioConnection          patchCord3(mixer1, queueRecord);
AudioConnection          patchCord4(mixer1, 0, mixer2, 1);
AudioConnection          patchCord5(queuePlay, 0, mixer2, 0);
AudioConnection          patchCord6(mixer2, 0, i2s2Play, 0);
AudioConnection          patchCord7(mixer2, 0, i2s2Play, 1);
AudioControlSGTL5000     sgtl5000_1;     //xy=923,106
// GUItool: end automatically generated code



#define SAMPLES 128
int16_t  buffer[SAMPLES];
int16_t  bufferO[SAMPLES];
int16_t inputFX = 0, outputFX = 0;
int speed = 0, time = 0;

void setup() {
  AudioMemory(20);
  sgtl5000_1.enable();
  sgtl5000_1.volume(0.8);
  sgtl5000_1.inputSelect(AUDIO_INPUT_MIC);
  sgtl5000_1.micGain(16);
  //sgtl5000_1.lineInLevel(5);
  //sgtl5000_1.lineOutLevel(10);

  mixer1.gain(0, 1.0);
  mixer1.gain(1, 1.0);
  mixer1.gain(2, 0);
  mixer1.gain(3, 0);

  mixer2.gain(0, 1.0);
  mixer2.gain(1, 0);
  mixer2.gain(2, 0);
  mixer2.gain(3, 0);

  queuePlay.setBehaviour(AudioPlayQueue::NON_STALLING);
  queuePlay.setMaxBuffers(8);

  queueRecord.begin();

  timer.begin(effect, 30);
  timer.priority(128);

}

void input() { // i2S input
  memcpy(buffer, queueRecord.readBuffer(), 256);
  queueRecord.freeBuffer();
  for (int i = 0; i < AUDIO_BLOCK_SAMPLES; i++) {
    inputFX = buffer[i];
  }
}

void output() { //i2S output
  memcpy(bufferO, queuePlay.getBuffer(), 256);
  for (int i = 0; i < AUDIO_BLOCK_SAMPLES; i++) {
    bufferO[i] = outputFX;
    queuePlay.playBuffer();
  }
}

void loop() {}

void effect() {
  if (queueRecord.available() >= 1)input(),output();
  //test();
  octaver();
}

void test() { // clean send input to output.
  outputFX = inputFX;
}

void octaver() {
  int q = inputFX;
  time = map(analogRead(15), 0, 1023, 0, 500);
  speed++;
  if (speed >= time) {
    speed = 0;
    outputFX = q;
  }
}
 
Back
Top