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