Go Down

Topic: Library for playing MIDI files from the Arduino (Read 6 times) previous topic - next topic

marco_c

#10
Jan 01, 2013, 08:13 am Last Edit: Jan 05, 2013, 12:56 am by marco_c Reason: 1
This version (0.4) now works with everything I have been able to throw at it. :)

I have reworked the timing section so that it is tighter and more accurate in keeping the music to time. There were also serious logical errors in the processing of MIDI run on messages that caused the some files to play badly or not at all (see my first post).

I think there is a bit of tidy up to do and then it can be released as v1.


Arduino libraries http://arduinocode.codeplex.com
Parola hardware & library http://parola.codeplex.com

robtillaart

Good to hear it is working now!
I wait until after the cleanup is done before reviewing again ;)
Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

marco_c

This work is now completed and can be found at  http://code.google.com/p/arduino-code-repository/

Thanks to robtillaart for his great comments and feedback during development.

The library is used to process MIDI files from the SD card. MIDI and SYSEX events are passed to the calling program through callback functions for processing. This allows programmers the flexibility to implement a message to a MIDI synthesiser through serial interface or other output devices,
like a MIDI shield or custom hardware.

Processing of files may may be paused and restarted using methods in the library.

Download the library and see MIDIFile.h for more information if you are interested.
Arduino libraries http://arduinocode.codeplex.com
Parola hardware & library http://parola.codeplex.com

robtillaart


Hi,
minor issue, the midihelper.h has no construct like

#ifndef _MIDIFILE_H
#define _MIDIFILE_H

in midifile.cpp ~line 270
Code: [Select]

for (n = 0; (n < 100) && (!doneEvents); n++)  //<<<<<<<<<<<<<<<<<<<<
{
doneEvents = false;

for (uint8_t i = 0; i < _trackCount; i++) // cycle through all
{
bool b;

if (_format != 0) DUMPX(i);
// Other than the first event, the other have an elapsed time of 0 (ie occur simultaneously)
b = _track[i].getNextEvent(this, (n==0 ? elapsedTime : 0));
if (b && (_format != 0))
DUMPS("\n-- TRK ");
doneEvents |= b;
}
n++;  //<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< extra n++ in the loop? why ?

// When there are no more events, just break out
if (!doneEvents)
break;
}


in int MIDIFile::load()
if there is an error should you not close the file ?
+ some var names are still cryptic e.g. c  (which is a string containing part of header)



shorter?
Code: [Select]
uint32_t readVarLen(SdFile *f)
// read a variable length parameter from the input stream
{
  uint32_t  value = 0;
  char      c;
 
  do
  {
    c = f->read();
    value = (value << 7) + (c & 0x7f);
  }  while (c & 0x80);
 
  return(value);
}


buffer with "position info"
Code: [Select]
void dumpBuffer(uint8_t *p, int len)
{
  for (int i=0; i<len; i++, p++)
  {
    if (i% 8 ==0)
{
   DUMP('\n');    // << #DEFINE DUMPLN(T) Serial.println(T) ??
   DUMP(i);
   DUMP('\t');
}
    DUMP(' ');
    if (*p<=0xf)
DUMP('0');
    DUMPX(*p);
  }
}


finally there is a style diff between the #ifdef used for void MFTrack::dump(void) and  void MIDIFile::dump(void)

(end of nitpicking ;)
Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

marco_c

Thanks again for the review (nitpick?) :)

Quote
midihelper.h has no construct like

OK. It has now, but it is only ever included in one file which is protected from re-inclusion.

Quote
n++;  //<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< extra n++ in the loop? why ?

Left over from when it was a while loop. Should not affect the functionality though, as the for loop is just a way to limit too many events. Effectively halves the (arbitrary) limit.

Quote
if there is an error should you not close the file ?

Yes absolutely. Interesting is that SDFat did not fail over eepeated teationg with a fle that was not correct. It must handle the case of the open file (or maybe it just doesn't care?).

Quote
some var names are still cryptic e.g. c

This is picky. The char array is local to a block of 5 lines of code! To keep you happy I have renamed it 'h' :P

Quote
shorter?

Clearly so. I'll do some testing as the original code was proposed as the right code to process the varlen parameters by the MIDI organisation.

Quote
#DEFINE DUMPLN(T) Serial.println(T) ??

The philosophy adopted in the DUMP output is that the \n is at the start of the new line, not at the end of the previous one. This makes it cleaner as I can't always tell where the end may be but am sure when I start a new line. So I need to explicitely use '\n' when I want it. It also makes it easier if I want to add debug as I don't need to worry about the line endings sprinkled through the code.

Quote
style diff between the #ifdef used for void MFTrack::dump(void) and  void MIDIFile::dump(void)

I assume you mean in the header file for the class definition?
I wanted to keep the dump function prototype available at all times so that I don't need #if in the sketch code around a call to the dump() method, even if it is an empty function. However, in the classes, the #if switch will cut out all the code for the MFTRack class, as this is only called by MIDIFile.dump().
I suppose an alternative is an empty inline definition in the class dependent on the #if, but the result isthe same.
Arduino libraries http://arduinocode.codeplex.com
Parola hardware & library http://parola.codeplex.com

Go Up