Playing a wav file from SD Card reader

joebmz98

Member
Hiya,

I'm new to this forums!

I decided to take upon a rather grand project of a small granular sampler with the Teensy 4.0 and its audio shield. Currently, I'm getting used to the whole, having a dev board in front of me as I'm very much used to a Matlab or JUCE environment (I am doing an Arduino course at the same time to help familiarise myself).

Unfortunately, I've had issues just using some of the example pieces of code. For example, the "WavFilePlayer" from Teensyduino, I uploaded to my teensy and after the setup function, the sample I have on my SD card plays once but never again. Here is the attached code:

Code:
// Simple WAV file player example
//
// Three types of output may be used, by configuring the code below.
//
//   1: Digital I2S - Normally used with the audio shield:
//         http://www.pjrc.com/store/teensy3_audio.html
//
//   2: Digital S/PDIF - Connect pin 22 to a S/PDIF transmitter
//         https://www.oshpark.com/shared_projects/KcDBKHta
//
//   3: Analog DAC - Connect the DAC pin to an amplified speaker
//         http://www.pjrc.com/teensy/gui/?info=AudioOutputAnalog
//
// To configure the output type, first uncomment one of the three
// output objects.  If not using the audio shield, comment out
// the sgtl5000_1 lines in setup(), so it does not wait forever
// trying to configure the SGTL5000 codec chip.
//
// The SD card may connect to different pins, depending on the
// hardware you are using.  Uncomment or configure the SD card
// pins to match your hardware.
//
// Data files to put on your SD card can be downloaded here:
//   http://www.pjrc.com/teensy/td_libs_AudioDataFiles.html
//
// This example code is in the public domain.

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

AudioPlaySdWav           playWav1;
// Use one of these 3 output types: Digital I2S, Digital S/PDIF, or Analog DAC
AudioOutputI2S           audioOutput;
//AudioOutputSPDIF       audioOutput;
//AudioOutputAnalog      audioOutput;
//On Teensy LC, use this for the Teensy Audio Shield:
//AudioOutputI2Sslave    audioOutput;

AudioConnection          patchCord1(playWav1, 0, audioOutput, 0);
AudioConnection          patchCord2(playWav1, 1, audioOutput, 1);
AudioControlSGTL5000     sgtl5000_1;

// Use these with the Teensy Audio Shield
#define SDCARD_CS_PIN    10
#define SDCARD_MOSI_PIN  7   // Teensy 4 ignores this, uses pin 11
#define SDCARD_SCK_PIN   14  // Teensy 4 ignores this, uses pin 13

// Use these with the Teensy 3.5 & 3.6 & 4.1 SD card
//#define SDCARD_CS_PIN    BUILTIN_SDCARD
//#define SDCARD_MOSI_PIN  11  // not actually used
//#define SDCARD_SCK_PIN   13  // not actually used

// Use these for the SD+Wiz820 or other adaptors
//#define SDCARD_CS_PIN    4
//#define SDCARD_MOSI_PIN  11
//#define SDCARD_SCK_PIN   13

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

  // Audio connections require memory to work.  For more
  // detailed information, see the MemoryAndCpuUsage example
  AudioMemory(8);

  // Comment these out if not using the audio adaptor board.
  // This may wait forever if the SDA & SCL pins lack
  // pullup resistors
  sgtl5000_1.enable();
  sgtl5000_1.volume(0.5);

  SPI.setMOSI(SDCARD_MOSI_PIN);
  SPI.setSCK(SDCARD_SCK_PIN);
  if (!(SD.begin(SDCARD_CS_PIN))) {
    // stop here, but print a message repetitively
    while (1) {
      Serial.println("Unable to access the SD card");
      delay(500);
    }
  }
}

void playFile(const char *filename)
{
  Serial.print("Playing file: ");
  Serial.println(filename);

  // Start playing the file.  This sketch continues to
  // run while the file plays.
  playWav1.play(filename);

  // A brief delay for the library read WAV info
  delay(25);

  // Simply wait for the file to finish playing.
  while (playWav1.isPlaying()) {
    // uncomment these lines if you audio shield
    // has the optional volume pot soldered
    //float vol = analogRead(15);
    //vol = vol / 1024;
    // sgtl5000_1.volume(vol);
  }
}


void loop() {
  
playFile("01.wav");  // filenames are always uppercase 8.3 format
  delay(1000);

playFile("02.wav");  // filenames are always uppercase 8.3 format
  delay(1000);
  
 
}

I tried repeating it in the code as seen above to get it to repeat during the main loop function, to no avail.

