Audio files corrupt after some time !

Status
Not open for further replies.
Hi !

I have a project of 11 audio players running in a small theme park. It is mounted in a boatride and it reads RFID data from the serial input and plays files on different locations. Everything is running fine except that the files (or SDHC card) will get corrupt after 3 weeks of usage. When the park's maintenance team replaces the files on the same SDHC, everything is fine again. (for about 3 weeks lol)

I used the read-only simplified SD library from Mr. Stoffregen and i formatted all the cards using SDFormatter before putting anything on the cards. (mac)
I also produced the sound files and it's very unlikely there's something incorrect with the encoding. I used quality Sandisk 8GB SDHC cards. I am also using a quality Meanwell 5v power supply.

I must add that every ride cycle (about 10 minutes) the units will be disconnected for 30 secs. This is because the boat will recharge the on-board battery. The environment is very humid and warm but i couldn't imagine this is why the files become corrupt.

Hopefully you can find something incorrect in my code.... (?)


Code:
#include <SD.h>
#include <Audio.h>
#include <Wire.h>
#include <SPI.h>

// GUItool: begin automatically generated code
AudioPlaySdWav           B_Player;     //xy=79,257
AudioPlaySdWav           A_Player;       //xy=81,172
AudioEffectFade          B_Fader_L;          //xy=264,244
AudioEffectFade          B_Fader_R;          //xy=264,277
AudioEffectFade          A_Fader_L;          //xy=265,142
AudioEffectFade          A_Fader_R;          //xy=265,178
AudioMixer4              mixer_Left ;         //xy=464,164
AudioMixer4              mixer_Right;         //xy=468,261
AudioOutputI2S           audioOutput;    //xy=649,211
AudioConnection          patchCord1(B_Player, 0, B_Fader_L, 0);
AudioConnection          patchCord2(B_Player, 1, B_Fader_R, 0);
AudioConnection          patchCord3(A_Player, 0, A_Fader_L, 0);
AudioConnection          patchCord4(A_Player, 1, A_Fader_R, 0);
AudioConnection          patchCord5(B_Fader_L, 0, mixer_Left, 1);
AudioConnection          patchCord6(B_Fader_R, 0, mixer_Right, 1);
AudioConnection          patchCord7(A_Fader_L, 0, mixer_Left, 0);
AudioConnection          patchCord8(A_Fader_R, 0, mixer_Right, 0);
AudioConnection          patchCord9(mixer_Left, 0, audioOutput, 0);
AudioConnection          patchCord10(mixer_Right, 0, audioOutput, 1);
AudioControlSGTL5000     sgtl5000_1;     //xy=94,523
// GUItool: end automatically generated code


// Pinout for SDCARD on audio adaptor board
#define SDCARD_CS_PIN    10
#define SDCARD_MOSI_PIN  7
#define SDCARD_SCK_PIN   14

// Program variables
String    inMessage ;      // Holds the latest incoming serial message
int       parseTimer = 30;    // Timeout for WAV parsing after call
int       fadeTime = 3000;    // Global fade time
int       cpuCurrent ;        // Holds the current cpu value when 'cpu' command has been called
int       cpuMax;             // Holds the max cpu when 'cpu' command has been called
int       memoryCurrent;      // Holds the current memory value when 'mem' command has been called
int       memoryMax;          // Holds the max memory when 'mem' command has been called
int       cpuCounter ;        // used for incrementing in do-Loop (yes i know we can do this differently)
int       memoryCounter ;     // used for incrementing in do-Loop (yes i know we can do this differently)
int       show1Cycles ;       // Holds the number of shows played
int       show2Cycles ;       // Holds the number of shows played
int       show3Cycles ;       // Holds the number of shows played
int       show4Cycles ;       // Holds the number of shows played
int       show5Cycles ;       // Holds the number of shows played
int       show6Cycles ;       // Holds the number of shows played
int       showStatus = 0;     // Keeps track of the show state, so the same show isn't triggered again

void setup() {

  Serial.begin(9600);
  Serial1.begin(9600);
  Serial.setTimeout(50);
  Serial1.setTimeout(50);

  // Audio memory allocation
  AudioMemory(16);

  // Activate the chip and default volume settings
  sgtl5000_1.enable();
  sgtl5000_1.volume(0.5);

  // Default mixer settings
  mixer_Left.gain(0, 0.6);
  mixer_Left.gain(1, 0.6);
  mixer_Right.gain(0, 0.6);
  mixer_Right.gain(1, 0.6);

  SPI.setMOSI(SDCARD_MOSI_PIN);
  SPI.setSCK(SDCARD_SCK_PIN);
  if (!(SD.begin(SDCARD_CS_PIN))) {
    // Stop here, but print a message repetitively
    while (1) {
      Serial.println(F("Unable to access the SD card"));
      delay(500);
    }
  }
}

