Wave Shield: Wav Starts but Cuts Out

Just this morning, I got my idea of an Amiibo (NFC) music box (without the little figure rotating) working and I am all giddy with excitement! One problem though. One of the tracks keeps cutting out.

The music box starts with an intro (maybe the character’s name or a sound effect) and then goes to the music. For just one of the intro files, it starts a few notes and then cuts out.

I have tried different files and it does not work. What makes this weird is that I use the exact same conversion tool so if it is not working for one it should not work for the others.

Today’s Code

#include <WaveHC.h>
#include <WaveUtil.h>
#include <Wire.h>
#include <Adafruit_NFCShield_I2C.h>
//#include <MemoryFree.h>

//Loading Strings into PROGMEM to save RAM
#include <avr/pgmspace.h>
//Character Intro File Names
const char string_0[] PROGMEM = "splsqdin.wav";
const char string_1[] PROGMEM = "splsqdlp.wav";
const char string_2[] PROGMEM = "splminin.wav";
const char string_3[] PROGMEM = "splminlp.wav";
const char string_4[] PROGMEM = "splfinin.wav";
const char string_5[] PROGMEM = "splfinlp.wav";

// Then set up a table to refer to your strings.

const char* const string_table[] PROGMEM =      
{   
  string_0, string_1, string_2, string_3, string_4, string_5,  
};

char buffer[71];

#define IRQ 6 // this trace must be cut and rewired!
#define RESET 8

Adafruit_NFCShield_I2C nfc(IRQ, RESET);

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()
uint32_t versiondata;

//My Added Variables
uint32_t lastcard = 0;
uint32_t currentcard = 1;
uint32_t CID = 0;
boolean songplaying = false;

//Loop()
uint32_t cardidentifier = 0;
uint8_t success;
uint8_t uid[] = { 0, 0, 0, 0, 0, 0, 0 }; // Buffer to store the returned UID
uint8_t uidLength; // Length of the UID (4 or 7 bytes depending on ISO14443A card type)
 
//////////////////////////////////// SETUP

void setup() {
  // set up Serial library at 9600 bps
  Serial.begin(115200);
    
  PgmPrintln("Amiibo Scanner");
  
  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();
  
  // find Adafruit RFID/NFC shield
  nfc.begin();

  versiondata = nfc.getFirmwareVersion();
  if (! versiondata) {
    Serial.print(F("Didn't find PN53x board"));
    while (1); // halt
  }
  // Got ok data, print it out!
  Serial.print(F("Found chip PN5")); Serial.println((versiondata>>24) & 0xFF, HEX);
  Serial.print(F("Firmware ver. ")); Serial.print((versiondata>>16) & 0xFF, DEC);
  Serial.print('.'); Serial.println((versiondata>>8) & 0xFF, DEC);
  
  // configure board to read RFID tags
  nfc.SAMConfig();
  
  //enable timeout waiting for cards
  nfc.setPassiveActivationRetries(50);

}

/////////////////////////////////// LOOP

unsigned digit = 0;