I've also attached the audio file just in case that's causing an issue. I've read online a lot about wav files needing to be 16 bit, 44.1kHz PCM. I'm fairly certain the files I am using are but I could be wrong.

I did also try re-formatting my SD card to FAT32 as per many online forums recommendations.

Any advice?
 
Well you have lowercase filename despite the comment saying uppercase only... No idea if that's the issue, but it leaps out of the page...
 
You didn't actually attach the audio (you may have to zip it as WAV isn't an allowed attachment type). The exact format is often a cause of issues, though as you're reporting the file plays once I'd be a bit surprised if that's the case here.

The example you've mildly modified is pretty ancient, and the uppercase 8.3 format requirement should no longer be the case. Have you gone back to the vanilla example, using the WAV files from https://www.pjrc.com/teensy/td_libs_AudioDataFiles.html ?
 
You didn't actually attach the audio (you may have to zip it as WAV isn't an allowed attachment type). The exact format is often a cause of issues, though as you're reporting the file plays once I'd be a bit surprised if that's the case here.

The example you've mildly modified is pretty ancient, and the uppercase 8.3 format requirement should no longer be the case. Have you gone back to the vanilla example, using the WAV files from https://www.pjrc.com/teensy/td_libs_AudioDataFiles.html ?

Ah my bad. I'll attach them as a zip folder when I'm home from work. I would have thought the same about the format issue.

The code is pretty much the vanilla example that came as part of the library. I believe, off the top of my head, it's in Libraries>Audio>WavFilePlayer. The modifications I made was to change the files that are in the code so I could use my own samples - reason being the demo files didn't work for me.
 
Built and tried it, it works for me, both files play repeatedly as intended. The files themselves are fine. Only differences from your setup are I've used a Teensy 4.1, but I left the code as-is and put the files on the audio adaptor SD card, so it's a like-for-like test.

As expected, the orange LED on the Teensy glows during playback - do you see that? What about during the second times through - do you get the right messages on the serial monitor, and any sign of a glow (even a brief flash)?

Struggling to understand what might be going on here...
 
Morning all,

I was away over the weekend so apologies for not getting back to you. I ran the same code again but changed it at the end to only repeat 1 of the audio files. I can now audibly hear something looping - but it's definitely not the original guitar sound


(wouldn't let me upload the zip)

Modified code is as follows:

Code:
// Simple WAV file player example
//
// Three types of output may be used, by configuring the code below.
//
//   1: Digital I2S - Normally used with the audio shield:
//         http://www.pjrc.com/store/teensy3_audio.html
//
//   2: Digital S/PDIF - Connect pin 22 to a S/PDIF transmitter
//         https://www.oshpark.com/shared_projects/KcDBKHta
//
//   3: Analog DAC - Connect the DAC pin to an amplified speaker
//         http://www.pjrc.com/teensy/gui/?info=AudioOutputAnalog
//
// To configure the output type, first uncomment one of the three
// output objects.  If not using the audio shield, comment out
// the sgtl5000_1 lines in setup(), so it does not wait forever
// trying to configure the SGTL5000 codec chip.
//
// The SD card may connect to different pins, depending on the
// hardware you are using.  Uncomment or configure the SD card
// pins to match your hardware.
//
// Data files to put on your SD card can be downloaded here:
//   http://www.pjrc.com/teensy/td_libs_AudioDataFiles.html
//
// This example code is in the public domain.

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

AudioPlaySdWav           playWav1;
// Use one of these 3 output types: Digital I2S, Digital S/PDIF, or Analog DAC
AudioOutputI2S           audioOutput;
//AudioOutputSPDIF       audioOutput;
//AudioOutputAnalog      audioOutput;
//On Teensy LC, use this for the Teensy Audio Shield:
//AudioOutputI2Sslave    audioOutput;

AudioConnection          patchCord1(playWav1, 0, audioOutput, 0);
AudioConnection          patchCord2(playWav1, 1, audioOutput, 1);
AudioControlSGTL5000     sgtl5000_1;

// Use these with the Teensy Audio Shield
#define SDCARD_CS_PIN    10
#define SDCARD_MOSI_PIN  7   // Teensy 4 ignores this, uses pin 11
#define SDCARD_SCK_PIN   14  // Teensy 4 ignores this, uses pin 13

// Use these with the Teensy 3.5 & 3.6 & 4.1 SD card
//#define SDCARD_CS_PIN    BUILTIN_SDCARD
//#define SDCARD_MOSI_PIN  11  // not actually used
//#define SDCARD_SCK_PIN   13  // not actually used

// Use these for the SD+Wiz820 or other adaptors
//#define SDCARD_CS_PIN    4
//#define SDCARD_MOSI_PIN  11
//#define SDCARD_SCK_PIN   13

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

  // Audio connections require memory to work.  For more
  // detailed information, see the MemoryAndCpuUsage example
  AudioMemory(8);

  // Comment these out if not using the audio adaptor board.
  // This may wait forever if the SDA & SCL pins lack
  // pullup resistors
  sgtl5000_1.enable();
  sgtl5000_1.volume(0.5);

  SPI.setMOSI(SDCARD_MOSI_PIN);
  SPI.setSCK(SDCARD_SCK_PIN);
  if (!(SD.begin(SDCARD_CS_PIN))) {
    // stop here, but print a message repetitively
    while (1) {
      Serial.println("Unable to access the SD card");
      delay(500);
    }
  }
}

