LCOV - code coverage report
Current view: top level - src/engraving/dom - harmony.h Coverage Total Hit
Test: filtered_coverage.info Lines: 94.0 % 67 63
Test Date: 2026-11-05 04:07:02

            Line data    Source code
       1              : /*
       2              :  * SPDX-License-Identifier: GPL-3.0-only
       3              :  * MuseScore-Studio-CLA-applies
       4              :  *
       5              :  * MuseScore Studio
       6              :  * Music Composition & Notation
       7              :  *
       8              :  * Copyright (C) 2021 MuseScore Limited and others
       9              :  *
      10              :  * This program is free software: you can redistribute it and/or modify
      11              :  * it under the terms of the GNU General Public License version 3 as
      12              :  * published by the Free Software Foundation.
      13              :  *
      14              :  * This program is distributed in the hope that it will be useful,
      15              :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      16              :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      17              :  * GNU General Public License for more details.
      18              :  *
      19              :  * You should have received a copy of the GNU General Public License
      20              :  * along with this program.  If not, see <https://www.gnu.org/licenses/>.
      21              :  */
      22              : #pragma once
      23              : 
      24              : #include <vector>
      25              : 
      26              : #include "chordlist.h"
      27              : #include "parenthesis.h"
      28              : #include "draw/types/font.h"
      29              : 
      30              : #include "textbase.h"
      31              : #include "score.h"
      32              : 
      33              : #include "pitchspelling.h"
      34              : #include "realizedharmony.h"
      35              : 
      36              : namespace mu::engraving {
      37              : struct ChordDescription;
      38              : class ParsedChord;
      39              : class Score;
      40              : class Transaction;
      41              : 
      42              : enum class HarmonyType : unsigned char {
      43              :     STANDARD,
      44              :     ROMAN,
      45              :     NASHVILLE
      46              : };
      47              : 
      48              : enum class HarmonyRenderItemType : unsigned char {
      49              :     TEXT,
      50              :     PAREN
      51              : };
      52              : 
      53              : struct HarmonyRenderItem {
      54        10618 :     virtual ~HarmonyRenderItem() = default;
      55        10746 :     HarmonyRenderItem(bool align, double _x, double _y)
      56        10746 :         : m_hAlign(align), m_pos(_x, _y) {}
      57              : 
      58        18034 :     PointF pos() const { return m_pos + m_offset; }
      59        10842 :     double x() const { return m_pos.x(); }
      60        35530 :     double y() const { return m_pos.y(); }
      61        10802 :     void movex(double v) { m_pos.rx() += v; }
      62           30 :     void movey(double v) { m_pos.ry() += v; }
      63           32 :     void setx(double v) { m_pos.rx() = v; }
      64           64 :     void sety(double v) { m_pos.ry() = v; }
      65        10746 :     void setOffset(const PointF& p) { m_offset = p; }
      66              : 
      67              :     virtual double height() const = 0;
      68              : 
      69        10746 :     bool align() const { return m_hAlign; }
      70              : 
      71              :     virtual RectF boundingRect() const = 0;
      72              :     virtual RectF tightBoundingRect() const = 0;
      73              : 
      74              :     virtual double leftPadding() const = 0;
      75              :     virtual double rightPadding() const = 0;
      76              : 
      77              :     virtual HarmonyRenderItemType type() const = 0;
      78              : 
      79              : private:
      80              :     bool m_hAlign = true;
      81              :     PointF m_offset;       // Offset for placing within the TextBase.
      82              :     PointF m_pos;          // Position of segments relative to Harmony position
      83              : };
      84              : 
      85              : struct ChordSymbolParen : HarmonyRenderItem {
      86           64 :     ChordSymbolParen(Parenthesis* p, bool hAlign, double _x, double _y)
      87           64 :         : HarmonyRenderItem(hAlign, _x, _y), parenItem(p) {}
      88           96 :     ~ChordSymbolParen() { delete parenItem; }
      89              : 
      90            0 :     RectF boundingRect() const override { return parenItem->shape().bbox(); }
      91           64 :     RectF tightBoundingRect() const override { return parenItem->shape().bbox(); }
      92              : 
      93              :     double top = DBL_MAX;
      94              :     double bottom = -DBL_MAX;
      95              :     double closingParenPos = -DBL_MAX;
      96              : 
      97              :     Parenthesis* parenItem = nullptr;
      98              : 
      99          128 :     double height() const override { return parenItem->height(); }
     100              : 
     101           64 :     double leftPadding() const override { return parenItem->direction() == DirectionH::LEFT ? OUTER_PADDING : INNER_PADDING; }
     102           32 :     double rightPadding() const override { return parenItem->direction() == DirectionH::LEFT ? INNER_PADDING : OUTER_PADDING; }
     103              : 
     104           96 :     HarmonyRenderItemType type() const override { return HarmonyRenderItemType::PAREN; }
     105              : 
     106              : private:
     107              :     static constexpr double INNER_PADDING = 0.05;
     108              :     static constexpr double OUTER_PADDING = 0.1;
     109              : };
     110              : 
     111              : //---------------------------------------------------------
     112              : //   TextSegment
     113              : //---------------------------------------------------------
     114              : 
     115              : struct TextSegment : HarmonyRenderItem {
     116              :     double width() const;
     117              :     double capHeight() const;
     118              :     RectF boundingRect() const override;
     119              :     RectF tightBoundingRect() const override;
     120              : 
     121        10682 :     void setText(const String& t) { m_text = t; }
     122        89830 :     String text() const { return m_text; }
     123              : 
     124           96 :     muse::draw::Font font() const { return m_font; }
     125              :     void setFont(const muse::draw::Font& f);
     126              : 
     127         7122 :     double leftPadding() const override { return 0.0; }
     128         7154 :     double rightPadding() const override { return 0.0; }
     129              : 
     130        28518 :     double height() const override { return tightBoundingRect().height(); }
     131              : 
     132        14276 :     HarmonyRenderItemType type() const override { return HarmonyRenderItemType::TEXT; }
     133              : 
     134        10682 :     TextSegment(const String& s, const muse::draw::Font& f, double _x, double _y, bool align)
     135        10682 :         : HarmonyRenderItem(align, _x, _y) { setText(s); setFont(f); }
     136              : 
     137              : private:
     138              :     muse::draw::Font m_font;
     139              :     String m_text;
     140              : };
     141              : 
     142              : class HDegree;
     143              : 
     144              : //---------------------------------------------------------
     145              : //   @@ HarmonyInfo
     146              : //      Contains all identifying information for a chord. The Harmony DOM class can have many of these
     147              : //      as polychords
     148              : //
     149              : //   @P m_bassTpc       int             bass note as "tonal pitch class"
     150              : //   @P m_rootTpc       int             root note as "tonal pitch class"
     151              : //   @P m_id            int             harmony identifier
     152              : //   @P m_textName      String          plaintext representation of chord
     153              : //   @P m_parsedChord   ParsedChord*    parsed representation of the plaintext chord
     154              : //---------------------------------------------------------
     155              : 
     156              : class HarmonyInfo
     157              : {
     158              : public:
     159              :     HarmonyInfo(int id, int rootTpc, int bassTpc, String textName, ParsedChord* pc, Score* score)
     160              :         : m_id(id), m_rootTpc(rootTpc), m_bassTpc(bassTpc), m_textName(textName), m_parsedChord(pc), m_score(score) {}
     161         1078 :     HarmonyInfo(Score* score)
     162         1078 :         : m_score(score) {}
     163              :     HarmonyInfo(const HarmonyInfo& h);
     164              :     ~HarmonyInfo();
     165              : 
     166         7621 :     int id() const { return m_id; }
     167          367 :     void setId(int v) { m_id = v; }
     168              : 
     169         9284 :     int rootTpc() const { return m_rootTpc; }
     170         1187 :     void setRootTpc(int v) { m_rootTpc = v; }
     171              : 
     172         6087 :     int bassTpc() const { return m_bassTpc; }
     173          416 :     void setBassTpc(int v) { m_bassTpc = v; }
     174              : 
     175         3291 :     String textName() const { return m_textName; }
     176          756 :     void setTextName(const String& v) { m_textName = v; }
     177              : 
     178        19012 :     ChordList* chordList() const { return m_score ? m_score->chordList() : nullptr; }
     179              : 
     180              :     const ChordDescription* descr() const;
     181              :     const ChordDescription* descr(const String&, const ParsedChord* pc = 0) const;
     182              :     const ChordDescription* getDescription();
     183              :     const ChordDescription* getDescription(const String&, const ParsedChord* pc = 0);
     184              :     const ChordDescription* generateDescription();
     185              : 
     186          150 :     void setParsedChord(ParsedChord* v) { m_parsedChord = v; }
     187         1300 :     ParsedChord* parsedChord() const { return m_parsedChord; }
     188              :     ParsedChord* getParsedChord();
     189              : 
     190              :     bool hasModifiers() const;
     191              : 
     192              : private:
     193              :     int m_id = -1;                          // >0 = id of matched chord from chord list, if applicable
     194              :                                             // -1 = invalid chord
     195              :                                             // <-10000 = private id of generated chord or matched chord with no id
     196              :     int m_rootTpc = Tpc::TPC_INVALID;       // root note for chord
     197              :     int m_bassTpc = Tpc::TPC_INVALID;       // bass note or chord bass; used for "slash" chords
     198              :                                             // or notation of bass note in chord
     199              : 
     200              :     String m_textName;                      // name recognized from chord list, read from score file, or constructed from imported source
     201              :                                             // Also stores the whole RNA string to be rendered
     202              :     ParsedChord* m_parsedChord = nullptr;   // parsed form of chord
     203              :     Score* m_score = nullptr;
     204              : };
     205              : 
     206              : //---------------------------------------------------------
     207              : //   @@ Harmony
     208              : //      This DOM class represents the chord symbol in the score. It contains the necessary information to
     209              : //      layout standard chords and polychords
     210              : //---------------------------------------------------------
     211              : 
     212              : class Harmony final : public TextBase
     213              : {
     214         2201 :     OBJECT_ALLOCATOR(engraving, Harmony)
     215        33394 :     DECLARE_CLASSOF(ElementType::HARMONY)
     216              : 
     217              : public:
     218              :     Harmony(EngravingObject* parent = 0); // Segment or FretDiagram
     219              :     Harmony(const Harmony&);
     220              :     ~Harmony();
     221              : 
     222           44 :     Harmony* clone() const override { return new Harmony(*this); }
     223              : 
     224              :     int id() const; // WILL BE DEPRECATED AFTER RelaizedHarmony IS UPDATED
     225              : 
     226            0 :     bool play() const { return m_play; }
     227              : 
     228            3 :     void setBassCase(NoteCaseType c) { m_bassCase = c; }
     229          748 :     NoteCaseType bassCase() const { return m_bassCase; }
     230            3 :     void setRootCase(NoteCaseType c) { m_rootCase = c; }
     231          749 :     NoteCaseType rootCase() const { return m_rootCase; }
     232              : 
     233              :     Segment* getParentSeg() const;
     234              :     FretDiagram* getParentFretDiagram() const;
     235              :     Harmony* findNext() const;
     236              :     Harmony* findPrev() const;
     237              :     Fraction ticksTillNext(int utick, bool stopAtMeasureEnd = false) const;
     238              : 
     239              :     RealizedHarmony& realizedHarmony();
     240              :     const RealizedHarmony& getRealizedHarmony() const;
     241              : 
     242            0 :     bool isEditable() const override { return !isInFretBox(); }
     243              :     void startEdit(EditData&) override;
     244              :     bool isEditAllowed(EditData&) const override;
     245              :     bool edit(EditData&) override;
     246              :     void endEdit(EditData&) override;
     247              : 
     248              :     bool isPlayable() const override;
     249              : 
     250              :     bool isRealizable() const;
     251              :     bool isInFretBox() const;
     252              : 
     253              :     int bassTpc() const;                           // WILL BE DEPRECATED AFTER RelaizedHarmony IS UPDATED
     254              :     int rootTpc() const;                           // WILL BE DEPRECATED AFTER RelaizedHarmony IS UPDATED
     255              :     void addDegree(const HDegree& d);
     256              :     const std::vector<HDegree>& degreeList() const;
     257        21382 :     HarmonyType harmonyType() const { return m_harmonyType; }
     258              :     void setHarmonyType(HarmonyType val);
     259              : 
     260              :     const ParsedChord* parsedForm() const;                                             // WILL BE DEPRECATED AFTER RelaizedHarmony IS UPDATED
     261              : 
     262              :     void afterRead();
     263              :     void render();
     264              : 
     265         3759 :     bool isPolychord() const { return m_chords.size() > 1; }
     266        17189 :     const std::vector<HarmonyInfo*> chords() const { return m_chords; }
     267          990 :     void addChord(HarmonyInfo* info) { m_chords.push_back(info); }
     268              : 
     269              :     bool hasModifiers() const;
     270              : 
     271              :     String displayText() const;
     272              :     String harmonyName() const;
     273              : 
     274              :     double baseLine() const override;
     275              :     void spatiumChanged(double oldValue, double newValue) override;
     276              :     void localSpatiumChanged(double oldValue, double newValue) override;
     277              :     void setHarmony(const String& s);
     278              : 
     279          542 :     int subtype() const override { return static_cast<int>(harmonyType()); }
     280              : 
     281              :     TranslatableString typeUserName() const override;
     282              :     String accessibleInfo() const override;
     283              :     String generateScreenReaderInfo() const;
     284              :     String screenReaderInfo() const override;
     285              : 
     286              :     bool acceptDrop(EditData&) const override;
     287              :     EngravingItem* drop(Transaction& tx, EditData&) override;
     288              : 
     289              :     void undoChangeProperty(Pid id, const PropertyValue& v, PropertyFlags ps) override;
     290              :     using EngravingObject::undoChangeProperty;
     291              :     PropertyValue getProperty(Pid propertyId) const override;
     292              :     bool setProperty(Pid propertyId, const PropertyValue& v) override;
     293              :     PropertyValue propertyDefault(Pid id) const override;
     294              : 
     295              :     bool positionRelativeToNoteheadRest() const override;
     296              : 
     297              :     double mag() const override;
     298              : 
     299           55 :     double bassScale() const { return m_bassScale; }
     300         1134 :     void setBassScale(double v) { m_bassScale = v; }
     301              : 
     302              :     Color curColor(const rendering::PaintOptions& opt) const override;
     303              :     void setColor(const Color& color) override;
     304              : 
     305            0 :     bool doNotStackModifiers() const { return m_doNotStackModifiers; }
     306              : 
     307              :     NoteCaseType rootRenderCase(HarmonyInfo* info) const;
     308              :     NoteCaseType bassRenderCase() const;
     309              : 
     310        81560 :     FontStyle fontStyle() const override { return m_fontStyle; }
     311        37381 :     String family() const override { return m_fontFamily; }
     312        24066 :     double size() const override { return m_fontSize; }
     313              : 
     314         1226 :     void setFontStyle(const FontStyle& val) override { m_fontStyle = val; }
     315         1226 :     void setFamily(const String& val) override { m_fontFamily = val; }
     316         1226 :     void setSize(const double& val) override { m_fontSize = val; }
     317              : 
     318              :     struct LayoutData : public TextBase::LayoutData {
     319              :         ld_field<double> harmonyHeight = { "[Harmony] harmonyHeight", 0.0 };    // used for calculating the height is frame while editing.
     320              :         ld_field<std::vector<LineF> > polychordDividerLines = { "[Harmony] polychordDividerLine", std::vector<LineF>() };
     321              :         ld_field<double> polychordDividerOffset = { "[Harmony] polychordDividerOffset", 0.0 };
     322              :         ld_field<double> baseline = { "[Harmony] baseline", 0.0 };
     323              :         ld_field<std::vector<muse::draw::Font> > fontList = "[Harmony] fontList";          // temp values used in render()
     324              :         ld_field<std::vector<HarmonyRenderItem*> > renderItemList = "[Harmony] renderItemList";              // rendered chord
     325              :     };
     326        32296 :     DECLARE_LAYOUTDATA_METHODS(Harmony)
     327              : 
     328              : private:
     329              :     std::vector<HarmonyInfo*> m_chords;
     330              : 
     331              :     const std::vector<const ChordDescription*> parseHarmony(const String& s, bool syntaxOnly = false);
     332              :     const ChordDescription* parseSingleHarmony(const String& s, HarmonyInfo* info, bool syntaxOnly = false);
     333              : 
     334              :     Sid getPropertyStyle(Pid) const override;
     335              : 
     336              :     Harmony* findInSeg(Segment* seg) const;
     337              : 
     338              :     bool m_isMisspelled = false;                         // show spell check warning
     339              :     HarmonyType m_harmonyType = HarmonyType::STANDARD;   // used to control rendering, transposition, export, etc.
     340              : 
     341              :     mutable RealizedHarmony m_realizedHarmony;           // the realized harmony used for playback
     342              : 
     343              :     std::vector<HDegree> m_degreeList;
     344              : 
     345              :     bool m_play = true;                                  // whether or not to play back the harmony
     346              :     bool m_doNotStackModifiers = false;
     347              : 
     348              :     NoteCaseType m_rootCase = NoteCaseType::AUTO;
     349              :     NoteCaseType m_bassCase = NoteCaseType::AUTO;        // case as typed
     350              : 
     351              :     double m_bassScale = 1.0;
     352              : 
     353              :     // Overridden textbase properties to apply to whole item
     354              :     double m_fontSize = 10.0;
     355              :     String m_fontFamily = u"";
     356              :     FontStyle m_fontStyle;
     357              : };
     358              : } // namespace mu::engraving
        

Generated by: LCOV version 2.0-1