MIDI library conflict?

I’ve been using the MIDI library to ‘map’ certain notes to program changes and also send MIDI clock. But recently, I wanted to play MIDI files from an SD card, which is proving to be quite a challenge. I’m not sure why my code isn’t working. Either the MIDI library functions work or the MIDIfile library functions work. But not both.

Note: the MIDIfile library is something I found that plays MIDI files from and SD card. It works, I know that. But not in my code with the MIDI library code:

#include <MIDIFile.h>
#include <MIDI.h>
#include <SdFat.h>

int MIDI_ENABLE = 19; 
/*
8/9/13: 
 
 Things this sketch does: 
 ------------------------------------
 1. Program change up/down
 a.  note 60 is up, note 62 is down
 
 2. "Mute"  parts 1-7b (sets the volume to zero)
 a.  note 64 is part 1
 b.  note 66 is part 2
 c.  note 68 is part 3
 d.  note 70 is part 4
 e.  note 72 is part 5
 f.  note 74 is part 6
 g.  note 76 is part 6a
 h.  note 78 is part 6b
 i.  note 79 is part 7a
 j.  note 80 is part 7b
 
 2.  Can send a hard coded MIDI master clock signal.  
 
 
 
 
 TO DO:
 ----------------------------
Play a MIDI file from SD card, in sync with Master clock.
 
 
 */
//SoftwareSerial SSerial(2, 3);
#define	DEBUG(x)	Serial.print(x)
#define	DEBUGX(x)	Serial.print(x, HEX)
int led = 13;



const int chipSelect = 10;
//SD2Card	SD;
SdFat SD;
MIDIFile SMF;


/*  this is the MIDIfile section that handles playing of the MIDI files on the SD card*/

void midiCallback(midi_event *pev)
// Called by the MIDIFile library when a file event needs to be processed
// thru the midi communications interface.
// This callback is set up in the setup() function.
{
  if ((pev->data[0] >= 0x80) && (pev->data[0] <= 0xe0))
  {
    Serial.write(pev->data[0] | pev->channel);
    Serial.write(&pev->data[1], pev->size-1);
  }
  else
    Serial.write(pev->data, pev->size);
 }

void sysexCallback(sysex_event *pev)
// Called by the MIDIFile library when a system Exclusive (sysex) file event needs 
// to be processed thru the midi communications interface. MOst sysex events cannot 
// really be processed, so we just ignore it here.
// This callback is set up in the setup() function
{
  DEBUG("\nS T");
  DEBUG(pev->track);
  DEBUG(": Data ");
  for (uint8_t i=0; i<pev->size; i++)
  {
    DEBUGX(pev->data[i]);
	DEBUG(' ');
  }
}

void midiSilence(void)
// Turn everything off on every channel.
// Some midi files are badly behaved and leave notes hanging, so between songs turn
// off all the notes and sound
{
  midi_event	ev;

  // All sound off
  // When All Sound Off is received all oscillators will turn off, and their volume
  // envelopes are set to zero as soon as possible.
  ev.size = 0;
  ev.data[ev.size++] = 0xb0;
  ev.data[ev.size++] = 120;
  ev.data[ev.size++] = 0;

  for (ev.channel = 0; ev.channel < 16; ev.channel++)
    midiCallback(&ev);
}

long bpm = 120;
long tempo = 1000/(bpm/60);

long prevmillis = 0;
long interval = tempo/24;    //interval is the number of milliseconds defined by tempo formula.



byte P = 0;  //program or patch number
byte M1 = 0;  //mute for part 1 off
byte M2 = 0;  //mute for part 2 off
byte M3 = 0;  //mute for part 3 off
byte M4 = 0;  //mute for part 4 off
byte M5 = 0;  //mute for part 5 off
byte M6a = 0;  //mute for part 6a off
byte M6b = 0;  //mute for part 6b off
byte M7a = 0;  //mute for part 7a off
byte M7b = 0;  //mute for part 7b off
byte S = 0;   //stop/start bit

part 2 of the code:

