Skip to content
Permalink
Browse files
Support for slurs with timestamps (start and end)
  • Loading branch information
lpugin committed Feb 16, 2016
1 parent 20d2bba commit cfc4059
Show file tree
Hide file tree
Showing 11 changed files with 80 additions and 12 deletions.
@@ -39,6 +39,11 @@ class TimestampAttr : public LayerElement {
void SetDrawingPos(double pos) { m_actualDurPos = pos; };
///@}

/**
* Returns the duration (in double) for the Timestamp.
*/
virtual double GetTimestampAttrAlignmentDuration(int meterUnit);

private:
//
public:
@@ -111,7 +111,7 @@ void Doc::PrepareDrawing()
Functor prepareTimeSpanning(&Object::PrepareTimeSpanning);
this->Process(&prepareTimeSpanning, &params, NULL, NULL, UNLIMITED_DEPTH, BACKWARD);

// First we tried backward because nomrally the spanning elements are at the end of
// First we try backward because nomrally 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 forward
@@ -121,6 +121,7 @@ void Doc::PrepareDrawing()
this->Process(&prepareTimeSpanning, &params);
}

// Now try to match the @tstamp and @tstamp2 attributes.
params.clear();
ArrayOfDocObjectBeatPairs tstamps;
params.push_back(&timeSpanningElements);
@@ -242,6 +242,7 @@ int Layer::SetDrawingXY(ArrayPtrVoid *params)
// param 4: a pointer to the current layer
// param 5: a pointer to the view (unused)
// param 6: a bool indicating if we are processing layer elements or not
// param 7: a pointer to the functor for passing it to the timestamps (unused)
Measure **currentMeasure = static_cast<Measure **>((*params).at(2));
Layer **currentLayer = static_cast<Layer **>((*params).at(4));
bool *processLayerElements = static_cast<bool *>((*params).at(6));
@@ -36,6 +36,7 @@
#include "syl.h"
#include "tie.h"
#include "timeinterface.h"
#include "timestamp.h"
#include "tuplet.h"
#include "verse.h"
#include "view.h"
@@ -213,6 +214,13 @@ double LayerElement::GetAlignmentDuration(Mensur *mensur, MeterSig *meterSig, bo
if (meterSig) meterSig->GetUnit();
return beatRpt->GetBeatRptAlignmentDuration(meterUnit);
}
else if (this->Is() == TIMESTAMP_ATTR) {
TimestampAttr *timestampAttr = dynamic_cast<TimestampAttr *>(this);
assert(timestampAttr);
int meterUnit = 4;
if (meterSig) meterSig->GetUnit();
return timestampAttr->GetTimestampAttrAlignmentDuration(meterUnit);
}
else {
return 0.0;
}
@@ -330,7 +338,13 @@ int LayerElement::AlignHorizontally(ArrayPtrVoid *params)
// get the duration of the event
double duration = this->GetAlignmentDuration(*currentMensur);

(*measureAligner)->SetMaxTime((*time) + duration);
// For timestamp, what we get from GetAlignmentDuration is actually the position of the timestamp
// So use it as current time - we can do this because the timestamp loop is redirected from the measure
// The time will be reset to 0.0 when starting a new layer anyway
if (this->Is() == TIMESTAMP_ATTR)
(*time) = duration;
else
(*measureAligner)->SetMaxTime((*time) + duration);

m_alignment = (*measureAligner)->GetAlignmentAtTime(*time, type);

@@ -341,8 +355,10 @@ int LayerElement::AlignHorizontally(ArrayPtrVoid *params)

// LogDebug("AlignHorizontally: Time %f - %s", (*time), this->GetClassName().c_str());

// increase the time position
(*time) += duration;
// increase the time position, but only when not a timestamp (it would actually do nothing)
if (this->Is() != TIMESTAMP_ATTR) {
(*time) += duration;
}

