Skip to content

Commit

Permalink
Merge pull request rism-digital#3831 from paul-bayleaf/fix-italian-ta…
Browse files Browse the repository at this point in the history
…b-ledgers-and-rhythms

Fix rism-digital#3828 Italian lute tablature bass notes.
  • Loading branch information
lpugin authored Oct 17, 2024
2 parents c643a67 + 3b0fe9c commit 8aa02c4
Show file tree
Hide file tree
Showing 4 changed files with 62 additions and 24 deletions.
2 changes: 1 addition & 1 deletion include/vrv/note.h
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +166,7 @@ class Note : public LayerElement,
* @name Return the smufl string to use for a note give the notation type
*/
///@{
std::u32string GetTabFretString(data_NOTATIONTYPE notationType, int &overline, int &strike) const;
std::u32string GetTabFretString(data_NOTATIONTYPE notationType, int &overline, int &strike, int &underline) const;
///@}

/**
Expand Down
50 changes: 34 additions & 16 deletions src/note.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -224,6 +224,17 @@ bool Note::HasLedgerLines(int &linesAbove, int &linesBelow, const Staff *staff)
staff = this->GetAncestorStaff();
}

if (staff->IsTabLuteFrench() || staff->IsTabLuteGerman() || staff->IsTabLuteItalian()) {
// French and German tablature do not use ledger lines.
// Italian tablature does use a single ledger line for 7th course, and compressed
// ledger lines for fretted 8th and above, but not for open 8th and above. So
// rather than use the CMN ledger line handling we draw our own.
// Guitar tablature has been left as originally implemented.
linesAbove = 0;
linesBelow = 0;
return false;
}

linesAbove = (this->GetDrawingLoc() - staff->m_drawingLines * 2 + 2) / 2;
linesBelow = -(this->GetDrawingLoc()) / 2;

Expand Down Expand Up @@ -271,10 +282,11 @@ const TabGrp *Note::IsTabGrpNote() const
return vrv_cast<const TabGrp *>(this->GetFirstAncestor(TABGRP, MAX_TABGRP_DEPTH));
}

std::u32string Note::GetTabFretString(data_NOTATIONTYPE notationType, int &overline, int &strike) const
std::u32string Note::GetTabFretString(data_NOTATIONTYPE notationType, int &overline, int &strike, int &underline) const
{
overline = 0;
strike = 0;
underline = 0;

// @glyph.num, @glyph.name or @altsym
const Resources *resources = this->GetDocResources();
Expand Down Expand Up @@ -321,21 +333,27 @@ std::u32string Note::GetTabFretString(data_NOTATIONTYPE notationType, int &overl

if (notationType == NOTATIONTYPE_tab_lute_italian) {
std::u32string fretStr;
int fret = this->GetTabFret();
// Maximum allowed would be 19 (always bindly adding 1 as first figure)
if (fret > 9) fretStr.push_back(SMUFL_EBE1_luteItalianFret1);
switch (fret % 10) {
case 0: fretStr.push_back(SMUFL_EBE0_luteItalianFret0); break;
case 1: fretStr.push_back(SMUFL_EBE1_luteItalianFret1); break;
case 2: fretStr.push_back(SMUFL_EBE2_luteItalianFret2); break;
case 3: fretStr.push_back(SMUFL_EBE3_luteItalianFret3); break;
case 4: fretStr.push_back(SMUFL_EBE4_luteItalianFret4); break;
case 5: fretStr.push_back(SMUFL_EBE5_luteItalianFret5); break;
case 6: fretStr.push_back(SMUFL_EBE6_luteItalianFret6); break;
case 7: fretStr.push_back(SMUFL_EBE7_luteItalianFret7); break;
case 8: fretStr.push_back(SMUFL_EBE8_luteItalianFret8); break;
case 9: fretStr.push_back(SMUFL_EBE9_luteItalianFret9); break;
default: break;
const int fret = this->GetTabFret();
const int course = this->GetTabCourse();

// Italian tablature glyphs are contiguous
static_assert(SMUFL_EBE1_luteItalianFret1 == SMUFL_EBE0_luteItalianFret0 + 1);
static_assert(SMUFL_EBE2_luteItalianFret2 == SMUFL_EBE0_luteItalianFret0 + 2);
// ...
static_assert(SMUFL_EBE9_luteItalianFret9 == SMUFL_EBE0_luteItalianFret0 + 9);

if (course <= 7 || fret != 0) {
const auto decimal = std::div(fret, 10);
if (decimal.quot > 0) fretStr.push_back(SMUFL_EBE0_luteItalianFret0 + decimal.quot);
if (decimal.rem <= 9) fretStr.push_back(SMUFL_EBE0_luteItalianFret0 + decimal.rem);
if (course >= 7) strike = 1; // course 7 and fretted courses >= 8 use a ledger line
underline = std::max(0, course - 7); // compressed ledger lines for fretted courses >= 8
}
else {
// open courses >= 8 just use the number of the course on stave line 7
const auto decimal = std::div(course, 10);
if (decimal.quot > 0) fretStr.push_back(SMUFL_EBE0_luteItalianFret0 + decimal.quot);
if (decimal.rem <= 9) fretStr.push_back(SMUFL_EBE0_luteItalianFret0 + decimal.rem);
}
return fretStr;
}
Expand Down
4 changes: 3 additions & 1 deletion src/tuning.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,9 @@ int Tuning::CalcPitchPos(
case NOTATIONTYPE_tab_lute_french:
// all courses >= 7 are positioned above line 0
return (lines - std::min(course, 7)) * 2 + 1; // above the line
case NOTATIONTYPE_tab_lute_italian: return (course - 1) * 2;
case NOTATIONTYPE_tab_lute_italian:
// all courses >= 7 are positioned on line 7
return (std::min(course, 7) - 1) * 2;
case NOTATIONTYPE_tab_lute_german:
if (loc != MEI_UNSET) {
return loc;
Expand Down
30 changes: 24 additions & 6 deletions src/view_tab.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -106,10 +106,11 @@ void View::DrawTabNote(DeviceContext *dc, LayerElement *element, Layer *layer, S
bool drawingCueSize = false;
int overline = 0;
int strike = 0;
int underline = 0;

if (staff->m_drawingNotationType == NOTATIONTYPE_tab_guitar) {

std::u32string fret = note->GetTabFretString(staff->m_drawingNotationType, overline, strike);
std::u32string fret = note->GetTabFretString(staff->m_drawingNotationType, overline, strike, underline);

FontInfo fretTxt;
if (!dc->UseGlobalStyling()) {
Expand All @@ -135,7 +136,7 @@ void View::DrawTabNote(DeviceContext *dc, LayerElement *element, Layer *layer, S
}
else {

std::u32string fret = note->GetTabFretString(staff->m_drawingNotationType, overline, strike);
std::u32string fret = note->GetTabFretString(staff->m_drawingNotationType, overline, strike, underline);
// Center for italian tablature
if (staff->IsTabLuteItalian()) {
y -= (m_doc->GetGlyphHeight(SMUFL_EBE0_luteItalianFret0, glyphSize, drawingCueSize) / 2);
Expand All @@ -153,17 +154,20 @@ void View::DrawTabNote(DeviceContext *dc, LayerElement *element, Layer *layer, S
dc->SetFont(m_doc->GetDrawingSmuflFont(glyphSize, false));
this->DrawSmuflString(dc, x, y, fret, HORIZONTALALIGNMENT_center, glyphSize);

// Add overlines or strikethoughs if required
if ((overline > 0 || strike > 0) && !fret.empty()) {
// Add overlines, strikethoughs and underlines if required
if ((overline > 0 || strike > 0 || underline > 0) && !fret.empty()) {
const int lineThickness
= m_options->m_lyricLineThickness.GetValue() * m_doc->GetDrawingUnit(staff->m_drawingStaffSize);
const int widthFront = m_doc->GetGlyphWidth(fret.front(), glyphSize, drawingCueSize);
const int widthBack = m_doc->GetGlyphWidth(fret.back(), glyphSize, drawingCueSize);
TextExtend extend;
dc->GetSmuflTextExtent(fret, &extend);

const int x1 = x - widthFront / 2;
const int x2 = x + extend.m_width - widthBack * 3 / 10; // trim right hand overhang on last character
// TODO These fiddle factors seem necessary to get the lines balanced on either side
// of the fret string. Can we do better?
const int x1
= x - (fret.size() == 1 ? widthFront * 7 / 10 : widthFront * 12 / 10); // extend on the left hand side
const int x2 = x + extend.m_width - widthBack * 1 / 10; // trim right hand overhang on last character

dc->SetPen(m_currentColor, lineThickness, AxSOLID);
dc->SetBrush(m_currentColor, AxSOLID);
Expand All @@ -184,6 +188,14 @@ void View::DrawTabNote(DeviceContext *dc, LayerElement *element, Layer *layer, S
y1 += 2 * lineThickness;
}

// underlines
y1 = y - extend.m_descent - lineThickness;

for (int i = 0; i < underline; ++i) {
dc->DrawLine(ToDeviceContextX(x1), ToDeviceContextY(y1), ToDeviceContextX(x2), ToDeviceContextY(y1));
y1 -= 2 * lineThickness;
}

dc->ResetPen();
dc->ResetBrush();
}
Expand Down Expand Up @@ -214,6 +226,12 @@ void View::DrawTabDurSym(DeviceContext *dc, LayerElement *element, Layer *layer,
* m_doc->GetDrawingUnit(staff->m_drawingStaffSize);
tabDurSym->SetDrawingYRel(-yRel);
}
else if (staff->IsTabLuteItalian()) {
// make space for 7th course
const int yRel
= ((staff->m_drawingLines - 1) * 2 - 7 * 2 + 1) * m_doc->GetDrawingUnit(staff->m_drawingStaffSize);
tabDurSym->SetDrawingYRel(-yRel);
}

int x = element->GetDrawingX();
int y = element->GetDrawingY();
Expand Down

0 comments on commit 8aa02c4

Please sign in to comment.