void HandleNoteOn (byte channel, byte note, byte velocity){
  //if note X is sent, send program change control to go up
  //todo: 

  if (velocity>0){ //needs to be greater than zero, not equal to,
    switch (note) {
    case 58: //note value of A#3 or 0x3a
      if (S == 0){
        S++;
        MIDI.sendRealTime(Start);
      }
      else
      {
        S--;
        MIDI.sendRealTime(Stop);
        //        MIDI.sendSongPosition(0);
      }
      break;
    case 60: //note value of C4  or 0x3C, handles program change 'up'
      if (P == 127){    //this notes that the program is at the highest of 127 and needs reset to 0
        P=0;
        MIDI.sendControlChange(99,05,10);
        MIDI.sendControlChange(98,107,10);
        MIDI.sendControlChange(06,0,10);
        MIDI.sendControlChange(99,05,10);
        MIDI.sendControlChange(98,108,10);
        MIDI.sendControlChange(06,0,10);
        MIDI.sendProgramChange(P,10);
      }
      else
      {
        P++;
        MIDI.sendControlChange(99,05,10);
        MIDI.sendControlChange(98,107,10);
        MIDI.sendControlChange(06,0,10);
        MIDI.sendControlChange(99,05,10);
        MIDI.sendControlChange(98,108,10);
        MIDI.sendControlChange(06,0,10);
        MIDI.sendProgramChange(P,10);

      }
      break;
    case 62: // note value of D4  or 0x3E, handles program change 'down'.
      if (P== 0){
        P=127;
        MIDI.sendControlChange(99,05,10);
        MIDI.sendControlChange(98,107,10);
        MIDI.sendControlChange(06,0,10);
        MIDI.sendControlChange(99,05,10);
        MIDI.sendControlChange(98,108,10);
        MIDI.sendControlChange(06,0,10);
        MIDI.sendProgramChange(P,10); 
      }
      else 
      {
        P--;
        MIDI.sendControlChange(99,05,10);
        MIDI.sendControlChange(98,107,10);
        MIDI.sendControlChange(06,0,10);
        MIDI.sendControlChange(99,05,10);
        MIDI.sendControlChange(98,108,10);
        MIDI.sendControlChange(06,0,10);
        MIDI.sendProgramChange(P,10);

      }
      break;
    case 64:      //part 1 mute, M variable tells us if it's muted already;  all these mutes actually set the volume to zero, uses the volume NRPNs!
      if (M1==0) {
        MIDI.sendControlChange(99,5,10);
        MIDI.sendControlChange(98,1,10);
        MIDI.sendControlChange(06,0,10);  //sets level to zero, for part 1
        //need to toggle it
        M1=1;
      }
      else {
        MIDI.sendControlChange(99,5,10);
        MIDI.sendControlChange(98,1,10);
        MIDI.sendControlChange(06,120,10);
        M1=0;
      }

      break;
    case 66:
      if (M2==0) {
        MIDI.sendControlChange(99,5,10);
        MIDI.sendControlChange(98,9,10);
        MIDI.sendControlChange(06,0,10);  //sets level to zero, for part 2
        //need to toggle it
        M2=1;
      }
      else {
        MIDI.sendControlChange(99,5,10);
        MIDI.sendControlChange(98,9,10);
        MIDI.sendControlChange(06,120,10);
        M2=0;
      }
      break;
    case 68:   //mute for part 3
      if (M3==0) {
        MIDI.sendControlChange(99,5,10);
        MIDI.sendControlChange(98,17,10);
        MIDI.sendControlChange(06,0,10);  //sets level to zero, for part 3
        //need to toggle it
        M3=1;
      }
      else {
        MIDI.sendControlChange(99,5,10);
        MIDI.sendControlChange(98,17,10);
        MIDI.sendControlChange(06,120,10);
        M3=0;
      }
      break;
    case 70:
      if (M4==0) {
        MIDI.sendControlChange(99,5,10);
        MIDI.sendControlChange(98,25,10);
        MIDI.sendControlChange(06,0,10);  //sets level to zero, for part 1
        //need to toggle it
        M4=1;
      }
      else {
        MIDI.sendControlChange(99,5,10);
        MIDI.sendControlChange(98,25,10);
        MIDI.sendControlChange(06,120,10);
        M4=0;
      }
      break;
    case 72:
      if (M5==0) {
        MIDI.sendControlChange(99,5,10);
        MIDI.sendControlChange(98,33,10);
        MIDI.sendControlChange(06,0,10);  //sets level to zero, for part 1
        //need to toggle it
        M5=1;
      }
      else {
        MIDI.sendControlChange(99,5,10);
        MIDI.sendControlChange(98,33,10);
        MIDI.sendControlChange(06,120,10);
        M5=0;
      }
      break;
    case 74:
      if (M6a==0) {
        MIDI.sendControlChange(99,5,10);
        MIDI.sendControlChange(98,41,10);
        MIDI.sendControlChange(06,0,10);  //sets level to zero, for part 1
        //need to toggle it
        M6a=1;
      }
      else {
        MIDI.sendControlChange(99,5,10);
        MIDI.sendControlChange(98,41,10);
        MIDI.sendControlChange(06,120,10);
        M6a=0;
      }
      break;
    case 76:
      if (M6b==0) {
        MIDI.sendControlChange(99,5,10);
        MIDI.sendControlChange(98,49,10);
        MIDI.sendControlChange(06,0,10);  //sets level to zero, for part 1
        //need to toggle it
        M6b=1;
      }
      else {
        MIDI.sendControlChange(99,5,10);
        MIDI.sendControlChange(98,49,10);
        MIDI.sendControlChange(06,120,10);
        M6b=0;
      }
      break;
    case 78:
      if (M7a==0) {
        MIDI.sendControlChange(99,5,10);
        MIDI.sendControlChange(98,57,10);
        MIDI.sendControlChange(06,0,10);  //sets level to zero, for part 1
        //need to toggle it
        M7a=1;
      }
      else {
        MIDI.sendControlChange(99,5,10);
        MIDI.sendControlChange(98,57,10);
        MIDI.sendControlChange(06,120,10);
        M7a=0;
      }
      break;
    case 80:
      if (M7b==0) {
        MIDI.sendControlChange(99,5,10);
        MIDI.sendControlChange(98,65,10);
        MIDI.sendControlChange(06,0,10);  //sets level to zero, for part 1
        //need to toggle it
        M7b=1;
      }
      else {
        MIDI.sendControlChange(99,5,10);
        MIDI.sendControlChange(98,65,10);
        MIDI.sendControlChange(06,120,10);
        M7b=0;
      }
      break;


    } //end of switch (note)  



  }

  else{
    switch(note){
    case 58:
      MIDI.sendNoteOff(58,0,10);
      break;
    case 60:
      MIDI.sendNoteOff(60,0,10);
      break;
    case 62:
      MIDI.sendNoteOff(62,0, 10);
      break;   
    case 64:
      MIDI.sendNoteOff(64,0, 10);
      break;      
    case 66:
      MIDI.sendNoteOff(66,0, 10);
      break;      
    case 68:
      MIDI.sendNoteOff(68,0, 10);
      break;      
    case 70:
      MIDI.sendNoteOff(70,0, 10);
      break;      
    case 72:
      MIDI.sendNoteOff(72,0, 10);
      break;      
    case 74:
      MIDI.sendNoteOff(74,0, 10);
      break;   
    case 76:
      MIDI.sendNoteOff(76,0, 10);
      break;      
    case 78:
      MIDI.sendNoteOff(78,0, 10);
      break;     
    case 80:
      MIDI.sendNoteOff(80,0, 10);
      break;            

    }
  }

}

