Audio lineIn reading data from SDplay output without any connections

SteveMcI

Member
Hello,

I don't know what happening but I either stumble on a bug, or more likely, I'm missing something obvious. As part of a larger project, I'm trying to play a wav file from the SD card (right now a 1000Hz Tone) through the headphone/lineout outputs while, at the same time, reading the line in. The line in (via the audio queue) is being sent to the Serial Monitor. It doesn't have to be perfectly continuous, I just need about 50 ms worth or 18 audio queue packets. I had this working last week so I don't know what happened as I can't think of whats changed. I do think I updated the Arduino IDE to the newest version (V2.2.1 updated 4 days ago). Has anyone else experienced this issue and how did you solve it.

Thus far I've tried tested this code using 2 different computers, and two different Teensy/audio board setups (Teensy 4.1 & Audio RevD Board and a Teensy 3.5 and Audio RevC board). Same results on every combination. I've also disconnected everything to make sure I didn't cross any wires.

I'm hoping its something stupid I'm missing but I haven't been able to figure it out.

I've attached a screenshot of the Audio System Design Tool, a screenshot of the output of the Serial Plotter and the .wav file I'm using

Thank you,
Steve

Here is code

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

// GUItool: begin automatically generated code
AudioInputI2S            i2s1;           //xy=378,193
AudioPlaySdWav           playSDWav;     //xy=485,429
AudioRecordQueue         queue1;         //xy=621,179
AudioAmplifier           ampR;           //xy=682,502
AudioAmplifier           ampL;           //xy=699,387
AudioOutputI2S           i2s2;           //xy=883,435
AudioConnection          patchCord1(i2s1, 0, queue1, 0);
AudioConnection          patchCord2(playSDWav, 0, ampL, 0);
AudioConnection          patchCord3(playSDWav, 1, ampR, 0);
AudioConnection          patchCord5(ampL, 0, i2s2, 0);
AudioConnection          patchCord4(ampR, 0, i2s2, 1);
AudioControlSGTL5000     audioboard;     //xy=724,623
// GUItool: end automatically generated code

//define pins for audio shield
#define SDCARD_CS_PIN 10
#define SDCARD_MOSI_PIN 7
#define SDCARD_SCK_PIN 14

// which input on the audio shield will be used?
const int myInput = AUDIO_INPUT_LINEIN;
//const int myInput = AUDIO_INPUT_MIC;

const long interval = 100; // how read out queue data
unsigned long previousMillis = 0;  
const int numPackets = 18;  // number of packets to read from queue
const int bufferleng = 128*numPackets; // each packet is 128 samples long
int16_t data[bufferleng];
int fs = 44100; // not used - sample rate used by audioboard 
File rootdir;

bool go = 1;
bool done = 0;

void setup() {

  Serial.begin(230400);
  delay(300);  //wait for init of serial
  while (Serial.available() == 0) {
    // do nothing, wait for Serial Input to start
  }
  Serial.println("CONNECTED");
  
  // Setup SD card
  SPI.setMOSI(SDCARD_MOSI_PIN);
  SPI.setSCK(SDCARD_SCK_PIN);
  if (!(SD.begin(SDCARD_CS_PIN))) {
    //make sure accessing SD
    while (1) {
      Serial.println("Unable to access the SD card");
      delay(500);
    }
  }
  
  // read out and print all the file names on SD
  rootdir = SD.open("/");
  printDirectory(rootdir);

  // Audio connections require memory, and the record queue uses this memory to buffer incoming audio.
  AudioMemory(25);

  // Enable the audio shield, select input, and enable output
  audioboard.enable();
  audioboard.inputSelect(myInput);
  audioboard.volume(0.8);
  
  ampL.gain(1);
  ampR.gain(1);

  Serial.println("START");
  delay(1);
}