void loop() {

  // Read from the UART serial
  if (Serial.available()) {
    inMessage = Serial.readString();
    Serial.print(F("USB : "));
    Serial.println(inMessage);
    msgEval();
  }
  // Read from the hardware port (RFID reader)
  if (Serial1.available()) {
    inMessage = Serial1.readString();
    Serial.print(F("Serial : "));
    Serial.println(inMessage);
    msgEval();
  }
}



Code:
void msgEval() {

  // Player A
  if (inMessage == "01\r" && showStatus != 1) {
    Serial.println(F("Playing TR01"));
    Serial1.println(F("Playing TR01"));
    showStatus = 1;
    show1Cycles++ ;
    inMessage = "" ;

    // Mixer settings
    A_Fader_L.fadeIn(fadeTime);
    A_Fader_R.fadeIn(fadeTime);
    B_Fader_L.fadeOut(fadeTime);
    B_Fader_R.fadeOut(fadeTime);

    // Play the files
    A_Player.play("1.WAV"); // Player A
    delay(fadeTime + 100);
    B_Player.stop(); // Player
    delay(parseTimer);
  }

  // Player B
  if (inMessage == "02\r" && showStatus != 2) {
    Serial.println(F("Playing TR02"));
    showStatus = 2;
    show2Cycles++ ;
    inMessage = "" ;

    // Track 2
    delay(3000);
    B_Player.play("2.WAV");
    delay(parseTimer);

    // Mixer settings
    A_Fader_L.fadeOut(fadeTime);
    A_Fader_R.fadeOut(fadeTime);
    B_Fader_L.fadeIn(fadeTime);
    B_Fader_R.fadeIn(fadeTime);

    // Stop the previous track
    delay(fadeTime + 100);
    A_Player.stop();
  }

  // Player A
  if (inMessage == "03\r" && showStatus != 3) {
    Serial.println(F("Playing TR03"));
    delay(5000);
    showStatus = 3;
    show3Cycles++ ;
    inMessage = "" ;

    // Track 3
    A_Player.play("3.WAV");
    delay(parseTimer);

    // Mixer settings
    B_Fader_L.fadeOut(fadeTime);
    B_Fader_R.fadeOut(fadeTime);
    A_Fader_L.fadeIn(fadeTime);
    A_Fader_R.fadeIn(fadeTime);

    // Stop the previous track
    delay(2000);
    B_Player.stop();
  }

  // Player B
  if (inMessage == "04\r" && showStatus != 4) {
    // Play the new track
    Serial.println(F("Playing TR04"));
    showStatus = 4;
    show4Cycles++ ;
    inMessage = "" ;

    // Track04
    B_Player.play("4.WAV");
    delay(parseTimer);

    // Mixer settings
    A_Fader_L.fadeOut(fadeTime);
    A_Fader_R.fadeOut(fadeTime);
    B_Fader_L.fadeIn(fadeTime);
    B_Fader_R.fadeIn(fadeTime);

    // Stop the previous track
    delay(fadeTime + 100);
    A_Player.stop();
  }

  // Player A
  if (inMessage == "05\r" && showStatus != 5) {
    Serial.println(F("Playing TR05"));
    showStatus = 5;
    show5Cycles++ ;
    inMessage = "" ;

    // Track 05
    A_Player.play("5.WAV");
    delay(parseTimer);

    // Mixer settings
    B_Fader_L.fadeOut(fadeTime);
    B_Fader_R.fadeOut(fadeTime);
    A_Fader_L.fadeIn(fadeTime);
    A_Fader_R.fadeIn(fadeTime);

    // Stop the previous track
    delay(fadeTime + 100);
    B_Player.stop();

    delay(22000);

    // Player B
    Serial.println(F("Playing TR06"));
    showStatus = 5;
    show6Cycles++ ;
    inMessage = "" ;

    // Track06
    B_Player.play("6.WAV");
    delay(parseTimer);

    // Mixer settings
    A_Fader_L.fadeOut(fadeTime);
    A_Fader_R.fadeOut(fadeTime);
    B_Fader_L.fadeIn(fadeTime);
    B_Fader_R.fadeIn(fadeTime);

    // Stop the previous track
    delay(fadeTime + 100);
    A_Player.stop();

  }


  if (inMessage == "stop\r" && showStatus != 0) {
    Serial.println(F("Stopped !"));
    showStatus = 0;
    A_Fader_L.fadeOut(1000);
    B_Fader_L.fadeOut(1000);
    A_Fader_R.fadeOut(1000);
    B_Fader_R.fadeOut(1000);

    delay(1100);
    A_Player.stop();
    B_Player.stop();

  }

  if (inMessage == "?\r") {
    Serial.println(F("---Show Cycles---"));
    Serial.print(F("Show 1 : "));
    Serial.println(show1Cycles);

    Serial.print(F("Show 2 : "));
    Serial.println(show2Cycles);

    Serial.print(F("Show 3 : "));
    Serial.println(show3Cycles);

    Serial.print(F("Show 4 : "));
    Serial.println(show4Cycles);

    Serial.print(F("Show 5 : "));
    Serial.println(show5Cycles);
    Serial.println(F("-----------------"));
  }

  if (inMessage == "clearshows\r") {
    Serial.println(F("---Show Cycles---"));
    show1Cycles = 0;
    show2Cycles = 0;
    show3Cycles = 0;
    show4Cycles = 0;
    show5Cycles = 0;
    Serial.print(F("Show 1 : "));
    Serial.println(show1Cycles);

    Serial.print(F("Show 2 : "));
    Serial.println(show2Cycles);

    Serial.print(F("Show 3 : "));
    Serial.println(show3Cycles);

    Serial.print(F("Show 4 : "));
    Serial.println(show4Cycles);

    Serial.print(F("Show 5 : "));
    Serial.println(show5Cycles);
    Serial.println(F("-----------------"));
  }

  if (inMessage == "cpu\r") {
    Serial.println(F("-----CPU test started-----"));
    do  {
      cpuCurrent = AudioProcessorUsage();
      Serial.print(F("CPU : "));
      Serial.println(cpuCurrent);
      cpuCounter++ ;
      delay(75);
    } while (cpuCounter < 100);
    cpuCounter = 0;
    cpuMax = AudioProcessorUsageMax();
    Serial.println(F("-----CPU test complete !-----"));
    Serial.println(F("-----------------------------"));
    Serial.print(F("Max CPU : "));
    Serial.println(cpuMax);
    AudioProcessorUsageMaxReset();
  }

  if (inMessage == "mem\r") {
    Serial.println(F("-----MEMORY test started-----"));
    do  {
      memoryCurrent = AudioMemoryUsage();
      Serial.print(F("Memory : "));
      Serial.println(memoryCurrent);
      memoryCounter++ ;
      delay(75);
    } while (memoryCounter < 100);
    memoryCounter = 0;
    memoryMax = AudioMemoryUsageMax();
    Serial.println(F("-----MEMORY test complete !-----"));
    Serial.println(F("--------------------------------"));
    Serial.print(F("Max Memory : "));
    Serial.println(memoryMax);
    AudioMemoryUsageMaxReset();
  }
}
 