part 3 of my code

[code]

void setup() {


  MIDI.begin(MIDI_CHANNEL_OMNI);
  //Serial.begin(31250);
   pinMode(MIDI_ENABLE, OUTPUT);      // sets the digital pin as output 
  digitalWrite(MIDI_ENABLE, HIGH);
  //  MIDI.turnThruOff();

 MIDI.setHandleNoteOn(HandleNoteOn);
  MIDI.sendProgramChange(P,10);
  //   MIDI.setHandleClock ( HandleClock );


  //MIDIfile & SD card setups
  // Initialise SD
  if (!SD.begin(chipSelect, SPI_HALF_SPEED))SD.initErrorHalt();
   Serial.println("begin success");

  SD.begin(chipSelect, SPI_HALF_SPEED);

  // Initialise MIDIFile
  SMF.begin(&SD);
  SMF.setMidiHandler(midiCallback);
  SMF.setSysexHandler(sysexCallback);


}

void Sync(){

  unsigned long currentMillis = millis();
  if(currentMillis - prevmillis > interval) {
    // save the last time.
    prevmillis = currentMillis;
    MIDI.sendRealTime(Clock);    
  }

}


void loop () {
  int err = -1;


  SMF.setFilename("SCALE.MID");
SMF.load(); //lost sync at this point.
  err=SMF.load();  //try to print the load result
  SMF.setTempo(bpm);

  if (err != -1)
  {
    DEBUG("\nSMF load Error ");
    DEBUG(err);
    //digitalWrite(SMF_ERROR_LED, HIGH);
//    delay(WAIT_DELAY);
  }
  else
  {
    while (!SMF.isEOF())
    {
      if (SMF.getNextEvent());
    }
    // done with this one
    SMF.close();

  }
 MIDI.read(); 
   Sync();
}

