Audio Play SD Card WAV File

Dong Clerk

New member
Hi, I'm new to Teensy and this is my first project. I got a Teensy 4.1 and one of the thing I wanted to make is it to play music through a speaker. After spending hours looking online how I could achieve my objective I'm starting to lose hope. I do not know if it is achievable with only the pieces I'm using (Teensy 4.1, SD card, a very simple speaker). Ergo I am asking for help.

IMG_1516.jpg



On Arduino, I have used the File>Examples>Audio>WavFilePlayer example as my main template. I removed some code that I think did not matter for what I am doing.
______________________________________________________________________________________________________________________________________________________
______________________________________________________________________________________________________________________________________________________

#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 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

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

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

//Fonction----------------------------------------------------------------------------------

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("MUSIC.WAV"); // filenames are always uppercase 8.3 format
delay(500);
}
______________________________________________________________________________________________________________________________________________________
______________________________________________________________________________________________________________________________________________________


My most urgent questions are: Where should I connect the speaker on my Teensy 4.1? How do I call the music in the SD to the speaker and what important commands am I missing?

Thank you
 
Last edited:
Unfortunately you won't be able to do what you want with just what you've bought.

The 3.1, 3.2, 3.5, and 3.6 Teensies (for which the example was written) have 1 pin (Teensy 3.1 and 3.2) or two pins (Teensy 3.5 or 3.6) that are analog DACs. An Analog DAC is a pin that when you do an AnalogWrite to the pin, it modifies the voltage on the pin to be between 0 and the reference voltage (typically 3.3v). The sound produced by a DAC is decent, but other sound systems (including the audio shield on the Teensy) produce much better sound. Unfortunately the microprocessor used in the Teensy 4.0/4.1/MicroMod no longer provides a DAC.

