MD_MIDIFile - Playing only the middle of a file

Has anyone using the brilliant MD_MIDIFile library been able to play a MIDI track starting at a set point part way through the file and then stopping at a set point before the end of the file?

For example, Starting at 40% in to the track and then once it reaches 60% of the track stop playing.

I'm thinking that getLength() along with startOffset and currOffset could be my best chance of success, any thoughts?

I have not heard of anyone doing this. Interested in any responses you may get.

Me too Marco :slight_smile:

Is there a simple way for me to access the Protected Attributes in MD_MFTrack?

With MD_MFTrack MFT; in my header

and Serial.println(MFT._currOffset); in my loop i get the error....

In file included from /home/chris/Arduino/LoopingShredSabrev5.3/LoopingShredSabrev5.3.ino:29:0:
/home/chris/Arduino/libraries/MD_MIDIFile/src/MD_MIDIFile.h: In function 'void loop()':
/home/chris/Arduino/libraries/MD_MIDIFile/src/MD_MIDIFile.h:591:13: error: 'uint32_t MD_MFTrack::_currOffset' is protected
   uint32_t  _currOffset;    ///< offset from start of the track for the next read of SD data
             ^
LoopingShredSabrev5.3:325:24: error: within this context
     Serial.println(MFT._currOffset);

You can by just moving the attribute to the public section of the class definition (quick and dirty), or by creating a getTrackOffset() type method to return the value (a better solution).

Note however that just jumping x% characters into the track does not mean you are x% through the time the track will play. Notes vary in length and you also need to respect that the MIDI file has a structure and you are more than likely to be jumping into the middle of a sequence of bytes that need to be interpreted together.

You also need to coordinate between the different tracks (usually of different lengths) if you want to be x% through the musical piece.

Ah yes good points for me to chew on - I'll need to have a think about how to get synched up and find the start of the next sequence, for my purposes i'll only ever have one track so that should make things a little easier.

I've started to attack this problem with a quick and dirty move for now and see how I go....


Still struggling to get those protected variables back though, i must be missing something simple >>

Tried moving uint32_t _currOffset; to public of class **MD_MFTrack **
Included MD_MFTrack MFT; in my header
then tried calling the variable in my loop() with
Serial.println(MFT._currOffset);
Compiles OK but only get 0 returned

Tried adding inline uint32_t getcurrOffset(void) { return (_currOffset); } ; to public of class MD_MFTrack
Included MD_MFTrack MFT; in my header
then tried calling the variable in my loop() with
Serial.println(MFT.getcurrOffset());
Compiles OK but only get 0 returned

:o

You are one object removed from the Track and just need to thread through the MIDIfile object to get at the track stuff.

You need to expose the offset to the MFTrack for the track you want from the MIDIFile object you are using. Otherwise you are just getting an offset from an unused standalone track structure.

The simplest I can think of is to have your getCurrOffset(uint8_t trackID) in MIDIFile and then reference the array of tracks in there to return the offset.

Looks like this newbie has got his work cut out for him :o

I've made some progress on this...

Using _length and _startOffset from MD_MIDITrack I can calculate my loop end offset.
During midiCallback() I check to see if _currOffset is greater than my calculated loop end offset. If it is i call SMF.restart() to take me back to _startOffset. Easy.

Now the trickier bit... The start of the loop,

I can easily calculate my loop start offset but as you pointed out it will most likely drop me in the middle of a midi event. So what unique information can i look for to identify where i am in the code and move me along to where the next data block starts....

Can a 0x90 get used anywhere other than a note on command?

Can a 0x80 get used anywhere other than a note off command?

Can the 0x0 that can come with a note off command get used anywhere else?

Does 0x80 0x0 get used anywhere other than in a note off command?

Any other unique things i could perhaps hang on to???....

hex.png

Unfortunately for me this was all done years ago and I no longer remember the ins and outs of the MIDI file format. I would expect that any byte could appear in a SYSEX event, for example, as this is a manufacturer specific block.

There is a MIDI standard that defines this so maybe it can offer some info on this.
Some introduction material here: Standard MIDI file format, updated
Standards document here: Standard MIDI Files (SMF) Specification

Someone else may know more.

Little update for you...

I've had success!

See wobbly footage of prototype in action

Your code seems to handle the currOffset being any value at all and successfully find its way to the beginning of the next midievent every time in my testing. My files are however very simple, with only one track which may make all the difference here.

Thanks for all your pointers Marco, it is so appreciated.

Good to hear.

Back on this project after moving house....

After writing some automated testing scripts it seems that dropping into the MIDI file stream and just playing works about 90% of the time, those other 10% give a guru meditation full reset, not good.

One way to get this success rate up to 100% could be that I parse each MIDI file when first loaded and note all the valid offsets (eg 44, 53, 62, 71, 80, 89, 98, 107, 116, 125, 134......) Then when i jump back to the middle of the track i make sure I land at the nearest valid offset point...