Hiyall

I am building a device that takes a 5pin DIN MIDI input(awaiting parts so not implemented) from drum pads, and then plays audio from banks of samples. The banks of samples need to be added to by the user, which is why using the SD card works nicely.

I'm trying to avoid using a raspberry pi to avoid the bloat and variables of having an OS and the time taken by a boot up. That being said, I might need to resort to using a pi if I run into fairly immovable issues with a T4 + Audio Board.

The code obviously works when playing a couple of samples at the same time using RAW, but when it comes to properly spamming it, it crashes leaving me with an eeeeeeeeeeeeeee sound which is fun. This thing needs to be pretty bombproof which is one of the reasons why I went microcontroller over pi. There are 10 pads which, although it's unlikely that all of them will be sounding at the same time, should support all 10 being played at the same time.

I assume that the SD class is causing a bit of an issue, however that being out of the way I can imagine that I would still not be able to solve this problem by playing directly from the SD.

The way I see it currently is that there are 4 possibilities:
1. I have a mistake in my code, or haven't optimised it properly for audio
2. The SD class isn't up to scratch, but there might be an alternative which would allow 10 simultaneous RAW file playbacks
3. Loading the files from the SD card to the Flash chip on boot, and then play the files from there would work
4. The hardware isn't quite suited for what is necessary, and I should use a PI or similar.

Thanks everyone!

Code:
#include <Bounce.h>

#include <Audio.h>
#include <Wire.h>
#include <SPI.h>
#include <SD.h>
#include <SerialFlash.h>

// Use these with the Teensy Audio Shield
#define SDCARD_CS_PIN    10
#define SDCARD_MOSI_PIN  7
#define SDCARD_SCK_PIN   14

// GUItool: begin automatically generated code
AudioPlaySdRaw           playSdRaw1;     //xy=181.66666666666663,553.3333333333333
AudioPlaySdRaw           playSdRaw3;     //xy=184.99999999999997,664.9999999999999
AudioPlaySdRaw           playSdRaw8;     //xy=194.99999999999997,969.9999999999999
AudioPlaySdRaw           playSdRaw9;     //xy=195.00000762939453,1031.6667079925537
AudioPlaySdRaw           playSdRaw10;    //xy=198.3333282470703,1090.0000438690186
AudioPlaySdRaw           playSdRaw5;     //xy=201.66666666666663,781.6666666666665
AudioPlaySdRaw           playSdRaw2;     //xy=203.33333333333331,606.6666666666666
AudioPlaySdRaw           playSdRaw7;     //xy=203.33333333333331,916.6666666666665
AudioPlaySdRaw           playSdRaw6;     //xy=205,833.3333463668823
AudioPlaySdRaw           playSdRaw4;     //xy=206.66666666666663,721.6666666666665
AudioAmplifier           amp2; //xy=333.0000457763672,605.9999933242798
AudioAmplifier           amp1;           //xy=334.3333740234375,554.3333101272583
AudioAmplifier           amp3; //xy=337.0000534057617,664.000002861023
AudioAmplifier           amp4; //xy=337.47621154785156,730.6666965484619
AudioAmplifier           amp5; //xy=337.47620391845703,784.6667003631592
AudioAmplifier           amp8; //xy=337,910
AudioAmplifier           amp9; //xy=337.47615814208984,976.666693687439
AudioAmplifier           amp10; //xy=337.4761505126953,1030.6666975021362
AudioAmplifier           amp6; //xy=344.47620391845703,833.0000019073486
AudioAmplifier           amp11; //xy=344.4761505126953,1078.9999990463257
AudioMixer4              mixer10; //xy=513,988
AudioMixer4              mixer8; //xy=515.4762802124023,612.8571166992188
AudioMixer4              mixer7; //xy=517.7142944335938,768.5238037109375
AudioMixer4              mixer9; //xy=681.4285888671875,719
AudioEffectFlange        flange1; //xy=828.5714721679688,780.4285888671875
AudioEffectFreeverb      freeverb1; //xy=833.5714721679688,701.4285888671875
AudioEffectBitcrusher    bitcrusher1;    //xy=838.333366394043,739.9999885559082
AudioMixer4              mixer1; //xy=980.5714721679688,734.1428833007812
AudioAmplifier           amp7; //xy=1107,734.0000610351562
AudioOutputI2S           i2s1;           //xy=1232.571418762207,728.2857475280762
AudioConnection          patchCord1(playSdRaw1, amp1);
AudioConnection          patchCord2(playSdRaw3, amp3);
AudioConnection          patchCord3(playSdRaw8, amp9);
AudioConnection          patchCord4(playSdRaw9, amp10);
AudioConnection          patchCord5(playSdRaw10, amp11);
AudioConnection          patchCord6(playSdRaw5, amp5);
AudioConnection          patchCord7(playSdRaw2, amp2);
AudioConnection          patchCord8(playSdRaw7, amp8);
AudioConnection          patchCord9(playSdRaw6, amp6);
AudioConnection          patchCord10(playSdRaw4, amp4);
AudioConnection          patchCord11(amp2, 0, mixer8, 1);
AudioConnection          patchCord12(amp1, 0, mixer8, 0);
AudioConnection          patchCord13(amp3, 0, mixer8, 2);
AudioConnection          patchCord14(amp4, 0, mixer7, 0);
AudioConnection          patchCord15(amp5, 0, mixer7, 1);
AudioConnection          patchCord16(amp8, 0, mixer10, 0);
AudioConnection          patchCord17(amp9, 0, mixer10, 1);
AudioConnection          patchCord18(amp10, 0, mixer10, 2);
AudioConnection          patchCord19(amp6, 0, mixer7, 2);
AudioConnection          patchCord20(amp11, 0, mixer10, 3);
AudioConnection          patchCord21(mixer10, 0, mixer9, 2);
AudioConnection          patchCord22(mixer8, 0, mixer9, 0);
AudioConnection          patchCord23(mixer7, 0, mixer9, 1);
AudioConnection          patchCord24(mixer9, freeverb1);
AudioConnection          patchCord25(mixer9, flange1);
AudioConnection          patchCord26(mixer9, 0, mixer1, 0);
AudioConnection          patchCord27(mixer9, bitcrusher1);
AudioConnection          patchCord28(flange1, 0, mixer1, 3);
AudioConnection          patchCord29(freeverb1, 0, mixer1, 1);
AudioConnection          patchCord30(bitcrusher1, 0, mixer1, 2);
AudioConnection          patchCord31(mixer1, amp7);
AudioConnection          patchCord32(amp7, 0, i2s1, 0);
AudioConnection          patchCord33(amp7, 0, i2s1, 1);
AudioControlSGTL5000     sgtl5000_1;     //xy=584,113
// GUItool: end automatically generated code

File root;

String padFiles[10];
int numBanksTotal;
int numBank;
bool fx1Toggle;
bool fx2Toggle;
bool fx3Toggle;

Bounce bankL = Bounce(0,5);
Bounce bankR = Bounce(1,5);
Bounce fx1 = Bounce(2,5);
Bounce fx2 = Bounce(3,5);
Bounce fx3 = Bounce(4,5);

void setup() {
  // put your setup code here, to run once:
  pinMode(0, INPUT_PULLUP);
  pinMode(1, INPUT_PULLUP);
  pinMode(2, INPUT_PULLUP);
  pinMode(3, INPUT_PULLUP);
  pinMode(4, INPUT_PULLUP);

  pinMode(14, OUTPUT);
  pinMode(15, OUTPUT);
  pinMode(16, OUTPUT);

  // Configure SPI
  SPI.setMOSI(SDCARD_MOSI_PIN);
  SPI.setSCK(SDCARD_SCK_PIN);

  Serial.begin(9600);
  //while(!Serial);

  fx1Toggle=false;
  fx2Toggle=false;
  fx3Toggle=false;

  Serial.println(AudioMemoryUsageMax());
  AudioMemory(16);

  sgtl5000_1.enable();
  sgtl5000_1.volume(0.5);

  usbMIDI.setHandleNoteOn(myNoteOn);
  usbMIDI.setHandleNoteOff(myNoteOff);
  
  numBank=0;
  checkFileSystem();
  setPadFiles();
  setAudioSettings();
  
}

void setAudioSettings(){
  //going to need to have all of the settings as variables that can be updated
  Serial.print("FX1: ");
  Serial.println(fx1Toggle);
  Serial.print("FX2: ");
  Serial.println(fx2Toggle);
  Serial.print("FX3: ");
  Serial.println(fx3Toggle);

  setIndicators();
}

void checkFileSystem(){
  //read the SD, are there folders? make a list of the folders
  //all of the pads will be assigned, but there should be a check when loading
  //print out info to the console for debug
  if (!(SD.begin(SDCARD_CS_PIN))) {
    // stop here, but print a message repetitively
    while (1) {
      Serial.println("Unable to access the SD card");
      delay(500);
    }
  }
  root = SD.open("/");
  printDirectory(root, 0);
  
  Serial.print("number of banks found: ");
  Serial.println(numBanksTotal);
}

void loop() {
  // put your main code here, to run repeatedly:
  checkMIDI();
  checkButtons();
  //Serial.println(AudioMemoryUsage());
}

void checkButtons(){
  //check if the UI buttons have been pressed
  bankL.update();
  bankR.update();
  fx1.update();
  fx2.update();
  fx3.update();

  if(bankL.fallingEdge()){
    numBank--;
    if(numBank<0)numBank=numBanksTotal-1;
    setPadFiles();
  }
  if(bankR.fallingEdge()){
    numBank++;
    if(numBank>=numBanksTotal)numBank=0;
    setPadFiles();
  }
  if(fx1.fallingEdge()){
    fx1Toggle=!fx1Toggle;
    Serial.print("FX1: ");
    Serial.println(fx1Toggle);
    if(fx1Toggle)freeverb1.roomsize(0.8);
    else freeverb1.roomsize(0.0);
    setIndicators();
  }
  if(fx2.fallingEdge()){
    fx2Toggle=!fx2Toggle;
    Serial.print("FX2: ");
    Serial.println(fx2Toggle);
    if(fx2Toggle)bitcrusher1.bits(4);
    else bitcrusher1.bits(16);
    setIndicators();
  }
  if(fx3.fallingEdge()){
    fx3Toggle=!fx3Toggle;
    Serial.print("FX3: ");
    Serial.println(fx3Toggle);
    
    setIndicators();
  }
}

void checkMIDI(){
  //is there a MIDI input?
  usbMIDI.read();
}
void playNote(int midiNote){
  Serial.println(midiNote);
  if(midiNote==60)playSdRaw1.play(padFiles[0].c_str());
  if(midiNote==62)playSdRaw2.play(padFiles[1].c_str());
  if(midiNote==64)playSdRaw3.play(padFiles[2].c_str());
  if(midiNote==66)playSdRaw4.play(padFiles[3].c_str());
  if(midiNote==70)playSdRaw5.play(padFiles[4].c_str());
  if(midiNote==73)playSdRaw6.play(padFiles[5].c_str());
  if(midiNote==74)playSdRaw7.play(padFiles[6].c_str());
  if(midiNote==80)playSdRaw8.play(padFiles[7].c_str());
  if(midiNote==80)playSdRaw9.play(padFiles[8].c_str());
  if(midiNote==80)playSdRaw10.play(padFiles[9].c_str());
}

void myNoteOn(byte channel, byte note, byte velocity) {
  // When using MIDIx4 or MIDIx16, usbMIDI.getCable() can be used
  // to read which of the virtual MIDI cables received this message.
  Serial.print("Note On, ch=");
  Serial.print(channel, DEC);
  Serial.print(", note=");
  Serial.print(note, DEC);
  Serial.print(", velocity=");
  Serial.println(velocity, DEC);
  playNote(int(note));
}

void myNoteOff(byte channel, byte note, byte velocity) {
  Serial.print("Note Off, ch=");
  Serial.print(channel, DEC);
  Serial.print(", note=");
  Serial.print(note, DEC);
  Serial.print(", velocity=");
  Serial.println(velocity, DEC);
}

void setIndicators(){
  if(fx1Toggle)digitalWrite(14,HIGH);
  else digitalWrite(14,LOW);
  if(fx2Toggle)digitalWrite(15,HIGH);
  else digitalWrite(15,LOW);
  if(fx3Toggle)digitalWrite(16,HIGH);
  else digitalWrite(16,LOW);
}

void setPadFiles(){
  //set the pad filenames
  Serial.print("pads set to bank: ");
  Serial.println(numBank);
  String adjNumBank;
  if(numBank<10)adjNumBank="bank0"+String(numBank);
  else adjNumBank = "bank"+String(numBank);
  padFiles[0]=adjNumBank+"/pad0.RAW";
  padFiles[1]=adjNumBank+"/pad1.RAW";
  padFiles[2]=adjNumBank+"/pad2.RAW";
  padFiles[3]=adjNumBank+"/pad3.RAW";
  padFiles[4]=adjNumBank+"/pad4.RAW";
  padFiles[5]=adjNumBank+"/pad5.RAW";
  padFiles[6]=adjNumBank+"/pad6.RAW";
  padFiles[7]=adjNumBank+"/pad7.RAW";
  padFiles[8]=adjNumBank+"/pad8.RAW";
  padFiles[9]=adjNumBank+"/pad9.RAW";
 
  //playSdRaw1.play(padFiles[0].c_str());
//debug test
  for(int i=0;i<10;i++){
    Serial.println(padFiles[i]);
  }
}

void printDirectory(File dir, int numTabs) {
  while (true) {

    File entry =  dir.openNextFile();
    if (! entry) {
      // no more files
      break;
    }
    for (uint8_t i = 0; i < numTabs; i++) {
      //Serial.print('\t');
    }
    //Serial.print(entry.name());
    if (entry.isDirectory()) {
      //Serial.println("/");
      if(String(entry.name()).startsWith("BANK"))numBanksTotal++;
      Serial.println(entry.name());
      printDirectory(entry, numTabs + 1);
    } else {
      // files have sizes, directories do not
      //Serial.print("\t\t");
      //Serial.println(entry.size(), DEC);
    }
    entry.close();
  }
}