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