void loop() 
{
  
  //Memory Checker
  
  //Serial.print(F("Memory Available = "));
  //Serial.println(freeMemory());
  
  
  // wait for RFID card to show up!
  Serial.println(F("Waiting for an Amiibo ..."));

    
  // Wait for an ISO14443A type cards (Mifare, etc.). When one is found
  // 'uid' will be populated with the UID, and uidLength will indicate
  // if the uid is 4 bytes (Mifare Classic) or 7 bytes (Mifare Ultralight)
  success = nfc.readPassiveTargetID(PN532_MIFARE_ISO14443A, uid, &uidLength);

  cardidentifier = 0;
  CID = 999; 
  if (success) 
  {
    // Found a card!

    Serial.print(F("Amiibo detected #"));
    // turn the four byte UID of a mifare classic into a single variable #
    cardidentifier = uid[3];
    cardidentifier <<= 8; cardidentifier |= uid[2];
    cardidentifier <<= 8; cardidentifier |= uid[1];
    cardidentifier <<= 8; cardidentifier |= uid[0];
    Serial.println(cardidentifier);
    
    //Check the previous card
    
    (lastcard = currentcard);
    (currentcard = cardidentifier);
    
    Serial.print(F("Last Amiibo:    #"));
    Serial.println(lastcard);
    Serial.print(F("Current Card:"));
    Serial.println(currentcard);
    
    // Check Character ID
    
      // Try to read the Character info page (#21)
      uint8_t charID[32];
      success = nfc.mifareultralight_ReadPage (21, charID);
      
    if (success)
    {
        // turn page 21 into a character ID
      CID = charID[6];
      CID <<= 8; CID |= charID[6];
      CID <<= 8; CID |= charID[5];
      CID <<= 8; CID |= charID[4];
      CID <<= 8; CID |= charID[3];
      CID <<= 8; CID |= charID[2];
      CID <<= 8; CID |= charID[1];
      CID <<= 8; CID |= charID[0];
      Serial.println("Character Number: ");
      Serial.println(CID);
    
    
      if (currentcard == lastcard) 
      {
      /*
        If there is no song playing, play a song.
      */
        if (songplaying == false) 
        {
          //Squid Song
          if (CID == 6)      
          {strcpy_P(buffer, (char*)pgm_read_word(&(string_table[1])));
            playfile(buffer);
            if (wave.isplaying) {
              songplaying = true;
            }
          }
          //Male Inkling Song
          if (CID == 7)      
          {strcpy_P(buffer, (char*)pgm_read_word(&(string_table[3])));
            playfile(buffer);
            if (wave.isplaying) {
              songplaying = true;
            }
          }
          //Female Inkling Song
          if (CID == 8)      
          {strcpy_P(buffer, (char*)pgm_read_word(&(string_table[5])));
            playfile(buffer);
            if (wave.isplaying) {
              songplaying = true;
            }
          }
        }
      }
      /*
        There is no song playing, play the intro sequence!
      */
      else 
      {
        //Squid
        if (CID == 6) 
        {
          strcpy_P(buffer, (char*)pgm_read_word(&(string_table[0])));
          playcomplete(buffer);
        }
        //Male Inkling Song
        if (CID == 7) 
        {
          strcpy_P(buffer, (char*)pgm_read_word(&(string_table[2])));
          playcomplete(buffer);
        }
        //Female Inkling Song
        if (CID == 8) 
        {
          strcpy_P(buffer, (char*)pgm_read_word(&(string_table[4])));
          playcomplete(buffer);
        }
      }
      songplaying = wave.isplaying
    }
    else 
    {
      //if (currentcard == lastcard) 
      //{
       // Serial.println("CID else");
        wave.stop();
      //}  
      lastcard = 123456;
      currentcard = 654321;
      songplaying = false;
    }
  } 

   //If the Amiibo is gone, stop the song.
  else 
    {
      //if (currentcard == lastcard) 
      //{
        //Serial.println("UID else");
        wave.stop();
      //}  
      lastcard = 321123;
      currentcard = 123321;
      songplaying = false;
    }  
}

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

Has anyone got any ideas why it does not work? This is what I convert the files to.

  • .Wav format
  • Mono
  • 16-Bit (PCM)
  • 22050 htz

When I get home I will be moving the files around. Based on the fact I tried multiple sound effects in the same array index it could be that index that is causing the problem. I am also going to try replacing it with a wav file that already works.

For just one of the intro files, it starts a few notes and then cuts out.

You only have two files defined, both with the same name. It is impossible for one track to not play correctly, if the other one does.

PaulS: You only have two files defined, both with the same name. It is impossible for one track to not play correctly, if the other one does.

Oh sorry I should make this more apparent. I did mention this earlier ;)

Last Night's Code (Today's Code is the same but with more sounds and amiibos added)

Since last night, I have made a proper naming convention for file names

8 characters long

PPP - NNN - TT

  • PPP - Game/Franchise (Splatoon = "spl")
  • NNN - Character (Squid = "sqd")
  • TT - Type (Either "in" for intro or "lp" for loop)

Hopefully that clears up a few things!

Hopefully that clears up a few things!

Not a bit. You made some changes to the code. You did NOT bother posting the new code.

The program plays one track incorrectly. WHICH ONE?

PaulS:
Not a bit. You made some changes to the code. You did NOT bother posting the new code.

The program plays one track incorrectly. WHICH ONE?

I can’t post the code when I am 10 miles away from the laptop…so I made a mock-code to help you.

//Loading Strings into PROGMEM to save RAM
#include <avr/pgmspace.h>

