Skip to content

Instantly share code, notes, and snippets.

@velophonic
Created November 29, 2016 12:38
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save velophonic/3eab6d4c64d7ac6dcc6235d1799f09b4 to your computer and use it in GitHub Desktop.
Save velophonic/3eab6d4c64d7ac6dcc6235d1799f09b4 to your computer and use it in GitHub Desktop.
Arduino code
/* Knock Sensor sound
This sketch reads a piezo element to detect a knocking sound.
It reads an analog pin and compares the result to a set threshold.
If the result is greater than the threshold, it writes
"knock" to the serial port, and toggles the LED on pin 13.
This example plays every .WAV file it finds on the SD card when piezo is "knocked"
*/
#include <FatReader.h>
#include <SdReader.h>
#include <avr/pgmspace.h>
#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;
FatReader f; // 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);
// these constants won't change:
const int ledPin = 13; // led connected to digital pin 13
const int knockSensor1 = A0; // the piezo is connected to analog pin 0
const int knockSensor2 = A1; // the piezo is connected to analog pin 0
const int knockSensor3 = A2; // the piezo is connected to analog pin 0
const int knockSensor4 = A3; // the piezo is connected to analog pin 0
const int threshold = 50; // threshold value to decide when the detected sound is a knock or not
// these variables will change:
int sensorReading1 = 0; // variable to store the value read from the sensor pin
int sensorReading2 = 0;
int sensorReading3 = 0;
int sensorReading4 = 0;
int ledState = LOW; // variable used to store the last LED status, to toggle the light
//////////////////////////////////// SETUP
void setup() {
pinMode(ledPin, OUTPUT); // declare the ledPin as as OUTPUT
Serial.begin(9600); // use the serial port
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() {
// read the sensors and store it in the variable sensorReading:
sensorReading1 = analogRead(knockSensor1);
sensorReading2 = analogRead(knockSensor2);
sensorReading3 = analogRead(knockSensor3);
sensorReading4 = analogRead(knockSensor4);
// if the sensor reading is greater than the threshold:
if (sensorReading1 >= threshold) {
//play sound
playcomplete("DO.WAV");
// toggle the status of the ledPin:
ledState = !ledState;
// update the LED pin itself:
digitalWrite(ledPin, ledState);
// send the string "Knock!" back to the computer, followed by newline
Serial.println("Knock1!");
}
if (sensorReading2 >= threshold) {
//play sound
playcomplete("RE.WAV");
// toggle the status of the ledPin:
ledState = !ledState;
// update the LED pin itself:
digitalWrite(ledPin, ledState);
// send the string "Knock!" back to the computer, followed by newline
Serial.println("Knock2!");
}
if (sensorReading3 >= threshold) {
//play sound
playcomplete("MI.WAV");
// toggle the status of the ledPin:
ledState = !ledState;
// update the LED pin itself:
digitalWrite(ledPin, ledState);
// send the string "Knock!" back to the computer, followed by newline
Serial.println("Knock3!");
}
if (sensorReading4 >= threshold) {
//play sound
playcomplete("FA.WAV");
// toggle the status of the ledPin:
ledState = !ledState;
// update the LED pin itself:
digitalWrite(ledPin, ledState);
// send the string "Knock!" back to the computer, followed by newline
Serial.println("Knock4!");
}
delay(10); // delay to avoid overloading the serial port buffer
}
/////////////////////////////////// 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
}
}
}
}
// Plays a full file from beginning to end with no pause.
void playcomplete(char *name) {
// call our helper to find and play this name
playfile(name);
while (wave.isplaying) {
// do nothing while its playing
}
// now its done playing
}
void playfile(char *name) {
// see if the wave object is currently doing something
if (wave.isplaying) {// already playing something, so stop it!
wave.stop(); // stop it
}
// look in the root directory and open the file
if (!f.open(root, name)) {
putstring("Couldn't open file "); Serial.print(name); return;
}
// OK read the file and turn it into a wave object
if (!wave.create(f)) {
putstring_nl("Not a valid WAV"); return;
}
// ok time to play! start playback
wave.play();
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment