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 :
23 : #ifndef MU_IMPORTEXPORT_MEIEXPORTER_H
24 : #define MU_IMPORTEXPORT_MEIEXPORTER_H
25 :
26 : #include "engraving/types/types.h"
27 :
28 : #include "modularity/ioc.h"
29 : #include "imeiconfiguration.h"
30 :
31 : #include "meiconverter.h"
32 :
33 : #include "thirdparty/libmei/element.h"
34 : #include "thirdparty/libmei/shared.h"
35 :
36 : #include "pugixml.hpp"
37 :
38 : namespace mu::engraving {
39 : class Articulation;
40 : class Beam;
41 : class Chord;
42 : class ChordLine;
43 : class ChordRest;
44 : class Clef;
45 : class EngravingItem;
46 : class Fingering;
47 : class Lyrics;
48 : class Measure;
49 : class Note;
50 : class Part;
51 : class Rest;
52 : class Score;
53 : class Staff;
54 : class TremoloSingleChord;
55 : class TremoloTwoChord;
56 : class Trill;
57 : class Tuplet;
58 : class VBox;
59 : }
60 :
61 : namespace mu::iex::mei {
62 : class UIDRegister;
63 :
64 : enum layerElementCounter {
65 : ACCID_L = 0,
66 : BEAM_L,
67 : HARM_L,
68 : GRACEGRP_L,
69 : SYL_L,
70 : VERSE_L,
71 : UNSPECIFIED_L,
72 : };
73 :
74 : /**
75 : * Class of exporting Music Encoding Initiative (MEI) files
76 : */
77 :
78 : class MeiExporter
79 : {
80 : public:
81 : muse::GlobalInject<mu::iex::mei::IMeiConfiguration> configuration;
82 :
83 : public:
84 64 : MeiExporter(engraving::Score* s) { m_score = s; }
85 : bool write(std::string& meiData);
86 :
87 : private:
88 : bool writeHeader();
89 : bool writeScore();
90 : bool writeScoreDef();
91 : bool writePgHead(const engraving::VBox* vBox);
92 : bool writeLines(pugi::xml_node node, const muse::StringList& lines);
93 : bool writeLinesWithSMuFL(pugi::xml_node node, const muse::StringList& lines);
94 : bool writeScoreDefChange();
95 : bool writeStaffGrpStart(const engraving::Staff* staff, std::vector<int>& ends, const engraving::Part* part);
96 : bool writeStaffGrpEnd(const engraving::Staff* staff, std::vector<int>& ends);
97 : bool writeStaffDef(const engraving::Staff* staff, const engraving::Measure* measure, const engraving::Part* part, bool isPart);
98 : bool writeLabel(pugi::xml_node node, const engraving::Part* part);
99 : bool writeInstrDef(pugi::xml_node node, const engraving::Part* part);
100 : bool writeEnding(const engraving::Measure* measure);
101 : bool writeEndingEnd(const engraving::Measure* measure);
102 : bool writeMeasure(const engraving::Measure* measure, int& measureN, bool& isFirst, bool& wasLastIrregular);
103 : bool writeStaff(const engraving::Staff* staff, const engraving::Measure* measure);
104 : bool writeLayer(engraving::track_idx_t track, const engraving::Staff* staff, const engraving::Measure* measure);
105 :
106 : /**
107 : * Methods for writing MEI elements within a <layer>
108 : */
109 : bool writeArtics(const engraving::Chord* chord);
110 : bool writeArtic(const engraving::Articulation* articulation);
111 : bool writeArtic(const engraving::ChordLine* chordline);
112 : bool writeBeamAndTuplet(const engraving::ChordRest* chordRest, bool& closingBeam, bool& closingTuplet, bool& closingBeamInTuplet);
113 : bool writeBeamAndTupletEnd(bool closingBeam, bool closingTuplet, bool closingBeamInTuplet);
114 : bool writeBeam(const engraving::Beam* beam, const engraving::ChordRest* chordRest, bool& closing);
115 : bool writeBTrem(const engraving::TremoloSingleChord* tremolo);
116 : bool writeFTrem(const engraving::TremoloTwoChord* tremolo);
117 : bool writeClef(const engraving::Clef* clef);
118 : bool writeChord(const engraving::Chord* chord, const engraving::Staff* staff);
119 : bool writeGraceGrp(const engraving::Chord* chord, const engraving::Staff* staff, bool isAfter = false);
120 : bool writeNote(const engraving::Note* note, const engraving::Chord* chord, const engraving::Staff* staff, bool isChord);
121 : bool writeMRpt(const engraving::MeasureRepeat* measureRepeat);
122 : bool writeRest(const engraving::Rest* rest, const engraving::Staff* staff);
123 : bool writeSyl(const engraving::Lyrics* lyrics, const muse::String& text, ElisionType elision);
124 : bool writeTuplet(const engraving::Tuplet* tuplet, const engraving::EngravingItem* item, bool& closing);
125 : bool writeVerses(const engraving::ChordRest* chordRest);
126 : bool writeVerse(const engraving::Lyrics* lyrics);
127 :
128 : /**
129 : * Methods for writing MEI control events (within <measure>)
130 : */
131 : bool writeArpeg(const engraving::Arpeggio* arpeggio, const std::string& startid);
132 : bool writeBreath(const engraving::Breath* breath, const std::string& startid);
133 : bool writeDir(const engraving::TextBase* dir, const std::string& startid);
134 : bool writeDir(const engraving::TextLineBase* dir, const std::string& startid);
135 : bool writeDynam(const engraving::Dynamic* dynamic, const std::string& startid);
136 : bool writeF(const engraving::FiguredBassItem* figuredBassItem);
137 : bool writeFb(const engraving::FiguredBass* figuredBass, const std::string& startid);
138 : bool writeFermata(const engraving::Fermata* fermata, const std::string& startid);
139 : bool writeFermata(const engraving::Fermata* fermata, const libmei::xsdPositiveInteger_List& staffNs, double tstamp);
140 : bool writeFing(const engraving::Fingering* fing, const std::string& startid);
141 : bool writeGliss(const engraving::Glissando* gliss, const std::string& startid);
142 : bool writeHairpin(const engraving::Hairpin* hairpin, const std::string& startid);
143 : bool writeHarm(const engraving::Harmony* harmony, const std::string& startid);
144 : bool writeHarpPedal(const engraving::HarpPedalDiagram* harpPedalDiagram, const std::string& startid);
145 : bool writeOctave(const engraving::Ottava* ottava, const std::string& startid);
146 : bool writeOrnament(const engraving::Ornament* ornament, const std::string& startid);
147 : bool writePedal(const engraving::Pedal* pedal, const std::string& startid);
148 : bool writeRehearsalMark(const engraving::RehearsalMark* mark, const std::string& startid);
149 : bool writeRepeatMark(const engraving::Jump* jump, const engraving::Measure* measure);
150 : bool writeRepeatMark(const engraving::Marker* marker, const engraving::Measure* measure);
151 : bool writeSlur(const engraving::Slur* slur, const std::string& startid);
152 : bool writeTempo(const engraving::TempoText* tempoText, const std::string& startid);
153 : bool writeTie(const engraving::Tie* tie, const std::string& startid);
154 : bool writeTrill(const engraving::Trill* trill, const std::string& startid);
155 :
156 : /**
157 : * Methods for writing specific MEI attribute classes within elements
158 : */
159 : bool writeBeamTypeAtt(const engraving::ChordRest* chordRest, libmei::AttTyped& typeAtt);
160 : bool writeStaffIdentAtt(const engraving::ChordRest* chordRest, const engraving::Staff* staff, libmei::AttStaffIdent& staffIdentAtt);
161 : bool writeStemAtt(const engraving::Chord* chord, libmei::AttStems& stemsAtt);
162 :
163 : /**
164 : * Helper methods
165 : */
166 : bool isCurrentNode(const libmei::Element& element);
167 : std::vector<const engraving::Volta*> findVoltasInMeasure(const engraving::Measure* measure);
168 : void fillControlEventMap(const std::string& xmlId, const engraving::ChordRest* chordRest);
169 : std::string findStartIdFor(const engraving::EngravingItem* item);
170 : void addToRepeatMarkList(const engraving::EngravingItem* repeatMark, pugi::xml_node node, const std::string& xmlId);
171 : void addJumpToRepeatMarks();
172 : bool addFermataToMap(engraving::track_idx_t track, const engraving::Segment* segment, const engraving::Measure* measure);
173 : std::pair<libmei::xsdPositiveInteger_List, double> findTstampFor(const engraving::EngravingItem* item);
174 : bool isNode(pugi::xml_node node, const muse::String& name);
175 : pugi::xml_node getLastChordRest(pugi::xml_node node);
176 : void addNodeToOpenControlEvents(pugi::xml_node node, const engraving::Spanner* spanner, const std::string& startid);
177 : void addEndidToControlEvents();
178 : bool isLaissezVibrer(const engraving::SymId id);
179 :
180 : /**
181 : * Methods for generating @xml:ids
182 : */
183 : uint32_t hash(uint32_t number, bool reverse);
184 : std::string baseEncodeInt(uint32_t value, uint8_t base);
185 : std::string generateHashID();
186 : std::string getXmlIdFor(const engraving::EngravingItem* item, const char c);
187 : void resetLayerIDs();
188 : std::string getSectionXmlId();
189 : std::string getMeasureXmlId(const engraving::Measure* measure);
190 : std::string getStaffXmlId();
191 : std::string getLayerXmlId();
192 : std::string getLayerXmlIdFor(layerElementCounter elementType);
193 :
194 : /** A structure of holding a list of repeat marks to be post-process in addJumpToRepeatMarks (currently unused) */
195 : struct RepeatMark {
196 : const engraving::EngravingItem* m_repeatMark = nullptr;
197 : pugi::xml_node m_node;
198 : std::string m_xmlId;
199 : std::string m_jumptToLabel;
200 : std::string m_jumpToXmlId;
201 : };
202 :
203 : /** The Score pointer */
204 : engraving::Score* m_score = nullptr;
205 :
206 : /** The uid register */
207 : UIDRegister* m_uids;
208 :
209 : /** MEI xml element */
210 : pugi::xml_node m_mei;
211 : /** Current xml element */
212 : pugi::xml_node m_currentNode;
213 :
214 : /** When writing layers, keep a pointer to the keySig segment (if any) to prepend a scoreDef if necessary */
215 : const engraving::Segment* m_keySig;
216 : /** Same for the timeSig segment */
217 : const engraving::Segment* m_timeSig;
218 : /** A flag indicating that we have multiple sections in the file */
219 : bool m_hasSections;
220 :
221 : /** A list of items (first) for which we know the @startid (second) */
222 : std::vector<std::pair<const engraving::EngravingItem*, std::string> > m_startingControlEventList;
223 : /** A map of items with the @endid they will need to have added */
224 : std::map<const engraving::EngravingItem*, std::string> m_endingControlEventMap;
225 : /** A map of items with the @plist value they will need to have added */
226 : std::map<const engraving::EngravingItem*, std::string> m_plistMap;
227 : /** A map of chord that are a plist of the arpeggio */
228 : std::map<const engraving::Chord*, const engraving::Arpeggio*> m_arpegPlistMap;
229 : /** A map of elements (e.g., Fermata) to which a tstamp will need to be added */
230 : std::vector<std::pair<const engraving::EngravingItem*, std::pair<libmei::xsdPositiveInteger_List, double> > > m_tstampControlEventMap;
231 : /** A map of items with the corresponding node (to which the endid from m_endingControlEventMap or plist from m_plistMap will be added) */
232 : std::map<const engraving::EngravingItem*, pugi::xml_node> m_openControlEventMap;
233 :
234 : std::vector<MeiExporter::RepeatMark> m_repeatMarks;
235 :
236 : /** Counters for generating xml:ids */
237 : int m_xmlIDCounter;
238 : int m_sectionCounter;
239 : int m_measureCounter;
240 : int m_staffCounter;
241 : int m_layerCounter;
242 : /** Sub counters by elementType */
243 : std::vector<int> m_layerCounterFor;
244 :
245 : /** map of abbreviations for element within layers */
246 : inline static const std::map<layerElementCounter, muse::String> s_layerXmlIdMap = {
247 : { ACCID_L, u"a" },
248 : { BEAM_L, u"b" },
249 : { GRACEGRP_L, u"g" },
250 : { SYL_L, u"s" },
251 : { VERSE_L, u"v" },
252 : { UNSPECIFIED_L, u"x" }
253 : };
254 : };
255 : } // namespace
256 :
257 : #endif // MU_IMPORTEXPORT_MEIEXPORTER_H
|