Skip to content

Commit

Permalink
Merge pull request #3587 from DavidBauer1984/time-spanning
Browse files Browse the repository at this point in the history
Improve runtime of time spanning functor
  • Loading branch information
lpugin authored Feb 2, 2024
2 parents c3da438 + dd22633 commit 8964131
Show file tree
Hide file tree
Showing 3 changed files with 55 additions and 31 deletions.
7 changes: 6 additions & 1 deletion include/vrv/preparedatafunctor.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
};

//----------------------------------------------------------------------------
Expand Down
12 changes: 5 additions & 7 deletions src/doc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}

Expand Down
67 changes: 44 additions & 23 deletions src/preparedatafunctor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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)
{
Expand All @@ -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;
}
Expand Down Expand Up @@ -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
//----------------------------------------------------------------------------
Expand Down

0 comments on commit 8964131

Please sign in to comment.