Export midi file does not observe any pauses (e.g. Caesura & Section Break)

• Aug 28, 2015 - 06:01
Reported version
2.2
Type
Functional
Severity
3
Status
closed
Project

Section breaks will pause playback and exported wav/mp3/etc, except exported midi file.

e.g. attached mscx has two measures seperated by section break, but the exported midi file does not include the pause.

Tested in both 2.0.2 release and git build c89fe33


Comments

Title Export midi file does not observe SECTION_BREAK pauses Export midi file does not observe any pauses (e.g. Caesura & Section Break)
Severity

Actually, on further investigation, I've discovered that the exported midi does not even include pauses from Caesuras. Apparently export midi was not modified when pauses were implemented. I've updated this title and will go ahead and fix both pauses.

The fix is probably simple, in exportmidi.cpp. For section break pauses, in a for loop will need to iterate over all repeat segments and add a pause event when there is a pauseBefore (note: I will need my last PR to be merged first). For the caesura pauses, should just be a matter of including similar pause event logic as the score's tempomap.

Severity

@eric, any progress? I see you have a related PR marked "on hold", but that PR also says it doesn't solve the problem of MIDI files not matching exported WAV, which is what I care about. I might take a look at this one myself, but wondered if you found anything when you tried.

Severity

There is no such MIDI event as a "pause" (at least not that can appear in a SMF). The obvious workaround would be to use an extremely slow tempo for a few ticks. Unfortunately, MIDI tempos are specified in "microseconds per quarter note" using 3 bytes, which is not enough bytes to pause for longer than 35ms on a single tick (assuming 480 ticks per quarter note). We can't use more than one tick for a pause because pauses can happen "between" notes.

