Code is freezing after playing a sample from SD card

Status
Not open for further replies.

MadMind

Well-known member
Hi everyone,

I'm writing to the community because I've made a code which is working fine until it gets frozen after a various amount of time...

FINAL EDIT : Problem has been finally solved by adapting the Random no repeat function for reading random files in more than 1 folder. I used a 2D array to stock the index and random values already used for each folder.

Here is the code you could use if you want to play files in different folders without repeating them before the list has been played (very useful with audio files project !!!). For those who are used to play around with pure data or max/msp it corresponds to the [URN] object :

Thx again for the ones who helped me !!!

Code:
int index_tab[4] = {0,0,0,0};           // A REGLER SI ON AUGMENTE LE NOMBRE DE DOSSIER nombre de samples deja jouées;
int sampleDejaJoues[4][100];       // Défini la taille du tableau et initialise toutes les valeurs à 0
int unplayedSample = 0;
int lastPlayedSample = -1;

int URN(int folder, int nbtotfile) {
  boolean etat = true;

  while (etat) {
    etat = false;
    unplayedSample = int(random(nbtotfile));
    for (int i = 0; i < index_tab[folder]; i++) {
      if (sampleDejaJoues[folder][i] == unplayedSample) {
        etat = true;
        break;
      }
    }
    if (index_tab[folder] == 0 && unplayedSample == lastPlayedSample) {
      etat = true;
    }
  }

  if (index_tab[folder] < nbtotfile) {
    sampleDejaJoues[folder][index_tab[folder]] = unplayedSample;
    index_tab[folder] ++;
  }
  if (index_tab[folder] == nbtotfile) {
    index_tab[folder] = 0;
    lastPlayedSample = unplayedSample;
    initSampleSelecteur(folder,nbtotfile);
  }
  return unplayedSample + 1;
}

//Init Sample

void initSampleSelecteur(int folder, int nbtotfile) {
  for (int i = 0; i < nbtotfile; i++) {
    sampleDejaJoues[folder][i] = -1;
  }
}
 
Last edited:
After making a new set of tests I realised that the problem would probably come from the second players called "// Loop tremblement" in the code.

As more than one parameter is changing at the same time for that objects serie (mixers volume, AM modulation etc...) I'm supposing that I should use the AudioInterrupts() and AudioNoInterrupts() functions. I saw this sometime but I still don't really understand precisly the in and the out even with the documentation. I couldn't find any example so it's a bit hard for me to understand the underlying concept.

Does someone could give me some examples of how to use it ?

I thank you a lot.

Have a nice day !

PS : Does the AudioInterrupt() function use the same philosophy that this Interrupt concept pointed here : https://www.pjrc.com/teensy/interrupts.html
 
Not an expert on the topic but my understanding of the noInterupts call is to lock interupts from the audio code (processing packets through yo output buffers) for a period of time while you go through updating values before enabling them again once all new values are in place. So an examples usage would be the way the mixers produce noise when overdriven (total of inputs levels+gain greater than one) so if you have code that changes the mixer one input from 0.2 to 0.6 but has not yet wound down the other inputs to compensate you will get noise transients if you have a audio processing event triggered between lines of your code (more likely to strike as your number of instructions between these steps increase.

If you do this quickly enough the various buffers will not run out, if you don't then your output will glitch anyway as buffers run empty. Not sure if this will help with your problem though.
 
Thank you for your explanation !

It seems that it doesn't solve the problem anyway as it's still freezing...

Is it possible that the problem is about a conflict between both players ? It seems to work well when one of both isn't active...
 
Might it be possible that the freeze come from the fact that there are 2 samples called from the SD card ? I know there are some restrictions about playing more than 1 sample at the same time but I've read on PJRC that it's possible to play until 4 samples at the same time with the SanDisk micro SD 16GO and that's what I've bought.

Any feedbacks ?
 
Some time ago I started work on optimizing the SD library to better handle playing multiple files at the same time. It's still considered experimental. It can only read, so turning on this optimization means you can't write to the card at all. It was done before Teensy 3.5 & 3.6, so it only works with SPI-connected cards.

To give it a try, find and edit SD_t3.h. On a mac, control-click Arduino and Show Package Contents to look inside. Windows & Linux have just regular folders for Arduino's internal stuff. See the comments in that file for info. Just uncomment 1 line to turn on the optimization.

Please let me know if that solves this problem you're seeing?
 
Hey Paul,

Thanks for your quick reply and all your work !

I only have teensy 3.2, so I guess the uncommented line won't have any effect, will it ?
 
I only have teensy 3.2, so I guess the uncommented line won't have any effect, will it ?

Yes, it will work on Teensy 3.2. You can be the judge of whether it actually helps with the problem you have. I'm curious to hear how it works for you?

If using 3.5 or 3.6, it will *not* work with the built in SD socket.
 
Sorry, I misunderstood !
I'll try it in a couple of days and I'll definitly let you know here.
Thanks !
 
Hey Paul,

I've just tried to uncomment the line you told me and now the audio files sounds glitched when they're played. So I couldn't use this method. Would you have another idea ?

Thx a lot.
 
It seems that the new code without using 2 SD players at the same time is still freezing after new tests...the code just stop after 30min or one hour...especially when the time of retrig sample are shorts... Our installation is supposed to be on for a day long...

I don't have any ideas where is it coming from... Hardware ? Code ? Are the delays too short to support a quick replay (mini = 100ms) ? Are the AudioMemory doen't support that ? It also seems to freeze when the player is retriging samples after more than 5 secondes...So it doesn't make any sense to me...It really gets me crazy so if someone gets the problem, it will save my project and our exhibition.

Thx a lot.

Code:
#include <Audio.h>
#include <Wire.h>
#include <SPI.h>
#include <SD.h>
#include <SerialFlash.h>
#include <MedianFilter.h>   //https://github.com/daPhoosa/MedianFilter
#include <RunningAverage.h> //https://playground.arduino.cc/Main/RunningAverage
#include <Bounce.h>

// GUItool: begin automatically generated code
AudioSynthNoiseWhite     noise1;         //xy=58,381
AudioPlaySdWav           playSdWav1;     //xy=73,307
AudioMixer4              mixer1;         //xy=366,321
AudioMixer4              mixer2;         //xy=366,389
AudioInputI2S            i2s2;           //xy=518,160
AudioAnalyzeRMS          rms1;           //xy=693,154
AudioOutputI2S           i2s1;           //xy=826,382
AudioConnection          patchCord1(noise1, 0, mixer1, 1);
AudioConnection          patchCord2(noise1, 0, mixer2, 1);
AudioConnection          patchCord3(playSdWav1, 0, mixer1, 0);
AudioConnection          patchCord4(playSdWav1, 1, mixer2, 0);
AudioConnection          patchCord5(mixer1, 0, i2s1, 0);
AudioConnection          patchCord6(mixer2, 0, i2s1, 1);
AudioConnection          patchCord7(i2s2, 0, rms1, 0);
AudioControlSGTL5000     sgtl5000_1;     //xy=69,91
// GUItool: end automatically generated code


//Use these with the audio adaptor board

#define SDCARD_CS_PIN    10
#define SDCARD_MOSI_PIN  7
#define SDCARD_SCK_PIN   14

#define LED 13
#define ProxiPin A3

// DECLARATION & INIT VARIABLES

// Settings fonctions

MedianFilter MedianProx(15, 0);
RunningAverage MicroRA(15);

// Déclaration des fonctions

void CalibProxiMic();
int CountingFile (File DirName);
float JaugePassage (bool DetectEvent, float TimeWindow);
float JaugePeak (bool DetectEvent, float TimeWindow);
int URN(int nbtotfile);
void TrigFile(const char *filename);
void LoopFile(const char *filename);
void initSampleSelecteur(int nbtotfile);
float Line(float arrivee, float TimeInterpol);

// Variables données

int Proxi;
float MicroRms;

float deriveeNoise;
float deriveeMic;
float MemNoise = 0;
float MemMic = 0;

int ProxiMedian = 0;
float Micro_Moyenne = 0;

// Variables calib Proxi + Micro

int TempsCalib = 5000 ;            // REGLAGE  : durée calibration.
int TempsCalibGain = 2000 ;

int ProxiMin = 1023;
float ProxiMax = 0;
float MicroMin = 1023;
float MicroMax = 0;

// Variables Calibration compensation Gain

float MicroCorrec;
float InternalSig;
float InternalSigCorrected;
float AttenuationFactor = 0.40;    // Dans calib.
float delayCompens = 0.44;          // REGLAGE entrer une valeur selon la distance par rapport au microphone.
float DetectSignal = 0;

// Variable Compteur nombre de fichiers par dossier

File root;
int NbFiles[4] = {0};

// Variables JAUGES

int NbPeak = 0;

int ThreshPeak = 20 ;              //(10 par défaut par rapport à la dérivée)

bool DetectPeak = 0;

int TpsStockagePassage = 10000 ;  //REGLAGE (Temps de stockage de la jauge Proxi)
int TpsStockagePeak = 1500;       //REGLAGE (Temps de stockage de la jauge Micro)

float jaugePeak = 0;

// Valeurs de seuil de changement d'humeur + changement de rapidité de déclenchement

int SeuilAgressif;
int Condition = 1;
int SeuilJaugeMicro = 1;              //REGLAGE (Seuil de changement d'humeur Micro)

// Variables fonction TRIGFILE

int RangeMin;
int RangeMax;
int BorneMinMin ;
int BorneMinMax ;
int BorneMaxMax ;

int resetMillis = 0;
int threshTrig = 0;
int randomMin = 50;
int randomMax = 34000;
int corpusSampleNumber = 10;   //REGLAGE (Nombre de son dans chaque dossier)

int sample_rand = 1;           // tirage au sort du numéro du sample.
String SoundFile, SoundType;
String HumeurFolder[4]  = {"serein", "timide", "hilare", "hostile"};
int selecthumeur = 0;
int previoushumeur = 1000;
int statechangeselecthumeur = 0;

// Variables Agressif

float ProxiRangeMin = 0;
float ProxiRangeMax = 0;
float ProxiValueMin = 0;
float ProxiValueMax = 0;

int AMfreqMax = 15;           // REGLAGE (fréquence max de la modulation d'amplitude)

//-------------

// MAIN CODE

// >>>>> SETUP <<<<<

void setup() {
  Serial.begin(9600);
  randomSeed(analogRead(A9));  //passer la fonction random en réelle fonction aléatoire.

  //AUDIO

  AudioMemory(70);             // Audio connections require memory to work.  For more detailed information, see the MemoryAndCpuUsage example
  // setup audio board
  SoundFile = String();
  SoundType = String(".wav");
  sgtl5000_1.enable();
  sgtl5000_1.volume(0.7);                         //REGLAGE
  sgtl5000_1.inputSelect(AUDIO_INPUT_MIC);
  sgtl5000_1.micGain(50);
  //Setup SD Card
  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("Unable to access the SD card");
      delay(1000);
    }
  }
  //Compte le nombre de fichiers dans chacun des dossiers d'humeur.

  for (int i = 0; i <= 3; i++) {
    String FileRemove = HumeurFolder[i] + "/" + "DS_STO~1";
    SD.remove(FileRemove.c_str());
    String FolderName = HumeurFolder[i] + "/";
    root = SD.open(FolderName.c_str());
    NbFiles[i] = CountingFile(root);
  }
  Serial.print("Le nombre de fichiers dans le dossier serein est de : ");
  Serial.println(NbFiles[0]);
  Serial.print("Le nombre de fichiers dans le dossier timide est de : ");
  Serial.println(NbFiles[1]);
  Serial.print("Le nombre de fichiers dans le dossier hilare est de : ");
  Serial.println(NbFiles[2]);
  Serial.print("Le nombre de fichiers dans le dossier hostile est de : ");
  Serial.println(NbFiles[3]);
  Serial.println();

  // Calibration Proximètre et Microphone
  CalibProxiMic();
}

