Midi File Exports, Repeats, measure number on the score

• Mar 26, 2017 - 17:48

I think this may be as much about midi representation as Musescore, but I hope someone can get me on the right track.

I am using Musescore and an OMR program to convert old sheet music (that I own) to a more readable score. At the same time, I have a player piano and am exporting Midi and have a little Midi player program that runs there on a touch screen powered by a Raspberry Pi. The Pi is too slow for Musescore itself (I tried, it will run, but it cannot play at full speed even moderately complex pieces), so I wrote a midi player.

The Midi player counts measures and shows the current bar number, which aligns with the displayed Musescore-exported PDF. The user can enter any measure to start playing. Perfect. Handy for my wife, she can hear the timing on a piece she is learning (the midi player will play at any tempo so she can slow it down).

The issue is on repeats. Let's say you played 4 bars, repeated, skipped the 4th and played the fifth. From a Musescore perspective that 5th measure is number 5, but inside the midi file it is number 8. As best I can tell there is no indication in the midi file that you are repeating, it just "plays" the repeat out the midi. In fact in looking at the midi standards I see no provision for indicating any kind of measure count or repeat or even indicating a repeat was done.

What I am doing now is going through and manually numbering measures, so I will show as text (in the example above) the first measure as "1/5" to indicate it is measure 1 the first time, and 5 the second. That works, but is really tedious. Since I try showing it only once on each system, it also gets screwed up with any reformatting and migrates to the middle of the page and has to be redone.

So here's my question: Am I missing anything? Is there any way in a midi file to tell what bar you are actually playing (the way Musescore numbers it)?

Or conversely, is there any way (plugin?) to tell Musescore to number measures honoring the repeats in some fashion?

I've searched and read and cannot even find discussion of this, so I think I am either using the wrong terms, or am out on a niche area... so thanks in advance for anyone who might have advice.


Comments

As far as MS numbering easier I know of 1 trick. Right click measure 5 and select measure properties. Then change add to measure 0 to add to measure 3 and all subsequent measure numbers will be counted properly from that point until the next repeat. Unfortunately I can't think of an automated way of fixing the "1/5" and so on way of counting measures with out using a plug in that will automatically add staff text with the proper measure count. Considering your programming ability, I think you should be able to do that. Version 2.x plugin instructions are included in the Plugin creator according to the handbook.

In reply to by mike320

Thanks, Mike320. I'll look at the plugin stuff, I keep hoping someone will say "oh, that's baked into this nibble of the Midi file you just have to look". I don't really need the measures renumbered so much as having them match what I can derive while playing the midi file. Calling it 5 or 8 would be fine so long as I can match the number in selecting where to start playing in the midi file. But I doubt that's going to happen.

In reply to by Ferguson

If you are ok with one more file to deal with, then you can run MuseScore with mscore yourfile.mscz -o yourfile.mpos
It will generate an .mpos XML file containing the list of "graphical measures" as "element" tag and a list of "events" refering one element and giving its time. So for a two measures score with repeat barlines you would get something like


element id=1
element id=2

and


event elid=1 position=0
event elid=2 position=2
event elid=1 position=4
event elid=2 position=6

Hope it helps.

In reply to by [DELETED] 5

OK, obviously there's a whole part of Musescore I wasn't even aware of. :)

I will look at that, but this brings up another possibility entirely. It may be easier for me to modify the midi output portion of Musescore to include measure numbers (e.g. as text meta fields). The midi export is already doing the unroll, I just need to look to see if measure numbers are exposed and available in that routine; if they are it's pretty trivial and since meta text is largely ignored (at least by instrument type use of midi files) it might be an even better solution, as then I can use real (i.e. as normally counted) measure numbers. Either leave the repeat number ambiguous (e.g. which pass through), or include in the UI a choice for "pass" in some fashion.

But going to definitely look at this as I had no clue "mscore" existed. Thank you. More later after I stare at the midi export a while.

In reply to by mike320

I read through that, it's intriguing though a bit contrary to another goal. One reason I did this is to get my wife moving a bit more on her piano lessons - shuffling paper was painful, so I thought this would help. Unrolling would be helpful to play, but I am not sure constructive to learning to play, as repeats are so widespread and ability to read them so necessary to sight reading. However (see above to the alternate file) it raises another possibility.

I don't know if this should go in a separate thread, but trying to not litter so here goes...

I am hoping someone who does development will help me to know if I'm on the right track.

I want to add a meta text field to the midi output at the start of each measure, containing the musescore-numbering measure number (so when playing repeats I am seeing it counted rolled up, not unrolled).

ExportMidi's write method appears to be where data is output and I could insert a text meta, but I don't see any link back to the measure information (and in particular the _no and _noOffset (or their get methods).

So I went back up to renderMidi and collectMeasureEvents has access to the measure information where it's called from renderStaff. It's there, whether the _no and _noOffset are populated at that point I have no clue yet.

So what I'm thinking is add a measure number (or number and offset to be consistent) to the NPlayEvent type optionally, and pass it through and save it in the events collection of NPlayEvent's, which should then I think get me visibility back in ExportMidi, where I could write it out as a text meta.

This seems very roundabout though, and I hate adding properties to a widely used class I don't understand well, so am wondering if I'm missing something obvious, and there is some visibility in the ExportMidi of the measure number?

Or conversely, if I did add to the class, any apparent issues doing it this way?

Am I anywhere near the right track? First time modifying the program.

I'm putting up a VM now so I can build Musescore so haven't actually tried this yet, just been staring at code.

In reply to by Ferguson

Just to put some closure to this in case anyone else is looking...

I was able to do this inside of the exportmidi.cpp program (with thanks to lasconic for a pointer to keep it simple), by following the trail from the NPlayEvent up to note, which derives from element, which allows one to find the measure, and thus the measure number.

I output a Meta type "Marker" event whenever outputting a note where the measure changes. I was then able to change my midi player program to look for these markers, and if present use them to label measures, if not it just counts beats and bars from the time signatures. Works perfectly; the midi file then has measure numbers that match the score, but are unrolled (e.g. it might go 1-2-3-4-5-1-2-3-4-6-7-8-1-2-3-4-6-7 for a repeat, with alternative endings, and a dc a fine.

At the same time I discovered the lack (as of 2.1) of control over midi-channels by staff, and when I had a grand staff with vocals the piano parts were coming out as channel 2, which my physical midi device was ignoring. Since exportmidi.cpp is where all that is controlled, I changed it to suppress all but the last two staves -- which in my case is right, but obviously would not work for others (actual midi channel controls are in 3.0 I think).

So with a couple dozen lines of code total, I got both issues fixed nicely. Thanks for the help.

In reply to by Ferguson

Hi! Could you please give me some pointers on how you detected the measure change? I am quite new to this codebase and my c++ is pretty rusty.
I tried something along the lines of

const NPlayEvent& event = i->second;

const Measure* note_measure = event.note()->findMeasure();
                    if (note_measure != previous_measure) {
...

but it causes a segmentation fault.

Do you still have an unanswered question? Please log in first to post your question.