MIDI data to digital output

I want to make an instrument that plays MIDI files from an SD card. I am using an Arduino Mega 2560. The output will be digital i/o signals sent to digital pins for each "note" ( ex: a different led for each midi note (one per pin)). Disregard velocity for now. I need the noteON and noteOFF bytes to turn on and off each digitalPin for each note, respectively, in time with the music. I am using the MD_MIDIFile library from marco_c. I am also running into the error message "Error compiling for board Arduino Mega or Mega 2560" which I am also unsure how to resolve.

How do I debug the MIDI data to read and then send an i/o output to a specific digitalPin for each note, instead of a direct MIDI send? (line 13 in the code below:).

// Test playing a succession of MIDI files from the SD card.
// Example program to demonstrate the use of the MIDFile library
// Just for fun light up a LED in time to the music.
//
// Hardware required:
//  SD card interface - change SD_SELECT for SPI comms
//  3 LEDs (optional) - to display current status and beat. 
//  Change pin definitions for specific hardware setup - defined below.

#include <SdFat.h>
#include <MD_MIDIFile.h>

#define USE_MIDI  1   /// THIS IS LINE 13!!!  set to 1 to enable MIDI output, otherwise debug output 

#if USE_MIDI // set up for direct MIDI serial output

#define DEBUG(x)
#define DEBUGX(x)
#define DEBUGS(s)
#define SERIAL_RATE 31250

#else // don't use MIDI to allow printing debug statements

#define DEBUG(x)  Serial.print(x)
#define DEBUGX(x) Serial.print(x, HEX)
#define DEBUGS(s) Serial.print(F(s))
#define SERIAL_RATE 57600

#endif // USE_MIDI


// SD chip select pin for SPI comms.
// Arduino Ethernet shield, pin 4.
// Default SD chip select is the SPI SS pin (10). (53 for mega)
// Other hardware will be different as documented for that hardware.
const uint8_t SD_SELECT = 53;

// LED definitions for status and user indicators
const uint8_t READY_LED = 7;      // when finished
const uint8_t SMF_ERROR_LED = 6;  // SMF error
const uint8_t SD_ERROR_LED = 5;   // SD error
const uint8_t BEAT_LED = 4;       // toggles to the 'beat'

const uint16_t WAIT_DELAY = 2000; // ms

#define ARRAY_SIZE(a) (sizeof(a)/sizeof(a[0]))

// The files in the tune list should be located on the SD card 
// or an error will occur opening the file and the next in the 
// list will be opened (skips errors).
const char *tuneList[] = 
{
  "1.MID",  // simplest and shortest file
  "2.MID",

};

// These don't play as they need more than 16 tracks but will run if MIDIFile.h is changed
//#define MIDI_FILE  "SYMPH9.MID"     // 29 tracks
//#define MIDI_FILE  "CHATCHOO.MID"   // 17 tracks
//#define MIDI_FILE  "STRIPPER.MID"   // 25 tracks

SdFat  SD;
MD_MIDIFile SMF;

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);
  }
  else
    Serial.write(pev->data, pev->size);
#endif
  DEBUG("\n");
  DEBUG(millis());
  DEBUG("\tM T");
  DEBUG(pev->track);
  DEBUG(":  Ch ");
  DEBUG(pev->channel+1);
  DEBUG(" Data ");
  for (uint8_t i=0; i<pev->size; i++)
  {
  DEBUGX(pev->data[i]);
    DEBUG(' ');
  }
}

void sysexCallback(sysex_event *pev)
// Called by the MIDIFile library when a system Exclusive (sysex) file event needs 
// to be processed through 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);
}

void setup(void)
{
  // Set up LED pins
  pinMode(READY_LED, OUTPUT);
  pinMode(SD_ERROR_LED, OUTPUT);
  pinMode(SMF_ERROR_LED, OUTPUT);
  pinMode(BEAT_LED, OUTPUT);

  // reset LEDs
  digitalWrite(READY_LED, LOW);
  digitalWrite(SD_ERROR_LED, LOW);
  digitalWrite(SMF_ERROR_LED, LOW);
  digitalWrite(BEAT_LED, LOW);
  
  Serial.begin(SERIAL_RATE);

  DEBUG("\n[MidiFile Play List]");

  // Initialize SD
  if (!SD.begin(SD_SELECT, SPI_FULL_SPEED))
  {
    DEBUG("\nSD init fail!");
    digitalWrite(SD_ERROR_LED, HIGH);
    while (true) ;
  }

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

  digitalWrite(READY_LED, HIGH);
}