// >>>>> MAIN LOOP <<<<<

void loop() {
  // LECTURE DES DONNEES

  Proxi = analogRead(ProxiPin);              // DOIT ETRE COMPRIS DE 0 à 1
  MedianProx.in(Proxi);
  ProxiMedian = MedianProx.out();

  //Micro Moyenne

  MicroRms = rms1.read() * 1000;            // DOIT ETRE COMPRIS DE 0 à 1
  MicroRA.addValue(MicroRms);
  Micro_Moyenne = MicroRA.getAverage();

  // JAUGE PEAK

  // Modif du seuil de comptabilité du nb de peaks pour éviter un retrig.

  if (playSdWav1.isPlaying()) {
    ThreshPeak =  Micro_Moyenne + 1;
  }
  else {
    ThreshPeak = MicroMin * 2;
  }

  // Jauge du nombre de peak toutes les x secondes
  if (Micro_Moyenne > ThreshPeak) {
    DetectPeak = 1;
  }
  else {
    DetectPeak = 0;
  }

  jaugePeak = JaugePeak(DetectPeak, TpsStockagePeak);

  // SELECTIONNE LA BONNE  HUMEUR ET LES BONNES PLAGES DE RANDOM RETRIG

  // Serein
  if (jaugePeak < SeuilJaugeMicro && ProxiMedian > SeuilAgressif) {
    if (Condition != 1) {
      corpusSampleNumber = NbFiles[0] ;          //Met à jour le nombre total de fichiers disponible dans le dossier serein
      RangeMin = ProxiMax - SeuilAgressif;
      RangeMax = ProxiMax;
      BorneMinMin = 3000 ;                        // REGLAGE
      BorneMinMax = 10000;                        // REGLAGE
      BorneMaxMax = 20000;                        // REGLAGE
      selecthumeur = 0 ;
      threshTrig = random(randomMin, randomMax);
      Condition = 1;
    }
  }

  // Agressif
  if (jaugePeak < SeuilJaugeMicro && ProxiMedian < SeuilAgressif) {
    if (Condition != 2) {
      corpusSampleNumber = NbFiles[3];          //Met à jour le nombre total de fichiers disponible dans le dossier timide
      RangeMin = ProxiMin;
      RangeMax = ProxiMax - SeuilAgressif;
      BorneMinMin = 100 ;                        // REGLAGE
      BorneMinMax = 200;                        // REGLAGE
      BorneMaxMax = 1000;                        // REGLAGE
      selecthumeur = 3;
      threshTrig = random(randomMin, randomMax);
      Condition = 2;
    }
  }

  // Hilare
  if (jaugePeak > SeuilJaugeMicro && ProxiMedian > SeuilAgressif) {
    if (Condition != 3) {
      corpusSampleNumber = NbFiles[2];         //Met à jour le nombre total de fichiers disponible dans le dossier hilare
      RangeMin = ProxiMax - SeuilAgressif;
      RangeMax = ProxiMax;
      BorneMinMin = 500 ;                        // REGLAGE
      BorneMinMax = 1000;                        // REGLAGE
      BorneMaxMax = 3000;                        // REGLAGE
      selecthumeur = 2;
      threshTrig = random(randomMin, randomMax);
      Condition = 3;
    }
  }

  // Timide
  if (jaugePeak > SeuilJaugeMicro && ProxiMedian < SeuilAgressif) {
    if (Condition != 4) {
      corpusSampleNumber = NbFiles[1];        //Met à jour le nombre total de fichiers disponible dans le dossier hostile
      RangeMin = ProxiMin;
      RangeMax = ProxiMax - SeuilAgressif;
      BorneMinMin = 14000 ;                        // REGLAGE
      BorneMinMax = 25000;                         // REGLAGE
      BorneMaxMax = 35000;                         // REGLAGE
      selecthumeur = 1;
      threshTrig = random(randomMin, randomMax);
      Condition = 4;
    }
  }

  ProxiRangeMin = map(ProxiMedian, RangeMin, RangeMax, BorneMinMin, BorneMinMax) ;
  ProxiRangeMax = map(ProxiMedian, RangeMin, RangeMax, BorneMinMax, BorneMaxMax) ;
  randomMin = constrain(ProxiRangeMin, BorneMinMin, BorneMinMax) ;
  randomMax = constrain(ProxiRangeMax, BorneMinMax, BorneMaxMax) ;

  // PLAYER AUDIO

  // Random Retrig

  if (millis() - resetMillis > threshTrig) {
    resetMillis = millis();
    sample_rand = URN(corpusSampleNumber) + 1;              // TIRAGE ALEATOIRE SANS REDECLENCHER LE MEME SON.
    SoundFile = HumeurFolder[selecthumeur] + "/" + sample_rand + SoundType;  //inttochar
    TrigFile(SoundFile.c_str());                                //JOUE LE fichier après un temps tiré aléatoirement définie dans une fourchette qui varie selon la somme des deux capteurs. .c_str() passe un string en char (en gros...)
    threshTrig = random(randomMin, randomMax);
  }


  // MONITORING

  //  Serial.print("Millis - Reset Millis : ");
  //  Serial.println(millis() - resetMillis);

  //  Serial.print("Proxi Median : ");
  //  Serial.println(ProxiMedian);
  //  Serial.print("DETECT PASSAGE : ");
  //  Serial.print(DetectPassage);
  //  Serial.print("  !!  JAUGE PASSAGE : ");
  //  Serial.println(jaugePassage);

  //  Serial.println("----------");

  //  Serial.print("RANDOM MIN : ");
  //  Serial.print(randomMin);
  //  Serial.print("  !!  RANDOM MAX : ");
  //  Serial.println(randomMax);

//  Serial.print("Micro : ");
//  Serial.print(Micro_Moyenne);
//  Serial.print("  !!  Signal interne : ");
//  Serial.println(InternalSigCorrected);

  //    Serial.print("DETECT PEAK : ");
  //    Serial.print(DetectPeak);
  //    Serial.print("  !!  JAUGE PEAK : ");
  //    Serial.println(jaugePeak);

  //  Serial.println("----------");
  //    AudioProcessorUsageMaxReset();
  //    AudioMemoryUsageMaxReset();
  //    Serial.print("CPU =");
  //    Serial.print(AudioProcessorUsage());
  //    Serial.print(",");
  //    Serial.print(AudioProcessorUsageMax());
  //    Serial.print("    ");
  //    Serial.print("Memory: ");
  //    Serial.print(AudioMemoryUsage());
  //    Serial.print(",");
  //    Serial.print(AudioMemoryUsageMax());
  //    Serial.println("    ");
  delay(10);
}

//-------------

//FONCTIONS

//-------------

// CALIBRATION PROXI & MICRO

void CalibProxiMic () {

  int InitTimerCalib = millis();
  Serial.println(" >>>>>>>>>>> Début de Calibration <<<<<<<<<< ");
  while (millis() - InitTimerCalib < TempsCalib) {
//    while (millis() - InitTimerCalib < TempsCalibGain) {
//      noise1.amplitude(1);
//      MicroRms = rms1.read() * 1000;
//      MicroRA.addValue(MicroRms);
//      Micro_Moyenne = MicroRA.getAverage();
//      InternalSig = rms2.read() * 1000;
//      AttenuationFactor = Micro_Moyenne / InternalSig;
//      delay(10);
//    }
//    noise1.amplitude(0);
    MicroRms = rms1.read() * 1000;
    Proxi = analogRead(ProxiPin);
    MicroRA.addValue(MicroRms);
    Micro_Moyenne = MicroRA.getAverage();
    // record the minimum Proxi Value
    if (Proxi < ProxiMin) {
      ProxiMin = Proxi;
    }
    // record the maximum Proxi value
    if (Proxi > ProxiMax) {
      ProxiMax = Proxi;
      ThreshPassage = ProxiMax - ProxiMax * 10 / 100 ;    // REGLAGE auto du seuil de détection d'un passage à -10% de la valeur max
      SeuilAgressif = ProxiMax / 2;
    }
    // record the minimum Micro Value
    if (Micro_Moyenne < MicroMin) {
      MicroMin = Micro_Moyenne;
    }
    delay(10);
  }
  if (ProxiMin > ProxiMax / 2) ProxiMin = ProxiMax / 2 ;
  ThreshPeak = MicroMin * 2;

  Serial.print("ProxiMin & ProxiMax : ");
  Serial.print(ProxiMin);
  Serial.print(" & ");
  Serial.println(ProxiMax);
  Serial.print("MicroMin & MicroMax : ");
  Serial.print(MicroMin);
  Serial.print(" & ");
  Serial.println(MicroMax);
  Serial.print("ThresPassage : ");
  Serial.print(ThreshPassage);
  Serial.print("  !!  Seuil agressif : ");
  Serial.print(SeuilAgressif);
  Serial.print("  !!  ThresPeak : ");
  Serial.print(ThreshPeak);
  Serial.print("  !!  Facteur d'atténuation : ");
  Serial.println(AttenuationFactor);
  Serial.println(" >>>>>>>>>>> Fin de Calibration <<<<<<<<<< ");
}

//-------------

// COMPTAGE DU NOMBRE DE FICHIERS PAR DOSSIER

int CountingFile (File DirName) {
  int FileNumber = 0;
  while (true) {
    File entry =  DirName.openNextFile();
    Serial.println(entry.name());

    if (! entry) {
      // no more files to scan
      break;
    }
    FileNumber++;
    //    if (!entry.isHidden()) {
    //      FileNumber++;
    //    }
    entry.close();
  }
  return FileNumber;
}

//-------------
//-------------

// FONCTIONS JAUGE : COMPTE NB D'EVENEMENTS DANS UN INTERVALLE DE TEMPS DONNE ET L'INTERPOLE LINEAIREMENT PAR RAPPORT A LA VALEUR PRECEDENTE ET PENDANT L'INTERVALLE DE TEMPS DETERMINE.

float JaugePeak (bool DetectEvent, float TimeWindow) {

  static float nbEvent = 0;
  static float arrivee = 0;
  static float depart = 0;
  static float Temps = 0;
  static bool LastDetectEvent = 0;
  static bool LastStockageEvent = 0;
  static bool StockageEvent = 0;

  if (DetectEvent != LastDetectEvent) { //Detection d'un front montant
    if (DetectEvent) {
      nbEvent++;  // Incrémentation du nombre de passage.
      LastDetectEvent = 1;
    }
    else {
      LastDetectEvent = 0;
    }
  }

  StockageEvent = millis() - Temps > TimeWindow; // Condition de temps pour retourner la future valeur de la jauge (toutes les X secondes)

  if (StockageEvent != LastStockageEvent) {
    if (StockageEvent) {
      depart = arrivee;
      arrivee = nbEvent; // On retourne le nombre d'évènements.
      Temps = (float)millis();  //On remet le compteur de temps à 0 pour la prochaine boucle et avoir un snapshot régulier.
      nbEvent = 0; // On remet le nombre d'évènements à 0.
      LastStockageEvent = 1;
    }
    else {
      LastStockageEvent = 0;
    }
  }

  float coef = (arrivee - depart) / TimeWindow ;
  float Line = (coef * ((float)millis() - Temps) + depart); // Interpolation linéaire (= Line pure data)
  return Line;
}

//-------------
//-------------

// FONCTION URN Thomas (tire aléatoirement un son qui n'a pas encore été joué)

int index_tab = 0; // nombre de samples deja jouées;
int sampleDejaJoues[100]; //Défini la taille du tableau et initialise toutes les valeurs à 0
int unplayedSample = 0;
int lastPlayedSample = -1;

int URN(int nbtotfile) {
  boolean etat = true;

  while (etat) {
    etat = false;
    unplayedSample = int(random(nbtotfile));
    for (int i = 0; i < index_tab; i++) {
      if (sampleDejaJoues[i] == unplayedSample) {
        etat = true;
        break;
      }
    }
    if (index_tab == 0 && unplayedSample == lastPlayedSample) {
      etat = true;
    }
  }

  if (index_tab < nbtotfile) {
    sampleDejaJoues[index_tab] = unplayedSample;
    index_tab ++;
  }

  if (index_tab == nbtotfile) {
    index_tab = 0;
    lastPlayedSample = unplayedSample;
    initSampleSelecteur(nbtotfile);
  }
  return unplayedSample;
}

//Init Sample

void initSampleSelecteur(int nbtotfile) {
  for (int i = 0; i < nbtotfile; i++) {
    sampleDejaJoues[i] = -1;
  }
}

//-------------
//-------------

// TRIG UN FICHIER SON EN COUPANT LE PRECEDENT

void TrigFile(const char *filename)
{
  Serial.println("");
  Serial.print(" >>>>>>>>>>>>>>> Playing file : ");
  Serial.print(filename);
  Serial.println(" <<<<<<<<<<<<<<< ");
  Serial.println("");

  // Start playing the file.  This sketch continues to
  // run while the file plays.
  playSdWav1.play(filename);

  // A brief delay for the library read WAV info
  delay(5);
}


//-------------
//-------------

// INTERPOLATION LINEAIRE EN UN TEMPS DONNE (=LINE dans Pure Data)

float Line(float data, float arrivee, float TimeInterpol) {
  static float Temps = 0;
  static float depart = 0;
  static float coef = 0;
  static float line = 0;
  static float PreviousArrivee = 0;

  if (arrivee != PreviousArrivee) {
    PreviousArrivee = arrivee ;
    depart = line;
    Temps = (float)millis();
  }
  coef = (data - depart) / TimeInterpol ;
  if ((float)millis() - Temps <= TimeInterpol) {
    line = (coef * ((float)millis() - Temps) + depart);
  }
  return line;
}
 
Last edited:
I simplified the code at his maximum and it's still freezing, even with a 10 ms delay for letting the library to read the wav information.
It's just playing sound files from micro SD with a variation in the retrig time according to microphone and proximeter.
There is a random no repeat function called URN.

Here is the new code :

Code:
#include <Audio.h>
#include <Wire.h>
#include <SPI.h>
#include <SD.h>
#include <SerialFlash.h>
#include <MedianFilter.h>   //https://github.com/daPhoosa/MedianFilter
#include <RunningAverage.h> //https://playground.arduino.cc/Main/RunningAverage
#include <Bounce.h>

// GUItool: begin automatically generated code
AudioPlaySdWav           playSdWav1;     //xy=92,311
AudioMixer4              mixer1;         //xy=385,325
AudioMixer4              mixer2;         //xy=385,393
AudioInputI2S            i2s2;           //xy=537,164
AudioAnalyzeRMS          rms1;           //xy=712,158
AudioOutputI2S           i2s1;           //xy=845,386
AudioConnection          patchCord1(playSdWav1, 0, mixer1, 0);
AudioConnection          patchCord2(playSdWav1, 1, mixer2, 0);
AudioConnection          patchCord3(mixer1, 0, i2s1, 0);
AudioConnection          patchCord4(mixer2, 0, i2s1, 1);
AudioConnection          patchCord5(i2s2, 0, rms1, 0);
AudioControlSGTL5000     sgtl5000_1;     //xy=88,95
// GUItool: end automatically generated code

//Use these with the audio adaptor board

#define SDCARD_CS_PIN    10
#define SDCARD_MOSI_PIN  7
#define SDCARD_SCK_PIN   14

#define LED 13
#define ProxiPin A3

// DECLARATION & INIT VARIABLES

// Settings fonctions

MedianFilter MedianProx(15, 0);
RunningAverage MicroRA(15);

// Déclaration des fonctions

void CalibProxiMic();
int CountingFile (File DirName);
float JaugePeak (bool DetectEvent, float TimeWindow);
int URN(int nbtotfile);
void TrigFile(const char *filename);
void LoopFile(const char *filename);
void initSampleSelecteur(int nbtotfile);
float Line(float arrivee, float TimeInterpol);

// Variables données

int Proxi;
float MicroRms;

float deriveeNoise;
float deriveeMic;

int ProxiMedian = 0;
float Micro_Moyenne = 0;

// Variables calib Proxi + Micro

int TempsCalib = 5000 ;            // REGLAGE  : durée calibration.

int ProxiMin = 1023;
float ProxiMax = 0;
float MicroMin = 1023;
float MicroMax = 0;

// Variable Compteur nombre de fichiers par dossier

File root;
int NbFiles[4] = {0};

// Variables JAUGES

int NbPeak = 0;
int ThreshPeak = 20 ;              //(10 par défaut par rapport à la dérivée)
bool DetectPeak = 0;
int TpsStockagePeak = 1500;       //REGLAGE (Temps de stockage de la jauge Micro)
float jaugePeak = 0;

// Valeurs de seuil de changement d'humeur + changement de rapidité de déclenchement

int SeuilProxi;
int Condition = 0;
int SeuilJaugeMicro = 1;              //REGLAGE (Seuil de changement d'humeur Micro)

// Variables PROXI Range

float ProxiRangeMin = 0;
float ProxiRangeMax = 0;
float ProxiValueMin = 0;
float ProxiValueMax = 0;

int RangeMin;
int RangeMax;
int BorneMinMin ;
int BorneMinMax ;
int BorneMaxMax ;

int randomMin;
int randomMax;

// Variables fonction TRIGFILE
int resetMillis = 0;
int threshTrig = 0;
int corpusSampleNumber = 10;   // Nombre de son dans chaque dossier

int sample_rand = 1;           // tirage au sort du numéro du sample.
String SoundFile, SoundType;
String HumeurFolder[4]  = {"serein", "timide", "hilare", "hostile"};
int selecthumeur = 0;
int previoushumeur = 1000;
int statechangeselecthumeur = 0;

// Variables Timide
int FreezeTimideTime = 60000;           // REGLAGE (durée du mode timide)

//-------------
//-------------

//                                 >>>>> SETUP <<<<<

void setup() {
  Serial.begin(9600);
  randomSeed(analogRead(A9));  //passer la fonction random en réelle fonction aléatoire.

  //AUDIO

  AudioMemory(70);             // Audio connections require memory to work.  For more detailed information, see the MemoryAndCpuUsage example
  // setup audio board
  SoundFile = String();
  SoundType = String(".wav");
  sgtl5000_1.enable();
  sgtl5000_1.volume(0.7);                         //REGLAGE
  sgtl5000_1.inputSelect(AUDIO_INPUT_MIC);
  sgtl5000_1.micGain(50);

  //Setup SD Card
  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("Unable to access the SD card");
      delay(1000);
    }
  }
  //Compte le nombre de fichiers dans chacun des dossiers d'humeur.

  for (int i = 0; i <= 3; i++) {
    String FileRemove = HumeurFolder[i] + "/" + "DS_STO~1";
    SD.remove(FileRemove.c_str());
    String FolderName = HumeurFolder[i] + "/";
    root = SD.open(FolderName.c_str());
    NbFiles[i] = CountingFile(root);
  }
  Serial.print("Le nombre de fichiers dans le dossier serein est de : ");
  Serial.println(NbFiles[0]);
  Serial.print("Le nombre de fichiers dans le dossier timide est de : ");
  Serial.println(NbFiles[1]);
  Serial.print("Le nombre de fichiers dans le dossier hilare est de : ");
  Serial.println(NbFiles[2]);
  Serial.print("Le nombre de fichiers dans le dossier hostile est de : ");
  Serial.println(NbFiles[3]);
  Serial.println();

  // Calibration Proximètre et Microphone
  CalibProxiMic();
}

// >>>>> MAIN LOOP <<<<<

void loop() {
  // LECTURE DES DONNEES

  Proxi = analogRead(ProxiPin);              // DOIT ETRE COMPRIS DE 0 à 1
  MedianProx.in(Proxi);
  ProxiMedian = MedianProx.out();

  //Micro Moyenne

  MicroRms = rms1.read() * 1000;            // DOIT ETRE COMPRIS DE 0 à 1
  MicroRA.addValue(MicroRms);
  Micro_Moyenne = MicroRA.getAverage();

  // JAUGES PEAK

  // Modif du seuil de comptabilité du nb de peaks pour éviter un retrig.

  if (playSdWav1.isPlaying()) {
    ThreshPeak =  Micro_Moyenne + 1;
  }
  else {
    ThreshPeak = MicroMin * 2;
  }

  // Jauge du nombre de peak toutes les x secondes
  if (Micro_Moyenne > ThreshPeak) {
    DetectPeak = 1;
  }
  else {
    DetectPeak = 0;
  }

  jaugePeak = JaugePeak(DetectPeak, TpsStockagePeak);

  // SELECTIONNE LA BONNE  HUMEUR ET LES BONNES PLAGES DE RANDOM RETRIG

  // Serein
  if (jaugePeak < SeuilJaugeMicro && ProxiMedian > SeuilProxi) {
    if (Condition != 1) {
      corpusSampleNumber = NbFiles[0] ;          //Met à jour le nombre total de fichiers disponible dans le dossier serein
      RangeMin = SeuilProxi;
      RangeMax = ProxiMax;
      BorneMinMin = 5000 ;                        // REGLAGE
      BorneMinMax = 10000;                        // REGLAGE
      BorneMaxMax = 20000;                        // REGLAGE
      selecthumeur = 0 ;
      threshTrig = random(randomMin, randomMax);
      Condition = 1;
    }
  }

  // Agressif
  if (jaugePeak < SeuilJaugeMicro && ProxiMedian < SeuilProxi) {
    if (Condition != 2) {
      corpusSampleNumber = NbFiles[3];          //Met à jour le nombre total de fichiers disponible dans le dossier timide
      RangeMin = ProxiMin;
      RangeMax = SeuilProxi;
      BorneMinMin = 100 ;                        // REGLAGE
      BorneMinMax = 200;                        // REGLAGE
      BorneMaxMax = 1000;                        // REGLAGE                                // REGLAGE
      selecthumeur = 3;
      threshTrig = random(randomMin, randomMax);
      Condition = 2;
    }
  }

  // Hilare
  if (jaugePeak > SeuilJaugeMicro && ProxiMedian > SeuilProxi) {
    if (Condition != 3) {
      corpusSampleNumber = NbFiles[2];         //Met à jour le nombre total de fichiers disponible dans le dossier hilare
      RangeMin = SeuilProxi;
      RangeMax = ProxiMax;
      BorneMinMin = 500 ;                        // REGLAGE
      BorneMinMax = 1000;                        // REGLAGE
      BorneMaxMax = 3000;                        // REGLAGE
      selecthumeur = 2;
      threshTrig = random(randomMin, randomMax);
      Condition = 3;
    }
  }

  // Timide
  if (jaugePeak > SeuilJaugeMicro && ProxiMedian < SeuilProxi) {
    if (Condition != 4) {
      corpusSampleNumber = NbFiles[1];                     //Met à jour le nombre total de fichiers disponible dans le dossier hostile
      selecthumeur = 1;
      Condition = 4;
      randomMin = 15000;                                   // REGLAGE
      randomMax = 45000;                                   // REGLAGE
      int ResetMillisTimide = millis();
      while (millis() - ResetMillisTimide < FreezeTimideTime) {
        Serial.println("  INSIDE TIMIDE <<<<<<<<<<<<<<<<<<<<<<<< ");
        if (millis() - resetMillis > threshTrig) {
          resetMillis = millis();
          sample_rand = URN(corpusSampleNumber) + 1;                  // TIRAGE ALEATOIRE SANS REDECLENCHER LE MEME SON.
          SoundFile = HumeurFolder[selecthumeur] + "/" + sample_rand + SoundType;  //inttochar
          TrigFile(SoundFile.c_str());                                //JOUE LE fichier après un temps tiré aléatoirement définie dans une fourchette qui varie selon la somme des deux capteurs. .c_str() passe un string en char (en gros...)
          threshTrig = random(randomMin, randomMax);
        }
        delay(10);
      }
    }
  }

  ProxiRangeMin = map(ProxiMedian, RangeMin, RangeMax, BorneMinMin, BorneMinMax) ;
  ProxiRangeMax = map(ProxiMedian, RangeMin, RangeMax, BorneMinMax, BorneMaxMax) ;
  randomMin = constrain(ProxiRangeMin, BorneMinMin, BorneMinMax) ;
  randomMax = constrain(ProxiRangeMax, BorneMinMax, BorneMaxMax) ;

  // PLAYER AUDIO

  // Random Retrig

  if (millis() - resetMillis > threshTrig) {
    resetMillis = millis();
    sample_rand = URN(corpusSampleNumber) + 1;              // TIRAGE ALEATOIRE SANS REDECLENCHER LE MEME SON.
    SoundFile = HumeurFolder[selecthumeur] + "/" + sample_rand + SoundType;  //inttochar
    TrigFile(SoundFile.c_str());                                //JOUE LE fichier après un temps tiré aléatoirement définie dans une fourchette qui varie selon la somme des deux capteurs. .c_str() passe un string en char (en gros...)
    threshTrig = random(randomMin, randomMax);
  }
  delay(10);
}

//-------------

//FONCTIONS

//-------------

// CALIBRATION PROXI & MICRO

void CalibProxiMic () {

  int InitTimerCalib = millis();
  Serial.println(" >>>>>>>>>>> Début de Calibration <<<<<<<<<< ");
  while (millis() - InitTimerCalib < TempsCalib) {
    MicroRms = rms1.read() * 1000;
    Proxi = analogRead(ProxiPin);
    MicroRA.addValue(MicroRms);
    Micro_Moyenne = MicroRA.getAverage();
    // record the minimum Proxi Value
    if (Proxi < ProxiMin) {
      ProxiMin = Proxi;
    }
    // record the maximum Proxi value
    if (Proxi > ProxiMax) {
      ProxiMax = Proxi;
    }
    // record the minimum Micro Value
    if (Micro_Moyenne < MicroMin) {
      MicroMin = Micro_Moyenne;
    }
    delay(10);
  }
  if (ProxiMin > ProxiMax / 2) ProxiMin = ProxiMax / 2 ;
  SeuilProxi = ProxiMax / 2;
  ThreshPeak = MicroMin * 3;

  Serial.print("ProxiMin & ProxiMax : ");
  Serial.print(ProxiMin);
  Serial.print(" & ");
  Serial.println(ProxiMax);
  Serial.print("MicroMin : ");
  Serial.print(MicroMin);
  Serial.print("  !!  Seuil Proxi : ");
  Serial.print(SeuilProxi);
  Serial.print("  !!  ThresPeak : ");
  Serial.println(ThreshPeak);
  Serial.println(" >>>>>>>>>>> Fin de Calibration <<<<<<<<<< ");
}

//-------------

// COMPTAGE DU NOMBRE DE FICHIERS PAR DOSSIER

int CountingFile (File DirName) {
  int FileNumber = 0;
  while (true) {
    File entry =  DirName.openNextFile();
    Serial.println(entry.name());

    if (! entry) {
      // no more files to scan
      break;
    }
    FileNumber++;
    //    if (!entry.isHidden()) {
    //      FileNumber++;
    //    }
    entry.close();
  }
  return FileNumber;
}


//-------------

// FONCTIONS JAUGE : COMPTE NB D'EVENEMENTS DANS UN INTERVALLE DE TEMPS DONNE ET L'INTERPOLE LINEAIREMENT PAR RAPPORT A LA VALEUR PRECEDENTE ET PENDANT L'INTERVALLE DE TEMPS DETERMINE.

float JaugePeak (bool DetectEvent, float TimeWindow) {

  static float nbEvent = 0;
  static float arrivee = 0;
  static float depart = 0;
  static float Temps = 0;
  static bool LastDetectEvent = 0;
  static bool LastStockageEvent = 0;
  static bool StockageEvent = 0;

  if (DetectEvent != LastDetectEvent) { //Detection d'un front montant
    if (DetectEvent) {
      nbEvent++;  // Incrémentation du nombre de peak.
      LastDetectEvent = 1;
    }
    else {
      LastDetectEvent = 0;
    }
  }

  StockageEvent = millis() - Temps > TimeWindow; // Condition de temps pour retourner la future valeur de la jauge (toutes les X secondes)

  if (StockageEvent != LastStockageEvent) {
    if (StockageEvent) {
      depart = arrivee;
      arrivee = nbEvent; // On retourne le nombre d'évènements.
      Temps = (float)millis();  //On remet le compteur de temps à 0 pour la prochaine boucle et avoir un snapshot régulier.
      nbEvent = 0; // On remet le nombre d'évènements à 0.
      LastStockageEvent = 1;
    }
    else {
      LastStockageEvent = 0;
    }
  }

  float coef = (arrivee - depart) / TimeWindow ;
  float Line = (coef * ((float)millis() - Temps) + depart); // Interpolation linéaire (= Line pure data)
  return Line;
}

//-------------
//-------------

// FONCTION URN Thomas (tire aléatoirement un son qui n'a pas encore été joué)

int index_tab = 0; // nombre de samples deja jouées;
int sampleDejaJoues[100]; //Défini la taille du tableau et initialise toutes les valeurs à 0
int unplayedSample = 0;
int lastPlayedSample = -1;

int URN(int nbtotfile) {
  boolean etat = true;

  while (etat) {
    etat = false;
    unplayedSample = int(random(nbtotfile));
    for (int i = 0; i < index_tab; i++) {
      if (sampleDejaJoues[i] == unplayedSample) {
        etat = true;
        break;
      }
    }
    if (index_tab == 0 && unplayedSample == lastPlayedSample) {
      etat = true;
    }
  }

  if (index_tab < nbtotfile) {
    sampleDejaJoues[index_tab] = unplayedSample;
    index_tab ++;
  }

  if (index_tab == nbtotfile) {
    index_tab = 0;
    lastPlayedSample = unplayedSample;
    initSampleSelecteur(nbtotfile);
  }
  return unplayedSample;
}

//Init Sample

void initSampleSelecteur(int nbtotfile) {
  for (int i = 0; i < nbtotfile; i++) {
    sampleDejaJoues[i] = -1;
  }
}

//-------------
//-------------

// TRIG UN FICHIER SON EN COUPANT LE PRECEDENT

void TrigFile(const char *filename)
{
  Serial.println("");
  Serial.print(" >>>>>>>>>>>>>>> Playing file : ");
  Serial.print(filename);
  Serial.println(" <<<<<<<<<<<<<<< ");
  Serial.println("");

  // Start playing the file.  This sketch continues to
  // run while the file plays.
  playSdWav1.play(filename);

  // A brief delay for the library read WAV info
  delay(10);
}

//-------------
//-------------

// INTERPOLATION LINEAIRE EN UN TEMPS DONNE (=LINE dans Pure Data)


float Line(float data, float arrivee, float TimeInterpol) {
  static float Temps = 0;
  static float depart = 0;
  static float coef = 0;
  static float line = 0;
  static float PreviousArrivee = 0;

  if (arrivee != PreviousArrivee) {
    PreviousArrivee = arrivee ;
    depart = line;
    Temps = (float)millis();
  }
  coef = (data - depart) / TimeInterpol ;
  if ((float)millis() - Temps <= TimeInterpol) {
    line = (coef * ((float)millis() - Temps) + depart);
  }
  return line;
}
 
Any chance you could try to reproduce the problem with a smaller program which does not depend on the microphone and sensor? Then I could run it here and try to reproduce the problem on the hardware I have. There's not much I can do if I do not have a way to reproduce the problem.
 
Yeah Paul that's I'm gonna trying to do in a couple of minutes after resolving other little problems.. I definitly keep you updated asap !!! Thanks a lot for your reply !!! It's warming me up cause I feel exhausted this last few days, as nothing is working before the exhibition... (It's been 4 months I'm fighting to learn arduino and teensy programing).
I'll get back to you in a few time.
 
Sorry I edited the post and deleting the previous one...

I said it's not that shorter but it's important you get everything. I added random instead of sensors and translated comments.
The main part is from 192 to 249 where it changes folder samples and limit of random retrig.

There are 5 main functions but the one I'm not to sure are : gauge (function which count the number of peak and linearly interpolate value every x secondes) and URN which is a random without repeat files until the whole list has been played.

Here are the sounds you can test with : https://www.dropbox.com/sh/hg8yjj3vwnpmmia/AACp83h-ZmKT1hn9fY_zzMpWa?dl=0

Let me know if you need anything else or if you have question.


Code:
#include <Audio.h>
#include <Wire.h>
#include <SPI.h>
#include <SD.h>
#include <SerialFlash.h>
#include <MedianFilter.h>   //https://github.com/daPhoosa/MedianFilter
#include <RunningAverage.h> //https://playground.arduino.cc/Main/RunningAverage
#include <Bounce.h>

// GUItool: begin automatically generated code
AudioPlaySdWav           playSdWav1;     //xy=108,284
AudioMixer4              mixer1;         //xy=401,298
AudioMixer4              mixer2;         //xy=401,366
AudioOutputI2S           i2s1;           //xy=861,359
AudioConnection          patchCord1(playSdWav1, 0, mixer1, 0);
AudioConnection          patchCord2(playSdWav1, 1, mixer2, 0);
AudioConnection          patchCord3(mixer1, 0, i2s1, 0);
AudioConnection          patchCord4(mixer2, 0, i2s1, 1);
AudioControlSGTL5000     sgtl5000_1;     //xy=104,68
// GUItool: end automatically generated code


//Use these with the audio adaptor board

#define SDCARD_CS_PIN    10
#define SDCARD_MOSI_PIN  7
#define SDCARD_SCK_PIN   14

#define LED 13

// DECLARATION & INIT VARIABLES

// Settings fonctions

MedianFilter MedianProx(15, 0);
RunningAverage MicroRA(15);

// functions declaration

void CalibProxiMic();
int CountingFile (File DirName);
float JaugePeak (bool DetectEvent, float TimeWindow);
int URN(int nbtotfile);
void TrigFile(const char *filename);
void initSampleSelecteur(int nbtotfile);

// Data variables

int Proxi;
float MicroRms;
int ProxiMedian = 0;
float Micro_Moyenne = 0;

// Variables calib Proxi + Micro

int TempsCalib = 5000 ;            // REGLAGE  : durée calibration.
int ProxiMin = 1023;
float ProxiMax = 0;
float MicroMin = 1023;
float MicroMax = 0;

// Counting files per folder variables

File root;
int NbFiles[4] = {0};

// GAUGE variables

int NbPeak = 0;
int ThreshPeak = 20 ;              //(10 par défaut par rapport à la dérivée)
bool DetectPeak = 0;
int TpsStockagePeak = 1500;       //REGLAGE (Temps de stockage de la jauge Micro)
float jaugePeak = 0;

// Threshold of changing folder and retriger timing.

int SeuilProxi;
int Condition = 0;
int SeuilJaugeMicro = 1;              //REGLAGE (Seuil de changement d'humeur Micro)

// retriger Range.

float ProxiRangeMin = 0;
float ProxiRangeMax = 0;
float ProxiValueMin = 0;
float ProxiValueMax = 0;

int RangeMin;
int RangeMax;
int BorneMinMin ;
int BorneMinMax ;
int BorneMaxMax ;

int randomMin;
int randomMax;

// TRIGFILE function variable

int resetMillis = 0;
int threshTrig = 0;
int corpusSampleNumber = 10;   // Number of sounds in each folder (automatically defined)

int sample_rand = 1;           // Random sample number.
String SoundFile, SoundType;
String HumeurFolder[4]  = {"serein", "timide", "hilare", "hostile"};
int selecthumeur = 0;
int previoushumeur = 1000;
int statechangeselecthumeur = 0;

// Variables Timide
int FreezeTimideTime = 60000;           // REGLAGE (Shy mode time for freezing loop)

//-------------
//-------------

//                                   >>>>> SETUP <<<<<

void setup() {
  Serial.begin(9600);
  randomSeed(analogRead(A9));

  //AUDIO

  AudioMemory(70);             // Audio connections require memory to work.  For more detailed information, see the MemoryAndCpuUsage example
  // setup audio board
  SoundFile = String();
  SoundType = String(".wav");
  sgtl5000_1.enable();
  sgtl5000_1.volume(0.7);                         //REGLAGE
  sgtl5000_1.micGain(50);

  //Setup SD Card
  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("Unable to access the SD card");
      delay(1000);
    }
  }
  // Counting files in each folder

  for (int i = 0; i <= 3; i++) {
    String FileRemove = HumeurFolder[i] + "/" + "DS_STO~1";
    SD.remove(FileRemove.c_str());
    String FolderName = HumeurFolder[i] + "/";
    root = SD.open(FolderName.c_str());
    NbFiles[i] = CountingFile(root);
  }
  Serial.print("Le nombre de fichiers dans le dossier serein est de : ");
  Serial.println(NbFiles[0]);
  Serial.print("Le nombre de fichiers dans le dossier timide est de : ");
  Serial.println(NbFiles[1]);
  Serial.print("Le nombre de fichiers dans le dossier hilare est de : ");
  Serial.println(NbFiles[2]);
  Serial.print("Le nombre de fichiers dans le dossier hostile est de : ");
  Serial.println(NbFiles[3]);
  Serial.println();

  // Calibration (see the function bellow)
  CalibProxiMic();
}

// >>>>> MAIN LOOP <<<<<

void loop() {
  // DATA READING

  Proxi = random(20, 300);              // DOIT ETRE COMPRIS DE 0 à 1
  MedianProx.in(Proxi);
  ProxiMedian = MedianProx.out();

  MicroRms = random(20, 50);            // DOIT ETRE COMPRIS DE 0 à 1
  MicroRA.addValue(MicroRms);
  Micro_Moyenne = MicroRA.getAverage();

  // GAUGE PEAK DETECTION

  // Detect peak
  if (Micro_Moyenne > ThreshPeak) {
    DetectPeak = 1;
  }
  else {
    DetectPeak = 0;
  }

  // Count the number of peak every x secondes and linearly interpole values (see funtion bellow)

  jaugePeak = JaugePeak(DetectPeak, TpsStockagePeak);

  // SELECT THE RIGHT FOLDER (corresponding to the right mood) AND RETRIG SETTING ACCORDING TO DATA.

  // Serein
  if (jaugePeak < SeuilJaugeMicro && ProxiMedian > SeuilProxi) {
    if (Condition != 1) {
      corpusSampleNumber = NbFiles[0] ;          // Update the number of available soundfiles in "serein" folder
      RangeMin = SeuilProxi;
      RangeMax = ProxiMax;
      BorneMinMin = 5000 ;                        // REGLAGE
      BorneMinMax = 10000;                        // REGLAGE
      BorneMaxMax = 20000;                        // REGLAGE
      selecthumeur = 0 ;
      Condition = 1;
    }
  }

  // Hostile
  if (jaugePeak < SeuilJaugeMicro && ProxiMedian < SeuilProxi) {
    if (Condition != 2) {
      corpusSampleNumber = NbFiles[3];          // Update the number of available soundfiles in "hostile" folder
      RangeMin = ProxiMin;
      RangeMax = SeuilProxi;
      BorneMinMin = 100 ;                        // REGLAGE
      BorneMinMax = 200;                        // REGLAGE
      BorneMaxMax = 1000;                        // REGLAGE
      selecthumeur = 3;
      Condition = 2;
    }
  }

  // Hilare
  if (jaugePeak > SeuilJaugeMicro && ProxiMedian > SeuilProxi) {
    if (Condition != 3) {
      corpusSampleNumber = NbFiles[2];          // Update the number of available soundfiles in "hilare" folder
      RangeMin = SeuilProxi;
      RangeMax = ProxiMax;
      BorneMinMin = 500 ;                        // REGLAGE
      BorneMinMax = 1000;                        // REGLAGE
      BorneMaxMax = 3000;                        // REGLAGE
      selecthumeur = 2;
      Condition = 3;
    }
  }

  // Timide
  if (jaugePeak > SeuilJaugeMicro && ProxiMedian < SeuilProxi) {
    if (Condition != 4) {
      corpusSampleNumber = NbFiles[1];                     // Update the number of available soundfiles in "timide" folder
      RangeMin = ProxiMin;
      RangeMax = SeuilProxi;
      BorneMinMin = 500 ;                        // REGLAGE
      BorneMinMax = 1000;                        // REGLAGE
      BorneMaxMax = 3000;                        // REGLAGE
      selecthumeur = 1;
      Condition = 4;
    }
  }

  //Changing the limits of the random number which define the time after playing another sound. Depends on the data.

  ProxiRangeMin = map(ProxiMedian, RangeMin, RangeMax, BorneMinMin, BorneMinMax) ;
  ProxiRangeMax = map(ProxiMedian, RangeMin, RangeMax, BorneMinMax, BorneMaxMax) ;
  randomMin = constrain(ProxiRangeMin, BorneMinMin, BorneMinMax) ;
  randomMax = constrain(ProxiRangeMax, BorneMinMax, BorneMaxMax) ;
  threshTrig = random(randomMin, randomMax);

  // PLAYER AUDIO

  // Random Retrig : PLAY A RANDOM NO REPEAT SOUND AFTER A CERTAIN AMOUNT OF TIME DETERMINED BY THE LIMIT (see above)

  if (millis() - resetMillis > threshTrig) {
    resetMillis = millis();
    sample_rand = URN(corpusSampleNumber) + 1;                  // RANDOM NO REPEAT TO CHOOSE A NEW SAMPLE IN THE RIGHT FOLDER
    SoundFile = HumeurFolder[selecthumeur] + "/" + sample_rand + SoundType;  //inttochar
    TrigFile(SoundFile.c_str());                                // TRIG THE GOOD SOUNDFILE
  }
  delay(500);
}

//-------------

//FONCTIONS

//-------------

// CALIBRATION PROXI & MICRO

void CalibProxiMic () {

  int InitTimerCalib = millis();
  Serial.println(" >>>>>>>>>>> Début de Calibration <<<<<<<<<< ");
  while (millis() - InitTimerCalib < TempsCalib) {
    Proxi = random(20, 300);
    MicroRms = random(20, 50);
    MicroRA.addValue(MicroRms);
    Micro_Moyenne = MicroRA.getAverage();
    // record the minimum Proxi Value
    if (Proxi < ProxiMin) {
      ProxiMin = Proxi;
    }
    // record the maximum Proxi value
    if (Proxi > ProxiMax) {
      ProxiMax = Proxi;
    }
    // record the minimum Micro Value
    if (Micro_Moyenne < MicroMin) {
      MicroMin = Micro_Moyenne;
    }
    delay(10);
  }
  if (ProxiMin > ProxiMax / 2) ProxiMin = ProxiMax / 2 ;
  SeuilProxi = ProxiMax / 2;
  ThreshPeak = MicroMin * 3;

  Serial.print("ProxiMin & ProxiMax : ");
  Serial.print(ProxiMin);
  Serial.print(" & ");
  Serial.println(ProxiMax);
  Serial.print("MicroMin : ");
  Serial.print(MicroMin);
  Serial.print("  !!  Seuil Proxi : ");
  Serial.print(SeuilProxi);
  Serial.print("  !!  ThresPeak : ");
  Serial.println(ThreshPeak);
  Serial.println(" >>>>>>>>>>> Fin de Calibration <<<<<<<<<< ");
}

