Loud Buzzing Crash

sethhead

Member
Hi there, this is my first post, so I apologize if I am a little green with all of this. I have been attempting to make a toy for my son that uses the Teensy 3.2 and audio shield along with a USB game controller that I have wired each button to individual pins for the Teensy to read. The concept is that each button on the controller triggers a wav file that I can customize. Right now, I am attempting to make it so that you can trigger music to play using playSDWav2. While the music is playing, you can trigger all of the sound effects with the other buttons using playSDWav1 simultaneously (going through a mixer to combine them). All of the output comes out of an 8ohm, .25w speaker that is connected to a PAM8302 amplifier. I am also using a Mac with the Teensyduino application and Teensy Loader to upload the code onto my Teensy.

Right now, everything is working as intended with the exception of a fatal crash that results in a loud buzzing noise. The buzzing noise seems to occur more frequently when two files are being played at once (usually when the background music is playing and the sound effect is being pressed in rapid succession), however it will also happen when a single wav file is being played as well (although less frequently). I found a thread where someone had a similar issue and suggested using an experimental SD library optimization by changing the SD_t3.h file, which I tried. It seems the problem is still persisting and I am not sure why.

I have noticed that specific files tend to trigger the crash more than others (the a button and left button are more consistently creating the buzzing crash), but I am not sure if it is related to my code or possibly the wav files themselves. I am also wondering if I am maybe just simply pushing the Teensy too hard with what I am trying to do. Any help would be greatly appreciated! Here is my complete code:

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

	//documentation for these libraries are found here: https://www.pjrc.com/teensy/gui/?info=AudioPlaySdWav
	

	AudioPlaySdWav           playSdWav2;     //xy=291,430
	AudioPlaySdWav           playSdWav1;     //xy=296,301
	AudioMixer4              mixer1;         //xy=563,363
	AudioOutputI2S           i2s1;           //xy=780,362
	AudioConnection          patchCord1(playSdWav2, 0, mixer1, 1);
	AudioConnection          patchCord2(playSdWav1, 0, mixer1, 0);
	AudioConnection          patchCord3(mixer1, 0, i2s1, 0);
	AudioConnection          patchCord4(mixer1, 0, i2s1, 1);
	AudioControlSGTL5000     sgtl5000_1;     //xy=64.5,50
	

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

	//int buttonPins[] = {0,1,2,3,4,5,8,15,16,17,20,21};
	

	Bounce buttonA = Bounce(0, 10);
	Bounce buttonB = Bounce(1, 10);
	Bounce buttonY = Bounce(2, 10);
	Bounce buttonX = Bounce(3, 10);
	Bounce buttonR = Bounce(4, 10);
	Bounce buttonL = Bounce(5, 10);
	Bounce buttonStart = Bounce(8, 10);
	Bounce buttonUp = Bounce(15, 10);
	Bounce buttonRight = Bounce(16, 10);
	Bounce buttonDown = Bounce(17, 10);
	Bounce buttonLeft = Bounce(20, 10);
	Bounce buttonSelect = Bounce(21, 10);
	

	

	

	//used for shorthand when checking if select button is being held
	int selectPin = 21;
	

	//used to determine whether the drum machine hihat is being looped or not in the drum state
	bool loopOn = false;
	

	//used to determine if the game state or drum state is active (inputting the Konami code will activate the drums tate)
	bool gameState = true;
	

	//sets the initial volume
	float vol = 0.9;
	

	//used to change volume by an increment set as num
	void changeVolume(float num) {
	  vol = vol + num;
	  mixer1.gain(0, vol);
	  mixer1.gain(1, vol);
	  mixer1.gain(2, vol);
	  mixer1.gain(3, vol);
	  Serial.println(vol);
	}
	

	//tempo for the looped hihat in the drum state
	int tempo = 200;
	

	//array to hold file folder extensions for drum preset folders
	char drumPresets[40][32];
	

	//array to hold file folder extensions for game preset folders
	char gamePresets[40][32];
	

	//used to hold the number of drum and game presets to be used when switching presets
	int numberOfDrums = 0;
	int numberOfGames = 0;
	

	//used to hold the number of background music files to be able to generate a random number that would pick a bgr file at random
	//stores the number of BGR files in the same index corresponding to the index of the preset in gamePresets 
	//(therefore being able to be called using the same reference index stored in currentIndex
	int numberOfBgr[40];
	

	//variable used to determine which preset is currently active in the drum or game arrays, depending on whther or not the drum or game state is active
	int currentIndex = 0;
	

	//used to point to the string stored in the game or drum state arrays that will be used as the current folder extension acting as the current preset
	const char *currentPreset;
	

	//function to combine the current preset string (or preset folder) and the button pressed. \
	//Concatenate file extension (variable named "combined") will look something like this: "_GAMES/MARIO/A/COIN.WAV"
	void playFile(const char *input) {
	    char combined[32] = {0};
	    Serial.println(input);
	    strcpy(combined, currentPreset);
	    strcat(combined, "/");
	    strcat(combined, input);
	  //combined now looks like "_GAMES/MARIO/A" if input is "A." 
	  //SD.open will then find the first file in the "A" folder and the name of this file will be concatenated onto combined variable
	    File folder = SD.open(combined);
	    File sound = folder.openNextFile();
	    if (!sound) {
	      Serial.println("no file to play");
	      return;
	      }
	    strcat(combined, "/");
	    strcat(combined, sound.name());
	    Serial.println("combined: ");
	    Serial.println(combined);
	    //play the file
	    playSdWav1.play(combined);
	

	}
	

	int getRandomNumber(int maximum) {
	    srand((unsigned)millis());
	    return rand() % maximum;
	  }
	

	//function to play a background music file from the "BGR" folder in the current preset folder
	void playRandomBgr() {
	  Serial.println("\ntrying to play bgr");
	  
	  char combined[32] = {0};
	  
	  strcpy(combined, currentPreset);
	  strcat(combined, "/bgr");
	  File directory = SD.open(combined);
	  if (!numberOfBgr[currentIndex]){return;}
	

	  int bgrSize = numberOfBgr[currentIndex];
	  
	  int randIndex = getRandomNumber(bgrSize) + 1;
	  Serial.println("random index = ");
	  Serial.print(randIndex);
	  Serial.print("\n\n");
	  for (int i = 1; i <= randIndex; i++) {
	    File entry = directory.openNextFile();
	    if (i == randIndex) {
	      strcat(combined, "/");
	      strcat(combined, entry.name());
	      if (!entry) {
	          Serial.println("**no bgr to play**");
	          return;
	        }
	        Serial.println("trying to play ");
	        Serial.print(combined);
	        Serial.print("\n\n");
	        if (!SD.exists(combined)){
	          return;
	          }
	      playSdWav2.play(combined);
	      }
	  }
	}
	

	//the following code allows the Konami Code to be inputted for the purpose of switching from the game state to the drum state
	char konamiCode[11][9] = {"Up", "Up", "Down", "Down", "Left", "Right", "Left", "Right", "B", "A", "Start"};
	int konamiCodePlace = 0;
	

	bool konamiCodeCheck(const char *input) {
	  //what to do if the last input of the konami code is pressed
	  if (!strcmp(konamiCode[konamiCodePlace], input)){
	      if (konamiCodePlace == 10) {
	          konamiCodePlace = 0;
	          playSdWav2.stop();
	          Serial.println("***You did the konami code!***");
	          gameState = !gameState;
	          //will need to change so that you can get out of drumPresets if done a second time
	          currentPreset = drumPresets[0];
	          Serial.print(currentPreset);
	      }else{
	        //what to do if any other Konami code input is correctly pressed
	          konamiCodePlace++;
	      }
	    return true;
	  }else{
	    //what to do if Konami code input is not pressed
	    konamiCodePlace = 0;
	    return false;
	  }
	}
	

	

	//files should be arranged in the following manner:
	//    _GAMES (or _DRUMS if a drum preset
	//      MARIO
	//        A
	//          COIN.WAV
	//        B
	//          JUMP.WAV
	//        X
	//          FIREBALL.WAV
	//        Y
	//          BLOCK.WAV
	//        L
	//          1UP.WAV
	//        R
	//          POWERUP.WAV
	//        UP
	//          VINE.WAV
	//        DOWN
	//          PIPE.WAV
	//        LEFT
	//          BUMP.WAV
	//        RIGHT
	//          DEATH.WAV
	//        BGR (will not be present in a drum preset)
	//          OVERWRLD.WAV
	//          UNDRWRLD.WAV
	//          CASTLE.WAV
	//          WATER.WAV
	

	

	//used to scan the SD card to populate preset arrays
	void scanBgr(const char *folderName, int index) {
	  char combined[32] = {0};
	  strcpy(combined, folderName);
	  strcat(combined, "/bgr");
	    File bgrDir = SD.open(combined);
	    Serial.print("\ntrying to scan ");
	    Serial.print(combined);
	    Serial.print(" for bgr and length is ");
	    int bgrInDir = 0;
	        while (true) {
	            File bgr = bgrDir.openNextFile();
	            if (bgr) {
	              bgrInDir++;
	            }else{
	              bgrDir.rewindDirectory();
	              numberOfBgr[index] = bgrInDir;
	              Serial.println(numberOfBgr[index]);
	              break;
	            }
	        }
	  }
	    
	    
	void scanFolder(const char *folderName, bool isGame) {
	  Serial.println("scanning folders");
	    File directory = SD.open(folderName);
	    int index = 0;
	    while (true) {
	        File entry = directory.openNextFile();
	        if (entry) {
	            char combined[32] = {0};
	            strcpy(combined, folderName);
	            strcat(combined, "/");
	            strcat(combined, entry.name());
	            if (isGame) {
	

	                scanBgr(combined, index);
	              
	                strcpy(gamePresets[index], combined);
	                Serial.println(gamePresets[0]);
	                Serial.println(gamePresets[1]);
	                Serial.println(gamePresets[2]);
	                Serial.println(gamePresets[3]);
	                Serial.println("\n\n\n\n\n");
	                numberOfGames++;
	            }else{
	                //Serial.println(index);
	                strcpy(drumPresets[index], combined);
	                Serial.println(drumPresets[index]);
	                Serial.println("\n\n\n\n\n");
	                numberOfDrums++;
	            }
	            index++;
	        }else{
	            Serial.println("done with");
	            Serial.println(folderName);
	            directory.rewindDirectory();
	            break;
	        }
	        
	    }
	}
	    
	    
	    
	    
	

	

	void setup() {
	

	  pinMode(0, INPUT_PULLUP);
	  pinMode(1, INPUT_PULLUP);
	  pinMode(2, INPUT_PULLUP);
	  pinMode(3, INPUT_PULLUP);
	  pinMode(4, INPUT_PULLUP);
	  pinMode(5, INPUT_PULLUP);
	  pinMode(8, INPUT_PULLUP);
	  pinMode(15, INPUT_PULLUP);
	  pinMode(16, INPUT_PULLUP);
	  pinMode(17, INPUT_PULLUP);
	  pinMode(20, INPUT_PULLUP);
	  pinMode(21, INPUT_PULLUP);
	    
	

	  Serial.begin(9600);
	  AudioMemory(8);
	  sgtl5000_1.enable();
	  sgtl5000_1.volume(0.5);
	  SPI.setMOSI(SDCARD_MOSI_PIN);
	  SPI.setSCK(SDCARD_SCK_PIN);
	  if (!(SD.begin(SDCARD_CS_PIN))) {
	    while (1) {
	      Serial.println("Unable to access the SD card");
	      delay(500);
	    }
	  delay(1000);
	  }
	  scanFolder("_GAMES",true);
	  scanFolder("_DRUMS",false);
	  
	  //drumPresets[0] = "_DRUMS/postal";
	  //gamePresets[0] = "_GAMES/megaman";
	  //gamePresets[1] = "_GAMES/smb";
	  //gamePresets[2] = "_GAMES/loz";
	  //gamePresets[3] = "_GAMES/sonic";
	

	  Serial.println(gamePresets[0]);
	  //currentIndex = 0;
	  //currentPreset = gamePresets[currentIndex];
	  currentPreset = gamePresets[getRandomNumber(numberOfGames)];
	  delay(1000);   
	}
	

	void loop() {
	//going to loop hihat in the delay of the tempo
	  if (!gameState){
	    if (loopOn == true) {
	      //too loud
	      playFile("Y");
	      delay(tempo);
	    }
	  }
	

	  //what to do for each button press
	  if (buttonA.update()){
	    if (buttonA.fallingEdge()){
	      Serial.print("a");
	      playFile("A");
	      konamiCodeCheck("A");
	    }
	  }
	

	  if (buttonB.update()){
	    if (buttonB.fallingEdge()){
	      playFile("B");
	      konamiCodeCheck("B");
	    }
	  }
	  if (buttonX.update()){
	    if (buttonX.fallingEdge()){
	      playFile("X");
	      konamiCodePlace = 0;
	    }
	  }
	

	  if (buttonY.update()){
	    if (buttonY.fallingEdge()){
	      playFile("Y");
	      konamiCodePlace = 0;
	    }
	  }
	

	  if (buttonUp.update()){
	    if (buttonUp.fallingEdge()){
	      //if select is being held as hotkey, increase volume
	      if (digitalRead(selectPin) == LOW && vol < 1){
	        changeVolume(0.1);
	      }
	      playFile("Up");
	      konamiCodeCheck("Up");
	    }
	  }
	

	  if (buttonDown.update()){
	    if (buttonDown.fallingEdge()){
	      playFile("Down");
	      //if select is being held as hotkey, decrease volume
	      if (digitalRead(selectPin) == LOW && vol > 0.1){
	        changeVolume(-0.1);
	      }
	      konamiCodeCheck("Down");
	    }
	  }
	

	  if (buttonLeft.update()){
	    if (buttonLeft.fallingEdge()){
	      //if select is pressed also
	      if (digitalRead(selectPin) == LOW){
	        playSdWav2.stop();
	        //if it's greater than zero, increment up
	        if (currentIndex > 0){
	          currentIndex--;
	        //if it is zero, cycle back around to the last index
	        }else{
	          //what to do if in gameState
	          if (gameState){
	            //currentIndex = last index of gamePresets
	            currentIndex = numberOfGames - 1;
	          }else{
	            //currentIndex = last index of drumPresets
	            currentIndex = numberOfDrums - 1;
	          }
	        }
	        //sets the current preset with the previously set index
	        if (gameState) {
	          currentPreset = gamePresets[currentIndex];
	          Serial.println(currentPreset);
	        }else{
	          currentPreset = drumPresets[currentIndex];
	          Serial.println(currentPreset);
	        }
	      }else{
	        //do this only if select isn't pressed
	         konamiCodeCheck("Left");
	      }
	      //do this if select is pressed or not (put this with konamiCodeCheck if it should only be done without select
	      playFile("Left");
	    }
	  }
	

	  if (buttonRight.update()){
	    if (buttonRight.fallingEdge()){
	      //if select is pressed
	      if (digitalRead(selectPin) == LOW){
	        playSdWav2.stop();
	        //if not in game state
	        if (!gameState) {
	          //notworking here?
	          //if not at the end of the list, index goes up
	          if (currentIndex < numberOfDrums - 1){
	            currentIndex++;
	          }else{
	            //if at the end of the list, index goes back to zero
	            currentIndex = 0;
	          }
	          //sets the drum preset
	          currentPreset = drumPresets[currentIndex];
	          Serial.println(currentPreset);
	          //what to do if in gamestate
	        }else{
	          //if not at the end of the list, index goes up
	          if (currentIndex < numberOfGames - 1){
	            currentIndex++;
	          }else{
	            //if at the end of the list, index goes back to zero
	            currentIndex = 0;
	          }
	          currentPreset = gamePresets[currentIndex];
	          Serial.println(currentPreset);
	        }
	      }else{
	        //check for konami code if select is not being pressed
	        konamiCodeCheck("Right");
	      }
	      //plays no matter what
	      playFile("Right");
	    }
	  }
	

	   if (buttonStart.update()){
	    if (buttonStart.fallingEdge()){
	      Serial.print("Start");
	      if (gameState) {
	        if (playSdWav2.isPlaying()){
	          //if in gamestate and something is already playing, stop playing
	          playSdWav2.stop();
	        }else{
	          //if not playing, start playing a random bgr
	          playRandomBgr();
	        }
	        konamiCodeCheck("Start");
	      //always happens whether successfully inputting code or not
	      if (digitalRead(selectPin) == LOW){
	        //turns on loop if select is held
	        //**go back to make this work only in drum state
	        loopOn = !loopOn;
	        }
	      }
	    }
	  }
	

	  if (buttonSelect.update()){
	    if (buttonSelect.fallingEdge()){
	      konamiCodePlace = 0;
	    }
	  }
	

	  if (buttonL.update()){
	    if (buttonL.fallingEdge()){
	      //if select is held as hotkey, decrease tempo (will increase the delay)
	      if (digitalRead(selectPin) == LOW && tempo > 100) {
	        tempo = tempo +5;
	      }
	      playFile("L");
	      konamiCodePlace = 0;
	    }
	  }
	

	  if (buttonR.update()){
	    if (buttonR.fallingEdge()){
	      //if select is held as hotkey, increase tempo (will decrease the delay)
	      if (digitalRead(selectPin) == LOW && tempo < 1000) {
	         tempo = tempo -5;
	      }
	      playFile("R");
	      konamiCodePlace = 0;
	    }
	  }
	}
 