const char string_0[] PROGMEM = "splsqdin.wav";
const char string_1[] PROGMEM = "splsqdlp.wav";
const char string_2[] PROGMEM = "splminin.wav";
const char string_3[] PROGMEM = "splminlp.wav";
const char string_4[] PROGMEM = "splfinin.wav";   <---THIS IS THE ONE THAT BREAKS
const char string_5[] PROGMEM = "splfimlp.wav";

// Then set up a table to refer to your strings.
const char* const string_table[] PROGMEM =      
{   
  string_0, string_1, string_2, string_3, string_4, string_5
};
      else 
      {
        //Squid
        if (CID == 6) 
        {
          strcpy_P(buffer, (char*)pgm_read_word(&(string_table[0])));
          playcomplete(buffer);
        }        
        //Male Inkling
        if (CID == 7) 
        {
          strcpy_P(buffer, (char*)pgm_read_word(&(string_table[2])));
          playcomplete(buffer);
        }
        //Female Inkling
        if (CID == 8) 
        {
          strcpy_P(buffer, (char*)pgm_read_word(&(string_table[4])));
          playcomplete(buffer);
        }
      }

This should give you a clearer idea of the difference between last night’s code and today’s

I can't post the code when I am 10 miles away from the laptop...so I made a mock-code to help you.

You want that I should make up an answer?

Right I have rebuilt the whole code! The only part I can’t remember is the actual values the Amiibos are registered as. So this is exactly how it is on my laptop!

#include <WaveHC.h>
#include <WaveUtil.h>
#include <Wire.h>
#include <Adafruit_NFCShield_I2C.h>
//#include <MemoryFree.h>

//Loading Strings into PROGMEM to save RAM
#include <avr/pgmspace.h>
//Character Intro File Names
const char string_0[] PROGMEM = "splsqdin.wav";
const char string_1[] PROGMEM = "splsqdlp.wav";
const char string_2[] PROGMEM = "splminin.wav";
const char string_3[] PROGMEM = "splminlp.wav";
const char string_4[] PROGMEM = "splfinin.wav";
const char string_5[] PROGMEM = "splfinlp.wav";

// Then set up a table to refer to your strings.

const char* const string_table[] PROGMEM =      
{   
  string_0, string_1, string_2, string_3, string_4, string_5,  
};

char buffer[71];

#define IRQ 6 // this trace must be cut and rewired!
#define RESET 8

Adafruit_NFCShield_I2C nfc(IRQ, RESET);

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()
uint32_t versiondata;

//My Added Variables
uint32_t lastcard = 0;
uint32_t currentcard = 1;
uint32_t CID = 0;
boolean songplaying = false;

//Loop()
uint32_t cardidentifier = 0;
uint8_t success;
uint8_t uid[] = { 0, 0, 0, 0, 0, 0, 0 }; // Buffer to store the returned UID
uint8_t uidLength; // Length of the UID (4 or 7 bytes depending on ISO14443A card type)
 
//////////////////////////////////// SETUP

void setup() {
  // set up Serial library at 9600 bps
  Serial.begin(115200);
    
  PgmPrintln("Amiibo Scanner");
  
  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();
  
  // find Adafruit RFID/NFC shield
  nfc.begin();

  versiondata = nfc.getFirmwareVersion();
  if (! versiondata) {
    Serial.print(F("Didn't find PN53x board"));
    while (1); // halt
  }
  // Got ok data, print it out!
  Serial.print(F("Found chip PN5")); Serial.println((versiondata>>24) & 0xFF, HEX);
  Serial.print(F("Firmware ver. ")); Serial.print((versiondata>>16) & 0xFF, DEC);
  Serial.print('.'); Serial.println((versiondata>>8) & 0xFF, DEC);
  
  // configure board to read RFID tags
  nfc.SAMConfig();
  
  //enable timeout waiting for cards
  nfc.setPassiveActivationRetries(50);

}

/////////////////////////////////// LOOP

unsigned digit = 0;

