My "DoorTunes" (AKA: MP3 Doorbell)
Hardware:
Arduino Uno
Audio Shield (v1.1) "Wave Shield"
/* * This plays one .WAV file from the SD card by index when the doorbell is pressed */ #include#include 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 represents the WAV file 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 const int numberOfTunes = 14; // See sketch (openByIndex) example uint16_t tunesIndex[numberOfTunes]; // Number of Tune files. /* * 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); void findFiles(FatReader &dir); const int doorBellPin = 7; // Analog pin for doorbell int doorBellState = 0; long randNumber, lastNumber; //////////////////////////////////// SETUP void setup() { Serial.begin(9600); // set up Serial library at 9600 bps for debugging putstring_nl("\nRunning Setup!"); // say we woke up! putstring("Free RAM: "); // This can help with debugging, running out of RAM is bad Serial.println(FreeRam()); // Set the output pins for the DAC control. This pins are defined in the library pinMode(2, OUTPUT); pinMode(3, OUTPUT); pinMode(4, OUTPUT); pinMode(5, OUTPUT); pinMode(doorBellPin, INPUT); // 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); putstring("\nCalling findFiles()"); root.rewind(); findFiles(root); putstring("\nDONE WITH SETUP"); } //////////////////////////////////// LOOP void loop() { doorBellState = digitalRead(doorBellPin); if(doorBellState == HIGH) { putstring("\nDOORBELL is Pressed!\n"); // print a random number from 0 to NumberOfTunes randNumber = random(numberOfTunes); while(randNumber == lastNumber) { Serial.println("Dude, we already heard that song! Pick something original"); randNumber = random(numberOfTunes); } lastNumber = randNumber; putstring("\nRandom Number: "); Serial.println(randNumber); // Try to open the root directory if (!root.openRoot(vol)) { error("Can't open root dir!"); // Something went wrong, } Serial.println(tunesIndex[randNumber]); // open by index if (!file.open(root, tunesIndex[randNumber])) { error("open by index"); } // create and play Wave if (!wave.create(file)) error("wave.create"); wave.play(); uint8_t n = 0; while (wave.isplaying) {// playing occurs in interrupts, so we print dots in realtime // I also use this to keep it from trying to play more than one file while the doorbell is pressed. putstring("."); if (!(++n % 32))Serial.println(); delay(300); } } } /////////////////////////////////// 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); } /* * Find all the tunes - possible stack overflow if subdirectories too nested */ void findFiles(FatReader &dir) { putstring("\nRunning findFiles()"); FatReader file; int tunesCounter = 0; 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)) { putstring("\nfindFiles() Not a wav or subdir."); 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()) { putstring("Subdir: "); printEntryName(dirBuf); // recursive call to findFiles(file); } else { // Add the file to the tunes[] // Aha! we found a file that isnt a directory putstring("Adding file: "); 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! putstring("tunesCounter: "); Serial.println(tunesCounter); // Save file's index (byte offset of directory entry divided by entry size) // Current position is just after entry so subtract one. tunesIndex[tunesCounter] = root.readPosition()/32 - 1; tunesCounter++; sdErrorCheck(); // everything OK? } } } putstring("\nDONE Running findFiles()"); }
No comments:
Post a Comment