1 2 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ 3 4 /* 5 Rosegarden 6 A MIDI and audio sequencer and musical notation editor. 7 Copyright 2000-2021 the Rosegarden development team. 8 9 This file is Copyright 2002 10 Hans Kieserman <hkieserman@mail.com> 11 with heavy lifting from csoundio as it was on 13/5/2002. 12 13 More or less complete rewrite (Aug 2011) 14 Niek van den Berg <niekjvandenberg@gmail.com> 15 16 Other copyrights also apply to some parts of this work. Please 17 see the AUTHORS file and individual file headers for details. 18 19 This program is free software; you can redistribute it and/or 20 modify it under the terms of the GNU General Public License as 21 published by the Free Software Foundation; either version 2 of the 22 License, or (at your option) any later version. See the file 23 COPYING included with this distribution for more information. 24 */ 25 26 #ifndef RG_MUSICXMLEXPORTHELPER_H 27 #define RG_MUSICXMLEXPORTHELPER_H 28 29 #include "PercussionMap.h" 30 31 #include "base/NotationTypes.h" 32 #include "base/Track.h" 33 #include "base/Segment.h" 34 #include "gui/application/RosegardenMainViewWidget.h" 35 36 // MusicXML supports only 6 slurs at thesame time is a single part. 37 #define MAXSLURS 6 38 39 40 class QObject; 41 42 namespace Rosegarden 43 { 44 45 class Key; 46 class Clef; 47 48 typedef std::vector<TrackId> TrackVector; 49 50 /** 51 */ 52 53 class MusicXmlExportHelper 54 { 55 public: 56 // The exporter doesn't try to find a reasonable divisions number but 57 // simply uses the samen number which is used internally. 58 static const int divisions = 960; 59 60 typedef std::map<Segment *, int> VoiceMap; 61 62 //! NOTE Temporary solution to store direction/notations for the future. 63 //! A better construction is possible however this might influence the old 64 //! MxmlEvent algorithme. First clean up this part and then a better solution 65 //! will be implemented. 66 class SimpleQueue { 67 public: 68 bool direction; 69 int staff; 70 int voice; 71 timeT time; 72 std::string string; 73 }; 74 75 /** 76 * This class contains some data to support multi stave part. A MusicXmlExporter 77 * will have a StaffInfo for each staff (=track) in the part. 78 */ 79 class StaffInfo { 80 public: 81 StaffInfo(TrackId id=0) : trackId(id)82 trackId(id) 83 { 84 voice = 0; 85 time = 0; 86 startTime = 0; 87 endTime = 0; 88 firstVoice = 0; 89 lastVoice = 0; 90 } 91 92 TrackId trackId; 93 int voice; // Primary voice for the staff. 94 std::vector<Segment *> segments; 95 timeT time; 96 timeT startTime; 97 timeT endTime; 98 int firstVoice; 99 int lastVoice; 100 Key key; 101 Clef clef; 102 AccidentalTable accTable; 103 }; 104 typedef std::map<int, StaffInfo> StaffMap; 105 106 /** 107 * MusicXmlExporter represents a MusicXML part. 108 */ 109 110 public: 111 MusicXmlExportHelper(const std::string &name, const TrackVector &tracklist, bool percussion, 112 bool selectedSegmentsOnly, 113 timeT compositionEndTime, Composition *composition, 114 RosegardenMainViewWidget *view, 115 AccidentalTable::OctaveType octaveType, 116 AccidentalTable::BarResetType barResetType); 117 ~MusicXmlExportHelper(); 118 119 /** 120 * Returns the part name. 121 */ getPartName()122 std::string getPartName() {return m_partName;} 123 124 /** 125 * Returns true if the part is a multi staff part. 126 */ isMultiStave()127 bool isMultiStave() {return m_staves.size() > 1;} 128 129 /** 130 * Returns the number of staves in the part. 131 */ getStaffCount()132 int getStaffCount() {return m_staves.size();} 133 134 /** 135 * Returns the number of active voices at give time. 136 * 137 * @param time the time the number of voices is requested. 138 */ 139 int getNumberOfActiveVoices(timeT time); 140 141 /** 142 * Sets the number of instruments on this staff. The default is 143 * 1 instrument. However, on percussion parts multiple instruments 144 * might be used. 145 */ 146 void setInstrumentCount(int count); 147 148 /** 149 * When true the <octave-shift> element will be used in the 150 * transpose attribute. 151 */ setUseOctaveShift(bool use)152 void setUseOctaveShift(bool use) {m_useOctaveShift = use;} 153 154 /** 155 * Write all events between startTime and endTime to the MusicXML file. 156 **/ 157 void writeEvents(int bar, std::ostream &str); 158 159 /** 160 * Handle the events. 161 **/ 162 void handleEvent(Segment *segment, Event &event); 163 164 165 void printSummary(); 166 167 protected: 168 /** 169 * Creates the <time> element. This member is called every time 170 * a new time signature changes. 171 */ 172 void addTimeSignature(timeT time, const TimeSignature &ts); 173 174 /** 175 * Creates the <transpose> element and is called for each new 176 * segment. 177 * Please note it is supposed every time all segments of a track will 178 * have the same transpostion. However, this is not checked! 179 */ 180 void addTransposition(timeT time, int transpose); 181 182 /** 183 * Implements the Key events and creates the <key> element. 184 */ 185 void addKey(const Event &event); 186 187 /** 188 * Implements the Clef event and creates the <clef> element. 189 */ 190 void addClef(const Event &event); 191 192 /** 193 * Handles the Text::Dynamic events and creates a <dynamics> 194 * element. 195 */ 196 void addDynamic(const Event &event); 197 198 /** 199 * Handles the Text::Direction, Text::LocalDirection, Text::Tempo and 200 * the Text::LocalTempo events. It use the same font weight, style and 201 * size as Lilypond does. 202 * For now the sizes are fixed. 203 */ 204 void addDirection(const Event &event); 205 206 /** 207 * Handles the Text::Chord event and create a <harmony> element. It 208 * tries to parse the chord text to a suiteble harmony. 209 */ 210 void addChord(const Event &event); 211 212 /** 213 * Handles the Indication::Slur and Indication::PhrasingSlur events. 214 */ 215 void addSlur(const Event &event, bool dashed); 216 217 /** 218 * Handles the Indication::TrillLine event. 219 */ 220 void addTrillLine(const Event &event); 221 222 /** 223 * Handles the Indication::Glissando event. 224 */ 225 void addGlissando(const Event &event); 226 227 /** 228 * Handles the Indication::Crescendo and Indication::Decrescendo events. 229 */ 230 void addWedge(const Event &event, bool crescendo); 231 232 /** 233 * Handles the Indication::QuindicesimaUp, Indication::OttavaUp, 234 * Indication::OttavaDown and Indication::QuindicesimaDown events. 235 */ 236 void addOctaveShift(const Event &event); 237 238 /** 239 * Handles the Text::Lyric event. Since lyrics are part of the <note> 240 * element, created by addNote(), addLyric() creates the necessary 241 * MusicXML code and stores it to be used by addNote(). 242 */ 243 void addLyric(const Event &event); 244 245 /** 246 * Handles the Note::EventType and Note::EventRestType and creates 247 * the <note> element. 248 */ 249 void addNote(const Segment &segment, const Event &event); 250 251 /** 252 * All addXxx() members, handling several events, stores all MusicXML 253 * code in string. This member will write all collect strings in the 254 * correct order to the ouput file. 255 */ 256 void flush(std::ostream &str); 257 258 /** 259 * Converts the Rosegarden notetype to MusicXML notenames. 260 */ 261 std::string getNoteName(int noteType) const; 262 263 /** 264 * Queue and retrieve delayed events. 265 */ 266 void queue(bool direction, timeT time, std::string str); 267 std::string retrieve(bool direction, timeT time); 268 269 /** 270 * Scan the surrounding of the event to see it is part of a tuplet or 271 * beamgroup. 272 */ 273 void updatePart(Segment *segment, Event &event); 274 275 /** 276 * Add a temporary segment to the composition. 277 */ 278 void addTemporarySegment(Segment *segment, int staff, int voice, int &count) ; 279 280 /** 281 * Creates new segment, filled with rests to fill the gap between 282 * two segments of the first voice of a staff. 283 */ 284 void generateRestSegment(int staff, timeT begin, timeT end, int voice, int &count); 285 286 /** 287 * Returns the number of the next available slur. MusicXML allows 288 * 6 parallel slurs at the same time. If the number of parallel 289 * slurs exceed this value, -1 is returned. 290 */ getSlurNumber(const Indication & indication)291 int getSlurNumber(const Indication &indication) 292 { 293 timeT endSlur = m_curtime + indication.getIndicationDuration(); 294 int number = -1; 295 for (int i = 0; i < MAXSLURS; i++) { 296 if (m_slurEndTimes[i] < m_curtime) 297 m_slurEndTimes[i] = -1; 298 if ((number < 0) && (m_slurEndTimes[i] < 0)) { 299 number = i; 300 m_slurEndTimes[i] = endSlur; 301 } 302 } 303 return number+1; 304 } 305 306 /** 307 * The note duration as create by the Percussion Matrix Editor are note 308 * the durations are expected in the Notation Editor. This member tries 309 * to create durations which should be me more usual in percussion 310 * sheets. 311 * Please note this part is still experimental and doesn't support all 312 * kinds of more complex rithms (like tuplets!). 313 */ 314 void quantizePercussion(); 315 bool emptyQuantizeQueue(PercussionMap &pm, Segment *segment, 316 std::vector<Event *> &events, 317 timeT begin, timeT end, bool stem); 318 319 /** 320 * Returns true is selectedSegmentsOnly is true and the segment is not 321 * selected. 322 */ 323 bool skipSegment(Segment *segment, bool selectedSegmentsOnly); 324 325 Composition *m_composition; 326 RosegardenMainViewWidget *m_view; 327 328 std::string m_partName; 329 bool m_percussionTrack; 330 int m_curVoice; 331 long m_group; 332 std::string m_tupletGroup; 333 long m_actualNotes; 334 long m_normalNotes; 335 int m_prvbeam; 336 int m_curbeam; 337 int m_nxtbeam; 338 339 int m_staff; 340 StaffMap m_staves; 341 VoiceMap m_voices; 342 timeT m_curtime; 343 344 int instrumentCount; 345 346 bool m_pendingAttributes; 347 timeT m_attributesTime; 348 std::string m_strDivisions; 349 std::string m_strKey; 350 std::string m_strTimesignature; 351 std::string m_strStaves; 352 std::string m_strClef; 353 std::string m_strStaffDetails; 354 std::string m_strTranspose; 355 bool m_useOctaveShift; 356 357 bool m_pendingNote; 358 std::string m_strNote; 359 std::string m_strSlurs; 360 std::string m_strLyrics; 361 timeT m_slurEndTimes[MAXSLURS]; 362 std::map<int, std::string> m_syllabic; 363 364 bool m_pendingDirections; 365 timeT m_directionTime; 366 std::string m_strDirection; 367 368 std::vector<SimpleQueue> tmp_queue; 369 370 std::vector<Segment *> m_restSegments; 371 372 AccidentalTable::OctaveType m_octaveType; 373 AccidentalTable::BarResetType m_barResetType; 374 }; 375 376 } 377 #endif 378