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