void playFile(const char *filename)
{
  Serial.print("Playing file: ");
  Serial.println(filename);

  // Start playing the file.  This sketch continues to
  // run while the file plays.
  playWav1.play(filename);

  // A brief delay for the library read WAV info
  delay(25);

  // Simply wait for the file to finish playing.
  while (playWav1.isPlaying()) {
    // uncomment these lines if you audio shield
    // has the optional volume pot soldered
    //float vol = analogRead(15);
    //vol = vol / 1024;
    // sgtl5000_1.volume(vol);
  }
}


void loop() {
  playFile("02.WAV");  // filenames are always uppercase 8.3 format
  delay(500);
 
}
 
Can't really hear the Teensy audio output on the video. I'm curious as to what you have the headphone output plugged into ... it must not be grounded, there's a warning on the back of the PCB but still none on the PJRC web page.
 
Ah sorry! I forgot to put the volume on OBS up. The sound can only be described as like Data noise interfering with the audio path. The ground path of the Audio out is isolated from the VGND as seen from this photo:


I've had it play the sound normally before so I don't think it's anything to do with that.
 
Also attached a second video - I'm now back to square one where the audio will play once and only once.

The only difference is I went and re-exported the audio files as 44.1khz 16-bit PCM and I took out the teensy from my breadboard
 

Attachments

  • video2.zip
    1.4 MB · Views: 21
Hmm ... interesting. It sounds like the Teensy is re-booting 8 seconds after playing the sample, which suggests perhaps it's crashing. You could add the following into startup:
C++:
        if (CrashReport)
        {
            Serial.println(CrashReport);
        }
and if that comes up in the serial monitor with a problem, after the Teensy has rebooted, use the addr2line utility to find where the crash occurs.
 
I tried this* across the code and there was no crash.

It is definitely trying to do it but failing somewhere
 
Last edited:
@joebmz98: I may be misreading what you mean in p#12, but just to make sure that there is no misunderstanding, the code listed in p#11 must be placed specifically & only within your setup() function. It will cause a check to see if the previous run resulted in a crash, and generate a report specifically to the Serial Monitor if/as appropriate. It is not intended to be sprinkled throughout your code.

Mark J Culross
KD5RXT
 
code listed in p#11 must be placed specifically & only within your setup() function
And it must assure that Serial (or other chosen Stream) is online and ready for the output.
Code:
void setup() {}
//...
  Serial.begin(9600); // not required but will wait up to 2 secs for connection
        if (CrashReport)
        {
            while ( !Serial );
            Serial.println(CrashReport);
        }
//...
}
 
The non-necessity of the additional delay was questioned/discussed in an earlier thread <here>. The recently created page covering the CrashReport() details <here> does not show that same delay as required. Should it be there ?? Should the CrashReport() page be updated ??

Mark J Culross
KD5RXT
 
Should it be there ?? Should the CrashReport() page be updated ??
Indeed, to assure any output is seen indeed there needs to be a Pause until Serial is Online.

But minimal code examples can exclude that ...
... And as always, some systems run without SerMon active and that would then just hang forever ...

The 8 second restart is a clue to look for CrashReport -

Perhaps a line of info showing:
Code:
To assure seeing CrashReport output, confirm that Serial (or other chosen Stream) is online and ready for the output.

        if (CrashReport)
        {
            while ( !Serial );
            Serial.println(CrashReport);
        }
 
Last edited:
Thank you all for the suggestions. However, there is no crash during the setup() function.

We're now back to weird glitchy noise sounds that last for the duration of the sample length. I only added the crash report part to the start of the setup() function.
 
Morning all,

Since I've not had much progress on this, is there a source code yous would recommend to get me started anew?
 
Back
Top