Does the application crash or is it just a 'crashing' sound ?
Is the crash momentary or continous ?
Does the sound return to normal when the effect is finished playing ?
Does the issue depend on what background file is being played ?
 
The application crashes completely (meaning no functionality or serial output).
The loud buzz plays continuously until I power it off. Powering it back on resets it back to normal.
Also, which background file does not seem to affect it.
 
I think I isolated the problem to the plaFile function. I created a test sketch that isolates the problem without some of the other (possibly convoluded) code:

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

//documentation for these libraries are found here: https://www.pjrc.com/teensy/gui/?info=AudioPlaySdWav

AudioPlaySdWav           playSdWav2;     //xy=291,430
AudioPlaySdWav           playSdWav1;     //xy=296,301
AudioMixer4              mixer1;         //xy=563,363
AudioOutputI2S           i2s1;           //xy=780,362
AudioConnection          patchCord1(playSdWav2, 0, mixer1, 1);
AudioConnection          patchCord2(playSdWav1, 0, mixer1, 0);
AudioConnection          patchCord3(mixer1, 0, i2s1, 0);
AudioConnection          patchCord4(mixer1, 0, i2s1, 1);
AudioControlSGTL5000     sgtl5000_1;     //xy=64.5,50

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

//int buttonPins[] = {0,1,2,3,4,5,8,15,16,17,20,21};

