Trying to understand code

Please help! I have found a short piece of free code that's supposed to work for my project, but it isn't working quite right ... but I don't understand it well enough yet to figure out what it is actually doing! I tried contacting the original coder, but he hasn't responded. Could someone please add notations to help me understand what the commands are and maybe find where the error is? Thank you!

#include <SD.h>
#include <TMRpcm.h> 
TMRpcm tmrpcm; 

File root;
File entry;

const int chipSelect = 4;    

const int oldCard = SPI_HALF_SPEED;
const int newCard = SPI_QUARTER_SPEED;

int cardType = oldCard;

int wasPlaying = 0;
int inSwitch = 7;
int finished = 0;
int start = 0;
int pauseOn = 0;
unsigned long timeDiff = 0;
unsigned long timePress = 0;

void setup() {
  Serial.begin(9600);
  Serial.print("\nInitializing SD card...");
  pinMode(chipSelect, OUTPUT); 
  if (!SD.begin(chipSelect,cardType)) {
    Serial.println("failed!");
    return;
  }
  Serial.println("done.");

  tmrpcm.speakerPin = 9;
  
  pinMode(inSwitch,INPUT_PULLUP);
  digitalWrite(inSwitch,HIGH);
  
  root = SD.open("/");
}

void loop(void) {
  if(!tmrpcm.isPlaying() && wasPlaying == 1) { 
    tmrpcm.stopPlayback();
    playNext();  
  }
  
  if (millis() - timeDiff > 50) { // check switch every 100ms 
     timeDiff = millis(); // get current millisecond count
      
      if(digitalRead(inSwitch) == LOW) {
        
        if(start==0) {
          start=1; 
          playNext();
          delay(200);

        } else {
        
          timePress = millis();
          while(digitalRead(inSwitch)==LOW) {
            delay(50);
          }
          if (millis() - timePress < 1000 && start == 1) {
            tmrpcm.pause();
            if (pauseOn == 0) {
              pauseOn = 1;
            } else {
              pauseOn = 0;
            }
          }
          if (millis() - timePress > 1000 && start == 1) {
             if (pauseOn == 1) {pauseOn = 0; tmrpcm.pause();}
             tmrpcm.stopPlayback();
             timePress = millis();
             if (finished == 0) {
               playNext(); 
             } else {
               finished = 0;
               Serial.println("Restarting."); 
               root.rewindDirectory();
               playNext(); 
             }
          }
       }
     }
  }
}

void playNext() {
  entry = root.openNextFile();
  if (entry) {
    entry.close();
    tmrpcm.play(entry.name()); 
    wasPlaying = 1;
  } else {
    if (wasPlaying == 1) {
      Serial.println("Completed playback."); 
      wasPlaying = 0;
      finished = 1;
      start = 0;
      root.rewindDirectory();
    }     
  }
}

