diff --git a/src/engraving/data/chords/chords_jazz.xml b/src/engraving/data/chords/chords_jazz.xml
index ad1ffb40dee4c..056117767cfec 100644
--- a/src/engraving/data/chords/chords_jazz.xml
+++ b/src/engraving/data/chords/chords_jazz.xml
@@ -76,7 +76,7 @@
-
+
@@ -222,12 +222,12 @@
o
- sc:0.5 :push :mx circle :popy sc:2
+ sc:0.8 :push :mx circle :popy sc:1.25 m:0.1:0
0
- sc:0.5 :push :mx oslash :popy sc:2
+ sc:0.8 :push :mx oslash :popy sc:1.25 m:0.1:0
diff --git a/src/engraving/data/chords/chords_std.xml b/src/engraving/data/chords/chords_std.xml
index e9877465fe551..e14f2406142cc 100644
--- a/src/engraving/data/chords/chords_std.xml
+++ b/src/engraving/data/chords/chords_std.xml
@@ -215,12 +215,12 @@
o
- sc:0.5 :push :mx circle :popy sc:2
+ sc:0.5 :push :mx circle :popy sc:2 m:0.1:0
0
- sc:0.5 :push :mx oslash :popy sc:2
+ sc:0.5 :push :mx oslash :popy sc:2 m:0.1:0
diff --git a/src/engraving/dom/edit.cpp b/src/engraving/dom/edit.cpp
index 3eeac8e1fc307..e922303f22477 100644
--- a/src/engraving/dom/edit.cpp
+++ b/src/engraving/dom/edit.cpp
@@ -6397,6 +6397,23 @@ static bool chordHasVisibleNote(const Chord* chord)
return false;
}
+static bool chordHasVisibleChild(const Chord* chord)
+{
+ for (EngravingObject* child : chord->scanChildren()) {
+ if (toEngravingItem(child)->visible()) {
+ return true;
+ }
+ }
+
+ for (const Chord* graceNote : chord->graceNotes()) {
+ if (chordHasVisibleChild(graceNote)) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
static void undoChangeOrnamentVisibility(Ornament* ornament, bool visible);
static void undoChangeNoteVisibility(Note* note, bool visible)
@@ -6448,9 +6465,9 @@ static void undoChangeNoteVisibility(Note* note, bool visible)
ElementType::LEDGER_LINE, // temporary objects, impossible to change visibility
};
- for (const Chord* chord : chords) {
- for (const EngravingObject* obj : chord->linkList()) {
- const Chord* linkedChord = toChord(obj);
+ for (Chord* chord : chords) {
+ for (EngravingObject* obj : chord->linkList()) {
+ Chord* linkedChord = toChord(obj);
chordHasVisibleNote_ = chordHasVisibleNote(linkedChord);
for (EngravingObject* child : linkedChord->scanChildren()) {
const ElementType type = child->type();
@@ -6471,6 +6488,10 @@ static void undoChangeNoteVisibility(Note* note, bool visible)
child->undoChangeProperty(Pid::VISIBLE, chordHasVisibleNote_);
}
}
+ bool visible = chordHasVisibleChild(linkedChord);
+ if (!visible) {
+ linkedChord->undoChangeProperty(Pid::VISIBLE, visible);
+ }
}
}
}
diff --git a/src/engraving/dom/gradualtempochange.cpp b/src/engraving/dom/gradualtempochange.cpp
index a08218df704d2..df5ef7a488437 100644
--- a/src/engraving/dom/gradualtempochange.cpp
+++ b/src/engraving/dom/gradualtempochange.cpp
@@ -22,6 +22,8 @@
#include "gradualtempochange.h"
+#include "dom/rehearsalmark.h"
+#include "dom/text.h"
#include "measure.h"
#include "score.h"
#include "segment.h"
@@ -147,6 +149,8 @@ PropertyValue GradualTempoChange::getProperty(Pid id) const
return tempoChangeFactor();
case Pid::SNAP_AFTER:
return snapToItemAfter();
+ case Pid::TEMPO_ALIGN_RIGHT_OF_REHEARSAL_MARK:
+ return m_alignRightOfRehearsalMark;
default:
return TextLineBase::getProperty(id);
}
@@ -167,6 +171,9 @@ bool GradualTempoChange::setProperty(Pid id, const PropertyValue& val)
case Pid::SNAP_AFTER:
setSnapToItemAfter(val.toBool());
break;
+ case Pid::TEMPO_ALIGN_RIGHT_OF_REHEARSAL_MARK:
+ m_alignRightOfRehearsalMark = val.toBool();
+ break;
default:
if (!TextLineBase::setProperty(id, val)) {
return false;
@@ -221,6 +228,9 @@ PropertyValue GradualTempoChange::propertyDefault(Pid propertyId) const
case Pid::SNAP_AFTER:
return true;
+ case Pid::TEMPO_ALIGN_RIGHT_OF_REHEARSAL_MARK:
+ return true;
+
default:
return TextLineBase::propertyDefault(propertyId);
}
@@ -261,6 +271,62 @@ Sid GradualTempoChange::getPropertyStyle(Pid id) const
return TextLineBase::getPropertyStyle(id);
}
+bool GradualTempoChange::adjustForRehearsalMark(bool start) const
+{
+ const Segment* segment = start ? startSegment() : endSegment();
+ if (!m_alignRightOfRehearsalMark || !segment) {
+ return false;
+ }
+
+ const RehearsalMark* rehearsalMark = toRehearsalMark(segment->findAnnotation(ElementType::REHEARSAL_MARK, track(), track()));
+ if (!rehearsalMark) {
+ return false;
+ }
+ RectF thisBbox = ldata()->bbox().translated(pos());
+ RectF rehearsalMarkBbox = rehearsalMark ? rehearsalMark->ldata()->bbox().translated(rehearsalMark->pos()) : RectF();
+
+ const bool sameSide = placeAbove() == rehearsalMark->placeAbove();
+ const bool collision = placeAbove() ? muse::RealIsEqualOrMore(rehearsalMarkBbox.bottom(), thisBbox.top()) : muse::RealIsEqualOrLess(
+ rehearsalMarkBbox.top(), thisBbox.bottom());
+
+ return sameSide && collision;
+}
+
+PointF GradualTempoChange::linePos(Grip grip, System** system) const
+{
+ bool start = grip == Grip::START;
+ PointF defaultPos = TextLineBase::linePos(grip, system);
+ if (!adjustForRehearsalMark(start)) {
+ return defaultPos;
+ }
+
+ const Segment* segment = start ? startSegment() : endSegment();
+ const RehearsalMark* rehearsalMark = toRehearsalMark(segment->findAnnotation(ElementType::REHEARSAL_MARK, track(), track()));
+ RectF rehearsalMarkBbox = rehearsalMark ? rehearsalMark->ldata()->bbox().translated(rehearsalMark->pos()) : RectF();
+
+ PointF rehearsalMarkPos = segment->pos() + segment->measure()->pos();
+ rehearsalMarkBbox.translate(rehearsalMarkPos);
+
+ Text* text = start ? toGradualTempoChangeSegment(frontSegment())->text() : toGradualTempoChangeSegment(backSegment())->endText();
+
+ const double sp = spatium();
+
+ double padding = sp;
+ if (text) {
+ const double fontSizeScaleFactor = text->size() / 10.0;
+ padding = 0.5 * sp * fontSizeScaleFactor;
+ }
+
+ padding *= start ? 1.0 : -1.0;
+ double x = (start ? rehearsalMarkBbox.right() : rehearsalMarkBbox.left()) + padding;
+
+ *system = segment->measure()->system();
+
+ x = start ? std::max(x, defaultPos.x()) : x;
+
+ return PointF(x, 0.0);
+}
+
void GradualTempoChange::added()
{
requestToRebuildTempo();
diff --git a/src/engraving/dom/gradualtempochange.h b/src/engraving/dom/gradualtempochange.h
index 9170d69b34dc3..e828b65865145 100644
--- a/src/engraving/dom/gradualtempochange.h
+++ b/src/engraving/dom/gradualtempochange.h
@@ -56,6 +56,9 @@ class GradualTempoChange : public TextLineBase
bool snapToItemAfter() const { return m_snapToItemAfter; }
void setSnapToItemAfter(bool v) { m_snapToItemAfter = v; }
+ bool adjustForRehearsalMark(bool start) const;
+ PointF linePos(Grip grip, System** system) const override;
+
protected:
void added() override;
void removed() override;
@@ -69,6 +72,8 @@ class GradualTempoChange : public TextLineBase
bool m_snapToItemAfter = true;
+ bool m_alignRightOfRehearsalMark = true;
+
friend class GradualTempoChangeSegment;
};
diff --git a/src/engraving/dom/score.cpp b/src/engraving/dom/score.cpp
index 85f7bad669275..2f042d6329554 100644
--- a/src/engraving/dom/score.cpp
+++ b/src/engraving/dom/score.cpp
@@ -1612,7 +1612,8 @@ void Score::addElement(EngravingItem* element)
break;
}
- if (element->isTextBase() && toTextBase(element)->hasParentSegment()) {
+ if (element->isTextBase() && toTextBase(element)->hasParentSegment()
+ && toSegment(element->parent())->isType(Segment::CHORD_REST_OR_TIME_TICK_TYPE)) {
MoveElementAnchors::checkMeasureBoundariesAndMoveIfNeed(element);
}
diff --git a/src/engraving/dom/volta.cpp b/src/engraving/dom/volta.cpp
index f03fda12495d7..f46a7de581d99 100644
--- a/src/engraving/dom/volta.cpp
+++ b/src/engraving/dom/volta.cpp
@@ -331,12 +331,15 @@ PointF Volta::linePos(Grip grip, System** system) const
bool isAtSystemStart = segment->rtick().isZero() && measure && measure->system() && measure->isFirstInSystem();
bool searchForPrevBarline = start ? segment->rtick().isZero() && (measure->repeatStart() || !isAtSystemStart) : true;
+ SegmentType barlineType = start ? (SegmentType::StartRepeatBarLine | SegmentType::EndBarLine) : SegmentType::EndBarLine;
+
if (searchForPrevBarline) {
Segment* prev = segment;
- while (prev && !prev->isType(SegmentType::BarLineType) && prev->tick() == segment->tick()) {
+ while (prev && !prev->isType(barlineType) && prev->tick() == segment->tick()) {
prev = prev->prev1MMenabled();
}
- if (prev && prev->isType(SegmentType::BarLineType)) {
+
+ if (prev && prev->isType(barlineType)) {
segment = prev;
}
}
diff --git a/src/engraving/rendering/score/dynamicslayout.cpp b/src/engraving/rendering/score/dynamicslayout.cpp
index 231e62527974d..2a68747827b4c 100644
--- a/src/engraving/rendering/score/dynamicslayout.cpp
+++ b/src/engraving/rendering/score/dynamicslayout.cpp
@@ -75,7 +75,8 @@ void DynamicsLayout::doLayoutDynamic(Dynamic* item, Dynamic::LayoutData* ldata,
}
bool centerOnNote = item->centerOnNotehead() || (!item->centerOnNotehead() && item->align().horizontal == AlignH::HCENTER);
- double noteHeadWidth = item->score()->noteHeadWidth();
+ double mag = item->staff()->staffMag(item);
+ double noteHeadWidth = item->score()->noteHeadWidth() * mag;
ldata->moveX(noteHeadWidth * (centerOnNote ? 0.5 : 1));
diff --git a/src/engraving/rendering/score/harmonylayout.cpp b/src/engraving/rendering/score/harmonylayout.cpp
index 1c4add953bc13..23b1f42869c90 100644
--- a/src/engraving/rendering/score/harmonylayout.cpp
+++ b/src/engraving/rendering/score/harmonylayout.cpp
@@ -774,6 +774,41 @@ void HarmonyLayout::renderActionParen(Harmony* item, const RenderActionParenPtr&
harmonyCtx.renderItemList.push_back(parenItem);
}
+void HarmonyLayout::kernCharacters(const Harmony* item, const String& text, HarmonyRenderCtx& harmonyCtx)
+{
+ if (harmonyCtx.renderItemList.empty()) {
+ return;
+ }
+ // Character pair and distance to move the second
+ static const std::map, double> KERNED_CHARACTERS {
+ { { u"A", u"\uE870" }, -0.4 }, // dim
+ { { u"A", u"\uE871" }, -0.3 }, // half-dim
+ { { u"\uE873", u"\uE870" }, -0.4 }, // triangle - dim
+ { { u"\uE873", u"\uE871" }, -0.3 }, // triangle - half-dim
+
+ { { u"A", u"\uE18E" }, -0.15 }, // dim JAZZ
+ { { u"A", u"\uE18F" }, -0.15 }, // hal-dim JAZZ
+ { { u"\uE18A", u"\uE18E" }, -0.15 }, // triangle - dim JAZZ
+ { { u"\uE18A", u"\uE18F" }, -0.15 }, // triangle - half-dim JAZZ
+ };
+
+ HarmonyRenderItem* prevSeg = harmonyCtx.renderItemList.back();
+ TextSegment* ts = dynamic_cast(prevSeg);
+ if (!ts) {
+ return;
+ }
+
+ for (auto& kernInfo : KERNED_CHARACTERS) {
+ const std::pair kernPair = kernInfo.first;
+ if (ts->text().endsWith(kernPair.first) && text.startsWith(kernPair.second)) {
+ const FontMetrics fm = FontMetrics(item->font());
+ const double scale = harmonyCtx.scale * item->mag();
+ harmonyCtx.pos = harmonyCtx.pos + PointF(kernInfo.second, 0.0) * FontMetrics::capHeight(item->font()) * scale;
+ break;
+ }
+ }
+}
+
void HarmonyLayout::renderActionSet(Harmony* item, Harmony::LayoutData* ldata, const RenderActionSetPtr& a, HarmonyRenderCtx& harmonyCtx)
{
const ChordList* chordList = item->score()->chordList();
@@ -786,6 +821,8 @@ void HarmonyLayout::renderActionSet(Harmony* item, Harmony::LayoutData* ldata, c
font.setPointSizeF(font.pointSizeF() * nmag);
}
+ kernCharacters(item, text, harmonyCtx);
+
TextSegment* ts = new TextSegment(text, font, harmonyCtx.x(), harmonyCtx.y(), harmonyCtx.hAlign);
harmonyCtx.movex(ts->width());
diff --git a/src/engraving/rendering/score/harmonylayout.h b/src/engraving/rendering/score/harmonylayout.h
index ca5ec3cd7e5d3..d1cc3afb1e5f1 100644
--- a/src/engraving/rendering/score/harmonylayout.h
+++ b/src/engraving/rendering/score/harmonylayout.h
@@ -86,5 +86,7 @@ class HarmonyLayout
static void renderActionAlign(HarmonyRenderCtx& harmonyCtx);
static void renderActionScale(const RenderActionScalePtr& a, HarmonyRenderCtx& harmonyCtx);
static void renderActionParen(Harmony* item, const RenderActionParenPtr& a, HarmonyRenderCtx& harmonyCtx);
+
+ static void kernCharacters(const Harmony* item, const String& text, HarmonyRenderCtx& harmonyCtx);
};
}
diff --git a/src/engraving/rendering/score/restlayout.cpp b/src/engraving/rendering/score/restlayout.cpp
index 94e4933d48d72..e2a94301558d6 100644
--- a/src/engraving/rendering/score/restlayout.cpp
+++ b/src/engraving/rendering/score/restlayout.cpp
@@ -497,7 +497,11 @@ InterruptionPoints RestLayout::computeInterruptionPoints(const Measure* measure,
for (const Segment* segment = measure->first(SegmentType::ChordRest); segment; segment = segment->next(SegmentType::ChordRest)) {
for (track_idx_t track = sTrack; track < eTrack; ++track) {
EngravingItem* item = segment->element(track);
- if (item && item->isRest() && toRest(item)->isGap()) {
+ if (!item) {
+ continue;
+ }
+ const bool gapRest = item->isRest() && toRest(item)->isGap();
+ if (gapRest || !item->visible()) {
for (voice_idx_t voice = 0; voice < VOICES; ++voice) {
interruptionPointSets[voice].insert(segment->rtick());
interruptionPointSets[voice].insert(segment->rtick() + segment->ticks());
diff --git a/src/engraving/rendering/score/tlayout.cpp b/src/engraving/rendering/score/tlayout.cpp
index 9a159e3b75078..e51841267599d 100644
--- a/src/engraving/rendering/score/tlayout.cpp
+++ b/src/engraving/rendering/score/tlayout.cpp
@@ -3012,25 +3012,63 @@ void TLayout::layoutGraceNotesGroup2(const GraceNotesGroup* item, GraceNotesGrou
ldata->setShape(shape);
}
-void TLayout::layoutGradualTempoChangeSegment(GradualTempoChangeSegment* item, LayoutContext& ctx)
+void TLayout::manageTempoChangeSnapping(GradualTempoChangeSegment* item, LayoutContext& ctx)
{
- LAYOUT_CALL_ITEM(item);
-
GradualTempoChangeSegment::LayoutData* ldata = item->mutldata();
ldata->disconnectSnappedItems();
-
- layoutTextLineBaseSegment(item, ctx);
-
GradualTempoChangeSegment* tempoChangeSegmentSnappedBefore = item->findElementToSnapBefore();
if (tempoChangeSegmentSnappedBefore) {
ldata->connectItemSnappedBefore(tempoChangeSegmentSnappedBefore);
+ doLayoutGradualTempoChangeSegment(tempoChangeSegmentSnappedBefore, ctx);
}
TempoText* tempoTextSnappedAfter = item->findElementToSnapAfter();
if (tempoTextSnappedAfter) {
ldata->connectItemSnappedAfter(tempoTextSnappedAfter);
}
+}
+
+void TLayout::doLayoutGradualTempoChangeSegment(GradualTempoChangeSegment* item, LayoutContext& ctx)
+{
+ GradualTempoChangeSegment::LayoutData* ldata = item->mutldata();
+
+ auto extendLineToSnappedItemAfter = [item](EngravingItem* itemAfter) {
+ assert(itemAfter->isGradualTempoChangeSegment() || itemAfter->isTempoText());
+ if (item->tempoChange()->adjustForRehearsalMark(false)
+ || itemAfter->findAncestor(ElementType::SYSTEM) != item->system()) {
+ return;
+ }
+
+ double xItemPos = itemAfter->pageX() - item->system()->pageX();
+ double itemLeftEdge = xItemPos + itemAfter->ldata()->bbox().left();
+
+ double padding = item->spatium();
+ if (itemAfter->isTempoText()) {
+ const double fontSizeScaleFactor = toTempoText(itemAfter)->size() / 10.0;
+ padding = 0.5 * item->spatium() * fontSizeScaleFactor;
+ } else if (itemAfter->isGradualTempoChangeSegment()) {
+ Text* startText = toGradualTempoChangeSegment(itemAfter)->text();
+ if (startText) {
+ const double fontSizeScaleFactor = startText->size() / 10.0;
+ padding = 0.5 * item->spatium() * fontSizeScaleFactor;
+ }
+ }
+
+ double maxTempoLineEnd = itemLeftEdge - padding;
+ double xEndDiff = maxTempoLineEnd - (item->pos().x() + item->pos2().x());
+ item->rxpos2() += xEndDiff;
+ };
+
+ if (ldata->itemSnappedAfter() && ldata->itemSnappedAfter()->isTempoText()) {
+ TempoText* tempoTextSnappedAfter = toTempoText(ldata->itemSnappedAfter());
+ extendLineToSnappedItemAfter(tempoTextSnappedAfter);
+ } else if (ldata->itemSnappedAfter() && ldata->itemSnappedAfter()->isGradualTempoChangeSegment()) {
+ GradualTempoChangeSegment* tempoChangeSegmentSnappedAfter = toGradualTempoChangeSegment(ldata->itemSnappedAfter());
+ extendLineToSnappedItemAfter(tempoChangeSegmentSnappedAfter);
+ }
+
+ mu::engraving::rendering::score::TLayout::layoutTextLineBaseSegment(item, ctx);
if (item->isStyled(Pid::OFFSET)) {
item->roffset() = item->tempoChange()->propertyDefault(Pid::OFFSET).value();
@@ -3042,6 +3080,15 @@ void TLayout::layoutGradualTempoChangeSegment(GradualTempoChangeSegment* item, L
Autoplace::autoplaceSpannerSegment(item, ldata, ctx.conf().spatium());
}
+void TLayout::layoutGradualTempoChangeSegment(GradualTempoChangeSegment* item, LayoutContext& ctx)
+{
+ LAYOUT_CALL_ITEM(item);
+
+ manageTempoChangeSnapping(item, ctx);
+
+ doLayoutGradualTempoChangeSegment(item, ctx);
+}
+
void TLayout::layoutGradualTempoChange(GradualTempoChange* item, LayoutContext& ctx)
{
LAYOUT_CALL_ITEM(item);
@@ -3285,7 +3332,8 @@ void TLayout::manageHairpinSnapping(HairpinSegment* item, LayoutContext& ctx)
}
// In case of dynamics/expressions before or after, make space for them horizontally
- double hairpinDistToDynOrExpr = ctx.conf().style().styleMM(Sid::autoplaceHairpinDynamicsDistance);
+ double mag = item->staff()->staffMag(item);
+ double hairpinDistToDynOrExpr = ctx.conf().style().styleMM(Sid::autoplaceHairpinDynamicsDistance) * mag;
bool makeSpaceBefore = (doSnapBefore && possibleSnapBeforeElement->isTextBase())
|| (possibleSnapBeforeElement && possibleSnapBeforeElement->isDynamic());
@@ -5876,16 +5924,10 @@ void TLayout::layoutTempoText(const TempoText* item, TempoText::LayoutData* ldat
Segment* s = item->segment();
RehearsalMark* rehearsalMark = toRehearsalMark(s->findAnnotation(ElementType::REHEARSAL_MARK, item->track(), item->track()));
- RectF rehearsMarkBbox = rehearsalMark ? rehearsalMark->ldata()->bbox().translated(rehearsalMark->pos()) : RectF();
+ RectF rehearsalMarkBbox = rehearsalMark ? rehearsalMark->ldata()->bbox().translated(rehearsalMark->pos()) : RectF();
RectF thisBbox = ldata->bbox().translated(item->pos());
- if (rehearsalMark && rehearsMarkBbox.bottom() > thisBbox.top()
- && item->getProperty(Pid::TEMPO_ALIGN_RIGHT_OF_REHEARSAL_MARK).toBool()) {
- double rightEdge = rehearsMarkBbox.right();
- const double padding = 0.5 * item->fontMetrics().xHeight();
- double curX = ldata->pos().x();
- ldata->setPosX(std::max(curX, rightEdge + padding));
- } else if (s->rtick().isZero()) {
+ if (s->rtick().isZero()) {
Segment* p = item->segment()->prev(SegmentType::TimeSig);
if (p && !p->allElementsInvisible()) {
ldata->moveX(-(s->x() - p->x()));
@@ -5895,6 +5937,21 @@ void TLayout::layoutTempoText(const TempoText* item, TempoText::LayoutData* ldat
}
}
}
+
+ if (rehearsalMark) {
+ const bool sameSide = item->placeAbove() == rehearsalMark->placeAbove();
+ const bool collision
+ = item->placeAbove() ? muse::RealIsEqualOrMore(rehearsalMarkBbox.bottom(), thisBbox.top()) : muse::RealIsEqualOrLess(
+ rehearsalMarkBbox.top(), thisBbox.bottom());
+
+ if (sameSide && collision && item->getProperty(Pid::TEMPO_ALIGN_RIGHT_OF_REHEARSAL_MARK).toBool()) {
+ double rightEdge = rehearsalMarkBbox.right();
+ const double fontSizeScaleFactor = item->size() / 10.0;
+ const double padding = 0.5 * item->spatium() * fontSizeScaleFactor;
+ double curX = ldata->pos().x();
+ ldata->setPosX(std::max(curX, rightEdge + padding));
+ }
+ }
Autoplace::autoplaceSegmentElement(item, ldata);
}
diff --git a/src/engraving/rendering/score/tlayout.h b/src/engraving/rendering/score/tlayout.h
index 2cd13553ab79e..9aed960629b0a 100644
--- a/src/engraving/rendering/score/tlayout.h
+++ b/src/engraving/rendering/score/tlayout.h
@@ -402,6 +402,9 @@ class TLayout
static void manageHairpinSnapping(HairpinSegment* item, LayoutContext& ctx);
static void checkRehearsalMarkVSBigTimeSig(const RehearsalMark* item, RehearsalMark::LayoutData* ldata);
+
+ static void manageTempoChangeSnapping(GradualTempoChangeSegment* item, LayoutContext& ctx);
+ static void doLayoutGradualTempoChangeSegment(GradualTempoChangeSegment* item, LayoutContext& ctx);
};
}
diff --git a/src/engraving/rw/read460/tread.cpp b/src/engraving/rw/read460/tread.cpp
index 430a3b1dde837..02376cdf4406a 100644
--- a/src/engraving/rw/read460/tread.cpp
+++ b/src/engraving/rw/read460/tread.cpp
@@ -2973,6 +2973,7 @@ void TRead::read(Harmony* h, XmlReader& e, ReadContext& ctx)
} else if (TRead::readProperty(h, tag, e, ctx, Pid::HARMONY_VOICE_LITERAL)) {
} else if (TRead::readProperty(h, tag, e, ctx, Pid::HARMONY_VOICING)) {
} else if (TRead::readProperty(h, tag, e, ctx, Pid::HARMONY_DURATION)) {
+ } else if (TRead::readProperty(h, tag, e, ctx, Pid::HARMONY_BASS_SCALE)) {
} else if (TRead::readProperty(h, tag, e, ctx, Pid::HARMONY_DO_NOT_STACK_MODIFIERS)) {
} else if (!readProperties(static_cast(h), e, ctx)) {
e.unknown();
diff --git a/vtest/scores/dynamics-15.mscz b/vtest/scores/dynamics-15.mscz
new file mode 100644
index 0000000000000..0a43579b6563a
Binary files /dev/null and b/vtest/scores/dynamics-15.mscz differ
diff --git a/vtest/scores/harmony-39.mscz b/vtest/scores/harmony-39.mscz
new file mode 100644
index 0000000000000..94758e786c226
Binary files /dev/null and b/vtest/scores/harmony-39.mscz differ
diff --git a/vtest/scores/harmony-40.mscz b/vtest/scores/harmony-40.mscz
new file mode 100644
index 0000000000000..498770de7702b
Binary files /dev/null and b/vtest/scores/harmony-40.mscz differ
diff --git a/vtest/scores/harmony-41.mscz b/vtest/scores/harmony-41.mscz
new file mode 100644
index 0000000000000..5fb7ffa8e201d
Binary files /dev/null and b/vtest/scores/harmony-41.mscz differ
diff --git a/vtest/scores/rests-13.mscz b/vtest/scores/rests-13.mscz
new file mode 100644
index 0000000000000..433d1a5be1c60
Binary files /dev/null and b/vtest/scores/rests-13.mscz differ
diff --git a/vtest/scores/tempoChangeLines-2.mscz b/vtest/scores/tempoChangeLines-2.mscz
new file mode 100644
index 0000000000000..2f02e79c24eec
Binary files /dev/null and b/vtest/scores/tempoChangeLines-2.mscz differ
diff --git a/vtest/scores/tempoText-2.mscz b/vtest/scores/tempoText-2.mscz
new file mode 100644
index 0000000000000..a3fb706bc9053
Binary files /dev/null and b/vtest/scores/tempoText-2.mscz differ
diff --git a/vtest/scores/tie-26.mscz b/vtest/scores/tie-26.mscz
new file mode 100644
index 0000000000000..1edecbe4d247c
Binary files /dev/null and b/vtest/scores/tie-26.mscz differ