GSoC 2016 - Week 2 - First attempt at Semi-Realtime MIDI
This was my second week working on note entry with MuseScore for Google Summer of Code. Having figured out MuseScore’s existing implementation of note entry last week, this week I was able to make real progress with the new modes. In fact, I think it’s time for another video!
This week’s summary:
- Rhythm input mode nearly complete!
- Basic implementation of auto and manual semi-realtime modes
- Changes to the audio sequencer to allow metronome ticks in note entry mode
Still to do:
- Some usability questions for rhythm input mode
- Performance improvements needed for automatic semi-realtime mode
- Simplification of rhythms and voice extraction in semi-realtime modes
Semi-Realtime modes
The bulk of my work over the last week has been on my semi-realtime modes for entering notes by playing the piece naturally on the keyboard. I managed to implement basic input for both the automatic and manual version of this mode. Entering notes in these modes currently results in a series of tied notes. These tied notes can be combined by exporting the file in the MIDI format and then re-importing it into MuseScore, and one of my tasks for the coming weeks will be to make this process automatic.
Preview of note entry in Semi-Realtime mode before simplification of rhythms and voice extraction.
I have found that the manual version of semi-realtime is quite effective for entering notes. In the manual version, the sustain pedal is used to tap beats and the user simply plays in time with the beats. Pressing a midi note enters a note with the currently selected duration (e.g. a crotchet or “quarter note”), and then each press of the sustain pedal ties on another note of the same duration. The user sets the pace with the pedal, so they are free to speed up or slow down depending on the difficulty of the piece.
In the automatic version, the “beats” happen at regular intervals like a metronome. I currently have it set up so that the beats do not start until the user user holds down the sustain pedal, and they continue for as long as the pedal is held. Unfortunately, there appears to be some lag due to the recalculation of the score layout on every beat, so in practice the intervals are not very regular. This means that the automatic version of semi-realtime is not very usable at the moment, but I think that this will not be an issue once the new layout optimisations are in place. In a worst-case scenario, automatic realtime entry could be done in a special view with fixed bar lengths to avoid any recalculations during note entry.
Somewhat to my surprise, the most difficult aspect of implementing semi-realtime mode so far has been getting MuseScore to play an audible "tick" sound on the beat. My plan was to borrow the metronome sounds that are used in playback mode, but this proved to be quite a challenge! The metronome is not a MIDI instrument as I first assumed, but it is actually made up of hard-coded raw audio samples that were never intended to be used outside of playback mode. In playback mode the sequencer intercepts the MIDI metronome events and adds the raw samples directly to the audio stream before passing the note events to the MIDI synthesizer. Outside of playback mode the sequencer is bypassed and MIDI events (e.g. Note ON when the user adds a new note in note input mode) are sent straight to the synthesizer, so there is no opportunity to add the metronome sound. I managed to get the sequencer involved again in note entry mode so that the metronome sound is available, but I had to work out how to manage various memory locks designed to prevent multiple threads from modifying the audio stream at the same time.
Once I had the metronome working I began experimenting with the tick sounds. There are two tick sounds with slightly different pitches: "tick" and "tack". In playback mode the ticks are determined by the time signature, with a tick for the first beat of the measure and a tack for the remaining beats. For example 4/4 sounds like this: "TICK... Tack... Tack... Tack... TICK... Tack... Tack... Tack... TICK... Tack... Tack... Tack...", etc. In Semi-Realtime note entry mode the user can choose the length of each beat, and might select something smaller than the actual beat. In my current implementation I use the volume of the "tacks" to indicate which beats are "real" and which are "extra". For example, if the user chooses to enter quavers (eighth-notes) then there will now be 8 beats - 4 real and 4 extra. The extra beats are played more quietly than the real beats, like this: "TICK... tack... Tack... tack... Tack... tack... Tack... tack... TICK... tack... Tack... tack... Tack... tack... Tack... tack..." etc.
Rhythm input mode
This is a new mode for MuseScore where pressing numeric keys enters notes of different duration (quarter notes, eighth notes, etc.) but all of the same pitch (middle C). The pitches are then set in Repitch mode. I introduced Rhythm mode last week and made an early attempt at implementing it. This week I managed to sort out entering rests and dotted notes, so that’s rhythm input mode essentially finished! However, there are still a few things to consider:
- Providing audible feedback about what the user just entered
- Rests and dotted notes - room for improvement?
It would be helpful for users if they didn’t have to look away from the score they are transcribing to know that they entered the right rhythm. This is where audible feedback comes in. Normally MuseScore plays the pitch of note, but clearly that is not useful here. As I said last week, Rhythm input was inspired by a similar mode from Denemo - another music notation program. Denemo uses percussion sounds to indicate the note duration, so it would probably make sense for MuseScore to do something similar. Currently the synthesizer can only deal with MIDI instruments that are actually in the score, so I will have to create some kind of dummy percussion instrument to play rhythm noises, or alternatively I could use hard-coded samples as is done for the metronome.
I have Rhythm mode set so that pressing the period key (.) toggles dotted rhythms on or off, and pressing the zero key (0”) toggles between entering notes or rests. The question is, should this change only last for the next note/rest entered, or should it be permanent until the button is pressed again? Also, might some users like the option to press and hold the button while entering dotted notes/rests and then release it when they want to return to entering normal notes? Making the toggle only last for one note is easy, but the press-and-hold method will require more work because MuseScore’s shortcut mechanism can currently only detect when a key is initially pressed, not whether it is still being pressed or whether it has been released. However, having such an ability may prove to be useful for other modes too.
Personal blog post: http://peterjonas.net/blog/musescore/gsoc-week-2-first-attempt-at-semi-…
Comments
I wonder whether it might be better not to rely on the sustain pedal for both semi-real-time modes. I have a 25-key controller that did not come with a pedal. I can see how it's needed for the "manual" mode, but is it for the "automatic" mode? Why not have the metronome start when a "record" button is clicked, or a shortcut pressed?
Regarding the lag, I believe the layout speed optimizations are already done—if more is planned, there's not much further it's possible to go. The crux of the improvements is that if a change affects only one page, then only that page will be re-laid out, which gets response time for most edits down to a couple milliseconds. So the lag on the addition of a note (present also in other note entry modes) is probably coming from something other than the layout.
In reply to I wonder whether it might be by Isaac Weiss
I believe the layout performance improvements are "available" but are not yet being used everywhere that they could be. Basically, there is the old "doLayout" function which does layout for the whole score, and the new function "doLayoutRange", which only does layout for the part of the score you ask it to do layout for. However, sometimes it is not easy to know in advance which bit of the score needs to be included in the range, so some edit functions are still using "doLayout" and haven't been updated yet to use "doLayoutRange".
Regarding the use of the sustain pedal, eventually that will be optional and you will be able to change it to something else in the settings, but I'm using it for the time being because it is the most convenient control both in terms of keeping hands free and because the code is there already from manual mode. At the moment, as soon as you press "record" the computer starts playing clicks, so you will lose your place if your hands are not on the keyboard. I'll need to add some kind of "count-in" for when something other than a pedal is being used to start recording.
In reply to I believe the layout by shoogle
I've used a few programs that start a metronome going, but don't start actually recording until you hit the first note...
In reply to I've used a few programs that by Isaac Weiss
What do those programs do when you stop playing notes? Do they stop recording or do they add rests?
In reply to What do those programs do by shoogle
They keep going until you press the stop button—after all, you may very well wish to record a certain duration of rest.
In reply to They keep going until you by Isaac Weiss
Regarding the different layout functions: should I file that in the issue tracker?
In reply to Regarding the different by Isaac Weiss
Well, at any rate, I have: #114361: Note input calls doLayout function (relayout entire score) instead of doLayoutRange, resulting in slow response time
Regarding "Rhythm input mode", middle C will not work for all instruments, so you probably want to check which instrument you are on and change the pitch accordingly. I'm not sure it's necessary to have a percussion sound, using the current staff instrument sound might be good enough, maybe even better.
In reply to Regarding "Rhythm input by [DELETED] 5
I want to communicate the actual duration entered, not just the fact that a button was pressed. The natural way would be to play the note for its duration, but that wouldn't be helpful for very short notes, and it wouldn't be fun for very long ones. I suppose I could do it via pitch, but that might be confusing.