So that leaves two available options:

  1. Insert a measure's worth of ticks at the place of the pause and use a tempo change to make the measure last the required duration, and another tempo change afterwards to return to the previous tempo. (Inserting a whole measure's worth of ticks ensures that notes line up in the same place within bars around the pause. Inserting a measure of 4/4 would allow a pause of 67 seconds long, which should be ample. Multiple measures and/or time signature changes could be used to obtain a longer pause.)
  2. "Create" a MIDI pause event using a System Exclusive extension to the MIDI standard. This is easier to implement, and has the advantage of not inserting extra measures or tempo changes or modifying the notation in any way. The major disadvantage is MIDI players except MuseScore would ignore the pause (unless they were updated to understand the SysEx, which probably wouldn't happen). This means playback of the MIDI file wouldn't match exported WAV/MP3, but the information about the pause would be there for anyone parsing the MIDI file, which is all I need for my purposes.

So (1) has the advantage that playback of MIDI files would match the playback of exported WAV/MP3, but notation of the imported MIDI file would not match the notation of the original MSCZ. Implementing (2) would achieve the opposite (correct notation but incorrect playback).

Since MIDI files are more about sound that playback I am inclined to go for (1), even if it is a bit more tricky to implement, but if anyone disagrees then let me know. (Another possibility would be to go for (1) but add a SysEx event to say that the extra measures are really a pause, though this may be more trouble than its worth.)

I note that in the other issue you mention that a fix would probably have to wait until MuseScore 3.0. I need this fixed in 2.2 so I'm afraid that probably means I can't fix the other issue.

Hmm, not looked properly at the code but I'm not sure how this will help you there. Any event you add (pause, tick or tempo marking) will surely be caught in the repeat? You will need to make the event belong to the measure before or after the section break, but what if there is a repeat before *and* after the section break? The event will get caught in one of the repeats either way.

And anyway, my extra measure's worth of ticks is a hack to get around the fact there is no "pause" event in standard MIDI, but MuseScore does have a pause event so I don't think you want to go adding ticks. A better solution might be to distinguish between pauses due to section breaks and pauses due to breaths. Pauses due to section breaks should only be counted once, whereas other pauses count on every repeat.

My original plan for that issue was to insert an extra tick to represent the pause. That tick would have been between the end repeat and start repeat around such a section break, so that pause would correctly only be applied once when unrolling. But that idea was shot down because would have messed with musescore's assumption that measures have a fixed number of ticks. But if I apply your idea and have pauses be represented by a complete measure worth of ticks, then that wouldn't break that assumption.

I don't think should force pauses of section breaks to always only count once. That might make sense when section breaks are used to divide movements, but musescore doesn't specifically dictate that section breaks are to be used to only represent divisions between movements. To musescore, all that section breaks mean is a restart of system header and measure count, and someone might use section break to do just that, and so still should be able to jump or repeat between section breaks.

I can get away with an extra measure of ticks here because it's only for export - once the file is exported MuseScore doesn't have to worry about it again - but if you are planning on storing this extra measure within MuseScore then it could still mess things up.

Section breaks can already only be played once. If you insert a repeat a few bars after a section break you will see that the repeat only jumps back to the section break, not to the beginning of the piece.

I never said I would store an extra measure inside musescore. All I was suggesting is when generating the event map to insert a measure worth of ticks.

Regarding repeats and DC's, yes they seem to go back to the section break. But DS's can go back to previous sections.

Well I've not looked at the code (so perhaps I should stop commenting!) but if you're only doing this for export then the "musescore expects a fixed number of ticks" rule shouldn't apply. For standard audio export at least you should be safe to insert one extra tick with a pause. Let's say this is tick 1000, now you store a tuple (1000,1) somewhere, meaning that ticks after tick 1000 occur 1 tick later than expected. I see no difference between doing this and what I was planning on doing, which was storing (1000,x) where "x" is the number of ticks in a measure.

That issue was to make the section breaks pauses with repeats work for playback, but ideally a fix for that issue would also fix that in midi export, and that's the reason why I first responded to your first comment here. I think doing a fix that works elegantly for both cases of playback and export is better than having one set of code only fix the problem for playback and one set of code only fix the problem for export. I would think that adding a whole measure's worth of ticks to the event map works for both playback and export, which is why I liked that idea.

In reply to by System Message

Severity
Reported version 2.1 2.2

I tried this in 2.2.1 released. This renders score navigation/measure-counting in the output MIDI completely useless. It is now impossible to correlate a score with a midi tool's representation of it when active pauses are used. Of course, the solution here is, as it was before, not to use them at all if post-processing MIDI is important to you.

The right answer is a box for articulation control (note end) in the inspector, In the meantime, I wish there were a way (perhaps a secret setting somewhere) to keep this out of midi files.

Due to the limitations of the MIDI format there is no perfect solution here. The important point is that MIDI files exported from MuseScore now sound like exported WAV/MP3 files, which didn't use to be the case. Of secondary importance, MIDI files that get re-imported into notation software will look like the original score it was exported from (notes occur at the same places in each measure). If there are a few extra measures that throw off the numbering then that's a small price to pay to get the above features.

If you need an accurate measure count then you can simply right-click on any pause, go to Select > All similar, and set the pause duration to zero in the Inspector before you export the MIDI file. If the score has any section breaks then you would need to eliminate the pause for each of them individually by right-clicking on them and changing their properties.

Alternatively, if you wrote the code to count measures in MIDI files then you can have it ignore the extra measures that were inserted to make pauses. You can recognise these pauses because there will be a tempo change (which may or may not fall at the beginning of a measure) followed by exactly one measure's worth of ticks before the next tempo change (which may or may not be a change back to the original tempo). The empty measure's worth of ticks will contain no MIDI events except the tempo change.

If you like, you could also modify MuseScore's code to have it insert a SysEx message to indicate that "the following X ticks are part of a pause" so that you know they should not be included in a measure count.

In reply to by shoogle

While both of these actually remain possibilities, there is a perfect solution, or two, which are articulation control from the inspector (i.e., like the piano editor, but it wouldn't crash and you could click on notes instead of gold bars), or new kinds of pauses that do that for you (and fermata control would be up to you). At some point, this product is going to have to retire the "Not a performance tool!" excuse and provide performance controls similar to those of similar, older systems.

A perfect solution for MIDI export would:

  1. Sound like the original
  2. Look like the original
  3. Have the same number of bars as the original
  4. Give the above features in all MIDI players (i.e. not make use of SysEx messages)

We chose to satisfy (1), (2) and (4) at the expense of (3). What you are asking for is more control, so that there is an easy way to make a different choice, but the point is that you would still have to make a choice. It is simply not possible to satisfy all of those points at once, so there is no perfect solution.

What we could do is add a checkbox option to the Preferences that says "Export pauses in MIDI files?". That would give you (2), (3) and (4) but it would be at the expense of (1). Alternatively (or in addition) we could do what I suggested before and add a SysEx message to say "here comes a pause" so that you can ignore it from the measure count, but that would give you (1), (2) and (3) at the expense of (4).