I was having this same issue. My solution was to stop using SanDisk. I've begun using ADATA brand SHDC cards. If you have access to a MicroCenter store, their branded SD cards are actually ADATA and are about half the price ;) So far so good. No more file corruptions.
 
I was having this same issue. My solution was to stop using SanDisk. I've begun using ADATA brand SHDC cards. If you have access to a MicroCenter store, their branded SD cards are actually ADATA and are about half the price ;) So far so good. No more file corruptions.


Good to know there are more people having this issue. ADATA is pretty hard to get in my country (The Netherlands) would Kingston be a substitute ?
 
Any idea if the bad card was a genuine Sandisk? The market is flooded with counterfeits claiming to be Sandisk.


Hi Paul,

I got the cards from 2 different vendors, at least one of them was a trusted dealer and one of the top vendors here in The Netherlands. I did some random card testing and the speed also looked good. The packaging was all original, no spelling errors or anything. Keep in mind all my 11 projects are failing. they are either all counterfeits or all original :p

Have you ever seen the same issue before ?
 
I have not tried Kingston. I do have a PNY that has also had no problems. My SanDisks I was having to reformat every couple of weeks or so.
 
I saw something like this just once, but at the time wrote it off as a low quality SD card (which is was).

Maybe there is something else wrong? Hard to say.

If I wanted to recreate your circumstances here, how would I go about replacing the RFID reader? Maybe another Teensy could send the same or similar-enough commands? Any chance you could help with that part?
 
I'm actually experiencing the same problem. I'm kind of scratching my head, going mad trying to find the source of the problem.

