1 #include "effects/effectrack.h"
2
3 #include "effects/effectchainmanager.h"
4 #include "effects/effectslot.h"
5 #include "effects/effectsmanager.h"
6 #include "engine/effects/engineeffectrack.h"
7 #include "moc_effectrack.cpp"
8 #include "util/assert.h"
9
EffectRack(EffectsManager * pEffectsManager,EffectChainManager * pEffectChainManager,const unsigned int iRackNumber,const QString & group,SignalProcessingStage stage)10 EffectRack::EffectRack(EffectsManager* pEffectsManager,
11 EffectChainManager* pEffectChainManager,
12 const unsigned int iRackNumber,
13 const QString& group, SignalProcessingStage stage)
14 : m_pEngineEffectRack(nullptr),
15 m_pEffectsManager(pEffectsManager),
16 m_pEffectChainManager(pEffectChainManager),
17 m_signalProcessingStage(stage),
18 m_iRackNumber(iRackNumber),
19 m_group(group),
20 m_controlNumEffectChainSlots(ConfigKey(m_group, "num_effectunits")),
21 m_controlClearRack(ConfigKey(m_group, "clear")) {
22 connect(&m_controlClearRack, &ControlObject::valueChanged, this, &EffectRack::slotClearRack);
23 m_controlNumEffectChainSlots.setReadOnly();
24 addToEngine();
25 }
26
~EffectRack()27 EffectRack::~EffectRack() {
28 removeFromEngine();
29 //qDebug() << "EffectRack::~EffectRack()";
30 }
31
getEngineEffectRack()32 EngineEffectRack* EffectRack::getEngineEffectRack() {
33 return m_pEngineEffectRack;
34 }
35
addToEngine()36 void EffectRack::addToEngine() {
37 m_pEngineEffectRack = new EngineEffectRack(m_iRackNumber);
38 EffectsRequest* pRequest = new EffectsRequest();
39 pRequest->type = EffectsRequest::ADD_EFFECT_RACK;
40 pRequest->AddEffectRack.pRack = m_pEngineEffectRack;
41 pRequest->AddEffectRack.signalProcessingStage = m_signalProcessingStage;
42 m_pEffectsManager->writeRequest(pRequest);
43
44 // Add all effect chains.
45 for (int i = 0; i < m_effectChainSlots.size(); ++i) {
46 EffectChainSlotPointer pSlot = m_effectChainSlots[i];
47 EffectChainPointer pChain = pSlot->getEffectChain();
48 if (pChain) {
49 // Add the effect to the engine.
50 pChain->addToEngine(m_pEngineEffectRack, i);
51 // Update its parameters in the engine.
52 pChain->updateEngineState();
53 }
54 }
55 }
56
removeFromEngine()57 void EffectRack::removeFromEngine() {
58 // Order doesn't matter when removing.
59 for (int i = 0; i < m_effectChainSlots.size(); ++i) {
60 EffectChainSlotPointer pSlot = m_effectChainSlots[i];
61 EffectChainPointer pChain = pSlot->getEffectChain();
62 if (pChain) {
63 pChain->removeFromEngine(m_pEngineEffectRack, i);
64 }
65 }
66
67 EffectsRequest* pRequest = new EffectsRequest();
68 pRequest->type = EffectsRequest::REMOVE_EFFECT_RACK;
69 pRequest->RemoveEffectRack.signalProcessingStage = m_signalProcessingStage;
70 pRequest->RemoveEffectRack.pRack = m_pEngineEffectRack;
71 m_pEffectsManager->writeRequest(pRequest);
72 m_pEngineEffectRack = nullptr;
73 }
74
registerInputChannel(const ChannelHandleAndGroup & handle_group)75 void EffectRack::registerInputChannel(const ChannelHandleAndGroup& handle_group) {
76 foreach (EffectChainSlotPointer pChainSlot, m_effectChainSlots) {
77 pChainSlot->registerInputChannel(handle_group);
78 }
79 }
80
slotClearRack(double v)81 void EffectRack::slotClearRack(double v) {
82 if (v > 0) {
83 foreach (EffectChainSlotPointer pChainSlot, m_effectChainSlots) {
84 pChainSlot->clear();
85 }
86 }
87 }
88
numEffectChainSlots() const89 int EffectRack::numEffectChainSlots() const {
90 return m_effectChainSlots.size();
91 }
92
addEffectChainSlotInternal(EffectChainSlotPointer pChainSlot)93 void EffectRack::addEffectChainSlotInternal(EffectChainSlotPointer pChainSlot) {
94 m_effectChainSlots.append(pChainSlot);
95 m_controlNumEffectChainSlots.forceSet(
96 m_controlNumEffectChainSlots.get() + 1);
97 }
98
getEffectChainSlot(int i)99 EffectChainSlotPointer EffectRack::getEffectChainSlot(int i) {
100 if (i < 0 || i >= m_effectChainSlots.size()) {
101 qWarning() << "WARNING: Invalid index for getEffectChainSlot";
102 return EffectChainSlotPointer();
103 }
104 return m_effectChainSlots[i];
105 }
106
loadNextChain(const unsigned int iChainSlotNumber,EffectChainPointer pLoadedChain)107 void EffectRack::loadNextChain(const unsigned int iChainSlotNumber,
108 EffectChainPointer pLoadedChain) {
109 if (pLoadedChain) {
110 pLoadedChain = pLoadedChain->prototype();
111 }
112
113 EffectChainPointer pNextChain = m_pEffectChainManager->getNextEffectChain(
114 pLoadedChain);
115
116 pNextChain = EffectChain::clone(pNextChain);
117 pNextChain->addToEngine(m_pEngineEffectRack, iChainSlotNumber);
118 m_effectChainSlots[iChainSlotNumber]->loadEffectChainToSlot(pNextChain);
119 m_effectChainSlots[iChainSlotNumber]->updateRoutingSwitches();
120 }
121
122
loadPrevChain(const unsigned int iChainSlotNumber,EffectChainPointer pLoadedChain)123 void EffectRack::loadPrevChain(const unsigned int iChainSlotNumber,
124 EffectChainPointer pLoadedChain) {
125 if (pLoadedChain) {
126 pLoadedChain = pLoadedChain->prototype();
127 }
128
129 EffectChainPointer pPrevChain = m_pEffectChainManager->getPrevEffectChain(
130 pLoadedChain);
131
132 pPrevChain = EffectChain::clone(pPrevChain);
133 pPrevChain->addToEngine(m_pEngineEffectRack, iChainSlotNumber);
134 m_effectChainSlots[iChainSlotNumber]->loadEffectChainToSlot(pPrevChain);
135 m_effectChainSlots[iChainSlotNumber]->updateRoutingSwitches();
136 }
137
maybeLoadEffect(const unsigned int iChainSlotNumber,const unsigned int iEffectSlotNumber,const QString & id)138 void EffectRack::maybeLoadEffect(const unsigned int iChainSlotNumber,
139 const unsigned int iEffectSlotNumber,
140 const QString& id) {
141 if (iChainSlotNumber >= static_cast<unsigned int>(m_effectChainSlots.size())) {
142 return;
143 }
144
145 EffectChainSlotPointer pChainSlot = m_effectChainSlots[iChainSlotNumber];
146 if (pChainSlot == nullptr) {
147 return;
148 }
149 EffectSlotPointer pEffectSlot = pChainSlot->getEffectSlot(iEffectSlotNumber);
150
151 bool loadNew = false;
152 if (pEffectSlot == nullptr || pEffectSlot->getEffect() == nullptr) {
153 loadNew = true;
154 } else if (id != pEffectSlot->getEffect()->getManifest()->id()) {
155 loadNew = true;
156 }
157
158 if (loadNew) {
159 EffectChainPointer pChain = pChainSlot->getOrCreateEffectChain(m_pEffectsManager);
160 EffectPointer pEffect = m_pEffectsManager->instantiateEffect(id);
161 pChain->replaceEffect(iEffectSlotNumber, pEffect);
162 }
163 }
164
loadNextEffect(const unsigned int iChainSlotNumber,const unsigned int iEffectSlotNumber,EffectPointer pEffect)165 void EffectRack::loadNextEffect(const unsigned int iChainSlotNumber,
166 const unsigned int iEffectSlotNumber,
167 EffectPointer pEffect) {
168 if (iChainSlotNumber >= static_cast<unsigned int>(m_effectChainSlots.size())) {
169 return;
170 }
171
172 QString effectId = pEffect ? pEffect->getManifest()->id() : QString();
173 QString nextEffectId = m_pEffectsManager->getNextEffectId(effectId);
174 EffectPointer pNextEffect = m_pEffectsManager->instantiateEffect(nextEffectId);
175
176 EffectChainSlotPointer pChainSlot = m_effectChainSlots[iChainSlotNumber];
177 EffectChainPointer pChain = pChainSlot->getOrCreateEffectChain(m_pEffectsManager);
178 pChain->replaceEffect(iEffectSlotNumber, pNextEffect);
179 }
180
181
loadPrevEffect(const unsigned int iChainSlotNumber,const unsigned int iEffectSlotNumber,EffectPointer pEffect)182 void EffectRack::loadPrevEffect(const unsigned int iChainSlotNumber,
183 const unsigned int iEffectSlotNumber,
184 EffectPointer pEffect) {
185 if (iChainSlotNumber >= static_cast<unsigned int>(m_effectChainSlots.size())) {
186 return;
187 }
188
189 QString effectId = pEffect ? pEffect->getManifest()->id() : QString();
190 QString prevEffectId = m_pEffectsManager->getPrevEffectId(effectId);
191 EffectPointer pPrevEffect = m_pEffectsManager->instantiateEffect(prevEffectId);
192
193 EffectChainSlotPointer pChainSlot = m_effectChainSlots[iChainSlotNumber];
194 EffectChainPointer pChain = pChainSlot->getOrCreateEffectChain(m_pEffectsManager);
195 pChain->replaceEffect(iEffectSlotNumber, pPrevEffect);
196 }
197
toXml(QDomDocument * doc) const198 QDomElement EffectRack::toXml(QDomDocument* doc) const {
199 QDomElement rackElement = doc->createElement("Rack");
200 QDomElement groupElement = doc->createElement("Group");
201 QDomText groupText = doc->createTextNode(m_group);
202 groupElement.appendChild(groupText);
203 rackElement.appendChild(groupElement);
204
205 QDomElement chainsElement = doc->createElement("Chains");
206 for (const EffectChainSlotPointer& pChainSlot : m_effectChainSlots) {
207 QDomElement chain = pChainSlot->toXml(doc);
208 chainsElement.appendChild(chain);
209 }
210 rackElement.appendChild(chainsElement);
211 return rackElement;
212 }
213
refresh()214 void EffectRack::refresh() {
215 for (const auto& pChainSlot : qAsConst(m_effectChainSlots)) {
216 EffectChainPointer pChain = pChainSlot->getOrCreateEffectChain(m_pEffectsManager);
217 pChain->refreshAllEffects();
218 }
219 }
220
isAdoptMetaknobValueEnabled() const221 bool EffectRack::isAdoptMetaknobValueEnabled() const {
222 return m_pEffectChainManager->isAdoptMetaknobValueEnabled();
223 }
224
StandardEffectRack(EffectsManager * pEffectsManager,EffectChainManager * pChainManager,const unsigned int iRackNumber)225 StandardEffectRack::StandardEffectRack(EffectsManager* pEffectsManager,
226 EffectChainManager* pChainManager,
227 const unsigned int iRackNumber)
228 : EffectRack(pEffectsManager, pChainManager, iRackNumber,
229 formatGroupString(iRackNumber), SignalProcessingStage::Postfader) {
230 for (int i = 0; i < EffectChainManager::kNumStandardEffectChains; ++i) {
231 addEffectChainSlot();
232 }
233 }
234
addEffectChainSlot()235 EffectChainSlotPointer StandardEffectRack::addEffectChainSlot() {
236 int iChainSlotNumber = numEffectChainSlots();
237
238 QString group = formatEffectChainSlotGroupString(getRackNumber(),
239 iChainSlotNumber);
240 EffectChainSlot* pChainSlot =
241 new EffectChainSlot(this, group, iChainSlotNumber);
242
243 for (int i = 0; i < kNumEffectsPerUnit; ++i) {
244 pChainSlot->addEffectSlot(
245 StandardEffectRack::formatEffectSlotGroupString(
246 getRackNumber(), iChainSlotNumber, i));
247 }
248
249 connect(pChainSlot, &EffectChainSlot::nextChain, this, &StandardEffectRack::loadNextChain);
250 connect(pChainSlot, &EffectChainSlot::prevChain, this, &StandardEffectRack::loadPrevChain);
251
252 connect(pChainSlot, &EffectChainSlot::nextEffect, this, &StandardEffectRack::loadNextEffect);
253 connect(pChainSlot, &EffectChainSlot::prevEffect, this, &StandardEffectRack::loadPrevEffect);
254
255 // Register all the existing channels with the new EffectChain.
256 const QSet<ChannelHandleAndGroup>& registeredChannels =
257 m_pEffectChainManager->registeredInputChannels();
258 for (const ChannelHandleAndGroup& handle_group : registeredChannels) {
259 pChainSlot->registerInputChannel(handle_group);
260 }
261
262 EffectChainSlotPointer pChainSlotPointer = EffectChainSlotPointer(pChainSlot);
263 addEffectChainSlotInternal(pChainSlotPointer);
264
265 return pChainSlotPointer;
266 }
267
OutputEffectRack(EffectsManager * pEffectsManager,EffectChainManager * pChainManager)268 OutputEffectRack::OutputEffectRack(EffectsManager* pEffectsManager,
269 EffectChainManager* pChainManager)
270 : EffectRack(pEffectsManager, pChainManager, 0,
271 "[OutputEffectRack]", SignalProcessingStage::Postfader) {
272
273 const QString unitGroup = "[OutputEffectRack_[Master]]";
274 // Hard code only one EffectChainSlot
275 EffectChainSlot* pChainSlot = new EffectChainSlot(this, unitGroup, 0);
276 EffectChainPointer pChain(new EffectChain(m_pEffectsManager, unitGroup));
277 pChainSlot->loadEffectChainToSlot(pChain);
278 pChain->addToEngine(getEngineEffectRack(), 0);
279 // Add a single EffectSlot for the master EQ effect
280 pChainSlot->addEffectSlot("[OutputEffectRack_[Master]_Effect1]");
281
282 connect(pChainSlot, &EffectChainSlot::nextChain, this, &OutputEffectRack::loadNextChain);
283 connect(pChainSlot, &EffectChainSlot::prevChain, this, &OutputEffectRack::loadPrevChain);
284
285 connect(pChainSlot, &EffectChainSlot::nextEffect, this, &OutputEffectRack::loadNextEffect);
286 connect(pChainSlot, &EffectChainSlot::prevEffect, this, &OutputEffectRack::loadPrevEffect);
287
288 // Register the master channel.
289 const ChannelHandleAndGroup* masterHandleAndGroup = nullptr;
290
291 // TODO(Be): Remove this hideous hack to get the ChannelHandleAndGroup
292 const QSet<ChannelHandleAndGroup>& registeredChannels =
293 m_pEffectChainManager->registeredInputChannels();
294 for (const ChannelHandleAndGroup& handle_group : registeredChannels) {
295 if (handle_group.name() == "[MasterOutput]") {
296 masterHandleAndGroup = &handle_group;
297 break;
298 }
299 }
300 DEBUG_ASSERT(masterHandleAndGroup != nullptr);
301
302 pChainSlot->registerInputChannel(*masterHandleAndGroup);
303 pChain->enableForInputChannel(*masterHandleAndGroup);
304 pChain->setMix(1.0);
305
306 EffectChainSlotPointer pChainSlotPointer = EffectChainSlotPointer(pChainSlot);
307 addEffectChainSlotInternal(pChainSlotPointer);
308 }
309
PerGroupRack(EffectsManager * pEffectsManager,EffectChainManager * pChainManager,const unsigned int iRackNumber,const QString & group)310 PerGroupRack::PerGroupRack(EffectsManager* pEffectsManager,
311 EffectChainManager* pChainManager,
312 const unsigned int iRackNumber,
313 const QString& group)
314 : EffectRack(pEffectsManager, pChainManager, iRackNumber, group,
315 SignalProcessingStage::Prefader) {
316 }
317
setupForGroup(const QString & groupName)318 void PerGroupRack::setupForGroup(const QString& groupName) {
319 VERIFY_OR_DEBUG_ASSERT(!m_groupToChainSlot.contains(groupName)) {
320 return;
321 }
322
323 int iChainSlotNumber = m_groupToChainSlot.size();
324 QString chainSlotGroup = formatEffectChainSlotGroupForGroup(
325 getRackNumber(), iChainSlotNumber, groupName);
326 EffectChainSlot* pChainSlot = new EffectChainSlot(this, chainSlotGroup,
327 iChainSlotNumber);
328 EffectChainSlotPointer pChainSlotPointer(pChainSlot);
329 addEffectChainSlotInternal(pChainSlotPointer);
330 m_groupToChainSlot[groupName] = pChainSlotPointer;
331
332 // TODO(rryan): Set up next/prev signals.
333
334 EffectChainPointer pChain(new EffectChain(m_pEffectsManager, chainSlotGroup));
335 pChainSlot->loadEffectChainToSlot(pChain);
336 pChain->addToEngine(getEngineEffectRack(), iChainSlotNumber);
337 // Set the chain to be fully wet.
338 pChain->setMix(1.0);
339 pChain->updateEngineState();
340
341 // TODO(rryan): remove.
342 const ChannelHandleAndGroup* handleAndGroup = nullptr;
343 for (const ChannelHandleAndGroup& handle_group :
344 m_pEffectChainManager->registeredInputChannels()) {
345 if (handle_group.name() == groupName) {
346 handleAndGroup = &handle_group;
347 break;
348 }
349 }
350 DEBUG_ASSERT(handleAndGroup != nullptr);
351
352 // Register this channel alone with the chain slot.
353 pChainSlot->registerInputChannel(*handleAndGroup);
354 pChainSlot->updateRoutingSwitches();
355
356 // Add a single effect slot
357 pChainSlot->addEffectSlot(formatEffectSlotGroupString(0, groupName));
358 // DlgPrefEq loads the Effect with loadEffectToGroup
359
360 configureEffectChainSlotForGroup(pChainSlotPointer, groupName);
361 }
362
loadEffectToGroup(const QString & groupName,EffectPointer pEffect)363 bool PerGroupRack::loadEffectToGroup(const QString& groupName, EffectPointer pEffect) {
364 EffectChainSlotPointer pChainSlot = getGroupEffectChainSlot(groupName);
365 VERIFY_OR_DEBUG_ASSERT(pChainSlot) {
366 return false;
367 }
368
369 EffectChainPointer pChain = pChainSlot->getOrCreateEffectChain(m_pEffectsManager);
370 pChain->replaceEffect(0, pEffect);
371 pChainSlot->updateRoutingSwitches();
372
373 if (pEffect != nullptr) {
374 pEffect->setEnabled(true);
375 }
376 return true;
377 }
378
getGroupEffectChainSlot(const QString & group)379 EffectChainSlotPointer PerGroupRack::getGroupEffectChainSlot(const QString& group) {
380 return m_groupToChainSlot[group];
381 }
382
QuickEffectRack(EffectsManager * pEffectsManager,EffectChainManager * pChainManager,const unsigned int iRackNumber)383 QuickEffectRack::QuickEffectRack(EffectsManager* pEffectsManager,
384 EffectChainManager* pChainManager,
385 const unsigned int iRackNumber)
386 : PerGroupRack(pEffectsManager, pChainManager, iRackNumber,
387 QuickEffectRack::formatGroupString(iRackNumber)) {
388 }
389
configureEffectChainSlotForGroup(EffectChainSlotPointer pSlot,const QString & groupName)390 void QuickEffectRack::configureEffectChainSlotForGroup(
391 EffectChainSlotPointer pSlot, const QString& groupName) {
392 Q_UNUSED(groupName);
393 // Set the parameter default value to 0.5 (neutral).
394 pSlot->setSuperParameter(0.5);
395 pSlot->setSuperParameterDefaultValue(0.5);
396 }
397
loadEffectToGroup(const QString & groupName,EffectPointer pEffect)398 bool QuickEffectRack::loadEffectToGroup(const QString& groupName,
399 EffectPointer pEffect) {
400 PerGroupRack::loadEffectToGroup(groupName, pEffect);
401 EffectChainSlotPointer pChainSlot = getGroupEffectChainSlot(groupName);
402 // Force update metaknobs and parameters to match state of superknob
403 pChainSlot->setSuperParameter(pChainSlot->getSuperParameter(), true);
404 return true;
405 }
406
EqualizerRack(EffectsManager * pEffectsManager,EffectChainManager * pChainManager,const unsigned int iRackNumber)407 EqualizerRack::EqualizerRack(EffectsManager* pEffectsManager,
408 EffectChainManager* pChainManager,
409 const unsigned int iRackNumber)
410 : PerGroupRack(pEffectsManager, pChainManager, iRackNumber,
411 EqualizerRack::formatGroupString(iRackNumber)) {
412 }
413
configureEffectChainSlotForGroup(EffectChainSlotPointer pSlot,const QString & groupName)414 void EqualizerRack::configureEffectChainSlotForGroup(EffectChainSlotPointer pSlot,
415 const QString& groupName) {
416 // Create aliases for legacy EQ controls.
417 // NOTE(rryan): If we ever add a second EqualizerRack then we need to make
418 // these only apply to the first.
419 EffectSlotPointer pEffectSlot = pSlot->getEffectSlot(0);
420 if (pEffectSlot) {
421 const QString& effectSlotGroup = pEffectSlot->getGroup();
422 ControlDoublePrivate::insertAlias(ConfigKey(groupName, "filterLow"),
423 ConfigKey(effectSlotGroup, "parameter1"));
424
425 ControlDoublePrivate::insertAlias(ConfigKey(groupName, "filterMid"),
426 ConfigKey(effectSlotGroup, "parameter2"));
427
428 ControlDoublePrivate::insertAlias(ConfigKey(groupName, "filterHigh"),
429 ConfigKey(effectSlotGroup, "parameter3"));
430
431 ControlDoublePrivate::insertAlias(ConfigKey(groupName, "filterLowKill"),
432 ConfigKey(effectSlotGroup, "button_parameter1"));
433
434 ControlDoublePrivate::insertAlias(ConfigKey(groupName, "filterMidKill"),
435 ConfigKey(effectSlotGroup, "button_parameter2"));
436
437 ControlDoublePrivate::insertAlias(ConfigKey(groupName, "filterHighKill"),
438 ConfigKey(effectSlotGroup, "button_parameter3"));
439
440 ControlDoublePrivate::insertAlias(ConfigKey(groupName, "filterLow_loaded"),
441 ConfigKey(effectSlotGroup, "parameter1_loaded"));
442
443 ControlDoublePrivate::insertAlias(ConfigKey(groupName, "filterMid_loaded"),
444 ConfigKey(effectSlotGroup, "parameter2_loaded"));
445
446 ControlDoublePrivate::insertAlias(ConfigKey(groupName, "filterHigh_loaded"),
447 ConfigKey(effectSlotGroup, "parameter3_loaded"));
448
449 ControlDoublePrivate::insertAlias(ConfigKey(groupName, "filterLowKill_loaded"),
450 ConfigKey(effectSlotGroup, "button_parameter1_loaded"));
451
452 ControlDoublePrivate::insertAlias(ConfigKey(groupName, "filterMidKill_loaded"),
453 ConfigKey(effectSlotGroup, "button_parameter2_loaded"));
454
455 ControlDoublePrivate::insertAlias(ConfigKey(groupName, "filterHighKill_loaded"),
456 ConfigKey(effectSlotGroup, "button_parameter3_loaded"));
457 }
458 }
459