Forum Rule: Always post complete source code & details to reproduce any issue!
Page 1 of 2 1 2 LastLast
Results 1 to 25 of 26

Thread: Recording Stereo Audio to SD Card

  1. #1
    Junior Member
    Join Date
    Sep 2017
    Location
    Brisbane, Australia
    Posts
    3

    Recording Stereo Audio to SD Card

    I'm testing the ability of the Teensy (3.2 with Audio Board and 3.5) to record two channels of audio to the SD card and get write interruptions in the recorded stream. Mono works fine. Any hints on how to do this are welcome.

    I'm writing tow files concurrently to the SD card, each using its own queue object from the teensy Audio Library.

    The occasional write timing increases can be seen in this sample print output.

    SD write L, us=1260
    SD write R, us=1249
    SD write L, us=1268
    SD write R, us=1263
    SD write R, us=20907
    SD write L, us=91518
    SD write R, us=89989
    SD write L, us=91151
    SD write R, us=89601

    Below is my test code FYI.

    Code:
    #include <Audio.h>
    #include <Wire.h>
    #include <SPI.h>
    #include <SD.h>
    #include <SerialFlash.h>
    
    // GUItool: begin automatically generated code
    AudioPlaySdRaw           playRaw1;     //xy=264,355
    AudioSynthWaveformSine   sine1;          //xy=273,465
    AudioSynthWaveformSine   sine2; 
    //AudioSynthNoiseWhite     noise1;         //xy=282,522
    AudioRecordQueue         queue1;         //xy=425,489
    AudioRecordQueue         queue2; 
    AudioOutputI2S           i2s1;           //xy=451,351
    AudioConnection          patchCord1(playRaw1, 0, i2s1, 0);
    AudioConnection          patchCord2(playRaw1, 0, i2s1, 1);
    AudioConnection          patchCord3(sine1, queue1);
    AudioConnection          patchCord4(sine2, queue2);
    //AudioConnection          patchCord4(noise1, queue1);
    // GUItool: end automatically generated code
    
    AudioControlSGTL5000     sgtl5000_1;     //xy=265,212
    
    // which input on the audio shield will be used?
    //const int myInput = AUDIO_INPUT_LINEIN;
    const int myInput = AUDIO_INPUT_MIC;
    
    // Use these with the Teensy 3.5 & 3.6 SD card
    #define SDCARD_CS_PIN    BUILTIN_SDCARD // 254?
    #define SDCARD_MOSI_PIN  11  // not actually used
    #define SDCARD_SCK_PIN   13  // not actually used
    
    // Remember which mode we're doing
    int mode = 0;  // 0=stopped, 1=recording, 2=playing
    
    unsigned long Timer;
    
    // The file where data is recorded
    File frecL;
    File frecR;
    
    void setup() {
    
      // Audio connections require memory, and the record queue
      // uses this memory to buffer incoming audio.
      AudioMemory(60);
    
      // Enable the audio shield, select input, and enable output
      sgtl5000_1.enable();
      sgtl5000_1.inputSelect(myInput);
      sgtl5000_1.volume(0.5);
    
       // set sine osc 
      sine1.amplitude(1.0);
      sine1.frequency(440);
      sine2.amplitude(1.0);
      sine2.frequency(261);
      // set up ch 2 noise
      //noise1.amplitude(1.0);
    
     // Initialize the SD card
      SPI.setMOSI(SDCARD_MOSI_PIN);
      SPI.setSCK(SDCARD_SCK_PIN);
      if (!(SD.begin(SDCARD_CS_PIN))) {
        // stop here if no SD card, but print a message
        while (1) {
          Serial.println("Unable to access the SD card");
          delay(500);
        }
      }
      
      Timer = millis();
      startRecording();
    }
    
    
    void loop() {
      if((millis()-Timer)>5000) {
        stopRecording();
        startPlaying();
        while(playRaw1.isPlaying()) {
        }
        stopPlaying();
        Timer = millis();
        startRecording();
      }
      else {
        continueRecording();
      }
     
    }
    
    
    void startRecording() {
      Serial.println("startRecording");
      if (SD.exists("RECORD_L.RAW")) {
        SD.remove("RECORD_L.RAW");
      }
      if (SD.exists("RECORD_R.RAW")) {
        SD.remove("RECORD_R.RAW");
      }
      frecL = SD.open("RECORD_L.RAW", FILE_WRITE);
      frecR = SD.open("RECORD_R.RAW", FILE_WRITE);
      if (frecL) {
        queue1.begin();
        mode = 1;
      }
      if (frecR) {
        queue2.begin();
        mode = 1;
      }
    }
    
    void continueRecording() {
       
      if (queue1.available() >= 2) {
        byte buffer[512];
    
        memcpy(buffer, queue1.readBuffer(), 256);
        queue1.freeBuffer();
        memcpy(buffer+256, queue1.readBuffer(), 256);
        queue1.freeBuffer();
        // write all 512 bytes to the SD card
        elapsedMicros usec = 0;
        frecL.write(buffer, 512);
    
        Serial.print("SD write L, us=");
        Serial.println(usec);
      }
      if (queue2.available() >= 2) {
        byte buffer[512];
        memcpy(buffer, queue2.readBuffer(), 256);
        queue2.freeBuffer();
        memcpy(buffer+256, queue2.readBuffer(), 256);
        elapsedMicros usec = 0;
        queue2.freeBuffer();
        // write all 512 bytes to the SD card
        //elapsedMicros usec = 0;
        frecR.write(buffer, 512);
        Serial.print("SD write R, us=");
        Serial.println(usec);
      } 
    }
    
    void stopRecording() {
      Serial.println("stopRecording");
      queue1.end();
      queue2.end();
      if (mode == 1) {
        while (queue1.available() > 0) {
          frecL.write((byte*)queue1.readBuffer(), 256);
          queue1.freeBuffer();
        }
        frecL.close();
        while (queue2.available() > 0) {
          frecR.write((byte*)queue2.readBuffer(), 256);
          queue2.freeBuffer();
        }
        frecR.close();
      }
      mode = 0;
    }
    
    
    void startPlaying() {
      Serial.println("startPlaying");
      playRaw1.play("RECORD_L.RAW");
      mode = 2;
    }
    
    void continuePlaying() {
      if (!playRaw1.isPlaying()) {
        playRaw1.stop();
        mode = 0;
      }
    }
    
    void stopPlaying() {
      Serial.println("stopPlaying");
      if (mode == 2) playRaw1.stop();
      //mode = 0;
    }
    Last edited by algomusic; 09-08-2017 at 07:07 AM.

  2. #2
    Junior Member
    Join Date
    Sep 2017
    Location
    Brisbane, Australia
    Posts
    3
    I solved my own problem raised here, by interleaving the audio data from the two queues and doing a single file write to the SD card. This was a little more complicated than I'd hoped, and it might be nice to have a stereo-queue object that does the interleaving for us

    Here's the source code for a working solution for those that want it (there is some oddity in buffer sizes, but it seems to work).

    Code:
    #include <Audio.h>
    #include <Wire.h>
    #include <SPI.h>
    #include <SD.h>
    #include <SerialFlash.h>
    
    // GUItool: begin automatically generated code
    AudioPlaySdRaw           playRaw1;     //xy=264,355
    AudioSynthWaveformSine   sine1;          //xy=273,465
    AudioSynthKarplusStrong  string1;        //xy=144,430
    AudioRecordQueue         queue1;         //xy=425,489
    AudioRecordQueue         queue2; 
    AudioOutputI2S           i2s1;           //xy=451,351
    AudioConnection          patchCord3(string1, queue1);
    AudioConnection          patchCord4(sine1, queue2);
    // GUItool: end automatically generated code
    
    AudioControlSGTL5000     sgtl5000_1;     //xy=265,212
    
    const int myInput = AUDIO_INPUT_MIC;
    
    // Use these with the Teensy 3.5 & 3.6 SD card
    #define SDCARD_CS_PIN    BUILTIN_SDCARD // 254?
    #define SDCARD_MOSI_PIN  11  // not actually used
    #define SDCARD_SCK_PIN   13  // not actually used
    
    // Remember which mode we're doing
    int mode = 0;  // 0=stopped, 1=recording, 2=playing
    
    unsigned long Timer;
    
    // The file where data is recorded
    File frec;
    
    void setup() {
      // record queue uses this memory to buffer incoming audio.
      AudioMemory(120); // 60
    
      // Enable the audio shield, select input, and enable output
      sgtl5000_1.enable();
      sgtl5000_1.inputSelect(myInput);
      sgtl5000_1.volume(0.5);
    
       // set sine osc 
      sine1.amplitude(1.0);
      sine1.frequency(261);
    
     // Initialize the SD card
      SPI.setMOSI(SDCARD_MOSI_PIN);
      SPI.setSCK(SDCARD_SCK_PIN);
      if (!(SD.begin(SDCARD_CS_PIN))) {
        // stop here if no SD card, but print a message
        while (1) {
          Serial.println("Unable to access the SD card");
          delay(500);
        }
      }
      Timer = millis();
      startRecording();
    }
    
    
    void loop() {
      if((millis()-Timer)>5000 && mode == 1) {
        stopRecording();
      }
      else {
        if (mode == 1) continueRecording();
      }
    }
    
    void startRecording() {
      Serial.println("StartRecording");
      if (SD.exists("RECORD.RAW")) {
        SD.remove("RECORD.RAW");
      }
      frec = SD.open("RECORD.RAW", FILE_WRITE);
      if (frec) {
        Serial.println("File Open");
        queue1.begin();
        queue2.begin();
        mode = 1;
      }
      string1.noteOn(440, 1.0);
    }
    
    void continueRecording() {
      if (queue1.available() >= 2 && queue2.available() >= 2) {
        byte buffer[512];
        byte bufferL[256];
        byte bufferR[256];
        memcpy(bufferL, queue1.readBuffer(), 256);
        memcpy(bufferR, queue2.readBuffer(), 256);
        queue1.freeBuffer();
        queue2.freeBuffer();
        for (int i=0; i<512; i+=4) {
          buffer[i] = bufferL[i];
          buffer[i+1] = bufferL[i+1];
          buffer[i+2] = bufferR[i];
          buffer[i+3] = bufferR[i+1];
        }
        frec.write(buffer, 256);
      }
    }
    
    void stopRecording() {
      Serial.println("StopRecording");
      queue1.end();
      queue2.end();
      // flush buffer
      while (queue1.available() > 0 && queue2.available() > 0) {
        queue1.readBuffer();
        queue1.freeBuffer();
        queue2.readBuffer();
        queue2.freeBuffer();
      }
      frec.close(); // close file
      mode = 0;
    }

  3. #3
    Quote Originally Posted by algomusic View Post
    I solved my own problem raised here, by interleaving the audio data from the two queues and doing a single file write to the SD card. This was a little more complicated than I'd hoped, and it might be nice to have a stereo-queue object that does the interleaving for us

    Here's the source code for a working solution for those that want it (there is some oddity in buffer sizes, but it seems to work).

    Hey Algomusic,

    I did some recordings today with two mics attached to the line-inputs of the audio shield. When I imported the raw-file to Audacity (to playback and convert) it turned out to be a mono recording (I could import as a stereo but that resulted in two identical tracks). For a project I am doing I am looking for stereo sound, so your code looks really interesting; I just have some initial questions:

    I see you make two AudioRecorderQueue objects, but where do you assign which line inputs goes to which Queue?
    I assume it outputs two files one with the left channel and one with the right channel that can be joined together in other software?

    Kind regards,

    inimidi

  4. #4
    Code:
    #include <Audio.h>
    #include <Wire.h>
    #include <SPI.h>
    #include <SD.h>
    #include <SerialFlash.h>
    
    // GUItool: begin automatically generated code
    
    AudioInputI2S            i2s2;           //xy=105,63
    
    AudioRecordQueue         queue1;         //xy=425,489
    AudioAnalyzePeak         peak1;          //xy=278,108
    AudioConnection          patchCord1(i2s2, 0, queue1, 0);
    AudioConnection          patchCord2(i2s2, 0, peak1, 0);
    
    AudioRecordQueue         queue2;         //xy=425,489
    AudioAnalyzePeak         peak2;          //xy=278,108
    AudioConnection          patchCord5(i2s2, 1, queue2, 0);
    AudioConnection          patchCord6(i2s2, 1, peak2, 0);
    
    AudioPlaySdRaw           playRaw1;     //xy=264,355
    AudioSynthWaveformSine   sine1;          //xy=273,465
    AudioSynthKarplusStrong  string1;        //xy=144,430
    AudioOutputI2S           i2s1;           //xy=451,351
    AudioConnection          patchCord3(string1, queue1);
    AudioConnection          patchCord4(sine1, queue2);
    // GUItool: end automatically generated code
    
    AudioControlSGTL5000     sgtl5000_1;     //xy=265,212
    
    
    const int myInput = AUDIO_INPUT_LINEIN;   //THIS IS CHANGED---------------
    
    // Use these with the Teensy Audio Shield
    #define SDCARD_CS_PIN    10               //THIS IS CHANGED---------------
    #define SDCARD_MOSI_PIN  7                //THIS IS CHANGED---------------
    #define SDCARD_SCK_PIN   14               //THIS IS CHANGED---------------
    
    // Remember which mode we're doing
    int mode = 0;  // 0=stopped, 1=recording, 2=playing
    
    unsigned long Timer;
    
    // The file where data is recorded
    File frec;
    
    void setup() {
      //Serial.println("ghello ghello");
    
      // record queue uses this memory to buffer incoming audio.
      AudioMemory(120); // 60
    
      // Enable the audio shield, select input, and enable output
      sgtl5000_1.enable();
      sgtl5000_1.inputSelect(myInput);
      sgtl5000_1.volume(0.5);
    
      // set sine osc
      sine1.amplitude(1.0);
      sine1.frequency(261);
    
      // Initialize the SD card
      SPI.setMOSI(SDCARD_MOSI_PIN);
      SPI.setSCK(SDCARD_SCK_PIN);
      if (!(SD.begin(SDCARD_CS_PIN))) {
        // stop here if no SD card, but print a message
        while (1) {
          Serial.println("Unable to access the SD card");
          delay(500);
        }
      }
      // Serial.println("ghello");
      //Timer = millis();
      Serial.println("go");
      Serial.println(millis());
    
      // Serial.println(millis());
    }
    
    
    void loop() {
      
      if (mode == 0) {
        startRecording();
      }
    
      if (mode == 1) {
        continueRecording();
        if (millis() > 5000) {
          Serial.println(millis());
          stopRecording();
          mode = 2;
        }
      }
    
      /*if((millis())>15000 && mode == 1) {
        stopRecording();
        //Serial.println(millis());
      }
      else {
        if (mode == 1) continueRecording();
      }*/
    }
    
    void startRecording() {
      Serial.println("StartRecording");
      if (SD.exists("RECORDS.RAW")) {
        SD.remove("RECORDS.RAW");
      }
      frec = SD.open("RECORDS.RAW", FILE_WRITE);
      if (frec) {
        Serial.println("File Open");
        queue1.begin();
        queue2.begin();
        mode = 1;
      }
      string1.noteOn(440, 1.0);
    }
    
    void continueRecording() {
      if (queue1.available() >= 2 && queue2.available() >= 2) {
        byte buffer[512];
        byte bufferL[256];
        byte bufferR[256];
        memcpy(bufferL, queue1.readBuffer(), 256);
        memcpy(bufferR, queue2.readBuffer(), 256);
        queue1.freeBuffer();
        queue2.freeBuffer();
        for (int i = 0; i < 512; i += 4) {
          buffer[i] = bufferL[i];
          buffer[i + 1] = bufferL[i + 1];
          buffer[i + 2] = bufferR[i];
          buffer[i + 3] = bufferR[i + 1];
        }
        frec.write(buffer, 256);
      }
    }
    
    void stopRecording() {
      Serial.println("StopRecording");
      queue1.end();
      queue2.end();
      // flush buffer
      while (queue1.available() > 0 && queue2.available() > 0) {
        queue1.readBuffer();
        queue1.freeBuffer();
        queue2.readBuffer();
        queue2.freeBuffer();
      }
      frec.close(); // close file
      mode = 0;
    }
    I modified the code in an attempt to get it working on a teensy3.2 + audio adapter

    however it does something weird . . . It waits till the 10s recording time has emitted and then apparently quickly opens and closes the file writing nothing in it.
    Did youencounter similar issues when writing your code?

  5. #5
    Junior Member
    Join Date
    Sep 2017
    Location
    Brisbane, Australia
    Posts
    3
    I'm glad you found the code useful. In answer to your questions.

    1. The code records a single file which Audacity can read as a stereo file.

    2. The loop function does start and stop short recordings, this was my testing process. Modify the time to do recordings of different length and remove the loop callback to only record once.

    It would be more convenient to add connected buttons to start and stop the recording if you prefer.

  6. #6
    Hey algomusic,


    Thanks for the answers
    Your stereo-recording code really helps set the audio board set itself apart from competitor audio-recording boards. That's why I am determined to get it working for the teensy3.2 as well

    1. The code records a single file which Audacity can read as a stereo file.
    Awesome~ I have been studying your code andit looks like you create two separate files that are presumably merged at the end; where in the code are they merged (so I understand the code better)?


    2. The loop function does start and stop short recordings, this was my testing process. Modify the time to do recordings of different length and remove the loop callback to only record once.
    I tried different times ranging from 5 to 100 seconds (5000-100000 millis) yet none of them work. I always get an empty file. In the serial monitor I observe it opening and closing the file instantly.

    kind regards~

  7. #7

    Working code for teensy3.2 + audio shield

    I got it working~

    Here is the code:

    Code:
    #include <Audio.h>
    #include <Wire.h>
    #include <SPI.h>
    #include <SD.h>
    #include <SerialFlash.h>
    
    // GUItool: begin automatically generated code
    AudioInputI2S            i2s2;           //xy=484.6000061035156,295
    AudioAnalyzePeak         peak2;          //xy=669.1999969482422,350.1999969482422
    AudioRecordQueue         queue1;         //xy=672.5999755859375,182
    AudioAnalyzePeak         peak1;          //xy=675.5999755859375,227
    AudioPlaySdRaw           playRaw1;       //xy=681.6000061035156,389
    AudioRecordQueue         queue2;         //xy=698.1999969482422,307.1999969482422
    AudioOutputI2S           i2s1;           //xy=849.6000061035156,352
    AudioConnection          patchCord1(i2s2, 0, queue1, 0);
    AudioConnection          patchCord2(i2s2, 0, peak1, 0);
    AudioConnection          patchCord3(i2s2, 1, queue2, 0);
    AudioConnection          patchCord4(i2s2, 1, peak2, 0);
    AudioConnection          patchCord5(playRaw1, 0, i2s1, 0);
    AudioConnection          patchCord6(playRaw1, 0, i2s1, 1);
    // GUItool: end automatically generated code
    
    AudioControlSGTL5000     sgtl5000_1;     //xy=265,212
    
    
    // which input on the audio shield will be used?
    const int myInput = AUDIO_INPUT_LINEIN;
    //const int myInput = AUDIO_INPUT_MIC;
    
    
    // Use these with the Teensy Audio Shield
    #define SDCARD_CS_PIN    10
    #define SDCARD_MOSI_PIN  7
    #define SDCARD_SCK_PIN   14
    
    // Use these with the Teensy 3.5 & 3.6 SD card
    //#define SDCARD_CS_PIN    BUILTIN_SDCARD // 254?
    //#define SDCARD_MOSI_PIN  11  // not actually used
    //#define SDCARD_SCK_PIN   13  // not actually used
    
    // Remember which mode we're doing
    int mode = 0;  // 0=stopped, 1=recording, 2=playing
    
    
    
    // The file where data is recorded
    File frec;
    
    void setup() {
      // record queue uses this memory to buffer incoming audio.
      AudioMemory(120); // 60
    
      // Enable the audio shield, select input, and enable output
      sgtl5000_1.enable();
      sgtl5000_1.inputSelect(myInput);
      sgtl5000_1.volume(0.5);
    
    
    
      // Initialize the SD card
      SPI.setMOSI(SDCARD_MOSI_PIN);
      SPI.setSCK(SDCARD_SCK_PIN);
      if (!(SD.begin(SDCARD_CS_PIN))) {
        // stop here if no SD card, but print a message
        while (1) {
          Serial.println("Unable to access the SD card");
          delay(500);
        }
      }
    
      startRecording();
    }
    
    
    void loop() {
      if (millis() > 10000 && mode == 1) {
        stopRecording();
      }
      else {
        if (mode == 1) continueRecording();
      }
    }
    
    void startRecording() {
      Serial.println("StartRecording");
      if (SD.exists("RECORD3.RAW")) {
        SD.remove("RECORD3.RAW");
      }
      frec = SD.open("RECORD3.RAW", FILE_WRITE);
      if (frec) {
        Serial.println("File Open");
        queue1.begin();
        queue2.begin();
        mode = 1;
      }
    
    }
    
    void continueRecording() {
      if (queue1.available() >= 2 && queue2.available() >= 2) {
        byte buffer[512];
        byte bufferL[256];
        byte bufferR[256];
        memcpy(bufferL, queue1.readBuffer(), 256);
        memcpy(bufferR, queue2.readBuffer(), 256);
        queue1.freeBuffer();
        queue2.freeBuffer();
        for (int i = 0; i < 512; i += 4) {
          buffer[i] = bufferL[i];
          buffer[i + 1] = bufferL[i + 1];
          buffer[i + 2] = bufferR[i];
          buffer[i + 3] = bufferR[i + 1];
        }
        elapsedMicros usec = 0;
        frec.write(buffer, 256);  //256 or 512 (dudes code)
        Serial.print("SD write, us=");
        Serial.println(usec);
      }
    }
    
    void stopRecording() {
      Serial.println("StopRecording");
      queue1.end();
      queue2.end();
      // flush buffer
      while (queue1.available() > 0 && queue2.available() > 0) {
        queue1.readBuffer();
        queue1.freeBuffer();
        queue2.readBuffer();
        queue2.freeBuffer();
      }
      frec.close(); // close file
      mode = 4;
    }
    If you want you can add

    Code:
    sgtl5000_1.lineInLevel(2,2);
    in the setup() to get better quality audio.

    On the line in I have connected two electret microphone break out boards by adafruit:
    https://www.adafruit.com/product/1713

    They come with a nifty tutorial to connect:
    https://learn.adafruit.com/adafruit-...x9814/overview
    Don't forget that you need to add some capacitors.

  8. #8
    Quote Originally Posted by inimidi View Post
    I got it working~
    I am able to make a stereo recording, but the audio rate is 2X when I convert from raw to wav at 44100. If I convert at 22050, the rate is good, but I'm missing all the content above 11K. Is anyone else encountering this?

    My conversion code:

    Code:
    sox -t raw -b 16 -e signed-integer -r 44100 -c 2 input.raw output.wav
    I do not have this problem when making a mono recording.

  9. #9
    if anyone else encounters sample rate issues, see my code below. i made some changes to inimidi's code based on panphonic's post here: https://forum.pjrc.com/threads/33852...eue-Interleave

    Code:
    #include <Audio.h>
    #include <Wire.h>
    #include <SPI.h>
    #include <SD.h>
    #include <SerialFlash.h>
    
    // GUItool: begin automatically generated code
    AudioInputI2S            i2s1;           //xy=168,145
    AudioRecordQueue         queue1;         //xy=360,62
    AudioRecordQueue         queue2;         //xy=389,145
    AudioConnection          patchCord1(i2s1, 0, queue1, 0);
    AudioConnection          patchCord2(i2s1, 1, queue2, 0);
    // GUItool: end automatically generated code
    
    AudioControlSGTL5000     sgtl5000_1;     //xy=265,212
    
    
    // which input on the audio shield will be used?
    const int myInput = AUDIO_INPUT_LINEIN;
    //const int myInput = AUDIO_INPUT_MIC;
    
    
    // Use these with the Teensy Audio Shield
    #define SDCARD_CS_PIN    10
    #define SDCARD_MOSI_PIN  7
    #define SDCARD_SCK_PIN   14
    
    // Use these with the Teensy 3.5 & 3.6 SD card
    //#define SDCARD_CS_PIN    BUILTIN_SDCARD // 254?
    //#define SDCARD_MOSI_PIN  11  // not actually used
    //#define SDCARD_SCK_PIN   13  // not actually used
    
    // Remember which mode we're doing
    int mode = 0;  // 0=stopped, 1=recording, 2=playing
    
    
    
    // The file where data is recorded
    File frec;
    
    void setup() {
      // record queue uses this memory to buffer incoming audio.
      AudioMemory(120); // 60
    
      // Enable the audio shield, select input, and enable output
      sgtl5000_1.enable();
      sgtl5000_1.inputSelect(myInput);
      sgtl5000_1.volume(0.5);
    
    
    
      // Initialize the SD card
      SPI.setMOSI(SDCARD_MOSI_PIN);
      SPI.setSCK(SDCARD_SCK_PIN);
      if (!(SD.begin(SDCARD_CS_PIN))) {
        // stop here if no SD card, but print a message
        while (1) {
          Serial.println("Unable to access the SD card");
          delay(500);
        }
      }
    
      startRecording();
    }
    
    
    void loop() {
      if (millis() > 10000 && mode == 1) {
        stopRecording();
      }
      else {
        if (mode == 1) continueRecording();
      }
    }
    
    void startRecording() {
      Serial.println("StartRecording");
      if (SD.exists("RECORD.RAW")) {
        SD.remove("RECORD.RAW");
      }
      frec = SD.open("RECORD.RAW", FILE_WRITE);
      if (frec) {
        Serial.println("File Open");
        queue1.begin();
        queue2.begin();
        mode = 1;
      }
    
    }
    
    // write all 512 bytes to the SD card   
    void continueRecording() {
      if (queue1.available() >= 2 && queue2.available() >= 2) {
        byte buffer[512];
        byte bufferL[256];
        byte bufferR[256];
        memcpy(bufferL, queue1.readBuffer(), 256);
        memcpy(bufferR, queue2.readBuffer(), 256);
        queue1.freeBuffer();
        queue2.freeBuffer();
        int b = 0;
        for (int i = 0; i < 512; i += 4) {
          buffer[i] = bufferL[b];
          buffer[i + 1] = bufferL[b + 1];
          buffer[i + 2] = bufferR[b];
          buffer[i + 3] = bufferR[b + 1];
          b = b+2;
        }
        elapsedMicros usec = 0;
        frec.write(buffer, 512);  //256 or 512 (dudes code)
        Serial.print("SD write, us=");
        Serial.println(usec);
      }
    }
    
    void stopRecording() {
      Serial.println("StopRecording");
      queue1.end();
      queue2.end();
      // flush buffer
      while (queue1.available() > 0 && queue2.available() > 0) {
        queue1.readBuffer();
        queue1.freeBuffer();
        queue2.readBuffer();
        queue2.freeBuffer();
      }
      frec.close(); // close file
      mode = 4;
    }

  10. #10
    Quote Originally Posted by maxwellstein View Post
    if anyone else encounters sample rate issues, see my code below. i made some changes to inimidi's code based on panphonic's post here: https://forum.pjrc.com/threads/33852...eue-Interleave
    I was encountering the same problem, just fixed it manually in audacity every time, which is far from ideal.
    Definitely going to give this a try, thanks for sharing.

    EDIT:
    Tried it works like a charm~
    Last edited by inimidi; 11-08-2017 at 09:15 AM.

  11. #11
    Senior Member
    Join Date
    Jul 2017
    Posts
    120
    Any idea how to record mono channel using ADC ? Not from using Audio shield. Also anyone have experience recording with .wav header extension ?

  12. #12
    Senior Member PaulStoffregen's Avatar
    Join Date
    Nov 2012
    Posts
    28,461
    Quote Originally Posted by Wicky21 View Post
    Any idea how to record mono channel using ADC ? Not from using Audio shield.
    Easy, just connect the adc object in the design tool, rather than the i2s one.

    If using the examples, also delete any sgtl5000 config stuff.

  13. #13
    Senior Member
    Join Date
    Jul 2017
    Posts
    120
    Quote Originally Posted by PaulStoffregen View Post
    Easy, just connect the adc object in the design tool, rather than the i2s one.

    If using the examples, also delete any sgtl5000 config stuff.
    Paul i able achieve that. But it store as .raw file. Any idea how to convert it into .wav and store it on the SD card?

  14. #14
    Senior Member+ Theremingenieur's Avatar
    Join Date
    Feb 2014
    Location
    Colmar, France
    Posts
    2,594
    the .raw file is basically a .wav file without file header. You will find both file formats well documented on the www when you ask the good old Lady Google. Then you'll have to write some code which will read and analyze your .raw file, generate the corresponding .wav header, and write out the latter again to the SD card.

    Alternatively, you might peek the Adacity open source code which is either on GitHub or on Sourceforge, and find your inspiration there.

  15. #15
    You can interleave much simpler

    Code:
    inline void mxLR(byte *dst, const int16_t *srcL, const int16_t *srcR)
      {
        byte cnt = 128;
        int16_t *d = (int16_t *)dst;
        const int16_t *l = srcL;
        const int16_t *r = srcR;
    
        while (cnt--)
        {
          *(d++) = *l++;
          *(d++) = *r++;
        }
      }
    Code:
                    byte buffer[512]; // data to write
                    mxLR(buffer, queue1.readBuffer(), queue2.readBuffer()); // interleave 
                    queue1.freeBuffer(); queue2.freeBuffer();  // free buffer
                    frec.write(buffer, 512); // write block

  16. #16

    Audio skips when stereo recording

    Quote Originally Posted by maxwellstein View Post
    if anyone else encounters sample rate issues, see my code below. i made some changes to inimidi's code based on panphonic's post here: https://forum.pjrc.com/threads/33852...eue-Interleave

    Code:
    #include <Audio.h>
    #include <Wire.h>
    #include <SPI.h>
    #include <SD.h>
    #include <SerialFlash.h>
    
    // GUItool: begin automatically generated code
    AudioInputI2S            i2s1;           //xy=168,145
    AudioRecordQueue         queue1;         //xy=360,62
    AudioRecordQueue         queue2;         //xy=389,145
    AudioConnection          patchCord1(i2s1, 0, queue1, 0);
    AudioConnection          patchCord2(i2s1, 1, queue2, 0);
    // GUItool: end automatically generated code
    
    AudioControlSGTL5000     sgtl5000_1;     //xy=265,212
    
    
    // which input on the audio shield will be used?
    const int myInput = AUDIO_INPUT_LINEIN;
    //const int myInput = AUDIO_INPUT_MIC;
    
    
    // Use these with the Teensy Audio Shield
    #define SDCARD_CS_PIN    10
    #define SDCARD_MOSI_PIN  7
    #define SDCARD_SCK_PIN   14
    
    // Use these with the Teensy 3.5 & 3.6 SD card
    //#define SDCARD_CS_PIN    BUILTIN_SDCARD // 254?
    //#define SDCARD_MOSI_PIN  11  // not actually used
    //#define SDCARD_SCK_PIN   13  // not actually used
    
    // Remember which mode we're doing
    int mode = 0;  // 0=stopped, 1=recording, 2=playing
    
    
    
    // The file where data is recorded
    File frec;
    
    void setup() {
      // record queue uses this memory to buffer incoming audio.
      AudioMemory(120); // 60
    
      // Enable the audio shield, select input, and enable output
      sgtl5000_1.enable();
      sgtl5000_1.inputSelect(myInput);
      sgtl5000_1.volume(0.5);
    
    
    
      // Initialize the SD card
      SPI.setMOSI(SDCARD_MOSI_PIN);
      SPI.setSCK(SDCARD_SCK_PIN);
      if (!(SD.begin(SDCARD_CS_PIN))) {
        // stop here if no SD card, but print a message
        while (1) {
          Serial.println("Unable to access the SD card");
          delay(500);
        }
      }
    
      startRecording();
    }
    
    
    void loop() {
      if (millis() > 10000 && mode == 1) {
        stopRecording();
      }
      else {
        if (mode == 1) continueRecording();
      }
    }
    
    void startRecording() {
      Serial.println("StartRecording");
      if (SD.exists("RECORD.RAW")) {
        SD.remove("RECORD.RAW");
      }
      frec = SD.open("RECORD.RAW", FILE_WRITE);
      if (frec) {
        Serial.println("File Open");
        queue1.begin();
        queue2.begin();
        mode = 1;
      }
    
    }
    
    // write all 512 bytes to the SD card   
    void continueRecording() {
      if (queue1.available() >= 2 && queue2.available() >= 2) {
        byte buffer[512];
        byte bufferL[256];
        byte bufferR[256];
        memcpy(bufferL, queue1.readBuffer(), 256);
        memcpy(bufferR, queue2.readBuffer(), 256);
        queue1.freeBuffer();
        queue2.freeBuffer();
        int b = 0;
        for (int i = 0; i < 512; i += 4) {
          buffer[i] = bufferL[b];
          buffer[i + 1] = bufferL[b + 1];
          buffer[i + 2] = bufferR[b];
          buffer[i + 3] = bufferR[b + 1];
          b = b+2;
        }
        elapsedMicros usec = 0;
        frec.write(buffer, 512);  //256 or 512 (dudes code)
        Serial.print("SD write, us=");
        Serial.println(usec);
      }
    }
    
    void stopRecording() {
      Serial.println("StopRecording");
      queue1.end();
      queue2.end();
      // flush buffer
      while (queue1.available() > 0 && queue2.available() > 0) {
        queue1.readBuffer();
        queue1.freeBuffer();
        queue2.readBuffer();
        queue2.freeBuffer();
      }
      frec.close(); // close file
      mode = 4;
    }
    Does anyone else have that the recordings "skip" when recording in stereo? In a 10s recording there is consistently a chunk missing of around 800ms. Which is clearly noticeable with continuous speech or music. I tried it with two different teensy+audio boards and the problem seems to persist.

    When looking at the serial monitor when recording the "usec" seems to have a moment in which it significantly increases for a bit. Any one an idea on how to fix this?

    Things I tried that did not seem to work for me:
    - Assigning more AudioMemory (from 120 -> 180)
    - Doubling buffersizes

  17. #17
    Junior Member
    Join Date
    Aug 2017
    Posts
    19
    Quote Originally Posted by maxwellstein View Post
    if anyone else encounters sample rate issues, see my code below. i made some changes to inimidi's code based on panphonic's post here: https://forum.pjrc.com/threads/33852...eue-Interleave

    Code:
    #include <Audio.h>
    #include <Wire.h>
    #include <SPI.h>
    #include <SD.h>
    #include <SerialFlash.h>
    
    // GUItool: begin automatically generated code
    AudioInputI2S            i2s1;           //xy=168,145
    AudioRecordQueue         queue1;         //xy=360,62
    AudioRecordQueue         queue2;         //xy=389,145
    AudioConnection          patchCord1(i2s1, 0, queue1, 0);
    AudioConnection          patchCord2(i2s1, 1, queue2, 0);
    // GUItool: end automatically generated code
    
    AudioControlSGTL5000     sgtl5000_1;     //xy=265,212
    
    
    // which input on the audio shield will be used?
    const int myInput = AUDIO_INPUT_LINEIN;
    //const int myInput = AUDIO_INPUT_MIC;
    
    
    // Use these with the Teensy Audio Shield
    #define SDCARD_CS_PIN    10
    #define SDCARD_MOSI_PIN  7
    #define SDCARD_SCK_PIN   14
    
    // Use these with the Teensy 3.5 & 3.6 SD card
    //#define SDCARD_CS_PIN    BUILTIN_SDCARD // 254?
    //#define SDCARD_MOSI_PIN  11  // not actually used
    //#define SDCARD_SCK_PIN   13  // not actually used
    
    // Remember which mode we're doing
    int mode = 0;  // 0=stopped, 1=recording, 2=playing
    
    
    
    // The file where data is recorded
    File frec;
    
    void setup() {
      // record queue uses this memory to buffer incoming audio.
      AudioMemory(120); // 60
    
      // Enable the audio shield, select input, and enable output
      sgtl5000_1.enable();
      sgtl5000_1.inputSelect(myInput);
      sgtl5000_1.volume(0.5);
    
    
    
      // Initialize the SD card
      SPI.setMOSI(SDCARD_MOSI_PIN);
      SPI.setSCK(SDCARD_SCK_PIN);
      if (!(SD.begin(SDCARD_CS_PIN))) {
        // stop here if no SD card, but print a message
        while (1) {
          Serial.println("Unable to access the SD card");
          delay(500);
        }
      }
    
      startRecording();
    }
    
    
    void loop() {
      if (millis() > 10000 && mode == 1) {
        stopRecording();
      }
      else {
        if (mode == 1) continueRecording();
      }
    }
    
    void startRecording() {
      Serial.println("StartRecording");
      if (SD.exists("RECORD.RAW")) {
        SD.remove("RECORD.RAW");
      }
      frec = SD.open("RECORD.RAW", FILE_WRITE);
      if (frec) {
        Serial.println("File Open");
        queue1.begin();
        queue2.begin();
        mode = 1;
      }
    
    }
    
    // write all 512 bytes to the SD card   
    void continueRecording() {
      if (queue1.available() >= 2 && queue2.available() >= 2) {
        byte buffer[512];
        byte bufferL[256];
        byte bufferR[256];
        memcpy(bufferL, queue1.readBuffer(), 256);
        memcpy(bufferR, queue2.readBuffer(), 256);
        queue1.freeBuffer();
        queue2.freeBuffer();
        int b = 0;
        for (int i = 0; i < 512; i += 4) {
          buffer[i] = bufferL[b];
          buffer[i + 1] = bufferL[b + 1];
          buffer[i + 2] = bufferR[b];
          buffer[i + 3] = bufferR[b + 1];
          b = b+2;
        }
        elapsedMicros usec = 0;
        frec.write(buffer, 512);  //256 or 512 (dudes code)
        Serial.print("SD write, us=");
        Serial.println(usec);
      }
    }
    
    void stopRecording() {
      Serial.println("StopRecording");
      queue1.end();
      queue2.end();
      // flush buffer
      while (queue1.available() > 0 && queue2.available() > 0) {
        queue1.readBuffer();
        queue1.freeBuffer();
        queue2.readBuffer();
        queue2.freeBuffer();
      }
      frec.close(); // close file
      mode = 4;
    }
    Hello guys. Im using this code and im experiencing some periodic pop sounds in the recordings. Has anyone else had this problem?


    Im using teensy 3.6 with audioshield.


    Click image for larger version. 

Name:	Capture.PNG 
Views:	190 
Size:	41.7 KB 
ID:	13953

    Click image for larger version. 

Name:	Capture2.PNG 
Views:	168 
Size:	34.8 KB 
ID:	13954


    Thank you

  18. #18
    Senior Member
    Join Date
    Oct 2016
    Posts
    211
    How can I play the raw file stereo? The play object is mono..

  19. #19
    Junior Member
    Join Date
    Nov 2021
    Posts
    14
    Quote Originally Posted by danixdj View Post
    How can I play the raw file stereo? The play object is mono..
    I'm interested to know how to do this as well. It sounds like the only way is to convert the .raw to a .wav. I've seen folks do that with Audacity, but it'd be nice to do it all onboard the Teensy.

    I'm going to dig into it further but I'm curious if anyone has any experience with making the header file for a .raw to a .wav

  20. #20
    Senior Member
    Join Date
    Apr 2014
    Location
    -
    Posts
    9,735
    Quote Originally Posted by Ceiling View Post
    I'm interested to know how to do this as well. It sounds like the only way is to convert the .raw to a .wav. I've seen folks do that with Audacity, but it'd be nice to do it all onboard the Teensy.

    I'm going to dig into it further but I'm curious if anyone has any experience with making the header file for a .raw to a .wav
    Try this: https://github.com/FrankBoesing/Teensy-WavePlayer
    (Can record to wav, despite of the name)

  21. #21
    Senior Member
    Join Date
    Jul 2014
    Posts
    3,509
    Quote Originally Posted by Ceiling View Post
    I'm going to dig into it further but I'm curious if anyone has any experience with making the header file for a .raw to a .wav
    Not a big deal:
    To speed up recording and simplify procedures, extend wav header to 512 bytes by inserting a new chunk with real info or dummy data.
    before closing file, estimate file size etc, rewind file to header, write header, advance again to EOF and close file.

    Edit:
    Obviously to record stereo you must multiplex the data again after audio object demultiplexed stereo data into single channel queues.
    Last edited by WMXZ; 11-21-2021 at 11:22 AM.

  22. #22
    Junior Member
    Join Date
    Nov 2021
    Posts
    14
    Quote Originally Posted by Frank B View Post
    Try this: https://github.com/FrankBoesing/Teensy-WavePlayer
    (Can record to wav, despite of the name)
    Hey Frank-

    I finally got around to trying out the WavePlayer with a Teensy 3.2 and the Audio Shield. I had to change a few things on the I2S record example but it seemed to work. I did run into a loud buzzing noise when playing back the recording, but I'm thinking that's likely related to my janky test setup. I read a bit about ground loops but I couldn't find any root cause. I tried grounding the mic input and running the Teensy off of a battery rather than USB but didn't notice any difference, still a loud harsh buzzing during playback.

    I read on the documentation that you recommend using the Teensy 4.0 with the on-board SD reader rather than SPI; is this mainly related to speed concerns? I have the 3.2 and I'd like to use the audio shield as the project I'm working on needs stereo audio. I'm not opposed to picking up a Teensy 4.0 as well, but was just curious why you recommended that.

  23. #23
    Senior Member
    Join Date
    Apr 2014
    Location
    -
    Posts
    9,735
    Quote Originally Posted by Ceiling View Post
    Hey Frank-

    I read on the documentation that you recommend using the Teensy 4.0 with the on-board SD reader rather than SPI; is this mainly related to speed concerns? I have the 3.2 and I'd like to use the audio shield as the project I'm working on needs stereo audio. I'm not opposed to picking up a Teensy 4.0 as well, but was just curious why you recommended that.
    I recommend a Teensy 4.1, to use its inbuilt SD Slot (not the one from the shield) and a really good SD Card (There is a thread about good cards here). Note, both: Teensy 4.1 PLUS fast card
    The inbuilt slot has the faster 4 bit SDIO interface which is *way* faster than SPI. The CPU is not that important.
    And it's the only Teensy where I played a bit with recording. However, it's not tested much. There is a chance that it will not work with your program, too. No guarantees.
    I'm using other systems now, so it's unlikely that I do much with that anytime soon.
    Last edited by Frank B; 12-06-2021 at 04:51 PM.

  24. #24
    Senior Member
    Join Date
    Apr 2014
    Location
    -
    Posts
    9,735

  25. #25
    Junior Member
    Join Date
    Oct 2022
    Posts
    7
    Hey I tried the code you posted, and it works well but I have issues with the recording on the SD card. Sometimes the usec time drastically increases from 5us to random numbers higher than, 50000us. Did anyone encounter that also ? It is problematic because the audio is slightly cut.
    Click image for larger version. 

Name:	Screenshot 2023-02-27 181627.jpg 
Views:	12 
Size:	75.4 KB 
ID:	30516

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •