kpower
Published © GPL3+

Play Midi files from an SD Card using your Arduino UNO

Save Midi files to an SD Card and using a SD shield with an Arduino, play the songs on a Midi device

IntermediateFull instructions provided4 hours5,046
Play Midi files from an SD Card using your Arduino UNO

Things used in this project

Hardware components

Arduino UNO
Arduino UNO
×1
DS1307 Data Logger Shield
×1
Audio / Video Cable Assembly, MIDI
Audio / Video Cable Assembly, MIDI
×1
PCB Panel Mount MIDI Female DIN 5-Pin Jack
×1
Flash Memory Card, SD Card
Flash Memory Card, SD Card
×1
MC74HC14A Hex Schmitt-Trigger Inverter
×1
Through Hole Resistor, 220 ohm
Through Hole Resistor, 220 ohm
×2
Pushbutton switch 12mm
SparkFun Pushbutton switch 12mm
×1

Software apps and online services

Arduino IDE
Arduino IDE

Hand tools and fabrication machines

Soldering iron (generic)
Soldering iron (generic)
Wire Stripper & Cutter, 18-10 AWG / 0.75-4mm² Capacity Wires
Wire Stripper & Cutter, 18-10 AWG / 0.75-4mm² Capacity Wires

Story

Read more

Custom parts and enclosures

Schmitt Trigger spec sheet

Schematics

Schematic

Midi Output Circuit

Code

Read Files from SD Card

Arduino
Test SD Card Reader - list files on the card
/*  SDlistFiles

 This example shows how print out the files in a directory on a SD card

 The circuit:
 * SD card attached to SPI bus as follows:
 ** MOSI - pin 11
 ** MISO - pin 12
 ** CLK - pin 13
 ** CS - pin 10

 This example code is in the public domain.
 
 */
#include <SPI.h>
#include <SD.h>

File root;

// Chip Select for SD Card - Pin 10 for shield
const int chipSelect = 10;

void setup() {
  // Open serial communications and wait for port to open:
  Serial.begin(9600);
  pinMode(chipSelect,OUTPUT);
  
  Serial.print("Initializing SD card...");

  if (!SD.begin(chipSelect)) {
    Serial.println("initialization failed!");
    return;
  }
  Serial.println("initialization done.");

}

void loop() {
  root = SD.open("/");

  printDirectory(root, 0);

  Serial.println("done!");

  delay(5000);
}

void printDirectory(File dir, int numTabs) {
  while (true) {

    File entry =  dir.openNextFile();
    if (! entry) {
      // no more files
      break;
    }
    for (uint8_t i = 0; i < numTabs; i++) {
      Serial.print('\t');
    }
    Serial.print(entry.name());
    if (entry.isDirectory()) {
      Serial.println("/");
      printDirectory(entry, numTabs + 1);
    } else {
      // files have sizes, directories do not
      Serial.print("\t\t");
      Serial.println(entry.size(), DEC);
    }
    entry.close();
  }
}

Minimal Midi Player

Arduino
Play midi files from SD card using Arduino
#include <SdFat.h>
#include <MD_MIDIFile.h>
#define SERIAL_RATE 31250 // Midi standard serial rate is 31250 baud
#define ARRAY_SIZE(a) (sizeof(a)/sizeof((a)[0]))

const byte SD_SELECT = 10; // Chip select for Sd card is pin 10
const char *loopfile = "LOOPDEMO.MID"; // pointer to midi file on SD card
const int buttonPin = 7;    // the number of the pushbutton pin
const int ledPin = 6;      // the number of the LED pin
bool playFile = false; // boolean variable indicating if a file should be played


SDFAT  SD;
MD_MIDIFile SMF; // create an instance of a midi file

// 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.
void midiCallback(midi_event *pev){
  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 setup() {
  pinMode(buttonPin, INPUT_PULLUP); // use built in pullup resistor with push button
  pinMode(ledPin, OUTPUT);
  digitalWrite(ledPin, LOW);
  
  Serial.begin(SERIAL_RATE);

  // Initialize SD Card
  if (!SD.begin(SD_SELECT, SPI_FULL_SPEED)){  
    while (true) ;
  }

  // Initialize MIDIFile
  SMF.begin(&SD);
  SMF.setMidiHandler(midiCallback);
  SMF.looping(false);
}

void loop() {
  // Wait for pushbutton input
  int reading = digitalRead(buttonPin);
  // If push button is depressed, load midi file and switch on LED
  if (reading == LOW) {
    playFile = true;
    digitalWrite(ledPin, HIGH); // Switch on LED
    SMF.load(loopfile);
    }

  // play the file if playFile is true
  if(playFile == true){
  // Play until end of file is reached  
    while (!SMF.isEOF()){
    SMF.getNextEvent();
    }
  }
  // Once file is finished playing, close midi file and switch off LED
  playFile = false;
  digitalWrite(ledPin, LOW);
  SMF.close();
}

Multiple Midi Tracks

Arduino
Allow user to play multiple tracks from the SD Card
/*
Plays multiple midi files from an SD Card
Only midi file on the SD Card
All files must be in root directory
File names must follow following format XXXXXXXX.mid
*/
#include <SdFat.h>
#include <sdios.h>
#include <MD_MIDIFile.h>

#define SERIAL_RATE 31250 // Midi standard serial rate is 31250 baud
#define ARRAY_SIZE(a) (sizeof(a)/sizeof((a)[0]))

SDFAT  SD;
File file;
File dir;
MD_MIDIFile SMF; // create an instance of a midi file
const byte SD_SELECT = 10; // Chip select for Sd card is pin 10
char midiName[13]; // character array to hold midi file names
const int buttonPin = 7;    // the number of the pushbutton pin
const int ledPin = 6;      // the number of the LED pin
bool playFile = false; // boolean variable indicating if a file should be played
int err; // error code returned from midi file load


// 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.
void midiCallback(midi_event *pev){
  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 setup() {
  pinMode(buttonPin, INPUT_PULLUP); // use built in pullup resistor with push button
  pinMode(ledPin, OUTPUT);
  digitalWrite(ledPin, LOW);
  
  Serial.begin(SERIAL_RATE);

  // Initialize SD Card
  if (!SD.begin(SD_SELECT, SPI_FULL_SPEED)){  
    while (true) ;
  }

  // Initialize MIDIFile
  SMF.begin(&SD);
  SMF.setMidiHandler(midiCallback);
  SMF.looping(false);
}

void loop() {
  // Wait for pushbutton input
  int reading = digitalRead(buttonPin);
  // If push button is depressed, load midi file and switch on LED
  if (reading == LOW) {
    playFile = true;
    digitalWrite(ledPin, HIGH); // Switch on LED
    }

  // play files son the SD card if playFile is true
  if(playFile == true){
    dir.open("/");
    while (file.openNext(&dir, O_RDONLY)) {
      file.getName(midiName,13);  // Use SdFat getfile name to get next midi file from SD Card
      file.close();
      
      char *nextTune = &midiName[0];  // create pointer to the filename retrieved by SdFat
      err = SMF.load(nextTune);

      // Play until end of file is reached  
      while (!SMF.isEOF()){
        SMF.getNextEvent();
      }

      SMF.close();
      delay(500);
    }
  }
  // Once files are finished playing, set flag to false and switch off LED
  playFile = false;
  digitalWrite(ledPin, LOW);
}

Credits

kpower

kpower

19 projects • 6 followers
Qualified Electrical Engineer with experience in software and hardware development

Comments