So I am trying to get my arduino mega (2560) to act as the brain for a project involving midi files from an SD card being played by bells connected to motors on relays (one output signal per motor).
Eventually I want to be able to load up a bunch of midi files onto an SD card and then have each song played sequentially by my motors (which will then spin and generate the sounds for each "note").
I have a piece of test code that seems to be reading the output data from the midi file and sending it just fine to the serial monitor (as seen here),
//include appropriate libraries
#include <MIDI.h>
#include <SPI.h>
#include <SD.h>
//create "filename" placeholder variable for files when opened
File myfile;
//SD pin designations FOR ARDUINO UNO are as follows: MOSI-11, MISO-12, SCK-13, CS-10. SD pin designations FOR ARDUINO MEGA are as follows:MOSI-51, MISO-50, SCK-52, CS-53
const int chipSelect = 53;
// put your setup code here, to run once:
void setup() {
//CS pin must be left as an output or else SD library functions will not work.
pinMode(chipSelect, OUTPUT);
//start serial monitor (for testing purposes only)
Serial.begin(9600);
// wait for Serial Monitor to connect. Needed for native USB port boards only:
while (!Serial);
Serial.print("Initializing SD card...");
if (!SD.begin(chipSelect)) {
Serial.println("initialization failed. Things to check:");
Serial.println("1. is a card inserted?");
Serial.println("2. is your wiring correct?");
Serial.println("3. did you change the chipSelect pin to match your shield or module?");
Serial.println("Note: press reset or reopen this serial monitor after fixing your issue!");
while (true);
}
Serial.println("initialization done.");
}
// put your main code here, to run repeatedly:
void loop() {
myfile = SD.open("1.mid"); //open file "1.mid" is just the name of the first file on the SD card, eventually I want it to go through a list of file names.
if (myfile){
Serial.println("1.mid");
while (myfile.available()) {
Serial.println(myfile.read()); //read file in serial monitor format
}
myfile.close(); //close file
}
}
But when I tweak a couple things and try to put it all together in my actual code, as seen here, I have problems reading the SD card and it doesn't even make it past the initialization stage.
//include appropriate libraries
#include <MIDI.h>
#include <SPI.h>
#include <SD.h>
//create "filename" placeholder variable for files when opened
File songname;
//create all motor outputs (relay signals (HIGH/LOW))
int NoteA = 2;
int NoteB = 3;
int NoteC = 4;
int NoteD = 5;
int NoteE = 6;
int NoteF = 7;
int NoteG = 8;
//SD pin designations are as follows: MOSI-51, MISO-50, SCK-52, CS-53
const int chipSelect = 53;
//set indexing variable for files
int i = 0;
//MIDI pitch values for each "note"
int Aa [ ] = {0, 1, 12, 13, 24, 25, 36, 37, 48, 49, 60, 61, 72, 73, 84, 85, 96, 97, 108, 109, 120, 121}; //22 items in list
int Bb [ ] = {2, 2, 14, 14, 26, 26, 38, 38, 50, 50, 62, 62, 74, 74, 86, 86, 98, 98, 110, 110, 122, 122};
int Cc [ ] = {3, 4, 15, 16, 27, 28, 39, 40, 51, 52, 63, 64, 75, 76, 87, 88, 99, 100, 111, 112, 123, 124};
int Dd [ ] = {5, 6, 17, 18, 29, 30, 41, 42, 53, 54, 65, 66, 77, 78, 89, 90, 101, 102, 113, 114, 125, 126};
int Ee [ ] = {7, 7, 19, 19, 31, 31, 43, 43, 55, 55, 67, 67, 79, 79, 91, 91, 103, 103, 115, 115, 127, 127};
int Ff [ ] = {8, 9, 20, 21, 32, 33, 44, 45, 56, 57, 68, 69, 80, 81, 92, 93, 104, 105, 116, 117, 128, 129};
int Gg [ ] = {10, 11, 22, 23, 34, 35, 46, 47, 58, 59, 70, 71, 82, 83, 94, 95, 106, 107, 118, 119, 130, 131};
//create a new array with all song names in a list form (for indexing) ---eventually I will make this a list of all the filenames on SD card
const char* songList [ ] = {"1.mid", "2.mid"};
int songTotal = 1; //number of items in songlist/on SD card
// Create and bind the MIDI interface to the default hardware Serial port
MIDI_CREATE_DEFAULT_INSTANCE();
//////////////////////////////////////////~code~//////////////////////////////////////////////////////////////
// put your setup code here, to run once:
void setup() {
//start serial monitor (for testing purposes only)
Serial.begin(38400);
//set output signals for each "note"(motor)
pinMode(NoteA, OUTPUT);
pinMode(NoteB, OUTPUT);
pinMode(NoteC, OUTPUT);
pinMode(NoteD, OUTPUT);
pinMode(NoteE, OUTPUT);
pinMode(NoteF, OUTPUT);
pinMode(NoteG, OUTPUT);
//CS pin must be left as an output or else SD library functions will not work.
pinMode(chipSelect, OUTPUT);
// wait for Serial Monitor to connect. Needed for native USB port boards only:
while (!Serial);
Serial.print("Initializing SD card...");
if (!SD.begin(chipSelect)) {
Serial.println("initialization failed. Things to check:");
Serial.println("1. is a card inserted?");
Serial.println("2. is your wiring correct?");
Serial.println("3. did you change the chipSelect pin to match your shield or module?");
Serial.println("Note: press reset or reopen this serial monitor after fixing your issue!");
while (true);
}
Serial.println("initialization done.");
//set MIDI interfacing to reference the callback functions below
MIDI.begin();
MIDI.setHandleNoteOn(doSomeStuffWithNoteOn);
MIDI.setHandleNoteOff(doSomeStuffWithNoteOff);
}
/////////////////////////////////////////////////~main run~////////////////////////////////////////////////
// put your main code here, to run repeatedly:
void loop() {
for (int i = 0; i<=songTotal; i++){
songname = SD.open(songList[i]); //open file - should be smth like this: "songnamesarray[i]"
if (songname){
Serial.println(songList[i]);
while (songname.available()) {
MIDI.read(); //read file in MIDI format to reference callback functions below
}
songname.close(); //close file
}
}
i=0;
}
////////////////////////////////////~callback functions~/////////////////////////////////////////////////
//assign actions for notes using a callback
void doSomeStuffWithNoteOn(byte channel, byte pitch, byte velocity){
//if pitch is within the arrays above, turn on the corresponding motor
for (int count = 0; count <= 21; count++){
if(pitch == Aa[count]){
digitalWrite(NoteA, HIGH);
}
if(pitch == Bb[count]){
digitalWrite(NoteB, HIGH);
}
if(pitch == Cc[count]){
digitalWrite(NoteC, HIGH);
}
if(pitch == Dd[count]){
digitalWrite(NoteD, HIGH);
}
if(pitch == Ee[count]){
digitalWrite(NoteE, HIGH);
}
if(pitch == Ff[count]){
digitalWrite(NoteF, HIGH);
}
if(pitch == Gg[count]){
digitalWrite(NoteG, HIGH);
}
else {
}
}
}
void doSomeStuffWithNoteOff(byte channel, byte pitch, byte velocity){
//if pitch is within the arrays above, turn off the corresponding motor
for (int count = 0; count <= 21; count++){
if(pitch == Aa[count]){
digitalWrite(NoteA, LOW);
}
if(pitch == Bb[count]){
digitalWrite(NoteB, LOW);
}
if(pitch == Cc[count]){
digitalWrite(NoteC, LOW);
}
if(pitch == Dd[count]){
digitalWrite(NoteD, LOW);
}
if(pitch == Ee[count]){
digitalWrite(NoteE, LOW);
}
if(pitch == Ff[count]){
digitalWrite(NoteF, LOW);
}
if(pitch == Gg[count]){
digitalWrite(NoteG, LOW);
}
else {
}
}
}
This code doesn't even seem to make it past the initialization stage. My serial monitor says "Initializing SD card..." and then random characters, and freezes. My main problem right now, and the one I really need help with, is that I cannot get the SD card to be recognized once I drop it into my main code.
Needless to say, no files are being read, and thus no motors are spinning.
PS: just had this thought as I was writing this, but could i take the data directly from my test code and parse it out into usable data without having to use the midi library? From what I have seen from my serial monitor using test code, the data from the midi file seems to just be integers, which could still be compatible with my "official" code, as long as I separate the pitch data from the channel and velocity data....I am just unsure how to do that either haha.
Advice and insight very appreciated! Thanks!