1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ 2 3 /* 4 Rosegarden 5 A MIDI and audio sequencer and musical notation editor. 6 Copyright 2000-2021 the Rosegarden development team. 7 8 Other copyrights also apply to some parts of this work. Please 9 see the AUTHORS file and individual file headers for details. 10 11 This program is free software; you can redistribute it and/or 12 modify it under the terms of the GNU General Public License as 13 published by the Free Software Foundation; either version 2 of the 14 License, or (at your option) any later version. See the file 15 COPYING included with this distribution for more information. 16 */ 17 18 19 #ifndef RG_LILYPOND_SEGMENTS_CONTEXT_H 20 #define RG_LILYPOND_SEGMENTS_CONTEXT_H 21 22 /* 23 * LilyPondSegmentsContext.h 24 * 25 * This file defines a class which maintains the context of the segments 26 * which have to be exported to LilyPond. 27 * 28 * This class is used to 29 * - Hide the segments of the composition which are not exported 30 * - Simplify the access of voices inside a same track 31 * - See when a repeating segment may be printed inside 32 * repeat bars. (i.e. when no other unrepeating segment 33 * coexists at the same time on an other track). 34 * - Find out which linked segments may be printed as repeat with volta. 35 * - Compute the time offset which have to be set in LilyPond for 36 * each segment (with keyword \skip). 37 * 38 * 39 * Here is an example: 40 * 41 * // Create a LilyPondSegmentsContext object and insert into it segments 42 * // to export 43 * LilyPondSegmentsContext lsc(m_composition); 44 * for (...) { 45 * Segment * seg = ... 46 * lsc.addSegment(seg); 47 * } 48 * 49 * // Prepare everything inside the LilyPondSegmentsContext 50 * lsc.precompute(); 51 * lsc.fixRepeatStartTimes(); 52 * lsc.fixVoltaStartTimes(); 53 * 54 * // Then get from it the segments sorted and ready to use 55 * Track *track; 56 * for (track = lsc.useFirstTrack(); track; track = lsc.useNextTrack()) { 57 * int voiceIndex; 58 * for (voiceIndex = lsc.useFirstVoice(); 59 * voiceIndex != -1; voiceIndex = lsc.useNextVoice()) { 60 * Segment *seg; 61 * for (seg = lsc.useFirstSegment(); 62 * seg; seg = lsc.useNextSegment()) { 63 * 64 * // Write here the LilyPond stuff related to seg 65 * ... 66 * // Getting data from context when needed 67 * int trackPos = lsc.getTrackPos(); 68 * bool repeated = lsc.isRepeating(); 69 * timeT lilyPondStartTime = lsc.getSegmentStartTime(); 70 * etc... 71 * 72 * } 73 * } 74 * } 75 * 76 */ 77 78 79 #include "base/NotationTypes.h" 80 81 #include <set> 82 #include <map> 83 #include <list> 84 #include <string> 85 86 87 namespace Rosegarden 88 { 89 90 class Composition; 91 class Track; 92 class Segment; 93 class LilyPondExporter; 94 95 class LilyPondSegmentsContext 96 { 97 98 public: 99 /** 100 * Create an empty segment context 101 */ 102 LilyPondSegmentsContext(Composition *composition); 103 104 ~LilyPondSegmentsContext(); 105 106 /** 107 * Add a segment to the context 108 */ 109 void addSegment(Segment *segment); 110 111 /** 112 * Return true if the segment context is empty 113 */ 114 bool containsNoSegment(); 115 116 /** 117 * Walk through all segments, find the repeating ones and compute 118 * their start times in the LilyPond score assuming they are synchronous. 119 */ 120 void precompute(); 121 122 /** 123 * Walk through all segments and fix their start times when some repeating 124 * segments are printed with repeat bars in the LilyPond score. 125 */ 126 void fixRepeatStartTimes(); 127 128 /** 129 * Walk through all segments and fix their start times when some linked 130 * segments are printed in the LilyPond score as repeat with volta. 131 */ 132 void fixVoltaStartTimes(); 133 134 /** 135 * Return the smaller start time of the segments being exported. 136 * Only valid after precompute() has been executed. 137 */ getFirstSegmentStartTime()138 timeT getFirstSegmentStartTime() { return m_firstSegmentStartTime; } 139 140 /** 141 * Return the larger end time of the segments being exported. 142 * Only valid after precompute() has been executed. 143 */ getLastSegmentEndTime()144 timeT getLastSegmentEndTime() { return m_lastSegmentEndTime; } 145 146 /** 147 * Prepare to get the segments on the first track. 148 * Return null if there is no track. 149 */ 150 Track * useFirstTrack(); 151 152 /** 153 * Go to the next track 154 * Return null if there is no more track. 155 */ 156 Track * useNextTrack(); 157 158 /** 159 * Return the position of the current track or -1 160 */ 161 int getTrackPos(); 162 163 /** 164 * Prepare to get the segments on the first voice of the current track. 165 * Return the voice index of the first voice. 166 * Return -1 if there is no track. 167 */ 168 int useFirstVoice(); 169 170 /** 171 * Go to the next voice. 172 * Return the voice index of this voice. 173 * Return -1 if there is no more voice. 174 */ 175 int useNextVoice(); 176 177 /** 178 * Return the current voice index or -1 179 */ 180 int getVoiceIndex(); 181 182 /** 183 * Prepare to get the segments on the current track and for the current 184 * voice. 185 * Return null if there is no segment on the current track and voice. 186 */ 187 Segment * useFirstSegment(); 188 189 /** 190 * Go to the next segment. 191 * Return null if there is no more segment on the current track and voice. 192 */ 193 Segment * useNextSegment(); 194 195 /** 196 * Return the start time of the current segment in LilyPond 197 */ 198 timeT getSegmentStartTime(); 199 200 /** 201 * Return how many time the current segment is repeated in LilyPond 202 */ 203 int getNumberOfRepeats(); 204 205 /** 206 * Return true if the segment is repeated (a repeating segment or 207 * simple repeated links) without volta 208 */ 209 bool isRepeated(); 210 211 /** 212 * Return true if the segment is a repeating segment (not linked segments) 213 */ 214 bool isRepeatingSegment(); 215 216 /** 217 * Return true if the repetition is made of several linked segments 218 * without alternate ends 219 */ 220 bool isSimpleRepeatedLinks(); 221 222 /** 223 * Return true if the segment is inside a "repeat with volta" chain 224 */ 225 bool isRepeatWithVolta(); 226 227 /** 228 * Return true if the segment is synchronous 229 */ 230 bool isSynchronous(); 231 232 /** 233 * Return true if the segment is a volta 234 */ 235 bool isVolta(); 236 237 /** 238 * Return true if the segment is the first volta of a chain 239 */ 240 bool isFirstVolta(); 241 242 /** 243 * Return true if the segment is the last volta of a chain 244 */ 245 bool isLastVolta(); 246 247 /** 248 * Return the text of the current volta. 249 */ 250 std::string getVoltaText(); 251 252 /** 253 * Return the number of time the current volta is played. 254 */ 255 int getVoltaRepeatCount(); 256 257 /** 258 * Return true if the previous segment (on the same voice) was repeating 259 * without volta. 260 */ 261 bool wasRepeatingWithoutVolta(); 262 263 /** 264 * Return the last key signature defined on the last contiguous segment 265 * on the same voice. 266 * Return an undefined key (or default key) if the previous segment is 267 * not contiguous or if there is no previous segment. 268 */ 269 Rosegarden::Key getPreviousKey(); 270 271 /** 272 * Return true if LilyPond automatic volta mode is usable. 273 * Valid as soon as precompute() has been executed. 274 * 275 * Currently, this is a global flag: automatic and manual repeat/volta 276 * are not mixed in the same score. 277 */ isAutomaticVoltaUsable()278 bool isAutomaticVoltaUsable() { return m_automaticVoltaUsable; } 279 280 /// Only for instrumentation while debugging 281 void dump(); 282 283 static int m_nextRepeatId; 284 285 private : 286 287 struct SegmentData; 288 289 struct Volta { 290 const SegmentData * data; 291 std::set<int> voltaNumber; 292 VoltaVolta293 Volta(const SegmentData *sd, int number) 294 { 295 data = sd; 296 voltaNumber.insert(number); 297 } 298 }; 299 300 typedef std::vector<Volta *> VoltaChain; 301 302 struct SegmentData 303 { 304 Segment * segment; 305 306 mutable timeT duration; // Duration without repeat 307 mutable timeT wholeDuration; // Duration with repeat 308 mutable int numberOfRepeats; // 0 if not repeating 309 mutable timeT remainderDuration; 310 311 mutable bool synchronous; // Multitrack repeat is possible 312 mutable int syncCount; // Number of parallel synchronous 313 // segments on the other voices and 314 // tracks 315 mutable bool noRepeat; // Repeat is forbidden 316 mutable bool ignored; // Mark the segments inserted in 317 // a repeat chain (with or without 318 // volta) except the first one. 319 320 mutable int repeatId; // Identify a repeat with volta chain 321 mutable int numberOfVolta; // How many repeat in the chain 322 mutable bool startOfRepeatChain; 323 mutable bool volta; // Mark a volta 324 mutable VoltaChain * rawVoltaChain; 325 mutable VoltaChain * sortedVoltaChain; 326 327 mutable timeT startTime; // In LilyPond output 328 mutable timeT endTime; // In LilyPond output 329 330 mutable Rosegarden::Key previousKey; // Last key in the previous segment 331 332 mutable int simpleRepeatId; // Identify a repeat without volta chain 333 mutable int numberOfSimpleRepeats; // How many segments in the chain 334 SegmentDataSegmentData335 SegmentData(Segment * seg) 336 { 337 segment = seg; 338 duration = 0; 339 wholeDuration = 0; 340 numberOfRepeats = 0; 341 remainderDuration = 0; 342 synchronous = true; 343 syncCount = 0; 344 noRepeat = false; 345 ignored = false; 346 repeatId = 0; 347 numberOfVolta = 0; 348 startOfRepeatChain = false; 349 volta = false; 350 rawVoltaChain = nullptr; 351 sortedVoltaChain = nullptr; 352 startTime = 0; 353 endTime = 0; 354 previousKey = Rosegarden::Key("undefined"); 355 simpleRepeatId = 0; 356 numberOfSimpleRepeats = 0; 357 } 358 }; 359 360 struct SegmentDataCmp { 361 bool operator()(const SegmentData &s1, const SegmentData &s2) const; 362 }; 363 364 class SegmentSet : 365 public std::multiset<SegmentData, 366 LilyPondSegmentsContext::SegmentDataCmp> 367 { 368 public: 369 void scanForRepeatedLinks(); 370 371 private: 372 void setIterators(iterator it); 373 374 bool isPossibleStartOfSimpleRepeat(); 375 bool isNextSegmentOfSimpleRepeat(); 376 377 bool isPossibleStartOfRepeatWithVolta(); 378 bool isNextSegmentsOfRepeatWithVolta(); 379 380 bool isValidSimpleRepeatingSegment(iterator base, iterator target); 381 bool isValidRepeatingSegment(iterator base, iterator baseVolta, iterator target); 382 bool isValidVoltaSegment(iterator repeating, iterator target); 383 384 private: 385 iterator m_it0; 386 iterator m_it1; 387 iterator m_it2; 388 iterator m_it3; 389 iterator m_it4; 390 391 iterator m_start; 392 int m_count; 393 }; 394 395 typedef std::map<int, SegmentSet> VoiceMap; 396 typedef std::map<int, VoiceMap> TrackMap; 397 398 class SegmentDataList : public std::list<const SegmentData *> 399 { 400 public: 401 402 // Only for instrumentation while debugging 403 void dump(); 404 }; 405 406 /** 407 * Begin to look on all tracks/voices for all segments synchronous of the 408 * given one. 409 * Return null if no segment found. 410 */ 411 const SegmentData * getFirstSynchronousSegment(Segment * seg); 412 413 /** 414 * Get the next segment synchronous of the one passed as argument of 415 * the last call of getFirstSynchronousSegment(). 416 * Return null if no more segment found. 417 */ 418 const SegmentData * getNextSynchronousSegment(); 419 420 /** 421 * Look in the specified voice of the specified track for linked segments 422 * which may be exported as repeat with volta and mark them accordingly. 423 * The concerned segments are gathered in the set passed as argument. 424 */ 425 void lookForRepeatedLinksWithVolta(SegmentSet &segSet); 426 427 /** 428 * Look in the specified voice of the specified track for linked segments 429 * which may be exported as simple repeat and mark them accordingly. 430 * The concerned segments are gathered in the set passed as argument. 431 * 432 * The previously found repeat with volta sequences are ignored 433 * when pass=1, but not when pass=2. 434 */ 435 void lookForSimpleRepeatedLinks(SegmentSet &segSet, int pass = 1); 436 437 /** 438 * Look for similar segments in the raw volta chain (on all tracks 439 * simultaneously) and fill the sorted volta chain accordingly. 440 * The argument is the list of the associated synchronous main repeat 441 * segment data from all the tracks. 442 */ 443 void sortAndGatherVolta(SegmentDataList &); 444 445 446 TrackMap m_segments; 447 448 Composition * m_composition; 449 450 timeT m_epsilon; 451 timeT m_firstSegmentStartTime; 452 timeT m_lastSegmentEndTime; 453 bool m_automaticVoltaUsable; 454 455 TrackMap::iterator m_trackIterator; 456 VoiceMap::iterator m_voiceIterator; 457 SegmentSet::iterator m_segIterator; 458 VoltaChain::iterator m_voltaIterator; 459 460 // Used by "Get Synchronous Segment" (GSS) methods 461 // getFirstSynchronousSegment() and getNextSynchronousSegment() to remember 462 // the current position in maps and set. 463 Segment * m_GSSSegment; 464 TrackMap::iterator m_GSSTrackIterator; 465 VoiceMap::iterator m_GSSVoiceIterator; 466 SegmentSet::iterator m_GSSSegIterator; 467 468 bool m_repeatWithVolta; // Repeat with volta is usable in LilyPondExporter 469 470 // Values associated with segment returned by useNextSegment() 471 VoltaChain * m_currentVoltaChain; 472 bool m_firstVolta; 473 bool m_lastVolta; 474 475 bool m_wasRepeatingWithoutVolta; // Remember the type of the previous 476 // segment (which was the current one 477 // before the last call of useNextSegment()) 478 479 bool m_lastWasOK; // To deal with recursion in useNextSegment() 480 }; 481 482 483 } 484 485 #endif // RG_LILYPOND_SEGMENTS_CONTEXT_H 486