Пример #1
0
//     chord                             |<--fudge time-->|
// ------x-------------------------------|----------------|---------------------|------
//       |<-----------------thresh time------------------>|<--thresh ext time-->|
//
void collectChords(
            MTrack &track,
            const ReducedFraction &humanTolCoeff,
            const ReducedFraction &nonHumanTolCoeff)
      {
      auto &chords = track.chords;
      if (chords.empty())
            return;

      Q_ASSERT_X(areNotesLongEnough(chords),
                 "MChord::collectChords", "There are too short notes");

      const auto &opers = preferences.midiImportOperations.data()->trackOpers;
      const auto minAllowedDur = minAllowedDuration();

      const auto threshTime = (opers.isHumanPerformance.value())
                                    ? minAllowedDur * humanTolCoeff
                                    : minAllowedDur * nonHumanTolCoeff;
      const auto fudgeTime = threshTime / 4;
      const auto threshExtTime = threshTime / 2;

      ReducedFraction currentChordStart;
      ReducedFraction curThreshTime;
                  // if note onTime goes after max chord offTime
                  // then this is not a chord but arpeggio
      ReducedFraction maxOffTime;

      setToNegative(currentChordStart, curThreshTime, maxOffTime); // invalidate

      for (auto it = chords.begin(); it != chords.end(); ) {
            if (it->second.isInTuplet) {
                  setToNegative(currentChordStart, curThreshTime, maxOffTime);
                  ++it;
                  continue;
                  }

            const auto maxNoteOffTime = MChord::maxNoteOffTime(it->second.notes);
            if (it->first < currentChordStart + curThreshTime) {

                  // this branch should not be executed when it == chords.begin()
                  Q_ASSERT_X(it != chords.begin(),
                             "MChord: collectChords", "it == chords.begin()");

                  if (it->first <= maxOffTime - minAllowedDur) {
                                    // add current note to the previous chord
                        auto chordAddTo = std::prev(it);
                        if (it->second.voice != chordAddTo->second.voice) {
                              setToNegative(currentChordStart, curThreshTime, maxOffTime);
                              ++it;
                              continue;
                              }

                        if (!hasNotesWithEqualPitch(chordAddTo->second, it->second)) {
                              for (const auto &note: it->second.notes)
                                    chordAddTo->second.notes.push_back(note);
                              if (maxNoteOffTime > maxOffTime)
                                    maxOffTime = maxNoteOffTime;
                              }
                        if (it->first >= currentChordStart + curThreshTime - fudgeTime
                                    && curThreshTime == threshTime) {
                              curThreshTime += threshExtTime;
                              }

                        it = chords.erase(it);
                        continue;
                        }
                  }

            currentChordStart = it->first;
            maxOffTime = maxNoteOffTime;
            curThreshTime = threshTime;
            ++it;
            }

      Q_ASSERT_X(areOnTimeValuesDifferent(chords),
                 "MChord: collectChords",
                 "onTime values of chords are equal but should be different");
      }
Пример #2
0
void collectChords(std::multimap<int, MTrack> &tracks)
      {
      for (auto &track: tracks) {
            auto &chords = track.second.chords;
            if (chords.empty())
                  continue;

            const auto &opers = preferences.midiImportOperations.data()->trackOpers;
            const auto minAllowedDur = minAllowedDuration();

            const auto threshTime = (opers.isHumanPerformance.value())
                                          ? minAllowedDur * 2 : minAllowedDur / 2;
            const auto fudgeTime = threshTime / 4;
            const auto threshExtTime = threshTime / 2;

            ReducedFraction currentChordStart(-1, 1);    // invalid
            ReducedFraction curThreshTime(-1, 1);
                        // if note onTime goes after max chord offTime
                        // then this is not a chord but arpeggio
            ReducedFraction maxOffTime(-1, 1);

                              // chords here should consist of a single note
                              // because notes are not united into chords yet
            Q_ASSERT_X(areSingleNoteChords(chords),
                       "MChord: collectChords", "Some chords have more than one note");

            for (auto it = chords.begin(); it != chords.end(); ) {
                  const auto &note = it->second.notes[0];

                              // short events with len < minAllowedDuration must be cleaned up
                  Q_ASSERT_X(note.offTime - it->first >= minAllowedDuration(),
                             "MChord: collectChords", "Note length is less than min allowed duration");

                  if (it->first < currentChordStart + curThreshTime) {

                                    // this branch should not be executed when it == chords.begin()
                        Q_ASSERT_X(it != chords.begin(),
                                   "MChord: collectChords", "it == chords.begin()");

                        if (it->first <= maxOffTime - minAllowedDur) {
                                          // add current note to the previous chord
                              auto prev = std::prev(it);

                              bool hasNoteWithThisPitch = false;
                              for (const auto &n: prev->second.notes) {
                                    if (n.pitch == note.pitch) {
                                          hasNoteWithThisPitch = true;
                                          break;
                                          }
                                    }
                              if (!hasNoteWithThisPitch) {
                                    prev->second.notes.push_back(note);
                                    if (note.offTime > maxOffTime)
                                          maxOffTime = note.offTime;
                                    }
                              if (it->first >= currentChordStart + curThreshTime - fudgeTime
                                          && curThreshTime == threshTime) {
                                    curThreshTime += threshExtTime;
                                    }
                              it = chords.erase(it);
                              continue;
                              }
                        }
                  currentChordStart = it->first;
                  maxOffTime = note.offTime;
                  curThreshTime = threshTime;
                  ++it;
                  }

            Q_ASSERT_X(areOnTimeValuesDifferent(chords),
                       "MChord: collectChords",
                       "onTime values of chords are equal but should be different");
            Q_ASSERT_X(areNotesLongEnough(chords),
                       "MChord::collectChords", "There are too short notes");
            }
      }