What's it supposed to do, what does it do instead?
Please post with code tags next time (use the # button), I've updated this post for you.

I believe it is supposed to "playback PCM/WAV files directly from an SD Card".

Looks like it automatically just plays music off the SD card and cycles through the files

To Dan, make sure that your ChipSelect pin is correct and that you have the SD Card Reader/Writer properly hooked up to your Arduino and working first.

Along the same train of thought, make sure you have the speaker hooked up properly to the right pins and that it is working as well. Basically you want to take this a step at a time instead of all at one chunk due to the several separate systems/components involved.

Thank you. I am utterly new to this. It is supposed to play one of 6 prerecorded messages (depending on which of six buttons is pushed) for 15 seconds and then stop. I can see now that only one button is accounted for (I should have looked more closely before uploading it), and it's skipping tracks or just switching off when I push the button. I think they guy who did it for me didn't completely understand. And he didn't use any notes, so I don't really know what's going on. :frowning:

Danthemanforth:
Thank you. I am utterly new to this. It is supposed to play one of 6 prerecorded messages (depending on which of six buttons is pushed) for 15 seconds and then stop. I can see now that only one button is accounted for (I should have looked more closely before uploading it), and it's skipping tracks or just switching off when I push the button. I think they guy who did it for me didn't completely understand. And he didn't use any notes, so I don't really know what's going on. :frowning:

So you had someone else write the code for you? Yeah, I don't think that he did what you wanted to happen. I can tell you for sure that the program only is reading one button known as "inSwitch", not 6. I don't think it plays for 15 seconds and stops either, it looks like it just plays through the file and upon completion plays the next file. I think you really need to talk to that guy.

Alright. Thank you. I don't suppose you would repost the code with notes on where I need to add/remove commands and conditions? I'd like to use this as an opportunity to learn my way around the code, so I don't need to depend on others so entirely, or be completely in the dark about why things are not working.

This isn't actually code, but it's the basic framework of what I'm trying to do.

if button-X- pushed
	if audio *any* = on
		then: do nothing
	if audio *any* = off
		then: change LED-X- to on
			 change audio-X- to on
	if audio-X- = end
	AND audio-X- playtime =  >15 seconds
		then: change LED-X- to off
			 change audio-X- to off
			 change LED-X- to on
			 change audio-X- to on
	if audio-X- playtime = +15 seconds
		then: change LED-X- to off
			 change audio-X- to off

I basically need this kind of function for all 6 buttons.

I'd suggest that getting your desired functionality working is going to be quite tricky with what you currently have. I'd suggest you start with something simpler.

Leave setup as is (remove the sd.open if you like). Replace loop with something that uses digital read to check for a button press, use isPlaying to see if anything is playing and play to play a specific wave file if nothing is. Once you have it working for one, copy and paste or arrays will get you going with six and then you can think about the timeout.

Ok. So, a round of heavy googling brought me to Ladyada's Project Page Overview | Wave Shield | Adafruit Learning System on which she basically describes how to build/use almost the exact circuit I am aiming for. The only difference is that, in addition to accessing specific wave files associated with one of 6 respective buttons from an sd card, I also would like each button to trigger an LED to light up for as long as the associated wave file is playing.

My first question is where I should/shouldn't plug the buttons and LEDs into on the wave shield...

IMAGE
http://www.adafruit.com/index.php?main_page=popup_image_additional&pID=94&pic=3&products_image_large_additional=images/large/94top_LRG.jpg

... and my second question is how to add the locations of the LEDs and buttons, as well as how to use them, without messing up this beautiful piece of code that runs the arduino & shield as-is?

#include <FatReader.h>
#include <SdReader.h>
#include <avr/pgmspace.h>
#include "WaveUtil.h"
#include "WaveHC.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 filesystem on the card
FatReader f;      // This holds the information for the file we're play

WaveHC wave;      // This is the only wave (audio) object, since we will only play one at a time

#define DEBOUNCE 5  // button debouncer

// here is where we define the buttons that we'll use. button "1" is the first, button "6" is the 6th, etc
byte buttons[] = {14, 15, 16, 17, 18, 19};
// This handy macro lets us determine how big the array up above is, by checking the size
#define NUMBUTTONS sizeof(buttons)
// we will track if a button is just pressed, just released, or 'pressed' (the current state
volatile byte pressed[NUMBUTTONS], justpressed[NUMBUTTONS], justreleased[NUMBUTTONS];

// this handy function will return the number of bytes currently free in RAM, great for debugging!   
int freeRam(void)
{
  extern int  __bss_end; 
  extern int  *__brkval; 
  int free_memory; 
  if((int)__brkval == 0) {
    free_memory = ((int)&free_memory) - ((int)&__bss_end); 
  }
  else {
    free_memory = ((int)&free_memory) - ((int)__brkval); 
  }
  return free_memory; 
} 

void sdErrorCheck(void)
{
  if (!card.errorCode()) return;
  putstring("\n\rSD I/O error: ");
  Serial.print(card.errorCode(), HEX);
  putstring(", ");
  Serial.println(card.errorData(), HEX);
  while(1);
}

void setup() {
  byte i;
  
  // set up serial port
  Serial.begin(9600);
  putstring_nl("WaveHC with ");
  Serial.print(NUMBUTTONS, DEC);
  putstring_nl("buttons");
  
  putstring("Free RAM: ");       // This can help with debugging, running out of RAM is bad
  Serial.println(freeRam());      // if this is under 150 bytes it may spell trouble!
  
  // 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);
 
  // pin13 LED
  pinMode(13, OUTPUT);
 
  // Make input & enable pull-up resistors on switch pins
  for (i=0; i< NUMBUTTONS; i++) {
    pinMode(buttons[i], INPUT);
    digitalWrite(buttons[i], HIGH);
  }
  
  //  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!)  
    putstring_nl("Card init. failed!");  // Something went wrong, lets print out why
    sdErrorCheck();
    while(1);                            // then 'halt' - do nothing!
  }
  
  // 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  :(
    putstring_nl("No valid FAT partition!");
    sdErrorCheck();      // Something went wrong, lets print out why
    while(1);                            // then 'halt' - do nothing!
  }
  
  // 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)) {
    putstring_nl("Can't open root dir!"); // Something went wrong,
    while(1);                             // then 'halt' - do nothing!
  }
  
  // Whew! We got past the tough parts.
  putstring_nl("Ready!");
  
  TCCR2A = 0;
  TCCR2B = 1<<CS22 | 1<<CS21 | 1<<CS20;

  //Timer2 Overflow Interrupt Enable
  TIMSK2 |= 1<<TOIE2;


}

SIGNAL(TIMER2_OVF_vect) {
  check_switches();
}

void check_switches()
{
  static byte previousstate[NUMBUTTONS];
  static byte currentstate[NUMBUTTONS];
  byte index;

  for (index = 0; index < NUMBUTTONS; index++) {
    currentstate[index] = digitalRead(buttons[index]);   // read the button
    
    /*     
    Serial.print(index, DEC);
    Serial.print(": cstate=");
    Serial.print(currentstate[index], DEC);
    Serial.print(", pstate=");
    Serial.print(previousstate[index], DEC);
    Serial.print(", press=");
    */
    
    if (currentstate[index] == previousstate[index]) {
      if ((pressed[index] == LOW) && (currentstate[index] == LOW)) {
          // just pressed
          justpressed[index] = 1;
      }
      else if ((pressed[index] == HIGH) && (currentstate[index] == HIGH)) {
          // just released
          justreleased[index] = 1;
      }
      pressed[index] = !currentstate[index];  // remember, digital HIGH means NOT pressed
    }
    //Serial.println(pressed[index], DEC);
    previousstate[index] = currentstate[index];   // keep a running tally of the buttons
  }
}


void loop() {
  byte i;
  
  if (justpressed[0]) {
    justpressed[0] = 0;
    playfile("DO.WAV");
  }
  else if (justpressed[1]) {
      justpressed[1] = 0;
      playfile("RE.WAV");
  }
  else if (justpressed[2]) {
      justpressed[2] = 0;
      playfile("MI.WAV");
  }
  else if (justpressed[3]) {
      justpressed[3] = 0;
      playfile("FA.WAV");
  } 
  else if (justpressed[4]) {
      justpressed[4] = 0;
      playfile("SO.WAV");
  } 
  else if (justpressed[5]) {
      justpressed[5] = 0;
      playfile("LA.WAV");
  }
}



// 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();
}

I know I have bitten off more than I can chew right now, but I really do learn fastest by jumping into the deep end and asking for input when I'm well and truly stumped. Thank you again for helping me with this!

Add the Buttons/LEDs on any of the available digital/analog pins.

You don't really have to mess up the code to simply add some push buttons and LEDs. In setup add your pinMode() for input and output of each pin (depending on where you put them on the shield), and then wherever each piece of code is that plays a file, you just embed a single line to turn the LED on.

When I used SD.h to read/write SD, I also had to include SPI.h.

Danthemanforth .... you know Forth? There are AVR Forth versions.

GoForSmoke:
When I used SD.h to read/write SD, I also had to include SPI.h.

Danthemanforth .... you know Forth? There are AVR Forth versions.

That's really strange, I've used two separate SD breakout boards and I've never included SPI.h