For most other pins, if you do AnalogWrite to the pin, it uses what is typically called PWM (pulse width modulation) that turns the pin on/off very fast, so that the average voltage will be what is specified (note some pins don't support PWM). This PWM is useful for making lights dim. It can be used for playing sounds, though it may not be as good as a DAC might be.

You can then connect this DAC pin and ground to an amplifier, which then connects to a speaker. I don't know what pin AudioOutputAnalog audioOutput uses on the Teensy 4.0, but if it there is a way to set the pin to a pin that does PWM, you can use the new Audio Output function (AudioOutputPWM) that uses a PWM pin for output. You would need to use Teensydunio 1.57 (the current release) to use this. I haven't tried function myself.

If you aren't connecting up a display that uses SPI (most displays do use SPI), you can use pin 10 and 12 to output sound via MQS (medium quality sound). Unfortunately MQS uses pin 10 and 12, while SPI requires using pin 12 for the MISO function. While I have an example that just uses Tonesweep with MQS, I haven't hooked it up to the SD wav player.

The main option that people do is to use an extra card that offloads the audio processing. There are at least 3 different cards that you can use:
  • The main approach is to use the official Teensy audio adapter. This is a board made to be mounted on top of or under the Teensy (you will need to solder pins and headers for this),
  • PJRC has a much cheaper board that uses a PT8211 chip. Even though I've bought some of these boards, I haven't actually soldered them up to use.
  • The third option is to get an external I2S device that you hook up to the appropriate pins, and hook speaker(s) to the device. There are typically 2 variants. One variant provides stereo, but you will need amplifiers on the speakers. The other device is a mono device, but it provides the amplifier. Here is one I bought: https://smile.amazon.com/gp/product/B07PS653CD/ref=ppx_yo_dt_b_asin_title_o00_s00?ie=UTF8&psc=1

As I mentioned above, that once you produce sound in some fashion, you will need to put an amplifier between the Teensy and the speaker. Otherwise, you likely would only be able to hear a faint echo. You can buy them in various places, but you will need one if you want to continue. Here is one on ebay that looks like it might do the trick (though it looks like you will get 10 parts): https://www.ebay.com/itm/334461295386?hash=item4ddf725b1a.

Another alternative, that may take more work on your part to set up is to make the Teensy into a USB audio device. You build the Teensy as a Serial + MIDO + Audio (or just Audio device) instead of the normal USB serial device. Once you attach the Teensy, you may need to do something on your system to enable using the device (under Linux I needed to set the Teensy as the default input device, and then issue the 'play -d' command). The advantage is that you won't need any extra parts (assuming your computer has speakers that are turned on).
 
Last edited:
Here is an example of ToneSweep for external I2S:

Code:
/*
  Demo of the audio sweep function.
  The user specifies the amplitude,
  start and end frequencies (which can sweep up or down)
  and the length of time of the sweep.

  Modified to eliminate the audio shield, and use Max98357A mono I2S chip.
  https://smile.amazon.com/gp/product/B07PS653CD/ref=ppx_yo_dt_b_asin_title_o00_s00?ie=UTF8&psc=1

  Pins:		Teensy 4.0	Teensy 3.x

  LRCLK:	Pin 20/A6	Pin 23/A9
  BCLK:		Pin 21/A7	Pin 9
  DIN:		Pin 7		Pin 22/A8
  Gain:		see below	see below
  Shutdown:	N/C		N/C
  Ground:	Ground		Ground
  VIN:		5v		5v

  Other I2S pins not used by the Max98357A device:

  MCLK		Pin 23		Pin 11
  DOUT		Pin 8		Pin 13

  Gain setting:

  15dB	if a 100K resistor is connected between GAIN and GND
  12dB	if GAIN is connected directly to GND
   9dB	if GAIN is not connected to anything (this is the default)
   6dB	if GAIN is conneted directly to Vin
   3dB	if a 100K resistor is connected between GAIN and Vin.

  SD setting (documentation from the Adafruit board)

  This pin is used for shutdown mode but is also used for setting which channel
  is output. It's a little confusing but essentially:

  * If SD is connected to ground directly (voltage is under 0.16V) then the amp
    is shut down

  * If the voltage on SD is between 0.16V and 0.77V then the output is (Left +
    Right)/2, that is the stereo average.

  * If the voltage on SD is between 0.77V and 1.4V then the output is just the
    Right channel

  * If the voltage on SD is higher than 1.4V then the output is the Left
    channel.

    This is compounded by an internal 100K pulldown resistor on SD so you need
    to use a pullup resistor on SD to balance out the 100K internal pulldown.

  Or alternatively, use the HiLetgo PCM5102 I2S IIS Lossless Digital Audio DAC
  Decoder which provides stereo output:
  https://smile.amazon.com/gp/product/B07Q9K5MT8/ref=ppx_yo_dt_b_asin_title_o00_s00?ie=UTF8&psc=1  */

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

// GUItool: begin automatically generated code (edited by meissner afterwards).
AudioSynthToneSweep	tonesweep;		//xy=99,198
AudioMixer4		mixer2;			//xy=280,253
AudioMixer4		mixer1;			//xy=280,175
AudioOutputI2S		i2s;			//xy=452,189

AudioConnection		patchCord1(tonesweep, 0, mixer1, 0);
AudioConnection		patchCord2(tonesweep, 0, mixer2, 0);
AudioConnection		patchCord3(mixer2,    0, i2s,    1);
AudioConnection		patchCord4(mixer1,    0, i2s,    0);
// GUItool: end automatically generated code

const float	t_ampx	= 0.8;
const int	t_lox	= 10;
const int	t_hix	= 22000;
const float	t_timex	= 10;		// Length of time for the sweep in seconds

// Do a sweep in both directions, enabling or disabling the left/right speakers
void do_sweep (int i)
{
  int do_left  = (i & 1) != 0;
  int do_right = (i & 2) != 0;
  float gain   = (do_left && do_right) ? 0.5f : 1.0f;

  Serial.printf ("Sweep up,   left = %c, right = %c\n",
		 (do_left)  ? 'Y' : 'N',
		 (do_right) ? 'Y' : 'N');

  mixer1.gain (0, do_left  ? gain : 0.0f);
  mixer2.gain (0, do_right ? gain : 0.0f);

  if (!tonesweep.play (t_ampx, t_lox, t_hix, t_timex)) {
    Serial.println ("ToneSweep - play failed");
    while (1)
      ;
  }

  // wait for the sweep to end
  while (tonesweep.isPlaying ())
    ;

  // and now reverse the sweep
  Serial.printf ("Sweep down, left = %c, right = %c\n",
		 (do_left)  ? 'Y' : 'N',
		 (do_right) ? 'Y' : 'N');

  if (!tonesweep.play (t_ampx, t_hix, t_lox, t_timex)) {
    Serial.println("ToneSweep - play failed");
    while (1)
      ;
  }

  // wait for the sweep to end
  while (tonesweep.isPlaying ())
    ;

  Serial.println ("Sweep done");
}

void setup(void)
{
  // Wait for at least 3 seconds for the USB serial connection
  Serial.begin (9600);
  while (!Serial && millis () < 3000)
    ;

  AudioMemory (8);
  Serial.println ("setup done");

  for (int i = 1; i <= 3; i++)
    do_sweep (i);

  Serial.println ("Done");
}

void loop (void)
{
}

Obviously for playing songs from the SD card, you would need to replace the bits that do the tone sweep.
 
Back
Top