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  * CheckForParallelsDialog.h
20  *
21  *  Created on: Mar 22, 2015
22  *      Author: lambache
23  */
24 
25 #ifndef SRC_GUI_DIALOGS_CHECKFORPARALLELSDIALOG_H_
26 #define SRC_GUI_DIALOGS_CHECKFORPARALLELSDIALOG_H_
27 
28 #include "base/Segment.h"
29 #include "base/Composition.h"
30 #include "base/Studio.h"
31 #include "document/RosegardenDocument.h"
32 #include "gui/editors/notation/NotationStaff.h"
33 #include "gui/editors/notation/NotationScene.h"
34 #include "gui/editors/notation/NotationView.h"
35 
36 #include <QTextBrowser>
37 #include <QDialog>
38 #include <QString>
39 #include <QCheckBox>
40 #include <QPushButton>
41 
42 
43 // check for parallels in voices
44 //
45 // we go through all segments in the notation editor, take all events and look for progressions
46 //
47 // a progression consists of two notes with no rest in between
48 // the time of the progression is defined as the begin of the second note
49 //
50 // we examine all progressions that occur at the same time and check whether the progressions form a parallel movement
51 //
52 // these are shown in the textBrowser of the dialog and marked in color in the notation editor
53 //
54 // parallelism is checked by pitch values, so a diminished fifth is the same as an augmented fourth
55 // this means that a movement from an augmented fourth to a perfect fifth is the same as from an diminished fifth to a perfect fifth
56 //   and is therefore considered a parallel
57 //
58 // frankly, I have no idea how this could be figured out with sensible effort...
59 //
60 // as we go through the notation content by segment, we will not find transitions across segment boundaries
61 // in principle this should be possible, but is too complicated for me at the moment...
62 
63 
64 namespace Rosegarden
65 {
66 
67 
68 class CheckForParallelsDialog : public QDialog
69 {
70     Q_OBJECT
71 public:
72     typedef std::vector<Segment *> SegmentVector;
73 
74     // types of parallels
75 
76     enum ParallelType {UNISON, FIFTH, OCTAVE, HIDDEN_FIFTH, HIDDEN_OCTAVE};
77 
78     // 'Transition' represents a transition from one note to another
79     //
80     // this is the basic entity to check for parallels
81 
82     typedef struct {
83         Segment::iterator note;             // the note on which the transition ends
84         Segment::iterator predecessor;      // the note before
85         Segment *segment;                   // pointer to the segment to which the transition belongs
86         NotationStaff *staff;               // pointer to the staff to which the transition belongs
87         int TrackPosition;                  // position of track in rosegarden gui
88         QString trackLabel;
89         timeT time;                         // occurrence time of the transition, i.e. start time of the note
90     } Transition;
91 
92     // description of parallel
93 
94     typedef struct {
95         ParallelType type;
96 
97         Segment::iterator note1;            // notes at end of parallel
98         Segment::iterator note2;
99 
100         Segment::iterator predecessor1;     // notes at begin of parallel
101         Segment::iterator predecessor2;
102 
103         Segment *segment1;                  // pointers to the segments
104         Segment *segment2;
105 
106         NotationStaff *staff1;              // pointers to staves
107         NotationStaff *staff2;
108 
109         int trackPosition1;                 // shown number of track in notation editor
110         int trackPosition2;
111 
112         QString trackLabel1;                // label of track
113         QString trackLabel2;
114 
115         timeT time;                         // occurrence time of the parallel, i.e. start note
116     } Parallel;
117 
118     // a set of parallels that occur at a specific time
119     typedef std::vector<Parallel> ParallelSet;
120 
121     // this describes where a parallel occurs in the notation view
122     typedef struct {
123         timeT   time;
124         NotationStaff *staff;
125     } parallelLocation;
126 
127     // link between segment and staff so we can position the pointer properly to the parallel
128     typedef struct {
129         Segment *segment;
130         NotationStaff *staff;       // staff that the segment belongs to
131     } SegmentStaffLink;
132 
133     // compare function for sorting the transitionList
sortByTime(const Transition & t1,const Transition & t2)134     static bool sortByTime(const Transition &t1, const Transition &t2) { return t1.time < t2.time; }
135 
136     CheckForParallelsDialog(NotationView *parent, RosegardenDocument *document, NotationScene *ns, Composition *comp);
137 
138 protected slots:
139     void startCheck();
140     void clear();
141     void cleanUpAndLeave();
142     void checkForUnisonsClicked();
143     void checkForHiddenParallelsClicked();
144     void exportText();
145     void onTextBrowserclicked();
146 
147 private:
148 
149     // add text to textBrowser
150     void addText(QString text);
151 
152     // check a set of transitions for parallels
153     void checkParallels(std::vector<Transition> &tSet);
154 
155     // returns true if the transition set has parallels
156     bool hasParallels(std::vector<Transition> &tSet, std::vector<Parallel> &p);
157 
158     // fill the fields of a parallel with exception of type
159     void populateParallel(Transition t1, Transition t2, Parallel &p);
160 
161     // returns a string that identifies a track
162     // track label if present, otherwise position of track
163     QString makeTrackString(int trackPosition, QString trackLabel);
164 
165     // updates the list of segments that are currently in the notationView
166     void updateSegments();
167 
168     // write out the transition list (for debug purposes)
169     void writeTransitionList(std::vector<Transition> transitionList);
170 
171     // write a single transition
172     void writeTransition(std::vector<Transition>::iterator it);
173 
174     //-------------------------------------------------------------------------
175 
176     // where we display the results of the check
177     QTextBrowser *textBrowser;
178 
179     // the notation view
180     NotationView *notationView;
181 
182     // the document
183     RosegardenDocument *document;
184 
185     // the current NotationScene
186     NotationScene *notationScene;
187 
188     // all segments in the notation view (pointers!)
189     SegmentVector segment;
190 
191     // current composition
192     Composition *composition;
193 
194     // all transitions in all segments
195     std::vector<Transition> transitionList;
196 
197     // all found parallels
198     std::vector<ParallelSet> parallelList;
199 
200     // shall we check for unisons?
201     /*static*/ bool checkForUnisons;
202     QCheckBox *checkForUnisonsCheckBox;
203 
204     // shall we check for hidden parallels?
205     /*static*/ bool checkForHiddenParallels;
206     QCheckBox *checkForHiddenParallelsCheckBox;
207 
208     // hack to find line when user clicks into textBrowser
209     // could not find how to do this with mouse events in reasonable time
210     // so we follow the cursor changes but we have to ignore this as long as we are populating the window
211     bool ignoreCursor;
212 
213     // list of locations vs. line numbers in textBrowser
214     std::vector<parallelLocation> locationForLine;
215 
216     // list of all links between staves and segments so we know to which staff a segement belongs
217     std::vector<SegmentStaffLink> segmentStaffLinkList;
218 
219     // the button to start the search
220     QPushButton *startButton;
221 
222     // a list of potential stop points of checking for each track in case of multiple notes
223     std::vector<timeT> checkStopTime;
224 };
225 
226 
227 }
228 
229 
230 
231 #endif /* SRC_GUI_DIALOGS_CHECKFORPARALLELSDIALOG_H_ */
232