Midi Chord Player - Notes Sound Intermittently

Building another midi chord player. This time I'm using an SD card to provide a data file that can be read and written to into two arrays. Works great. Display, works great. All buttons work perfectly. Code seems to work perfectly. Except, when a midi chord is played, I might have to press the button 4 times to get it to sound. Sometimes twice. Sometimes 6 times. The display updates to the correct chord when played, so I know the "if" statement is being initiated by the correct button push. Thought it was a memory problem, so I downgraded to only 6 chord buttons and only 5 chord choices. No avail. I had functions for the midi chord on/off, but broke those out into each button push. So the code was efficient, but now its not. But that didn't make a difference.

So my question is does the SD card reader cause problems with any of the digital buttons? I'm using a Leonardo, which has its own dedicated SD pins. Here's the code followed by the data file:

#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include <Bounce2.h>
#include <MIDIUSB.h>
#include <SD.h>
LiquidCrystal_I2C lcd(0x27, 20, 4); 
const int SD_CS_PIN = 10;            // Chip select pin for SD card module
const char filename[] = "data.txt";  // File name for storing and reading the matrix
const int ButtonPins[] = {0, 1, 4, 5, 6, 7, 8, 9, 11, 12, 13, A0};    // Currently 8 chord buttons, 2 tranpose, 4 programming
int transpose = 0; 
int transposebank = 0;
int b14 = 0; 
int b15 = 0; 
int b16 = 0; 
int bp17 = 0;
int assigned;
int Menu_loop = 0;
int notetrack = 0;
int notetrack1 = 0;
int notetrack2 = 0;
int notetrack3 = 0;
int button_assignments[6][4];                
const char* chord_names[6];               
const int midi_note_nums[12] = {48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59};                                                      
const char* root_chord[12] = {"C ", "C#", "D ", "D#", "E ", "F ", "F#", "G ", "G#", "A ", "A#", "B "}; 
const char* chord_type[5] = {"Maj ", "Min ", "7th ", "M7th", "m7th"};                        
const int chord_intervals[5][4] = {         // Each row is a series of midi intervals                            
    {0, 4, 7, 0},  // Major                 // intervals that are added to the selected root midi note to create chords
    {0, 3, 7, 0},  // Minor
    {0, 4, 7, 10}, // 7th
    {0, 4, 7, 11}, // maj7th
    {0, 3, 7, 10}, // min7th
};  
void update_display() {
    lcd.clear();
    lcd.setCursor(0, 0);
    lcd.print(" Midi Chord Player ");
    lcd.setCursor(0, 2);
    lcd.print("Chord:");
    lcd.setCursor(7, 2);
    lcd.print("          ");
    lcd.setCursor(0, 3);
    lcd.print("Octave: ");
    lcd.setCursor(8,3);
    lcd.print("    ");
    lcd.setCursor(8,3);
    lcd.print(transposebank);
}    
const int nButtons = sizeof ButtonPins / sizeof ButtonPins[0];
Bounce buttons[nButtons];
void setup() {
    for (int i = 0; i < nButtons; i++){
        pinMode(ButtonPins[i], INPUT_PULLUP);
        buttons[i].attach(ButtonPins[i]);
        buttons[i].interval(40);
    }
    lcd.init();
    lcd.backlight();
    lcd.clear();
    update_display();
    Serial.begin(31250);
//    
// Initialize the SD card
//
  if (!SD.begin(SD_CS_PIN)) {
    lcd.clear();
    lcd.setCursor(0,0);
    lcd.print("SD card");
    lcd.setCursor (0,1);
    lcd.print("Initialization");
    lcd.setCursor(0,2);
    lcd.print("failed!");
    while (1);
  }
    // Read the button_assignments and chord_names matrices from the SD card function
    readMatrix();
}
void loop() 
{
  for (int i = 0; i < nButtons; i++){ 
    buttons[i].update();       
      if (buttons[i].fell()) {
        if (i==6) {                                             // Check for Transpose Down Button Press - down to -1
               if (transposebank== -1) {                        // If -1 octaves Down button pushed, stays on -1 octaves down (-12 to midi note)
                  transposebank= -1;
               } else {
                   transposebank = transposebank-1;  
                   transpose = transpose-12;                    // If Octave is 1, 2, or 3, drops notes -12
                   lcd.setCursor (8,3);
                   lcd.print(transposebank);
                } 
        } else if (i==7) {                                     // Check for Transpose Up Button Press
              if (transposebank==3)                            // If 3 octaves up (+3), deducts -36 to midi note and rolls back over to 0 octaves up
                {                  
                  transposebank = 3;             
                } else {
                   transposebank= transposebank+1;
                   transpose = transpose+12;                  // If UP pushed adds +12 to midi note for button push
                   lcd.setCursor (8,3);
                   lcd.print(transposebank);
                }
        } else if (i==0)                                        // check for chord button press buttons 0-7
            {                    
              notetrack = ((button_assignments[i][0])+transpose); 
              midiEventPacket_t noteOn = {0x09, 0x90 | 0, notetrack, 60}; 
              MidiUSB.sendMIDI(noteOn);
              delay(10);
              notetrack1 = ((button_assignments[i][1])+transpose); 
              midiEventPacket_t noteOn1 = {0x09, 0x90 | 0, notetrack1, 60}; 
              MidiUSB.sendMIDI(noteOn1);
              delay(10);
              notetrack2 = ((button_assignments[i][2])+transpose); 
              midiEventPacket_t noteOn2 = {0x09, 0x90 | 0, notetrack2, 60}; 
              MidiUSB.sendMIDI(noteOn2);
              delay(10);
              notetrack3 = ((button_assignments[i][3])+transpose); 
              midiEventPacket_t noteOn3 = {0x09, 0x90 | 0, notetrack3, 60}; 
              MidiUSB.sendMIDI(noteOn3);
              delay(10);
              lcd.setCursor(7, 2);
              lcd.print(String(chord_names[i]));
        } else if (i==1)  
            {                    
              notetrack = ((button_assignments[i][0])+transpose); 
              midiEventPacket_t noteOn = {0x09, 0x90 | 0, notetrack, 60}; 
              MidiUSB.sendMIDI(noteOn);
              delay(10);
              notetrack1 = ((button_assignments[i][1])+transpose); 
              midiEventPacket_t noteOn1 = {0x09, 0x90 | 0, notetrack1, 60}; 
              MidiUSB.sendMIDI(noteOn1);
              delay(10);
              notetrack2 = ((button_assignments[i][2])+transpose); 
              midiEventPacket_t noteOn2 = {0x09, 0x90 | 0, notetrack2, 60}; 
              MidiUSB.sendMIDI(noteOn2);
              delay(10);
              notetrack3 = ((button_assignments[i][3])+transpose); 
              midiEventPacket_t noteOn3 = {0x09, 0x90 | 0, notetrack3, 60}; 
              MidiUSB.sendMIDI(noteOn3);
              delay(10);
              lcd.setCursor(7, 2);
              lcd.print(String(chord_names[i]));
        } else if (i==2)  
            {                    
              notetrack = ((button_assignments[i][0])+transpose); 
              midiEventPacket_t noteOn = {0x09, 0x90 | 0, notetrack, 60}; 
              MidiUSB.sendMIDI(noteOn);
              delay(10);
              notetrack1 = ((button_assignments[i][1])+transpose); 
              midiEventPacket_t noteOn1 = {0x09, 0x90 | 0, notetrack1, 60}; 
              MidiUSB.sendMIDI(noteOn1);
              delay(10);
              notetrack2 = ((button_assignments[i][2])+transpose); 
              midiEventPacket_t noteOn2 = {0x09, 0x90 | 0, notetrack2, 60}; 
              MidiUSB.sendMIDI(noteOn2);
              delay(10);
              notetrack3 = ((button_assignments[i][3])+transpose); 
              midiEventPacket_t noteOn3 = {0x09, 0x90 | 0, notetrack3, 60}; 
              MidiUSB.sendMIDI(noteOn3);
              delay(10);
              lcd.setCursor(7, 2);
              lcd.print(String(chord_names[i]));
        } else if (i==3)  {                    
              notetrack = ((button_assignments[i][0])+transpose); 
              midiEventPacket_t noteOn = {0x09, 0x90 | 0, notetrack, 60}; 
              MidiUSB.sendMIDI(noteOn);
              delay(10);
              notetrack1 = ((button_assignments[i][1])+transpose); 
              midiEventPacket_t noteOn1 = {0x09, 0x90 | 0, notetrack1, 60}; 
              MidiUSB.sendMIDI(noteOn1);
              delay(10);
              notetrack2 = ((button_assignments[i][2])+transpose); 
              midiEventPacket_t noteOn2 = {0x09, 0x90 | 0, notetrack2, 60}; 
              MidiUSB.sendMIDI(noteOn2);
              delay(10);
              notetrack3 = ((button_assignments[i][3])+transpose); 
              midiEventPacket_t noteOn3 = {0x09, 0x90 | 0, notetrack3, 60}; 
              MidiUSB.sendMIDI(noteOn3);
              delay(10);
              lcd.setCursor(7, 2);
              lcd.print(String(chord_names[i]));
        } else if (i==4)  {                    
              notetrack = ((button_assignments[i][0])+transpose); 
              midiEventPacket_t noteOn = {0x09, 0x90 | 0, notetrack, 60}; 
              MidiUSB.sendMIDI(noteOn);
              delay(10);
              notetrack1 = ((button_assignments[i][1])+transpose); 
              midiEventPacket_t noteOn1 = {0x09, 0x90 | 0, notetrack1, 60}; 
              MidiUSB.sendMIDI(noteOn1);
              delay(10);
              notetrack2 = ((button_assignments[i][2])+transpose); 
              midiEventPacket_t noteOn2 = {0x09, 0x90 | 0, notetrack2, 60}; 
              MidiUSB.sendMIDI(noteOn2);
              delay(10);
              notetrack3 = ((button_assignments[i][3])+transpose); 
              midiEventPacket_t noteOn3 = {0x09, 0x90 | 0, notetrack3, 60}; 
              MidiUSB.sendMIDI(noteOn3);
              delay(10);
              lcd.setCursor(7, 2);
              lcd.print(String(chord_names[i]));
        } else if (i==5)  {                    
              notetrack = ((button_assignments[i][0])+transpose); 
              midiEventPacket_t noteOn = {0x09, 0x90 | 0, notetrack, 60}; 
              MidiUSB.sendMIDI(noteOn);
              delay(10);
              notetrack1 = ((button_assignments[i][1])+transpose); 
              midiEventPacket_t noteOn1 = {0x09, 0x90 | 0, notetrack1, 60}; 
              MidiUSB.sendMIDI(noteOn1);
              delay(10);
              notetrack2 = ((button_assignments[i][2])+transpose); 
              midiEventPacket_t noteOn2 = {0x09, 0x90 | 0, notetrack2, 60}; 
              MidiUSB.sendMIDI(noteOn2);
              delay(10);
              notetrack3 = ((button_assignments[i][3])+transpose); 
              midiEventPacket_t noteOn3 = {0x09, 0x90 | 0, notetrack3, 60}; 
              MidiUSB.sendMIDI(noteOn3);
              delay(10);
              lcd.setCursor(7, 2);
              lcd.print(String(chord_names[i]));
        } else if (i==8){                        
             Sub_Menu();           // Submenu program functionality
             update_display();
            }
        } else if (buttons[i].rose()) {                                                                         // Check if cord button rose  
                  midiEventPacket_t noteOff = {0x08, 0x80 | 0, notetrack, 0};      // if note button rose, turn off note
                  MidiUSB.sendMIDI(noteOff);
                  delay(10);
                  midiEventPacket_t noteOff1 = {0x08, 0x80 | 0, notetrack1, 0};      // if note1 button rose, turn off note
                  MidiUSB.sendMIDI(noteOff1);
                  delay(10);
                  midiEventPacket_t noteOff2 = {0x08, 0x80 | 0, notetrack2, 0};      // if note2 button rose, turn off note
                  MidiUSB.sendMIDI(noteOff2);
                  delay(10);
                  midiEventPacket_t noteOff3 = {0x08, 0x80 | 0, notetrack3, 0};      // if note3 button rose, turn off note
                  MidiUSB.sendMIDI(noteOff3);
                  delay(10);
                  lcd.setCursor(7, 2);
                  lcd.print("         "); 
             }                    
   } 
} 
///////     Clear memory before reading   /////
void freeChordNamesMemory() {
  for (int i = 0; i < 6; i++) {
    if (chord_names[i] != NULL) {
      delete[] chord_names[i];  // Free the memory
      chord_names[i] = NULL;    // Set the pointer to NULL
    }
  }
}
///////     Read Matrix From SD Card     /////
void readMatrix() {
  File file = SD.open("data.txt", FILE_READ);
  if (file) {
    // Read button_assignments array
    for (int i = 0; i < 6; i++) {
      for (int j = 0; j < 4; j++) {
        button_assignments[i][j] = file.parseInt();
      }
    }
    // Consume the newline character at the end of button_assignments
    file.readStringUntil('\n');
    // Read chord_names array
    for (int i = 0; i < 6; i++) {
      String chordStr = file.readStringUntil('\n');      // Read the string until newline
      chord_names[i] = new char[chordStr.length() + 1];  // Allocate memory
      strcpy(chord_names[i], chordStr.c_str());          // Copy the string
    }
    file.close(); // Close the file
  } else {
                  // Display an error message if the file cannot be opened
    lcd.clear();
    lcd.print("Error opening data.txt");
  }
}
///////     Save button_assignments to SD Card      ///////
void saveMatrix() {
  // Delete the existing file
  SD.remove(filename);
  // Create a new file
  File file = SD.open(filename, FILE_WRITE);
  if (file) {
    // Write button_assignments array
    for (int i = 0; i < 6; i++) {
      for (int j = 0; j < 4; j++) {
        file.print(button_assignments[i][j]);
        file.print(' ');
      }
      file.println();
    }
    // Write chord_names array
    for (int i = 0; i < 6; i++) {
      file.println(String(chord_names[i]));
    }
    file.close();  // Close the file
  } else {
    lcd.clear();
    lcd.print("Error writing data.txt");
  }
}
/////// Program Buttons Function///////
void Sub_Menu() {               //loop until save/exit //
    Menu_loop = 0;
    lcd.clear();
    lcd.setCursor (0,0);
    lcd.print ("Program: Select All");
    lcd.setCursor(0,1);
    lcd.print("Button:" + String(b14 + 1));
    lcd.setCursor(0,2);
    lcd.print("Assigned:" + String(chord_names[b14]));
    lcd.setCursor(0,3);
    lcd.print("Root:");
    lcd.setCursor (8,3);
    lcd.print("Type:");
    while (Menu_loop < 1) {   
        for (int m = 8; m < 12; m++) { 
            buttons[m].update();
            if (buttons[m].fell()) {
                if (m==8) {                 // Pick Button to Program
                    b14 = b14+1;
                    assigned = b14;
                    if (b14 > 5) {
                        b14 = 0;
                    }
                    lcd.setCursor(0,1);
                    lcd.print("                   ");
                    lcd.setCursor(0,1);
                    lcd.print("Button:" + String(b14 +1));
                    lcd.setCursor(0,2);
                    lcd.print("                   ");
                    lcd.setCursor(0,2);
                    lcd.print ("Assigned:" + String(chord_names[b14]));
                    Menu_loop = 0;
                    b15=0;
                    b16=0;
                } else if (m==9) {         //Pick Root Chord
                    b15 = b15 + 1;
                    if (b15 > 11) {
                        b15 = 0;
                    }
                    lcd.setCursor(0,1);
                    lcd.print("                   ");
                    lcd.setCursor(0,1);
                    lcd.print("Button:" + String(b14));
                    lcd.setCursor(0,2);
                    lcd.print("                   ");
                    lcd.setCursor(0,2);
                    lcd.print ("Assigned:" + String(chord_names[assigned]));
                    lcd.setCursor(0,3);
                    lcd.print ("Root:" + String(root_chord[b15]));          
                    Menu_loop = 0;
                } else if (m==10)           // Pick Type of Chord
                    {
                    b16 = b16 + 1;  
                    if (b16 > 5) {
                        b16 = 0;
                    }
                    lcd.setCursor(0,1);
                    lcd.print("                   ");
                    lcd.setCursor(0,1);
                    lcd.print("Button:" + String(b14));
                    lcd.setCursor(0,2);
                    lcd.print("                   ");
                    lcd.setCursor(0,2);
                    lcd.print ("Assigned:" + String(chord_names[assigned]));
                    lcd.setCursor (8,3);
                    lcd.print ("Type:" + String(chord_type[b16]));
                    String combinedString = String(root_chord[b15]) + String(chord_type[b16]);
                    if (chord_names[b14] != NULL) {
                      delete[] chord_names[b14];                               // Free the existing string if it exists
                    }
                    chord_names[b14] = new char[combinedString.length() + 1];  // Allocate new memory
                    strcpy(chord_names[b14], combinedString.c_str());          // Copy the new string
                    for (int j = 0; j<4; j++ ) {
                            button_assignments[b14][j] = chord_intervals[b16][j] + midi_note_nums[b15]; // Assign Chord Midi #'s to Array
                        } 
                    Menu_loop = 0;
                } else if (m==11) { 
                    lcd.clear();
                    lcd.setCursor(4,1);
                    lcd.print ("Save & Exit ?");
                    lcd.setCursor(3,2);
                    lcd.print("(press again)");
                    if (bp17 == 0) {
                        bp17 = bp17 + 1;
                        Menu_loop = 0;
                    } else if (bp17 == 1) {
                        saveMatrix();                 // Save New Button Assignments to SD Card
                        freeChordNamesMemory();       // Erase Memory
                        readMatrix();                 // Reload Memory
                        b14 = 0;
                        b15= 0;
                        b16 = 0;
                        bp17 = 0;
                        Menu_loop = 1;
                    }   
                }         
            }
        }
    }
}