Bounce buttonA = Bounce(0, 10);
Bounce buttonB = Bounce(1, 10);
Bounce buttonY = Bounce(2, 10);
Bounce buttonX = Bounce(3, 10);
Bounce buttonR = Bounce(4, 10);
Bounce buttonL = Bounce(5, 10);
Bounce buttonStart = Bounce(8, 10);
Bounce buttonUp = Bounce(15, 10);
Bounce buttonRight = Bounce(16, 10);
Bounce buttonDown = Bounce(17, 10);
Bounce buttonLeft = Bounce(20, 10);
Bounce buttonSelect = Bounce(21, 10);



const char *currentPreset;
void playFile(const char *input) {
    char combined[32] = {0};
    Serial.println(input);
    strcpy(combined, currentPreset);
    strcat(combined, "/");
    strcat(combined, input);
  //combined now looks like "_GAMES/MARIO/A" if input is "A." 
  //SD.open will then find the first file in the "A" folder and the name of this file will be concatenated onto combined variable

    File folder = SD.open(combined);
    File sound = folder.openNextFile();
    if (!sound) {
      Serial.println("no file to play");
      return;
      }
    strcat(combined, "/");
    strcat(combined, sound.name());


  
    Serial.println("combined: ");
    Serial.println(combined);
    //play the file
    playSdWav1.play(combined);
}

    


void setup() {

  pinMode(0, INPUT_PULLUP);
  pinMode(1, INPUT_PULLUP);
  pinMode(2, INPUT_PULLUP);
  pinMode(3, INPUT_PULLUP);
  pinMode(4, INPUT_PULLUP);
  pinMode(5, INPUT_PULLUP);
  pinMode(8, INPUT_PULLUP);
  pinMode(15, INPUT_PULLUP);
  pinMode(16, INPUT_PULLUP);
  pinMode(17, INPUT_PULLUP);
  pinMode(20, INPUT_PULLUP);
  pinMode(21, INPUT_PULLUP);
    
  currentPreset = "_GAMES/_MEGAMAN";
    

  Serial.begin(9600);
  AudioMemory(8);
  sgtl5000_1.enable();
  sgtl5000_1.volume(0.5);
  SPI.setMOSI(SDCARD_MOSI_PIN);
  SPI.setSCK(SDCARD_SCK_PIN);
  if (!(SD.begin(SDCARD_CS_PIN))) {
    while (1) {
      Serial.println("Unable to access the SD card");
      delay(500);
    }
  delay(1000);
  }
  delay(1000);   
}

void loop() {
//going to loop hihat in the delay of the tempo
  if (!playSdWav2.isPlaying()) {
    playSdWav2.play("BOSS.WAV");
  }
  //what to do for each button press
  if (buttonA.update()){
    if (buttonA.fallingEdge()){
      playFile("A");
      //playSdWav1.play("JUMP.WAV");
    }
  }
}

The idea behind this function is for a way to open a specific file folder and retrieve the name of the first file in that file folder, concatenating to the "combined" variable as it goes. The "combined" variable would then represent the path to play the file used as an argument in the playSdWav1 function. I am seeing the issue specifically around SD.open and folder.openNextFile. I am going to research these functions a little bit more to see what is causing them to not work properly.
 
Perhaps the sound file should be closed before calling playSdWav1.play(combined), it is opened again in this function.
 
That's a good point. I added folder.close() as well as sound.close() (I'm not sure if I need both or just sound.close). I also added a check to make sure the file paths exist before calling .open()

The problem is greatly reduced, however it still is happening when both channels are playing. I am noticing that SD.exists(combined) is returning as true most of the time, but will occasionally return as false (although the file path is the same). I am wondering if I'm missing something, or if there is something about the SD library that makes these functions somewhat unreliable. I feel like I'm getting closer, thanks for your help mlu!

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

//documentation for these libraries are found here: https://www.pjrc.com/teensy/gui/?info=AudioPlaySdWav

AudioPlaySdWav           playSdWav2;     //xy=291,430
AudioPlaySdWav           playSdWav1;     //xy=296,301
AudioMixer4              mixer1;         //xy=563,363
AudioOutputI2S           i2s1;           //xy=780,362
AudioConnection          patchCord1(playSdWav2, 0, mixer1, 1);
AudioConnection          patchCord2(playSdWav1, 0, mixer1, 0);
AudioConnection          patchCord3(mixer1, 0, i2s1, 0);
AudioConnection          patchCord4(mixer1, 0, i2s1, 1);
AudioControlSGTL5000     sgtl5000_1;     //xy=64.5,50

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

//int buttonPins[] = {0,1,2,3,4,5,8,15,16,17,20,21};

Bounce buttonA = Bounce(0, 10);
Bounce buttonB = Bounce(1, 10);
Bounce buttonY = Bounce(2, 10);
Bounce buttonX = Bounce(3, 10);
Bounce buttonR = Bounce(4, 10);
Bounce buttonL = Bounce(5, 10);
Bounce buttonStart = Bounce(8, 10);
Bounce buttonUp = Bounce(15, 10);
Bounce buttonRight = Bounce(16, 10);
Bounce buttonDown = Bounce(17, 10);
Bounce buttonLeft = Bounce(20, 10);
Bounce buttonSelect = Bounce(21, 10);



const char *currentPreset;
void playFile(const char *input) {
    char combined[32] = {0};
    strcpy(combined, currentPreset);
    strcat(combined, "/");
    strcat(combined, input);
  //combined now looks like "_GAMES/MARIO/A" if input is "A." 
  //SD.open will then find the first file in the "A" folder and the name of this file will be concatenated onto combined variable
    Serial.println(combined);
    if (!SD.exists(combined)) {
        Serial.println("pathfile does not exist");
        Serial.println("pathfile:    ");
        Serial.println(combined);
        return;
      }else{
        File folder = SD.open(combined);
        if (!folder) {
            Serial.println("Something went wrong with the file path in playFile");
            Serial.println("file path:   ");
            Serial.print(combined);
            folder.close();
            return;
        }
        File sound = folder.openNextFile();
        if (!sound) {
          Serial.println("could not open next file");
          Serial.println("file path:   ");
          Serial.print(combined);
          folder.close();
          sound.close();
          return;
        }
      strcat(combined, "/");
      strcat(combined, sound.name());
    
    folder.close();
    sound.close();
  
      Serial.println("file path:   ");
      Serial.print(combined);
      
      //play the file
      playSdWav1.play(combined);
    }
}

    


