diff --git a/include/vrv/annotscore.h b/include/vrv/annotscore.h new file mode 100644 index 0000000000..b35110d445 --- /dev/null +++ b/include/vrv/annotscore.h @@ -0,0 +1,88 @@ +///////////////////////////////////////////////////////////////////////////// +// Name: annotscore.h +// Author: David Lewis +// Created: 2024 +// Copyright (c) Authors and others. All rights reserved. +///////////////////////////////////////////////////////////////////////////// + +#ifndef __VRV_ANNOTSCORE_H__ +#define __VRV_ANNOTSCORE_H__ + +#include "atts_cmn.h" +#include "atts_shared.h" +#include "controlelement.h" +#include "editorial.h" +#include "timeinterface.h" + +namespace vrv { + +//---------------------------------------------------------------------------- +// AnnotScore +//---------------------------------------------------------------------------- + +/** + * This class models the MEI element where @type is score. + */ +class AnnotScore : public ControlElement, public TimeSpanningInterface, public AttPlist { +public: + /** + * @name Constructors, destructors, and other standard methods + * Reset method reset all attribute classes + */ + ///@{ + AnnotScore(); + virtual ~AnnotScore(); + // Object *Clone() const override { return new AnnotScore(*this); } + void Reset() override; + std::string GetClassName() const override { return "AnnotScore"; } + ///@} + + /** + * @name Getter to interfaces + */ + ///@{ + TimePointInterface *GetTimePointInterface() override { return vrv_cast(this); } + const TimePointInterface *GetTimePointInterface() const override + { + return vrv_cast(this); + } + TimeSpanningInterface *GetTimeSpanningInterface() override { return vrv_cast(this); } + const TimeSpanningInterface *GetTimeSpanningInterface() const override + { + return vrv_cast(this); + } + + /** + * Add a text element to an annotation. + * Only supported elements will be actually added to the child list. + */ + bool IsSupportedChild(Object *object) override; + + ///@} + + //----------// + // Functors // + //----------// + + /** + * Interface for class functor visitation + */ + ///@{ + FunctorCode Accept(Functor &functor) override; + FunctorCode Accept(ConstFunctor &functor) const override; + FunctorCode AcceptEnd(Functor &functor) override; + FunctorCode AcceptEnd(ConstFunctor &functor) const override; + ///@} + +protected: + // +private: + // +public: + // +private: +}; + +} // namespace vrv + +#endif diff --git a/include/vrv/functorinterface.h b/include/vrv/functorinterface.h index f24743f583..f4faf6eb64 100644 --- a/include/vrv/functorinterface.h +++ b/include/vrv/functorinterface.h @@ -16,6 +16,7 @@ class Accid; class Alignment; class AlignmentReference; class AnchoredText; +class AnnotScore; class Arpeg; class Artic; class BarLine; @@ -280,6 +281,8 @@ class FunctorInterface { ///@{ virtual FunctorCode VisitAnchoredText(AnchoredText *anchoredText); virtual FunctorCode VisitAnchoredTextEnd(AnchoredText *anchoredText); + virtual FunctorCode VisitAnnotScore(AnnotScore *annotScore); + virtual FunctorCode VisitAnnotScoreEnd(AnnotScore *annotScore); virtual FunctorCode VisitArpeg(Arpeg *arpeg); virtual FunctorCode VisitArpegEnd(Arpeg *arpeg); virtual FunctorCode VisitBeamSpan(BeamSpan *beamSpan); @@ -653,6 +656,8 @@ class ConstFunctorInterface { ///@{ virtual FunctorCode VisitAnchoredText(const AnchoredText *anchoredText); virtual FunctorCode VisitAnchoredTextEnd(const AnchoredText *anchoredText); + virtual FunctorCode VisitAnnotScore(const AnnotScore *annotScore); + virtual FunctorCode VisitAnnotScoreEnd(const AnnotScore *annotScore); virtual FunctorCode VisitArpeg(const Arpeg *arpeg); virtual FunctorCode VisitArpegEnd(const Arpeg *arpeg); virtual FunctorCode VisitBeamSpan(const BeamSpan *beamSpan); diff --git a/include/vrv/iomei.h b/include/vrv/iomei.h index e58c74f20c..d0a8169f90 100644 --- a/include/vrv/iomei.h +++ b/include/vrv/iomei.h @@ -28,6 +28,7 @@ class Add; class AltSymInterface; class AnchoredText; class Annot; +class AnnotScore; class App; class AreaPosInterface; class Arpeg; @@ -432,6 +433,7 @@ class MEIOutput : public Output { */ ///@{ void WriteAnchoredText(pugi::xml_node currentNode, AnchoredText *anchoredText); + void WriteAnnotScore(pugi::xml_node currentNode, AnnotScore *annotScore); void WriteArpeg(pugi::xml_node currentNode, Arpeg *arpeg); void WriteBeamSpan(pugi::xml_node currentNode, BeamSpan *beamSpan); void WriteBracketSpan(pugi::xml_node currentNode, BracketSpan *bracketSpan); @@ -800,6 +802,7 @@ class MEIInput : public Input { bool ReadAbbr(Object *parent, pugi::xml_node abbr, EditorialLevel level, Object *filter = NULL); bool ReadAdd(Object *parent, pugi::xml_node add, EditorialLevel level, Object *filter = NULL); bool ReadAnnot(Object *parent, pugi::xml_node annot); + bool ReadAnnotScore(Object *parent, pugi::xml_node annot); bool ReadApp(Object *parent, pugi::xml_node app, EditorialLevel level, Object *filter = NULL); bool ReadAppChildren(Object *parent, pugi::xml_node parentNode, EditorialLevel level, Object *filter = NULL); bool ReadChoice(Object *parent, pugi::xml_node choice, EditorialLevel level, Object *filter = NULL); @@ -865,6 +868,11 @@ class MEIInput : public Input { */ void ReadUnsupportedAttr(pugi::xml_node element, Object *object); + /** + * Returns true if the element is a 'score' annotation. Currently based on @type + */ + bool IsAnnotScore(pugi::xml_node element); + /** * Returns true if the element is name is an editorial element (e.g., "app", "supplied", etc.) */ diff --git a/include/vrv/vrvdef.h b/include/vrv/vrvdef.h index 750326523f..dd83f73f48 100644 --- a/include/vrv/vrvdef.h +++ b/include/vrv/vrvdef.h @@ -176,6 +176,7 @@ enum ClassId : uint16_t { // Ids for ControlElement child classes CONTROL_ELEMENT, ANCHOREDTEXT, + ANNOTSCORE, ARPEG, BEAMSPAN, BRACKETSPAN, diff --git a/src/annotscore.cpp b/src/annotscore.cpp new file mode 100644 index 0000000000..7b37810eb8 --- /dev/null +++ b/src/annotscore.cpp @@ -0,0 +1,86 @@ +///////////////////////////////////////////////////////////////////////////// +// Name: annotscore.cpp +// Author: David Lewis +// Created: 2024 +// Copyright (c) Authors and others. All rights reserved. +///////////////////////////////////////////////////////////////////////////// + +#include "annotscore.h" + +//---------------------------------------------------------------------------- + +#include + +//---------------------------------------------------------------------------- + +#include "devicecontext.h" +#include "doc.h" +#include "functor.h" +#include "text.h" +#include "verticalaligner.h" +#include "vrv.h" + +namespace vrv { + +//---------------------------------------------------------------------------- +// AnnotScore +//---------------------------------------------------------------------------- + +static const ClassRegistrar s_factory("annotScore", ANNOTSCORE); + +AnnotScore::AnnotScore() : ControlElement(ANNOTSCORE, "annotscore-"), AttPlist() +{ + this->RegisterInterface(TimeSpanningInterface::GetAttClasses(), TimeSpanningInterface::IsInterface()); + this->RegisterAttClass(ATT_PLIST); + + this->Reset(); +} + +AnnotScore::~AnnotScore() {} + +void AnnotScore::Reset() +{ + ControlElement::Reset(); + this->ResetPlist(); + TimeSpanningInterface::Reset(); +} + +bool AnnotScore::IsSupportedChild(Object *child) +{ + if (child->IsTextElement()) { + assert(dynamic_cast(child)); + } + else if (child->Is(ANNOT)) { + assert(dynamic_cast(child)); + } + else { + return false; + } + return true; +} + +//---------------------------------------------------------------------------- +// AnnotScore functor methods +//---------------------------------------------------------------------------- + +FunctorCode AnnotScore::Accept(Functor &functor) +{ + return functor.VisitAnnotScore(this); +} + +FunctorCode AnnotScore::Accept(ConstFunctor &functor) const +{ + return functor.VisitAnnotScore(this); +} + +FunctorCode AnnotScore::AcceptEnd(Functor &functor) +{ + return functor.VisitAnnotScoreEnd(this); +} + +FunctorCode AnnotScore::AcceptEnd(ConstFunctor &functor) const +{ + return functor.VisitAnnotScoreEnd(this); +} + +} // namespace vrv diff --git a/src/functorinterface.cpp b/src/functorinterface.cpp index 202645cbbb..24fe283336 100644 --- a/src/functorinterface.cpp +++ b/src/functorinterface.cpp @@ -11,6 +11,7 @@ #include "accid.h" #include "anchoredtext.h" +#include "annotscore.h" #include "arpeg.h" #include "artic.h" #include "barline.h" @@ -490,6 +491,16 @@ FunctorCode FunctorInterface::VisitAnchoredTextEnd(AnchoredText *anchoredText) return this->VisitControlElementEnd(anchoredText); } +FunctorCode FunctorInterface::VisitAnnotScore(AnnotScore *annotScore) +{ + return this->VisitControlElement(annotScore); +} + +FunctorCode FunctorInterface::VisitAnnotScoreEnd(AnnotScore *annotScore) +{ + return this->VisitControlElementEnd(annotScore); +} + FunctorCode FunctorInterface::VisitArpeg(Arpeg *arpeg) { return this->VisitControlElement(arpeg); @@ -1824,6 +1835,16 @@ FunctorCode ConstFunctorInterface::VisitAnchoredTextEnd(const AnchoredText *anch return this->VisitControlElementEnd(anchoredText); } +FunctorCode ConstFunctorInterface::VisitAnnotScore(const AnnotScore *annotScore) +{ + return this->VisitControlElement(annotScore); +} + +FunctorCode ConstFunctorInterface::VisitAnnotScoreEnd(const AnnotScore *annotScore) +{ + return this->VisitControlElementEnd(annotScore); +} + FunctorCode ConstFunctorInterface::VisitArpeg(const Arpeg *arpeg) { return this->VisitControlElement(arpeg); diff --git a/src/iohumdrum.cpp b/src/iohumdrum.cpp index e4a02f50c3..428ceab63f 100644 --- a/src/iohumdrum.cpp +++ b/src/iohumdrum.cpp @@ -2939,7 +2939,7 @@ void HumdrumInput::createDigitalSource(pugi::xml_node sourceDesc) pugi::xml_node bibl = source.append_child("bibl"); bibl.append_copy(m_simpleTitle); for (pugi::xml_node_iterator childIt = m_simpleComposersDoc.begin(); childIt != m_simpleComposersDoc.end(); - ++childIt) { + ++childIt) { bibl.append_copy(*childIt); } @@ -3691,7 +3691,7 @@ void HumdrumInput::createPrintedSource(pugi::xml_node sourceDesc) bibl.append_copy(m_simpleTitle); for (pugi::xml_node_iterator childIt = m_simpleComposersDoc.begin(); childIt != m_simpleComposersDoc.end(); - ++childIt) { + ++childIt) { bibl.append_copy(*childIt); } diff --git a/src/iomei.cpp b/src/iomei.cpp index a6a4fe2b25..b197c6c5d6 100644 --- a/src/iomei.cpp +++ b/src/iomei.cpp @@ -20,6 +20,7 @@ #include "altsyminterface.h" #include "anchoredtext.h" #include "annot.h" +#include "annotscore.h" #include "app.h" #include "arpeg.h" #include "artic.h" @@ -472,6 +473,10 @@ bool MEIOutput::WriteObjectInternal(Object *object, bool useCustomScoreDef) m_currentNode = m_currentNode.append_child("anchoredText"); this->WriteAnchoredText(m_currentNode, vrv_cast(object)); } + else if (object->Is(ANNOTSCORE)) { + m_currentNode = m_currentNode.append_child("annot"); + this->WriteAnnotScore(m_currentNode, vrv_cast(object)); + } else if (object->Is(ARPEG)) { m_currentNode = m_currentNode.append_child("arpeg"); this->WriteArpeg(m_currentNode, vrv_cast(object)); @@ -1964,6 +1969,15 @@ void MEIOutput::WriteAnchoredText(pugi::xml_node currentNode, AnchoredText *anch this->WriteTextDirInterface(currentNode, anchoredText); } +void MEIOutput::WriteAnnotScore(pugi::xml_node currentNode, AnnotScore *annotScore) +{ + assert(annotScore); + + this->WriteControlElement(currentNode, annotScore); + annotScore->WritePlist(currentNode); + // Currently ignoring annot contents -- normal annot looks at child elements here +} + void MEIOutput::WriteArpeg(pugi::xml_node currentNode, Arpeg *arpeg) { assert(arpeg); @@ -5470,7 +5484,12 @@ bool MEIInput::ReadMeasureChildren(Object *parent, pugi::xml_node parentNode) this->NormalizeAttributes(current); // editorial if (this->IsEditorialElementName(currentName)) { - success = this->ReadEditorialElement(parent, current, EDITORIAL_MEASURE); + if (currentName == "annot" && this->IsAnnotScore(current)) { + success = this->ReadAnnotScore(parent, current); + } + else { + success = this->ReadEditorialElement(parent, current, EDITORIAL_MEASURE); + } } // content else if (currentName == "anchoredText") { @@ -7666,6 +7685,33 @@ bool MEIInput::ReadAnnot(Object *parent, pugi::xml_node annot) } } +bool MEIInput::ReadAnnotScore(Object *parent, pugi::xml_node annot) +{ + AnnotScore *vrvAnnotScore = new AnnotScore(); + // Note: there probably needs to be more in here (see model methods) + + vrvAnnotScore->ReadPlist(annot); + + parent->AddChild(vrvAnnotScore); + + bool hasNonTextContent = false; + // copy all the nodes inside into the document + for (pugi::xml_node child = annot.first_child(); child; child = child.next_sibling()) { + const std::string nodeName = child.name(); + if (!hasNonTextContent && (!nodeName.empty())) hasNonTextContent = true; + // This is also orphan code -- we can't copy the contents here + } + this->ReadUnsupportedAttr(annot, vrvAnnotScore); + // Unless annot has only text we do not load children because they are preserved in Annot::m_content + if (hasNonTextContent) { + return true; + } + else { + // Again, this is code that may not apply for annotScore + return this->ReadTextChildren(vrvAnnotScore, annot, vrvAnnotScore); + } +} + bool MEIInput::ReadApp(Object *parent, pugi::xml_node app, EditorialLevel level, Object *filter) { if (!m_hasScoreDef) { @@ -8264,6 +8310,13 @@ bool MEIInput::ReadXMLComment(Object *object, pugi::xml_node element) return true; } +bool MEIInput::IsAnnotScore(pugi::xml_node annot) +{ + // If the annotation is a score annotation, it'll have @type="score" (we can also guess) + std::string value = annot.attribute("type").value(); + return (value == "score"); +} + bool MEIInput::IsEditorialElementName(std::string elementName) { auto i = std::find(MEIInput::s_editorialElementNames.begin(), MEIInput::s_editorialElementNames.end(), elementName); diff --git a/src/iomusxml.cpp b/src/iomusxml.cpp index eb9d68fb6d..60c50fa09f 100644 --- a/src/iomusxml.cpp +++ b/src/iomusxml.cpp @@ -4739,8 +4739,8 @@ std::string MusicXmlInput::GetOrnamentGlyphNumber(int attributes) const static std::map precomposedNames = { { APPR_Above | FORM_Inverted, "U+E5C6" }, { APPR_Below | FORM_Inverted, "U+E5B5" }, { APPR_Above | FORM_Normal, "U+E5C7" }, { APPR_Below | FORM_Normal, "U+E5B8" }, - { FORM_Inverted | DEP_Above, "U+E5BB" }, { FORM_Inverted | DEP_Below, "U+E5C8" } - // these values need to be matched with proper SMuFL codes first + { FORM_Inverted | DEP_Above, "U+E5BB" }, + { FORM_Inverted | DEP_Below, "U+E5C8" } // these values need to be matched with proper SMuFL codes first /*, { FORM_Normal | DEP_Above, "U+????" }, { FORM_Normal | DEP_Below, "U+????" }, { APPR_Above | FORM_Normal | DEP_Above, "U+????" }, { APPR_Above | FORM_Normal | DEP_Above, "U+????" }, { APPR_Above | FORM_Normal | DEP_Below, "U+????" },