void loop() {

  playSDWav.play("1000Hz_CALIB.WAV");

  delay(10);

  while (playSDWav.isPlaying()){

    // for pause without delay() function at bottom
    unsigned long currentMillis = millis();
    
    if (go){
      go = 0;

      // begin queue for recording data
      queue1.begin();

      //  wait till queue has enough packets then stop queue and stop playing
      while(!done){
        if (queue1.available() >= numPackets) {
          queue1.end();
          done = 1;
        }
      }    

      // *********** wait till after playing to do more stuff *************
      
      // organize data from queue into buffer array
      for (int i = 1; i <= numPackets; i++){
        uint16_t (*buffer) = (queue1.readBuffer());
        queue1.freeBuffer();

        for (int j = 0; j < 128; j++){
          data[128*(i-1) + j] = buffer[j];
        }
      }

      // clear queue
      queue1.clear();

      // Serial print data to Arduino Plotter
      for (int i = 0; i < bufferleng; i++){
        Serial.print("LowBound:");
        Serial.print(-1000);
        Serial.print(",");
        Serial.print("UpBound:");
        Serial.print(1000);
        Serial.print(",");
        Serial.print("Data:");   
        Serial.println(data[i]);
      }      
    }
      
    if (currentMillis - previousMillis >= interval){

      // save the last time you blinked the LED
      previousMillis = currentMillis;
      done = 0;
      go = 1;
      
    }
  }
}

// ******* function to print all the file names on the SD card and return the number of files*******
int printDirectory(File rootdir) {

  int count = 0;
  Serial.println("FILENAMES...");

  while (true) {
    File entry =  rootdir.openNextFile();
    if (!entry) { // no more files
      break;
    }
    if (!entry.isDirectory()) {
      Serial.println(entry.name());
      count++;
    }
    entry.close();
  }
  rootdir.rewindDirectory();
  return count;
}
 

Attachments

  • wavFiles.zip
    278.7 KB · Views: 47
  • Teensy Audio Setup.png
    Teensy Audio Setup.png
    15.9 KB · Views: 49
  • Serial Plotter Screenshot.png
    Serial Plotter Screenshot.png
    29.3 KB · Views: 41
Both input and output should be i2s1, not i2s2.