data file:
60 64 67 72
65 69 72 76
70 74 77 81
75 79 82 86
80 84 87 91
85 89 92 96
C Maj
D Min
E 7th
F maj7th
G min7th
A sus4

I don't see any calls to MidiUSB.flush(). Without them, the MIDI data will only be transmitted once the USB buffer is completely full, explaining the need to send all messages multiple times before they are actually transmitted.

I see you're using Strings and manual calls to new/delete. With only 2.5 KiB of RAM, you need to be careful with memory fragmentation. Regardless of fragmentation, bare new/delete should always be avoided and should instead be encapsulated using RAII.

Good catch on the midi.flush. Rookie mistake. :wink:

Thanks for the advice on the memory. Problem is, I’m not sure how to read/write to the SD device without doing what I did. I wanted to be able to edit the chords and assigned buttons and those edits not be lost when powered off.

I’ll do some more research….I’m still new to coding on the arduino.

Thanks again!

1 Like

Use the EEPROM for none volatile storage.

Yes, lots of problems. The SD card reader is using some of the same pins as your button pins.

Thanks for everyone's help. Made changes to some of the code as suggested (not writing to memory but to a string) and everything is working well. Made no pin changes and kept it at 6 buttons for chords rather than my original 8. But that leaves room in the memory.

#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include <Bounce2.h>
#include <MIDIUSB.h>
#include <SD.h>