void tickMetronome(void)
// flash a LED to the beat
{
  static uint32_t lastBeatTime = 0;
  static boolean  inBeat = false;
  uint16_t  beatTime;

  beatTime = 60000/SMF.getTempo();    // msec/beat = ((60sec/min)*(1000 ms/sec))/(beats/min)
  if (!inBeat)
  {
    if ((millis() - lastBeatTime) >= beatTime)
    {
      lastBeatTime = millis();
      digitalWrite(BEAT_LED, HIGH);
      inBeat = true;
    }
  }
  else
  {
    if ((millis() - lastBeatTime) >= 100) // keep the flash on for 100ms only
    {
      digitalWrite(BEAT_LED, LOW);
      inBeat = false;
    }
  }
}

void loop(void)
{
  static enum { S_IDLE, S_PLAYING, S_END, S_WAIT_BETWEEN } state = S_IDLE;
  static uint16_t currTune = ARRAY_SIZE(tuneList);
  static uint32_t timeStart;

  switch (state)
  {
  case S_IDLE:    // now idle, set up the next tune
    {
      int err;

      DEBUGS("\nS_IDLE");

      digitalWrite(READY_LED, LOW);
      digitalWrite(SMF_ERROR_LED, LOW);

      currTune++;
      if (currTune >= ARRAY_SIZE(tuneList))
        currTune = 0;

      // use the next file name and play it
      DEBUG("\nFile: ");
      DEBUG(tuneList[currTune]);
      err = SMF.load(tuneList[currTune]);
      if (err != MD_MIDIFile::E_OK)
      {
        DEBUG(" - SMF load Error ");
        DEBUG(err);
        digitalWrite(SMF_ERROR_LED, HIGH);
        timeStart = millis();
        state = S_WAIT_BETWEEN;
        DEBUGS("\nWAIT_BETWEEN");
      }
      else
      {
        DEBUGS("\nS_PLAYING");
        state = S_PLAYING;
      }
    }
    break;

  case S_PLAYING: // play the file
    DEBUGS("\nS_PLAYING");
    if (!SMF.isEOF())
    {
      if (SMF.getNextEvent())
        tickMetronome();
    }
    else
      state = S_END;
    break;

  case S_END:   // done with this one
    DEBUGS("\nS_END");
    SMF.close();
    midiSilence();
    timeStart = millis();
    state = S_WAIT_BETWEEN;
    DEBUGS("\nWAIT_BETWEEN");
    break;

  case S_WAIT_BETWEEN:    // signal finished with a dignified pause
    digitalWrite(READY_LED, HIGH);
    if (millis() - timeStart >= WAIT_DELAY)
      state = S_IDLE;
    break;

  default:
    state = S_IDLE;
    break;
  }
}

EDIT: First and foremost I need to resolve this compilation error first. Any help appreciated! Thanks

EDIT EDIT: Got the compilation error resolved, now how about the main problem?

Not sure it helps but I just took the code you posted and it compiled for the Arduino Mega. I am using the IDE version 1.8.13.

Thanks Mike,

I am using the IDE version 1.8.13

I am using IDE v 1.8.16...any way to switch it back to 1.8.13? Could that have been the source of the problem? Also, the SdFat.h library is not turning orange in my code like it is supposed to for libraries (even though the library is downloaded and visible in the file/examples tab)...any ideas?

Here is my complete error code directly copied from the IDE if this helps at all

Arduino: 1.8.16 (Mac OS X), Board: "Arduino Mega or Mega 2560, ATmega2560 (Mega 2560)"


