initial commit
This commit is contained in:
@@ -0,0 +1,131 @@
|
||||
/*
|
||||
* Text-to-speech example to speak the first n digits of pi.
|
||||
* The number is stored in flash, each digit is spoken one at a time.
|
||||
*/
|
||||
#include <WaveHC.h>
|
||||
#include <WaveUtil.h>
|
||||
|
||||
// put pi in flash memory
|
||||
const char pi[] PROGMEM = "3.1415926535897932384626433832795028841971693993751058209749";
|
||||
|
||||
SdReader card; // This object holds the information for the card
|
||||
FatVolume vol; // This holds the information for the partition on the card
|
||||
FatReader root; // This holds the information for the volumes root directory
|
||||
FatReader file; // This object represent the WAV file for a pi digit or period
|
||||
WaveHC wave; // This is the only wave (audio) object, since we will only play one at a time
|
||||
/*
|
||||
* Define macro to put error messages in flash memory
|
||||
*/
|
||||
#define error(msg) error_P(PSTR(msg))
|
||||
|
||||
//////////////////////////////////// SETUP
|
||||
|
||||
void setup() {
|
||||
// set up Serial library at 9600 bps
|
||||
Serial.begin(9600);
|
||||
|
||||
PgmPrintln("Pi speaker");
|
||||
|
||||
if (!card.init()) {
|
||||
error("Card init. failed!");
|
||||
}
|
||||
if (!vol.init(card)) {
|
||||
error("No partition!");
|
||||
}
|
||||
if (!root.openRoot(vol)) {
|
||||
error("Couldn't open dir");
|
||||
}
|
||||
|
||||
PgmPrintln("Files found:");
|
||||
root.ls();
|
||||
}
|
||||
|
||||
/////////////////////////////////// LOOP
|
||||
|
||||
unsigned digit = 0;
|
||||
|
||||
void loop() {
|
||||
// get next character from flash memory
|
||||
char c = pgm_read_byte(&pi[digit++]);
|
||||
|
||||
if (c == 0) {
|
||||
digit = 0;
|
||||
Serial.println();
|
||||
return;
|
||||
}
|
||||
Serial.write(c);
|
||||
|
||||
speaknum(c);
|
||||
|
||||
delay(10);
|
||||
}
|
||||
|
||||
/////////////////////////////////// HELPERS
|
||||
|
||||
char filename[13];
|
||||
void speaknum(char c) {
|
||||
uint8_t i=0;
|
||||
|
||||
// copy flash string for 'period' to filename
|
||||
strcpy_P(filename, PSTR("P.WAV"));
|
||||
|
||||
if ('0' <= c && c <= '9') {
|
||||
// digit - change 'P' to digit
|
||||
filename[0] = c;
|
||||
i = 1;
|
||||
}
|
||||
else if (c != '.') {
|
||||
// error if not period
|
||||
return;
|
||||
}
|
||||
playcomplete(filename);
|
||||
}
|
||||
/*
|
||||
* print error message and halt
|
||||
*/
|
||||
void error_P(const char *str) {
|
||||
PgmPrint("Error: ");
|
||||
SerialPrint_P(str);
|
||||
sdErrorCheck();
|
||||
while(1);
|
||||
}
|
||||
/*
|
||||
* print error message and halt if SD I/O error
|
||||
*/
|
||||
void sdErrorCheck(void) {
|
||||
if (!card.errorCode()) return;
|
||||
PgmPrint("\r\nSD I/O error: ");
|
||||
Serial.print(card.errorCode(), HEX);
|
||||
PgmPrint(", ");
|
||||
Serial.println(card.errorData(), HEX);
|
||||
while(1);
|
||||
}
|
||||
/*
|
||||
* Play a file and wait for it to complete
|
||||
*/
|
||||
void playcomplete(char *name) {
|
||||
playfile(name);
|
||||
while (wave.isplaying);
|
||||
|
||||
// see if an error occurred while playing
|
||||
sdErrorCheck();
|
||||
}
|
||||
/*
|
||||
* Open and start playing a WAV file
|
||||
*/
|
||||
void playfile(char *name) {
|
||||
if (wave.isplaying) {// already playing something, so stop it!
|
||||
wave.stop(); // stop it
|
||||
}
|
||||
if (!file.open(root, name)) {
|
||||
PgmPrint("Couldn't open file ");
|
||||
Serial.print(name);
|
||||
return;
|
||||
}
|
||||
if (!wave.create(file)) {
|
||||
PgmPrintln("Not a valid WAV");
|
||||
return;
|
||||
}
|
||||
// ok time to play!
|
||||
wave.play();
|
||||
}
|
||||
@@ -0,0 +1,131 @@
|
||||
/*
|
||||
* Adafruit SampleRateMod.pde example modified to use WaveHC.
|
||||
*
|
||||
* Play files with sample rate controlled by voltage on analog pin zero.
|
||||
*/
|
||||
#include <WaveHC.h>
|
||||
#include <WaveUtil.h>
|
||||
|
||||
SdReader card; // This object holds the information for the card
|
||||
FatVolume vol; // This holds the information for the partition on the card
|
||||
FatReader root; // This holds the information for the volumes root directory
|
||||
FatReader file; // This object represent the WAV file
|
||||
WaveHC wave; // This is the only wave (audio) object, since we will only play one at a time
|
||||
|
||||
/*
|
||||
* Define macro to put error messages in flash memory
|
||||
*/
|
||||
#define error(msg) error_P(PSTR(msg))
|
||||
|
||||
//////////////////////////////////// SETUP
|
||||
void setup() {
|
||||
Serial.begin(9600);
|
||||
Serial.println("Wave test!");
|
||||
|
||||
// try card.init(true) if errors occur on V1.0 Wave Shield
|
||||
if (!card.init()) {
|
||||
error("Card init. failed!");
|
||||
}
|
||||
// enable optimize read - some cards may timeout
|
||||
card.partialBlockRead(true);
|
||||
|
||||
if (!vol.init(card)) {
|
||||
error("No partition!");
|
||||
}
|
||||
if (!root.openRoot(vol)) {
|
||||
error("Couldn't open root");
|
||||
}
|
||||
putstring_nl("Files found:");
|
||||
root.ls();
|
||||
}
|
||||
|
||||
// forward declarition
|
||||
void playcomplete(FatReader &file);
|
||||
|
||||
//////////////////////////////////// LOOP
|
||||
void loop() {
|
||||
uint8_t i, r;
|
||||
char c, name[15];
|
||||
dir_t dir;
|
||||
|
||||
root.rewind();
|
||||
// scroll through the files in the directory
|
||||
while (root.readDir(dir) > 0) {
|
||||
// only play .WAV files
|
||||
if (strncmp_P((char *)&dir.name[8],PSTR("WAV"), 3)) continue;
|
||||
|
||||
if (!file.open(vol, dir)){
|
||||
putstring("Can't open ");
|
||||
printEntryName(dir);
|
||||
Serial.println();
|
||||
continue;
|
||||
}
|
||||
putstring("\n\rPlaying ");
|
||||
printEntryName(dir);
|
||||
Serial.println();
|
||||
playcomplete(file);
|
||||
file.close();
|
||||
}
|
||||
}
|
||||
/////////////////////////////////// HELPERS
|
||||
/*
|
||||
* print error message and halt
|
||||
*/
|
||||
void error_P(const char *str) {
|
||||
PgmPrint("Error: ");
|
||||
SerialPrint_P(str);
|
||||
sdErrorCheck();
|
||||
while(1);
|
||||
}
|
||||
/*
|
||||
* print error message and halt if SD I/O error, great for debugging!
|
||||
*/
|
||||
void sdErrorCheck(void) {
|
||||
if (!card.errorCode()) return;
|
||||
PgmPrint("\r\nSD I/O error: ");
|
||||
Serial.print(card.errorCode(), HEX);
|
||||
PgmPrint(", ");
|
||||
Serial.println(card.errorData(), HEX);
|
||||
while(1);
|
||||
}
|
||||
int16_t lastpotval = 0;
|
||||
#define HYSTERESIS 3
|
||||
/*
|
||||
* play file with sample rate changes
|
||||
*/
|
||||
void playcomplete(FatReader &file) {
|
||||
int16_t potval;
|
||||
uint32_t newsamplerate;
|
||||
|
||||
if (!wave.create(file)) {
|
||||
putstring_nl(" Not a valid WAV"); return;
|
||||
}
|
||||
// ok time to play!
|
||||
wave.play();
|
||||
|
||||
while (wave.isplaying) {
|
||||
potval = analogRead(0);
|
||||
if ( ((potval - lastpotval) > HYSTERESIS) || ((lastpotval - potval) > HYSTERESIS)) {
|
||||
putstring("pot = ");
|
||||
Serial.println(potval, DEC);
|
||||
putstring("tickspersam = ");
|
||||
Serial.print(wave.dwSamplesPerSec, DEC);
|
||||
putstring(" -> ");
|
||||
newsamplerate = wave.dwSamplesPerSec;
|
||||
newsamplerate *= potval;
|
||||
newsamplerate /= 512; // we want to 'split' between sped up and slowed down.
|
||||
if (newsamplerate > 24000) {
|
||||
newsamplerate = 24000;
|
||||
}
|
||||
if (newsamplerate < 1000) {
|
||||
newsamplerate = 1000;
|
||||
}
|
||||
wave.setSampleRate(newsamplerate);
|
||||
|
||||
Serial.println(newsamplerate, DEC);
|
||||
lastpotval = potval;
|
||||
}
|
||||
delay(100);
|
||||
}
|
||||
sdErrorCheck();
|
||||
}
|
||||
@@ -0,0 +1,146 @@
|
||||
// this sketch wiil do a read stress test on a SD card.
|
||||
// run time is about 25 seconds
|
||||
|
||||
#include <avr/pgmspace.h>
|
||||
#include <FatReader.h>
|
||||
#include <WaveUtil.h>
|
||||
SdReader card;
|
||||
|
||||
uint8_t cidDmp(void) {
|
||||
cid_t cid;
|
||||
if (!card.readCID(cid)) {
|
||||
putstring("readCID failed");
|
||||
sdError();
|
||||
return 0;
|
||||
}
|
||||
putstring("\nManufacturer ID: ");
|
||||
Serial.println(cid.mid, HEX);
|
||||
putstring("OEM ID: ");
|
||||
Serial.write(cid.oid[0]);
|
||||
Serial.write(cid.oid[1]);
|
||||
Serial.println();
|
||||
putstring("Product: ");
|
||||
for (uint8_t i = 0; i < 5; i++) {
|
||||
Serial.write(cid.pnm[i]);
|
||||
}
|
||||
putstring("\nVersion: ");
|
||||
Serial.print(cid.prv_n, DEC);
|
||||
Serial.write('.');
|
||||
Serial.println(cid.prv_m, DEC);
|
||||
putstring("Serial number: ");
|
||||
Serial.println(cid.psn);
|
||||
putstring("Manufacturing date: ");
|
||||
Serial.print(cid.mdt_month, DEC);
|
||||
Serial.write('/');
|
||||
Serial.println(2000 + cid.mdt_year_low + (cid.mdt_year_high << 4));
|
||||
Serial.println();
|
||||
return 1;
|
||||
}
|
||||
// print partition table
|
||||
uint8_t partDmp(void) {
|
||||
part_t pt;
|
||||
putstring_nl("partion,boot,type,start,length");
|
||||
for (uint8_t ip = 1; ip < 5; ip++) {
|
||||
if (!card.readData(0, PART_OFFSET + 16*(ip-1), (uint8_t *)&pt, 16)) {
|
||||
putstring("read partition table failed");
|
||||
sdError();
|
||||
return 0;
|
||||
}
|
||||
Serial.print(ip, DEC);
|
||||
Serial.write(',');
|
||||
Serial.print(pt.boot,HEX);
|
||||
Serial.write(',');
|
||||
Serial.print(pt.type, HEX);
|
||||
Serial.write(',');
|
||||
Serial.print(pt.firstSector);
|
||||
Serial.write(',');
|
||||
Serial.println(pt.totalSectors);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void sdError(void) {
|
||||
putstring_nl("SD error");
|
||||
putstring("errorCode: ");
|
||||
Serial.println(card.errorCode(), HEX);
|
||||
putstring("errorData: ");
|
||||
Serial.println(card.errorData(), HEX);
|
||||
return;
|
||||
}
|
||||
void setup(void) {
|
||||
Serial.begin(9600);
|
||||
}
|
||||
|
||||
void loop(void) {
|
||||
while (Serial.read() >= 0) {}
|
||||
putstring_nl("\ntype any character to start");
|
||||
while (Serial.read() < 0) {}
|
||||
uint32_t t0 = millis();
|
||||
uint8_t r = card.init(0);
|
||||
uint32_t d = millis()- t0;
|
||||
if (!r) {
|
||||
putstring_nl("\ncard.init failed");
|
||||
sdError();
|
||||
return;
|
||||
}
|
||||
putstring("\ninit time: ");
|
||||
Serial.println(d);
|
||||
putstring("\nCard type: ");
|
||||
switch(card.type()) {
|
||||
case SD_CARD_TYPE_SD1:
|
||||
putstring_nl("SD1");
|
||||
break;
|
||||
case SD_CARD_TYPE_SD2:
|
||||
putstring_nl("SD2");
|
||||
break;
|
||||
case SD_CARD_TYPE_SDHC:
|
||||
putstring_nl("SDHC");
|
||||
break;
|
||||
default:
|
||||
putstring_nl("Unknown");
|
||||
}
|
||||
|
||||
if(!cidDmp()) return;
|
||||
uint32_t size = card.cardSize();
|
||||
if (size == 0) {
|
||||
putstring("cardSize failed");
|
||||
sdError();
|
||||
return;
|
||||
}
|
||||
putstring("card size: ");
|
||||
Serial.print(size);
|
||||
putstring(" (512 byte blocks)\n");
|
||||
if(!partDmp()) return;
|
||||
uint16_t nTest = 20000;
|
||||
uint16_t nRead = 0;
|
||||
uint8_t buf[2];
|
||||
d = size/nTest;
|
||||
uint32_t b;
|
||||
putstring_nl("Read test starting. Please Wait.");
|
||||
uint32_t m0 = millis();
|
||||
for (nRead = 0; nRead < nTest; nRead++){
|
||||
b = nRead*d;
|
||||
if (!(r = card.readData(b, 510, buf, 2))) break;
|
||||
if (nRead == 0 && (buf[0] != 0X55 || buf[1] != 0XAA)) {
|
||||
putstring("Invalid block zero signature: ");
|
||||
Serial.print(buf[0], HEX);
|
||||
Serial.write(',');
|
||||
Serial.println(buf[1], HEX);
|
||||
}
|
||||
}
|
||||
uint32_t m1 = millis();
|
||||
putstring("\nRead ");
|
||||
Serial.print(nRead);
|
||||
putstring_nl(" blocks");
|
||||
putstring("mills: ");
|
||||
Serial.println(m1 - m0);
|
||||
if(r) {
|
||||
putstring_nl("\nDone");
|
||||
}
|
||||
else {
|
||||
putstring_nl("\nRead Failure");
|
||||
putstring("lbn: ");
|
||||
Serial.println(b);
|
||||
sdError();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,117 @@
|
||||
/*
|
||||
* DVOLUME must be set nonzero in WaveHC.h to use this example.
|
||||
*
|
||||
* Adafruit SoftVolumeChange.pde modified to use WaveHC library.
|
||||
*
|
||||
* Play files with software volume control.
|
||||
|
||||
*/
|
||||
#include <WaveHC.h>
|
||||
#include <WaveUtil.h>
|
||||
|
||||
SdReader card; // This object holds the information for the card
|
||||
FatVolume vol; // This holds the information for the partition on the card
|
||||
FatReader root; // This holds the information for the volumes root directory
|
||||
FatReader file; // This object represent the WAV file
|
||||
WaveHC wave; // This is the only wave (audio) object, since we will only play one at a time
|
||||
|
||||
/*
|
||||
* Define macro to put error messages in flash memory
|
||||
*/
|
||||
#define error(msg) error_P(PSTR(msg))
|
||||
|
||||
//////////////////////////////////// SETUP
|
||||
void setup() {
|
||||
Serial.begin(9600);
|
||||
Serial.println("Wave test!");
|
||||
|
||||
// try card.init(true) if errors occur on V1.0 Wave Shield
|
||||
if (!card.init()) {
|
||||
error("Card init. failed!");
|
||||
}
|
||||
// enable optimize read - some cards may timeout
|
||||
card.partialBlockRead(true);
|
||||
|
||||
if (!vol.init(card)) {
|
||||
error("No partition!");
|
||||
}
|
||||
if (!root.openRoot(vol)) {
|
||||
error("Couldn't open root"); return;
|
||||
}
|
||||
putstring_nl("Files found:");
|
||||
root.ls();
|
||||
}
|
||||
|
||||
// forward declarition
|
||||
void playcomplete(FatReader &file);
|
||||
|
||||
//////////////////////////////////// LOOP
|
||||
void loop() {
|
||||
uint8_t i, r;
|
||||
char c, name[15];
|
||||
dir_t dir;
|
||||
|
||||
root.rewind();
|
||||
// scroll through the files in the directory
|
||||
while (root.readDir(dir) > 0) {
|
||||
// only play .WAV files
|
||||
if (strncmp_P((char *)&dir.name[8],PSTR("WAV"), 3)) continue;
|
||||
|
||||
if (!file.open(vol, dir)){
|
||||
putstring("Can't open ");
|
||||
printEntryName(dir);
|
||||
Serial.println();
|
||||
continue;
|
||||
}
|
||||
putstring("\n\rPlaying ");
|
||||
printEntryName(dir);
|
||||
Serial.println();
|
||||
playcomplete(file);
|
||||
file.close();
|
||||
}
|
||||
}
|
||||
|
||||
/////////////////////////////////// HELPERS
|
||||
/*
|
||||
* print error message and halt
|
||||
*/
|
||||
void error_P(const char *str) {
|
||||
PgmPrint("Error: ");
|
||||
SerialPrint_P(str);
|
||||
sdErrorCheck();
|
||||
while(1);
|
||||
}
|
||||
/*
|
||||
* print error message and halt if SD I/O error, great for debugging!
|
||||
*/
|
||||
void sdErrorCheck(void) {
|
||||
if (!card.errorCode()) return;
|
||||
PgmPrint("\r\nSD I/O error: ");
|
||||
Serial.print(card.errorCode(), HEX);
|
||||
PgmPrint(", ");
|
||||
Serial.println(card.errorData(), HEX);
|
||||
while(1);
|
||||
}
|
||||
/*
|
||||
* Play files with software volume control
|
||||
*/
|
||||
void playcomplete(FatReader &file) {
|
||||
if (!wave.create(file)) {
|
||||
putstring_nl(" Not a valid WAV"); return;
|
||||
}
|
||||
// ok time to play!
|
||||
wave.play();
|
||||
while (wave.isplaying) {
|
||||
putstring("Vol: ");
|
||||
|
||||
// DVOLUME must be nonzero in WaveHC.h to use volume.
|
||||
Serial.println(wave.volume, DEC);
|
||||
|
||||
delay(2000);
|
||||
wave.volume++;
|
||||
if ( wave.volume == 12) {
|
||||
wave.volume = 0;
|
||||
}
|
||||
}
|
||||
sdErrorCheck();
|
||||
}
|
||||
@@ -0,0 +1,148 @@
|
||||
/*
|
||||
* This example plays every .WAV file it finds on the SD card in a loop
|
||||
*/
|
||||
#include <WaveHC.h>
|
||||
#include <WaveUtil.h>
|
||||
|
||||
SdReader card; // This object holds the information for the card
|
||||
FatVolume vol; // This holds the information for the partition on the card
|
||||
FatReader root; // This holds the information for the volumes root directory
|
||||
WaveHC wave; // This is the only wave (audio) object, since we will only play one at a time
|
||||
|
||||
uint8_t dirLevel; // indent level for file/dir names (for prettyprinting)
|
||||
dir_t dirBuf; // buffer for directory reads
|
||||
|
||||
|
||||
/*
|
||||
* Define macro to put error messages in flash memory
|
||||
*/
|
||||
#define error(msg) error_P(PSTR(msg))
|
||||
|
||||
// Function definitions (we define them here, but the code is below)
|
||||
void play(FatReader &dir);
|
||||
|
||||
//////////////////////////////////// SETUP
|
||||
void setup() {
|
||||
Serial.begin(9600); // set up Serial library at 9600 bps for debugging
|
||||
|
||||
putstring_nl("\nWave test!"); // say we woke up!
|
||||
|
||||
putstring("Free RAM: "); // This can help with debugging, running out of RAM is bad
|
||||
Serial.println(FreeRam());
|
||||
|
||||
// if (!card.init(true)) { //play with 4 MHz spi if 8MHz isn't working for you
|
||||
if (!card.init()) { //play with 8 MHz spi (default faster!)
|
||||
error("Card init. failed!"); // Something went wrong, lets print out why
|
||||
}
|
||||
|
||||
// enable optimize read - some cards may timeout. Disable if you're having problems
|
||||
card.partialBlockRead(true);
|
||||
|
||||
// Now we will look for a FAT partition!
|
||||
uint8_t part;
|
||||
for (part = 0; part < 5; part++) { // we have up to 5 slots to look in
|
||||
if (vol.init(card, part))
|
||||
break; // we found one, lets bail
|
||||
}
|
||||
if (part == 5) { // if we ended up not finding one :(
|
||||
error("No valid FAT partition!"); // Something went wrong, lets print out why
|
||||
}
|
||||
|
||||
// Lets tell the user about what we found
|
||||
putstring("Using partition ");
|
||||
Serial.print(part, DEC);
|
||||
putstring(", type is FAT");
|
||||
Serial.println(vol.fatType(), DEC); // FAT16 or FAT32?
|
||||
|
||||
// Try to open the root directory
|
||||
if (!root.openRoot(vol)) {
|
||||
error("Can't open root dir!"); // Something went wrong,
|
||||
}
|
||||
|
||||
// Whew! We got past the tough parts.
|
||||
putstring_nl("Files found (* = fragmented):");
|
||||
|
||||
// Print out all of the files in all the directories.
|
||||
root.ls(LS_R | LS_FLAG_FRAGMENTED);
|
||||
}
|
||||
|
||||
//////////////////////////////////// LOOP
|
||||
void loop() {
|
||||
root.rewind();
|
||||
play(root);
|
||||
}
|
||||
|
||||
/////////////////////////////////// HELPERS
|
||||
/*
|
||||
* print error message and halt
|
||||
*/
|
||||
void error_P(const char *str) {
|
||||
PgmPrint("Error: ");
|
||||
SerialPrint_P(str);
|
||||
sdErrorCheck();
|
||||
while(1);
|
||||
}
|
||||
/*
|
||||
* print error message and halt if SD I/O error, great for debugging!
|
||||
*/
|
||||
void sdErrorCheck(void) {
|
||||
if (!card.errorCode()) return;
|
||||
PgmPrint("\r\nSD I/O error: ");
|
||||
Serial.print(card.errorCode(), HEX);
|
||||
PgmPrint(", ");
|
||||
Serial.println(card.errorData(), HEX);
|
||||
while(1);
|
||||
}
|
||||
/*
|
||||
* play recursively - possible stack overflow if subdirectories too nested
|
||||
*/
|
||||
void play(FatReader &dir) {
|
||||
FatReader file;
|
||||
while (dir.readDir(dirBuf) > 0) { // Read every file in the directory one at a time
|
||||
|
||||
// Skip it if not a subdirectory and not a .WAV file
|
||||
if (!DIR_IS_SUBDIR(dirBuf)
|
||||
&& strncmp_P((char *)&dirBuf.name[8], PSTR("WAV"), 3)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
Serial.println(); // clear out a new line
|
||||
|
||||
for (uint8_t i = 0; i < dirLevel; i++) {
|
||||
Serial.write(' '); // this is for prettyprinting, put spaces in front
|
||||
}
|
||||
if (!file.open(vol, dirBuf)) { // open the file in the directory
|
||||
error("file.open failed"); // something went wrong
|
||||
}
|
||||
|
||||
if (file.isDir()) { // check if we opened a new directory
|
||||
putstring("Subdir: ");
|
||||
printEntryName(dirBuf);
|
||||
Serial.println();
|
||||
dirLevel += 2; // add more spaces
|
||||
// play files in subdirectory
|
||||
play(file); // recursive!
|
||||
dirLevel -= 2;
|
||||
}
|
||||
else {
|
||||
// Aha! we found a file that isnt a directory
|
||||
putstring("Playing ");
|
||||
printEntryName(dirBuf); // print it out
|
||||
if (!wave.create(file)) { // Figure out, is it a WAV proper?
|
||||
putstring(" Not a valid WAV"); // ok skip it
|
||||
} else {
|
||||
Serial.println(); // Hooray it IS a WAV proper!
|
||||
wave.play(); // make some noise!
|
||||
|
||||
uint8_t n = 0;
|
||||
while (wave.isplaying) {// playing occurs in interrupts, so we print dots in realtime
|
||||
putstring(".");
|
||||
if (!(++n % 32))Serial.println();
|
||||
delay(100);
|
||||
}
|
||||
sdErrorCheck(); // everything OK?
|
||||
// if (wave.errors)Serial.println(wave.errors); // wave decoding errors
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,184 @@
|
||||
/*
|
||||
* This sketch illustrates opening files by index
|
||||
* which can significantly reduce latency.
|
||||
*
|
||||
* How to prepare a test SD:
|
||||
* Start with a clean newly formatted SD.
|
||||
* First copy the 400 files in the 'fill' folder to the SD.
|
||||
* Next copy the 16 files in the 'DTMF' folder to the SD.
|
||||
* There should be 416 files in the SD root directory.
|
||||
*
|
||||
* You must copy the files in the above order so the 'fill'
|
||||
* files occur in the directory before the DTMF files.
|
||||
*
|
||||
* Run this sketch using the prepared SD. Notice the
|
||||
* difference in latency between play by name and
|
||||
* play by index.
|
||||
*/
|
||||
|
||||
#include <WaveHC.h>
|
||||
#include <WaveUtil.h>
|
||||
|
||||
SdReader card; // This object holds the information for the card
|
||||
FatVolume vol; // This holds the information for the partition on the card
|
||||
FatReader root; // This holds the information for the volumes root directory
|
||||
FatReader file; // This object represent the WAV file
|
||||
WaveHC wave; // This is the only wave (audio) object, since we will only play one at a time
|
||||
|
||||
// time to play each tone in milliseconds
|
||||
#define PLAY_TIME 200
|
||||
|
||||
/*
|
||||
* Define macro to put error messages in flash memory
|
||||
*/
|
||||
#define error(msg) error_P(PSTR(msg))
|
||||
|
||||
//////////////////////////////////// SETUP
|
||||
void setup() {
|
||||
Serial.begin(9600);
|
||||
|
||||
if (!card.init()) error("card.init");
|
||||
|
||||
// enable optimized read - some cards may timeout
|
||||
card.partialBlockRead(true);
|
||||
|
||||
if (!vol.init(card)) error("vol.init");
|
||||
|
||||
if (!root.openRoot(vol)) error("openRoot");
|
||||
|
||||
PgmPrintln("Index files");
|
||||
indexFiles();
|
||||
|
||||
PgmPrintln("Play files by index");
|
||||
playByIndex();
|
||||
|
||||
PgmPrintln("Play files by name");
|
||||
playByName();
|
||||
}
|
||||
|
||||
//////////////////////////////////// LOOP
|
||||
void loop() { }
|
||||
|
||||
/////////////////////////////////// HELPERS
|
||||
/*
|
||||
* print error message and halt
|
||||
*/
|
||||
void error_P(const char *str) {
|
||||
PgmPrint("Error: ");
|
||||
SerialPrint_P(str);
|
||||
sdErrorCheck();
|
||||
while(1);
|
||||
}
|
||||
/*
|
||||
* print error message and halt if SD I/O error, great for debugging!
|
||||
*/
|
||||
void sdErrorCheck(void) {
|
||||
if (!card.errorCode()) return;
|
||||
PgmPrint("\r\nSD I/O error: ");
|
||||
Serial.print(card.errorCode(), HEX);
|
||||
PgmPrint(", ");
|
||||
Serial.println(card.errorData(), HEX);
|
||||
while(1);
|
||||
}
|
||||
|
||||
// Number of files.
|
||||
#define FILE_COUNT 16
|
||||
|
||||
// Files are 'touch tone phone' DTMF tones, P = #, S = *
|
||||
// Most phones don't have A, B, C, and D tones.
|
||||
// file names are of the form DTMFx.WAV where x is one of
|
||||
// the letters from fileLetter[]
|
||||
char fileLetter[] = {'0', '1', '2', '3', '4', '5', '6',
|
||||
'7', '8', '9', 'A', 'B', 'C', 'D', 'P', 'S'};
|
||||
|
||||
// index of DTMF files in the root directory
|
||||
uint16_t fileIndex[FILE_COUNT];
|
||||
/*
|
||||
* Find files and save file index. A file's index is is the
|
||||
* index of it's directory entry in it's directory file.
|
||||
*/
|
||||
void indexFiles(void) {
|
||||
char name[10];
|
||||
|
||||
// copy flash string to RAM
|
||||
strcpy_P(name, PSTR("DTMFx.WAV"));
|
||||
|
||||
for (uint8_t i = 0; i < FILE_COUNT; i++) {
|
||||
|
||||
// Make file name
|
||||
name[4] = fileLetter[i];
|
||||
|
||||
// Open file by name
|
||||
if (!file.open(root, name)) error("open by name");
|
||||
|
||||
// Save file's index (byte offset of directory entry divided by entry size)
|
||||
// Current position is just after entry so subtract one.
|
||||
fileIndex[i] = root.readPosition()/32 - 1;
|
||||
}
|
||||
PgmPrintln("Done");
|
||||
}
|
||||
/*
|
||||
* Play file by index and print latency in ms
|
||||
*/
|
||||
void playByIndex(void) {
|
||||
for (uint8_t i = 0; i < FILE_COUNT; i++) {
|
||||
|
||||
// start time
|
||||
uint32_t t = millis();
|
||||
|
||||
// open by index
|
||||
if (!file.open(root, fileIndex[i])) {
|
||||
error("open by index");
|
||||
}
|
||||
|
||||
// create and play Wave
|
||||
if (!wave.create(file)) error("wave.create");
|
||||
wave.play();
|
||||
|
||||
// print time to open file and start play
|
||||
Serial.println(millis() - t);
|
||||
|
||||
// stop after PLAY_TIME ms
|
||||
while((millis() - t) < PLAY_TIME);
|
||||
wave.stop();
|
||||
|
||||
// check for play errors
|
||||
sdErrorCheck();
|
||||
}
|
||||
PgmPrintln("Done");
|
||||
}
|
||||
/*
|
||||
* Play file by name and print latency in ms
|
||||
*/
|
||||
void playByName(void) {
|
||||
char name[10];
|
||||
|
||||
// copy flash string to RAM
|
||||
strcpy_P(name, PSTR("DTMFx.WAV"));
|
||||
|
||||
for (uint8_t i = 0; i < FILE_COUNT; i++) {
|
||||
// start time
|
||||
uint32_t t = millis();
|
||||
|
||||
// make file name
|
||||
name[4] = fileLetter[i];
|
||||
|
||||
// open file by name
|
||||
if (!file.open(root, name)) error("open by name");
|
||||
|
||||
// create wave and start play
|
||||
if (!wave.create(file))error("wave.create");
|
||||
wave.play();
|
||||
|
||||
// print time
|
||||
Serial.println(millis() - t);
|
||||
|
||||
// stop after PLAY_TIME ms
|
||||
while((millis() - t) < PLAY_TIME);
|
||||
wave.stop();
|
||||
|
||||
// check for play errors
|
||||
sdErrorCheck();
|
||||
}
|
||||
PgmPrintln("Done");
|
||||
}
|
||||
Reference in New Issue
Block a user