LiquidCrystal_I2C lcd(0x27, 20, 4);
const int SD_CS_PIN = 10;            
const char filename[] = "data.txt";  
const int ButtonPins[] = {0, 1, 4, 5, 6, 7, 8, 9, 11, 12, 13, A0};
int transpose = 0; 
int transposebank = 0;
int b14 = 0; 
int b15 = 0; 
int b16 = 0; 
int bp17 = 0;
int Menu_loop = 0;
int notetrack = 0;
int notetrack1 = 0;
int notetrack2 = 0;
int notetrack3 = 0;
char assigned;
int button_assignments[6][4];                
char chord_names[6][20]; // Static allocation for chord names
const int midi_note_nums[12] = {48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59};                                                      
const char* root_chord[12] = {"C ", "C#", "D ", "D#", "E ", "F ", "F#", "G ", "G#", "A ", "A#", "B "}; 
const char* chord_type[5] = {"Maj ", "Min ", "7th ", "Ma7", "mi7"};                        
const int chord_intervals[5][4] = {         
    {0, 4, 7, 12},  // Major                 
    {0, 3, 7, 12},  // Minor
    {0, 4, 7, 10}, // 7th
    {0, 4, 7, 11}, // maj7th
    {0, 3, 7, 10}, // min7th
}; 
void update_display() {
    lcd.clear();
    lcd.setCursor(0, 0);
    lcd.print(" Midi Chord Player ");
    lcd.setCursor(0, 2);
    lcd.print("Chord:");
    lcd.setCursor(7, 2);
    lcd.print("          ");
    lcd.setCursor(0, 3);
    lcd.print("Octave: ");
    lcd.setCursor(7,3);
    lcd.print("    ");
    lcd.setCursor(7,3);
    lcd.print(transposebank);
}    
const int nButtons = sizeof ButtonPins / sizeof ButtonPins[0];
Bounce buttons[nButtons];
void setup() {
    for (int i = 0; i < nButtons; i++){
        pinMode(ButtonPins[i], INPUT_PULLUP);
        buttons[i].attach(ButtonPins[i]);
        buttons[i].interval(40);
    }
    lcd.init();
    lcd.backlight();
    lcd.clear();
    update_display();
    Serial.begin(31250);
//    
// Initialize the SD card
//
  if (!SD.begin(SD_CS_PIN)) {
    lcd.clear();
    lcd.setCursor(0,0);
    lcd.print("SD card");
    lcd.setCursor (0,1);
    lcd.print("Initialization");
    lcd.setCursor(0,2);
    lcd.print("failed!");
    while (1);
  }
    // Read the button_assignments and chord_names matrices from the SD card function
    readMatrix();
}
void loop() 
{
  for (int i = 0; i < nButtons; i++){ 
    buttons[i].update();       
      if (buttons[i].fell()) {
        if (i==6) {                                             // Check for Transpose Down Button Press - down to -1
               if (transposebank== -1) {                        // If -1 octaves Down button pushed, stays on -1 octaves down (-12 to midi note)
                  transposebank= -1;
               } else {
                   transposebank = transposebank-1;  
                   transpose = transpose-12;                    // If Octave is 1, 2, or 3, drops notes -12
                   lcd.setCursor (7,3);
                   lcd.print("    ");
                   lcd.setCursor (7,3);
                   lcd.print(transposebank);
                } 
        } else if (i==7) {                                     // Check for Transpose Up Button Press
              if (transposebank==3)                            // If 3 octaves up (+3), deducts -36 to midi note and rolls back over to 0 octaves up
                {                  
                  transposebank = 3;             
                } else {
                   transposebank= transposebank+1;
                   transpose = transpose+12;                  // If UP pushed adds +12 to midi note for button push
                   lcd.setCursor (7,3);
                   lcd.print("    ");
                   lcd.setCursor (7,3);
                   lcd.print(transposebank);
                }
        } else if (i==0 || i==1 || i==2 || i==3 || i==4 || i==5)                                        // check for chord button press buttons 0-7
            { 
              for (int j=0; j<4; j++) {                   
              notetrack = ((button_assignments[i][j])+transpose); 
              midiEventPacket_t noteOn = {0x09, 0x90 | 0, notetrack, 60}; 
              MidiUSB.sendMIDI(noteOn);
              delay(10);
              }
              MidiUSB.flush();
              lcd.setCursor(7, 2);
              lcd.print(String(chord_names[i]));
              //lcd.setCursor(12,2);
              //lcd.print ("     ");
        } else if (i==8){                        
             Sub_Menu();           // Submenu program functionality
             update_display();
            }
        } else if (buttons[i].rose()) {   
                  for (int j=0; j<4; j++) {  
                    notetrack = ((button_assignments[i][j])+transpose);                                                             // Check if cord button rose  
                    midiEventPacket_t noteOff = {0x08, 0x80 | 0, notetrack, 0};      // if note button rose, turn off note
                    MidiUSB.sendMIDI(noteOff);
                    delay(10);
                  }
                  MidiUSB.flush();
                  lcd.setCursor(7, 2);
                  lcd.print("         "); 
             }                    
   } 
} 
///////     Read Matrix From SD Card     /////
void readMatrix() {
  File file = SD.open("data.txt", FILE_READ);
  if (file) {
    // Read button_assignments array
    for (int i = 0; i < 6; i++) {
      for (int j = 0; j < 4; j++) {
        button_assignments[i][j] = file.parseInt();
      }
    }
    file.readStringUntil('\n'); // Consume the newline character

    // Read chord_names array
    for (int i = 0; i < 6; i++) {
      String chordStr = file.readStringUntil('\n');      // Read the string until newline
      strncpy(chord_names[i], chordStr.c_str(), sizeof(chord_names[i]) - 1); // Copy the string safely
      chord_names[i][sizeof(chord_names[i]) - 1] = '\0'; // Ensure null termination
    }
    file.close(); // Close the file
  } else {
    // Display an error message if the file cannot be opened
    lcd.clear();
    lcd.print("Error opening data.txt");
  }
}
void saveMatrix() {
  // Delete the existing file
  SD.remove(filename);
  // Create a new file
  File file = SD.open(filename, FILE_WRITE);
  if (file) {
    // Write button_assignments array
    for (int i = 0; i < 6; i++) {
      for (int j = 0; j < 4; j++) {
        file.print(button_assignments[i][j]);
        file.print(' ');
      }
      file.println();
    }
    // Write chord_names array
    for (int i = 0; i < 6; i++) {
      String chordName = String(chord_names[i]);
      chordName.trim(); // Remove leading/trailing whitespace and newlines
      file.println(chordName);
    }
    file.close();  // Close the file after writing all data
  } else {
    lcd.clear();
    lcd.print("Error writing data.txt");
  }
}
/////// Program Buttons Function///////
void Sub_Menu() {               
    Menu_loop = 0;
    lcd.clear();
    lcd.setCursor (0,0);
    lcd.print ("1 btn/sav each time");
    lcd.setCursor(0,1);
    lcd.print("Button:" + String(b14 + 1));
    lcd.setCursor(0,2);
    lcd.print("Assigned:" + String(chord_names[b14]));
    lcd.setCursor(0,3);
    lcd.print("Root:");
    lcd.setCursor (8,3);
    lcd.print("Type:");
    while (Menu_loop < 1) {   
        for (int m = 8; m < 12; m++) { 
            buttons[m].update();
            if (buttons[m].fell()) {
                if (m==8) {                 // Pick Button to Program
                    b14 = b14+1;
                    assigned = chord_names[b14];
                    if (b14 > 5) {
                        b14 = 0;
                    }
                    lcd.setCursor(0,1);
                    lcd.print("                   ");
                    lcd.setCursor(0,1);
                    lcd.print("Button:" + String(b14 + 1));
                    lcd.setCursor(0,2);
                    lcd.print("                   ");
                    lcd.setCursor(0,2);
                    lcd.print ("Assigned:" + String(chord_names[b14]));
                    Menu_loop = 0;
                } else if (m==9) {         //Pick Root Chord
                    b15 = b15 + 1;
                    if (b15 > 11) {
                        b15 = 0;
                    }
                    lcd.setCursor(0,1);
                    lcd.print("                   ");
                    lcd.setCursor(0,1);
                    lcd.print("Button:" + String(b14+1));
                    lcd.setCursor(0,2);
                    lcd.print("                   ");
                    lcd.setCursor(0,2);
                    lcd.print ("Assigned:" + String(chord_names[assigned]));
                    lcd.setCursor(0,3);
                    lcd.print ("Root:" + String(root_chord[b15]));          
                    Menu_loop = 0;
                } else if (m==10) { // Pick Type of Chord
                   b16 = b16 + 1;  
                   if (b16 > 4) {
                    b16 = 0;
                    }
                   lcd.setCursor(0,1);
                   lcd.print("                   ");
                   lcd.setCursor(0,1);
                   lcd.print("Button:" + String(b14+1));
                   lcd.setCursor(0,2);
                   lcd.print("                   ");
                   lcd.setCursor(0,2);
                   lcd.print("Assigned:" + String(chord_names[b14])); // Use b14 directly
                   lcd.setCursor(8,3);
                   lcd.print("Type:" + String(chord_type[b16]));
                   String combinedString = String(root_chord[b15]) + String(chord_type[b16]); 
                      // Use snprintf for safe string formatting
                   snprintf(chord_names[b14], sizeof(chord_names[b14]), "%s", combinedString.c_str()); 
                   //String (root_chord[b14]) = String(root_chord[b15]);
                   //String (chord_type[b14]) = String (chord_type[b16]);
                   Menu_loop = 0;
                } else if (m==11) { 
                    lcd.clear();
                    lcd.setCursor(4,1);
                    lcd.print ("Save & Exit ?");
                    lcd.setCursor(3,2);
                    lcd.print("(press again)");
                    if (bp17 == 0) {
                        bp17 = bp17 + 1;
                        Menu_loop = 0;
                    } else if (bp17 == 1) { 
                      for (int j = 0; j<4; j++ ) {
                      button_assignments[b14][j] = chord_intervals[b16][j] + midi_note_nums[b15]; // Assign Chord Midi #'s to Array
                     } 
                        saveMatrix();                 // Save New Button Assignments to SD Card    
                        readMatrix();                 // Reload Memory
                        b14 = 0;
                        b15= 0;
                        b16 = 0;
                        bp17 = 0;
                        Menu_loop = 1;
                  }   
                }         
            }
        }
    }
}

Have you considered FRAM memory, it works at processor speed, no delays when reading or writing, available in SPI and I2C. It is rated at over a billion writes. I use 32K x 8 devices and they are not that much then EEPROM.

Can you point me to some coding examples?

I was looking at the FRAM and it’s very intriguing. I need to understand how to code it before I pull the trigger and buy it. And it’s not expensive at all, so definitely worth looking in to!

They are in the FRAM library, a lot of examples, even speed tests!

Thanks!

I looked it over - WAY above my level of coding. :laughing:

I might by it and try messing with it anyway.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.