diff --git a/src/engraving/dom/note.h b/src/engraving/dom/note.h index 6c12f3df4e040..477eeadfb64cc 100644 --- a/src/engraving/dom/note.h +++ b/src/engraving/dom/note.h @@ -300,6 +300,8 @@ class Note final : public EngravingItem bool hidden() const { return m_hidden; } void setHidden(bool val) { m_hidden = val; } + bool hideNotehead() const { return m_hideNotehead; } + void setHideNotehead(bool val) { m_hideNotehead = val; } bool dotsHidden() const { return m_dotsHidden; } void setDotsHidden(bool val) { m_dotsHidden = val; } @@ -494,6 +496,8 @@ class Note final : public EngravingItem bool m_hidden = false; // marks this note as the hidden one if there are // overlapping notes; hidden notes are not played // and heads + accidentals are not shown + bool m_hideNotehead = false; // hides notehead glyph only for unison sharing; + // unlike m_hidden, does not affect playback or accidentals bool m_dotsHidden = false; // dots of hidden notes are hidden too // except if only one note is dotted bool m_fretConflict = false; // used by TAB staves to mark a fretting conflict: diff --git a/src/engraving/rendering/score/chordlayout.cpp b/src/engraving/rendering/score/chordlayout.cpp index 2fcd8b10808f0..e60f4bfea9d97 100644 --- a/src/engraving/rendering/score/chordlayout.cpp +++ b/src/engraving/rendering/score/chordlayout.cpp @@ -1992,12 +1992,28 @@ void ChordLayout::calculateChordOffsets(Segment* segment, staff_idx_t staffIdx, // thus user can force notes to be shared despite differing number of dots or either being stemless // by setting one of the notehead types to match the other or by making one notehead invisible // TODO: consider adding a style option, staff properties, or note property to control sharing - if ((nchord->dots() != pchord->dots() || !nchord->stem() || !pchord->stem() || nHeadType != pHeadType + + // check if the notes are unison + bool unisonMatch = (n->pitch() == p->pitch() && n->tpc() == p->tpc()); + + // for unisons we allow half noteheads to merge even with different durations, + // as the stem, flag, or beam makes the duration clear. + // dotted notes can also merge with non-dotted notes at unison. + if (((!unisonMatch && nchord->dots() != pchord->dots()) || !nchord->stem() || !pchord->stem() + || (nHeadType != pHeadType && !unisonMatch) || n->isSmall() || p->isSmall()) && ((n->headType() == NoteHeadType::HEAD_AUTO && p->headType() == NoteHeadType::HEAD_AUTO) || nHeadType != pHeadType) && (n->visible() == p->visible())) { shareHeads = false; + } else if (nHeadType != pHeadType && unisonMatch) { + // ensure if a unison includes an open notehead this is shown in + // preference to a filled notehead + if (nHeadType == NoteHeadType::HEAD_QUARTER) { + n->setHideNotehead(true); + } else if (pHeadType == NoteHeadType::HEAD_QUARTER) { + p->setHideNotehead(true); + } } } @@ -2381,6 +2397,7 @@ double ChordLayout::layoutChords2(std::vector& notes, bool up, LayoutCont // by default, notes and dots are not hidden // this may be changed later to allow unisons to share noteheads note->setHidden(false); + note->setHideNotehead(false); note->setDotsHidden(false); // be sure chord position is initialized diff --git a/src/engraving/rendering/score/tlayout.cpp b/src/engraving/rendering/score/tlayout.cpp index 7a458497d5228..3bd702ae5832f 100644 --- a/src/engraving/rendering/score/tlayout.cpp +++ b/src/engraving/rendering/score/tlayout.cpp @@ -4137,7 +4137,7 @@ void TLayout::layoutNote(const Note* item, Note::LayoutData* ldata) const_cast(item)->setHeadGroup(NoteHeadGroup::HEAD_DIAMOND); } - SymId nh = item->noteHead(); + SymId nh = item->hideNotehead() ? SymId::noSym : item->noteHead(); ldata->cachedNoteheadSym.set_value(nh); if (item->isNoteName()) {