backport patch from experimental to fix note display during playback 2.1.0+dfsg3-3
authormirabilos <mirabilos@evolvis.org>
Sat, 17 Mar 2018 21:55:40 +0000 (22:55 +0100)
committermirabilos <mirabilos@evolvis.org>
Sat, 17 Mar 2018 21:55:40 +0000 (22:55 +0100)
debian/changelog
debian/patches/09-fix-tracking-colliding-notes.patch [new file with mode: 0644]
debian/patches/series

index ebd8558..62317fd 100644 (file)
@@ -1,3 +1,9 @@
+musescore (2.1.0+dfsg3-3) unstable; urgency=medium
+
+  * Add patch to correct visual note tracking during playback
+
+ -- Thorsten Glaser <tg@mirbsd.de>  Sat, 17 Mar 2018 22:55:13 +0100
+
 musescore (2.1.0+dfsg3-2) unstable; urgency=low
 
   * Fix copyright file for fonts, latest licences from upstream
diff --git a/debian/patches/09-fix-tracking-colliding-notes.patch b/debian/patches/09-fix-tracking-colliding-notes.patch
new file mode 100644 (file)
index 0000000..282b417
--- /dev/null
@@ -0,0 +1,151 @@
+Description: Fix visual tracking of colliding notes
+Author: mirabilos <m@mirbsd.org>
+Forwarded: https://github.com/musescore/MuseScore/pull/3551
+Bug: https://musescore.org/en/node/270408
+
+--- a/libmscore/rendermidi.cpp
++++ b/libmscore/rendermidi.cpp
+@@ -166,7 +166,7 @@ static void playNote(EventMap* events, c
+       NPlayEvent ev(ME_NOTEON, channel, pitch, velo);
+       ev.setOriginatingStaff(staffIdx);
+       ev.setTuning(note->tuning());
+-      ev.setNote(note);
++      ev.notes.push_back(note);
+       events->insert(std::pair<int, NPlayEvent>(onTime, ev));
+       ev.setVelo(0);
+       events->insert(std::pair<int, NPlayEvent>(offTime, ev));
+--- a/mscore/seq.cpp
++++ b/mscore/seq.cpp
+@@ -498,9 +498,9 @@ void Seq::playEvent(const NPlayEvent& ev
+       int type = event.type();
+       if (type == ME_NOTEON) {
+             bool mute;
+-            const Note* note = event.note();
+-            if (note) {
++            if (!event.notes.empty()) {
++                  const Note* note = event.notes[0];
+                   Instrument* instr = note->staff()->part()->instrument(note->chord()->tick());
+                   const Channel* a = instr->channel(note->subchannel());
+                   mute = a->mute || a->soloMute;
+@@ -1470,20 +1470,18 @@ void Seq::heartBeatTimeout()
+                         break;
+             const NPlayEvent& n = guiPos->second;
+             if (n.type() == ME_NOTEON) {
+-                  const Note* note1 = n.note();
+-                  if (n.velo()) {
++                  for (auto it = n.notes.cbegin(); it != n.notes.cend(); ++it) {
++                        const Note* note1 = *it;
+                         while (note1) {
+-                              note1->setMark(true);
+-                              markedNotes.append(note1);
+-                              r |= note1->canvasBoundingRect();
+-                              note1 = note1->tieFor() ? note1->tieFor()->endNote() : 0;
+-                              }
+-                        }
+-                  else {
+-                        while (note1) {
+-                              note1->setMark(false);
++                              if (n.velo()) {
++                                    note1->setMark(true);
++                                    markedNotes.append(note1);
++                                    }
++                              else {
++                                    note1->setMark(false);
++                                    markedNotes.removeOne(note1);
++                                    }
+                               r |= note1->canvasBoundingRect();
+-                              markedNotes.removeOne(note1);
+                               note1 = note1->tieFor() ? note1->tieFor()->endNote() : 0;
+                               }
+                         }
+--- a/synthesizer/event.cpp
++++ b/synthesizer/event.cpp
+@@ -377,31 +377,44 @@ void EventList::insert(const Event& e)
+ void EventMap::fixupMIDI()
+       {
+-      unsigned short nowPlaying[_highestChannel + 1][128 /* notes */];
+-      int originatingTrack[_highestChannel + 1][128 /* notes */];
+-      auto it = begin();
++      /* track info for each of the 128 possible MIDI notes */
++      struct channelInfo {
++            /* which event the first ME_NOTEON came from */
++            NPlayEvent *event[128];
++            /* how often is the note on right now? */
++            unsigned short nowPlaying[128];
++            };
+-      memset(nowPlaying, 0, (_highestChannel + 1) * 128 * sizeof(unsigned short));
++      /* track info for each channel (on the heap, 0-initialised) */
++      struct channelInfo *info = (struct channelInfo *)calloc(_highestChannel + 1, sizeof(struct channelInfo));
++      auto it = begin();
+       while (it != end()) {
+             bool discard = false;
+             /* ME_NOTEOFF is never emitted, no need to check for it */
+             if (it->second.type() == ME_NOTEON) {
+-                  unsigned short np = nowPlaying[it->second.channel()][it->second.pitch()];
++                  unsigned short np = info[it->second.channel()].nowPlaying[it->second.pitch()];
+                   if (it->second.velo() == 0) {
+                         /* already off or still playing? */
+                         if (np == 0 || --np > 0)
+                               discard = true;
+-                        else
++                        else {
+                               /* hoist NOTEOFF to same track as NOTEON */
+-                              it->second.setOriginatingStaff(originatingTrack[it->second.channel()][it->second.pitch()]);
++                              it->second.setOriginatingStaff(info[it->second.channel()].event[it->second.pitch()]->getOriginatingStaff());
++                              /* copy linked Notes */
++                              it->second.notes = info[it->second.channel()].event[it->second.pitch()]->notes;
++                              }
++                        }
++                  else if (++np > 1) {
++                        /* already playing */
++                        discard = true;
++                        /* carry over the corresponding score notes */
++                        info[it->second.channel()].event[it->second.pitch()]->notes.insert(info[it->second.channel()].event[it->second.pitch()]->notes.end(), it->second.notes.begin(), it->second.notes.end());
+                         }
+-                  else if (++np > 1)
+-                        discard = true; /* already playing */
+                   else
+-                        originatingTrack[it->second.channel()][it->second.pitch()] = it->second.getOriginatingStaff();
+-                  nowPlaying[it->second.channel()][it->second.pitch()] = np;
++                        info[it->second.channel()].event[it->second.pitch()] = &(it->second);
++                  info[it->second.channel()].nowPlaying[it->second.pitch()] = np;
+                   }
+             if (discard)
+@@ -409,6 +422,8 @@ void EventMap::fixupMIDI()
+             else
+                   ++it;
+             }
++
++            free((void *)info);
+       }
+ }
+--- a/synthesizer/event.h
++++ b/synthesizer/event.h
+@@ -234,7 +234,7 @@ class PlayEvent : public MidiCoreEvent {
+ //---------------------------------------------------------
+ class NPlayEvent : public PlayEvent {
+-      const Note* _note = 0;
++      std::vector<const Note*> _notes;
+       int _origin = -1;
+    public:
+@@ -243,8 +243,9 @@ class NPlayEvent : public PlayEvent {
+          : PlayEvent(t, c, a, b) {}
+       NPlayEvent(const MidiCoreEvent& e) : PlayEvent(e) {}
+       NPlayEvent(BeatType beatType);
+-      const Note* note() const       { return _note; }
+-      void setNote(const Note* v)    { _note = v; }
++
++      std::vector<const Note*> notes;
++
+       int getOriginatingStaff() const { return _origin; }
+       void setOriginatingStaff(int i) { _origin = i; }
+       };
index e9720fa..2406fcb 100644 (file)
@@ -8,3 +8,4 @@ backport-c-fix.patch
 05-desktop-keywords.patch
 06-relative-paths-to-scores.patch
 08-fix-midi-export-collisions.patch
+09-fix-tracking-colliding-notes.patch