I use a Teensy 3.2 with an XBee S2C Pro and an audio shield.

When powering down the Teensy, it seems that there is an X (small, maybe 1%?) amount of chance that the audio file being read on the SD card will become corrupt. When looking at the content of the SD card afterwards, I can usually see files named something like "†¬" littering the card. From the windows GUI, it is impossible to delete these files (I guess because they're not really files, just garbage from the audio file that isn't recognized anymore). I have to format the SD card for these to disappear. I'm using SanDisks SD card I can confirm they're genuine.

It seems like the header of the file just gets deleted so it's not recognized anymore but the content is still there and sometimes the content is misread as files headers? Maybe?

I'm really confused by the problem, but it's becoming a real problem for my project. It doesn't happen often, but it's still too often that it's becoming a real problem.

Here's the concerned code. There's a lot of other stuff going on that is completely unrelated the audio code. Posting parsers and string manipulations doesn't really seem relevant in this case (unless a faulty non null terminated string could cause the problem, but it seems extremely unlikely since the problem never happens while the Teensy is running, only when powering it down). And it seems like a bug of this nature would manifest itself in different ways also (which it does not), not by simply corrupting the audio file on the SD card...

I should point out that they're is one file that can be read, deleted and written to while an audio file is playing, not sure if this can have an impact...

Code:
#include <Audio.h>
#include <Wire.h>
#include <SPI.h>
#include <SD.h>
#include <SerialFlash.h>
#include <stdlib.h>

//
#define DEBUG 1
#define NOP 122
#define VOLUME_NORMAL 0.8
#define COMMAND_DELAY 500
#define CANCEL 120

#define COMMAND_LENGTH 200

#define NB_OF_TRACKS 5

// Use these with the audio adaptor board
#define SDCARD_CS_PIN    10
#define SDCARD_MOSI_PIN  7
#define SDCARD_SCK_PIN   14



//Arg types
#define STRING 0
#define ENTIER 1
#define REAL 2

// Use these for the SD+Wiz820 or other adaptors
//#define SDCARD_CS_PIN    4
//#define SDCARD_MOSI_PIN  11
//#define SDCARD_SCK_PIN   13    

struct AudioFile{
  AudioPlaySdWav playWav;
  AudioEffectFade fadeL;
  //unsigned long timeBeforeStopTrack;
  unsigned long fadeOutStartedAt = 0;
  bool isFadeOutStarted = false;
  unsigned long activeFadeOutTime = 1;
  char* currentFilename = NULL;
  bool wasPlaying = false;
};

typedef struct AudioFile Track;

Track track1;
Track track2;
Track track3;
Track track4;
Track track5;

Track * allTracks[] = {&track1, &track2, &track3, &track4, &track5};

char ** filenames;// = {"1.WAV", "2.WAV", "3.WAV", "4.WAV", "5.WAV", "6.WAV", "7.WAV", "8.WAV", "9.WAV", "10.WAV", "11.WAV", "12.WAV", "13.WAV", "14.WAV", "15.WAV", "16.WAV", "17.WAV", "18.WAV", "19.WAV", "20.WAV", "21.WAV", "22.WAV", "23.WAV", "24.WAV"};

//********Les mixeurs ont 4 entrées et une seule sortie !!!!!*********
//Effets
/*AudioEffectChorus        chorus;
AudioEffectFlange        flange;
AudioEffectDelay         delai;
AudioFilterBiquad        filtre;
AudioEffectBitcrusher    bitcrusher;*/

//AudioMixer4              mixerSampleLMixer;
AudioMixer4              mixerSampleA;
AudioMixer4              mixerSampleC;
AudioMixer4              mixerSampleM;
/*AudioMixer4              delaiMixer1;
AudioMixer4              delaiMixer2;
AudioMixer4              mixerSampleMain;*/

//Possèdent deux entrées L/R
AudioOutputI2S           audioOutput;

AudioConnection          patchCord1(track1.playWav, 0, track1.fadeL, 0);
AudioConnection          patchCord2(track2.playWav, 0, track2.fadeL, 0);
AudioConnection          patchCord3(track3.playWav, 0, track3.fadeL, 0);
AudioConnection          patchCord4(track4.playWav, 0, track4.fadeL, 0);
AudioConnection          patchCord5(track5.playWav, 0, track5.fadeL, 0);