/Applications/Arduino.app/Contents/Java/arduino-builder -dump-prefs -logger=machine -hardware /Applications/Arduino.app/Contents/Java/hardware -hardware /Users/eijifrey/Library/Arduino15/packages -tools /Applications/Arduino.app/Contents/Java/tools-builder -tools /Applications/Arduino.app/Contents/Java/hardware/tools/avr -tools /Users/eijifrey/Library/Arduino15/packages -built-in-libraries /Applications/Arduino.app/Contents/Java/libraries -libraries /Users/eijifrey/Documents/Arduino/libraries -fqbn=arduino:avr:mega:cpu=atmega2560 -vid-pid=2341_0042 -ide-version=10816 -build-path /var/folders/f5/wmykvlzd0ml0hh17g7wscpvm0000gn/T/arduino_build_532785 -warnings=none -build-cache /var/folders/f5/wmykvlzd0ml0hh17g7wscpvm0000gn/T/arduino_cache_467695 -prefs=build.warn_data_percentage=75 -prefs=runtime.tools.avrdude.path=/Users/eijifrey/Library/Arduino15/packages/arduino/tools/avrdude/6.3.0-arduino17 -prefs=runtime.tools.avrdude-6.3.0-arduino17.path=/Users/eijifrey/Library/Arduino15/packages/arduino/tools/avrdude/6.3.0-arduino17 -prefs=runtime.tools.avr-gcc.path=/Users/eijifrey/Library/Arduino15/packages/arduino/tools/avr-gcc/7.3.0-atmel3.6.1-arduino7 -prefs=runtime.tools.avr-gcc-7.3.0-atmel3.6.1-arduino7.path=/Users/eijifrey/Library/Arduino15/packages/arduino/tools/avr-gcc/7.3.0-atmel3.6.1-arduino7 -prefs=runtime.tools.arduinoOTA.path=/Users/eijifrey/Library/Arduino15/packages/arduino/tools/arduinoOTA/1.3.0 -prefs=runtime.tools.arduinoOTA-1.3.0.path=/Users/eijifrey/Library/Arduino15/packages/arduino/tools/arduinoOTA/1.3.0 -verbose /Users/eijifrey/Documents/Career/EMPLOYERS/PINK SPARROW/2022/Art Mafia/MD_MIDIFile_play_test/MD_MIDIFile_play_test.ino
/Applications/Arduino.app/Contents/Java/arduino-builder -compile -logger=machine -hardware /Applications/Arduino.app/Contents/Java/hardware -hardware /Users/eijifrey/Library/Arduino15/packages -tools /Applications/Arduino.app/Contents/Java/tools-builder -tools /Applications/Arduino.app/Contents/Java/hardware/tools/avr -tools /Users/eijifrey/Library/Arduino15/packages -built-in-libraries /Applications/Arduino.app/Contents/Java/libraries -libraries /Users/eijifrey/Documents/Arduino/libraries -fqbn=arduino:avr:mega:cpu=atmega2560 -vid-pid=2341_0042 -ide-version=10816 -build-path /var/folders/f5/wmykvlzd0ml0hh17g7wscpvm0000gn/T/arduino_build_532785 -warnings=none -build-cache /var/folders/f5/wmykvlzd0ml0hh17g7wscpvm0000gn/T/arduino_cache_467695 -prefs=build.warn_data_percentage=75 -prefs=runtime.tools.avrdude.path=/Users/eijifrey/Library/Arduino15/packages/arduino/tools/avrdude/6.3.0-arduino17 -prefs=runtime.tools.avrdude-6.3.0-arduino17.path=/Users/eijifrey/Library/Arduino15/packages/arduino/tools/avrdude/6.3.0-arduino17 -prefs=runtime.tools.avr-gcc.path=/Users/eijifrey/Library/Arduino15/packages/arduino/tools/avr-gcc/7.3.0-atmel3.6.1-arduino7 -prefs=runtime.tools.avr-gcc-7.3.0-atmel3.6.1-arduino7.path=/Users/eijifrey/Library/Arduino15/packages/arduino/tools/avr-gcc/7.3.0-atmel3.6.1-arduino7 -prefs=runtime.tools.arduinoOTA.path=/Users/eijifrey/Library/Arduino15/packages/arduino/tools/arduinoOTA/1.3.0 -prefs=runtime.tools.arduinoOTA-1.3.0.path=/Users/eijifrey/Library/Arduino15/packages/arduino/tools/arduinoOTA/1.3.0 -verbose /Users/eijifrey/Documents/Career/EMPLOYERS/PINK SPARROW/2022/Art Mafia/MD_MIDIFile_play_test/MD_MIDIFile_play_test.ino
Using board 'mega' from platform in folder: /Users/eijifrey/Library/Arduino15/packages/arduino/hardware/avr/1.8.4
Using core 'arduino' from platform in folder: /Users/eijifrey/Library/Arduino15/packages/arduino/hardware/avr/1.8.4
Detecting libraries used...
/Users/eijifrey/Library/Arduino15/packages/arduino/tools/avr-gcc/7.3.0-atmel3.6.1-arduino7/bin/avr-g++ -c -g -Os -w -std=gnu++11 -fpermissive -fno-exceptions -ffunction-sections -fdata-sections -fno-threadsafe-statics -Wno-error=narrowing -flto -w -x c++ -E -CC -mmcu=atmega2560 -DF_CPU=16000000L -DARDUINO=10816 -DARDUINO_AVR_MEGA2560 -DARDUINO_ARCH_AVR -I/Users/eijifrey/Library/Arduino15/packages/arduino/hardware/avr/1.8.4/cores/arduino -I/Users/eijifrey/Library/Arduino15/packages/arduino/hardware/avr/1.8.4/variants/mega /var/folders/f5/wmykvlzd0ml0hh17g7wscpvm0000gn/T/arduino_build_532785/sketch/MD_MIDIFile_play_test.ino.cpp -o /dev/null
fork/exec /Users/eijifrey/Library/Arduino15/packages/arduino/tools/avr-gcc/7.3.0-atmel3.6.1-arduino7/bin/avr-g++: no such file or directory
Error compiling for board Arduino Mega or Mega 2560.