[/code]

If the MIDI library uses the serial port, then you cannot have the MIDIFile library opening up the same serial port. I am not sure what the effect would be, but it is likely that the last 'open' is the one that works and the other is lost.

What you should probably be doing is calling the generic MIDI 'send a message' library call using the parameters from the MIDIFile callback rather than calling the serial routines (ie, all your MIDI messages are sent through the MIDI library).

coincidentally, I've been thinking the same thing. I'm looking at the MIDI library right now to see if there is a generic "send" method...

void MIDI_Class::send ( kMIDIType type, byte data1, byte data2, byte channel )

The next issue would be that I'd have to find a way to determine the type of message in the data, which can be handled by MIDI.gettype.

this feels like a dumb question: I’m using the Ruggeduino MIDI shield, which allows you to change the MIDI IN/OUT to a variety of Digital in/outs. would that help me here? I think the MIDI library only supports Serial … ???

In the MIDI library header file there is this

#define USE_SERIAL_PORT         Serial      // Change the number (to Serial1 for example) if you want
                                            // to use a different serial port for MIDI I/O.

which means that you can change the serial port used to something else if you want to.

The MIDI library has a generic function to send messages

	void send(kMIDIType type, byte param1, byte param2, byte channel);

which you can invoke in the MIDIfile callback function, which receives as its parameter a pointer to this structure (defined in the MIDIfile header file)

typedef struct
{
	uint8_t	track;		// the track this was on
	uint8_t	channel;	// the midi channel
	uint8_t	size;		// the number of data bytes
	uint8_t	data[4];	// the data. Only 'size' bytes are valid
} midi_event;
  • The track you can ignore, as it is the track in the SMF being processed.
  • The channel should be mapped to the channel in the send() function above. Need to take care that whether the channel is zero or one based in MIDI. MIDIfile is zero based.
  • The rest of the data are KMIType, param1 and param2.

If you look at MIDI header file KMIType is

enum kMIDIType {
	NoteOff	              = 0x80,	///< Note Off
	NoteOn                = 0x90,	///< Note On
	AfterTouchPoly        = 0xA0,	///< Polyphonic AfterTouch
	ControlChange         = 0xB0,	///< Control Change / Channel Mode
	ProgramChange         = 0xC0,	///< Program Change
	AfterTouchChannel     = 0xD0,	///< Channel (monophonic) AfterTouch
	PitchBend             = 0xE0,	///< Pitch Bend
	SystemExclusive       = 0xF0,	///< System Exclusive
	TimeCodeQuarterFrame  = 0xF1,	///< System Common - MIDI Time Code Quarter Frame
	SongPosition          = 0xF2,	///< System Common - Song Position Pointer
	SongSelect            = 0xF3,	///< System Common - Song Select
	TuneRequest           = 0xF6,	///< System Common - Tune Request
	Clock                 = 0xF8,	///< System Real Time - Timing Clock
	Start                 = 0xFA,	///< System Real Time - Start
	Continue              = 0xFB,	///< System Real Time - Continue
	Stop                  = 0xFC,	///< System Real Time - Stop
	ActiveSensing         = 0xFE,	///< System Real Time - Active Sensing
	SystemReset           = 0xFF,	///< System Real Time - System Reset
	InvalidType           = 0x00    ///< For notifying errors
};

which are basically the MIDI codes for those functions. These should correspond to the first byte in data.

There's also the kMIDIType.gettype() function in the MIDI library that I might be able to use to get the type and then pass into the MIDI.send().

I'm now getting this odd pattern (via MIDI OX)