return FUNCTOR_CONTINUE;
}
@@ -378,6 +394,7 @@ int LayerElement::SetDrawingXY(ArrayPtrVoid *params)
// param 4: a pointer to the current layer
// param 5: a pointer to the view
// param 6: a bool indicating if we are processing layer elements or not
// param 7: a pointer to the functor for passing it to the timestamps (unused)
Doc *doc = static_cast<Doc *>((*params).at(0));
Measure **currentMeasure = static_cast<Measure **>((*params).at(2));
Staff **currentStaff = static_cast<Staff **>((*params).at(3));
@@ -156,6 +156,7 @@ int Measure::AlignHorizontally(ArrayPtrVoid *params)
// param 2: the current Mensur (unused)
// param 3: the current MeterSig (unused)
MeasureAligner **measureAligner = static_cast<MeasureAligner **>((*params).at(0));
Functor *alignHorizontally = static_cast<Functor *>((*params).at(4));

// clear the content of the measureAligner
m_measureAligner.Reset();
@@ -167,6 +168,9 @@ int Measure::AlignHorizontally(ArrayPtrVoid *params)
// point to it
(*measureAligner) = &m_measureAligner;

// We also need to align the timestamps
m_timestampAligner.Process(alignHorizontally, params);

if (m_leftBarLine.GetForm() != BARRENDITION_NONE) {
m_leftBarLine.SetAlignment(m_measureAligner.GetLeftAlignment());
}
@@ -318,15 +322,21 @@ int Measure::SetDrawingXY(ArrayPtrVoid *params)
// param 4: a pointer to the current layer (unused)
// param 5: a pointer to the view (unused)
// param 6: a bool indicating if we are processing layer elements or not
// param 7: a pointer to the functor for passing it to the timestamps
Doc *doc = static_cast<Doc *>((*params).at(0));
System **currentSystem = static_cast<System **>((*params).at(1));
Measure **currentMeasure = static_cast<Measure **>((*params).at(2));
bool *processLayerElements = static_cast<bool *>((*params).at(6));
Functor *setDrawingXY = static_cast<Functor *>((*params).at(7));

(*currentMeasure) = this;

// Second pass where we do just process layer elements
if ((*processLayerElements)) return FUNCTOR_CONTINUE;
if ((*processLayerElements)) {
// However, we need to process the timestamps
m_timestampAligner.Process(setDrawingXY, params);
return FUNCTOR_CONTINUE;
}

// Here we set the appropriate y value to be used for drawing
// With Raw documents, we use m_drawingXRel that is calculated by the layout algorithm
@@ -340,6 +350,10 @@ int Measure::SetDrawingXY(ArrayPtrVoid *params)
this->SetDrawingX(this->m_xAbs);
}

// Process the timestamps - we can do it already since the first pass in only taking care of X position for the
// LayerElements
m_timestampAligner.Process(setDrawingXY, params);

// For avoiding unused variable warning in non debug mode
doc = NULL;

@@ -384,6 +398,15 @@ int Measure::PrepareTimestampsEnd(ArrayPtrVoid *params)
assert(interface);
TimestampAttr *timestampAttr = m_timestampAligner.GetTimestampAtTime((*iter).second.second);
interface->SetStart(timestampAttr);
// purge the list of unmatched element is this is a TimeSpanningInterface element
if ((*iter).first->HasInterface(INTERFACE_TIME_SPANNING)) {
TimeSpanningInterface *tsInterface = dynamic_cast<TimeSpanningInterface *>((*iter).first);
assert(tsInterface);
if (tsInterface->HasStartAndEnd()) {
elements->erase(std::remove(elements->begin(), elements->end(), (*iter).first), elements->end());
}
}
// remove it
iter = tstamps->erase(iter);
}
// 0 means that we have a @tstamp2 (end) to add to the current measure
@@ -392,7 +415,7 @@ int Measure::PrepareTimestampsEnd(ArrayPtrVoid *params)
assert(interface);
TimestampAttr *timestampAttr = m_timestampAligner.GetTimestampAtTime((*iter).second.second);
interface->SetEnd(timestampAttr);
// We can check if the interface is now fully mapped (start / end)
// We can check if the interface is now fully mapped (start / end) and purge the list of unmatched elements
if (interface->HasStartAndEnd()) {
elements->erase(std::remove(elements->begin(), elements->end(), (*iter).first), elements->end());
}
@@ -405,8 +428,6 @@ int Measure::PrepareTimestampsEnd(ArrayPtrVoid *params)
}
}

LogMessage("%d", tstamps->size());

return FUNCTOR_CONTINUE;
};

