Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix #148311 by adding dummy note events to end of loop during playback #5719

Merged

Conversation

krkartikay
Copy link
Contributor

Resolves: https://musescore.org/en/node/148311

The playback in MuseScore relies on midi events to know when to stop playing / loop back to start. By default, metronome ticks are added to the events map at every beat, but if there is a note after the last tick, playback will loop back simply after playing the last note and will not reach the end of the measure.

One possible solution was to add an end-of-track (or similar) midi event to the last measure, however, that won't fix the issue because the user may try to loop a portion of the score, which might not end on a measure boundary. In this commit, I have added a dummy NPlayEvent at the end whenever the user selects a loop. This works even for loops within measures. As I have not modified libmscore/rendermidi.cpp, the exported MIDI files are not affected.

@krkartikay krkartikay force-pushed the 148311-loop-rests-last-measure branch from 5979ac3 to 17a7582 Compare February 15, 2020 16:47
Copy link
Contributor

@jthistle jthistle left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good, in general! Just a single comment.

mscore/seq.cpp Outdated
// this is to let the playback reach the end completely before starting again
if (!events.count(cs->loopOutTick().ticks())) {
NPlayEvent ev;
ev.setVelo(0);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would do ev.setValue(META_EOT), since that is what this event is (end of track). 0 is ME_INVALID or META_SEQUENCE_NUMBER, neither of which this event is, really.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well, it's not really an end-of-track event either, because the user can select a portion in the middle of the score to be looped. I did a bit of research about MIDI events, but I'm still not sure about which event exactly should be used here. I thought that using an invalid event is the best option because this isn't really a MIDI event, it's just a dummy object, and is never written to a MIDI file. Maybe being more explicit about it could be better?

Suggested change
ev.setVelo(0);
ev.setValue(ME_INVALID);

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, right... I was under the impression that this happened when the loop was right at the end of the score, no? If not, then you probably don't need to change anything.

Copy link
Contributor Author

@krkartikay krkartikay Feb 15, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, actually this happens whenever there is a gap between the last event and loop endpoint. Now, because users normally select loop endpoints which happen to align with metronome ticks, so this issue was only noticed at the last measure where there was no metronome tick at the end. However this fix is more general and adds an event at any loop endpoint.

The issue is fixed by adding dummy note events to end of loop
before playback, because the sequencer only looks for the last event
in the events map before looping back.
@krkartikay krkartikay force-pushed the 148311-loop-rests-last-measure branch from 17a7582 to ca83e84 Compare February 19, 2020 11:28
@dmitrio95
Copy link
Contributor

But this would put an invalid MIDI event into the render result, wouldn't it?

@krkartikay
Copy link
Contributor Author

But this would put an invalid MIDI event into the render result, wouldn't it?

Yeah, it does add an invalid midi event into the event list, but that seems to get ignored by the sequencer. Should I do something else in its place?

@MarcSabatella
Copy link
Contributor

I don't know what the MIDI spec says nor do I have any insight into how different implementations might react. But I'd say, if it works for our own internal playback in both Fluid and Zerberus, I won't worry about if there is some case where MIDI output or JACK or whatever doesn't work right when loop is enabled.

@anatoly-os anatoly-os merged commit 43ca8c0 into musescore:master Apr 25, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants