From 07b47b94d7d88426f2cd112a15ba8e5f1d3cefe2 Mon Sep 17 00:00:00 2001 From: Calum Matheson Date: Fri, 14 Feb 2025 13:12:24 +0000 Subject: [PATCH] Percussion panel - fix layout reset for Muse Sampler drumsets --- .../utilities/percussionutilities.cpp | 17 +++++++ src/notation/utilities/percussionutilities.h | 2 + .../percussionpanel/percussionpanelmodel.cpp | 49 ++++++++++++++++--- .../percussionpanel/percussionpanelmodel.h | 4 ++ .../percussionpanelpadlistmodel.cpp | 12 ++--- .../percussionpanelpadlistmodel.h | 2 +- src/playback/internal/drumsetloader.cpp | 22 +-------- 7 files changed, 75 insertions(+), 33 deletions(-) diff --git a/src/notation/utilities/percussionutilities.cpp b/src/notation/utilities/percussionutilities.cpp index f6f0157fdace3..ab23df77ef6f0 100644 --- a/src/notation/utilities/percussionutilities.cpp +++ b/src/notation/utilities/percussionutilities.cpp @@ -33,6 +33,23 @@ using namespace mu::notation; using namespace mu::engraving; +void PercussionUtilities::readDrumset(const muse::ByteArray& drumMapping, Drumset& drumset) +{ + XmlReader reader(drumMapping); + + while (reader.readNextStartElement()) { + if (reader.name() == "museScore") { + while (reader.readNextStartElement()) { + if (reader.name() == "Drum") { + drumset.load(reader); + } else { + reader.unknown(); + } + } + } + } +} + /// Returns a drum note prepared for preview. std::shared_ptr PercussionUtilities::getDrumNoteForPreview(const Drumset* drumset, int pitch) { diff --git a/src/notation/utilities/percussionutilities.h b/src/notation/utilities/percussionutilities.h index 63fe071c9f89f..bfceb2c06d1af 100644 --- a/src/notation/utilities/percussionutilities.h +++ b/src/notation/utilities/percussionutilities.h @@ -28,6 +28,7 @@ #include "iinteractive.h" #include "engraving/rendering/isinglerenderer.h" +#include "engraving/rw/xmlreader.h" #include "engraving/dom/chord.h" #include "engraving/dom/drumset.h" @@ -45,6 +46,7 @@ class PercussionUtilities INJECT_STATIC(mu::engraving::rendering::ISingleRenderer, engravingRender) public: + static void readDrumset(const muse::ByteArray& drumMapping, mu::engraving::Drumset& drumset); static std::shared_ptr getDrumNoteForPreview(const mu::engraving::Drumset* drumset, int pitch); static void editPercussionShortcut(mu::engraving::Drumset& drumset, int originPitch); diff --git a/src/notation/view/percussionpanel/percussionpanelmodel.cpp b/src/notation/view/percussionpanel/percussionpanelmodel.cpp index e035fb5bf92e8..1c8f257030e3c 100644 --- a/src/notation/view/percussionpanel/percussionpanelmodel.cpp +++ b/src/notation/view/percussionpanel/percussionpanelmodel.cpp @@ -490,16 +490,14 @@ void PercussionPanelModel::resetLayout() Instrument* inst = instAndPart.first; Part* part = instAndPart.second; - IF_ASSERT_FAILED(inst && inst->drumset() && part) { + IF_ASSERT_FAILED(audioSettings() && inst && part) { return; } - const InstrumentTemplate& instTemplate = instrumentsRepository()->instrumentTemplate(inst->id()); - const Drumset* defaultDrumset = instTemplate.drumset; + const muse::audio::AudioResourceMeta& resourceMeta = audioSettings()->trackInputParams(currentTrackId()).resourceMeta; + const bool isMuseSamplerDrumset = resourceMeta.type == muse::audio::AudioResourceType::MuseSamplerSoundPack; - IF_ASSERT_FAILED(defaultDrumset) { - return; - } + Drumset defaultDrumset = isMuseSamplerDrumset ? museSamplerDefaultDrumset() : standardDefaultDrumset(); Drumset defaultLayout = m_padListModel->constructDefaultLayout(defaultDrumset); if (defaultLayout == *m_padListModel->drumset()) { @@ -514,6 +512,45 @@ void PercussionPanelModel::resetLayout() undoStack->commitChanges(); } +Drumset PercussionPanelModel::standardDefaultDrumset() const +{ + const std::pair instAndPart = getCurrentInstrumentAndPart(); + const Instrument* inst = instAndPart.first; + const Part* part = instAndPart.second; + + IF_ASSERT_FAILED(inst && inst->drumset() && part) { + return Drumset(); + } + + const InstrumentTemplate& instTemplate = instrumentsRepository()->instrumentTemplate(inst->id()); + IF_ASSERT_FAILED(instTemplate.drumset) { + return Drumset(); + } + + return *instTemplate.drumset; +} + +Drumset PercussionPanelModel::museSamplerDefaultDrumset() const +{ + IF_ASSERT_FAILED(audioSettings()) { + return Drumset(); + } + + const muse::audio::AudioResourceMeta& resourceMeta = audioSettings()->trackInputParams(currentTrackId()).resourceMeta; + + const int instrumentId = resourceMeta.attributeVal(u"museUID").toInt(); + + const muse::ByteArray drumMapping = museSampler()->drumMapping(instrumentId); + IF_ASSERT_FAILED(!drumMapping.empty()) { + return Drumset(); + } + + Drumset defaultDrumset; + PercussionUtilities::readDrumset(drumMapping, defaultDrumset); + + return defaultDrumset; +} + InstrumentTrackId PercussionPanelModel::currentTrackId() const { if (!interaction()) { diff --git a/src/notation/view/percussionpanel/percussionpanelmodel.h b/src/notation/view/percussionpanel/percussionpanelmodel.h index d7ee970f73e5d..c6c2b503d8e99 100644 --- a/src/notation/view/percussionpanel/percussionpanelmodel.h +++ b/src/notation/view/percussionpanel/percussionpanelmodel.h @@ -30,6 +30,7 @@ #include "context/iglobalcontext.h" #include "actions/iactionsdispatcher.h" #include "playback/iplaybackcontroller.h" +#include "musesampler/imusesamplerinfo.h" #include "iinstrumentsrepository.h" #include "inotationconfiguration.h" @@ -54,6 +55,7 @@ class PercussionPanelModel : public QObject, public muse::Injectable, public mus muse::Inject globalContext = { this }; muse::Inject dispatcher = { this }; muse::Inject playbackController = { this }; + muse::Inject museSampler; muse::Inject instrumentsRepository = { this }; muse::Inject configuration = { this }; @@ -126,6 +128,8 @@ class PercussionPanelModel : public QObject, public muse::Injectable, public mus void playPitch(int pitch); void resetLayout(); + Drumset standardDefaultDrumset() const; + Drumset museSamplerDefaultDrumset() const; mu::engraving::InstrumentTrackId currentTrackId() const; diff --git a/src/notation/view/percussionpanel/percussionpanelpadlistmodel.cpp b/src/notation/view/percussionpanel/percussionpanelpadlistmodel.cpp index 2c24444cce3b4..b14686f2b7bae 100644 --- a/src/notation/view/percussionpanel/percussionpanelpadlistmodel.cpp +++ b/src/notation/view/percussionpanel/percussionpanelpadlistmodel.cpp @@ -179,7 +179,7 @@ void PercussionPanelPadListModel::setDrumset(const engraving::Drumset* drumset) removeEmptyRows(); } -mu::engraving::Drumset PercussionPanelPadListModel::constructDefaultLayout(const engraving::Drumset* defaultDrumset) const +mu::engraving::Drumset PercussionPanelPadListModel::constructDefaultLayout(const engraving::Drumset& defaultDrumset) const { //! NOTE: The idea of this method is take a "default" (template) drumset, find matching drums in the current drumset, and evaluate/return //! the default panel layout based on this information. The reason we can't simply revert to the default drumset in its entirety is that @@ -192,20 +192,20 @@ mu::engraving::Drumset PercussionPanelPadListModel::constructDefaultLayout(const QList noTemplateFound; for (int pitch = 0; pitch < mu::engraving::DRUM_INSTRUMENTS; ++pitch) { - if (defaultDrumset->isValid(pitch) && !defaultLayout.isValid(pitch)) { + if (defaultDrumset.isValid(pitch) && !defaultLayout.isValid(pitch)) { // Pitch was deleted - restore it... - defaultLayout.drum(pitch) = defaultDrumset->drum(pitch); + defaultLayout.drum(pitch) = defaultDrumset.drum(pitch); continue; } //! NOTE: Pitch + drum name isn't exactly the most robust identifier, but this will probably change with the new percussion ID system - if (!defaultDrumset->isValid(pitch) || defaultLayout.name(pitch) != defaultDrumset->name(pitch)) { + if (!defaultDrumset.isValid(pitch) || defaultLayout.name(pitch) != defaultDrumset.name(pitch)) { // Drum is valid, but we can't find a template for it. Set the position chromatically later... noTemplateFound.emplaceBack(pitch); continue; } - const int templateRow = defaultDrumset->drum(pitch).panelRow; - const int templateColumn = defaultDrumset->drum(pitch).panelColumn; + const int templateRow = defaultDrumset.drum(pitch).panelRow; + const int templateColumn = defaultDrumset.drum(pitch).panelColumn; defaultLayout.drum(pitch).panelRow = templateRow; defaultLayout.drum(pitch).panelColumn = templateColumn; diff --git a/src/notation/view/percussionpanel/percussionpanelpadlistmodel.h b/src/notation/view/percussionpanel/percussionpanelpadlistmodel.h index 0920dc3b40df2..74849f3c38741 100644 --- a/src/notation/view/percussionpanel/percussionpanelpadlistmodel.h +++ b/src/notation/view/percussionpanel/percussionpanelpadlistmodel.h @@ -77,7 +77,7 @@ class PercussionPanelPadListModel : public QAbstractListModel, public muse::Inje QList padList() const { return m_padModels; } - mu::engraving::Drumset constructDefaultLayout(const engraving::Drumset* templateDrumset) const; + mu::engraving::Drumset constructDefaultLayout(const engraving::Drumset& templateDrumset) const; int nextAvailableIndex(int pitch) const; //! NOTE: This may be equal to m_padModels.size() int nextAvailablePitch(int pitch) const; diff --git a/src/playback/internal/drumsetloader.cpp b/src/playback/internal/drumsetloader.cpp index 34350f0e11e16..f91f1e609e223 100644 --- a/src/playback/internal/drumsetloader.cpp +++ b/src/playback/internal/drumsetloader.cpp @@ -23,8 +23,7 @@ #include "drumsetloader.h" #include "notation/notationtypes.h" - -#include "engraving/rw/xmlreader.h" +#include "notation/utilities/percussionutilities.h" #include "global/types/bytearray.h" @@ -33,23 +32,6 @@ using namespace muse::audio; using namespace mu::notation; using namespace mu::engraving; -static void readDrumset(const muse::ByteArray& drumMapping, Drumset& drumset) -{ - XmlReader reader(drumMapping); - - while (reader.readNextStartElement()) { - if (reader.name() == "museScore") { - while (reader.readNextStartElement()) { - if (reader.name() == "Drum") { - drumset.load(reader); - } else { - reader.unknown(); - } - } - } - } -} - void DrumsetLoader::loadDrumset(INotationPtr notation, const InstrumentTrackId& trackId, const AudioResourceMeta& resourceMeta) { TRACEFUNC; @@ -93,7 +75,7 @@ void DrumsetLoader::loadDrumset(INotationPtr notation, const InstrumentTrackId& } Drumset drumset; - readDrumset(drumMapping, drumset); + PercussionUtilities::readDrumset(drumMapping, drumset); replaceDrumset(notation, trackId, drumset); m_drumsetCache.emplace(instrumentId, std::move(drumset));