Skip to content

Commit

Permalink
Merge pull request #26021 from alexpavlov96/guitarbend_import_fix_qua…
Browse files Browse the repository at this point in the history
…rter
  • Loading branch information
alexpavlov96 authored Jan 8, 2025
2 parents d1860d2 + a92c81c commit 10df670
Show file tree
Hide file tree
Showing 8 changed files with 945 additions and 368 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -34,15 +34,16 @@ namespace mu::iex::guitarpro {
constexpr int BEND_DIVISIONS = 60;

static void fillChordDurationsFromBendDiagram(BendDataContext& bendDataCtx, const BendDataCollector::ImportedBendInfo& importedInfo);
static void fillBendDataForNote(BendDataContext& bendDataCtx, const BendDataCollector::ImportedBendInfo& importedInfo);
static void fillBendDataForNote(BendDataContext& bendDataCtx, const BendDataCollector::ImportedBendInfo& importedInfo,
int noteIndexInChord);
static std::vector<BendDataCollector::BendSegment> bendSegmentsFromPitchValues(const PitchValues& pitchValues, bool noteTiedBack);
static bool isSlightBend(const BendDataCollector::ImportedBendInfo& importedInfo);
static BendDataCollector::ImportedBendInfo fillBendInfo(const Note* note, const PitchValues& pitchValues);

void BendDataCollector::storeBendData(mu::engraving::Note* note, const mu::engraving::PitchValues& pitchValues)
void BendDataCollector::storeBendData(const mu::engraving::Note* note, const mu::engraving::PitchValues& pitchValues)
{
if (!pitchValues.empty()) {
m_bendInfoForNote[note->track()][note->tick().ticks()][note->pitch()] = fillBendInfo(note, pitchValues);
m_bendInfoForNote[note->track()][note->tick().ticks()][note] = fillBendInfo(note, pitchValues);
}
}

Expand All @@ -61,8 +62,9 @@ BendDataContext BendDataCollector::collectBendDataContext()

for (const auto& [track, trackInfo] : m_bendInfoForNote) {
for (const auto& [tick, tickInfo] : trackInfo) {
for (const auto& [pitch, importedBendInfo] : tickInfo) {
fillBendDataForNote(bendDataCtx, importedBendInfo);
for (const auto& [note, importedBendInfo] : tickInfo) {
int idx = muse::indexOf(note->chord()->notes(), note);
fillBendDataForNote(bendDataCtx, importedBendInfo, idx);
}
}
}
Expand Down Expand Up @@ -95,7 +97,8 @@ std::vector<BendDataCollector::BendSegment> bendSegmentsFromPitchValues(const Pi
if (pitchValues.front().pitch != 0 && !noteTiedBack) {
BendDataCollector::BendSegment seg;
seg.startTime = seg.endTime = 0;
seg.pitchDiff = pitchValues.front().pitch;
seg.startPitch = 0;
seg.endPitch = pitchValues.front().pitch;

bendSegments.push_back(seg);
}
Expand All @@ -106,7 +109,8 @@ std::vector<BendDataCollector::BendSegment> bendSegmentsFromPitchValues(const Pi
if (!bendSegments.empty()) {
BendDataCollector::BendSegment& lastSeg = bendSegments.back();
lastSeg.endTime = pitchValues[i + 1].time;
lastSeg.pitchDiff = pitchValues[i + 1].pitch - pitchValues[i].pitch;
lastSeg.startPitch = pitchValues[i].pitch;
lastSeg.endPitch = pitchValues[i + 1].pitch;
}

continue;
Expand All @@ -116,7 +120,8 @@ std::vector<BendDataCollector::BendSegment> bendSegmentsFromPitchValues(const Pi
BendDataCollector::BendSegment seg;
seg.startTime = pitchValues[i].time;
seg.endTime = pitchValues[i + 1].time;
seg.pitchDiff = pitchValues[i + 1].pitch - pitchValues[i].pitch;
seg.startPitch = pitchValues[i].pitch;
seg.endPitch = pitchValues[i + 1].pitch;
bendSegments.push_back(seg);
} else {
if (previousPitchDiff != PitchDiff::SAME || bendSegments.empty()) {
Expand All @@ -130,7 +135,8 @@ std::vector<BendDataCollector::BendSegment> bendSegmentsFromPitchValues(const Pi
lastSeg.endTime = pitchValues[i + 1].time;
}

bendSegments.back().pitchDiff = pitchValues[i + 1].pitch - pitchValues[i].pitch;
bendSegments.back().startPitch = pitchValues[i].pitch;
bendSegments.back().endPitch = pitchValues[i + 1].pitch;
}

previousPitchDiff = currentPitchDiff;
Expand All @@ -146,7 +152,7 @@ BendDataCollector::ImportedBendInfo fillBendInfo(const Note* note, const PitchVa
info.note = note;

for (const auto& bs : info.segments) {
if (bs.pitchDiff != 0 && bs.startTime != bs.endTime) {
if (bs.pitchDiff() != 0 && bs.startTime != bs.endTime) {
info.pitchChangesAmount++;
}
}
Expand All @@ -161,15 +167,15 @@ static bool isSlightBend(const BendDataCollector::ImportedBendInfo& importedInfo
}

for (const auto& seg : importedInfo.segments) {
if (seg.pitchDiff == 25) {
if (seg.pitchDiff() == 25) {
return true;
}
}

return false;
}

void fillSlightBendData(BendDataContext& bendDataCtx, const BendDataCollector::ImportedBendInfo& importedInfo)
void fillSlightBendData(BendDataContext& bendDataCtx, const BendDataCollector::ImportedBendInfo& importedInfo, int noteIndexInChord)
{
const Note* note = importedInfo.note;
const Chord* chord = note->chord();
Expand All @@ -195,7 +201,7 @@ void fillSlightBendData(BendDataContext& bendDataCtx, const BendDataCollector::I
slightBendNoteData.endFactor = (double)(firstSeg.endTime + 1) / BEND_DIVISIONS;
slightBendNoteData.type = GuitarBendType::SLIGHT_BEND;

slightBendChordData.noteDataByPitch[note->pitch()] = std::move(slightBendNoteData);
slightBendChordData.noteDataByIdx[noteIndexInChord] = std::move(slightBendNoteData);
}

static bool isFirstPrebend(const BendDataCollector::ImportedBendInfo& importedInfo)
Expand All @@ -204,7 +210,7 @@ static bool isFirstPrebend(const BendDataCollector::ImportedBendInfo& importedIn
return firstSeg.startTime == firstSeg.endTime;
}

static void fillPrebendData(BendDataContext& bendDataCtx, const BendDataCollector::ImportedBendInfo& importedInfo)
static void fillPrebendData(BendDataContext& bendDataCtx, const BendDataCollector::ImportedBendInfo& importedInfo, int noteIndexInChord)
{
const Note* note = importedInfo.note;
Fraction tick = note->tick();
Expand All @@ -215,13 +221,13 @@ static void fillPrebendData(BendDataContext& bendDataCtx, const BendDataCollecto

BendDataContext::BendNoteData prebendNoteData;
prebendNoteData.type = GuitarBendType::PRE_BEND;
prebendNoteData.quarterTones = firstSeg.pitchDiff / 25;
prebendNoteData.quarterTones = firstSeg.endPitch / 25;

prebendChordData.noteDataByPitch[note->pitch()] = std::move(prebendNoteData);
prebendChordData.noteDataByIdx[noteIndexInChord] = std::move(prebendNoteData);
}

static void fillNormalBendData(BendDataContext& bendDataCtx, const BendDataCollector::ImportedBendInfo& importedInfo,
size_t startIndex)
size_t startIndex, int noteIndexInChord)
{
if (startIndex >= importedInfo.segments.size()) {
return;
Expand Down Expand Up @@ -260,8 +266,8 @@ static void fillNormalBendData(BendDataContext& bendDataCtx, const BendDataColle
bendChordData.startTick = currentTick;
BendDataContext::BendNoteData bendNoteData;
bendNoteData.type = GuitarBendType::BEND;
bendNoteData.quarterTones = seg.pitchDiff / 25;
bendChordData.noteDataByPitch[note->pitch()] = std::move(bendNoteData);
bendNoteData.quarterTones = seg.endPitch / 25;
bendChordData.noteDataByIdx[noteIndexInChord] = std::move(bendNoteData);

currentTick += tickDuration;
currentIndex++;
Expand Down Expand Up @@ -356,15 +362,15 @@ static void fillChordDurationsFromBendDiagram(BendDataContext& bendDataCtx, cons
if (isFirstPrebend(importedInfo)) {
addFullChordDuration(bendDataCtx, importedInfo);
startIndex = 1;
if (importedInfo.segments.size() > 1 && importedInfo.segments[1].pitchDiff == 0) {
if (importedInfo.segments.size() > 1 && importedInfo.segments[1].pitchDiff() == 0) {
startIndex = 2;
}
}

splitBendChordDurations(bendDataCtx, importedInfo, startIndex);
}

static void fillBendDataForNote(BendDataContext& bendDataCtx, const BendDataCollector::ImportedBendInfo& importedInfo)
static void fillBendDataForNote(BendDataContext& bendDataCtx, const BendDataCollector::ImportedBendInfo& importedInfo, int noteIndexInChord)
{
const Note* note = importedInfo.note;
IF_ASSERT_FAILED(note) {
Expand All @@ -379,20 +385,20 @@ static void fillBendDataForNote(BendDataContext& bendDataCtx, const BendDataColl
}

if (isSlightBend(importedInfo)) {
fillSlightBendData(bendDataCtx, importedInfo);
fillSlightBendData(bendDataCtx, importedInfo, noteIndexInChord);
return;
}

size_t startIndex = 0;

if (isFirstPrebend(importedInfo)) {
fillPrebendData(bendDataCtx, importedInfo);
fillPrebendData(bendDataCtx, importedInfo, noteIndexInChord);
startIndex = 1;
if (importedInfo.segments.size() > 1 && importedInfo.segments[1].pitchDiff == 0) {
if (importedInfo.segments.size() > 1 && importedInfo.segments[1].pitchDiff() == 0) {
startIndex = 2;
}
}

fillNormalBendData(bendDataCtx, importedInfo, startIndex);
fillNormalBendData(bendDataCtx, importedInfo, startIndex, noteIndexInChord);
}
} // namespace mu::iex::guitarpro
Original file line number Diff line number Diff line change
Expand Up @@ -38,14 +38,17 @@ class BendDataCollector
{
public:

void storeBendData(mu::engraving::Note* note, const mu::engraving::PitchValues& pitchValues);
void storeBendData(const mu::engraving::Note* note, const mu::engraving::PitchValues& pitchValues);
BendDataContext collectBendDataContext();

struct BendSegment {
int startTime = -1;
int middleTime = -1;
int endTime = -1;
int pitchDiff = -1;
int startPitch = -1;
int endPitch = -1;

int pitchDiff() const { return endPitch - startPitch; }
};

struct ImportedBendInfo {
Expand All @@ -55,6 +58,7 @@ class BendDataCollector
};

private:
std::unordered_map<mu::engraving::track_idx_t, std::map<int, std::map<int /*pitch*/, ImportedBendInfo> > > m_bendInfoForNote;
std::unordered_map<mu::engraving::track_idx_t,
std::map<int, std::unordered_map<const mu::engraving::Note*, ImportedBendInfo> > > m_bendInfoForNote;
};
} // mu::iex::guitarpro
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ struct BendDataContext {

struct BendChordData {
mu::engraving::Fraction startTick;
std::map<int /* pitch */, BendNoteData> noteDataByPitch;
std::map<int /* idx in chord */, BendNoteData> noteDataByIdx;
};

std::unordered_map<mu::engraving::track_idx_t, std::map<int, std::vector<mu::engraving::Fraction> > > bendChordDurations;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -154,18 +154,19 @@ static void createGuitarBends(const BendDataContext& bendDataCtx, mu::engraving:
std::sort(endChordNotes.begin(), endChordNotes.end(), [](Note* l, Note* r) {
return l->pitch() < r->pitch();
});

auto bendInfoIt = bendChordData.noteDataByPitch.begin();
for (size_t noteIndex = 0; noteIndex < endChordNotes.size(); noteIndex++) {
Note* startNote = startChordNotes[noteIndex];
Note* note = endChordNotes[noteIndex];

if (bendChordData.noteDataByPitch.size() <= noteIndex) {
LOGE() << "bend import error : bend data filled incorrectly, not all bends will be created";
return;
if (bendChordData.noteDataByIdx.find(noteIndex) == bendChordData.noteDataByIdx.end()) {
Tie* tie = Factory::createTie(score->dummy());
startNote->add(tie);
tie->setEndNote(note);
note->setTieBack(tie);
continue;
}

const BendDataContext::BendNoteData& bendNoteData = bendInfoIt->second;
Note* startNote = startChordNotes[noteIndex];
const auto& bendNoteData = bendChordData.noteDataByIdx.at(noteIndex);
int pitch = bendNoteData.quarterTones / 2;

if (bendNoteData.type == GuitarBendType::PRE_BEND) {
Expand Down Expand Up @@ -198,7 +199,7 @@ static void createGuitarBends(const BendDataContext& bendDataCtx, mu::engraving:
}

QuarterOffset quarterOff = bendNoteData.quarterTones % 2 ? QuarterOffset::QUARTER_SHARP : QuarterOffset::NONE;
bend->setEndNotePitch(startNote->pitch() + pitch, quarterOff);
bend->setEndNotePitch(bend->startNoteOfChain()->pitch() + pitch, quarterOff);
bend->setStartTimeFactor(bendNoteData.startFactor);
bend->setEndTimeFactor(bendNoteData.endFactor);
}
Expand All @@ -224,8 +225,6 @@ static void createGuitarBends(const BendDataContext& bendDataCtx, mu::engraving:

tiedNote = tie->endNote();
}

bendInfoIt = std::next(bendInfoIt);
}
}
} // namespace mu::iex::guitarpro
Loading

0 comments on commit 10df670

Please sign in to comment.