void setup() {

  pinMode(0, INPUT_PULLUP);
  pinMode(1, INPUT_PULLUP);
  pinMode(2, INPUT_PULLUP);
  pinMode(3, INPUT_PULLUP);
  pinMode(4, INPUT_PULLUP);
  pinMode(5, INPUT_PULLUP);
  pinMode(8, INPUT_PULLUP);
  pinMode(15, INPUT_PULLUP);
  pinMode(16, INPUT_PULLUP);
  pinMode(17, INPUT_PULLUP);
  pinMode(20, INPUT_PULLUP);
  pinMode(21, INPUT_PULLUP);
    
  currentPreset = "_GAMES/_MEGMAN";
    

  Serial.begin(9600);
  AudioMemory(8);
  sgtl5000_1.enable();
  sgtl5000_1.volume(0.5);
  SPI.setMOSI(SDCARD_MOSI_PIN);
  SPI.setSCK(SDCARD_SCK_PIN);
  if (!(SD.begin(SDCARD_CS_PIN))) {
    while (1) {
      Serial.println("Unable to access the SD card");
      delay(500);
    }
  delay(1000);
  }
  delay(1000);   
}

void loop() {
//going to loop hihat in the delay of the tempo
  if (!playSdWav2.isPlaying()) {
    //playSdWav2.play("BOSS.WAV");
  }
  //what to do for each button press
  if (buttonA.update()){
    if (buttonA.fallingEdge()){
      playFile("A");
      //playSdWav1.play("JUMP.WAV");
    }
  }
}
 
I couldn't figure out why the SD library wasn't functioning reliably, so I simplified my file system so that every file in each preset is named the same ("A.wav," "B.wav," "Up.wav," etc.) Now it works completely as intended when I am using the USB cable for power. I am trying to use battery power, and two AA's seems to work okay with a single file, but playing two at the same time is making it crash again. This time, instead of a buzz it's a loud, white noise static sound that continues indefinitely until I turn it off. It does not happen with the 5v from the USB, but I know 2 AA's is only giving me at most 3v, so I'm wonder if a third AA will fix it. Here's my code in case anyone wants to check it out.

I am also interested if anyone could tell me why 3v allows it to work mostly, but will occasionally crash. My understanding was that if it wasn't enough voltage, it simply wouldn't work. I don't know enough about electronics to understand why lower voltage would allow it work but with poorer performance. The whole point of this project was to learn more about electronics and programming in C++, so would love to hear from some of you guys who are much more knowledgeable than I am.

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

//documentation for these libraries are found here: https://www.pjrc.com/teensy/gui/?info=AudioPlaySdWav

AudioPlaySdWav           playSdWav2;     //xy=291,430
AudioPlaySdWav           playSdWav1;     //xy=296,301
AudioMixer4              mixer1;         //xy=563,363
AudioOutputI2S           i2s1;           //xy=780,362
AudioConnection          patchCord1(playSdWav2, 0, mixer1, 1);
AudioConnection          patchCord2(playSdWav1, 0, mixer1, 0);
AudioConnection          patchCord3(mixer1, 0, i2s1, 0);
AudioConnection          patchCord4(mixer1, 0, i2s1, 1);
AudioControlSGTL5000     sgtl5000_1;     //xy=64.5,50

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

//int buttonPins[] = {0,1,2,3,4,5,8,15,16,17,20,21};

Bounce buttonA = Bounce(0, 10);
Bounce buttonB = Bounce(1, 10);
Bounce buttonY = Bounce(2, 10);
Bounce buttonX = Bounce(3, 10);
Bounce buttonR = Bounce(4, 10);
Bounce buttonL = Bounce(5, 10);
Bounce buttonStart = Bounce(8, 10);
Bounce buttonUp = Bounce(15, 10);
Bounce buttonRight = Bounce(16, 10);
Bounce buttonDown = Bounce(17, 10);
Bounce buttonLeft = Bounce(20, 10);
Bounce buttonSelect = Bounce(21, 10);



//used for shorthand when checking if select button is being held
int selectPin = 21;

//used to determine whether the drum machine hihat is being looped or not in the drum state
bool loopOn = false;

//used to determine if the game state or drum state is active (inputting the Konami code will activate the drums tate)
bool gameState = true;

//sets the initial volume
float vol = 0.9;

//used to change volume by an increment set as num
void changeVolume(float num) {
  vol = vol + num;
  mixer1.gain(0, vol);
  mixer1.gain(1, vol);
  mixer1.gain(2, vol);
  mixer1.gain(3, vol);
  Serial.println(vol);
}

//tempo for the looped hihat in the drum state
int tempo = 200;

//array to hold file folder extensions for drum preset folders
char drumPresets[40][32];

//array to hold file folder extensions for game preset folders
char gamePresets[40][32];

//used to hold the number of drum and game presets to be used when switching presets
int numberOfDrums = 0;
int numberOfGames = 0;

//used to hold the number of background music files to be able to generate a random number that would pick a bgr file at random
//stores the number of BGR files in the same index corresponding to the index of the preset in gamePresets 
//(therefore being able to be called using the same reference index stored in currentIndex
int numberOfBgr[40];

//variable used to determine which preset is currently active in the drum or game arrays, depending on whther or not the drum or game state is active
int currentIndex = 0;

//used to point to the string stored in the game or drum state arrays that will be used as the current folder extension acting as the current preset
const char *currentPreset;

//function to combine the current preset string (or preset folder) and the button pressed. \
//Concatenate file extension (variable named "combined") will look something like this: "_GAMES/MARIO/A/COIN.WAV"
void playFile(const char *input) {
    char combined[32] = {0};
    Serial.println(input);
    strcpy(combined, currentPreset);
    strcat(combined, "/");
    strcat(combined, input);
    //**Comment the following line out and uncomment the lines after to experiment with scanning/reading the name of the file in a folder with the same name as the input
    strcat(combined, ".WAV");
    //combined now looks like "_GAMES/MARIO/A.WAV" if input is "A." 
  
  /*
  //Experimental code meant to read the folder with the same name as the input and pull the name of the file inside this folder
  //SD.open will then find the first file in the "A" folder and the name of this file will be concatenated onto combined variable
    File folder = SD.open(combined);
    File sound = folder.openNextFile();
    if (!sound) {
      Serial.println("no file to play");
      return;
      }
    strcat(combined, "/");
    strcat(combined, sound.name());
  
    //try this?
    sound.close();
    foler.close();
    //?
    */
  
  if (SD.exists(combined)) {
    Serial.println("file path: ");
    Serial.println(combined);
    //play the file
    playSdWav1.play(combined);
    return;
  }else{
    Serial.println("Cannot play file:  ");
    Serial.print(combined);
    return;
  }
}

int getRandomNumber(int maximum) {
    srand((unsigned)millis());
    return rand() % maximum;
  }

//function to play a background music file from the "BGR" folder in the current preset folder
void playRandomBgr() {
  Serial.println("\ntrying to play bgr");
  
  char combined[32] = {0};
  
  strcpy(combined, currentPreset);
  strcat(combined, "/bgr");
  File directory = SD.open(combined);
  if (!numberOfBgr[currentIndex]){return;}

  int bgrSize = numberOfBgr[currentIndex];
  
  int randIndex = getRandomNumber(bgrSize) + 1;
  Serial.println("random index = ");
  Serial.print(randIndex);
  Serial.print("\n\n");
  for (int i = 1; i <= randIndex; i++) {
    File entry = directory.openNextFile();
    if (i == randIndex) {
      strcat(combined, "/");
      strcat(combined, entry.name());
      if (!entry) {
          Serial.println("**no bgr to play**");
          return;
        }
        Serial.println("trying to play ");
        Serial.print(combined);
        Serial.print("\n\n");
        if (!SD.exists(combined)){
          Serial.println("Something went wrong,");
          Serial.println("Please check playRandomBgr");
          //will not attempt to play a file if it is not present
          return;
          }
        entry.close();
        directory.close();
        if (SD.exists(combined)) {
          playSdWav2.play(combined);
          return;
        }else{
          Serial.println("something went wrong and the BGR cannot be played:  ");
          Serial.println(combined);
          return;
        }     
      }
   }
}

//the following code allows the Konami Code to be inputted for the purpose of switching from the game state to the drum state
char konamiCode[11][9] = {"Up", "Up", "Down", "Down", "Left", "Right", "Left", "Right", "B", "A", "Start"};
int konamiCodePlace = 0;

