Arpeggiation sign doesn't play the top note on high BPM

• Dec 9, 2020 - 06:12
Reported version
S4 - Minor

Steps to reproduce:
1) Create new score with 348 BPM
2) Type a four-note chord (any notes)
3) Insert the arpeggiation sign
4) Playback

Expected: Play all 4 notes
Reality: Play only the lower 3 notes

I tried this many times but it still didn't work.
so I use grace notes instead of the arpeggiation sign.


Confirmed. Issue starts at slightly lower tempo, like 295. If playing in a loop at 395-396 it looses the top note on every 2nd run, at 294 at every 3rd. 397-398 works again, after 399 it fails always

Attachment Size
arpeggio.mscz 3.46 KB

I think the speed of the arpeggio is hard coded and there literally isn't time to play all four notes at that tempo. Notice it works if you make the chord a whole note, for instance. Probably if we automatically scaled the speed to be faster if the note length isn't long enough. But meanwhile, you can just do that yourself with the "stretch" setting in the Inspector - a value of 0.5 should work here (meaning the note values are half as long).

But I would note a human player would struggle with cases like this just as surely!

Stretch on arpeggios does affect the speed the arpeggio is played. When I set it low, like .2 it does play all of the notes. I didn't check to see what the max is for the setting.

Here's the code:

void renderArpeggio(Chord *chord, QList<NoteEventList> & ell)
      int notes = int(chord->notes().size());
      int l = 64;
      while (l && (l * notes > chord->upNote()->playTicks()))
            l = 2*l / 3;
      int start, end, step;
      bool up = chord->arpeggio()->arpeggioType() != ArpeggioType::DOWN && chord->arpeggio()->arpeggioType() != ArpeggioType::DOWN_STRAIGHT;
      if (up) {
            start = 0;
            end   = notes;
            step  = 1;
      else {
            start = notes - 1;
            end   = -1;
            step  = -1;
      int j = 0;
      for (int i = start; i != end; i += step) {
            NoteEventList* events = &(ell)[i];
            auto tempoRatio = chord->score()->tempomap()->tempo(chord->tick().ticks()) / Score::defaultTempo();
            int ot = (l * j * 1000) / chord->upNote()->playTicks() *
               tempoRatio * chord->arpeggio()->Stretch();
            events->append(NoteEvent(0, ot, 1000 - ot));

From the results, the length of each note in the arpeggio is shortened, not the entire chord duration. You can see better how this works by putting it on a whole note at 80 bpm and adjust the stretch on the arpeggio. I suspect there will be a stretch that will make the 4th note of that chord not play.