Forum Rule: Always post complete source code & details to reproduce any issue!
Results 1 to 3 of 3

Thread: Problem Using AudioPlaySdRaw's play() Function

Hybrid View

  1. #1
    Junior Member
    Join Date
    Feb 2019
    Posts
    9

    Problem Using AudioPlaySdRaw's play() Function

    Hi there,

    I'm trying to build a device that can record short sound snippets and play them back on command. I'm using a Teensy 3.6, and put together the following code to try and test the core functionality:

    Code:
    #include <Audio.h>
    #include <Wire.h>
    #include <SPI.h>
    #include <SD.h>
    #include <Bounce.h>
    #include <SerialFlash.h>
    
    #define REC_PIN_0             7
    #define INPUT_PIN             A1
    #define TRIG_PIN_0            8
    #define SAMPLE_NAME           "TstAudIO.raw"
    #define SDCARD_CS_PIN         BUILTIN_SDCARD
    
    
    AudioInputAnalog              input(INPUT_PIN);
    AudioRecordQueue              recQueue;
    AudioPlaySdRaw                samplePlayer;
    AudioOutputAnalogStereo       outputs;
    
    AudioConnection               in2Rec(input, 0, recQueue, 0);
    AudioConnection               samp2Outs(samplePlayer, 0, outputs, 0);
    
    Bounce recButton = Bounce(REC_PIN_0, 10);
    Bounce trigIn = Bounce(TRIG_PIN_0, 10);
    
    
    void setup() {
      //Audio Setup
      AudioMemory(80);
    
      //Serial Setup
      Serial.begin(9600);
      while (!Serial) {}
    
      //Trig/Rec Setup
      pinMode(REC_PIN_0, INPUT_PULLUP);
      pinMode(TRIG_PIN_0, INPUT_PULLUP);
    
      //SD Setup
      while (!(SD.begin(SDCARD_CS_PIN))) {
        Serial.println("Unable to access the SD card");
        delay(500);
      }
    
      analogReadResolution(16);
    
      Serial.println("setup() complete");
      Serial.println("Version with 16bit res");  
    }
    
    
    void loop() {
      updateRecButtons();
    
      updateTrigIns();
    }
    
    
    void updateRecButtons() {
      recButton.update();
      if (recButton.fallingEdge()) {
        Serial.println("Record Botton Pressed");
        record();
      }
    }
    
    
    void updateTrigIns() {
      trigIn.update();
      if (trigIn.fallingEdge()) {
        Serial.println("Sample Triggered");
        playSample();
      }
    }
    
    
    void record() {
      Serial.println("Entering record()");
    
      //Setup file to record into
      if(SD.exists(SAMPLE_NAME)) {
        SD.remove(SAMPLE_NAME);
        Serial.print("Deleting ");
        Serial.println(SAMPLE_NAME);
      }
      File file = SD.open(SAMPLE_NAME, FILE_WRITE);
      if(!file) {
        Serial.println("Error: File Not Found");
        while (digitalRead(REC_PIN_0) == LOW) {}
        return;
      }
    
      //Start Recording
      Serial.println("Starting to Record");
      recQueue.begin();
      while (!recButton.risingEdge()) {
        recButton.update();
        
        if (recQueue.available() >= 2) {
          byte buffer[512];
          
          memcpy(buffer, recQueue.readBuffer(), 256);
          recQueue.freeBuffer();
          memcpy(buffer+256, recQueue.readBuffer(), 256);
          recQueue.freeBuffer();
          
          file.write(buffer, 512);
        }
      }
    
      //Finish Recording
      Serial.println("Record Button Released");
      recQueue.end();
      while (recQueue.available() >= 2) {
        file.write((byte*)recQueue.readBuffer(), 256);
        recQueue.freeBuffer();
      }  
      file.close();
      Serial.println("Exiting record()");
    }
    
    
    void playSample() {
      if (!SD.exists(SAMPLE_NAME)) {
        Serial.print("File ");
        Serial.print(SAMPLE_NAME);
        Serial.println(" not found");
      } else {
        Serial.println("Playing sample");
        samplePlayer.stop();
        samplePlayer.play(SAMPLE_NAME);
      }
    }
    REC_PIN_0 and TRIG_PIN_0 are both connected to mechanical switches that control recording and playback (respectively). INPUT_PIN is connected to the audio in.

    The problem I'm running into is that this sketch runs fine when I'm just pressing the record button (REC_PIN_0), but freezes whenever I press the play button (TRIG_PIN_0). Pressing the record button prints all the expected comments to the Arduino IDE's serial monitor, and creates the expected .raw file. Pressing the play button satisfies the condition for the if statement in updateTrigIns(), but the Teensy does not print 'Sample Triggered' to the serial monitor, and after pressing the play button nothing happens if I try pressing the record button.

    After some troubleshooting, I've found out that if I comment out the line from playSample() that says 'samplePlayer.play(SAMPLE_NAME)' the sketch runs fine. Both 'Sample Triggered' and 'Playing sample' show up on the serial monitor, so that's telling me that I have the button wired up correctly and don't have any issues with the control flow of this sketch.

    However, I'm not sure what I should be trying now. I'm pretty sure I remember seeing somewhere that AudioInputAnalog records 12bit data, while AudioPlaySdRaw expects 16bit data. I also seem to remember seeing a function related to AudioInputAnalog that lets you change the resolution of 16bit, but the only thing I've been able to find this time around is analogReadResolution(), which isn't specific to AudioInputAnalog.

    Am I on the right track in thinking there's some incapatibility between the sort of file AudioInputAnalog creates and the sort of file AudioPlaySdRaw is meant to play? Or is there something else I should be looking into? Any thoughts you can share would be a huge help.

    Thanks!

  2. #2
    Have you played the recorded .raw file on a computer and verified that it's a good file, no corruption, etc?

    Once you know the file is okay, can you make a standalone sketch to play the pre-recorded .raw file?

    Edit... AudioInputAnalog casts the ADC samples to 16 bit, so no worries about resolution mismatch.

  3. #3
    Senior Member
    Join Date
    Nov 2012
    Posts
    1,148
    Code:
      while (recQueue.available() >= 2) {
        file.write((byte*)recQueue.readBuffer(), 256);
        recQueue.freeBuffer();
      }
    This will leave one record buffer in the queue. Wouldn't it be better to use >= 1 and drain it completely?

    Pete

Posting Permissions

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