bool konamiCodeCheck(const char *input) {
  //what to do if the last input of the konami code is pressed
  if (!strcmp(konamiCode[konamiCodePlace], input)){
      if (konamiCodePlace == 10) {
          konamiCodePlace = 0;
          playSdWav2.stop();
          Serial.println("***You did the konami code!***");
          gameState = !gameState;
          //will need to change so that you can get out of drumPresets if done a second time
          currentPreset = drumPresets[0];
          Serial.print(currentPreset);
      }else{
        //what to do if any other Konami code input is correctly pressed
          konamiCodePlace++;
      }
    return true;
  }else{
    //what to do if Konami code input is not pressed
    konamiCodePlace = 0;
    return false;
  }
}


//files should be arranged in the following manner:
//    _GAMES (or _DRUMS if a drum preset
//      MARIO
//        A
//          COIN.WAV
//        B
//          JUMP.WAV
//        X
//          FIREBALL.WAV
//        Y
//          BLOCK.WAV
//        L
//          1UP.WAV
//        R
//          POWERUP.WAV
//        UP
//          VINE.WAV
//        DOWN
//          PIPE.WAV
//        LEFT
//          BUMP.WAV
//        RIGHT
//          DEATH.WAV
//        BGR (will not be present in a drum preset)
//          OVERWRLD.WAV
//          UNDRWRLD.WAV
//          CASTLE.WAV
//          WATER.WAV


//used to scan the SD card to populate preset arrays
void scanBgr(const char *folderName, int index) {
  char combined[32] = {0};
  strcpy(combined, folderName);
  strcat(combined, "/bgr");
    File bgrDir = SD.open(combined);
    Serial.print("\ntrying to scan ");
    Serial.print(combined);
    Serial.print(" for bgr and length is ");
    int bgrInDir = 0;
        while (true) {
            File bgr = bgrDir.openNextFile();
            if (bgr) {
              bgrInDir++;
            }else{
              bgrDir.rewindDirectory();
              bgr.close();
              bgrDir.close();
              numberOfBgr[index] = bgrInDir;
              Serial.println(numberOfBgr[index]);
              break;
            }
        }
  }
    
    
void scanFolder(const char *folderName, bool isGame) {
  Serial.println("scanning folders");
    File directory = SD.open(folderName);
    int index = 0;
    while (true) {
        File entry = directory.openNextFile();
        if (entry) {
            char combined[32] = {0};
            strcpy(combined, folderName);
            strcat(combined, "/");
            strcat(combined, entry.name());
            if (isGame) {

                scanBgr(combined, index);
              
                strcpy(gamePresets[index], combined);
                Serial.println(gamePresets[0]);
                Serial.println(gamePresets[1]);
                Serial.println(gamePresets[2]);
                Serial.println(gamePresets[3]);
                Serial.println("\n\n\n\n\n");
                numberOfGames++;
            }else{
                //Serial.println(index);
                strcpy(drumPresets[index], combined);
                Serial.println(drumPresets[index]);
                Serial.println("\n\n\n\n\n");
                numberOfDrums++;
            }
            index++;
        }else{
            Serial.println("done with");
            Serial.println(folderName);
            directory.rewindDirectory();
            entry.close();
            directory.close();
            break;
        }
        
    }
}
    
    
    
    


void setup() {

  pinMode(0, INPUT_PULLUP);
  pinMode(1, INPUT_PULLUP);
  pinMode(2, INPUT_PULLUP);
  pinMode(3, INPUT_PULLUP);
  pinMode(4, INPUT_PULLUP);
  pinMode(5, INPUT_PULLUP);
  pinMode(8, INPUT_PULLUP);
  pinMode(15, INPUT_PULLUP);
  pinMode(16, INPUT_PULLUP);
  pinMode(17, INPUT_PULLUP);
  pinMode(20, INPUT_PULLUP);
  pinMode(21, INPUT_PULLUP);
    

  Serial.begin(9600);
  AudioMemory(8);
  sgtl5000_1.enable();
  sgtl5000_1.volume(0.5);
  SPI.setMOSI(SDCARD_MOSI_PIN);
  SPI.setSCK(SDCARD_SCK_PIN);
  if (!(SD.begin(SDCARD_CS_PIN))) {
    while (1) {
      Serial.println("Unable to access the SD card");
      delay(500);
    }
  delay(1000);
  }
  scanFolder("_GAMES",true);
  scanFolder("_DRUMS",false);
  
  //drumPresets[0] = "_DRUMS/postal";
  //gamePresets[0] = "_GAMES/megaman";
  //gamePresets[1] = "_GAMES/smb";
  //gamePresets[2] = "_GAMES/loz";
  //gamePresets[3] = "_GAMES/sonic";

  Serial.println(gamePresets[0]);
  //currentIndex = 0;
  //currentPreset = gamePresets[currentIndex];
  currentPreset = gamePresets[getRandomNumber(numberOfGames)];
  delay(1000);   
}

void loop() {
//going to loop hihat in the delay of the tempo
  if (!gameState){
    if (loopOn == true) {
      //too loud
      playFile("Y");
      delay(tempo);
    }
  }

  //what to do for each button press
  if (buttonA.update()){
    if (buttonA.fallingEdge()){
      Serial.print("a");
      playFile("A");
      konamiCodeCheck("A");
    }
  }

  if (buttonB.update()){
    if (buttonB.fallingEdge()){
      playFile("B");
      konamiCodeCheck("B");
    }
  }
  if (buttonX.update()){
    if (buttonX.fallingEdge()){
      playFile("X");
      konamiCodePlace = 0;
    }
  }

  if (buttonY.update()){
    if (buttonY.fallingEdge()){
      playFile("Y");
      konamiCodePlace = 0;
    }
  }

  if (buttonUp.update()){
    if (buttonUp.fallingEdge()){
      //if select is being held as hotkey, increase volume
      if (digitalRead(selectPin) == LOW && vol < 1){
        changeVolume(0.1);
      }
      playFile("Up");
      konamiCodeCheck("Up");
    }
  }

  if (buttonDown.update()){
    if (buttonDown.fallingEdge()){
      playFile("Down");
      //if select is being held as hotkey, decrease volume
      if (digitalRead(selectPin) == LOW && vol > 0.1){
        changeVolume(-0.1);
      }
      konamiCodeCheck("Down");
    }
  }

  if (buttonLeft.update()){
    if (buttonLeft.fallingEdge()){
      //if select is pressed also
      if (digitalRead(selectPin) == LOW){
        playSdWav2.stop();
        //if it's greater than zero, increment up
        if (currentIndex > 0){
          currentIndex--;
        //if it is zero, cycle back around to the last index
        }else{
          //what to do if in gameState
          if (gameState){
            //currentIndex = last index of gamePresets
            currentIndex = numberOfGames - 1;
          }else{
            //currentIndex = last index of drumPresets
            currentIndex = numberOfDrums - 1;
          }
        }
        //sets the current preset with the previously set index
        if (gameState) {
          currentPreset = gamePresets[currentIndex];
          Serial.println(currentPreset);
        }else{
          currentPreset = drumPresets[currentIndex];
          Serial.println(currentPreset);
        }
      }else{
        //do this only if select isn't pressed
         konamiCodeCheck("Left");
      }
      //do this if select is pressed or not (put this with konamiCodeCheck if it should only be done without select
      playFile("Left");
    }
  }

  if (buttonRight.update()){
    if (buttonRight.fallingEdge()){
      //if select is pressed
      if (digitalRead(selectPin) == LOW){
        playSdWav2.stop();
        //if not in game state
        if (!gameState) {
          //notworking here?
          //if not at the end of the list, index goes up
          if (currentIndex < numberOfDrums - 1){
            currentIndex++;
          }else{
            //if at the end of the list, index goes back to zero
            currentIndex = 0;
          }
          //sets the drum preset
          currentPreset = drumPresets[currentIndex];
          Serial.println(currentPreset);
          //what to do if in gamestate
        }else{
          //if not at the end of the list, index goes up
          if (currentIndex < numberOfGames - 1){
            currentIndex++;
          }else{
            //if at the end of the list, index goes back to zero
            currentIndex = 0;
          }
          currentPreset = gamePresets[currentIndex];
          Serial.println(currentPreset);
        }
      }else{
        //check for konami code if select is not being pressed
        konamiCodeCheck("Right");
      }
      //plays no matter what
      playFile("Right");
    }
  }

   if (buttonStart.update()){
    if (buttonStart.fallingEdge()){
      Serial.print("Start");
      if (gameState) {
        if (playSdWav2.isPlaying()){
          //if in gamestate and something is already playing, stop playing
          playSdWav2.stop();
        }else{
          //if not playing, start playing a random bgr
          playRandomBgr();
        }
        konamiCodeCheck("Start");
      //always happens whether successfully inputting code or not
      if (digitalRead(selectPin) == LOW){
        //turns on loop if select is held
        //**go back to make this work only in drum state
        loopOn = !loopOn;
        }
      }
    }
  }

  if (buttonSelect.update()){
    if (buttonSelect.fallingEdge()){
      konamiCodePlace = 0;
    }
  }

  if (buttonL.update()){
    if (buttonL.fallingEdge()){
      //if select is held as hotkey, decrease tempo (will increase the delay)
      if (digitalRead(selectPin) == LOW && tempo > 100) {
        tempo = tempo +5;
      }
      playFile("L");
      konamiCodePlace = 0;
    }
  }

  if (buttonR.update()){
    if (buttonR.fallingEdge()){
      //if select is held as hotkey, increase tempo (will decrease the delay)
      if (digitalRead(selectPin) == LOW && tempo < 1000) {
         tempo = tempo -5;
      }
      playFile("R");
      konamiCodePlace = 0;
    }
  }
}
 
