Skip to content

Commit

Permalink
Merge pull request #3905 from rism-digital/develop-lyrics
Browse files Browse the repository at this point in the history
Lyric improvements
ahankinson authored Jan 6, 2025
2 parents e535b90 + 8ed9ef4 commit f352406
Showing 15 changed files with 136 additions and 49 deletions.
1 change: 1 addition & 0 deletions include/vrv/options.h
Original file line number Diff line number Diff line change
@@ -714,6 +714,7 @@ class Options {
OptionDbl m_ledgerLineThickness;
OptionDbl m_ledgerLineExtension;
OptionIntMap m_lyricElision;
OptionDbl m_lyricHeightFactor;
OptionDbl m_lyricLineThickness;
OptionBool m_lyricNoStartHyphen;
OptionDbl m_lyricSize;
4 changes: 3 additions & 1 deletion include/vrv/syl.h
Original file line number Diff line number Diff line change
@@ -118,7 +118,9 @@ class Syl : public LayerElement,
* The verse number with multiple verses
* Value is 1 by default, set in PrepareLyrics
*/
int m_drawingVerse;
int m_drawingVerseN;
/** The verse place (below by default) */
data_STAFFREL m_drawingVersePlace;

/**
* A pointer to the next syllable of the word.
7 changes: 6 additions & 1 deletion include/vrv/verse.h
Original file line number Diff line number Diff line change
@@ -20,7 +20,12 @@ class Syl;
// Verse
//----------------------------------------------------------------------------

class Verse : public LayerElement, public AttColor, public AttLang, public AttNInteger, public AttTypography {
class Verse : public LayerElement,
public AttColor,
public AttLang,
public AttNInteger,
public AttPlacementRelStaff,
public AttTypography {
public:
/**
* @name Constructors, destructors, and other standard methods
12 changes: 8 additions & 4 deletions include/vrv/verticalaligner.h
Original file line number Diff line number Diff line change
@@ -195,9 +195,12 @@ class StaffAlignment : public Object {
* The position is calculated from the bottom.
*/
///@{
void AddVerseN(int verseN);
void AddVerseN(int verseN, data_STAFFREL place);
int GetVerseCount(bool collapse) const;
int GetVersePosition(int verseN, bool collapse) const;
int GetVerseCountAbove(bool collapse) const;
int GetVerseCountBelow(bool collapse) const;
int GetVersePositionAbove(int verseN, bool collapse) const;
int GetVersePositionBelow(int verseN, bool collapse) const;
///@}

/**
@@ -402,9 +405,10 @@ class StaffAlignment : public Object {
*/
int m_yRel;
/**
* Stores the verse@n of the staves attached to the aligner
* Stores the verse@n of the staves attached to the aligner (above and below)
*/
std::set<int> m_verseNs;
std::set<int> m_verseAboveNs;
std::set<int> m_verseBelowNs;

/**
* @name values for storing the overflow and overlap
2 changes: 1 addition & 1 deletion include/vrv/view.h
Original file line number Diff line number Diff line change
@@ -624,7 +624,7 @@ class View {
std::u32string IntToTimeSigFigures(unsigned short number);
std::u32string IntToSmuflFigures(unsigned short number, int offset);
int NestedTuplets(Object *object);
int GetSylYRel(int verseN, Staff *staff);
int GetSylYRel(int verseN, Staff *staff, data_STAFFREL place);
int GetFYRel(F *f, Staff *staff);
///@}

36 changes: 25 additions & 11 deletions src/adjustfloatingpositionerfunctor.cpp
Original file line number Diff line number Diff line change
@@ -34,20 +34,34 @@ FunctorCode AdjustFloatingPositionersFunctor::VisitStaffAlignment(StaffAlignment

staffAlignment->SortPositioners();

const bool verseCollapse = m_doc->GetOptions()->m_lyricVerseCollapse.GetValue();
if (m_classId == SYL) {
const bool verseCollapse = m_doc->GetOptions()->m_lyricVerseCollapse.GetValue();
if (staffAlignment->GetVerseCount(verseCollapse) > 0) {
FontInfo *lyricFont = m_doc->GetDrawingLyricFont(staffAlignment->GetStaff()->m_drawingStaffSize);
int descender = m_doc->GetTextGlyphDescender(L'q', lyricFont, false);
int height = m_doc->GetTextGlyphHeight(L'I', lyricFont, false);
int margin = m_doc->GetBottomMargin(SYL) * drawingUnit;
int minMargin = std::max((int)(m_doc->GetOptions()->m_lyricTopMinMargin.GetValue() * drawingUnit),
staffAlignment->GetOverflowBelow());
staffAlignment->SetOverflowBelow(
minMargin + staffAlignment->GetVerseCount(verseCollapse) * (height - descender + margin));
// For now just clear the overflowBelow, which avoids the overlap to be calculated. We could also keep them
// and check if they are some lyrics in order to know if the overlap needs to be calculated or not.
staffAlignment->ClearBBoxesBelow();
int verseHeight = m_doc->GetTextGlyphHeight(L'I', lyricFont, false)
- m_doc->GetTextGlyphDescender(L'q', lyricFont, false);
verseHeight *= m_doc->GetOptions()->m_lyricHeightFactor.GetValue();
if (staffAlignment->GetVerseCountAbove(verseCollapse)) {
int margin = m_doc->GetTopMargin(SYL) * drawingUnit;
int minMargin = std::max((int)(m_doc->GetOptions()->m_lyricTopMinMargin.GetValue() * drawingUnit),
staffAlignment->GetOverflowAbove());
staffAlignment->SetOverflowAbove(
minMargin + staffAlignment->GetVerseCountAbove(verseCollapse) * (verseHeight + margin));
// For now just clear the overflowBelow, which avoids the overlap to be calculated. We could also keep
// them and check if they are some lyrics in order to know if the overlap needs to be calculated or not.
staffAlignment->ClearBBoxesAbove();
}
if (staffAlignment->GetVerseCountBelow(verseCollapse)) {
int margin = m_doc->GetBottomMargin(SYL) * drawingUnit;
int minMargin = std::max((int)(m_doc->GetOptions()->m_lyricTopMinMargin.GetValue() * drawingUnit),
staffAlignment->GetOverflowBelow());
staffAlignment->SetOverflowBelow(
minMargin + staffAlignment->GetVerseCountBelow(verseCollapse) * (verseHeight + margin));
// For now just clear the overflowBelow, which avoids the overlap to be calculated. We could also keep
// them and check if there are some lyrics in order to know if the overlap needs to be calculated or
// not.
staffAlignment->ClearBBoxesBelow();
}
}
return FUNCTOR_SIBLINGS;
}
18 changes: 11 additions & 7 deletions src/alignfunctor.cpp
Original file line number Diff line number Diff line change
@@ -640,9 +640,9 @@ FunctorCode AlignVerticallyFunctor::VisitStaff(Staff *staff)
std::vector<Object *>::const_iterator verseIterator = std::find_if(
staff->m_timeSpanningElements.begin(), staff->m_timeSpanningElements.end(), ObjectComparison(VERSE));
if (verseIterator != staff->m_timeSpanningElements.end()) {
Verse *v = vrv_cast<Verse *>(*verseIterator);
assert(v);
alignment->AddVerseN(v->GetN());
Verse *verse = vrv_cast<Verse *>(*verseIterator);
assert(verse);
alignment->AddVerseN(verse->GetN(), verse->GetPlace());
}

// add verse number to alignment in case there are spanning SYL elements but there is no verse number already - this
@@ -653,9 +653,13 @@ FunctorCode AlignVerticallyFunctor::VisitStaff(Staff *staff)
Verse *verse = vrv_cast<Verse *>((*sylIterator)->GetFirstAncestor(VERSE));
if (verse) {
const int verseNumber = verse->GetN();
const data_STAFFREL versePlace = verse->GetPlace();
const bool verseCollapse = m_doc->GetOptions()->m_lyricVerseCollapse.GetValue();
if (!alignment->GetVersePosition(verseNumber, verseCollapse)) {
alignment->AddVerseN(verseNumber);
if ((versePlace == STAFFREL_above) && !alignment->GetVersePositionAbove(verseNumber, verseCollapse)) {
alignment->AddVerseN(verseNumber, verse->GetPlace());
}
if ((versePlace != STAFFREL_above) && !alignment->GetVersePositionBelow(verseNumber, verseCollapse)) {
alignment->AddVerseN(verseNumber, verse->GetPlace());
}
}
}
@@ -685,7 +689,7 @@ FunctorCode AlignVerticallyFunctor::VisitSyllable(Syllable *syllable)
StaffAlignment *alignment = m_systemAligner->GetStaffAlignmentForStaffN(m_staffN);
if (!alignment) return FUNCTOR_CONTINUE;
// Current limitation of only one syl (verse n) by syllable
alignment->AddVerseN(1);
alignment->AddVerseN(1, STAFFREL_below);

return FUNCTOR_CONTINUE;
}
@@ -720,7 +724,7 @@ FunctorCode AlignVerticallyFunctor::VisitVerse(Verse *verse)
if (!alignment) return FUNCTOR_CONTINUE;

// Add the number count
alignment->AddVerseN(verse->GetN());
alignment->AddVerseN(verse->GetN(), verse->GetPlace());

return FUNCTOR_CONTINUE;
}
2 changes: 2 additions & 0 deletions src/iomei.cpp
Original file line number Diff line number Diff line change
@@ -2870,6 +2870,7 @@ void MEIOutput::WriteVerse(pugi::xml_node currentNode, Verse *verse)
verse->WriteColor(currentNode);
verse->WriteLang(currentNode);
verse->WriteNInteger(currentNode);
verse->WritePlacementRelStaff(currentNode);
verse->WriteTypography(currentNode);
}

@@ -7163,6 +7164,7 @@ bool MEIInput::ReadVerse(Object *parent, pugi::xml_node verse)
vrvVerse->ReadColor(verse);
vrvVerse->ReadLang(verse);
vrvVerse->ReadNInteger(verse);
vrvVerse->ReadPlacementRelStaff(verse);
vrvVerse->ReadTypography(verse);

parent->AddChild(vrvVerse);
4 changes: 4 additions & 0 deletions src/options.cpp
Original file line number Diff line number Diff line change
@@ -1371,6 +1371,10 @@ Options::Options()
m_lyricElision.Init(ELISION_regular, &Option::s_elision);
this->Register(&m_lyricElision, "lyricElision", &m_generalLayout);

m_lyricHeightFactor.SetInfo("Lyric height factor", "The lyric verse line height factor");
m_lyricHeightFactor.Init(1.0, 1.0, 20.0);
this->Register(&m_lyricHeightFactor, "lyricHeightFactor", &m_generalLayout);

m_lyricLineThickness.SetInfo("Lyric line thickness", "The lyric extender line thickness");
m_lyricLineThickness.Init(0.25, 0.10, 0.50);
this->Register(&m_lyricLineThickness, "lyricLineThickness", &m_generalLayout);
3 changes: 2 additions & 1 deletion src/preparedatafunctor.cpp
Original file line number Diff line number Diff line change
@@ -1041,7 +1041,8 @@ FunctorCode PrepareLyricsFunctor::VisitSyl(Syl *syl)
{
Verse *verse = vrv_cast<Verse *>(syl->GetFirstAncestor(VERSE, MAX_NOTE_DEPTH));
if (verse) {
syl->m_drawingVerse = std::max(verse->GetN(), 1);
syl->m_drawingVerseN = std::max(verse->GetN(), 1);
syl->m_drawingVersePlace = verse->GetPlace();
}

syl->SetStart(vrv_cast<LayerElement *>(syl->GetFirstAncestor(NOTE, MAX_NOTE_DEPTH)));
3 changes: 2 additions & 1 deletion src/syl.cpp
Original file line number Diff line number Diff line change
@@ -59,7 +59,8 @@ void Syl::Reset()
this->ResetTypography();
this->ResetSylLog();

m_drawingVerse = 1;
m_drawingVerseN = 1;
m_drawingVersePlace = STAFFREL_below;
m_nextWordSyl = NULL;
}

2 changes: 2 additions & 0 deletions src/verse.cpp
Original file line number Diff line number Diff line change
@@ -38,6 +38,7 @@ Verse::Verse() : LayerElement(VERSE, "verse-"), AttColor(), AttLang(), AttNInteg
this->RegisterAttClass(ATT_COLOR);
this->RegisterAttClass(ATT_LANG);
this->RegisterAttClass(ATT_NINTEGER);
this->RegisterAttClass(ATT_PLACEMENTRELSTAFF);
this->RegisterAttClass(ATT_TYPOGRAPHY);

this->Reset();
@@ -51,6 +52,7 @@ void Verse::Reset()
this->ResetColor();
this->ResetLang();
this->ResetNInteger();
this->ResetPlacementRelStaff();
this->ResetTypography();

m_drawingLabelAbbr = NULL;
57 changes: 46 additions & 11 deletions src/verticalaligner.cpp
Original file line number Diff line number Diff line change
@@ -314,7 +314,8 @@ FunctorCode SystemAligner::AcceptEnd(ConstFunctor &functor) const
StaffAlignment::StaffAlignment() : Object(STAFF_ALIGNMENT)
{
m_yRel = 0;
m_verseNs.clear();
m_verseAboveNs.clear();
m_verseBelowNs.clear();
m_staff = NULL;
m_floatingPositionersSorted = true;

@@ -436,39 +437,73 @@ void StaffAlignment::SetRequestedSpaceBelow(int space)
}
}

void StaffAlignment::AddVerseN(int verseN)
void StaffAlignment::AddVerseN(int verseN, data_STAFFREL place)
{
// if 0, then assume 1;
verseN = std::max(verseN, 1);
m_verseNs.insert(verseN);
(place == STAFFREL_above) ? m_verseAboveNs.insert(verseN) : m_verseBelowNs.insert(verseN);
}

int StaffAlignment::GetVerseCount(bool collapse) const
{
if (m_verseNs.empty()) {
return (this->GetVerseCountAbove(collapse) + this->GetVerseCountBelow(collapse));
}

int StaffAlignment::GetVerseCountAbove(bool collapse) const
{
if (m_verseAboveNs.empty()) {
return 0;
}
else if (collapse) {
return (int)m_verseAboveNs.size();
}
else {
return (*m_verseAboveNs.rbegin());
}
}

int StaffAlignment::GetVerseCountBelow(bool collapse) const
{
if (m_verseBelowNs.empty()) {
return 0;
}
else if (collapse) {
return (int)m_verseNs.size();
return (int)m_verseBelowNs.size();
}
else {
return (*m_verseBelowNs.rbegin());
}
}

int StaffAlignment::GetVersePositionAbove(int verseN, bool collapse) const
{
if (m_verseAboveNs.empty()) {
// Syl in neumatic notation - since verse count will be 0, position is -1
return -1;
}
else if (collapse) {
auto it = std::find(m_verseAboveNs.begin(), m_verseAboveNs.end(), verseN);
int pos = (int)std::distance(m_verseAboveNs.begin(), it);
return pos;
}
else {
return *m_verseNs.rbegin();
return verseN - 1;
}
}

int StaffAlignment::GetVersePosition(int verseN, bool collapse) const
int StaffAlignment::GetVersePositionBelow(int verseN, bool collapse) const
{
if (m_verseNs.empty()) {
if (m_verseBelowNs.empty()) {
// Syl in neumatic notation - since verse count will be 0, position is -1
return -1;
}
else if (collapse) {
auto it = std::find(m_verseNs.rbegin(), m_verseNs.rend(), verseN);
int pos = (int)std::distance(m_verseNs.rbegin(), it);
auto it = std::find(m_verseBelowNs.rbegin(), m_verseBelowNs.rend(), verseN);
int pos = (int)std::distance(m_verseBelowNs.rbegin(), it);
return pos;
}
else {
return (*m_verseNs.rbegin()) - verseN;
return (*m_verseBelowNs.rbegin()) - verseN;
}
}

2 changes: 1 addition & 1 deletion src/view_control.cpp
Original file line number Diff line number Diff line change
@@ -1245,7 +1245,7 @@ void View::DrawSylConnector(
assert(syl->GetStart() && syl->GetEnd());
if (!syl->GetStart() || !syl->GetEnd()) return;

const int y = staff->GetDrawingY() + this->GetSylYRel(syl->m_drawingVerse, staff);
const int y = staff->GetDrawingY() + this->GetSylYRel(syl->m_drawingVerseN, staff, syl->m_drawingVersePlace);

// Invalid bounding boxes might occur for empty syllables without text child
if (!syl->HasContentHorizontalBB()) return;
32 changes: 22 additions & 10 deletions src/view_element.cpp
Original file line number Diff line number Diff line change
@@ -1753,7 +1753,7 @@ void View::DrawSyl(DeviceContext *dc, LayerElement *element, Layer *layer, Staff
}

if (!m_doc->IsFacs() && !m_doc->IsTranscription() && !m_doc->IsNeumeLines()) {
syl->SetDrawingYRel(this->GetSylYRel(syl->m_drawingVerse, staff));
syl->SetDrawingYRel(this->GetSylYRel(syl->m_drawingVerseN, staff, syl->m_drawingVersePlace));
}

dc->StartGraphic(syl, "", syl->GetID());
@@ -1871,7 +1871,7 @@ void View::DrawVerse(DeviceContext *dc, LayerElement *element, Layer *layer, Sta

TextDrawingParams params;
params.m_x = verse->GetDrawingX() - m_doc->GetDrawingUnit(staff->m_drawingStaffSize);
params.m_y = staff->GetDrawingY() + this->GetSylYRel(std::max(1, verse->GetN()), staff);
params.m_y = staff->GetDrawingY() + this->GetSylYRel(std::max(1, verse->GetN()), staff, verse->GetPlace());
params.m_pointSize = labelTxt.GetPointSize();

dc->SetBrush(m_currentColor, AxSOLID);
@@ -2098,22 +2098,34 @@ int View::GetFYRel(F *f, Staff *staff)
return y;
}

int View::GetSylYRel(int verseN, Staff *staff)
int View::GetSylYRel(int verseN, Staff *staff, data_STAFFREL place)
{
assert(staff);

StaffAlignment *alignment = staff->GetAlignment();
if (!alignment) return 0;

const bool verseCollapse = m_options->m_lyricVerseCollapse.GetValue();
int y = 0;
StaffAlignment *alignment = staff->GetAlignment();
if (alignment) {
FontInfo *lyricFont = m_doc->GetDrawingLyricFont(staff->m_drawingStaffSize);
int descender = -m_doc->GetTextGlyphDescender(L'q', lyricFont, false);
int height = m_doc->GetTextGlyphHeight(L'I', lyricFont, false);
int margin = m_doc->GetBottomMargin(SYL) * m_doc->GetDrawingUnit(staff->m_drawingStaffSize);

FontInfo *lyricFont = m_doc->GetDrawingLyricFont(staff->m_drawingStaffSize);
const int descender = m_doc->GetTextGlyphDescender(L'q', lyricFont, false);
const int height = m_doc->GetTextGlyphHeight(L'I', lyricFont, false);

int verseHeight = height - descender;
verseHeight *= m_doc->GetOptions()->m_lyricHeightFactor.GetValue();
int margin = m_doc->GetBottomMargin(SYL) * m_doc->GetDrawingUnit(staff->m_drawingStaffSize);

// above the staff
if (place == STAFFREL_above) {
y = alignment->GetOverflowAbove()
- (alignment->GetVersePositionAbove(verseN, verseCollapse)) * (verseHeight + margin) - (height);
}
else {
y = -alignment->GetStaffHeight() - alignment->GetOverflowBelow()
+ alignment->GetVersePosition(verseN, verseCollapse) * (height + descender + margin) + (descender);
+ alignment->GetVersePositionBelow(verseN, verseCollapse) * (verseHeight + margin) + verseHeight - height;
}

return y;
}

0 comments on commit f352406

Please sign in to comment.