Skip to content

Commit

Permalink
Merge pull request #3512 from paul-bayleaf/develop-tab-GLT-positioning
Browse files Browse the repository at this point in the history
Develop tab glt positioning
  • Loading branch information
lpugin authored Jan 24, 2024
2 parents 0b682d3 + 51437a8 commit df82a54
Show file tree
Hide file tree
Showing 11 changed files with 84 additions and 27 deletions.
2 changes: 1 addition & 1 deletion include/vrv/note.h
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,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, bool &overline) const;
std::u32string GetTabFretString(data_NOTATIONTYPE notationType, int &overline, int &strike) const;
///@}

/**
Expand Down
3 changes: 2 additions & 1 deletion include/vrv/staffdef.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,8 @@ class StaffDef : public ScoreDefElement,
public AttStaffDefLog,
public AttStaffDefVis,
public AttTimeBase,
public AttTransposition {
public AttTransposition,
public AttVerticalAlign {
public:
/**
* @name Constructors, destructors, and other standard methods
Expand Down
2 changes: 1 addition & 1 deletion include/vrv/tabdursym.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ namespace vrv {
/**
* This class models the MEI <tabDurSym> element.
*/
class TabDurSym : public LayerElement, public StemmedDrawingInterface, public AttNNumberLike {
class TabDurSym : public LayerElement, public StemmedDrawingInterface, public AttNNumberLike, public AttStaffLoc {
public:
/**
* @name Constructors, destructors, and other standard methods
Expand Down
8 changes: 6 additions & 2 deletions include/vrv/tuning.h
Original file line number Diff line number Diff line change
Expand Up @@ -42,16 +42,20 @@ class Tuning : public Object, public AttCourseLog {
/**
* Return the line for a note according to tablature type.
* Guitar, french and italian tablature: the line is based on the course.
* German tablature: the line is based on the note's index in the note list.
* German tablature: the line is based on the note's index in the note list
* or by explicit @loc.
*
* @param[in] course
* @param[in] notationType
* @param[in] lines
* @param[in] listSize
* @param[in] index - 0 based from the bottom of the chord
* @param[in] loc - German tablature: note@loc if specified, 0 at the bottom
* @param[in] topAlign - German tablature: true => align at the top, false => align at the bottom
* @return position in staff half lines
*/
int CalcPitchPos(int course, data_NOTATIONTYPE notationType, int lines, int listSize, int index) const;
int CalcPitchPos(
int course, data_NOTATIONTYPE notationType, int lines, int listSize, int index, int loc, bool topAlign) const;

/**
* Calculate the MIDI note number for course/fret
Expand Down
4 changes: 3 additions & 1 deletion src/calcalignmentpitchposfunctor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -105,8 +105,10 @@ FunctorCode CalcAlignmentPitchPosFunctor::VisitLayerElement(LayerElement *layerE
TabGrp *tabGrp = note->IsTabGrpNote();
if (tabGrp) {
assert(staffY->m_drawingTuning);
assert(staffY->m_drawingStaffDef);
loc = staffY->m_drawingTuning->CalcPitchPos(note->GetTabCourse(), staffY->m_drawingNotationType,
staffY->m_drawingLines, tabGrp->GetListSize(tabGrp), tabGrp->GetListIndex(note));
staffY->m_drawingLines, tabGrp->GetListSize(), tabGrp->GetListIndex(note), note->GetLoc(),
staffY->m_drawingStaffDef->GetValign() != VERTICALALIGNMENT_bottom);
}
else if ((note->HasPname() && (note->HasOct() || note->HasOctDefault())) || note->HasLoc()) {
loc = PitchInterface::CalcLoc(note, layerY, layerElementY);
Expand Down
4 changes: 4 additions & 0 deletions src/iomei.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1814,6 +1814,7 @@ void MEIOutput::WriteStaffDef(pugi::xml_node currentNode, StaffDef *staffDef)
staffDef->WriteStaffDefVis(currentNode);
staffDef->WriteTimeBase(currentNode);
staffDef->WriteTransposition(currentNode);
staffDef->WriteVerticalAlign(currentNode);
}

void MEIOutput::WriteInstrDef(pugi::xml_node currentNode, InstrDef *instrDef)
Expand Down Expand Up @@ -2793,6 +2794,7 @@ void MEIOutput::WriteTabDurSym(pugi::xml_node currentNode, TabDurSym *tabDurSym)

this->WriteLayerElement(currentNode, tabDurSym);
tabDurSym->WriteNNumberLike(currentNode);
tabDurSym->WriteStaffLoc(currentNode);
}

void MEIOutput::WriteTabGrp(pugi::xml_node currentNode, TabGrp *tabGrp)
Expand Down Expand Up @@ -5103,6 +5105,7 @@ bool MEIInput::ReadStaffDef(Object *parent, pugi::xml_node staffDef)
vrvStaffDef->ReadStaffDefVis(staffDef);
vrvStaffDef->ReadTimeBase(staffDef);
vrvStaffDef->ReadTransposition(staffDef);
vrvStaffDef->ReadVerticalAlign(staffDef);

if (!vrvStaffDef->HasN()) {
LogWarning("No @n on <staffDef> might yield unpredictable results");
Expand Down Expand Up @@ -6975,6 +6978,7 @@ bool MEIInput::ReadTabDurSym(Object *parent, pugi::xml_node tabRhyhtm)
this->ReadLayerElement(tabRhyhtm, vrvTabDurSym);

vrvTabDurSym->ReadNNumberLike(tabRhyhtm);
vrvTabDurSym->ReadStaffLoc(tabRhyhtm);

parent->AddChild(vrvTabDurSym);
this->ReadUnsupportedAttr(tabRhyhtm, vrvTabDurSym);
Expand Down
28 changes: 19 additions & 9 deletions src/note.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -267,9 +267,10 @@ const TabGrp *Note::IsTabGrpNote() const
return vrv_cast<const TabGrp *>(this->GetFirstAncestor(TABGRP, MAX_TABGRP_DEPTH));
}

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

if (notationType == NOTATIONTYPE_tab_lute_italian) {
std::u32string fretStr;
Expand Down Expand Up @@ -343,30 +344,35 @@ std::u32string Note::GetTabFretString(data_NOTATIONTYPE notationType, bool &over
const int fret = this->GetTabFret();
const int course = this->GetTabCourse();

// SMuFL has glyphs for German lute tablature following Hans Newsidler's notation
// for the 6th course.
// SMuFL has glyphs for German lute tablature following Hans and Melchior Newsidler's notation
// for the >= 6th courses.
// "German Renaissance lute tablature (U+EC00–U+EC2F)"
// https://w3c.github.io/smufl/latest/tables/german-renaissance-lute-tablature.html
//
// However, some glyphs are missing:
//
// Digit 1 with an oblique stroke for the open 6th course.
// Digit 1 with a strike through for the open 6th course.
// Digit 1 with two strike throughs for the open 7th course.
// Digit 1 with three strike throughs for the open 8th course.
// "et" for 2nd course 5th fret.
// "con" for 1st course 5th fret.
// Gothic font digits 1-5 for the open courses <= 5.
// Second lowercase alphabet with an overline used for courses <= 5 frets 6 to 10.
//
// To overcome these omissions I've substituted missing glyphs from other
// parts of the SMuFL collection. Overlines are drawn separately.
// parts of the SMuFL collection. Overlines and strike throughs are drawn separately.

if (course == 6 && fret >= 0 && fret <= 13) {
if (course >= 6 && fret >= 0 && fret <= 13) {
// + A B C D ...
if (fret == 0) {
fretStr = SMUFL_E595_ornamentLeftVerticalStrokeWithCross; // substitute for 1 with oblique stroke
fretStr = SMUFL_EA51_figbass1; // substitute for 1 with oblique stroke
strike = course - 5; // 6 course 1 strike, 7 course 2 strikes, ...
}
else {
// The German tablature uppercase letters A-N are contiguous, correctly omitting J
static_assert(SMUFL_EC23_luteGermanNUpper == SMUFL_EC17_luteGermanAUpper + 13 - 1);
fretStr = SMUFL_EC17_luteGermanAUpper + fret - 1;
overline = course - 6; // 6 course 0 overline, 7 course 1 overline, ...
}
}
else if (course >= 1 && course <= 5 && fret == 0) {
Expand All @@ -379,9 +385,13 @@ std::u32string Note::GetTabFretString(data_NOTATIONTYPE notationType, bool &over
const int firstAlphabetFret = fret <= 5 ? fret : fret - 5; // map second alphabet to first

if (course == 2 && firstAlphabetFret == 5) {
// TODO replace with U+EC24, luteGermanEt when available
// https://github.com/w3c/smufl/issues/274
fretStr = SMUFL_EA5F_figbass7Raised2; // substitute for "et"
}
else if (course == 1 && firstAlphabetFret == 5) {
// TODO replace with U+EC25, luteGermanCon when available
// https://github.com/w3c/smufl/issues/274
fretStr = SMUFL_EA61_figbass9; // substitute for "con"
}
else {
Expand All @@ -394,7 +404,7 @@ std::u32string Note::GetTabFretString(data_NOTATIONTYPE notationType, bool &over
}

// second alphabet needs an overline
overline = (fret >= 6);
overline = (fret >= 6) ? 1 : 0;
}
return fretStr;
}
Expand Down
3 changes: 3 additions & 0 deletions src/staffdef.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ StaffDef::StaffDef()
, AttStaffDefVis()
, AttTimeBase()
, AttTransposition()
, AttVerticalAlign()
{
this->RegisterAttClass(ATT_DISTANCES);
this->RegisterAttClass(ATT_LABELLED);
Expand All @@ -52,6 +53,7 @@ StaffDef::StaffDef()
this->RegisterAttClass(ATT_STAFFDEFVIS);
this->RegisterAttClass(ATT_TIMEBASE);
this->RegisterAttClass(ATT_TRANSPOSITION);
this->RegisterAttClass(ATT_VERTICALALIGN);

this->Reset();
}
Expand All @@ -71,6 +73,7 @@ void StaffDef::Reset()
this->ResetStaffDefVis();
this->ResetTimeBase();
this->ResetTransposition();
this->ResetVerticalAlign();

m_drawingVisibility = OPTIMIZATION_NONE;
}
Expand Down
5 changes: 4 additions & 1 deletion src/tabdursym.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,11 @@ namespace vrv {

static const ClassRegistrar<TabDurSym> s_factory("tabDurSym", TABDURSYM);

TabDurSym::TabDurSym() : LayerElement(TABDURSYM, "tabdursym-"), StemmedDrawingInterface(), AttNNumberLike()
TabDurSym::TabDurSym()
: LayerElement(TABDURSYM, "tabdursym-"), StemmedDrawingInterface(), AttNNumberLike(), AttStaffLoc()
{
this->RegisterAttClass(ATT_NNUMBERLIKE);
this->RegisterAttClass(ATT_STAFFLOC);

this->Reset();
}
Expand All @@ -45,6 +47,7 @@ void TabDurSym::Reset()
LayerElement::Reset();
StemmedDrawingInterface::Reset();
this->ResetNNumberLike();
this->ResetStaffLoc();
}

bool TabDurSym::IsSupportedChild(Object *child)
Expand Down
15 changes: 13 additions & 2 deletions src/tuning.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -56,14 +56,25 @@ bool Tuning::IsSupportedChild(Object *child)
return true;
}

int Tuning::CalcPitchPos(int course, data_NOTATIONTYPE notationType, int lines, int listSize, int index) const
int Tuning::CalcPitchPos(
int course, data_NOTATIONTYPE notationType, int lines, int listSize, int index, int loc, bool topAlign) const
{
switch (notationType) {
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_german: return (lines - (listSize - index)) * 2;
case NOTATIONTYPE_tab_lute_german:
if (loc != MEI_UNSET) {
return loc;
}
else if (topAlign) {
return (lines - (listSize - index)) * 2;
}
else {
// bottom align
return index * 2;
}
case NOTATIONTYPE_tab_guitar: [[fallthrough]];
default: return abs(course - lines) * 2;
}
Expand Down
37 changes: 28 additions & 9 deletions src/view_tab.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
#include "rend.h"
#include "smufl.h"
#include "staff.h"
#include "staffdef.h"
#include "stem.h"
#include "system.h"
#include "tabdursym.h"
Expand Down Expand Up @@ -105,11 +106,12 @@ void View::DrawTabNote(DeviceContext *dc, LayerElement *element, Layer *layer, S

int glyphSize = staff->GetDrawingStaffNotationSize();
bool drawingCueSize = false;
bool overline = false;
int overline = 0;
int strike = 0;

if (staff->m_drawingNotationType == NOTATIONTYPE_tab_guitar) {

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

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

std::u32string fret = note->GetTabFretString(staff->m_drawingNotationType, overline);
std::u32string fret = note->GetTabFretString(staff->m_drawingNotationType, overline, strike);
// Center for italian tablature
if (staff->IsTabLuteItalian()) {
y -= (m_doc->GetGlyphHeight(SMUFL_EBE0_luteItalianFret0, glyphSize, drawingCueSize) / 2);
Expand All @@ -153,8 +155,8 @@ 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 overline if required
if (overline && !fret.empty()) {
// Add overlines or strikethoughs if required
if ((overline > 0 || strike > 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);
Expand All @@ -165,13 +167,24 @@ void View::DrawTabNote(DeviceContext *dc, LayerElement *element, Layer *layer, S
const int x1 = x - widthFront / 2;
const int x2 = x + extend.m_width - widthBack * 3 / 10; // trim right hand overhang on last character

const int y1 = y + extend.m_ascent + lineThickness;
const int y2 = y1;

dc->SetPen(m_currentColor, lineThickness, AxSOLID);
dc->SetBrush(m_currentColor, AxSOLID);

dc->DrawLine(ToDeviceContextX(x1), ToDeviceContextY(y1), ToDeviceContextX(x2), ToDeviceContextY(y2));
// overlines
int y1 = y + extend.m_ascent + lineThickness;

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

// strikethroughs
y1 = y + extend.m_ascent / 2 - (strike - 1) * lineThickness;

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

dc->ResetPen();
dc->ResetBrush();
Expand Down Expand Up @@ -200,6 +213,12 @@ void View::DrawTabDurSym(DeviceContext *dc, LayerElement *element, Layer *layer,

dc->StartGraphic(tabDurSym, "", tabDurSym->GetID());

if (tabDurSym->HasLoc()) {
const int yRel = ((staff->m_drawingLines - 1) * 2 - tabDurSym->GetLoc())
* m_doc->GetDrawingUnit(staff->m_drawingStaffSize);
tabDurSym->SetDrawingYRel(-yRel);
}

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

Expand Down

0 comments on commit df82a54

Please sign in to comment.