GSoC 2016 - Week 11 - Automatic Real-time & PortMidi
This was my 11th week working on note entry with MuseScore for Google Summer of Code. Most of this week was spent making small improvements here and there and solving a few issues with automatic real-time mode.
This week’s summary:
- Workaround for PortMidi bug on Windows and Mac
- Metronome unit tests
- Instant note entry in automatic Real-time mode
Still to do:
- New rhythm simplification and voice extraction implementation
- Delayed preview for automatic real-time
- Test user feedback
PortMidi is a library that MuseScore uses to communicate with MIDI hardware and software on Windows and Mac. (On Linux MuseScore uses ALSA instead because PortMidi has a relatively limited feature set due to the need to support many Midi implementations across multiple operating systems.) Since my development system is Ubuntu Linux I had not noticed a bug in my new automatic real-time mode that only affects PortMidi.
MuseScore runs on a number of different operating systems, and each operating system has its own method of communicating with MIDI devices. Rather than having to support each method individually, MuseScore uses the PortMidi software library to provide a common MIDI interface on the Windows and Mac platforms. (On Linux MuseScore can use either ALSA or JACK, both of which provide more advanced capabilities than PortMidi - PortMidi’s features are limited precisely because it has to support multiple platforms).
Since my development system is Ubuntu Linux I had not noticed a bug that only affects PortMidi where attempting to enter a single note in automatic real-time mode resulted in an endless series of tied notes. The problem was caused by the fact that PortMidi (unlike ALSA and JACK) is unable to “inform” MuseScore of new MIDI input - it is up to MuseScore to “ask” whether there have been any new input events. My original implementation of auto mode involved a synchronous loop that would send a click, wait for a short period listening for MIDI input, and then send the next click. This function worked with ALSA, but with PortMidi it was blocking MuseScore’s periodic requests for new MIDI events. To prevent this issue I had to replace the synchronous loop with an asynchronous system of timers using Qt’s system of signals and slots.
Unfortunately, switching from the synchronous loop to the asynchronous calls made the metronome clicks more sporadic and has decreased the accuracy of automatic real-time mode at higher input tempos. It may be that the only way to alleviate this is to delay adding any notes to the score until the end of each measure so that the time spent in signal-blocking functions is minimised.
Instant note entry in automatic real-time mode
A positive consequence of using timers is that gives more control over how to enter the function from outside. By default there is a 750 ms delay between clicks (80 clicks-per-minute). The question is, when you first press a key should a click be triggered immediately or after 750 ms? I originally implemented it so that the delay comes first, giving the user time to prepare for the first click or even to release the key and cancel the note. This is still the case if the user presses the “realtime-advance” shortcut key, but not if the user pressed a note key. The result of this is that a user entering a semi-breve (whole note) counts beats like this:
Press … Two ... Three … Four …. Release
Press … One … Two … Three … Four …. Release
This behaviour appeared to me to be the most intuitive. A side effect of this is that it is now possible to enter a rest by pressing and immediately releasing a note key. This is because the key press immediately triggers a click, but there is a very small delay of 100 ms between the click being sent and the advancement actually occurring. This is intentional to catch any notes that the user might enter slightly late, but it means that if the key is released in this time then a rest will be entered instead. I could correct this “bug”, but I think it is actually quite useful to be able to enter a rest with the MIDI keyboard.