void loop() 
{
  
  //Memory Checker
  
  //Serial.print(F("Memory Available = "));
  //Serial.println(freeMemory());
  
  
  // wait for RFID card to show up!
  Serial.println(F("Waiting for an Amiibo ..."));

    
  // Wait for an ISO14443A type cards (Mifare, etc.). When one is found
  // 'uid' will be populated with the UID, and uidLength will indicate
  // if the uid is 4 bytes (Mifare Classic) or 7 bytes (Mifare Ultralight)
  success = nfc.readPassiveTargetID(PN532_MIFARE_ISO14443A, uid, &uidLength);

  cardidentifier = 0;
  CID = 999; 
  if (success) 
  {
    // Found a card!

    Serial.print(F("Amiibo detected #"));
    // turn the four byte UID of a mifare classic into a single variable #
    cardidentifier = uid[3];
    cardidentifier <<= 8; cardidentifier |= uid[2];
    cardidentifier <<= 8; cardidentifier |= uid[1];
    cardidentifier <<= 8; cardidentifier |= uid[0];
    Serial.println(cardidentifier);
    
    //Check the previous card
    
    (lastcard = currentcard);
    (currentcard = cardidentifier);
    
    Serial.print(F("Last Amiibo:    #"));
    Serial.println(lastcard);
    Serial.print(F("Current Card:"));
    Serial.println(currentcard);
    
    // Check Character ID
    
      // Try to read the Character info page (#21)
      uint8_t charID[32];
      success = nfc.mifareultralight_ReadPage (21, charID);
      
    if (success)
    {
        // turn page 21 into a character ID
      CID = charID[6];
      CID <<= 8; CID |= charID[6];
      CID <<= 8; CID |= charID[5];
      CID <<= 8; CID |= charID[4];
      CID <<= 8; CID |= charID[3];
      CID <<= 8; CID |= charID[2];
      CID <<= 8; CID |= charID[1];
      CID <<= 8; CID |= charID[0];
      Serial.println("Character Number: ");
      Serial.println(CID);
    
    
      if (currentcard == lastcard) 
      {
      /*
        If there is no song playing, play a song.
      */
        if (songplaying == false) 
        {
          //Squid Song
          if (CID == 6)      
          {strcpy_P(buffer, (char*)pgm_read_word(&(string_table[1])));
            playfile(buffer);
            if (wave.isplaying) {
              songplaying = true;
            }
          }
          //Male Inkling Song
          if (CID == 7)      
          {strcpy_P(buffer, (char*)pgm_read_word(&(string_table[3])));
            playfile(buffer);
            if (wave.isplaying) {
              songplaying = true;
            }
          }
          //Female Inkling Song
          if (CID == 8)      
          {strcpy_P(buffer, (char*)pgm_read_word(&(string_table[5])));
            playfile(buffer);
            if (wave.isplaying) {
              songplaying = true;
            }
          }
        }
      }
      /*
        There is no song playing, play the intro sequence!
      */
      else 
      {
        //Squid
        if (CID == 6) 
        {
          strcpy_P(buffer, (char*)pgm_read_word(&(string_table[0])));
          playcomplete(buffer);
        }
        //Male Inkling Song
        if (CID == 7) 
        {
          strcpy_P(buffer, (char*)pgm_read_word(&(string_table[2])));
          playcomplete(buffer);
        }
        //Female Inkling Song
        if (CID == 8) 
        {
          strcpy_P(buffer, (char*)pgm_read_word(&(string_table[4])));
          playcomplete(buffer);
        }
      }
      songplaying = wave.isplaying
    }
    else 
    {
      //if (currentcard == lastcard) 
      //{
       // Serial.println("CID else");
        wave.stop();
      //}  
      lastcard = 123456;
      currentcard = 654321;
      songplaying = false;
    }
  } 

   //If the Amiibo is gone, stop the song.
  else 
    {
      //if (currentcard == lastcard) 
      //{
        //Serial.println("UID else");
        wave.stop();
      //}  
      lastcard = 321123;
      currentcard = 123321;
      songplaying = false;
    }  
}

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

So this is exactly how it is on my laptop!

      songplaying = wave.isplaying

So, your problem is that your code doesn't compile?

PaulS:       songplaying = wave.isplaying

So, your problem is that your code doesn't compile?

Okay that one was my bad sorry part of the code was not put in the one I put up.

      songplaying = wave.isplaying()

But to answer your question, it does compile and it all works! However on one of the intro tracks (string_4), the music cuts out in less than a second. There is a brief pause and the looping track begins. It is like the Wave Shield gives up playing the track and waits to play the loop

Write some code to play a track, then delay(), then play the next track, then delay(), etc.

Is the problem with the wav file itself?

PaulS: Write some code to play a track, then delay(), then play the next track, then delay(), etc.