[ whoops, no I think that's the Audio tool being very confusing and renaming the second i2s input or output as i2s2, which should be i2s_2 ideally... ]

Perhaps temporarily reroute the i2s input to the i2s output and check that works, if so then the playback is likely the issue.
 
Thanks MarkT for the quick reply.

Are you refering to the two i2s outputs on the teensy 4.x? I am aware of this and i don't think this is the issue. I agree its confusing in the figure from the design tool but I believe I have this correct in the code (See below). I've tried playing around with the naming but no luck.

I will try the routing idea tomorrow.

Code:
// GUItool: begin automatically generated code
AudioInputI2S            i2s1;           //xy=378,193
AudioPlaySdWav           playSDWav;     //xy=485,429
AudioRecordQueue         queue1;         //xy=621,179
AudioAmplifier           ampR;           //xy=682,502
AudioAmplifier           ampL;           //xy=699,387
AudioOutputI2S           i2s2;           //xy=883,435
AudioConnection          patchCord1(i2s1, 0, queue1, 0);
AudioConnection          patchCord2(playSDWav, 0, ampL, 0);
AudioConnection          patchCord3(playSDWav, 1, ampR, 0);
AudioConnection          patchCord5(ampL, 0, i2s2, 0);
AudioConnection          patchCord4(ampR, 0, i2s2, 1);
AudioControlSGTL5000     audioboard;     //xy=724,623
// GUItool: end automatically generated code
 
I ran some additional tests including the pass through test MarkT suggested.

- Pass through test appeared to work correctly
- Tried uninstalling the newest arduino IDE (2.2.1) and installing the previous version (2.1.0). No change
- Played with playSDWav
* Commented out this line and everything worked as expected
* Delayed this line for 4 seconds. As soon as the wav file began to play, the issue returned.

Code:
playSDWav.play("1000Hz_CALIB.WAV");

- Changed the names of the line in/out, see below. No change

Code:
// GUItool: begin automatically generated code
AudioInputI2S            LineIn;           //xy=378,193
AudioPlaySdWav           playSDWav;     //xy=485,429
AudioRecordQueue         queue;         //xy=621,179
AudioAmplifier           ampL;           //xy=699,387
AudioAmplifier           ampR;           //xy=682,502
AudioOutputI2S           LineOut;           //xy=883,435
AudioConnection          patchCord1(LineIn, 0, queue, 0);
AudioConnection          patchCord2(playSDWav, 0, ampL, 0);
AudioConnection          patchCord3(playSDWav, 1, ampR, 0);
AudioConnection          patchCord5(ampL, 0, LineOut, 0);
AudioConnection          patchCord4(ampR, 0, LineOut, 1);
AudioControlSGTL5000     audioboard;     //xy=724,623
// GUItool: end automatically generated code

- Changed the audio input from AudioOutputI2S to AudioInputAnalog seems to work, however, I need the 16bit DAC from the teensy board, not the 10bit DAC on the teensy itself.
- Removed the right output and have the queue connected to the right input. This works However I will need stereo output. A possible workaround could be to use two audio shields and the quad output.

Code:
// GUItool: begin automatically generated code
AudioInputI2S            LineIn;           //xy=378,193
AudioPlaySdWav           playSDWav;     //xy=485,429
AudioRecordQueue         queue;         //xy=621,179
AudioAmplifier           ampL;           //xy=699,387
//AudioAmplifier           ampR;           //xy=682,502
AudioOutputI2S           LineOut;           //xy=883,435
AudioConnection          patchCord1(LineIn, 1, queue, 0);
AudioConnection          patchCord2(playSDWav, 0, ampL, 0);
//AudioConnection          patchCord3(playSDWav, 1, ampR, 0);
AudioConnection          patchCord5(ampL, 0, LineOut, 0);
//AudioConnection          patchCord4(ampR, 0, LineOut, 1);
AudioControlSGTL5000     audioboard;     //xy=724,623
// GUItool: end automatically generated code

It seems like the AudioInputI2S and AudioOutputI2S are somehow crossed in the SGTL5000. Does anyone know if this is true?
 
A couple more things to try. One is to increase the AudioMemory(25) to, say, 50. If you're using 18 blocks for the queue, that's leaving perilously few for other uses. The other is to move the queue1.freeBuffer(); line to after you've copied the data. As it stands it could be used again before the copy is finished.

Having said that, your code works for me (Teensy 4.1 and Rev D audio adaptor, Teensyduino 1.59 beta 3), though I was a bit flummoxed when nothing worked to start with, then looked closer and discovered you have to send a serial character to allow setup() to proceed. Never seen that one before...
 
Thank you h4yn0nnym0u5e. I tried both the things you suggested but sadly it didn't work. I did get it working properly by commenting out the "audioboard.volume(0.8);" (line 73).

Having said that, your code works for me (Teensy 4.1 and Rev D audio adaptor, Teensyduino 1.59 beta 3), though I was a bit flummoxed when nothing worked to start with, then looked closer and discovered you have to send a serial character to allow setup() to proceed. Never seen that one before...
I agree this is weird in the context of the code I posted. The overall project is communicating via Serial with Matlab, this line is to make the teensy wait for Matlab. I should have removed it for the posted code.




I'm posting my updated code because I've changed enough variable names and added a second queue. I was getting confused going back and forth with what I had originally posted.

It seems to work with "audioboard.volume(0.8);", in setup(), commented out. If any one knows why this line is causing issues, I'd love to know.
Code:
#include <Audio.h>
#include <Wire.h>
#include <SPI.h>
#include <SD.h>
#include <SerialFlash.h>

// GUItool: begin automatically generated code
AudioPlaySdWav           playSdWav;     //xy=485,429
AudioRecordQueue         queueL;         //xy=621,179
AudioRecordQueue         queueR;         //xy=621,179
AudioAmplifier           ampL;           //xy=699,387
AudioAmplifier           ampR;           //xy=682,502
AudioInputI2S            LineIn;           //xy=378,193
AudioOutputI2S           LineOut;           //xy=883,435
AudioConnection          patchCord1(playSdWav, 0, ampL, 0);
AudioConnection          patchCord2(playSdWav, 1, ampR, 0);
AudioConnection          patchCord3(ampL, 0, LineOut, 0);
AudioConnection          patchCord4(ampR, 0, LineOut, 1);
AudioConnection          patchCord5(LineIn, 0, queueL, 0);
AudioConnection          patchCord6(LineIn, 1, queueR, 0);
AudioControlSGTL5000     audioboard;     //xy=724,623
// GUItool: end automatically generated code

//define pins for audio shield
#define SDCARD_CS_PIN 10
#define SDCARD_MOSI_PIN  7  
#define SDCARD_SCK_PIN   14  

// which input on the audio shield will be used?
const int myInput = AUDIO_INPUT_LINEIN;
// const int myInput = AUDIO_INPUT_MIC;

const long interval = 75; // how read out queue data
unsigned long previousMillis = 0;  
const int numPackets = 18;  // number of packets to read from queue
const int bufferleng = 128*numPackets; // each packet is 128 samples long
int16_t dataL[bufferleng];
int16_t dataR[bufferleng];
int fs = 44100; // not used - sample rate used by audioboard 
File rootdir;

bool go = 1;
bool done = 0;

void setup() {

  Serial.begin(9600);
  delay(300);  //wait for init of serial
  // while (Serial.available() == 0) {
  //   // do nothing, wait for Serial Input to start, wait for matlab to start
  // }
  Serial.println("CONNECTED");
  
  // Setup SD card
  SPI.setMOSI(SDCARD_MOSI_PIN);
  SPI.setSCK(SDCARD_SCK_PIN);
  if (!(SD.begin(SDCARD_CS_PIN))) {
    //make sure accessing SD
    while (1) {
      Serial.println("Unable to access the SD card");
      delay(500);
    }
  }
  
  // read out and print all the file names on SD
  rootdir = SD.open("/");
  printDirectory(rootdir);

  // Audio connections require memory, and the record queue uses this memory to buffer incoming audio.
  AudioMemory(100);

  // Enable the audio shield, select input, and enable output
  audioboard.enable();
  audioboard.inputSelect(myInput);
  // audioboard.volume(0.8);

  ampL.gain(1);
  ampR.gain(1);

  Serial.println("START");
  delay(1);
}

void loop() {

  playSdWav.play("1000Hz_CALIB.WAV");
  //playSdWav.play("710Hz_calib.wav");

  delay(10);

  while (playSdWav.isPlaying()){

    // for pause without delay() function at bottom
    unsigned long currentMillis = millis();
    
    if (go){
      go = 0;

      // begin queue for recording data
      queueL.begin();
      queueR.begin();

      // wait till queue has enough packets then stop queue and stop playing
      while(!done){
        if ((queueL.available() >= numPackets) && (queueR.available() >= numPackets)) {
          queueL.end();
          queueR.end();
          done = 1;
        }
      }    

      // *********** wait till after playing to do more stuff *************
      
      // organize data from queue into buffer array
      for (int i = 1; i <= numPackets; i++){
        uint16_t (*bufferL) = (queueL.readBuffer());
        uint16_t (*bufferR) = (queueR.readBuffer());

        for (int j = 0; j < 128; j++){
          dataL[128*(i-1) + j] = bufferL[j];
          dataR[128*(i-1) + j] = bufferR[j];
        }
        queueL.freeBuffer();
        queueR.freeBuffer();
      }

      // clear queue
      queueL.clear();
      queueR.clear();

      // Serial print data to Arduino Plotter
      for (int i = 0; i < bufferleng; i++){
        Serial.print("LowBound:");
        Serial.print(-1000);
        Serial.print(",");
        Serial.print("UpBound:");
        Serial.print(1000);
        Serial.print(",");
        Serial.print("DataR:");   
        Serial.print(dataR[i]);
        Serial.print(",");
        Serial.print("DataL:");   
        Serial.println(dataL[i]);
      }      
    }
      
    if (currentMillis - previousMillis >= interval){

      // save the last time you blinked the LED
      previousMillis = currentMillis;
      done = 0;
      go = 1;
    }
  }
}

// ******* function to print all the file names on the SD card and return the number of files*******
int printDirectory(File rootdir) {

  int count = 0;
  Serial.println("FILENAMES...");

  while (true) {
    File entry =  rootdir.openNextFile();
    if (!entry) { // no more files
      break;
    }
    if (!entry.isDirectory()) {
      Serial.println(entry.name());
      count++;
    }
    entry.close();
  }
  //rootdir.rewindDirectory();
  return count;
}
 
Hi, SteveMcl!
I'm doing a similar project just like yours, and got the same issue. Here's the link to my thread: Unexpected FFT Peak with Disconnected Sensors.
I'm using "waveform" to generate a 10khz signal on line_out, and saving data recorded from line_in. Then, plot their FFTs. The problem is I can always see the peak on FFT at 10kHz, even when line_in and line_out are disconnected (no sensors attached).
I also tried your solution which is commenting out "audioboard.volume()", but I could still see the peak at 10khz. The good thing is the peak value actually decreases after commenting out this line. But I don't understand why we still see the peak here. Here's my Current Reply describing this.
Did you get rid of all the unexpected data after commenting out this line? Do you have any idea about my current issue?
Thank you!
 
What happens if you short the line inputs to ground? I'd expect almost no breakthough in that condition. Leaving them floating will allow a little 10kHz pickup through capacitive coupling.
 
What happens if you short the line inputs to ground? I'd expect almost no breakthough in that condition. Leaving them floating will allow a little 10kHz pickup through capacitive coupling.
Know I am jumping in here but curious on what is causing the problem. Using @Aaron Z sketch and Python sketches if you tie LineIN to Linein Ground
Figure_1.png

Still seeing a bit of peak out of the noise level at 10k and 20k
 
this is if I set
sgtl5000_1.lineInLevel(5); // 0-15, default 5, set input sensitivity
sgtl5000_1.lineOutLevel(29); // 13-31, default 29, set output voltage

from
sgtl5000_1.lineInLevel(15); // 0-15, default 5, set input sensitivity
sgtl5000_1.lineOutLevel(13); // 13-31, default 29, set output voltage
Figure_1.png
 
Guess the question is - is the sketch correct:
Code:
#include <Audio.h>
#include <SerialFlash.h>

// Setup for receiver
AudioInputI2S            i2s1;
AudioRecordQueue         queue;    // Use a queue object to record data into the buffer
AudioConnection          patchCord1(i2s1, queue);
AudioControlSGTL5000     sgtl5000_1;

// Setup for speaker
AudioSynthWaveform       waveform;     
AudioOutputI2S           i2s2;           
AudioConnection          patchCord2(waveform, 0, i2s2, 0);  // L LINE_OUT

const int myInput = AUDIO_INPUT_LINEIN;

void setup() {
  Serial.begin(9600);
  AudioMemory(60);

  sgtl5000_1.enable();
  sgtl5000_1.inputSelect(myInput);
  //sgtl5000_1.volume(1);
  sgtl5000_1.lineInLevel(15);    // 0-15, default 5, set input sensitivity
  sgtl5000_1.lineOutLevel(13);    // 13-31, default 29, set output voltage

  waveform.begin(1, 10000, WAVEFORM_SINE);   // Set amplitude and frequency for speaker

  queue.begin();
}

void loop() {
  if (queue.available() > 0) {
    int16_t *buffer = queue.readBuffer();
    for (int i = 0; i < AUDIO_BLOCK_SAMPLES; i++) {
      Serial.print(buffer[i]);
      if (i < AUDIO_BLOCK_SAMPLES - 1) Serial.print(",");
    }
    Serial.println();
    queue.freeBuffer();
  }
}

Maybe we should continue this on the other thread:
 
Back
Top