Arduino WAV Playback Direct from SD Card 

*TMRpcm Library beta released*

The Problem: 

I wanted to be able to play a variety of sound clips using the Arduino, but could only find examples or libraries using program memory or other such methods. There are music shields you can get, but no examples for playing raw files from an SD card that I could find.

The Solution - Build a Library:
  
My library is directly based on the code shown at arduino.cc/playground/Code/PCMAudio as well as the library shown at: hlt.media.mit.edu/?p=1963, both of which use PROGMEM.
This is also the first library I have written, so there may be a few items slightly off, especially at this point in developing it.

First off, I had no idea how to make this work, but since it could work from progmem, why not from an SD card? Some sort of buffering would be needed for sure but how much, how to implement, etc. were some of the issues that had to be figured out.

Since I had no idea what I was doing exactly or how I was going to do it, I attempted to convert the files/data from the above links into char or byte format and saving it directly to a file on the SD card with no spaces, commas, etc. and playing it using the same method. It actually worked!

Once I proved the concept, then it was a matter of finding the best/simplest way to format the data for playback. Checking into the format of WAV files, I realized that they can be saved into a format that I can read directly using an Arduino with an SD card. There is a small header at the beginning of the file, but then it is basically raw data. The data can be saved in an 8-bit format (0-255), which can be read into the Arduino, and written directly to the registers with no modification.

The next problem is that I have never written a library, and Arduino programming is somewhat new to me, although I have dabbled in various programming languages for "fun" over the years. Following the tutorials found online, I was able to turn my sketch into a library.

For me, the easiest method was to use iTunes to convert the wav files, but any PCM file in the correct format will work:


Click Edit > Preferences > Import Settings

Then change the dropdown to WAV Encoder and Setting: Custom > 16.000kHz, 8-bit, Mono

Now you can just right click any file in iTunes, and select Create WAV Version

Then just copy the file(s) to an SD card attached to an Arduino, and check out the library below, with included example sketch.


How it works:

Both the above example and library this was based on use PROGMEM to store the variables which drive the PCM signal. Since we are reading WAV files directly from SD, we can save as many as the SD card will allow, with general disregard for file size.

The library uses timers and interrupts to create a signal that runs at 16000 cycles/second. The signal is controlled by the variables we read in from a file. The file is read into a small buffer, and playback is started. While interrupts control the playback, the second buffer starts filling up with data, using the spare cpu cycles between interrupts, and resumes playback once the first buffer is 'emptied'. Then the first buffer starts loading data again, while the second is 'emptied' and so on. This allows a continuous stream of data to be available for playback. Testing seems to indicate a minmum requirement for about 400 bytes of total memory for a steady stream and/or reasonable sound quality. (soundBuff = 200)

How to load data: In order to load the needed data onto an SD card, the wave file must be in the correct format, or converted using iTunes and the instructions above. Basically, this can be done using any computer with an SD slot, using any method that outputs wav files in the correct format.

Conclusion: This is totally possible, and it now works! The sound quality is low, but for simple sound clips, this is reasonable.

Example:

File(s) are placed onto the root of the SD card, then the following sketch is run:

 _________________________________________________________________

#include <SD.h>                      // need to include the SD library
#define SD_ChipSelectPin 53  //example uses hardware SS pin 53 on Mega2560
#include <TMRpcm.h>           //  also need to include this library...

TMRpcm tmrpcm;   // create an object (tmrpcm) for use in this sketch

void setup(){
 

tmrpcm.speakerPin = 10;
tmrpcm.soundBuff = 500; //uses 1KB memory. Min setting is about 200 (400 bytes)
 
pinMode(10,OUTPUT); //speaker pin
Serial.begin(115200);
  if (!SD.begin(SD_ChipSelectPin)) {  //see if card present and initialized:
    Serial.println("SD fail");  return;   // don't do anything more if not
  }else{   Serial.println("SD ok");   }

  tmrpcm.play("music"); //file "temple" plays when arduino powers up, or reset
}

void loop(){
  
  if (Serial.available() ){
    if (Serial.read() == 'C'){ 
      tmrpcm.play("music"); //sending a C to serial port starts playback
    }
  }
}
_________________________________________________________________

Modify the filenames for tmrpcm.play() to match your file.

Function Usage:

play("myFile");
stopPlayback();

Files/Source:

Developed using Arduino IDE 1.0.1
This is more or less just proof-of-concept currently, and will only work on Arduino Megas currently.


Source Code (OLD):
   TMRpcm.h
   Example: music.ino

Original Library Package (OLD):
   TMRpcm.zip

Current version on GitHub (download)
See the Wiki for updated usage and info