0033917D 9 -- E0 65 67 1 --- Pitch Bend 0033917D 9 -- E0 69 6E 1 --- Pitch Bend 0033917E 9 -- E0 20 73 1 --- Pitch Bend 0033917F 9 -- E0 75 63 1 --- Pitch Bend 00339180 9 -- E0 63 65 1 --- Pitch Bend 00339181 9 -- E0 73 73 1 --- Pitch Bend 00339181 9 -- E0 0D 0A 1 --- Pitch Bend 003391B9 9 -- E0 62 65 1 --- Pitch Bend 003391BA 9 -- E0 67 69 1 --- Pitch Bend 003391BB 9 -- E0 6E 20 1 --- Pitch Bend 003391BC 9 -- E0 73 75 1 --- Pitch Bend 003391BD 9 -- E0 63 63 1 --- Pitch Bend 003391BE 9 -- E0 65 73 1 --- Pitch Bend 003391BF 9 -- E0 73 0D 1 --- Pitch Bend 003391F7 9 -- E0 0A 62 1 --- Pitch Bend 003391F8 9 -- E0 65 67 1 --- Pitch Bend

if I take the example MIDIfile sketch and simply add the MIDI.h reference, that sketch ceases to work. This somewhat confirms a conflict. The MIDI library is limited to using Serial as a comm method and changing the header file doesn't appear to work, but I'm not sure I'm doing it right either.

There is a MIDI library 4.0 that’s in beta and it supports Software Serial. But I’m at a loss as to how that might help me…

Take all references to serial out of the MIDIfile example sketch that you are using. This was covered in my longer post before.

The MIDIfile library DOES NOT use serial, only the example sketch and it is just an example. You should be handling the callback differently in your code. Again as per my long post above.

here’s an example of how I think the callback should look

void midiCallback(midi_event *pev)
// Called by the MIDIFile library when a file event needs to be processed
// thru the midi communications interface.
// This callback is set up in the setup() function.
//  0x80 is a status btye 0x8n (n=channel).  0xe0
{
  if ((pev->data[0] >= 0x80) && (pev->data[0] <= 0xe0))
  {
   // Serial.write(pev->data[0] | pev->channel);
   // Serial.write(&pev->data[1], pev->size-1);

    MIDI.send(MIDI.getType(), (pev->data[1]), (pev->data[2]), (pev->channel));

  }
  else
   // Serial.write(pev->data, pev->size);
  { MIDI.send(MIDI.getType(), (pev->data[1]), (pev->data[2]), (pev->channel));}
 
}

is that what you meant? I will test this out when I have more free time today…

Close. I am not sure that the get type is what you want but try it.

I tried this and I’m getting a weird error during compile:

void midiCallback(midi_event *pev)
// Called by the MIDIFile library when a file event needs to be processed
// thru the midi communications interface.
// This callback is set up in the setup() function.
{
  	if ((pev->data[0] >= 0x80) && (pev->data[0] <= 0xe0))
	{
		//SSerial.write(pev->data[0] | pev->channel);
		//SSerial.write(&pev->data[1], pev->size-1);

  MIDI.send((pev->data[0]), (pev->data[1]), (pev->data[2]), (pev->channel));
  

	}
	//else
		//SSerial.write(pev->data, pev->size);

  
}

MIDIFile_Play.ino: In function ‘void midiCallback(midi_event*)’:
MIDIFile_Play:133: error: invalid conversion from ‘uint8_t’ to ‘midi::MidiType’
MIDIFile_Play:133: error: initializing argument 1 of ‘void midi::MidiInterface::send(midi::MidiType, midi::DataByte, midi::DataByte, midi::Channel) [with SerialPort = HardwareSerial]’

Just cast the data[0] parameter to midi::MidiType.

void midiCallback(midi_event *pev)
// Called by the MIDIFile library when a file event needs to be processed
// thru the midi communications interface.
// This callback is set up in the setup() function.
{
  #if USE_MIDI
  	if ((pev->data[0] >= 0x80) && (pev->data[0] <= 0xe0))
	{
		//Serial.write(pev->data[0] | pev->channel);
		//Serial.write(&pev->data[1], pev->size-1);

  MIDI.send((midi::MidiType)pev->data[0], (pev->data[1]), (pev->data[2]), (pev->channel));
  

	}
	else
				Serial.write(pev->data, pev->size);
#endif

  DEBUG("\nM T");
  DEBUG(pev->track);
  DEBUG(":  Ch ");
  DEBUG(pev->channel+1);
  DEBUG(" Data ");
  for (uint8_t i=0; i<pev->size; i++)
  {
	DEBUGX((midi::MidiType)pev->data[i]);
    DEBUG(' ');
  }
}

I tried this and I get nothing. When I debug, i see it looks fine to me:

M T0: Ch 1 Data 90 48 64
M T0: Ch 1 Data 80 48 40
M T0: Ch 1 Data 90 49 64
M T0: Ch 1 Data 80 49 40
M T0: Ch 1 Data 90 4A 64
M T0: Ch 1 Data 80 4A 40
M T0: Ch 1 Data 90 4B 64
M T0: Ch 1 Data 80 4B 40
M T0: Ch 1 Data 90 4C 64
M T0: Ch 1 Data 80 4C 40
M T0: Ch 1 Data 90 4D 64
M T0: Ch 1 Data 80 4D 40
M T0: Ch 1 Data 90 4E 64
M T0: Ch 1 Data 80 4E 40
M T0: Ch 1 Data 90 4F 64
M T0: Ch 1 Data 80 4F 40

this is just a scale on channel 1, with NoteOn’s & NoteOffs. But I think the problem is that the MIDI.send() function is expecting a midi type from here:

/*! Type definition for practical use (because "unsigned char" is a bit long to write.. )*/
typedef uint8_t byte;
typedef uint16_t word;

/*! Enumeration of MIDI types */
enum kMIDIType {
	NoteOff	              = 0x80,	///< Note Off
	NoteOn                = 0x90,	///< Note On
	AfterTouchPoly        = 0xA0,	///< Polyphonic AfterTouch
	ControlChange         = 0xB0,	///< Control Change / Channel Mode
	ProgramChange         = 0xC0,	///< Program Change
	AfterTouchChannel     = 0xD0,	///< Channel (monophonic) AfterTouch
	PitchBend             = 0xE0,	///< Pitch Bend
	SystemExclusive       = 0xF0,	///< System Exclusive
	TimeCodeQuarterFrame  = 0xF1,	///< System Common - MIDI Time Code Quarter Frame
	SongPosition          = 0xF2,	///< System Common - Song Position Pointer
	SongSelect            = 0xF3,	///< System Common - Song Select
	TuneRequest           = 0xF6,	///< System Common - Tune Request
	Clock                 = 0xF8,	///< System Real Time - Timing Clock
	Start                 = 0xFA,	///< System Real Time - Start
	Continue              = 0xFB,	///< System Real Time - Continue
	Stop                  = 0xFC,	///< System Real Time - Stop
	ActiveSensing         = 0xFE,	///< System Real Time - Active Sensing
	SystemReset           = 0xFF,	///< System Real Time - System Reset
	InvalidType           = 0x00    ///< For notifying errors
};

now, this is just getting weird.

in one sketch, I'm getting:

sketch_sep09.ino: In function 'void midiCallback(midi_event*)': sketch_sep09:68: error: 'midi' has not been declared

for this line:

  MIDI.send((midi::MidiType)pev->data[0], (pev->data[1]), (pev->data[2]), (pev->channel));

and in another, I get:

MIDIFile_Play.ino: In function 'void setup()': MIDIFile_Play:188: error: 'NoteOn' was not declared in this scope MIDIFile_Play:189: error: 'NoteOff' was not declared in this scope

for this line:

MIDI.send(NoteOn, 64,  255, 1);
MIDI.send(NoteOff, 64, 255 , 1);

both sketches have references to the MIDI & MIDIfile libraries. this doesn't make sense to me.

Just cast the data[0] parameter to midi::MidiType.

The cast should be to kMIDIType. It is actually not part of the class definition if you look in the header file, but an external enumerated type.

that worked. Also, I had some library issues I think I sorted out.

The code compiles, but from what I can tell, it's looping in the setup() ???

void setup() {


 MIDI.begin(MIDI_CHANNEL_OMNI);
//  Serial.begin(57600);
   pinMode(MIDI_ENABLE, OUTPUT);      // sets the digital pin as output 
  digitalWrite(MIDI_ENABLE, HIGH);
  //  MIDI.turnThruOff();

  //   MIDI.setHandleClock ( HandleClock );


  //MIDIfile & SD card setups
  // Initialise SD
  if (!SD.begin(chipSelect, SPI_HALF_SPEED))SD.initErrorHalt();
 Serial.println("\n begin success");   //looping here?

 // SD.begin(chipSelect, SPI_HALF_SPEED);

  // Initialise MIDIFile
 SMF.begin(&SD);
 SMF.setMidiHandler(midiCallback);
//  SMF.setSysexHandler(sysexCallback);
MIDI.setHandleNoteOn(HandleNoteOn);
// MIDI.sendProgramChange(P,10);   

}