From 15676130a32ac68faad9eaeaec2f01658a16f1f7 Mon Sep 17 00:00:00 2001 From: Alexander Pavlov Date: Fri, 13 Dec 2024 22:00:29 +0200 Subject: [PATCH] guitar bend import: part 1 --- .../preferences/noteinputpreferencesmodel.h | 1 + .../compat/midi/compatmidirenderinternal.cpp | 7 +- src/engraving/dom/measure.cpp | 4 +- src/engraving/dom/measure.h | 4 +- src/engraving/iengravingconfiguration.h | 3 +- .../internal/engravingconfiguration.cpp | 11 +- .../internal/engravingconfiguration.h | 4 +- src/engraving/rendering/score/chordlayout.cpp | 20 - src/engraving/rendering/score/chordlayout.h | 1 - .../rendering/score/systemlayout.cpp | 1 - .../tests/mocks/engravingconfigurationmock.h | 3 +- src/importexport/guitarpro/CMakeLists.txt | 8 + .../guitarpro/internal/gtp/gpconverter.cpp | 21 +- .../guitarpro/internal/gtp/gpconverter.h | 4 +- .../guitarbendimport/benddatacollector.cpp | 296 +++++++++++++++ .../guitarbendimport/benddatacollector.h | 61 +++ .../guitarbendimport/benddatacontext.h | 45 +++ .../guitarbendimport/benddataprocessor.cpp | 195 ++++++++++ .../guitarbendimport/benddataprocessor.h | 42 +++ .../guitarbendimport/guitarbendimporter.cpp | 46 +++ .../guitarbendimport/guitarbendimporter.h | 51 +++ .../guitarpro/internal/importgtp-gp4.cpp | 10 +- .../guitarpro/internal/importgtp-gp5.cpp | 12 +- .../guitarpro/internal/importgtp.cpp | 18 +- .../guitarpro/internal/importgtp.h | 4 +- .../guitarpro/tests/CMakeLists.txt | 1 + .../guitarbendimporter_data/prebend-gp.mscx | 346 ++++++++++++++++++ .../guitarbendimporter_data/prebend-gp5.mscx | 339 +++++++++++++++++ .../tests/guitarbendimporter_data/prebend.gp | Bin 0 -> 8677 bytes .../tests/guitarbendimporter_data/prebend.gp5 | Bin 0 -> 1537 bytes .../slight_bend-gp.mscx | 262 +++++++++++++ .../slight_bend-gp5.mscx | 255 +++++++++++++ .../guitarbendimporter_data/slight_bend.gp | Bin 0 -> 8680 bytes .../guitarbendimporter_data/slight_bend.gp5 | Bin 0 -> 1555 bytes .../guitarbendimporter_data/tied_bend-gp.mscx | 227 ++++++++++++ .../tied_bend-gp5.mscx | 220 +++++++++++ .../guitarbendimporter_data/tied_bend.gp | Bin 0 -> 8714 bytes .../guitarbendimporter_data/tied_bend.gp5 | Bin 0 -> 1517 bytes .../tests/guitarbendimporter_tests.cpp | 109 ++++++ 39 files changed, 2558 insertions(+), 73 deletions(-) create mode 100644 src/importexport/guitarpro/internal/guitarbendimport/benddatacollector.cpp create mode 100644 src/importexport/guitarpro/internal/guitarbendimport/benddatacollector.h create mode 100644 src/importexport/guitarpro/internal/guitarbendimport/benddatacontext.h create mode 100644 src/importexport/guitarpro/internal/guitarbendimport/benddataprocessor.cpp create mode 100644 src/importexport/guitarpro/internal/guitarbendimport/benddataprocessor.h create mode 100644 src/importexport/guitarpro/internal/guitarbendimport/guitarbendimporter.cpp create mode 100644 src/importexport/guitarpro/internal/guitarbendimport/guitarbendimporter.h create mode 100644 src/importexport/guitarpro/tests/guitarbendimporter_data/prebend-gp.mscx create mode 100644 src/importexport/guitarpro/tests/guitarbendimporter_data/prebend-gp5.mscx create mode 100644 src/importexport/guitarpro/tests/guitarbendimporter_data/prebend.gp create mode 100644 src/importexport/guitarpro/tests/guitarbendimporter_data/prebend.gp5 create mode 100644 src/importexport/guitarpro/tests/guitarbendimporter_data/slight_bend-gp.mscx create mode 100644 src/importexport/guitarpro/tests/guitarbendimporter_data/slight_bend-gp5.mscx create mode 100644 src/importexport/guitarpro/tests/guitarbendimporter_data/slight_bend.gp create mode 100644 src/importexport/guitarpro/tests/guitarbendimporter_data/slight_bend.gp5 create mode 100644 src/importexport/guitarpro/tests/guitarbendimporter_data/tied_bend-gp.mscx create mode 100644 src/importexport/guitarpro/tests/guitarbendimporter_data/tied_bend-gp5.mscx create mode 100644 src/importexport/guitarpro/tests/guitarbendimporter_data/tied_bend.gp create mode 100644 src/importexport/guitarpro/tests/guitarbendimporter_data/tied_bend.gp5 create mode 100644 src/importexport/guitarpro/tests/guitarbendimporter_tests.cpp diff --git a/src/appshell/view/preferences/noteinputpreferencesmodel.h b/src/appshell/view/preferences/noteinputpreferencesmodel.h index ae578f2b575c5..b7f67b145afc6 100644 --- a/src/appshell/view/preferences/noteinputpreferencesmodel.h +++ b/src/appshell/view/preferences/noteinputpreferencesmodel.h @@ -24,6 +24,7 @@ #include +#include "async/asyncable.h" #include "modularity/ioc.h" #include "engraving/iengravingconfiguration.h" #include "shortcuts/ishortcutsconfiguration.h" diff --git a/src/engraving/compat/midi/compatmidirenderinternal.cpp b/src/engraving/compat/midi/compatmidirenderinternal.cpp index 296008e05e05a..a6a16dd28cc44 100644 --- a/src/engraving/compat/midi/compatmidirenderinternal.cpp +++ b/src/engraving/compat/midi/compatmidirenderinternal.cpp @@ -766,12 +766,7 @@ static void collectNote(EventsHolder& events, const Note* note, const CollectNot } // Bends - if (note->configuration()->useStretchedBends()) { - if (const StretchedBend* stretchedBend = note->stretchedBend()) { - collectBend(stretchedBend->pitchValues(), stretchedBend->staffIdx(), noteChannel, tick1, tick1 + getPlayTicksForBend( - note).ticks(), pitchWheelRenderer, noteEffect); - } - } else if (bendFor) { + if (bendFor) { collectGuitarBend(note, noteChannel, tick1, noteParams.graceOffsetOn, noteParams.previousChordTicks, pitchWheelRenderer, noteEffect); } else { diff --git a/src/engraving/dom/measure.cpp b/src/engraving/dom/measure.cpp index ecd46e2bbbc9a..fa549b0daf09c 100644 --- a/src/engraving/dom/measure.cpp +++ b/src/engraving/dom/measure.cpp @@ -585,7 +585,7 @@ bool Measure::showsMeasureNumber() /// Search for chord at position \a tick in \a track //--------------------------------------------------------- -Chord* Measure::findChord(Fraction t, track_idx_t track) +Chord* Measure::findChord(Fraction t, track_idx_t track) const { t -= tick(); for (Segment* seg = last(); seg; seg = seg->prev()) { @@ -607,7 +607,7 @@ Chord* Measure::findChord(Fraction t, track_idx_t track) /// Search for chord or rest at position \a tick at \a staff in \a voice. //--------------------------------------------------------- -ChordRest* Measure::findChordRest(Fraction t, track_idx_t track) +ChordRest* Measure::findChordRest(Fraction t, track_idx_t track) const { t -= tick(); for (const Segment& seg : m_segments) { diff --git a/src/engraving/dom/measure.h b/src/engraving/dom/measure.h index 30e111fc71d9b..fea34b1801620 100644 --- a/src/engraving/dom/measure.h +++ b/src/engraving/dom/measure.h @@ -221,8 +221,8 @@ class Measure final : public MeasureBase bool showsMeasureNumber(); bool showsMeasureNumberInAutoMode(); - Chord* findChord(Fraction tick, track_idx_t track); - ChordRest* findChordRest(Fraction tick, track_idx_t track); + Chord* findChord(Fraction tick, track_idx_t track) const; + ChordRest* findChordRest(Fraction tick, track_idx_t track) const; Fraction snap(const Fraction& tick, const PointF p) const; Fraction snapNote(const Fraction& tick, const PointF p, int staff) const; diff --git a/src/engraving/iengravingconfiguration.h b/src/engraving/iengravingconfiguration.h index b9d4b52a5afa5..906cbd3872189 100644 --- a/src/engraving/iengravingconfiguration.h +++ b/src/engraving/iengravingconfiguration.h @@ -124,7 +124,8 @@ class IEngravingConfiguration : MODULE_EXPORT_INTERFACE /// these configurations will be removed after solving https://github.com/musescore/MuseScore/issues/14294 virtual bool guitarProImportExperimental() const = 0; - virtual bool useStretchedBends() const = 0; + virtual bool experimentalGuitarBendImport() const = 0; + virtual void setExperimentalGuitarBendImport(bool enabled) = 0; virtual bool shouldAddParenthesisOnStandardStaff() const = 0; virtual bool negativeFretsAllowed() const = 0; virtual bool crossNoteHeadAlwaysBlack() const = 0; diff --git a/src/engraving/internal/engravingconfiguration.cpp b/src/engraving/internal/engravingconfiguration.cpp index 17b55f631de39..9eadffcbbff8e 100644 --- a/src/engraving/internal/engravingconfiguration.cpp +++ b/src/engraving/internal/engravingconfiguration.cpp @@ -132,6 +132,8 @@ void EngravingConfiguration::init() settings()->setDefaultValue(DO_NOT_SAVE_EIDS_FOR_BACK_COMPAT, Val(false)); settings()->setDescription(DO_NOT_SAVE_EIDS_FOR_BACK_COMPAT, muse::trc("engraving", "Do not save EIDs")); settings()->setCanBeManuallyEdited(DO_NOT_SAVE_EIDS_FOR_BACK_COMPAT, false); + + setExperimentalGuitarBendImport(guitarProImportExperimental()); } muse::io::path_t EngravingConfiguration::appDataPath() const @@ -388,9 +390,14 @@ bool EngravingConfiguration::guitarProImportExperimental() const return guitarProConfiguration() ? guitarProConfiguration()->experimental() : false; } -bool EngravingConfiguration::useStretchedBends() const +bool EngravingConfiguration::experimentalGuitarBendImport() const { - return guitarProImportExperimental(); + return m_experimentalGuitarBendImport; +} + +void EngravingConfiguration::setExperimentalGuitarBendImport(bool enabled) +{ + m_experimentalGuitarBendImport = enabled; } bool EngravingConfiguration::shouldAddParenthesisOnStandardStaff() const diff --git a/src/engraving/internal/engravingconfiguration.h b/src/engraving/internal/engravingconfiguration.h index 5e5b7cec9e43e..e0c83e43dd502 100644 --- a/src/engraving/internal/engravingconfiguration.h +++ b/src/engraving/internal/engravingconfiguration.h @@ -106,7 +106,8 @@ class EngravingConfiguration : public IEngravingConfiguration, public muse::Inje void setDoNotSaveEIDsForBackCompat(bool doNotSave) override; bool guitarProImportExperimental() const override; - bool useStretchedBends() const override; + bool experimentalGuitarBendImport() const override; + void setExperimentalGuitarBendImport(bool enabled) override; bool shouldAddParenthesisOnStandardStaff() const override; bool negativeFretsAllowed() const override; bool crossNoteHeadAlwaysBlack() const override; @@ -126,6 +127,7 @@ class EngravingConfiguration : public IEngravingConfiguration, public muse::Inje muse::ValNt m_debuggingOptions; bool m_multiVoice = false; + bool m_experimentalGuitarBendImport = false; }; } diff --git a/src/engraving/rendering/score/chordlayout.cpp b/src/engraving/rendering/score/chordlayout.cpp index 354742811ea1e..b09844486f359 100644 --- a/src/engraving/rendering/score/chordlayout.cpp +++ b/src/engraving/rendering/score/chordlayout.cpp @@ -57,7 +57,6 @@ #include "dom/staff.h" #include "dom/stem.h" #include "dom/stemslash.h" -#include "dom/stretchedbend.h" #include "dom/system.h" #include "dom/tie.h" #include "dom/slur.h" @@ -3078,25 +3077,6 @@ void ChordLayout::layoutChordBaseFingering(Chord* chord, System* system, LayoutC } } -void ChordLayout::layoutStretchedBends(Chord* chord, LayoutContext& ctx) -{ - if (!chord->configuration()->useStretchedBends()) { - return; - } - - for (EngravingItem* item : chord->el()) { - if (item && item->isStretchedBend()) { - toStretchedBend(item)->adjustBendInChord(); - } - } - - for (EngravingItem* item : chord->el()) { - if (item && item->isStretchedBend()) { - TLayout::layoutStretched(toStretchedBend(item), ctx); - } - } -} - void ChordLayout::crossMeasureSetup(Chord* chord, bool on, LayoutContext& ctx) { if (!on) { diff --git a/src/engraving/rendering/score/chordlayout.h b/src/engraving/rendering/score/chordlayout.h index c48639e3a9a53..e5f2877a36ec6 100644 --- a/src/engraving/rendering/score/chordlayout.h +++ b/src/engraving/rendering/score/chordlayout.h @@ -77,7 +77,6 @@ class ChordLayout static void resolveRestVSRest(std::vector& rests, const Staff* staff, Segment* segment, LayoutContext& ctx, bool considerBeams = false); static void layoutChordBaseFingering(Chord* chord, System* system, LayoutContext& ctx); - static void layoutStretchedBends(Chord* chord, LayoutContext& ctx); static void crossMeasureSetup(Chord* chord, bool on, LayoutContext& ctx); diff --git a/src/engraving/rendering/score/systemlayout.cpp b/src/engraving/rendering/score/systemlayout.cpp index 57fe7dc9e658a..ceb1e01c8c89a 100644 --- a/src/engraving/rendering/score/systemlayout.cpp +++ b/src/engraving/rendering/score/systemlayout.cpp @@ -817,7 +817,6 @@ void SystemLayout::layoutSystemElements(System* system, LayoutContext& ctx) ChordLayout::layoutArticulations(c, ctx); ChordLayout::layoutArticulations2(c, ctx); ChordLayout::layoutChordBaseFingering(c, system, ctx); - ChordLayout::layoutStretchedBends(c, ctx); } } diff --git a/src/engraving/tests/mocks/engravingconfigurationmock.h b/src/engraving/tests/mocks/engravingconfigurationmock.h index 44a258d3e13ca..20dadeca9df98 100644 --- a/src/engraving/tests/mocks/engravingconfigurationmock.h +++ b/src/engraving/tests/mocks/engravingconfigurationmock.h @@ -89,7 +89,8 @@ class EngravingConfigurationMock : public IEngravingConfiguration MOCK_METHOD(void, setDoNotSaveEIDsForBackCompat, (bool), (override)); MOCK_METHOD(bool, guitarProImportExperimental, (), (const, override)); - MOCK_METHOD(bool, useStretchedBends, (), (const, override)); + MOCK_METHOD(bool, experimentalGuitarBendImport, (), (const, override)); + MOCK_METHOD(void, setExperimentalGuitarBendImport, (bool), (override)); MOCK_METHOD(bool, shouldAddParenthesisOnStandardStaff, (), (const, override)); MOCK_METHOD(bool, negativeFretsAllowed, (), (const, override)); MOCK_METHOD(bool, crossNoteHeadAlwaysBlack, (), (const, override)); diff --git a/src/importexport/guitarpro/CMakeLists.txt b/src/importexport/guitarpro/CMakeLists.txt index 654c46e1911e4..c4c0bb592ad18 100644 --- a/src/importexport/guitarpro/CMakeLists.txt +++ b/src/importexport/guitarpro/CMakeLists.txt @@ -42,6 +42,14 @@ set(MODULE_SRC ${CMAKE_CURRENT_LIST_DIR}/internal/utils.cpp ${CMAKE_CURRENT_LIST_DIR}/internal/utils.h + ${CMAKE_CURRENT_LIST_DIR}/internal/guitarbendimport/guitarbendimporter.cpp + ${CMAKE_CURRENT_LIST_DIR}/internal/guitarbendimport/guitarbendimporter.h + ${CMAKE_CURRENT_LIST_DIR}/internal/guitarbendimport/benddatacontext.h + ${CMAKE_CURRENT_LIST_DIR}/internal/guitarbendimport/benddatacollector.cpp + ${CMAKE_CURRENT_LIST_DIR}/internal/guitarbendimport/benddatacollector.h + ${CMAKE_CURRENT_LIST_DIR}/internal/guitarbendimport/benddataprocessor.cpp + ${CMAKE_CURRENT_LIST_DIR}/internal/guitarbendimport/benddataprocessor.h + ${CMAKE_CURRENT_LIST_DIR}/internal/gtp/gp6dombuilder.cpp ${CMAKE_CURRENT_LIST_DIR}/internal/gtp/gp6dombuilder.h ${CMAKE_CURRENT_LIST_DIR}/internal/gtp/gp7dombuilder.cpp diff --git a/src/importexport/guitarpro/internal/gtp/gpconverter.cpp b/src/importexport/guitarpro/internal/gtp/gpconverter.cpp index 5be811fef9c67..eecf740ba46ad 100644 --- a/src/importexport/guitarpro/internal/gtp/gpconverter.cpp +++ b/src/importexport/guitarpro/internal/gtp/gpconverter.cpp @@ -38,7 +38,6 @@ #include "engraving/dom/spanner.h" #include "engraving/dom/staff.h" #include "engraving/dom/stafftext.h" -#include "engraving/dom/stretchedbend.h" #include "engraving/dom/tempotext.h" #include "engraving/dom/text.h" #include "engraving/dom/tie.h" @@ -252,6 +251,10 @@ GPConverter::GPConverter(Score* score, std::unique_ptr&& gpDom, cons _drumResolver = std::make_unique(); _drumResolver->initGPDrum(); m_continiousElementsBuilder = std::make_unique(_score); + + if (engravingConfiguration()->experimentalGuitarBendImport()) { + m_guitarBendImporter = std::make_unique(_score); + } } const std::unique_ptr& GPConverter::gpDom() const @@ -344,7 +347,9 @@ void GPConverter::convert(const std::vector >& mast addTempoMap(); addInstrumentChanges(); - StretchedBend::prepareBends(m_stretchedBends); + if (engravingConfiguration()->experimentalGuitarBendImport()) { + m_guitarBendImporter->applyBendsToChords(); + } addFermatas(); addContinuousSlideHammerOn(); @@ -2071,16 +2076,8 @@ void GPConverter::addBend(const GPNote* gpnote, Note* note) return; } - if (engravingConfiguration()->guitarProImportExperimental()) { - Chord* chord = toChord(note->parent()); - StretchedBend* stretchedBend = Factory::createStretchedBend(chord); - stretchedBend->setPitchValues(pitchValues); - stretchedBend->setTrack(note->track()); - stretchedBend->setNote(note); - note->setStretchedBend(stretchedBend); - - chord->add(stretchedBend); - m_stretchedBends.push_back(stretchedBend); + if (engravingConfiguration()->experimentalGuitarBendImport()) { + m_guitarBendImporter->collectBend(note, pitchValues); } else { Bend* bend = Factory::createBend(note); bend->setPoints(pitchValues); diff --git a/src/importexport/guitarpro/internal/gtp/gpconverter.h b/src/importexport/guitarpro/internal/gtp/gpconverter.h index c76eab8fdf444..999aad5b655bb 100644 --- a/src/importexport/guitarpro/internal/gtp/gpconverter.h +++ b/src/importexport/guitarpro/internal/gtp/gpconverter.h @@ -9,6 +9,7 @@ #include "gpdrumsetresolver.h" #include "gpmastertracks.h" #include "../continiouselementsbuilder.h" +#include "../guitarbendimport/guitarbendimporter.h" #include "types/fraction.h" #include "iengravingconfiguration.h" @@ -192,8 +193,6 @@ class GPConverter : public muse::Injectable // Index is the number of sharps. Using sharp keysigs for signatures with double flats std::vector m_sharpsToFlatKeysConverter{ 0, 1, 2, 3, 4, -7, -6, -5, -4, -3, -2, -1 }; - std::vector m_stretchedBends; - static constexpr mu::engraving::voice_idx_t VOICES = 4; bool m_showCapo = true; // TODO-gp : settings @@ -205,6 +204,7 @@ class GPConverter : public muse::Injectable std::unique_ptr _drumResolver; std::unique_ptr m_continiousElementsBuilder; + std::unique_ptr m_guitarBendImporter; }; } // namespace mu::iex::guitarpro #endif // MU_IMPORTEXPORT_GPCONVERTER_H diff --git a/src/importexport/guitarpro/internal/guitarbendimport/benddatacollector.cpp b/src/importexport/guitarpro/internal/guitarbendimport/benddatacollector.cpp new file mode 100644 index 0000000000000..f4840f1cc5c53 --- /dev/null +++ b/src/importexport/guitarpro/internal/guitarbendimport/benddatacollector.cpp @@ -0,0 +1,296 @@ +/* + * SPDX-License-Identifier: GPL-3.0-only + * MuseScore-Studio-CLA-applies + * + * MuseScore Studio + * Music Composition & Notation + * + * Copyright (C) 2024 MuseScore Limited + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 3 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#include "benddatacollector.h" + +#include +#include +#include +#include + +using namespace mu::engraving; + +namespace mu::iex::guitarpro { +constexpr int BEND_DIVISIONS = 60; + +static void fillBendDataContextForNote(BendDataContext& bendDataCtx, const BendDataCollector::ImportedBendInfo& importedInfo); +static std::vector bendSegmentsFromPitchValues(const PitchValues& pitchValues, bool noteTiedBack); +BendDataCollector::ImportedBendInfo fillBendInfo(const Note* note, const PitchValues& pitchValues); + +void BendDataCollector::storeBendData(mu::engraving::Note* note, const mu::engraving::PitchValues& pitchValues) +{ + if (!pitchValues.empty()) { + m_bendInfoForNote[note->track()][note->tick().ticks()] = fillBendInfo(note, pitchValues); + } +} + +BendDataContext BendDataCollector::collectBendDataContext() +{ + BendDataContext bendDataCtx; + + for (const auto& [track, trackInfo] : m_bendInfoForNote) { + for (const auto& [tick, importedBendInfo] : trackInfo) { + fillBendDataContextForNote(bendDataCtx, importedBendInfo); + } + } + + return bendDataCtx; +} + +std::vector bendSegmentsFromPitchValues(const PitchValues& pitchValues, + bool noteTiedBack) +{ + enum PitchDiff { + NONE, + SAME, + UP, + DOWN + }; + + std::vector bendSegments; + PitchDiff currentPitchDiff; + PitchDiff previousPitchDiff = PitchDiff::NONE; + + auto pitchDiff = [](int prevPitch, int currentPitch) { + if (prevPitch == currentPitch) { + return PitchDiff::SAME; + } + + return (prevPitch < currentPitch) ? PitchDiff::UP : PitchDiff::DOWN; + }; + + if (pitchValues.front().pitch != 0 && !noteTiedBack) { + BendDataCollector::BendSegment seg; + seg.startTime = seg.endTime = 0; + seg.pitchDiff = pitchValues.front().pitch; + + bendSegments.push_back(seg); + } + + for (size_t i = 0; i < pitchValues.size() - 1; i++) { + currentPitchDiff = pitchDiff(pitchValues[i].pitch, pitchValues[i + 1].pitch); + if (currentPitchDiff == previousPitchDiff) { + if (!bendSegments.empty()) { + BendDataCollector::BendSegment& lastSeg = bendSegments.back(); + lastSeg.endTime = pitchValues[i + 1].time; + lastSeg.pitchDiff = pitchValues[i + 1].pitch - pitchValues[i].pitch; + } + + continue; + } + + if (currentPitchDiff == PitchDiff::SAME) { + BendDataCollector::BendSegment seg; + seg.startTime = pitchValues[i].time; + seg.endTime = pitchValues[i + 1].time; + seg.pitchDiff = pitchValues[i + 1].pitch - pitchValues[i].pitch; + bendSegments.push_back(seg); + } else { + if (previousPitchDiff != PitchDiff::SAME || bendSegments.empty()) { + BendDataCollector::BendSegment seg; + seg.startTime = pitchValues[i].time; + seg.endTime = pitchValues[i + 1].time; + bendSegments.push_back(seg); + } else { + BendDataCollector::BendSegment& lastSeg = bendSegments.back(); + lastSeg.middleTime = pitchValues[i].time; + lastSeg.endTime = pitchValues[i + 1].time; + } + + bendSegments.back().pitchDiff = pitchValues[i + 1].pitch - pitchValues[i].pitch; + } + + previousPitchDiff = currentPitchDiff; + } + + return bendSegments; +} + +BendDataCollector::ImportedBendInfo fillBendInfo(const Note* note, const PitchValues& pitchValues) +{ + PitchValues adaptedPitchValues; + adaptedPitchValues.reserve(pitchValues.size() + 2); + + if (pitchValues.front().time != 0) { + PitchValue firstPv = pitchValues.front(); + firstPv.time = 0; + adaptedPitchValues.push_back(firstPv); + } + + for (const auto& pv : pitchValues) { + adaptedPitchValues.push_back(pv); + } + + if (pitchValues.back().time != BEND_DIVISIONS) { + PitchValue lastPv = pitchValues.back(); + lastPv.time = BEND_DIVISIONS; + adaptedPitchValues.push_back(lastPv); + } + + BendDataCollector::ImportedBendInfo info; + info.segments = bendSegmentsFromPitchValues(adaptedPitchValues, note->tieBack()); + info.note = note; + + for (const auto& bs : info.segments) { + if (bs.pitchDiff != 0 && bs.startTime != bs.endTime) { + info.pitchChangesAmount++; + } + } + + return info; +} + +static bool isSlightBend(const BendDataCollector::ImportedBendInfo& importedInfo) +{ + if (importedInfo.pitchChangesAmount != 1 || importedInfo.note->tieFor() || importedInfo.segments.size() != 2) { + return false; + } + + for (const auto& seg : importedInfo.segments) { + if (seg.pitchDiff == 25) { + return true; + } + } + + return false; +} + +void fillSlightBendDataContext(BendDataContext& bendDataCtx, const BendDataCollector::ImportedBendInfo& importedInfo) +{ + const Note* note = importedInfo.note; + const Chord* chord = note->chord(); + Fraction tick = chord->tick(); + + std::vector bendDurations; + Fraction duration = chord->actualTicks(); + bendDurations.push_back(duration); + + bendDataCtx.bendChordDurations[note->track()][tick.ticks()] = std::move(bendDurations); + + BendDataContext::BendData slightBendData; + slightBendData.quarterTones = 1; + + const auto& firstSeg = importedInfo.segments.front(); + if (firstSeg.middleTime != -1) { + slightBendData.startFactor = (double)firstSeg.middleTime / BEND_DIVISIONS; + } + + slightBendData.endFactor = (double)(firstSeg.endTime + 1) / BEND_DIVISIONS; + slightBendData.type = GuitarBendType::SLIGHT_BEND; + slightBendData.startTick = tick; + bendDataCtx.bendDataByEndTick[note->track()][tick.ticks()] = std::move(slightBendData); +} + +static bool isFirstPrebend(const BendDataCollector::ImportedBendInfo& importedInfo) +{ + const auto& firstSeg = importedInfo.segments.front(); + return firstSeg.startTime == firstSeg.endTime; +} + +static void fillPrebendDataContext(BendDataContext& bendDataCtx, const BendDataCollector::ImportedBendInfo& importedInfo) +{ + const Note* note = importedInfo.note; + BendDataContext::BendData prebendData; + + const auto& firstSeg = importedInfo.segments.front(); + prebendData.type = GuitarBendType::PRE_BEND; + prebendData.startTick = note->tick(); + prebendData.quarterTones = firstSeg.pitchDiff / 25; + + bendDataCtx.bendDataByEndTick[note->track()][note->tick().ticks()] = std::move(prebendData); + + std::vector bendDurations; + Fraction duration = note->chord()->actualTicks(); + bendDurations.push_back(duration); + + bendDataCtx.bendChordDurations[note->track()][note->tick().ticks()] = std::move(bendDurations); +} + +static void fillNormalBendDataContext(BendDataContext& bendDataCtx, const BendDataCollector::ImportedBendInfo& importedInfo, + size_t startIndex) +{ + // TODO: fill chords durations in proportion to bend diagram + const Note* note = importedInfo.note; + BendDataContext::BendData bendData; + + if (startIndex >= importedInfo.segments.size() - 1) { + return; + } + + const auto& firstSeg = importedInfo.segments.at(startIndex); + bendData.type = GuitarBendType::BEND; + bendData.startTick = note->tick(); + bendData.quarterTones = firstSeg.pitchDiff / 25; + + bendDataCtx.bendDataByEndTick[note->track()][note->chord()->actualTicks().ticks()] = std::move(bendData); + + std::vector bendDurations; + Fraction duration = note->chord()->actualTicks(); + bendDurations.push_back(duration); + + // currently not adding new chords - so checking if END chord for new bend already exists + // it's a test code + { + const Score* score = note->score(); + Fraction endChordTick = note->tick() + duration; + const Measure* endChordMeasure = score->tick2measure(endChordTick); + + if (endChordMeasure) { + const Chord* endChord = endChordMeasure->findChord(endChordTick, note->track()); + if (endChord) { + bendDurations.push_back(endChord->actualTicks()); + } + } + } + + bendDataCtx.bendChordDurations[note->track()][note->tick().ticks()] = std::move(bendDurations); +} + +static void fillBendDataContextForNote(BendDataContext& bendDataCtx, const BendDataCollector::ImportedBendInfo& importedInfo) +{ + const Note* note = importedInfo.note; + IF_ASSERT_FAILED(note) { + LOGE() << "couldn't fill bend data: note is NULL"; + return; + } + + const auto& bendSegments = importedInfo.segments; + IF_ASSERT_FAILED(!bendSegments.empty()) { + LOGE() << "couldn't fill bend data: bend segments are empty"; + return; + } + + std::vector bendDurations; + if (isSlightBend(importedInfo)) { + fillSlightBendDataContext(bendDataCtx, importedInfo); + return; + } + + size_t startIndex = 0; + + if (isFirstPrebend(importedInfo)) { + fillPrebendDataContext(bendDataCtx, importedInfo); + startIndex = 1; + } + + fillNormalBendDataContext(bendDataCtx, importedInfo, startIndex); +} +} // namespace mu::iex::guitarpro diff --git a/src/importexport/guitarpro/internal/guitarbendimport/benddatacollector.h b/src/importexport/guitarpro/internal/guitarbendimport/benddatacollector.h new file mode 100644 index 0000000000000..ff092103a8254 --- /dev/null +++ b/src/importexport/guitarpro/internal/guitarbendimport/benddatacollector.h @@ -0,0 +1,61 @@ +/* + * SPDX-License-Identifier: GPL-3.0-only + * MuseScore-Studio-CLA-applies + * + * MuseScore Studio + * Music Composition & Notation + * + * Copyright (C) 2024 MuseScore Limited + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 3 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once + +#include +#include +#include + +#include "benddatacontext.h" + +namespace mu::engraving { +class Note; +class Chord; +} + +namespace mu::iex::guitarpro { +class BendDataCollector +{ +public: + + void storeBendData(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; + }; + + struct ImportedBendInfo { + const mu::engraving::Note* note = nullptr; + int pitchChangesAmount = 0; + std::vector segments; + }; + +private: + // todo: here storing 1 note for "track+tick". TODO: adapt for chord + std::unordered_map > m_bendInfoForNote; +}; +} // mu::iex::guitarpro diff --git a/src/importexport/guitarpro/internal/guitarbendimport/benddatacontext.h b/src/importexport/guitarpro/internal/guitarbendimport/benddatacontext.h new file mode 100644 index 0000000000000..0511e8e448403 --- /dev/null +++ b/src/importexport/guitarpro/internal/guitarbendimport/benddatacontext.h @@ -0,0 +1,45 @@ +/* + * SPDX-License-Identifier: GPL-3.0-only + * MuseScore-Studio-CLA-applies + * + * MuseScore Studio + * Music Composition & Notation + * + * Copyright (C) 2024 MuseScore Limited + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 3 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once + +#include +#include + +namespace mu::engraving { +class Chord; +} + +namespace mu::iex::guitarpro { +struct BendDataContext { + struct BendData { + mu::engraving::Fraction startTick; + double startFactor = 0.0; + double endFactor = 1.0; + int quarterTones = 0; + mu::engraving::GuitarBendType type = mu::engraving::GuitarBendType::BEND; + }; + + std::unordered_map > > bendChordDurations; + std::unordered_map > bendDataByEndTick; +}; +} // mu::iex::guitarpro diff --git a/src/importexport/guitarpro/internal/guitarbendimport/benddataprocessor.cpp b/src/importexport/guitarpro/internal/guitarbendimport/benddataprocessor.cpp new file mode 100644 index 0000000000000..72ee754aa5580 --- /dev/null +++ b/src/importexport/guitarpro/internal/guitarbendimport/benddataprocessor.cpp @@ -0,0 +1,195 @@ +/* + * SPDX-License-Identifier: GPL-3.0-only + * MuseScore-Studio-CLA-applies + * + * MuseScore Studio + * Music Composition & Notation + * + * Copyright (C) 2024 MuseScore Limited + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 3 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#include "benddataprocessor.h" + +#include "benddatacontext.h" +#include +#include +#include +#include +#include +#include +#include + +using namespace mu::engraving; + +namespace mu::iex::guitarpro { +static void createGuitarBends(const BendDataContext& bendDataCtx, mu::engraving::Note* note); + +BendDataProcessor::BendDataProcessor(mu::engraving::Score* score) + : m_score(score) +{ +} + +void BendDataProcessor::processBends(const BendDataContext& bendDataCtx) +{ + for (const auto& [track, trackInfo] : bendDataCtx.bendChordDurations) { + for (const auto& [mainTick, chordsDurations] : trackInfo) { + if (chordsDurations.empty()) { + LOGE() << "bend import error : no chord duration data for track " << track << ", tick " << mainTick; + continue; + } + + Fraction mainTickFr = Fraction::fromTicks(mainTick); + const Measure* mainChordMeasure = m_score->tick2measure(mainTickFr); + + if (!mainChordMeasure) { + LOGE() << "bend import error : no valid measure for track " << track << ", tick " << mainTick; + return; + } + + const Chord* mainChord = mainChordMeasure->findChord(mainTickFr, track); + + if (!mainChord) { + LOGE() << "bend import error : no valid chord for track " << track << ", tick " << mainTick; + return; + } + + Fraction currentTick = mainChord->tick() + mainChord->ticks(); + createGuitarBends(bendDataCtx, mainChord->upNote()); + + for (size_t i = 1; i < chordsDurations.size(); i++) { + const Measure* currentMeasure = m_score->tick2measure(currentTick); + const Segment* curSegment = currentMeasure->findSegment(SegmentType::ChordRest, currentTick); + + if (curSegment) { + // adding bend for existing chord + const Measure* startMeasure = m_score->tick2measure(currentTick); + + if (!startMeasure) { + LOGE() << "bend import error : no valid measure for track " << track << ", tick " << currentTick; + return; + } + + const Chord* existingChord = startMeasure->findChord(currentTick, track); + + if (!existingChord) { + LOGE() << "bend import error : no valid chord for track " << track << ", tick " << currentTick; + return; + } + + Note* existingNote = existingChord->upNote(); // TODO: different notes + createGuitarBends(bendDataCtx, existingNote); + currentTick += existingChord->ticks(); + } else { + // TODO: create new segment and new chord on it + LOGE() << "bend wasn't added!"; + } + } + } + } +} + +static void createGuitarBends(const BendDataContext& bendDataCtx, mu::engraving::Note* note) +{ + Score* score = note->score(); + const Chord* chord = toChord(note->parent()); + int chordTicks = chord->tick().ticks(); + + // TODO: distinguish notes from same chord + if (bendDataCtx.bendDataByEndTick.find(chord->track()) == bendDataCtx.bendDataByEndTick.end()) { + LOGE() << "bend import error: bends data on track " << chord->track() << " doesn't exist"; + return; + } + + const auto& currentTrackData = bendDataCtx.bendDataByEndTick.at(chord->track()); + if (currentTrackData.find(chordTicks) == currentTrackData.end()) { + LOGE() << "bend import error: bends data on track " << chord->track() << " doesn't exist for tick " << chordTicks; + return; + } + + const BendDataContext::BendData& bendData = currentTrackData.at(chordTicks); + const Measure* startMeasure = score->tick2measure(bendData.startTick); + + if (!startMeasure) { + LOGE() << "bend import error : no valid measure for track " << chord->track() << ", tick " << bendData.startTick.ticks(); + return; + } + + const Chord* startChord = startMeasure->findChord(bendData.startTick, chord->track()); + + if (!startChord) { + LOGE() << "bend import error : no valid chord for track " << chord->track() << ", tick " << bendData.startTick.ticks(); + return; + } + + Note* startNote = startChord->upNote(); // TODO: separate notes in the same chord + int pitch = bendData.quarterTones / 2; + + if (bendData.type == GuitarBendType::PRE_BEND) { + int pitch = bendData.quarterTones / 2; + note->setPitch(note->pitch() + pitch); + note->setTpcFromPitch(); + GuitarBend* bend = score->addGuitarBend(bendData.type, note); + QuarterOffset quarterOff = bendData.quarterTones % 2 ? QuarterOffset::QUARTER_SHARP : QuarterOffset::NONE; + bend->setEndNotePitch(note->pitch(), quarterOff); + Note* startNote = bend->startNote(); + if (startNote) { + startNote->setPitch(note->pitch() - pitch); + startNote->setTpcFromPitch(); + } + } else if (bendData.type == GuitarBendType::SLIGHT_BEND) { + GuitarBend* bend = score->addGuitarBend(bendData.type, note); + bend->setStartTimeFactor(bendData.startFactor); + bend->setEndTimeFactor(bendData.endFactor); + } else { + if (startChord == chord) { + LOGE() << "bend import error : start and end chords are the same for track " << chord->track() << ", tick " << + bendData.startTick.ticks(); + return; + } + + GuitarBend* bend = score->addGuitarBend(bendData.type, startNote, note); + if (!bend) { + LOGE() << "bend wasn't created for track " << chord->track() << ", tick " << startChord->tick().ticks(); + return; + } + + QuarterOffset quarterOff = bendData.quarterTones % 2 ? QuarterOffset::QUARTER_SHARP : QuarterOffset::NONE; + bend->setEndNotePitch(startNote->pitch() + pitch, quarterOff); + bend->setStartTimeFactor(bendData.startFactor); + bend->setEndTimeFactor(bendData.endFactor); + } + + int newPitch = note->pitch(); + Note* tiedNote = nullptr; + + Tie* tieFor = startNote->tieFor(); + if (tieFor) { + tiedNote = tieFor->endNote(); + if (bendData.type != GuitarBendType::PRE_BEND) { + startNote->remove(tieFor); + } + } + + while (tiedNote) { + tiedNote->setPitch(newPitch); + tiedNote->setTpcFromPitch(); + Tie* tie = tiedNote->tieFor(); + if (!tie) { + break; + } + + tiedNote = tie->endNote(); + } +} +} // namespace mu::iex::guitarpro diff --git a/src/importexport/guitarpro/internal/guitarbendimport/benddataprocessor.h b/src/importexport/guitarpro/internal/guitarbendimport/benddataprocessor.h new file mode 100644 index 0000000000000..4480c8739500e --- /dev/null +++ b/src/importexport/guitarpro/internal/guitarbendimport/benddataprocessor.h @@ -0,0 +1,42 @@ +/* + * SPDX-License-Identifier: GPL-3.0-only + * MuseScore-Studio-CLA-applies + * + * MuseScore Studio + * Music Composition & Notation + * + * Copyright (C) 2024 MuseScore Limited + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 3 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once + +#include "benddatacontext.h" + +namespace mu::engraving { +class Note; +class Score; +} + +namespace mu::iex::guitarpro { +class BendDataProcessor +{ +public: + BendDataProcessor(mu::engraving::Score* score); + void processBends(const BendDataContext& bendDataCtx); + +private: + mu::engraving::Score* m_score = nullptr; +}; +} // mu::iex::guitarpro diff --git a/src/importexport/guitarpro/internal/guitarbendimport/guitarbendimporter.cpp b/src/importexport/guitarpro/internal/guitarbendimport/guitarbendimporter.cpp new file mode 100644 index 0000000000000..64ed29a1e8ee3 --- /dev/null +++ b/src/importexport/guitarpro/internal/guitarbendimport/guitarbendimporter.cpp @@ -0,0 +1,46 @@ +/* + * SPDX-License-Identifier: GPL-3.0-only + * MuseScore-Studio-CLA-applies + * + * MuseScore Studio + * Music Composition & Notation + * + * Copyright (C) 2024 MuseScore Limited + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 3 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#include "guitarbendimporter.h" + +#include "engraving/dom/chord.h" +#include "engraving/dom/note.h" +#include "engraving/dom/score.h" + +using namespace mu::engraving; + +namespace mu::iex::guitarpro { +GuitarBendImporter::GuitarBendImporter(mu::engraving::Score* score) + : m_dataCollector(std::make_unique()), + m_dataProcessor(std::make_unique(score)) +{ +} + +void GuitarBendImporter::collectBend(mu::engraving::Note* note, const mu::engraving::PitchValues& pitchValues) +{ + m_dataCollector->storeBendData(note, pitchValues); +} + +void GuitarBendImporter::applyBendsToChords() +{ + m_dataProcessor->processBends(m_dataCollector->collectBendDataContext()); +} +} // namespace mu::iex::guitarpro diff --git a/src/importexport/guitarpro/internal/guitarbendimport/guitarbendimporter.h b/src/importexport/guitarpro/internal/guitarbendimport/guitarbendimporter.h new file mode 100644 index 0000000000000..fabfe779f8a38 --- /dev/null +++ b/src/importexport/guitarpro/internal/guitarbendimport/guitarbendimporter.h @@ -0,0 +1,51 @@ +/* + * SPDX-License-Identifier: GPL-3.0-only + * MuseScore-Studio-CLA-applies + * + * MuseScore Studio + * Music Composition & Notation + * + * Copyright (C) 2024 MuseScore Limited + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 3 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#pragma once + +#include +#include +#include +#include "benddatacollector.h" +#include "benddataprocessor.h" + +namespace mu::engraving { +class Note; +class Chord; +class Score; +} + +namespace mu::iex::guitarpro { +class GuitarBendImporter +{ +public: + + GuitarBendImporter(mu::engraving::Score* score); + + void collectBend(mu::engraving::Note* note, const mu::engraving::PitchValues& pitchValues); + void applyBendsToChords(); + +private: + + std::unique_ptr m_dataCollector; + std::unique_ptr m_dataProcessor; +}; +} // mu::iex::guitarpro diff --git a/src/importexport/guitarpro/internal/importgtp-gp4.cpp b/src/importexport/guitarpro/internal/importgtp-gp4.cpp index cad0fa70c81b2..8dcaf9ed5726c 100644 --- a/src/importexport/guitarpro/internal/importgtp-gp4.cpp +++ b/src/importexport/guitarpro/internal/importgtp-gp4.cpp @@ -47,7 +47,6 @@ #include "engraving/dom/stafftext.h" #include "engraving/dom/stafftype.h" #include "engraving/dom/stringdata.h" -#include "engraving/dom/stretchedbend.h" #include "types/symid.h" #include "engraving/dom/tie.h" #include "engraving/dom/tremolosinglechord.h" @@ -615,6 +614,10 @@ int GuitarPro4::convertGP4SlideNum(int sl) bool GuitarPro4::read(IODevice* io) { m_continiousElementsBuilder = std::make_unique(score); + if (engravingConfiguration()->experimentalGuitarBendImport()) { + m_guitarBendImporter = std::make_unique(score); + } + f = io; curPos = 30; @@ -1187,7 +1190,10 @@ bool GuitarPro4::read(IODevice* io) } m_continiousElementsBuilder->addElementsToScore(); - StretchedBend::prepareBends(m_stretchedBends); + + if (engravingConfiguration()->experimentalGuitarBendImport()) { + m_guitarBendImporter->applyBendsToChords(); + } return true; } diff --git a/src/importexport/guitarpro/internal/importgtp-gp5.cpp b/src/importexport/guitarpro/internal/importgtp-gp5.cpp index a4483965f395b..816e6cc6c2dbf 100644 --- a/src/importexport/guitarpro/internal/importgtp-gp5.cpp +++ b/src/importexport/guitarpro/internal/importgtp-gp5.cpp @@ -56,14 +56,10 @@ #include "engraving/dom/stafftext.h" #include "engraving/dom/stafftype.h" #include "engraving/dom/stringdata.h" -#include "engraving/dom/stretchedbend.h" #include "types/symid.h" -#include "engraving/dom/tempotext.h" -#include "engraving/dom/text.h" #include "engraving/dom/tie.h" #include "engraving/dom/timesig.h" #include "engraving/dom/tremolosinglechord.h" -#include "engraving/dom/tremolobar.h" #include "engraving/dom/tuplet.h" #include "engraving/dom/volta.h" #include "engraving/dom/fretcircle.h" @@ -853,6 +849,10 @@ void GuitarPro5::readMeasures(int /*startingTempo*/) bool GuitarPro5::read(IODevice* io) { m_continiousElementsBuilder = std::make_unique(score); + if (engravingConfiguration()->experimentalGuitarBendImport()) { + m_guitarBendImporter = std::make_unique(score); + } + f = io; readInfo(); @@ -1087,7 +1087,9 @@ bool GuitarPro5::read(IODevice* io) } m_continiousElementsBuilder->addElementsToScore(); - StretchedBend::prepareBends(m_stretchedBends); + if (engravingConfiguration()->experimentalGuitarBendImport()) { + m_guitarBendImporter->applyBendsToChords(); + } return true; } diff --git a/src/importexport/guitarpro/internal/importgtp.cpp b/src/importexport/guitarpro/internal/importgtp.cpp index 4e1ac802697ca..f4578e8a60d43 100644 --- a/src/importexport/guitarpro/internal/importgtp.cpp +++ b/src/importexport/guitarpro/internal/importgtp.cpp @@ -65,7 +65,6 @@ #include "engraving/dom/staff.h" #include "engraving/dom/stafftext.h" #include "engraving/dom/stafftype.h" -#include "engraving/dom/stretchedbend.h" #include "engraving/dom/stringdata.h" #include "engraving/dom/tempotext.h" #include "engraving/dom/text.h" @@ -636,17 +635,8 @@ void GuitarPro::createBend(Note* note, std::vector& bendData) return; } - bool useStretchedBends = engravingConfiguration()->useStretchedBends(); - - if (useStretchedBends) { - Chord* chord = toChord(note->parent()); - StretchedBend* stretchedBend = Factory::createStretchedBend(chord); - stretchedBend->setPitchValues(bendData); - stretchedBend->setTrack(note->track()); - stretchedBend->setNote(note); - note->setStretchedBend(stretchedBend); - chord->add(stretchedBend); - m_stretchedBends.push_back(stretchedBend); + if (engravingConfiguration()->experimentalGuitarBendImport()) { + m_guitarBendImporter->collectBend(note, bendData); } else { Bend* bend = Factory::createBend(note); bend->setPoints(bendData); @@ -2657,7 +2647,9 @@ bool GuitarPro3::read(IODevice* io) } m_continiousElementsBuilder->addElementsToScore(); - StretchedBend::prepareBends(m_stretchedBends); + if (engravingConfiguration()->experimentalGuitarBendImport()) { + m_guitarBendImporter->applyBendsToChords(); + } return true; } diff --git a/src/importexport/guitarpro/internal/importgtp.h b/src/importexport/guitarpro/internal/importgtp.h index a0337f595c370..3251f9de38593 100644 --- a/src/importexport/guitarpro/internal/importgtp.h +++ b/src/importexport/guitarpro/internal/importgtp.h @@ -31,6 +31,7 @@ #include "gtp/gp67dombuilder.h" #include "continiouselementsbuilder.h" +#include "guitarbendimport/guitarbendimporter.h" #include "engraving/types/types.h" #include "engraving/engravingerrors.h" @@ -57,7 +58,6 @@ class MasterScore; class Ottava; class Hairpin; class Bend; -class StretchedBend; class Slur; } // namespace mu::engraving @@ -267,7 +267,6 @@ class GuitarPro : public muse::Injectable int slide = 0; int voltaSequence = 0; mu::engraving::Slur** slurs = nullptr; - std::vector m_stretchedBends; void skip(int64_t len); void read(void* p, int64_t len); @@ -325,6 +324,7 @@ class GuitarPro : public muse::Injectable size_t measures = 0; std::vector bars; std::unique_ptr m_continiousElementsBuilder; + std::unique_ptr m_guitarBendImporter; enum class GuitarProError : char { GP_NO_ERROR, GP_UNKNOWN_FORMAT, diff --git a/src/importexport/guitarpro/tests/CMakeLists.txt b/src/importexport/guitarpro/tests/CMakeLists.txt index edb14deca3eff..074c94276eae7 100644 --- a/src/importexport/guitarpro/tests/CMakeLists.txt +++ b/src/importexport/guitarpro/tests/CMakeLists.txt @@ -28,6 +28,7 @@ set(MODULE_TEST_SRC ${CMAKE_CURRENT_LIST_DIR}/environment.cpp ${CMAKE_CURRENT_LIST_DIR}/guitarpro_tests.cpp + ${CMAKE_CURRENT_LIST_DIR}/guitarbendimporter_tests.cpp ) set(MODULE_TEST_LINK diff --git a/src/importexport/guitarpro/tests/guitarbendimporter_data/prebend-gp.mscx b/src/importexport/guitarpro/tests/guitarbendimporter_data/prebend-gp.mscx new file mode 100644 index 0000000000000..6654e40a0b1a1 --- /dev/null +++ b/src/importexport/guitarpro/tests/guitarbendimporter_data/prebend-gp.mscx @@ -0,0 +1,346 @@ + + + + 480 + 1 + 1 + 1 + 0 + + + + + + + + + + + + + 2 + + stdNormal + + + + 1 + + tab6StrSimple + 6 + 1.5 + 1 + 1 + 0 + 0 + MuseScore Tab Modern + 15 + 0 + MuseScore Tab Sans + 9 + 0 + 0 + 0 + 1 + 0 + 1 + 0 + 0 + 1 + + + Electric Guitar + + Electric Guitar + el.guit. + + -7 + -12 + pluck.guitar.electric + 0 + + 24 + 52 + 57 + 62 + 67 + 71 + 76 + + + + + + + + + + 10 + + + + + + + + + + + + + + + + + + 0 + major + + + 4 + 4 + + + mf + 80 + + + 2 + metNoteQuarterUp = 120 + + + + no + eighth + + 1 + + + + noteheadParenthesisLeft + + + noteheadParenthesisRight + + 60 + 14 + 1 + 1 + + + 1 + 0 + 1 + + 3 + + + + + + + + + + + quarter + + + 62 + 16 + 1 + 1 + + + + 0 + + + + + + + + no + eighth + + 1 + + + + noteheadParenthesisLeft + + + noteheadParenthesisRight + + 60 + 14 + 3 + 1 + + + 1 + 0 + 1 + + 3 + + + + + + + + + + + quarter + + + + 1 + accidentalQuarterToneSharpArrowDown + + 64 + 18 + 1 + 1 + + + + 0 + + + + + + + + half + + + + + + + + + + + 0 + major + + + + + no + eighth + + 1 + + + + 60 + 14 + 1 + 1 + + + 1 + 0 + 1 + + + 3 + + + + + + + + + + + + quarter + + + + 62 + 16 + 1 + 1 + + + + 0 + + + + + + + + + no + eighth + + 1 + + + + 60 + 14 + 1 + 1 + + + 1 + 0 + 1 + + + 3 + + + + + + + + + + + + quarter + + + + + 1 + accidentalQuarterToneSharpArrowDown + + 64 + 18 + 1 + 1 + + + + 0 + + + + + + + + + half + + + + + + diff --git a/src/importexport/guitarpro/tests/guitarbendimporter_data/prebend-gp5.mscx b/src/importexport/guitarpro/tests/guitarbendimporter_data/prebend-gp5.mscx new file mode 100644 index 0000000000000..cf7586f4b88f8 --- /dev/null +++ b/src/importexport/guitarpro/tests/guitarbendimporter_data/prebend-gp5.mscx @@ -0,0 +1,339 @@ + + + + 480 + 1 + 1 + 1 + 0 + + + + + + + + + + + + + 2 + + stdNormal + + G8vb + + + 1 + + tab6StrSimple + 6 + 1.5 + 1 + 1 + 0 + 0 + MuseScore Tab Modern + 15 + 0 + MuseScore Tab Sans + 9 + 0 + 0 + 0 + 1 + 0 + 1 + 0 + 0 + 1 + + + Electric Guitar + + Electric Guitar + + pluck.guitar.electric + 0 + + 30 + 40 + 45 + 50 + 55 + 59 + 64 + + + + + + + + + + + 10 + + + + + + + + + + + + + + + + + + 0 + + + 4 + 4 + + + mf + 80 + + + + no + eighth + + 1 + + + + noteheadParenthesisLeft + + + noteheadParenthesisRight + + 60 + 14 + 1 + 1 + + + 1 + 0 + 1 + + 3 + + + + + + + + + + + quarter + + + 62 + 16 + 1 + 1 + + + + 0 + + + + + + + + no + eighth + + 1 + + + + noteheadParenthesisLeft + + + noteheadParenthesisRight + + 60 + 14 + 3 + 1 + + + 1 + 0 + 1 + + 3 + + + + + + + + + + + quarter + + + + 1 + accidentalQuarterToneSharpArrowDown + + 64 + 18 + 1 + 1 + + + + 0 + + + + + + + + half + + + + + + + + + + + 0 + + + + + no + eighth + + 1 + + + + 60 + 14 + 1 + 1 + + + 1 + 0 + 1 + + + 3 + + + + + + + + + + + + quarter + + + + 62 + 16 + 1 + 1 + + + + 0 + + + + + + + + + no + eighth + + 1 + + + + 60 + 14 + 1 + 1 + + + 1 + 0 + 1 + + + 3 + + + + + + + + + + + + quarter + + + + + 1 + accidentalQuarterToneSharpArrowDown + + 64 + 18 + 1 + 1 + + + + 0 + + + + + + + + + half + + + + + + diff --git a/src/importexport/guitarpro/tests/guitarbendimporter_data/prebend.gp b/src/importexport/guitarpro/tests/guitarbendimporter_data/prebend.gp new file mode 100644 index 0000000000000000000000000000000000000000..5c81d1ac7ac301a5a10b8944696b93bc68584bab GIT binary patch literal 8677 zcmaJ{1yEhfmc2l54ek;=7bjS72n6?wyX(EU1r6>R+#$F-1b2eFySoIJFkza*RlT%{6F2lqC_mf z2KH{sj&9Z_4(28%j_KOc5Mnjwa+-e1DC@zzo(8JWSeazPsP3dRfN=CgVJdnIj1tv6 z|#NfH20JDm54x++=tbzxgnR>hpKV==v}VBQ#;;Ng&)# zhQ1o4thC3{FW{B;buE?DmBpw0d&>@OXS@ZW_Guxxyd#P!F}D1UaT#PJ4>4rT!hVih z{>KlJDg2@AY!}aC#Acey^SAu=EK*N$hupu={Tff;j(#9gFbY!jhmg^FaTfE8_O`b% zF?A`COxnhkx#F8dyw&To0|yU{_%2=K>b5RXr(1JHR@WZ91asFlYaQ$EB7> z<358WBHx*&Xj@#&pTy7%2Krq?J)O{9ATDRz+r4q-9>u9roFp@OKIayo9PGK>*n`wB zJFlB|`};&4-(1td@uEKkANNVJ+fE7Gxi%y>#q7~!G!LCPlEY2Ev*g|AOlf?X_)Nwe zR)!|Qwd7Z@`fDj9wO3PJ_kN6eLye}DC!BxMAK{IEGB52c{+mi?geBtYxa_&v{760s z$?v65cw6XJFV2IO`erA`r_RCO-L135d}!()r8+q#3B@Z}xb1%ITlqB_G?RT_M{=D% z=?cN-8}Wc9sQSFG%3x|ARBx9yaLGR>59gKVrt`Se#J}lIr2)^oNL2*y#hlYNu}5QC zsHVG_agf0?+7QNR27dI<%t0CbQng00W-`POe9|R%u9rhWO__r`N%$uTa*@>xBFCc` zm&K?9DF_~fW{)6*58S-A5H(FAXQO)jW%mnzYa`M|Hfp9xW7vW^6HY{yG2Y?}ADpBDOJ_jr*c!xHp|OEg#&I4EwUepbboWjkZ&s;MML zCImG+>N_7)>jG0wq~L0C_ZU;e!H>^64RO6ba$|t$Pi%#sItUuH3qgnM0ZgR)%{?>e z1yqK*a^IDrmd(ox!F8sMg zn4AT#qiwHx^+%b zQnO@obl`VBDQ2?AJ*uok-I!*ofY6~2yMjL-s5a)-YpIJ1Y$F8FTTnyZP@$!90n42X z$86A`2^!%ucgR^}5Zj9o`)8-Ec zXZAQtCu<tzdl}dh4~1)@)zN%Rw}=S85Nvib($xwDWoV)`QDcUt zoq*PI8~uJ)((HchO}7sYqU08Z#3}Z+wfLlqFrZ^X#Rr8VDv2tY5v~Hq;9P_m-uGybzPSjPsd9+G>Ku24*o3WDocK znA;enPQdFoN)yOcT43BT^6!k2SP3hUWAB8DHc6&k1`fG%kg*cF0kOqz!|>teTHA^9 z37lLuf2Xf$r>T*z91Br)Q=tvjKGcnj966(5mRmnRvzuw`;Nrtu#M_ZhpL(Wv7hJ8jAX`oz}dw2PAChNkoweS8S+V`l9Kn z(A?_9H$8Ts_2N}h$#?=Gn*vS6-1!l4vpap`-rEuoWf-8QH)l5AGu{Umkd9hK7_ zBg@CS&D0=b)o-j}biv5PXj~Vh_K_DMw^Q#_&yglIl_-CTS|R5nHg)&)-cq}CJ%mzI zGN!#eztDan!40kMk2VZi%wKC$HU2D~&2XY^-lnW*qSBk9gszr?c@e_+#rmMb z!C=ors7{Nx%ID{{zzwf_N_vmjNXItTU^+o=xwwZMUnPQjv~hlwABsdn#z|v(8wM_U={oLE71suM*3Zv0I|OcoZy27;k^#y*-WNuspH9B~cQxZ5z;HR%RRI2HqbExB2f!~rKs79XgEy72v{RROdB zSm0Iduloz5}`}TG$I3fOH%?KUMfTL+S^9#cK6%o*gR3m$;D;BJL98T!2J0^#>)BvMygBP0<6w zS6ci651SD9XpS&WU{bI?l$$6b`>7a3o^(^_chm(YisppYD`br~9_B_Cfq3C0wxU4f zOn65jcYeWgT1k)H=}W3F^lBbx+$lSu8`84~i%sh3oYX31Fx&QYl@oBrpp~SA-q75qRPX z8e--lceE6nfj|sXqVV+x^Zf(EUh2fUgpavpr`xkx`Rz6cjL~CeJ>w7T zOxDJuY94hhb1K094A*9Fya-4n-uoy5_lpsk(L*w22|MAzBk#MWQVRNFd13)rOBqIL z+t225+Dy=Z?U;9q1t#m>nGL0mAcb=QX2x}+8(pxa@#}gNV(YUxm#RNaE66l3?Z51iXN5P z=g^|I&n}Th1|4V-Z_?R(Mbm~bUT};2nm+|VxjGGNA3zzsg$lPVhW4I_NoR4kMm#(&fiF)n?*Ce-t&0Ep=;@Sv6N>2x@HlTTFh- z*&+oSzrEfmmO%JwlKeB!BKXR<XR&?wZ~tvd;KX)T;VT^zyC|Na3_Z!`y6+|hCF z#;}Gyh-I;4L?d1BfTx7hOeA6eI(m;)Y5&Dhc8+cGn8ma#k)v}Ln9{WVy7ncbs*Kx5k^;;;$Y()E2 zkBJD6FttNO^9Je|3=^ZRhO1tT?NW5iaScQ#glbZ%oU#(Zf|ZoArrX`C01ce5%F@l? zDhgcGqNcS{FEY=Vfz1B5X7{DkQEonZ9$ zk{d(To$K+`v);bpqWQQ9;u|Iq<%z1?f}?H*T&dROCF*CyfRZMDuJ9wbjF#ir@3$54 zdpV9oD~91jLwH_T1xmv1w#*h&jB1MKP#IN6JkyHccJ{tVgojz=}BPFRbSsrtmwOb_YG^M>2!$6!km!ZU3>k5E*c_T^tP1DBPevgBR`>#o)PuWXil_gd{0x*Nme5z6vojZ0M zq)7B;cx|AD!0k3T@(RX8YU0O*|0i%FwVuf$P$qN6FjD;dLD@3Y3Yjl1<9q&sSli-n zXOR1l1omi6SCx_|I6f_4IS=JK!%nAUKGM!*a_fj{`3*3>7)k!E!tn3jMZIru*%Exq ze4n%|g;Y@^TaqHQcF*DBDf<1~yebS$95wqd^q0+}_IRW<>eP}?tLSjiZntI(A}c)# z$h2nA*Nj)c!aV)Vsp2O>jxWRmlcF1p1hhib z8fL}QRnk%efEL;G)S;v%Pe!G!=Dsioizk-Ava4M0CXMeFcirCBDiJI~gG<$>yX9mq= zv=&d5LLvPQbWRcRbhs#Msz;SC2U^Qn6*<&c$b~qot38OC8q_gY>NL2+>0F??5PJ?= za9r1s{l+Lh-;FWXk57}Ce*aDtfz1&!#t2>7tUr?hDej_=9FxOI(w|MH4rO+0?*Q~r zsiZyoX82-NLWn`vUfAG!0AGYjG%h1G6PXxeu5TC)V)^B0AMkyU?GCFjjm`T^ux2$~ zd*S$LI^KpD&OLsQ~ZNYG7VmJdkb6g<#;LLruqvlGK?XO_{dKD2^QBQY>HQ#vsvG>uou> zkx;{^egsW%)x$SD{}B*4(gy_cl)F=f)oi{IiXnBqbAhbAnMe0VMQ5x_83yuwO{Ghq zg8-j=V|C|>pZ%do*zIF#vo5WlHj6CtLd=A3lnm9pa;$eETDvBm;_#p7x6(A;&(7&; zMiPcc{_KcUyN3r|&b90;E;jUclE2(=zrdOhtDUU)dCH7o6<)5qlO^JZ8XD|CgH{SD z&PtSuy|~Ix0D`t|pPuDr&V`_obaGi%={b%_M@dUZihV?ZJX`f5V@xcUUj)k@%mc56>fcKPZ%Ih6hS0`GRR#5h&zC;8Ue7EVU-CN%_tWY$-_ zL0s8;#Y#}O#W_kdQAUGox~Epx)>%>^(G5|WGZ=ZH^~3(E4>LDID-jdrL=T+<5+eDf zrNrgmd|GrbMV8q_Y$#;)X4_QlRsv6o56wz}R#jxo3)k`l3~|jKNJ<0pUKS6zQ5BXg z$=+YAb0{0k%|577b-Fg0Z~Lj(Sp7TPW6tmn4mk7?r!Ge z&c%CziIU#quLikN8e!gnpI&0_XbGY-62A_sBT_PK83E-l^G|osZUQi+UaTWuV&hI~ znv#pLYKDJ=>PdiF_v_o-I#NQ8-ifKhRt4(uVQ&n~?p_MS>Cx9F-l*AeNkesigx!pg z9kkZ&O82mDK9@A!kiJJE$o=#ix!qVX1njsX^NsL#f-Pc{hJh(q#$%#ei8y5yy!T=) zT()fzCr91z{&M{HN#F#T);K*GoocjdVaE`sJ`-b2mur7YFvHb%t6@B!vG;MceGQI9 zFYr4li*`3M00812r}1A~i9~<15@ihBAWn{dj73umGbeikM+*qpNMC>5(D?2p6AA&q zOn!la@+bVY{cA#kzY!`J*#93oeM11WxGDD_0-(PU^zPLKMg6yYfA=~S>`hEf>`lN% zCJs!N4iK%`OeOh$BSnzVQwRo zOSpEC!bDvW%5#`LDLBGDjX^M+ztTo~c8@&lKDSyYgMOCa_Q{gnEFnIP9DF8DfcMCI z6=w_m91%K_v5(v7zw3pDym-aE^jm;B^x@1-^57)_7f3f&$Di%{{@Wv9{+a#Du5~bi z*qbn!*;<&M5L!W&xG#Tr!OjUm&U_rGc&p-Qig6>ij3cBqA;Ao&{@1fDSyxp3N+u6Bj-Y zlxQ(wI6j*D)w&IWIIo{r0SI_CqI0YD`XGJ$G0zw_SEfd!ZR!5F+FwHK8+JpTOhi1LWn$x<&XiKpqF);8^Zi7V%M#wrW1zavPypw%f8@MH=jvZ$ zcI}~Z8#x`Q3pRgx4$(+>(mQVCl2H+8H=^s>g6XHnh+eQ`m<$f2B^i@NK)pw83`Y+# zvnW_*%sD`f`XNQtFL!yLm&6>P^v=>pq+SWtM>W;g5dv}{KzcDs^c(8|@Kex5+J{O+ zgpF7*45oeem}!ZFarye|>+t3pQ_Qn(zE@Qe6B8}7(9aH7|1`eDN2@TO$Fa2x0hhPo z<#@(tmsck<4lUkm%P-HVM>Y3)<*TCwTY=ctDE0VmtkXw5<8ttIZ|s=-AB<>& zhlcl{sPX7w>A7I5Ui`1JuJ79$P|DVKZP02p73sIdpx2nKpQD*cr!31whgK3UI4nhP zy^EhyRlkUCHCJXp@(g46jDRTthq2&K`7JPX>Ftg4RLgP`pPmaaCS?4V*Iducld6at z;L0i7Ki8S)7zTy5V=1J$N0yfl6@8<8hZ$fqB_{P8rB1)4>^?rRO-XmoK90&LwQd-~Vub)V;Fwme)I zzizx=LVri0;75nxaT9rU3-yGuVdf)fj!BJsqvM`<ldV34G`w1Kv41t9@@^_B|D$Zc8acx7=#=cN%hWONbq?p>LmoSHyv-Q^2 zU>gB~9ARXCYX@EP{RD`RST;eZzhKo|r1Y^On=z#O;cpU+I3u~45bB=~eikDm7Jie? z4w9&%Zc(ydT+wJ#FP$;$P&cl+grj+rgg7rd5ZziD*vrXY{=|WtavTSp^eY`ERbO%| zO5DiV0j#TXr=i|kyx3A3s&pM%uIkE-ZOt(uE6~kA-^xvv9%!!9d;FQO{O90f9YV4f zZ1hyeL~?uNy-lAGL0c2mKIjr~USB$cu$yX5FH#YhAgaJ6nP2YOp=UOM>4~r=TPu|C zNTUpZ5uA*LO2f_SC@eg`ywy)|YgNWdU%@TYIT$Oqm;oxu|?>Tzn4st#2D4EEx9MP4PgD}0wE-(uHLyY2tRVm)9G)A~uzn!!P z(Py6`Z{%PB`!+K(C*>T9g}rGqPUAgTNI>@mqjB3Pd?|2LqQFshzHcrlr&!B+Me|MM z@=Fr+;#c9a?18V<3_@|{-C0!Q1fSjcp^tjsgv<88j-za-<3QpZgi`syyOnRZE2{wV zTEWI^O=dFPq?*0bcZ-5uiWOYMq+MB2=f8(^*sqP(?pc~zla^PP*4L@Mq89|bY;#4Q zq8BGUC3v`dygx^gbgr71bD5~*ZFdEqOqQ~0hQl@nWLg=+g-lL66isq=WrNqY%X9Hk zFj(Hgh0qrIvf$JkERNMvSLJj)O|lVgx3Y^kYm3kYnOA5^)*ffj*4((&?{yRx`cr+gTXkSsd^XFI;be5}R zYHn&{u!oaxlza9b4n-4ObD}#TkGNoJx+cukdQrcE9K6DZpg!u0J7oq>n^J7j+%L?N zQR+*CO=q86`shsyXpfVW1q|eK3F1G*$`~Rku~yZIPnE)T%(L#pUSC1D7}l7cI+^&l ztLn9b4%gZlD|8GKo42-+orVz;$RB?5a@;vjkg8VD%Pb*qbq>0$FhRu`&~L<^)A{Co zG7_6*Fv(jgGwQx0Ljkc}dPYK`Iz*isphe96d}Q84qwQBfYl}x&!JbOE|KgCv(g5mw zeyB8s@qphUnTNkCQ7bd_RHgKcP!)_@X_UJzbk~kP{P|=5M?I;&WS%$TK{R;mslSWv zrPa86-LL?&93E##Ssce6pu}ElPr4(NpuVdyv3sW2QsOYj)Te+_&Sgmw6JLfQ`$L#M zRVb){=WaSRJ~zIuc&taq1HMfGYt#9Y^?(r>pYhS*61P6E@)D4G#hjZAmbdCeAsyv* zLp73;Qg%Kh#y|=#Q6SibS{^2ogL9HoFFE~LfP<%i=%jPi=J}`D>BP4wFGFX3%T-CP zpD^ORCSE>lBg5=2`mGgfTI_aSFJar4w^?Nh39UNpqQB@AvfMt zX$_rPFTuZV&zP87L$M}t52|m;9N0aIRCejE4!p|RHx1$HBZSGQ^WUFQ&Q@zFBZz0V zx|EtKv1uwhWE$F8W!hnLhSXtt?jNh>q_Vw1{3VXz-KtdYj~;I`f^chGghCcC1vJz* zE`$$WbwI{={=NS4L5Od|wB5|-E~5XQUFazr`jZAmGGRI4jMok058I?@4qCZg7kl_`s-%EtI&TH`LAOCRW1L87hjq`pMS0T=RJXc zvix1$zZM05;la|73a1(QAHQ^Ykji|H6y!%->l4N0k3_{cE;fGxeIW*G&F}7vD*; Y|IVv|G%Vcf1pJ?;9|{0KAb;)s2QI(eTL1t6 literal 0 HcmV?d00001 diff --git a/src/importexport/guitarpro/tests/guitarbendimporter_data/prebend.gp5 b/src/importexport/guitarpro/tests/guitarbendimporter_data/prebend.gp5 new file mode 100644 index 0000000000000000000000000000000000000000..ca484cc6ed5d0d1b21d8408f2bbc8513f6049688 GIT binary patch literal 1537 zcmeHH%}&BV5Z(&%rv^P}OpInOYxLl6Vj$52r64pBA#I8ASYg%1T1Z=n9DEPo$BSp* zz_Sm5GhGQ7J#aRB$;{4v^UZ9#$ z;(5&ERM!QAG65JO5Pn~@VGndK6uxJNPRFxd7+0I3)$>JrDYJyNiw*lu0Keo1yuqXU zenM7a1D7oQ5@Irz%*@Yj;D6u1a4OIp(8D3q;&I025E#E@%dTjJK0ftI&k1cGxxbM> zx`1|ymP0#6+e6zyBaFIJSDF=s&zEQRDnsdMXeo2C_Kda$FykuDlEMc)aX z;2zA-ZaskJ3fseBQ4+Uy&kdsY literal 0 HcmV?d00001 diff --git a/src/importexport/guitarpro/tests/guitarbendimporter_data/slight_bend-gp.mscx b/src/importexport/guitarpro/tests/guitarbendimporter_data/slight_bend-gp.mscx new file mode 100644 index 0000000000000..e02248f162ccd --- /dev/null +++ b/src/importexport/guitarpro/tests/guitarbendimporter_data/slight_bend-gp.mscx @@ -0,0 +1,262 @@ + + + + 480 + 1 + 1 + 1 + 0 + + + + + + + + + + + + + 2 + + stdNormal + + + + 1 + + tab6StrSimple + 6 + 1.5 + 1 + 1 + 0 + 0 + MuseScore Tab Modern + 15 + 0 + MuseScore Tab Sans + 9 + 0 + 0 + 0 + 1 + 0 + 1 + 0 + 0 + 1 + + + Electric Guitar + + Electric Guitar + el.guit. + + -7 + -12 + pluck.guitar.electric + 0 + + 24 + 52 + 57 + 62 + 67 + 71 + 76 + + + + + + + + + + 10 + + + + + + + + + + + + + + + + + + 0 + major + + + 4 + 4 + + + mf + 80 + + + 2 + metNoteQuarterUp = 120 + + + + quarter + + + 60 + 14 + 1 + 1 + + + 3 + 0 + 0.283333 + + 3 + + + + + + + + + + + + + + + + + quarter + + + 60 + 14 + 1 + 1 + + + 3 + 0 + 0.733333 + + 3 + + + + + + + + + + + + + + + + + half + + + + + + + + + + + 0 + major + + + + + quarter + + + + 60 + 14 + 1 + 1 + + + 3 + 0 + 1 + + + 3 + + + + + + + + + + + + + + + + + + quarter + + + + 60 + 14 + 1 + 1 + + + 3 + 0 + 1 + + + 3 + + + + + + + + + + + + + + + + + + half + + + + + + diff --git a/src/importexport/guitarpro/tests/guitarbendimporter_data/slight_bend-gp5.mscx b/src/importexport/guitarpro/tests/guitarbendimporter_data/slight_bend-gp5.mscx new file mode 100644 index 0000000000000..25889de486b4b --- /dev/null +++ b/src/importexport/guitarpro/tests/guitarbendimporter_data/slight_bend-gp5.mscx @@ -0,0 +1,255 @@ + + + + 480 + 1 + 1 + 1 + 0 + + + + + + + + + + + + + 2 + + stdNormal + + G8vb + + + 1 + + tab6StrSimple + 6 + 1.5 + 1 + 1 + 0 + 0 + MuseScore Tab Modern + 15 + 0 + MuseScore Tab Sans + 9 + 0 + 0 + 0 + 1 + 0 + 1 + 0 + 0 + 1 + + + Electric Guitar + + Electric Guitar + + pluck.guitar.electric + 0 + + 30 + 40 + 45 + 50 + 55 + 59 + 64 + + + + + + + + + + + 10 + + + + + + + + + + + + + + + + + + 0 + + + 4 + 4 + + + mf + 80 + + + + quarter + + + 60 + 14 + 1 + 1 + + + 3 + 0 + 0.266667 + + 3 + + + + + + + + + + + + + + + + + quarter + + + 60 + 14 + 1 + 1 + + + 3 + 0 + 0.266667 + + 3 + + + + + + + + + + + + + + + + + half + + + + + + + + + + + 0 + + + + + quarter + + + + 60 + 14 + 1 + 1 + + + 3 + 0 + 1 + + + 3 + + + + + + + + + + + + + + + + + + quarter + + + + 60 + 14 + 1 + 1 + + + 3 + 0 + 1 + + + 3 + + + + + + + + + + + + + + + + + + half + + + + + + diff --git a/src/importexport/guitarpro/tests/guitarbendimporter_data/slight_bend.gp b/src/importexport/guitarpro/tests/guitarbendimporter_data/slight_bend.gp new file mode 100644 index 0000000000000000000000000000000000000000..4075cc3c68de21f4131ed5b83f4ae0928fc91a7a GIT binary patch literal 8680 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 K=_606jC}y>J%*V8 literal 0 HcmV?d00001 diff --git a/src/importexport/guitarpro/tests/guitarbendimporter_data/tied_bend-gp.mscx b/src/importexport/guitarpro/tests/guitarbendimporter_data/tied_bend-gp.mscx new file mode 100644 index 0000000000000..7852ab235c6fa --- /dev/null +++ b/src/importexport/guitarpro/tests/guitarbendimporter_data/tied_bend-gp.mscx @@ -0,0 +1,227 @@ + + + + 480 + 1 + 1 + 1 + 0 + + + + + + + + + + + + + 2 + + stdNormal + + + + 1 + + tab6StrSimple + 6 + 1.5 + 1 + 1 + 0 + 0 + MuseScore Tab Modern + 15 + 0 + MuseScore Tab Sans + 9 + 0 + 0 + 0 + 1 + 0 + 1 + 0 + 0 + 1 + + + Electric Guitar + + Electric Guitar + el.guit. + + -7 + -12 + pluck.guitar.electric + 0 + + 24 + 52 + 57 + 62 + 67 + 71 + 76 + + + + + + + + + + 10 + + + + + + + + + + + + + + + + + + 0 + major + + + 4 + 4 + + + mf + 80 + + + 2 + metNoteQuarterUp = 120 + + + + quarter + + + 60 + 14 + 5 + 2 + + + 0 + 0 + 1 + + 3 + + + + 1/4 + + + + + + + + quarter + + + 62 + 16 + 5 + 2 + + + + -1/4 + + + + + + + + half + + + + + + + + + + + 0 + major + + + + + quarter + + + + 60 + 14 + 5 + 2 + + + 0 + 0 + 1 + + + 3 + + + + 1/4 + + + + + + + + + quarter + + + + 62 + 16 + 5 + 2 + + + + -1/4 + + + + + + + + + half + + + + + + diff --git a/src/importexport/guitarpro/tests/guitarbendimporter_data/tied_bend-gp5.mscx b/src/importexport/guitarpro/tests/guitarbendimporter_data/tied_bend-gp5.mscx new file mode 100644 index 0000000000000..956021b04fdef --- /dev/null +++ b/src/importexport/guitarpro/tests/guitarbendimporter_data/tied_bend-gp5.mscx @@ -0,0 +1,220 @@ + + + + 480 + 1 + 1 + 1 + 0 + + + + + + + + + + + + + 2 + + stdNormal + + G8vb + + + 1 + + tab6StrSimple + 6 + 1.5 + 1 + 1 + 0 + 0 + MuseScore Tab Modern + 15 + 0 + MuseScore Tab Sans + 9 + 0 + 0 + 0 + 1 + 0 + 1 + 0 + 0 + 1 + + + Electric Guitar + + Electric Guitar + + pluck.guitar.electric + 0 + + 30 + 40 + 45 + 50 + 55 + 59 + 64 + + + + + + + + + + + 10 + + + + + + + + + + + + + + + + + + 0 + + + 4 + 4 + + + mf + 80 + + + + quarter + + + 60 + 14 + 5 + 2 + + + 0 + 0 + 1 + + 3 + + + + 1/4 + + + + + + + + quarter + + + 62 + 16 + 5 + 2 + + + + -1/4 + + + + + + + + half + + + + + + + + + + + 0 + + + + + quarter + + + + 60 + 14 + 5 + 2 + + + 0 + 0 + 1 + + + 3 + + + + 1/4 + + + + + + + + + quarter + + + + 62 + 16 + 5 + 2 + + + + -1/4 + + + + + + + + + half + + + + + + diff --git a/src/importexport/guitarpro/tests/guitarbendimporter_data/tied_bend.gp b/src/importexport/guitarpro/tests/guitarbendimporter_data/tied_bend.gp new file mode 100644 index 0000000000000000000000000000000000000000..b0912bce591b9a8d3ba57ae07ab07ab89e5e25cd GIT binary patch literal 8714 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 $R^dF+qo*YGbjH?>zz6c>~{kqIjS##R@ba@B~ z|1?YXE-Pc{6$Mf>J@r-|06_m^IsR);5&v(VqP&rpgPZFghtb^1!p+&p)yl!%#L#fv z)b#!}2LcvwNbs2x@lX0&``3UU{sss%a{fPXhQ@$*lIA=^uzpgf2~pYT%Dm@h^{IKj7__0lLZ;>R!PXV^yni8hAWP04;)$itx*qwCN11OM$2 z(ErT-<=eWLI5?XzSvXpmpWxXzEc0Bp`a#c&IGhEzQ1CZSQ|TPUfmHegK#|Nf7X8w z=!hW0eouJ}-r6vUV31{7XJx$Q3fp72Qq7kB*qlk+a$5ym4%6$o5uM!aGGz8c;I1`? zdT(pze$T+~LQl6BKy7fMQ`MEiuShvzYSRwrv2GqNxXlmJKJ`g}(Y8_OWw_&;X#S-$ z4Gyv=c;D)nVUxm-HpI2l1iFQ=;aSP4(qOPd5P@X$z_wr;^G!B*0>@I0_%c%5Y2%lM z=$t|;vGW!;9ZN|{y2LjB4XfI&f!kXD=6z)GLm8U4pG9B%`p=lB0Z~*EY{L< z>0%{hGX7W4$i1UyihJ2AS;pFBGrffKCPj|Y$b+mjZ9WW*sm&sQrol@3PSIU6?_AjZ z&)*1fQZ;C^xLPR~0A45&f z{$^;7ul>t)4xga5Ks&ZIzf+(c-EMCmb=&+6e!V_}Kv(?+Rlk_blfp1<5gT#6SZB)n zCKcaH1~sFKy>wvosh?g2B#tBpC4+)^K1+H7AAi5ffL?WAmE(Jx!`qH>_AyNg zk*|(7mcNn^B~J27Z7n_HqK=LGG|3=M#W42CZapt>&*>acZB)!RqbR-r-$U0j+EQ40 zx`GNxU`ejB*k``c&A3juuivaQ=+2H=IxkF+xCU18UTC&K1+(gPT;Gf5u0d4AM|)L^ zm7`9kOiT$ZV;&+D9O<#`Fzn!Vk*s=-C^U8jv3r&tv~&9VYjpy`oZ&=d|f4m)!v4W zF>9F92;YD(YS_NT%?6Ff`PC$w1_7oaj0~l$7NC%i6r3nxmN|Naro~KcXiLTv=nXqq z=5>?_xwP%X9v({?t^nn^q(Tus4rzjSGf5Y>adb`@=iUBu9~QgIrDY^4#DXSx4@{hOW~BD_Pch;Dy0*YgCE7ubJ0aWX#*50%oPZy_I9 zfve4@=@(qzm{OoPoTH^-Zb4{+4$~q95k1ss`IVXj4Tm;~#{M&z!%e-Ko=OQyDXRD^ zc^Pm9t{TM*nDx{lk3dAliF4MmCksD%TpqqA5}Pt z&tu9$As&vn@st(=gZp@mo{7%J-O<$*uD$PNCe0;+qM}4TSYlD9Y7;;tcmp+j0EpTJ zwo(xJhZR-Fe(h0pJ(GAuv(aU|Yu_K|?LWSbAw(FqI4ijloN4^3@ z{mZQtNqPr{w;`G;iIx7`_UIbA(-z(ixy4SPxG$OHvNLuKUKgR^U00Q}rn> z4|m0Ohl-3=mpsEcSe7dgUJ2p6l$%zHmR>z4`stqNb2sXy{YTp$Cd2}!dxy(BhBn|! z0O*>z;J{wVN)&}?f=2?WKu-3Pdl>;Ld_+0$12%--1hEnf6?KLB-Oh9rLJ5>APP=di zlefR)C$$dMwRbrU1q{5wlYMzH3{ev3VEIcexD9nF3CqeXK5FjoPJ^R!l|s*~fmx-U zf>u;TQaeFVdpC=&iy9-l_xD|k20s|h>4xXqyyLDKMsvTTh8=z$M6Tao_pKU7^1JT^i_txS$d_b2_>V_ zenyb<)&GVu+EyyR|D-MPmEO&}T57;S93ZYaE4(uqyjk9X7sBj?=_jaie3Qfff|6dg z8n`P*IgpQe>ZJ2LQq`TCX7gj6we=orHJ?fc)3j1^%S`2~@zV z=-c}*dI^;KuT_6tA9xc1Zvx;=2)r@rzv4BJ>d)t2tNwYJ;GZaeXZ~-3;jefN^!|hW z7s~%5AN~pSM)}|9{@bzMgu-9(8aVPdp#LKq{t5F&yWc2x*Pr&kPlb>5Kl}NoTKFf* zTaDi8^H!%fivCx;2Cn@L<$nnKKi9ui>#b666??1XU-24vNBrM)1 literal 0 HcmV?d00001 diff --git a/src/importexport/guitarpro/tests/guitarbendimporter_data/tied_bend.gp5 b/src/importexport/guitarpro/tests/guitarbendimporter_data/tied_bend.gp5 new file mode 100644 index 0000000000000000000000000000000000000000..531255963d53a962fae49ea79129090148e8afb1 GIT binary patch literal 1517 zcmeHH%}&BV5N`PgCE!70Vl;bMqX!gC3?zD>6oe)qq%9#HE3D913+WG$gYV({c=7CO z_z*bLrNKlGoDGwFv(sF$T zOFw}+h5IsaB67&Z`J7*W~kPy^3ODUrl_Rqil$SplUmhYo9;j&-=8=` zmpse~?RV6g#>uwtnuCCB_cTSON1#09%44!h1{GYf2Z~*JGMzi-XzURxce?kg(rD_m z44IN-SwzK*OH}4EXU2x4Kor|!j%|46#5OFls@B-Rci1qS$wKXR*BCKE@8~)0(qP^% zz;Zi)BZt2P_A}80VeXr L2. + */ + +#include + +#include "io/file.h" + +#include "engraving/tests/utils/scorerw.h" +#include "engraving/tests/utils/scorecomp.h" + +#include "engraving/dom/masterscore.h" +#include "engraving/dom/excerpt.h" + +#include "iengravingconfiguration.h" + +using namespace mu; +using namespace mu::engraving; + +static const String GUITARPRO_DIR(u"guitarbendimporter_data/"); + +namespace mu::iex::guitarpro { +extern Err importGTP(MasterScore*, muse::io::IODevice* io, const muse::modularity::ContextPtr& iocCtx, bool createLinkedTabForce = false, + bool experimental = false); +class GuitarBendImporter_Tests : public ::testing::Test, public muse::Injectable +{ +public: + muse::Inject engravingConfiguration = { this }; + + GuitarBendImporter_Tests(); + void SetUp() override; + void TearDown() override; + void gpReadTest(const String& folderName, const String& extension); +}; + +GuitarBendImporter_Tests::GuitarBendImporter_Tests() + : muse::Injectable(muse::modularity::globalCtx()) +{ +} + +void GuitarBendImporter_Tests::SetUp() +{ + engravingConfiguration()->setExperimentalGuitarBendImport(true); +} + +void GuitarBendImporter_Tests::TearDown() +{ + engravingConfiguration()->setExperimentalGuitarBendImport(false); +} + +void GuitarBendImporter_Tests::gpReadTest(const String& fileName, const String& extension) +{ + String gpFileName = GUITARPRO_DIR + fileName + u"." + extension; + String refFileName = GUITARPRO_DIR + fileName + u"-" + extension + u".mscx"; + + auto importFunc = [](MasterScore* score, const muse::io::path_t& path) -> Err { + muse::io::File file(path); + return importGTP(score, &file, muse::modularity::globalCtx(), true, true); + }; + + MasterScore* score = ScoreRW::readScore(gpFileName, false, importFunc); + EXPECT_TRUE(score); + EXPECT_TRUE(ScoreComp::saveCompareScore(score, u"guitarbend-" + fileName + u"-" + extension + u".mscx", refFileName)); + + delete score; +} + +TEST_F(GuitarBendImporter_Tests, gpSlightBend) { + gpReadTest(u"slight_bend", u"gp"); +} + +TEST_F(GuitarBendImporter_Tests, gp5SlightBend) { + gpReadTest(u"slight_bend", u"gp5"); +} + +TEST_F(GuitarBendImporter_Tests, gpPrebend) { + gpReadTest(u"prebend", u"gp"); +} + +TEST_F(GuitarBendImporter_Tests, gp5Prebend) { + gpReadTest(u"prebend", u"gp5"); +} + +TEST_F(GuitarBendImporter_Tests, gpTiedBend) { + gpReadTest(u"tied_bend", u"gp"); +} + +TEST_F(GuitarBendImporter_Tests, gp5TiedBend) { + gpReadTest(u"tied_bend", u"gp5"); +} +}