//Premier niveau de mixers (48 tracks (24 stereos) ->  12 mixers)
AudioConnection          patchCord6(track1.fadeL, 0, mixerSampleA, 0);
AudioConnection          patchCord7(track2.fadeL, 0, mixerSampleA, 1);
AudioConnection          patchCord8(track3.fadeL, 0, mixerSampleA, 2);
AudioConnection          patchCord9(track4.fadeL, 0, mixerSampleA, 3);
AudioConnection          patchCord10(track5.fadeL, 0, mixerSampleC, 0);

//2e niveau de mixers ( 12 mixers ->  4 mixers)
AudioConnection          patchCord11(mixerSampleA, 0, mixerSampleM, 0);
AudioConnection          patchCord12(mixerSampleC, 0, mixerSampleM, 1);

//effets
/*AudioConnection          patchCord13(mixerSampleM, 0, chorus, 0);
AudioConnection          patchCord14(chorus, 0, flange, 0);
AudioConnection          patchCord15(flange, 0, bitcrusher, 0);
AudioConnection          patchCord16(bitcrusher, 0, delaiMixer2, 0);
AudioConnection          patchCord17(bitcrusher, 0, delai, 0);
AudioConnection          patchCord18(delai, 0, delaiMixer1, 0);
AudioConnection          patchCord19(delai, 1, delaiMixer1, 1);
AudioConnection          patchCord20(delai, 2, delaiMixer1, 2);
AudioConnection          patchCord21(delai, 3, delaiMixer1, 3);
AudioConnection          patchCord22(delaiMixer1, 0, delaiMixer2, 1);
AudioConnection          patchCord23(delaiMixer2, 0, filtre, 0);
AudioConnection          patchCord24(filtre, 0, mixerSampleMain, 0);*/

//3e niveau de mixers (2 mixers -> audio output L/R)
AudioConnection          patchCord25(mixerSampleM, 0, audioOutput, 0);

AudioControlSGTL5000     sgtl5000_1;

//Variable pour recevoir et envoyer de l'information
char* varQueuedCommand = NULL;
unsigned char ACK;
File file;

//Les index pour les tracks (ressource audio) et les files (les pistes sur la carte SD)
int trackIndex = 0;
int fileIndex = 0;

unsigned long* defaultFadeOut;
unsigned long* defaultFadeIn;

//Variables pour timers
unsigned long commandStartedAt = 0;
bool isCommandDelayStarted = false;

char* fileBuffer;

float volumeValue = 0.0;

int NB_OF_FILES = 0;

//OPTIONS
bool track_loop = false;
bool files_loop = false; //Utilisé seulement en mode index (le mode est défini sur le Master)
bool isLastFile = false;

//Variables pour saisir les messages du XBEE
char* thisCommand = new char[COMMAND_LENGTH];
int thisCommandIndex = 0;
int endBufferCounter = 0;
bool check1 = false;
bool checkStart1 = false;
bool checkStart2 = false;
bool checkStart3 = false;


void setup() {
  //Pour communication avec le moniteur serial
  Serial.begin(9600);

  //Begin HW serial
  Serial1.begin(230400);

  // Audio connections require memory to work.  For more
  // detailed information, see the MemoryAndCpuUsage example
  AudioMemory(70);

  delay(500);

  if (DEBUG)
  {
    Serial.println("start");
  }
  
  //INIT SD card
  SPI.setMOSI(SDCARD_MOSI_PIN);
  SPI.setSCK(SDCARD_SCK_PIN);
  if (!(SD.begin(SDCARD_CS_PIN))) {
    fail("Unable to access the SD card");
    blinkTeensyLight(1);
  }

  if (SD.exists("error.log"))
  {
    SD.remove("error.log");
  }

  clearCommand();
  
  //Check how many tracks
  for (int i = 0; i < 98; ++i)
  {
      int thisAdd = 0;
      if (i >= 9)
      {
        thisAdd = 1;  
      }
      int theSize = 1 + thisAdd + 5;
      fileBuffer = new char[theSize];
      sprintf(fileBuffer, "%d", i+1);
      fileBuffer[theSize-1] = '\0';
      fileBuffer[theSize-2] = 'V';
      fileBuffer[theSize-3] = 'A';
      fileBuffer[theSize-4] = 'W';
      fileBuffer[theSize-5] = '.';
      if (SD.exists(fileBuffer))
      {
        ++NB_OF_FILES;
      }
      else
      {
        free(fileBuffer);
        break;
      }
      free(fileBuffer);
  }

  if (DEBUG)
  {
    Serial.println("apres files audio");
  }
  
  filenames = new char*[NB_OF_FILES];
  for (int i = 0; i < NB_OF_FILES; ++i)
  {
      int thisAdd = 0;
      if (i >= 9)
      {
        thisAdd = 1;  
      }
      int theSize = 1 + thisAdd + 5;
      filenames[i] = new char[theSize];
      sprintf(filenames[i], "%d", i+1);
      filenames[i][theSize-1] = '\0';
      filenames[i][theSize-2] = 'v';
      filenames[i][theSize-3] = 'a';
      filenames[i][theSize-4] = 'w';
      filenames[i][theSize-5] = '.';
  }
  
  if (NB_OF_FILES == 0)
  {
    fail("No tracks on SD card! (1.WAV, 2.WAV, etc...");
    blinkTeensyLight(2);
  }
  defaultFadeOut = new unsigned long[NB_OF_FILES];
  defaultFadeIn = new unsigned long[NB_OF_FILES];
  for (int i = 0; i < NB_OF_FILES; ++i)
  {
    defaultFadeOut[i] = 5000;
    defaultFadeIn[i] = 5000;  
  }

  unsigned int volumeSize = 0;
  if (SD.exists("VOLUME.txt"))
  {
    file = SD.open("VOLUME.txt");
    while (file.available())
    {
      ++volumeSize;
      file.read();
    }
    file.close(); 
  }
  
  if (SD.exists("VOLUME.txt"))
  {
    int index = 0;
    file = SD.open("VOLUME.txt");
    fileBuffer = new char[volumeSize];
    while (file.available())
    {
      fileBuffer[index++] = file.read();
    }
    file.close();
    String volumeString = String(fileBuffer);
    //Serial.print("volumeString : ");
    //Serial.println(volumeString);
    volumeValue = volumeString.toFloat();
  }
  else
  {
    volumeValue =  0.7;
  }
  
  Serial.print("volume value at start : ");
  Serial.println(volumeValue);
  if (SD.exists("VOLUME.txt"))
  {
    free(fileBuffer);
  }
  
  
  mixerSampleA.gain(0, 1);
  mixerSampleA.gain(1, 1);
  mixerSampleA.gain(2, 1);
  mixerSampleA.gain(3, 1);
  mixerSampleC.gain(0, 1);
  mixerSampleC.gain(1, 1);
  mixerSampleC.gain(2, 1);
  mixerSampleC.gain(3, 1);
  mixerSampleM.gain(0, volumeValue);
  mixerSampleM.gain(1, volumeValue);

  sgtl5000_1.enable();
  sgtl5000_1.volume(VOLUME_NORMAL); // 0 (muted) to 0.99, If over, it will mute the volume. 0,8023 is 0dB. 
  
  if (SD.exists("ACK.txt"))
  {
    file = SD.open("ACK.txt");
    if (file.available())
    {
      ACK = file.read();  
      if (DEBUG)
      {
        Serial.print("ACK is set to : ");
        Serial.println(ACK);  
      }
    }
    file.close();
  }
  else
  {
    fail("No ACK file on SD card!");
    blinkTeensyLight(3);
  }

  blinkTeensyLight(4);
  if (DEBUG)
  {
    Serial.println("all done");
  }
  
}


int getFileIndexFromFilename(const char* filename)
{
  for (int i = 0; i < NB_OF_FILES; ++i)
  {
    if (strcmp(filenames[i], filename) == 0)
    {
      return i;  
    }  
  }
  fail("Tried to find file index from filename, but the passed argument filename wasn't found in the filenames. Returning 0 instead! The argument was : ", filename);
  return 0;
}

void playFile(Track& thisTrack, const char* filename)
{
  // Play the specified file on the specified track.
  thisTrack.playWav.play(filename);
  if (thisTrack.currentFilename != NULL)
  {
    free(thisTrack.currentFilename);
  }
  thisTrack.currentFilename = new char[strlen(filename)+1];
  strcpy(thisTrack.currentFilename, filename);
  if (track_loop)
  {
    thisTrack.wasPlaying = true;
  }
  // A brief delay for the library read WAV info
  delay(5);
}

void stopTrack(Track& thisTrack)
{
  //Stop this track.
  thisTrack.playWav.stop();
  free(thisTrack.currentFilename);
  thisTrack.currentFilename = NULL;
  thisTrack.wasPlaying = false;
  // A brief delay for the library read WAV info
  delay(5);
}

void selectNextFile(void)
{
  if (!files_loop)
  {
    if (fileIndex < NB_OF_FILES)
    {
      ++fileIndex;
    }
  }
  else
  {
    if (fileIndex < NB_OF_FILES - 1)
    {
      ++fileIndex;
    }
    else
    {
      fileIndex = 0;  
    }
  }
}