@@ -115,6 +115,8 @@ void Page::LayOutHorizontally()
params.push_back(&currentMeterSig);
Functor alignHorizontally(&Object::AlignHorizontally);
Functor alignHorizontallyEnd(&Object::AlignHorizontallyEnd);
// Pass the functor for processing the timestamps
params.push_back(&alignHorizontally);
this->Process(&alignHorizontally, &params, &alignHorizontallyEnd);

// Unless duration-based spacing is disabled, set the X position of each Alignment.
@@ -186,6 +186,7 @@ int Staff::SetDrawingXY(ArrayPtrVoid *params)
// param 4: a pointer to the current layer (unused)
// param 5: a pointer to the view (unused)
// param 6: a bool indicating if we are processing layer elements or not
// param 7: a pointer to the functor for passing it to the timestamps (unused)
Doc *doc = static_cast<Doc *>((*params).at(0));
System **currentSystem = static_cast<System **>((*params).at(1));
Staff **currentStaff = static_cast<Staff **>((*params).at(3));
@@ -296,6 +296,7 @@ int System::SetDrawingXY(ArrayPtrVoid *params)
// param 4: a pointer to the current layer
// param 5: a pointer to the view (unused)
// param 6: a bool indicating if we are processing layer elements or not
// param 7: a pointer to the functor for passing it to the timestamps (unused)
Doc *doc = static_cast<Doc *>((*params).at(0));
System **currentSystem = static_cast<System **>((*params).at(1));
bool *processLayerElements = static_cast<bool *>((*params).at(6));
@@ -35,4 +35,9 @@ void TimestampAttr::Reset()
m_actualDurPos = 0.0;
}

double TimestampAttr::GetTimestampAttrAlignmentDuration(int meterUnit)
{
return DUR_MAX / meterUnit * m_actualDurPos;
}

} // namespace vrv
@@ -207,8 +207,21 @@ void View::DrawSlur(DeviceContext *dc, Slur *slur, int x1, int x2, Staff *staff,
endStemDir = endChord->GetDrawingStemDir();
}

Layer *layer1 = dynamic_cast<Layer *>(start->GetFirstParent(LAYER));
Layer *layer2 = dynamic_cast<Layer *>(end->GetFirstParent(LAYER));
Layer *layer1 = NULL;
Layer *layer2 = NULL;

// For now, with timestamps, get the first layer. We should eventually look at the @layerident (not implemented)
if (start->Is() == TIMESTAMP_ATTR)
layer1 = dynamic_cast<Layer *>(staff->FindChildByType(LAYER));
else
layer1 = dynamic_cast<Layer *>(start->GetFirstParent(LAYER));

// idem
if (end->Is() == TIMESTAMP_ATTR)
layer2 = dynamic_cast<Layer *>(staff->FindChildByType(LAYER));
else
layer2 = dynamic_cast<Layer *>(end->GetFirstParent(LAYER));

assert(layer1 && layer2);

if (layer1->GetN() != layer2->GetN()) {
@@ -364,13 +377,13 @@ void View::DrawSlur(DeviceContext *dc, Slur *slur, int x1, int x2, Staff *staff,
}

// Positions not attached to a note
if (spanningType == SPANNING_START) {
if ((spanningType == SPANNING_START) || (end->Is() == TIMESTAMP_ATTR)) {
if (up)
y2 = std::max(staff->GetDrawingY(), y1);
else
y2 = std::min(staff->GetDrawingY() - m_doc->GetDrawingStaffSize(staff->m_drawingStaffSize), y1);
}
else if (spanningType == SPANNING_END) {
else if ((spanningType == SPANNING_END) || (start->Is() == TIMESTAMP_ATTR)) {
if (up)
y1 = std::max(staff->GetDrawingY(), y2);
else
@@ -63,6 +63,7 @@ void View::DrawCurrentPage(DeviceContext *dc, bool background)
params.push_back(this);
params.push_back(&processLayerElement);
Functor setDrawingXY(&Object::SetDrawingXY);
params.push_back(&setDrawingXY);
// First pass without processing the LayerElements - we need this for cross-staff going down because
// the elements will need the position of the staff below to have been set before
m_currentPage->Process(&setDrawingXY, &params);

0 comments on commit cfc4059

Please sign in to comment.