You will be seeing the battery voltage droop under load - SDcards are very spiky loads as the internal erase cycles are
heavy current users (there's a whole boost converter being run on the silicon to generate the erase voltage).

1 LiFePO4 cell is nominally 3.2V and a better match to 3.3V and usually has significantly more current handling than alkaline
cells. I keep a stock of CR123 sized LiFePO4 cells and holders for use with 3.3V projects.
 
Ah, that makes sense! I am considering getting some LiFeP04 cells for future use. Thanks for the suggestion!

I also wanted to provide an update to see if anyone had more information. I fixed the voltage issue with a 3rd AA battery, however the initial buzzing crash is continuing to occur when playing two wav files at the same time, although it is happening less frequently. It seems that on some occasions of the button press, the file path will not be read by the SD card (returning an error message I made to the Serial), even though most of the time it is playing just fine.

It seems I can replicate the buzzing crash consistently by putting a filepath that doesn't exist in playSdWav1.play(), however the issue is happening when it is dealing with filepaths that definitely do exist. I made a handler that only triggers playSdWav1.play() if the filepath passes a SD.exists() if statement, thinking this would prevent that from happening; but it seems like the file path is returning true for SD.exists() but is not being read properly in the playSdWav1.play() function immediately after, resulting in a crash. Does anybody have any idea why this would be behaving this way?

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

//documentation for these libraries are found here: https://www.pjrc.com/teensy/gui/?info=AudioPlaySdWav

AudioPlaySdWav           playSdWav2;     //xy=291,430
AudioPlaySdWav           playSdWav1;     //xy=296,301
AudioMixer4              mixer1;         //xy=563,363
AudioOutputI2S           i2s1;           //xy=780,362
AudioConnection          patchCord1(playSdWav2, 0, mixer1, 1);
AudioConnection          patchCord2(playSdWav1, 0, mixer1, 0);
AudioConnection          patchCord3(mixer1, 0, i2s1, 0);
AudioConnection          patchCord4(mixer1, 0, i2s1, 1);
AudioControlSGTL5000     sgtl5000_1;     //xy=64.5,50

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

//int buttonPins[] = {0,1,2,3,4,5,8,15,16,17,20,21};

Bounce buttonA = Bounce(0, 10);
Bounce buttonB = Bounce(1, 10);
Bounce buttonY = Bounce(2, 10);
Bounce buttonX = Bounce(3, 10);
Bounce buttonR = Bounce(4, 10);
Bounce buttonL = Bounce(5, 10);
Bounce buttonStart = Bounce(8, 10);
Bounce buttonUp = Bounce(15, 10);
Bounce buttonRight = Bounce(16, 10);
Bounce buttonDown = Bounce(17, 10);
Bounce buttonLeft = Bounce(20, 10);
Bounce buttonSelect = Bounce(21, 10);



//used for shorthand when checking if select button is being held
int selectPin = 21;

//used to determine whether the drum machine hihat is being looped or not in the drum state
bool loopOn = false;

//used to determine if the game state or drum state is active (inputting the Konami code will activate the drums tate)
bool gameState = true;

//sets the initial volume
float vol = 0.9;

//used to change volume by an increment set as num
void changeVolume(float num) {
  vol = vol + num;
  mixer1.gain(0, vol);
  mixer1.gain(1, vol);
  mixer1.gain(2, vol);
  mixer1.gain(3, vol);
  Serial.println(vol);
}

//tempo for the looped hihat in the drum state
int tempo = 200;

//array to hold file folder extensions for drum preset folders
char drumPresets[40][32];

//array to hold file folder extensions for game preset folders
char gamePresets[40][32];

//used to hold the number of drum and game presets to be used when switching presets
int numberOfDrums = 0;
int numberOfGames = 0;

//used to hold the number of background music files to be able to generate a random number that would pick a bgr file at random
//stores the number of BGR files in the same index corresponding to the index of the preset in gamePresets 
//(therefore being able to be called using the same reference index stored in currentIndex
int numberOfBgr[40];

//variable used to determine which preset is currently active in the drum or game arrays, depending on whther or not the drum or game state is active
int currentIndex = 0;

//used to point to the string stored in the game or drum state arrays that will be used as the current folder extension acting as the current preset
const char *currentPreset;

[B]//function to combine the current preset string (or preset folder) and the button pressed. \
//Concatenate file extension (variable named "combined") will look something like this: "_GAMES/MARIO/A/COIN.WAV"
void playFile(const char *input) {
    char combined[32] = {0};
    Serial.println(input);
    strcpy(combined, currentPreset);
    strcat(combined, "/");
    strcat(combined, input);
    strcat(combined, ".WAV");
    //combined now looks like "_GAMES/MARIO/A.WAV" if input is "A." 
  
  
  
  if (SD.exists(combined)) {
    Serial.println("file path: ");
    Serial.println(combined);
    //play the file
    playSdWav1.play(combined);
    return;
  }else{
    Serial.println("Cannot play file:  ");
    Serial.print(combined);
    return;
  }
}[/B]

int getRandomNumber(int maximum) {
    srand((unsigned)millis());
    return rand() % maximum;
  }

//function to play a background music file from the "BGR" folder in the current preset folder
void playRandomBgr() {
  Serial.println("\ntrying to play bgr");
  
  char combined[32] = {0};
  
  strcpy(combined, currentPreset);
  strcat(combined, "/bgr");
  File directory = SD.open(combined);
  if (!numberOfBgr[currentIndex]){return;}

  int bgrSize = numberOfBgr[currentIndex];
  
  int randIndex = getRandomNumber(bgrSize) + 1;
  Serial.println("random index = ");
  Serial.print(randIndex);
  Serial.print("\n\n");
  for (int i = 1; i <= randIndex; i++) {
    File entry = directory.openNextFile();
    if (i == randIndex) {
      strcat(combined, "/");
      strcat(combined, entry.name());
      if (!entry) {
          Serial.println("**no bgr to play**");
          return;
        }
        Serial.println("trying to play ");
        Serial.print(combined);
        Serial.print("\n\n");
        if (!SD.exists(combined)){
          Serial.println("Something went wrong,");
          Serial.println("Please check playRandomBgr");
          //will not attempt to play a file if it is not present
          return;
          }
        entry.close();
        directory.close();
        if (SD.exists(combined)) {
          playSdWav2.play(combined);
          return;
        }else{
          Serial.println("something went wrong and the BGR cannot be played:  ");
          Serial.println(combined);
          return;
        }     
      }
   }
}

//the following code allows the Konami Code to be inputted for the purpose of switching from the game state to the drum state
char konamiCode[11][9] = {"Up", "Up", "Down", "Down", "Left", "Right", "Left", "Right", "B", "A", "Start"};
int konamiCodePlace = 0;

bool konamiCodeCheck(const char *input) {
  //what to do if the last input of the konami code is pressed
  if (!strcmp(konamiCode[konamiCodePlace], input)){
      if (konamiCodePlace == 10) {
          konamiCodePlace = 0;
          playSdWav2.stop();
          Serial.println("***You did the konami code!***");
          gameState = !gameState;
          //will need to change so that you can get out of drumPresets if done a second time
          currentPreset = drumPresets[0];
          Serial.print(currentPreset);
      }else{
        //what to do if any other Konami code input is correctly pressed
          konamiCodePlace++;
      }
    return true;
  }else{
    //what to do if Konami code input is not pressed
    konamiCodePlace = 0;
    return false;
  }
}


//files should be arranged in the following manner:
//    _GAMES (or _DRUMS if a drum preset
//      MARIO
//        A
//          COIN.WAV
//        B
//          JUMP.WAV
//        X
//          FIREBALL.WAV
//        Y
//          BLOCK.WAV
//        L
//          1UP.WAV
//        R
//          POWERUP.WAV
//        UP
//          VINE.WAV
//        DOWN
//          PIPE.WAV
//        LEFT
//          BUMP.WAV
//        RIGHT
//          DEATH.WAV
//        BGR (will not be present in a drum preset)
//          OVERWRLD.WAV
//          UNDRWRLD.WAV
//          CASTLE.WAV
//          WATER.WAV


//used to scan the SD card to populate preset arrays
void scanBgr(const char *folderName, int index) {
  char combined[32] = {0};
  strcpy(combined, folderName);
  strcat(combined, "/bgr");
    File bgrDir = SD.open(combined);
    Serial.print("\ntrying to scan ");
    Serial.print(combined);
    Serial.print(" for bgr and length is ");
    int bgrInDir = 0;
        while (true) {
            File bgr = bgrDir.openNextFile();
            if (bgr) {
              bgrInDir++;
            }else{
              bgrDir.rewindDirectory();
              bgr.close();
              bgrDir.close();
              numberOfBgr[index] = bgrInDir;
              Serial.println(numberOfBgr[index]);
              break;
            }
        }
  }
    
    
void scanFolder(const char *folderName, bool isGame) {
  Serial.println("scanning folders");
    File directory = SD.open(folderName);
    int index = 0;
    while (true) {
        File entry = directory.openNextFile();
        if (entry) {
            char combined[32] = {0};
            strcpy(combined, folderName);
            strcat(combined, "/");
            strcat(combined, entry.name());
            if (isGame) {

                scanBgr(combined, index);
              
                strcpy(gamePresets[index], combined);
                Serial.println(gamePresets[0]);
                Serial.println(gamePresets[1]);
                Serial.println(gamePresets[2]);
                Serial.println(gamePresets[3]);
                Serial.println("\n\n\n\n\n");
                numberOfGames++;
            }else{
                //Serial.println(index);
                strcpy(drumPresets[index], combined);
                Serial.println(drumPresets[index]);
                Serial.println("\n\n\n\n\n");
                numberOfDrums++;
            }
            index++;
        }else{
            Serial.println("done with");
            Serial.println(folderName);
            directory.rewindDirectory();
            entry.close();
            directory.close();
            break;
        }
        
    }
}
    
    
    
    


void setup() {

  pinMode(0, INPUT_PULLUP);
  pinMode(1, INPUT_PULLUP);
  pinMode(2, INPUT_PULLUP);
  pinMode(3, INPUT_PULLUP);
  pinMode(4, INPUT_PULLUP);
  pinMode(5, INPUT_PULLUP);
  pinMode(8, INPUT_PULLUP);
  pinMode(15, INPUT_PULLUP);
  pinMode(16, INPUT_PULLUP);
  pinMode(17, INPUT_PULLUP);
  pinMode(20, INPUT_PULLUP);
  pinMode(21, INPUT_PULLUP);
    

  Serial.begin(9600);
  AudioMemory(8);
  sgtl5000_1.enable();
  sgtl5000_1.volume(0.5);
  SPI.setMOSI(SDCARD_MOSI_PIN);
  SPI.setSCK(SDCARD_SCK_PIN);
  if (!(SD.begin(SDCARD_CS_PIN))) {
    while (1) {
      Serial.println("Unable to access the SD card");
      delay(500);
    }
  delay(1000);
  }
  scanFolder("_GAMES",true);
  scanFolder("_DRUMS",false);
  
  //drumPresets[0] = "_DRUMS/postal";
  //gamePresets[0] = "_GAMES/megaman";
  //gamePresets[1] = "_GAMES/smb";
  //gamePresets[2] = "_GAMES/loz";
  //gamePresets[3] = "_GAMES/sonic";

  Serial.println(gamePresets[0]);
  //currentIndex = 0;
  //currentPreset = gamePresets[currentIndex];
  currentPreset = gamePresets[getRandomNumber(numberOfGames)];
  delay(1000);   
}

void loop() {
//going to loop hihat in the delay of the tempo
  if (!gameState){
    if (loopOn == true) {
      //too loud
      playFile("Y");
      delay(tempo);
    }
  }

  //what to do for each button press
  if (buttonA.update()){
    if (buttonA.fallingEdge()){
      Serial.print("a");
      playFile("A");
      konamiCodeCheck("A");
    }
  }

  if (buttonB.update()){
    if (buttonB.fallingEdge()){
      playFile("B");
      konamiCodeCheck("B");
    }
  }
  if (buttonX.update()){
    if (buttonX.fallingEdge()){
      playFile("X");
      konamiCodePlace = 0;
    }
  }

  if (buttonY.update()){
    if (buttonY.fallingEdge()){
      playFile("Y");
      konamiCodePlace = 0;
    }
  }

  if (buttonUp.update()){
    if (buttonUp.fallingEdge()){
      //if select is being held as hotkey, increase volume
      if (digitalRead(selectPin) == LOW && vol < 1){
        changeVolume(0.1);
      }
      playFile("Up");
      konamiCodeCheck("Up");
    }
  }

  if (buttonDown.update()){
    if (buttonDown.fallingEdge()){
      playFile("Down");
      //if select is being held as hotkey, decrease volume
      if (digitalRead(selectPin) == LOW && vol > 0.1){
        changeVolume(-0.1);
      }
      konamiCodeCheck("Down");
    }
  }

  if (buttonLeft.update()){
    if (buttonLeft.fallingEdge()){
      //if select is pressed also
      if (digitalRead(selectPin) == LOW){
        playSdWav2.stop();
        //if it's greater than zero, increment up
        if (currentIndex > 0){
          currentIndex--;
        //if it is zero, cycle back around to the last index
        }else{
          //what to do if in gameState
          if (gameState){
            //currentIndex = last index of gamePresets
            currentIndex = numberOfGames - 1;
          }else{
            //currentIndex = last index of drumPresets
            currentIndex = numberOfDrums - 1;
          }
        }
        //sets the current preset with the previously set index
        if (gameState) {
          currentPreset = gamePresets[currentIndex];
          Serial.println(currentPreset);
        }else{
          currentPreset = drumPresets[currentIndex];
          Serial.println(currentPreset);
        }
      }else{
        //do this only if select isn't pressed
         konamiCodeCheck("Left");
      }
      //do this if select is pressed or not (put this with konamiCodeCheck if it should only be done without select
      playFile("Left");
    }
  }

  if (buttonRight.update()){
    if (buttonRight.fallingEdge()){
      //if select is pressed
      if (digitalRead(selectPin) == LOW){
        playSdWav2.stop();
        //if not in game state
        if (!gameState) {
          //notworking here?
          //if not at the end of the list, index goes up
          if (currentIndex < numberOfDrums - 1){
            currentIndex++;
          }else{
            //if at the end of the list, index goes back to zero
            currentIndex = 0;
          }
          //sets the drum preset
          currentPreset = drumPresets[currentIndex];
          Serial.println(currentPreset);
          //what to do if in gamestate
        }else{
          //if not at the end of the list, index goes up
          if (currentIndex < numberOfGames - 1){
            currentIndex++;
          }else{
            //if at the end of the list, index goes back to zero
            currentIndex = 0;
          }
          currentPreset = gamePresets[currentIndex];
          Serial.println(currentPreset);
        }
      }else{
        //check for konami code if select is not being pressed
        konamiCodeCheck("Right");
      }
      //plays no matter what
      playFile("Right");
    }
  }

   if (buttonStart.update()){
    if (buttonStart.fallingEdge()){
      Serial.print("Start");
      if (gameState) {
        if (playSdWav2.isPlaying()){
          //if in gamestate and something is already playing, stop playing
          playSdWav2.stop();
        }else{
          //if not playing, start playing a random bgr
          playRandomBgr();
        }
        konamiCodeCheck("Start");
      //always happens whether successfully inputting code or not
      if (digitalRead(selectPin) == LOW){
        //turns on loop if select is held
        //**go back to make this work only in drum state
        loopOn = !loopOn;
        }
      }
    }
  }

  if (buttonSelect.update()){
    if (buttonSelect.fallingEdge()){
      konamiCodePlace = 0;
    }
  }

  if (buttonL.update()){
    if (buttonL.fallingEdge()){
      //if select is held as hotkey, decrease tempo (will increase the delay)
      if (digitalRead(selectPin) == LOW && tempo > 100) {
        tempo = tempo +5;
      }
      playFile("L");
      konamiCodePlace = 0;
    }
  }

  if (buttonR.update()){
    if (buttonR.fallingEdge()){
      //if select is held as hotkey, increase tempo (will decrease the delay)
      if (digitalRead(selectPin) == LOW && tempo < 1000) {
         tempo = tempo -5;
      }
      playFile("R");
      konamiCodePlace = 0;
    }
  }
}
 
Last edited:
I was reading the page for the audio adapter and came across this section:

Recommended SD Card
Most SD cards are optimized for sequential access, where a camera or camcorder reads or writes a single large file. All SD cards work well for playing a single WAV file at a time.
For simultaneous playing of 2, 3 or 4 stereo WAV files, many common "class 10" cards perform poorly. Even though they can support many megabytes per second in sequential access, they have high latency for non-sequential access.

PJRC has tested several brands of SD cards. We recommend SanDisk Ultra for projects where multiple WAV files will be played at the same time. SanDisk Ultra is more expensive, but its non-sequential speed is much faster.

I think I am using a pretty cheap SD card so I am going to try and get the recommended one to see if this fixes the issue. Does anyone know if non-sequential access latency would cause a crash similar to what I'm seeing?
 
Just tried the recommended SanDisk Ultra 16gb SD card and still had the same issue. I feel like I'm at a dead end. Does anyone have any other suggestions as to what could be causing this at this point?
 
Still stuck on this and wanting to revive the project to see if I can finish it. Does anyone know of a higher quality alternative to the teensy 3.2 with audio shield? My suspicion is that the 3.2+audio shield just isn't able to take the load of playing one sound file and starting/stopping/starting/stopping a second sound file each time another button is pressed. My hope is that if I use a higher quality option I could use the same code without having these crashing issues that seem to be specific to the application I am wanting to use it for. Any help on this would be really appreciated!
 
Check which version of the software you're using. In Arduino, click Help > About.

If you have older than 1.54, try installing the latest. The SD library is now powered by SdFat, and the WAV player was updated to better handle simultaneous play.

Alternately, if using an old version before 1.54, and if the SD card is connected by SPI (won't work with the build in SD socket on Teensy 3.5 & 3.6), and won't work on any Teensy 4.x... you could try enabling an old experimental optimization. In has all those limitations and can't write to the card, but it does greatly improve simultaneous playing ... maybe even better than 1.54.

Look for the file SD_t3.h and read the comments about how to enable the experimental optimization.
 
Check which version of the software you're using. In Arduino, click Help > About.

If you have older than 1.54, try installing the latest. The SD library is now powered by SdFat, and the WAV player was updated to better handle simultaneous play.

Alternately, if using an old version before 1.54, and if the SD card is connected by SPI (won't work with the build in SD socket on Teensy 3.5 & 3.6), and won't work on any Teensy 4.x... you could try enabling an old experimental optimization. In has all those limitations and can't write to the card, but it does greatly improve simultaneous playing ... maybe even better than 1.54.

Look for the file SD_t3.h and read the comments about how to enable the experimental optimization.

Thanks for the reply! I'll check the version I'm using when I get home. I actually have already tried the experimental optimization in SD_t3.h and the issue is still happening. I'll try a few things and see if I can narrow it down, otherwise I might just simplify the project to not have the background music and just the sound effects.
 
Alright, so I did a lot of troubleshooting and here is a simplified version of the code that replicates the problem. I hard coded a lot of the file paths to see if I could eliminate the other functions that return the filepath and it is still happening:
Code:
#include <Bounce.h>
#include <Audio.h>
#include <Wire.h>
#include <SPI.h>
#include <SD.h>
#include <SerialFlash.h>
#include <string.h>

//documentation for these libraries are found here: https://www.pjrc.com/teensy/gui/?info=AudioPlaySdWav

AudioPlaySdWav           playSdWav2;     //xy=291,430
AudioPlaySdWav           playSdWav1;     //xy=296,301
AudioMixer4              mixer1;         //xy=563,363
AudioOutputI2S           i2s1;           //xy=780,362
AudioConnection          patchCord1(playSdWav2, 0, mixer1, 1);
AudioConnection          patchCord2(playSdWav1, 0, mixer1, 0);
AudioConnection          patchCord3(mixer1, 0, i2s1, 0);
AudioConnection          patchCord4(mixer1, 0, i2s1, 1);
AudioControlSGTL5000     sgtl5000_1;     //xy=64.5,50

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

//int buttonPins[] = {0,1,2,3,4,5,8,15,16,17,20,21};

Bounce buttonA = Bounce(0, 10);
Bounce buttonB = Bounce(1, 10);
Bounce buttonY = Bounce(2, 10);
Bounce buttonX = Bounce(3, 10);
Bounce buttonR = Bounce(4, 10);
Bounce buttonL = Bounce(5, 10);
Bounce buttonStart = Bounce(8, 10);
Bounce buttonUp = Bounce(15, 10);
Bounce buttonRight = Bounce(16, 10);
Bounce buttonDown = Bounce(17, 10);
Bounce buttonLeft = Bounce(20, 10);
Bounce buttonSelect = Bounce(21, 10);


void setup() {


  pinMode(0, INPUT_PULLUP);
  pinMode(1, INPUT_PULLUP);
  pinMode(2, INPUT_PULLUP);
  pinMode(3, INPUT_PULLUP);
  pinMode(4, INPUT_PULLUP);
  pinMode(5, INPUT_PULLUP);
  pinMode(8, INPUT_PULLUP);
  pinMode(15, INPUT_PULLUP);
  pinMode(16, INPUT_PULLUP);
  pinMode(17, INPUT_PULLUP);
  pinMode(20, INPUT_PULLUP);
  pinMode(21, INPUT_PULLUP);

  Serial.begin(9600);
  AudioMemory(8);
  sgtl5000_1.enable();
  sgtl5000_1.volume(0.5);
  SPI.setMOSI(SDCARD_MOSI_PIN);
  SPI.setSCK(SDCARD_SCK_PIN);
  if (!(SD.begin(SDCARD_CS_PIN))) {
    while (1) {
      Serial.println("Unable to access the SD card");
      delay(500);
    }
  delay(1000);
  }
  delay(1000);   
}

void loop() {
//going to loop hihat in the delay of the tempo
  //what to do for each button press
  if (buttonA.update()){
    if (buttonA.fallingEdge()){
      playSdWav1.play("_GAMES/_megman/a.WAV");
    }
  };
  if (buttonStart.update()){
    if (buttonStart.fallingEdge()){
      playSdWav2.play("_GAMES/_megman/bgr/airman.WAV");
    }
  };
}

I am seeing that the crash happens more with larger background music files (6MB does not happen very often, 15MB happens very often)

It also is inconsistent, to where sometimes I will get the problem to consistently happen only to find that it stops happening altogether the next time I turn it on.

My hypothesis is that it is either dependent on a smaller file size (although that still doesn't keep it from happening 100% of the time) or there is a problem with the hardware or SD.h library that is causing it to behave unpredictably.

One piece of evidence for the latter is that about 20% of the time, SD.exists() will return false for the same exact filepath that does work the other 80% of the time. I'm not sure if this bug might be the same thing that is causing it to crash and mak the loud, continued buzzing/static noise until I turn it off.


Anyone who has some info on what I could try would be greatly appreciated! I have been working on this project for over a year (off and on) and just can't seem to get past this problem at the home stretch for whatever reason. Help!
 
I'm trying to get this project through the goal posts and had one last idea of what might be going on. The project I'm working on has 12 buttons that are wired up. Right now, pins 0, 1, 2, 3, 4, 5, 8, 15, 16, 17, 20, and 21 are not connected to the audio shield and are acting as open/close switches for the buttons. Does anyone know if any of these pins would be causing a fatal crash by not being connected to the audio shield?

Using a Teensy 3.2 and the audio shield found here.
 
Back
Top