From a6d436ea0d358afc35fc4aadf3b8809be7f39ef5 Mon Sep 17 00:00:00 2001 From: David Bauer Date: Mon, 29 Jan 2024 21:04:32 +0100 Subject: [PATCH 1/2] Run forward twice --- src/doc.cpp | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/src/doc.cpp b/src/doc.cpp index e6c4313ba15..5f36ed7264a 100644 --- a/src/doc.cpp +++ b/src/doc.cpp @@ -609,18 +609,16 @@ void Doc::PrepareData() // Try to match all spanning elements (slur, tie, etc) by processing backwards PrepareTimeSpanningFunctor prepareTimeSpanning; - prepareTimeSpanning.SetDirection(BACKWARD); this->Process(prepareTimeSpanning); prepareTimeSpanning.SetDataCollectionCompleted(); - // First we try backwards because normally the spanning elements are at the end of - // the measure. However, in some case, one (or both) end points will appear afterwards - // in the encoding. For these, the previous iteration will not have resolved the link and - // the spanning elements will remain in the timeSpanningElements array. We try again forwards - // but this time without filling the list (that is only will the remaining elements) + // First we try a forward pass which should collect most of the spanning elements. + // However, in some cases, one (or both) end points might appear a few measures + // before the spanning element in the encoding. For these, the previous iteration will not have resolved the link + // and the spanning elements will remain in the timeSpanningElements array. We try again forwards but this time + // without filling the list (that is only resolving remaining elements). const ListOfSpanningInterOwnerPairs &interfaceOwnerPairs = prepareTimeSpanning.GetInterfaceOwnerPairs(); if (!interfaceOwnerPairs.empty()) { - prepareTimeSpanning.SetDirection(FORWARD); this->Process(prepareTimeSpanning); } From dd226338a6075a0cc8eb0eb7937dc5669df14231 Mon Sep 17 00:00:00 2001 From: David Bauer Date: Tue, 30 Jan 2024 22:05:17 +0100 Subject: [PATCH 2/2] Collect all time spanning descendants on first measure visit --- include/vrv/preparedatafunctor.h | 7 +++- src/preparedatafunctor.cpp | 67 +++++++++++++++++++++----------- 2 files changed, 50 insertions(+), 24 deletions(-) diff --git a/include/vrv/preparedatafunctor.h b/include/vrv/preparedatafunctor.h index 793d1e66c0e..1a185a7ba7c 100644 --- a/include/vrv/preparedatafunctor.h +++ b/include/vrv/preparedatafunctor.h @@ -493,18 +493,23 @@ class PrepareTimeSpanningFunctor : public Functor, public CollectAndProcess { FunctorCode VisitF(F *f) override; FunctorCode VisitFloatingObject(FloatingObject *floatingObject) override; FunctorCode VisitLayerElement(LayerElement *layerElement) override; + FunctorCode VisitMeasure(Measure *measure) override; FunctorCode VisitMeasureEnd(Measure *measure) override; ///@} protected: // private: - // + // Delegates to the pseudo functor of the interface + FunctorCode CallPseudoFunctor(Object *timeSpanningObject); + public: // private: // The interface list that holds the current elements to match ListOfSpanningInterOwnerPairs m_timeSpanningInterfaces; + // Indicates whether we currently traverse a measure + bool m_insideMeasure; }; //---------------------------------------------------------------------------- diff --git a/src/preparedatafunctor.cpp b/src/preparedatafunctor.cpp index 98b7b07152e..2d9226da362 100644 --- a/src/preparedatafunctor.cpp +++ b/src/preparedatafunctor.cpp @@ -650,7 +650,10 @@ FunctorCode PrepareTimePointingFunctor::VisitMeasureEnd(Measure *measure) // PrepareTimeSpanningFunctor //---------------------------------------------------------------------------- -PrepareTimeSpanningFunctor::PrepareTimeSpanningFunctor() : Functor(), CollectAndProcess() {} +PrepareTimeSpanningFunctor::PrepareTimeSpanningFunctor() : Functor(), CollectAndProcess() +{ + m_insideMeasure = false; +} void PrepareTimeSpanningFunctor::InsertInterfaceOwnerPair(Object *owner, TimeSpanningInterface *interface) { @@ -659,19 +662,16 @@ void PrepareTimeSpanningFunctor::InsertInterfaceOwnerPair(Object *owner, TimeSpa FunctorCode PrepareTimeSpanningFunctor::VisitF(F *f) { - // Pass it to the pseudo functor of the interface - TimeSpanningInterface *interface = f->GetTimeSpanningInterface(); - assert(interface); - return interface->InterfacePrepareTimeSpanning(*this, f); + if (!m_insideMeasure) { + return this->CallPseudoFunctor(f); + } + return FUNCTOR_CONTINUE; } FunctorCode PrepareTimeSpanningFunctor::VisitFloatingObject(FloatingObject *floatingObject) { - // Pass it to the pseudo functor of the interface - if (floatingObject->HasInterface(INTERFACE_TIME_SPANNING)) { - TimeSpanningInterface *interface = floatingObject->GetTimeSpanningInterface(); - assert(interface); - return interface->InterfacePrepareTimeSpanning(*this, floatingObject); + if (!m_insideMeasure && floatingObject->HasInterface(INTERFACE_TIME_SPANNING)) { + return this->CallPseudoFunctor(floatingObject); } return FUNCTOR_CONTINUE; } @@ -699,28 +699,49 @@ FunctorCode PrepareTimeSpanningFunctor::VisitLayerElement(LayerElement *layerEle return FUNCTOR_CONTINUE; } -FunctorCode PrepareTimeSpanningFunctor::VisitMeasureEnd(Measure *measure) +FunctorCode PrepareTimeSpanningFunctor::VisitMeasure(Measure *measure) { - if (this->IsProcessingData()) { - return FUNCTOR_CONTINUE; + if (this->IsCollectingData()) { + ListOfObjects timeSpanningObjects; + InterfaceComparison ic(INTERFACE_TIME_SPANNING); + measure->FindAllDescendantsByComparison(&timeSpanningObjects, &ic); + for (Object *object : timeSpanningObjects) { + this->CallPseudoFunctor(object); + } } + m_insideMeasure = true; - ListOfSpanningInterOwnerPairs::iterator iter = m_timeSpanningInterfaces.begin(); - while (iter != m_timeSpanningInterfaces.end()) { - // At the end of the measure (going backward) we remove elements for which we do not need to match the end (for - // now). Eventually, we could consider them, for example if we want to display their spanning or for improved - // midi output - if (iter->second->GetClassId() == HARM) { - iter = m_timeSpanningInterfaces.erase(iter); - } - else { - ++iter; + return FUNCTOR_CONTINUE; +} + +FunctorCode PrepareTimeSpanningFunctor::VisitMeasureEnd(Measure *measure) +{ + if (this->IsCollectingData()) { + ListOfSpanningInterOwnerPairs::iterator iter = m_timeSpanningInterfaces.begin(); + while (iter != m_timeSpanningInterfaces.end()) { + // At the end of the measure we remove elements for which we do not need to match the end (for now). + // Eventually, we could consider them, for example if we want to display their spanning or for + // improved midi output + if (iter->second->GetClassId() == HARM) { + iter = m_timeSpanningInterfaces.erase(iter); + } + else { + ++iter; + } } } + m_insideMeasure = false; return FUNCTOR_CONTINUE; } +FunctorCode PrepareTimeSpanningFunctor::CallPseudoFunctor(Object *timeSpanningObject) +{ + TimeSpanningInterface *interface = timeSpanningObject->GetTimeSpanningInterface(); + assert(interface); + return interface->InterfacePrepareTimeSpanning(*this, timeSpanningObject); +} + //---------------------------------------------------------------------------- // PrepareTimestampsFunctor //----------------------------------------------------------------------------