Edited from Arduino Playground - PCMAudio
First, you should convert sound files to PCM 8 bit 8Khz Wav files, I use Switch Sound File Converter for this. Then fill playlist string variable with file names separated with space(so files must not include space).
Also the code uses Timer0 so you cannot use delay/milis while playing sounds, after playing is finished you can use delay/milis as usual.
I hope someone could give an idea whether it can be accomplished with only 1 timer.
#include <Fat16.h>
SdCard card;
Fat16 file;
int speakerPin = 6;
volatile boolean playing = false;
String playlist = "";//non volatile since it is not used by loop while interrupts are on
boolean firstRampUp;//non volatile since it is not used by loop while interrupts are on
uint32_t sample;//non volatile since it is not used by loop while interrupts are on
uint32_t sounddata_length;//non volatile since it is not used by loop while interrupts are on
// This is called at 8000 Hz to load the next sample.
ISR(TIMER1_COMPA_vect)
{
if (playing) {
if (firstRampUp) {
if (OCR0A >= 128) {
firstRampUp = false;
OCR0A = file.read();
sample++;
} else {
OCR0A++;
}
} else {
if (sample >= sounddata_length) {
if (OCR0A == 0) {
stopPlayback();
} else {
OCR0A--;
}
} else {
OCR0A = file.read();
}
sample++;
}
}
}
void startPlayback()
{
firstRampUp = true;
sample = 0;
file.open(nextsound(), O_READ);
file.seekSet(46);//skip header bytes
sounddata_length = file.fileSize() - 4000;//skip garbage bytes at the end, is it a converter issue ?
bitSet(TCCR0A, COM0A1);
bitClear(TCCR0B, CS01);
cli();
bitSet(TCCR1B, WGM12);
bitClear(TCCR1A, WGM10);
bitClear(TCCR1B, CS11);
OCR1A = F_CPU / 8000;
bitSet(TIMSK1, OCIE1A);
sei();
playing = true;
}
void fixInternals()//set back to arduino default settings of interrupts, timers etc...
{
bitClear(TCCR0A, COM0A1);
bitSet(TCCR0B, CS01);
bitClear(TCCR1B, WGM12);
bitSet(TCCR1A, WGM10);
bitSet(TCCR1B, CS11);
OCR1A = 0;
bitClear(TIMSK1, OCIE1A);
}
void stopPlayback()
{
fixInternals();
file.close();
playing = false;
}
const char* nextsound()
{
String next = "";
int space = playlist.indexOf(" ");
if (space != -1) {
next = playlist.substring(0, space);
playlist = playlist.substring(space + 1);
} else {
next = playlist;
playlist = "";
}
next = next + ".WAV";
int l = next.length() + 1;
char nextcstr[l];
next.toCharArray(nextcstr, l);
return nextcstr;
}
void setup()
{
pinMode(speakerPin, OUTPUT);
card.init();
Fat16::init(&card);
}
void loop()
{
if (playlist == "") {
playlist = "MUSIC1 MUSIC2 MUSIC3";
delay(10000);
}
startPlayback();
while (playing) {;}
}
/*
"byte"-"bit"-"default value"-"pcm value"
TCCR1B CS10 -> 1 1
TCCR0B CS00 -> 1 1
TCCR0A WGM01 -> 1 1
TCCR0A WGM00 -> 1 1
TCCR0A COM0A0 -> 0 0
TCCR0A COM0B1 -> 0 0
TCCR0A COM0B0 -> 0 0
TCCR0B WGM02 -> 0 0
TCCR0B CS02 -> 0 0
TCCR1B CS12 -> 0 0
TCCR1A WGM11 -> 0 0
TCCR1B WGM13 -> 0 0
TCCR0A COM0A1 -> 0 1
TCCR1B WGM12 -> 0 1
TIMSK1 OCIE1A -> 0 1
TCCR0B CS01 -> 1 0
TCCR1B CS11 -> 1 0
TCCR1A WGM10 -> 1 0
OCR1A -> 0 varies
*/