Is the problem with the wav file itself?

I checked the wave files before uploading them and after uploading them to the SD Card. Media Player could still read them and clearly. This is why I posted the topic. Out of the 6 wav files, 5/6 of them work and they all used the same conversion process.

I will make that change the moment I get home.

EDIT: I did some tests and it seems the Amiibo is the reason. How can an Amiibo cause the track to cut out?

Yup I can now confirm it is the Amiibo. But that is weird. Surely if it is a problem with the Amiibo it would not allow the looping track to work properly either?

Longshot. Has the SD card been used a lot. I think they can get fragmented. Try a program like Killdisk, and reload your files in order. Leo..

JeremyBeare: Yup I can now confirm it is the Amiibo. But that is weird. Surely if it is a problem with the Amiibo it would not allow the looping track to work properly either?

It depends. Your analysis has been too vague so far. Please post a minimal but complete and tested program that demonstrates the problem, and describe what part of it does not work, ideally including the line in the program that does not behave the way you expect it to.

Wawa: Longshot. Has the SD card been used a lot. I think they can get fragmented. Try a program like Killdisk, and reload your files in order. Leo..

Well I did use an old SD card so it might be fragmented. But I plan on ordering a new SD card so that should solve it if it is the fragmenting issues.

arduinodlb: It depends. Your analysis has been too vague so far. Please post a minimal but complete and tested program that demonstrates the problem, and describe what part of it does not work, ideally including the line in the program that does not behave the way you expect it to.

I will post the most update code tonight. But as I mentioned the code all works. It is doing everything it is supposed to but one intro .wav file in particular starts to play, chokes and then the program carries on as normal continuing to play the Amiibo's loop .wav file.

I managed to prove it was that one Amiibo in particular by reallocating what .wav file was that Amiibo's intro .wav file. And no matter which wav file it was, length, size, etc it would have the same problem. I even took the original .wav file of the problem and allocated it to another Amiibo. It worked perfectly. So there is something to do with that Amiibo.

Again I will post the code tonight so you can have a proper look.

As promised, this is the code I currently have!

#include <WaveHC.h>
#include <WaveUtil.h>
#include <Wire.h>
#include <Adafruit_NFCShield_I2C.h>
//#include <MemoryFree.h>

//Loading Strings into PROGMEM to save RAM
#include <avr/pgmspace.h>
//Character Intro File Names and Sounds
const char string_0[] PROGMEM = "splsqdin.wav";
const char string_1[] PROGMEM = "splsqdlp.wav";
const char string_2[] PROGMEM = "splfinin.wav";
const char string_3[] PROGMEM = "splfinlp.wav";
const char string_4[] PROGMEM = "splminin.wav";
const char string_5[] PROGMEM = "splminlp.wav";

// Then set up a table to refer to your strings.

const char* const string_table[] PROGMEM =      
{   
  string_0, string_1, string_2, string_3, string_4, string_5, //Splatoon Wave
 };

char buffer[71];

#define IRQ 6 // this trace must be cut and rewired!
#define RESET 8

Adafruit_NFCShield_I2C nfc(IRQ, RESET);

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()
uint32_t versiondata;

//My Added Variables
uint32_t lastcard = 0;
uint32_t currentcard = 1;
uint32_t CID = 0;
boolean songplaying = false;

//Loop()
uint32_t cardidentifier = 0;
uint8_t success;
uint8_t uid[] = { 0, 0, 0, 0, 0, 0, 0 }; // Buffer to store the returned UID
uint8_t uidLength; // Length of the UID (4 or 7 bytes depending on ISO14443A card type)
 
//////////////////////////////////// SETUP

void setup() {
  // set up Serial library at 9600 bps
  Serial.begin(115200);
    
  PgmPrintln("Amiibo Scanner");
  
  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();
  
  // find Adafruit RFID/NFC shield
  nfc.begin();

  versiondata = nfc.getFirmwareVersion();
  if (! versiondata) {
    Serial.print(F("Didn't find PN53x board"));
    while (1); // halt
  }
  // Got ok data, print it out!
  Serial.print(F("Found chip PN5")); Serial.println((versiondata>>24) & 0xFF, HEX);
  Serial.print(F("Firmware ver. ")); Serial.print((versiondata>>16) & 0xFF, DEC);
  Serial.print('.'); Serial.println((versiondata>>8) & 0xFF, DEC);
  
  // configure board to read RFID tags
  nfc.SAMConfig();
  
  //enable timeout waiting for cards
  nfc.setPassiveActivationRetries(50);

}