Can you download and run the blink program onto your board?

No even the most basic blink function from the example library is showing a compiling error for Arduino Mega 2560 (same error code as above)

I think then that comes down to your installation. The old standby of uninstalling and installing again might work.

At least we now know it is nothing tho do with the library you are using.

I will put this in installation and troubleshooting maybe some one there will have an other thought on the problem.

I took the liberty of changing the title to better match what we now know is the problem.

1 Like

Yeah I tried it with a couple arduino unos I had lying around and it failed to compile even for those...yup i had to completely uninstall and reinstall my ide and libraries

I took the liberty of changing the title to better match what we now know is the problem.

My project didn't resolve into perfection just because we figured out that one compiling error. I have my entire original prompt to figure out still, which is why I made this topic in the first place. Please keep the topic appropriately titled and in the appropriate category.

No you have it wrong. If you can't even compile and run the blink code for your Mega and Uno, then this is the right place.

Again no. As nothing will compile the getting the one specific original code to compile, code that I may say that compiles perfectly on my machine, then you DO have an installation problem, so this is the best place for it to be.

As it is your post then you are free to change the title as you wish. Just open the first post for editing and change it.

But as I believe the post is in the right place, If you disagree, then you are quite at liberty to click the flag icon at the end of this post and ask the moderators to change it back.

It is a pity you are taking this attitude as I am only trying to help you get a solution to your real problem. Solve getting the blink to compile and I believe you solve that code you are trying to compile.

As I mentioned above the compiling error was resolved for all boards immediately after I did a complete uninstall and reinstall. BUT, I was still missing some kind of problem because my hardware was not responding the way I was expecting it to (I double checked the wiring and components). I actually came across a similar project you did with your glockenspiel and was inspired by your "don't use libraries" attitude so I am now going in that direction and trying to use your code from that project with some modifications. I will be posting that on a separate forum as I don't want to clog this one up. Also, I am not one to be rude, but the assumption that your one solution solved everything, and then taking the liberty of changing the title of my topic based on that assumption didn't rub me the right way, to say the least.

No you didn't, not in words I could understand what you wrote was

You never said that it worked after that.

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