void selectNextTrack(void)
{
  if (trackIndex < NB_OF_TRACKS - 1)
  {
    ++trackIndex;  
  }
  else
  {
    trackIndex = 0;  
  }
}

void fadeOutTrack(Track& thisTrack, unsigned long fadeOutInMIllis, bool nextTrack)
{
    thisTrack.fadeL.fadeOut(fadeOutInMIllis);
    thisTrack.activeFadeOutTime = fadeOutInMIllis;
    thisTrack.isFadeOutStarted = true;
    thisTrack.fadeOutStartedAt = millis();
    if (nextTrack)
    {
      selectNextTrack();
    }
}

void fadeInTrack(Track& thisTrack, unsigned long fadeInInMIllis, const char* filename, bool nextTrack, bool nextFile)
{
  thisTrack.fadeL.fadeOut(1);
  delay(1);
  playFile(thisTrack, filename);
  thisTrack.fadeL.fadeIn(fadeInInMIllis);
  if (nextTrack)
  {
    selectNextTrack();
  }
  if (nextFile)
  {
    selectNextFile();
  }
}

void fadeOutTrack()
{
  int effectiveIndex = fileIndex - 1;
  if (effectiveIndex < 0)
  {
    Serial.println("stop 1");
    fadeOutTrack(1);
  }
  else
  {
    Serial.print("stop default : ");
    Serial.println(defaultFadeOut[effectiveIndex]);
    /*Serial.print("this is the default value because the index used is : ");
    Serial.print(effectiveIndex);
    Serial.print(" and the values in the array are : ");
    for (int i = 0; i < NB_OF_FILES; i++)
    {
      Serial.print(defaultFadeOut[i]);
      Serial.print(", ");
    }
    Serial.println();*/
    fadeOutTrack(defaultFadeOut[effectiveIndex]);
  }
}

void fadeOutTrack(unsigned long fadeOutInMillis)
{
  fadeOutTrack(*allTracks[trackIndex], fadeOutInMillis, true);
}

void fadeOutTrack(const char* fileToStop)
{
  for (int i = 0; i < NB_OF_TRACKS; ++i)
  {
    if (strcmp(allTracks[i] -> currentFilename, fileToStop) == 0)
    {
      int thisFileIndex = getFileIndexFromFilename(fileToStop);
      fadeOutTrack(*allTracks[i], defaultFadeOut[thisFileIndex], false);
    }
  }
}

void fadeOutTrack(const char* fileToStop, long fadeOutInMillis)
{
  for (int i = 0; i < NB_OF_TRACKS; ++i)
  {
    if (strcmp(allTracks[i] -> currentFilename, fileToStop) == 0)
    {
      fadeOutTrack(*allTracks[i], fadeOutInMillis, false);
    }
  }
}

void fadeInTrack()
{
  if (fileIndex < NB_OF_FILES && fileIndex >= 0)
  {
    fadeInTrack(defaultFadeIn[fileIndex]);
  }
}

void fadeInTrack(unsigned long fadeInInMillis)
{
  if (fileIndex < NB_OF_FILES && fileIndex >= 0)
  {
    if (!allTracks[trackIndex] -> playWav.isPlaying() && fileIndex < NB_OF_FILES)
    {
      fadeInTrack(*allTracks[trackIndex], fadeInInMillis, filenames[fileIndex], false, true);
    }
  }
}

void fadeInTrack(const char* fileToPlay)
{
  Serial.print("Will fadeInTrack : ");
  Serial.println(fileToPlay);
  int thisFileIndex = getFileIndexFromFilename(fileToPlay);
  fadeInTrack(fileToPlay, defaultFadeIn[thisFileIndex]);
}

void fadeInTrack(const char* fileToPlay, unsigned long fadeInInMillis)
{
  fadeInTrack(*allTracks[trackIndex], fadeInInMillis, fileToPlay, true, false);  
}

boolean trackIsPlaying(const char* fileToPlay)
{
  Serial.println("will try to see if track is playing.");
  for (int i = 0; i < NB_OF_TRACKS; ++i)
  {
    if (strcmp(allTracks[i] -> currentFilename, fileToPlay) == 0 && allTracks[i] -> playWav.isPlaying() && !allTracks[i] -> isFadeOutStarted)
    {
      Serial.println("Is playing!.");
      return true;
    }
  }
  Serial.println("Is not playing.");
  return false;
}