//-------------

// COUNTING THE NUMBER OF FILE PER FOLDER.

int CountingFile (File DirName) {
  int FileNumber = 0;
  while (true) {
    File entry =  DirName.openNextFile();
    Serial.println(entry.name());

    if (! entry) {
      // no more files to scan
      break;
    }
    FileNumber++;
    //    if (!entry.isHidden()) {
    //      FileNumber++;
    //    }
    entry.close();
  }
  return FileNumber;
}

//-------------

// GAUGE FUNCTION : Counting event number in a certain range of time. Linearly interpol the past value to the present in this range of time.

float JaugePeak (bool DetectEvent, float TimeWindow) {

  static float nbEvent = 0;
  static float arrivee = 0;
  static float depart = 0;
  static float Temps = 0;
  static bool LastDetectEvent = 0;
  static bool LastStockageEvent = 0;
  static bool StockageEvent = 0;

  if (DetectEvent != LastDetectEvent) {
    if (DetectEvent) {
      nbEvent++;  // Increase peak number.
      LastDetectEvent = 1;
    }
    else {
      LastDetectEvent = 0;
    }
  }

  StockageEvent = millis() - Temps > TimeWindow; // Time condition before returning the next gauge value (every X secondes)

  if (StockageEvent != LastStockageEvent) {
    if (StockageEvent) {
      depart = arrivee;
      arrivee = nbEvent; // return the event number
      Temps = (float)millis();  // Reset the timing counter until the next loop.
      nbEvent = 0; // Reset event number
      LastStockageEvent = 1;
    }
    else {
      LastStockageEvent = 0;
    }
  }

  float coef = (arrivee - depart) / TimeWindow ;
  float Line = (coef * ((float)millis() - Temps) + depart); // linear Interpolation (= pure data Line object)
  return Line;
}

//-------------
//-------------

// FONCTION URN (Random No Repeat)

int index_tab = 0; // samples already played;
int sampleDejaJoues[100];
int unplayedSample = 0;
int lastPlayedSample = -1;

int URN(int nbtotfile) {
  boolean etat = true;

  while (etat) {
    etat = false;
    unplayedSample = int(random(nbtotfile));
    for (int i = 0; i < index_tab; i++) {
      if (sampleDejaJoues[i] == unplayedSample) {
        etat = true;
        break;
      }
    }
    if (index_tab == 0 && unplayedSample == lastPlayedSample) {
      etat = true;
    }
  }

  if (index_tab < nbtotfile) {
    sampleDejaJoues[index_tab] = unplayedSample;
    index_tab ++;
  }

  if (index_tab == nbtotfile) {
    index_tab = 0;
    lastPlayedSample = unplayedSample;
    initSampleSelecteur(nbtotfile);
  }
  return unplayedSample;
}

//Init Sample

void initSampleSelecteur(int nbtotfile) {
  for (int i = 0; i < nbtotfile; i++) {
    sampleDejaJoues[i] = -1;
  }
}

//-------------
//-------------

// TRIG Sound File and cut the previous one.

void TrigFile(const char *filename)
{
  Serial.println("");
  Serial.print(" >>>>>>>>>>>>>>> Playing file : ");
  Serial.print(filename);
  Serial.println(" <<<<<<<<<<<<<<< ");
  Serial.println("");

  // Start playing the file.  This sketch continues to
  // run while the file plays.
  playSdWav1.play(filename);

  // A brief delay for the library
 
Last edited:
Is it possible that the problem could come from a limitation about size of soundfiles / libraries ?

We did some tests the past night and one teensy + audio adaptor + sensors managed to run for 12 hours until it stopped this morning while another similar system stopped 3 or 4 times at least.
The only differences were the sensors and the sounds.
 
Could it come from this random no repeat function that I can call some times and with differents values of nbtotfile ?

Code:
int index_tab = 0; // nombre de samples deja jouées;
int sampleDejaJoues[100]; //Défini la taille du tableau et initialise toutes les valeurs à 0
int unplayedSample = 0;
int lastPlayedSample = -1;

int URN(int nbtotfile) {
  boolean etat = true;

  while (etat) {
    etat = false;
    unplayedSample = int(random(nbtotfile));
    for (int i = 0; i < index_tab; i++) {
      if (sampleDejaJoues[i] == unplayedSample) {
        etat = true;
        break;
      }
    }
    if (index_tab == 0 && unplayedSample == lastPlayedSample) {
      etat = true;
    }
  }

  if (index_tab < nbtotfile) {
    sampleDejaJoues[index_tab] = unplayedSample;
    index_tab ++;
  }

  if (index_tab == nbtotfile) {
    index_tab = 0;
    lastPlayedSample = unplayedSample;
    initSampleSelecteur(nbtotfile);
  }
  return unplayedSample;
}
 
Could it come from this random no repeat function that I can call some times and with differents values of nbtotfile ?

It would be worth testing/watching that function, since the while(etat) might never complete?? Either add a print() at function entry and exit, or set an LED HIGH on entry and LOW on exit ....
 
in URN you might print out nbfiles and indextab. if nbfiles is ever 0, i think the while(etat) will hang. are all members of NbFiles[] non zero?

Another possible source of hang's is an array index going out of bounds ... index_tab?

you should declare InitTimerCalib and TempsCalib uint32_t
 
Last edited:
I will try it tonight or tomorrow morning and let you know asap ! I still didn't understand what is uint32_t and when use it. Even with the arduino documentation and forum...
Thx for your precious help !
 
It seems that the code is working fine without any sensor and just with random. We're wondering wether the fact of soldering sensor on long USB cable can affect the power level needed by teensy to provide energy to the sensor. If the sensor doesn't have enough energy, can it stop the running code ?
 
Hey there !!

I've corrected the freeze !!! Finally ! A big big thanks to you. I wanted to apologize to have doubted about the audio system because it just was my beginner mistake.

in URN you might print out nbfiles and indextab. if nbfiles is ever 0, i think the while(etat) will hang. are all members of NbFiles[] non zero?

Another possible source of hang's is an array index going out of bounds ... index_tab?

you should declare InitTimerCalib and TempsCalib uint32_t

You were right Manitou : the code was freezing because of the array index was not reseting whearase the total file number were smaller. I was using the function for 4 folders so when the function got a smaller nbtotfiles and the index was bigger, there was big chance that the first stocked values corresponded to the random new values. But it couldn't reset the array as it was stuck into the while loop...

Here is the code you could use if you want to play files in different folders without repeating them before the list has been played (very useful with audio files !!!) :

Code:
int index_tab[4] = 0;           // A REGLER SI ON AUGMENTE LE NOMBRE DE DOSSIER nombre de samples deja jouées;
int sampleDejaJoues[4][100];       // Défini la taille du tableau et initialise toutes les valeurs à 0
int unplayedSample = 0;
int lastPlayedSample = -1;

int URN(int folder, int nbtotfile) {
  boolean etat = true;

  while (etat) {
    etat = false;
    unplayedSample = int(random(nbtotfile));
    for (int i = 0; i < index_tab[folder]; i++) {
      if (sampleDejaJoues[folder][i] == unplayedSample) {
        etat = true;
        break;
      }
    }
    if (index_tab[folder] == 0 && unplayedSample == lastPlayedSample) {
      etat = true;
    }
  }

  if (index_tab[folder] < nbtotfile) {
    sampleDejaJoues[folder][index_tab[folder]] = unplayedSample;
    index_tab[folder] ++;
  }
  if (index_tab[folder] == nbtotfile) {
    index_tab[folder] = 0;
    lastPlayedSample = unplayedSample;
    initSampleSelecteur(folder,nbtotfile);
  }
  return unplayedSample + 1;
}

//Init Sample

void initSampleSelecteur(int folder, int nbtotfile) {
  for (int i = 0; i < nbtotfile; i++) {
    sampleDejaJoues[folder][i] = -1;
  }
}
 
Last edited:
Status
Not open for further replies.
Back
Top