/////////////////////////////////// LOOP

unsigned digit = 0;

void loop() 
{
  //Memory Checker
  //Serial.print(F("Memory Available = "));
  //Serial.println(freeMemory());
  
  // wait for RFID card to show up!
  Serial.println(F("Waiting for an Amiibo ..."));
    
  // Wait for an ISO14443A type cards (Mifare, etc.). When one is found
  // 'uid' will be populated with the UID, and uidLength will indicate
  // if the uid is 4 bytes (Mifare Classic) or 7 bytes (Mifare Ultralight)
  success = nfc.readPassiveTargetID(PN532_MIFARE_ISO14443A, uid, &uidLength);

  cardidentifier = 0;
  CID = 999; 
  if (success) 
  {
    // Found a card!
    Serial.print(F("Amiibo detected #"));
    // turn the four byte UID of a mifare classic into a single variable #
    cardidentifier = uid[3];
    cardidentifier <<= 8; cardidentifier |= uid[2];
    cardidentifier <<= 8; cardidentifier |= uid[1];
    cardidentifier <<= 8; cardidentifier |= uid[0];
    Serial.println(cardidentifier);
    
    //Check the previous card
    (lastcard = currentcard);
    (currentcard = cardidentifier);
    
    Serial.print(F("Last Amiibo:    #"));
    Serial.println(lastcard);
    Serial.print(F("Current Card:"));
    Serial.println(currentcard);
    
    // Check Character ID
      // Try to read the Character info page (#21)
      uint8_t charID[32];
      success = nfc.mifareultralight_ReadPage (21, charID);
      
    if (success)
    {
        // turn page 21 into a character ID
      CID = charID[6];
      CID <<= 8; CID |= charID[6];
      CID <<= 8; CID |= charID[5];
      CID <<= 8; CID |= charID[4];
      CID <<= 8; CID |= charID[3];
      CID <<= 8; CID |= charID[2];
      CID <<= 8; CID |= charID[1];
      CID <<= 8; CID |= charID[0];
      Serial.println("Character Number: ");
      Serial.println(CID);
    
      if (currentcard == lastcard) 
      {
      /*
        If there is no song playing, play a song.
      */
        if (songplaying == false) 
        {
          //Squid (Splatoon)
          if (CID == 196616) {strcpy_P(buffer, (char*)pgm_read_word(&(string_table[1]))); playfile(buffer); }
          if (CID == 65544) {strcpy_P(buffer, (char*)pgm_read_word(&(string_table[3]))); playfile(buffer); }
          if (CID == 131080) {strcpy_P(buffer, (char*)pgm_read_word(&(string_table[5]))); playfile(buffer); }
        }
        
        songplaying = wave.isplaying; 
      }
      /*
        There is no song playing, play the intro sequence!
      */
      else 
      {
        //Squid (Splatoon)
        if (CID == 196616) { strcpy_P(buffer, (char*)pgm_read_word(&(string_table[0]))); playcomplete(buffer); }
        if (CID == 65544) {strcpy_P(buffer, (char*)pgm_read_word(&(string_table[2]))); playfile(buffer); }
        if (CID == 131080) { strcpy_P(buffer, (char*)pgm_read_word(&(string_table[4]))); playcomplete(buffer); }
      }
    }
    else 
    {
      //if (currentcard == lastcard) 
      //{
       // Serial.println("CID else");
        wave.stop();
      //}  
      lastcard = 123456;
      currentcard = 654321;
      songplaying = false;
    }
  } 

   //If the Amiibo is gone, stop the song.
  else 
    {
      //if (currentcard == lastcard) 
      //{
        //Serial.println("UID else");
        wave.stop();
      //}  
      lastcard = 321123;
      currentcard = 123321;
      songplaying = false;
    }  
}

/////////////////////////////////// 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
*/
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) {
  wave.stop();
  if (!file.open(root, name)) {
    PgmPrint("Couldn't open file ");
    Serial.println(name);
    return;
  }
  if (!wave.create(file)) {
    PgmPrintln("Not a valid WAV");
    return;
  }
  // ok time to play!
  wave.play();
}