void volumeDown()
{
  volumeValue -= 0.1;
  if (volumeValue < 0.0)
  {
    volumeValue = 0.0;  
  }
  setVolumeAtValue(volumeValue);
}

void volumeUp()
{
  
  volumeValue += 0.1;    
  
  if (volumeValue > 1.0)
  {
    volumeValue = 1.0;  
  }
  setVolumeAtValue(volumeValue);
}

void setVolumeAtValue(float thisVolumeValue)
{
  if (thisVolumeValue >= 0.0 && thisVolumeValue <= 1.0)
  {
    mixerSampleM.gain(0, thisVolumeValue);
    mixerSampleM.gain(1, thisVolumeValue);
    volumeValue = thisVolumeValue;
    if (SD.exists("VOLUME.txt"))
    {
      SD.remove("VOLUME.txt");
    }
    file = SD.open("VOLUME.txt", FILE_WRITE);
    if (file)
    {
      file.print(volumeValue);
      file.flush();
      file.close();
    }
  }
}

void stopAllTracks()
{
  for (int i = 0; i < NB_OF_TRACKS; ++i)
  {
    fadeOutTrack(*allTracks[i], 1, false);
  }
}


void loop() {
  int isAvailable = 0;
  // Take data received from the serial monitor and pass it to the HW UART
  isAvailable = Serial1.available();
  if (isAvailable > 0)
  {
    if (false)
    {
      Serial.print("Nb of available chars from XBee : ");
      Serial.println(isAvailable);  
    }
    //Serial.print("received data : ");
    for (int i = 0; i < isAvailable; ++i)
    {
      if (endBufferCounter < 3)
      {
        char thisChar = Serial1.read();
        //Serial.print(thisChar);
        if (!checkStart1)
        {
          if (thisChar == '_')
          {
            checkStart1 = true; 
          } 
        }
        else if (!checkStart2)
        {
          if (thisChar == '_')
          {
            checkStart2 = true; 
          } 
        }
        else if (!checkStart3)
        {
          if (thisChar == '_')
          {
            checkStart3 = true; 
          } 
        }
        else
        {
          thisCommand[thisCommandIndex] = thisChar;
          if (thisCommand[thisCommandIndex] == '-')
          {
            ++endBufferCounter;
          }
          else
          {
            endBufferCounter = 0;
          }
          ++thisCommandIndex;
        }
      }
      else
      {
        thisCommand[thisCommandIndex-3] = NULL;
        byte thisByte = Serial1.read();
        //Serial.print(thisByte);
        if (false)
        {
          Serial.print("this is byte value from XBee after '---' : ");
          Serial.println(thisByte);  
        }
        if (!check1 && thisByte == 13)
        {
          check1 = true;
        }
        else if (check1 && thisByte == 10)
        {
          //Serial.println();
          queueCommand();
          clearCommand();
          check1 = false;
          checkStart1 = false;  
          checkStart2 = false;  
          checkStart3 = false;  
          break;
        }
        else
        {
          //Serial.println();
          clearCommand();
          check1 = false;
          checkStart1 = false;  
          checkStart2 = false;  
          checkStart3 = false;
          break;
        }
      }
    }
    //Serial.println();
  }

  for (int i = 0; i < NB_OF_TRACKS; ++i)
  {
    Track * thisTrack = allTracks[i];
    if (thisTrack -> isFadeOutStarted)
    {
       /*//Serial.print("One track is fading out! : ");
      //Serial.print(i);
      //Serial.print(" with still ");
      //Serial.print(thisTrack -> timeBeforeStopTrack);
      //Serial.println(" milliseconds left");*/
       unsigned long currentTime = millis();
       if ((currentTime - thisTrack -> fadeOutStartedAt) > thisTrack -> activeFadeOutTime)
       {
         //Serial.print("Stopping track : ");
         //Serial.println(i);
          thisTrack -> activeFadeOutTime = 1;
          thisTrack -> isFadeOutStarted = false;
          stopTrack(*thisTrack);
       }
    } 
    if (track_loop)
    {
      if (!thisTrack -> playWav.isPlaying() && thisTrack -> wasPlaying)
      {
        playFile(*thisTrack, thisTrack -> currentFilename);
      }
    }
  }

  if (isCommandDelayStarted)
  {
    unsigned long currentTime = millis();
    if ((currentTime - commandStartedAt) > COMMAND_DELAY)
    {
      isCommandDelayStarted = false;
      executeCommand();
    }
  }

  delay(1);
}

Any help would be greatly appreciated...


EDIT : Added variable definitions.
 
Last edited:
Status
Not open for further replies.
Back
Top