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 #include "EventQuantizeCommand.h"
20 
21 #include "base/NotationTypes.h"
22 #include "base/Profiler.h"
23 #include "base/Quantizer.h"
24 #include "base/BasicQuantizer.h"
25 #include "base/LegatoQuantizer.h"
26 #include "base/NotationQuantizer.h"
27 #include "base/Segment.h"
28 #include "base/SegmentNotationHelper.h"
29 #include "base/Selection.h"
30 #include "document/BasicCommand.h"
31 #include "document/CommandRegistry.h"
32 #include "misc/Strings.h"
33 #include "base/BaseProperties.h"
34 #include "gui/application/RosegardenApplication.h"
35 
36 #include <QApplication>
37 #include <QProgressDialog>
38 #include <QSettings>
39 #include <QString>
40 
41 
42 namespace Rosegarden
43 {
44 
45 using namespace BaseProperties;
46 
EventQuantizeCommand(Segment & segment,timeT startTime,timeT endTime,Quantizer * quantizer)47 EventQuantizeCommand::EventQuantizeCommand(Segment &segment,
48                                            timeT startTime,
49                                            timeT endTime,
50                                            Quantizer *quantizer):
51     BasicCommand(getGlobalName(quantizer), segment, startTime, endTime,
52                  true),  // bruteForceRedo
53     m_quantizer(quantizer),
54     m_selection(nullptr)
55 {
56     // nothing else
57 }
58 
EventQuantizeCommand(EventSelection & selection,Quantizer * quantizer)59 EventQuantizeCommand::EventQuantizeCommand(EventSelection &selection,
60                                            Quantizer *quantizer):
61     BasicCommand(getGlobalName(quantizer),
62                  selection.getSegment(),
63                  selection.getStartTime(),
64                  selection.getEndTime(),
65                  true),  // bruteForceRedo
66     m_quantizer(quantizer),
67     m_selection(&selection)
68 {
69     // nothing else
70 }
71 
EventQuantizeCommand(Segment & segment,timeT startTime,timeT endTime,QString settingsGroup,QuantizeScope scope)72 EventQuantizeCommand::EventQuantizeCommand(Segment &segment,
73                                            timeT startTime,
74                                            timeT endTime,
75                                            QString settingsGroup,
76                                            QuantizeScope scope):
77     BasicCommand(getGlobalName(makeQuantizer(settingsGroup, scope)),
78                  segment, startTime, endTime,
79                  true),  // bruteForceRedo
80     m_selection(nullptr),
81     m_settingsGroup(settingsGroup)
82 {
83     // nothing else -- m_quantizer set by makeQuantizer
84 }
85 
EventQuantizeCommand(EventSelection & selection,QString settingsGroup,QuantizeScope scope)86 EventQuantizeCommand::EventQuantizeCommand(EventSelection &selection,
87                                            QString settingsGroup,
88                                            QuantizeScope scope) :
89     BasicCommand(getGlobalName(makeQuantizer(settingsGroup, scope)),
90                  selection.getSegment(),
91                  selection.getStartTime(),
92                  selection.getEndTime(),
93                  true),  // bruteForceRedo
94     m_selection(&selection),
95     m_settingsGroup(settingsGroup)
96 {
97     // nothing else -- m_quantizer set by makeQuantizer
98 }
99 
~EventQuantizeCommand()100 EventQuantizeCommand::~EventQuantizeCommand()
101 {
102     delete m_quantizer;
103 }
104 
105 QString
getGlobalName(Quantizer * quantizer)106 EventQuantizeCommand::getGlobalName(Quantizer *quantizer)
107 {
108     if (quantizer) {
109         if (dynamic_cast<NotationQuantizer *>(quantizer)) {
110             return tr("Heuristic Notation &Quantize");
111         } else {
112             return tr("Grid &Quantize");
113         }
114     }
115 
116     return tr("&Quantize...");
117 }
118 
119 void
modifySegment()120 EventQuantizeCommand::modifySegment()
121 {
122     Profiler profiler("EventQuantizeCommand::modifySegment", true);
123 
124     // Kick the event loop.
125     qApp->processEvents();
126 
127     Segment &segment = getSegment();
128     SegmentNotationHelper helper(segment);
129 
130     bool rebeam = false;
131     bool makeviable = false;
132     bool decounterpoint = false;
133 
134     if (!m_settingsGroup.isEmpty()) {
135         //!!! need way to decide whether to do these even if no settings group (i.e. through args to the command)
136         QSettings settings;
137         settings.beginGroup( m_settingsGroup );
138 
139         rebeam = qStrToBool( settings.value("quantizerebeam", "true" ) ) ;
140         makeviable = qStrToBool( settings.value("quantizemakeviable", "false" ) ) ;
141         decounterpoint = qStrToBool( settings.value("quantizedecounterpoint", "false" ) ) ;
142         settings.endGroup();
143     }
144 
145     timeT endTime = segment.getEndTime();
146 
147     if (m_selection) {
148         m_quantizer->quantize(m_selection);
149 
150     } else {
151         m_quantizer->quantize(&segment,
152                               segment.findTime(getStartTime()),
153                               segment.findTime(getEndTime()));
154     }
155 
156     // Kick the event loop.
157     qApp->processEvents();
158 
159     if (segment.getEndTime() < endTime) {
160         segment.setEndTime(endTime);
161     }
162 
163     if (m_progressTotal > 0) {
164         if (rebeam || makeviable || decounterpoint) {
165             if (m_progressDialog)
166                 m_progressDialog->setValue(
167                         m_progressTotal + m_progressPerCall / 2);
168         } else {
169             if (m_progressDialog)
170                 m_progressDialog->setValue(m_progressTotal + m_progressPerCall);
171         }
172     }
173 
174     if (m_selection) {
175         EventSelection::RangeTimeList ranges(m_selection->getRangeTimes());
176         for (EventSelection::RangeTimeList::iterator i = ranges.begin();
177                 i != ranges.end(); ++i) {
178             if (makeviable) {
179                 helper.makeNotesViable(i->first, i->second, true);
180             }
181             // Kick the event loop.
182             qApp->processEvents();
183             if (decounterpoint) {
184                 helper.deCounterpoint(i->first, i->second);
185             }
186             // Kick the event loop.
187             qApp->processEvents();
188             if (rebeam) {
189                 helper.autoBeam(i->first, i->second, GROUP_TYPE_BEAMED);
190                 helper.autoSlur(i->first, i->second, true);
191             }
192             // Kick the event loop.
193             qApp->processEvents();
194         }
195     } else {
196         if (makeviable) {
197             helper.makeNotesViable(getStartTime(), getEndTime(), true);
198         }
199         // Kick the event loop.
200         qApp->processEvents();
201         if (decounterpoint) {
202             helper.deCounterpoint(getStartTime(), getEndTime());
203         }
204         // Kick the event loop.
205         qApp->processEvents();
206         if (rebeam) {
207             helper.autoBeam(getStartTime(), getEndTime(), GROUP_TYPE_BEAMED);
208             helper.autoSlur(getStartTime(), getEndTime(), true);
209         }
210         // Kick the event loop.
211         qApp->processEvents();
212     }
213 
214     if (m_progressTotal > 0) {
215         if (rebeam || makeviable || decounterpoint) {
216             if (m_progressDialog)
217                 m_progressDialog->setValue(
218                         m_progressTotal  + m_progressPerCall / 2);
219         }
220     }
221 
222     if (m_progressDialog  &&  m_progressDialog->wasCanceled())
223         throw CommandCancelled();
224 }
225 
226 Quantizer *
makeQuantizer(QString settingsGroup,QuantizeScope scope)227 EventQuantizeCommand::makeQuantizer(QString settingsGroup,
228                                     QuantizeScope scope)
229 {
230     // See QuantizeParameters::getQuantizer() which is quite similar.
231 
232     QSettings settings;
233     settings.beginGroup(settingsGroup);
234 
235     timeT defaultUnit =
236         Note(Note::Demisemiquaver).getDuration();
237 
238     bool notationDefault =
239         (scope == QUANTIZE_NOTATION_ONLY ||
240          scope == QUANTIZE_NOTATION_DEFAULT);
241 
242     int type = settings.value("quantizetype", notationDefault ? 2 : 0).toInt();
243     timeT unit = settings.value("quantizeunit", (int)defaultUnit).toInt();
244 
245     bool notateOnly;
246     if (scope == QUANTIZE_NOTATION_ONLY) {
247         notateOnly = true;
248     } else {
249         notateOnly = qStrToBool(settings.value("quantizenotationonly", notationDefault));
250     }
251 
252     bool durations = qStrToBool(settings.value("quantizedurations", false));
253     int simplicity = settings.value("quantizesimplicity", 13).toInt();
254     int maxTuplet = settings.value("quantizemaxtuplet", 3).toInt();
255     bool counterpoint = qStrToBool(settings.value("quantizecounterpoint", false));
256     bool articulate = qStrToBool(settings.value("quantizearticulate", true));
257     int swing = settings.value("quantizeswing", 0).toInt();
258     int iterate = settings.value("quantizeiterate", 100).toInt();
259 
260     settings.endGroup();
261 
262     m_quantizer = nullptr;
263 
264     if (type == 0) {
265         if (notateOnly) {
266             m_quantizer = new BasicQuantizer
267                           (Quantizer::RawEventData,
268                            Quantizer::NotationPrefix,
269                            unit, durations, swing, iterate);
270         } else {
271             m_quantizer = new BasicQuantizer
272                           (Quantizer::RawEventData,
273                            Quantizer::RawEventData,
274                            unit, durations, swing, iterate);
275         }
276     } else if (type == 1) {
277         if (notateOnly) {
278             m_quantizer = new LegatoQuantizer
279                           (Quantizer::RawEventData,
280                            Quantizer::NotationPrefix, unit);
281         } else {
282             m_quantizer = new LegatoQuantizer
283                           (Quantizer::RawEventData,
284                            Quantizer::RawEventData, unit);
285         }
286     } else {
287 
288         NotationQuantizer *nq;
289 
290         if (notateOnly) {
291             nq = new NotationQuantizer();
292         } else {
293             nq = new NotationQuantizer
294                  (Quantizer::RawEventData,
295                   Quantizer::RawEventData);
296         }
297 
298         nq->setUnit(unit);
299         nq->setSimplicityFactor(simplicity);
300         nq->setMaxTuplet(maxTuplet);
301         nq->setContrapuntal(counterpoint);
302         nq->setArticulate(articulate);
303 
304         m_quantizer = nq;
305     }
306 
307     return m_quantizer;
308 }
309 
310 }
311