void collectChords(std::multimap<int, MTrack> &tracks) { for (auto &track: tracks) { auto &chords = track.second.chords; if (chords.empty()) continue; const ReducedFraction threshTime = minAllowedDuration() / 2; const ReducedFraction fudgeTime = threshTime / 4; const ReducedFraction 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 ¬e = 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) { // add current note to the previous chord auto prev = std::prev(it); prev->second.notes.push_back(note); if (it->first >= currentChordStart + curThreshTime - fudgeTime && curThreshTime == threshTime) { curThreshTime += threshExtTime; } if (note.offTime > maxOffTime) maxOffTime = note.offTime; 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"); } }
ReducedFraction maxNoteOffTime(const QList<MidiNote> ¬es) { ReducedFraction maxOffTime(0, 1); for (const auto ¬e: notes) { if (note.offTime > maxOffTime) maxOffTime = note.offTime; } return maxOffTime; }
ReducedFraction findSumLengthOfRests( const TupletInfo &tupletInfo, const ReducedFraction &startBarTick) { auto beg = tupletInfo.onTime; const auto tupletEndTime = tupletInfo.onTime + tupletInfo.len; const auto tupletNoteLen = tupletInfo.len / tupletInfo.tupletNumber; ReducedFraction sumLen = {0, 1}; const auto &opers = midiImportOperations.data()->trackOpers; const int currentTrack = midiImportOperations.currentTrack(); for (const auto &chord: tupletInfo.chords) { const auto staccatoIt = (opers.simplifyDurations.value(currentTrack)) ? tupletInfo.staccatoChords.find(chord.first) : tupletInfo.staccatoChords.end(); const MidiChord &midiChord = chord.second->second; const auto &chordOnTime = (chord.second->first < startBarTick) ? startBarTick : Quantize::findQuantizedTupletChordOnTime(*chord.second, tupletInfo.len, tupletLimits(tupletInfo.tupletNumber).ratio, startBarTick); if (beg < chordOnTime) sumLen += (chordOnTime - beg); ReducedFraction maxOffTime(0, 1); for (int i = 0; i != midiChord.notes.size(); ++i) { auto noteOffTime = midiChord.notes[i].offTime; if (staccatoIt != tupletInfo.staccatoChords.end() && i == staccatoIt->second) noteOffTime = chordOnTime + tupletNoteLen; if (noteOffTime > maxOffTime) maxOffTime = noteOffTime; } beg = Quantize::findQuantizedTupletNoteOffTime(chord.first, maxOffTime, tupletInfo.len, tupletLimits(tupletInfo.tupletNumber).ratio, startBarTick).first; if (beg >= tupletEndTime) break; } if (beg < tupletEndTime) sumLen += (tupletEndTime - beg); return sumLen; }
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 ¬e = 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"); } }