diff --git a/src/effects/effect.cpp b/src/effects/effect.cpp index 2c4c90f4c3e0..6392dcbbfe5c 100644 --- a/src/effects/effect.cpp +++ b/src/effects/effect.cpp @@ -210,3 +210,7 @@ EffectPointer Effect::createFromXml(EffectsManager* pEffectsManager, EffectPointer pEffect = pEffectsManager->instantiateEffect(effectId); return pEffect; } + +double Effect::getMetaknobDefault() { + return m_manifest.metaknobDefault(); +} diff --git a/src/effects/effect.h b/src/effects/effect.h index 3549ecbb4e76..af23e5e9245f 100644 --- a/src/effects/effect.h +++ b/src/effects/effect.h @@ -64,6 +64,8 @@ class Effect : public QObject { static EffectPointer createFromXml(EffectsManager* pEffectsManager, const QDomElement& element); + double getMetaknobDefault(); + signals: void enabledChanged(bool enabled); diff --git a/src/effects/effectchainmanager.cpp b/src/effects/effectchainmanager.cpp index 3ccdc159a739..05bc6f77df93 100644 --- a/src/effects/effectchainmanager.cpp +++ b/src/effects/effectchainmanager.cpp @@ -217,3 +217,7 @@ void EffectChainManager::loadEffectChains() { } } } + +bool EffectChainManager::isAdoptMetaknobValueEnabled() const { + return m_pConfig->getValue(ConfigKey("[Effects]", "AdoptMetaknobValue"), true); +} diff --git a/src/effects/effectchainmanager.h b/src/effects/effectchainmanager.h index 80ba40843743..4f6dfb9b7d27 100644 --- a/src/effects/effectchainmanager.h +++ b/src/effects/effectchainmanager.h @@ -63,6 +63,8 @@ class EffectChainManager : public QObject { static const int kNumStandardEffectChains = 4; + bool isAdoptMetaknobValueEnabled() const; + private: QString debugString() const { return "EffectChainManager"; diff --git a/src/effects/effectchainslot.cpp b/src/effects/effectchainslot.cpp index cbfdcdb4e16b..d56be77d1140 100644 --- a/src/effects/effectchainslot.cpp +++ b/src/effects/effectchainslot.cpp @@ -180,7 +180,7 @@ void EffectChainSlot::slotChainEffectChanged(unsigned int effectSlotNumber, pEffect = effects.at(effectSlotNumber); } if (pSlot != nullptr) { - pSlot->loadEffect(pEffect); + pSlot->loadEffect(pEffect, m_pEffectRack->isAdoptMetaknobValueEnabled()); } m_pControlNumEffects->forceSet(math_min( diff --git a/src/effects/effectmanifest.h b/src/effects/effectmanifest.h index d27de0031f71..14645f144f40 100644 --- a/src/effects/effectmanifest.h +++ b/src/effects/effectmanifest.h @@ -24,31 +24,32 @@ class EffectManifest final { EffectManifest() : m_isMixingEQ(false), m_isMasterEQ(false), - m_effectRampsFromDry(false) { + m_effectRampsFromDry(false), + m_metaknobDefault(0.5) { } - virtual const QString& id() const { + const QString& id() const { return m_id; } - virtual void setId(const QString& id) { + void setId(const QString& id) { m_id = id; } - virtual const QString& name() const { + const QString& name() const { return m_name; } - virtual void setName(const QString& name) { + void setName(const QString& name) { m_name = name; } - virtual const QString& shortName() const { + const QString& shortName() const { return m_shortName; } - virtual void setShortName(const QString& shortName) { + void setShortName(const QString& shortName) { m_shortName = shortName; } - virtual const QString& displayName() const { + const QString& displayName() const { if (!m_shortName.isEmpty()) { return m_shortName; } else { @@ -56,64 +57,71 @@ class EffectManifest final { } } - virtual const QString& author() const { + const QString& author() const { return m_author; } - virtual void setAuthor(const QString& author) { + void setAuthor(const QString& author) { m_author = author; } - virtual const QString& version() const { + const QString& version() const { return m_version; } - virtual void setVersion(const QString& version) { + void setVersion(const QString& version) { m_version = version; } - virtual const QString& description() const { + const QString& description() const { return m_description; } - virtual const bool& isMixingEQ() const { + const bool& isMixingEQ() const { return m_isMixingEQ; } - virtual void setIsMixingEQ(const bool value) { + void setIsMixingEQ(const bool value) { m_isMixingEQ = value; } - virtual const bool& isMasterEQ() const { + const bool& isMasterEQ() const { return m_isMasterEQ; } - virtual void setIsMasterEQ(const bool value) { + void setIsMasterEQ(const bool value) { m_isMasterEQ = value; } - virtual void setDescription(const QString& description) { + void setDescription(const QString& description) { m_description = description; } - virtual const QList& parameters() const { + const QList& parameters() const { return m_parameters; } - virtual QList& parameters() { + QList& parameters() { return m_parameters; } - virtual EffectManifestParameter* addParameter() { + EffectManifestParameter* addParameter() { m_parameters.append(EffectManifestParameter()); return &m_parameters.last(); } - virtual bool effectRampsFromDry() const { + bool effectRampsFromDry() const { return m_effectRampsFromDry; } - virtual void setEffectRampsFromDry(bool effectFadesFromDry) { + void setEffectRampsFromDry(bool effectFadesFromDry) { m_effectRampsFromDry = effectFadesFromDry; } + double metaknobDefault() const { + return m_metaknobDefault; + } + void setMetaknobDefault(double metaknobDefault) { + m_metaknobDefault = metaknobDefault; + } + private: QString debugString() const { return QString("EffectManifest(%1)").arg(m_id); @@ -130,6 +138,7 @@ class EffectManifest final { bool m_isMasterEQ; QList m_parameters; bool m_effectRampsFromDry; + double m_metaknobDefault; }; #endif /* EFFECTMANIFEST_H */ diff --git a/src/effects/effectrack.cpp b/src/effects/effectrack.cpp index 04679b4871eb..e34d0ade08da 100644 --- a/src/effects/effectrack.cpp +++ b/src/effects/effectrack.cpp @@ -211,6 +211,10 @@ QDomElement EffectRack::toXml(QDomDocument* doc) const { return rackElement; } +bool EffectRack::isAdoptMetaknobValueEnabled() const { + return m_pEffectChainManager->isAdoptMetaknobValueEnabled(); +} + StandardEffectRack::StandardEffectRack(EffectsManager* pEffectsManager, EffectChainManager* pChainManager, const unsigned int iRackNumber) @@ -283,7 +287,7 @@ OutputEffectRack::OutputEffectRack(EffectsManager* pEffectsManager, this, SLOT(loadPrevEffect(unsigned int, unsigned int, EffectPointer))); // Register the master channel. - const ChannelHandleAndGroup* masterHandleAndGroup; + const ChannelHandleAndGroup* masterHandleAndGroup = nullptr; // TODO(Be): Remove this hideous hack to get the ChannelHandleAndGroup const QSet& registeredChannels = @@ -336,7 +340,7 @@ void PerGroupRack::setupForGroup(const QString& groupName) { pChain->updateEngineState(); // TODO(rryan): remove. - const ChannelHandleAndGroup* handleAndGroup; + const ChannelHandleAndGroup* handleAndGroup = nullptr; for (const ChannelHandleAndGroup& handle_group : m_pEffectChainManager->registeredInputChannels()) { if (handle_group.name() == groupName) { diff --git a/src/effects/effectrack.h b/src/effects/effectrack.h index 9524e8481311..2bc5b013c88f 100644 --- a/src/effects/effectrack.h +++ b/src/effects/effectrack.h @@ -57,6 +57,8 @@ class EffectRack : public QObject { QDomElement toXml(QDomDocument* doc) const; + virtual bool isAdoptMetaknobValueEnabled() const; + public slots: void slotClearRack(double v); @@ -197,6 +199,11 @@ class QuickEffectRack : public PerGroupRack { group); } + bool isAdoptMetaknobValueEnabled() const override { + // No visible Metaknobs to adopt + return false; + } + protected: void configureEffectChainSlotForGroup(EffectChainSlotPointer pSlot, const QString& group) override; @@ -244,6 +251,11 @@ class EqualizerRack : public PerGroupRack { group); } + bool isAdoptMetaknobValueEnabled() const override { + // No visible Metaknobs to adopt + return false; + } + protected: void configureEffectChainSlotForGroup(EffectChainSlotPointer pSlot, const QString& group) override; diff --git a/src/effects/effectslot.cpp b/src/effects/effectslot.cpp index f7a42acdf3bc..3eb1bacf8b91 100644 --- a/src/effects/effectslot.cpp +++ b/src/effects/effectslot.cpp @@ -149,7 +149,7 @@ EffectButtonParameterSlotPointer EffectSlot::getEffectButtonParameterSlot(unsign return m_buttonParameters[slotNumber]; } -void EffectSlot::loadEffect(EffectPointer pEffect) { +void EffectSlot::loadEffect(EffectPointer pEffect, bool adoptMetaknobPosition) { //qDebug() << debugString() << "loadEffect" // << (pEffect ? pEffect->getManifest().name() : "(null)"); if (pEffect) { @@ -183,7 +183,13 @@ void EffectSlot::loadEffect(EffectPointer pEffect) { pParameter->loadEffect(pEffect); } - slotEffectMetaParameter(m_pControlMetaParameter->get(), true); + + if (adoptMetaknobPosition) { + slotEffectMetaParameter(m_pControlMetaParameter->get(), true); + } else { + m_pControlMetaParameter->set(pEffect->getMetaknobDefault()); + slotEffectMetaParameter(pEffect->getMetaknobDefault(), true); + } emit(effectLoaded(pEffect, m_iEffectNumber)); } else { diff --git a/src/effects/effectslot.h b/src/effects/effectslot.h index a0579504fd31..89c4da444659 100644 --- a/src/effects/effectslot.h +++ b/src/effects/effectslot.h @@ -71,7 +71,7 @@ class EffectSlot : public QObject { public slots: // Request that this EffectSlot load the given Effect - void loadEffect(EffectPointer pEffect); + void loadEffect(EffectPointer pEffect, bool adoptMetaknobPosition); void setMetaParameter(double v, bool force = false); void slotEnabled(double v); @@ -113,6 +113,7 @@ class EffectSlot : public QObject { const unsigned int m_iChainNumber; const unsigned int m_iEffectNumber; const QString m_group; + UserSettingsPointer m_pConfig; EffectPointer m_pEffect; ControlObject* m_pControlLoaded; diff --git a/src/effects/native/bitcrushereffect.cpp b/src/effects/native/bitcrushereffect.cpp index ed48e0a07635..0711045ca302 100644 --- a/src/effects/native/bitcrushereffect.cpp +++ b/src/effects/native/bitcrushereffect.cpp @@ -18,6 +18,7 @@ EffectManifest BitCrusherEffect::getManifest() { manifest.setDescription(QObject::tr( "Adds noise by the reducing the bit depth and sample rate")); manifest.setEffectRampsFromDry(true); + manifest.setMetaknobDefault(0.0); EffectManifestParameter* depth = manifest.addParameter(); depth->setId("bit_depth"); diff --git a/src/effects/native/echoeffect.cpp b/src/effects/native/echoeffect.cpp index a9c27e99accc..5dae9b6228bd 100644 --- a/src/effects/native/echoeffect.cpp +++ b/src/effects/native/echoeffect.cpp @@ -34,6 +34,7 @@ EffectManifest EchoEffect::getManifest() { manifest.setVersion("1.0"); manifest.setDescription(QObject::tr( "Stores the input signal in a temporary buffer and outputs it after a short time")); + manifest.setMetaknobDefault(db2ratio(-3.0)); EffectManifestParameter* delay = manifest.addParameter(); delay->setId("delay_time"); diff --git a/src/effects/native/flangereffect.cpp b/src/effects/native/flangereffect.cpp index fd6a6377a176..9ad084e2ba04 100644 --- a/src/effects/native/flangereffect.cpp +++ b/src/effects/native/flangereffect.cpp @@ -30,6 +30,7 @@ EffectManifest FlangerEffect::getManifest() { manifest.setVersion("1.0"); manifest.setDescription(QObject::tr( "Mixes the input with a delayed, pitch modulated copy of itself to create comb filtering")); + manifest.setMetaknobDefault(1.0); EffectManifestParameter* speed = manifest.addParameter(); speed->setId("speed"); diff --git a/src/effects/native/loudnesscontoureffect.cpp b/src/effects/native/loudnesscontoureffect.cpp index 495ae4416890..ce526dd39bd5 100644 --- a/src/effects/native/loudnesscontoureffect.cpp +++ b/src/effects/native/loudnesscontoureffect.cpp @@ -30,6 +30,7 @@ EffectManifest LoudnessContourEffect::getManifest() { manifest.setDescription(QObject::tr( "Amplifies low and high frequencies at low volumes to compensate for reduced sensitivity of the human ear.")); manifest.setEffectRampsFromDry(true); + manifest.setMetaknobDefault(-kMaxLoGain / 2); EffectManifestParameter* loudness = manifest.addParameter(); loudness->setId("loudness"); diff --git a/src/effects/native/tremoloeffect.cpp b/src/effects/native/tremoloeffect.cpp index 407090605a30..bf48c1e30686 100644 --- a/src/effects/native/tremoloeffect.cpp +++ b/src/effects/native/tremoloeffect.cpp @@ -20,6 +20,7 @@ EffectManifest TremoloEffect::getManifest() { manifest.setVersion("1.0"); manifest.setDescription(QObject::tr( "Cycles the volume up and down")); + manifest.setMetaknobDefault(1.0); EffectManifestParameter* depth = manifest.addParameter(); depth->setId("depth"); diff --git a/src/preferences/dialog/dlgprefinterface.cpp b/src/preferences/dialog/dlgprefinterface.cpp index 0ff6c729d163..155506fce8a8 100644 --- a/src/preferences/dialog/dlgprefinterface.cpp +++ b/src/preferences/dialog/dlgprefinterface.cpp @@ -255,6 +255,11 @@ void DlgPrefInterface::slotUpdate() { int inhibitsettings = static_cast(m_mixxx->getInhibitScreensaver()); comboBoxScreensaver->setCurrentIndex(comboBoxScreensaver->findData(inhibitsettings)); + + bool effectAdoptMetaknobValue = m_pConfig->getValue( + ConfigKey("[Effects]", "AdoptMetaknobValue"), true); + radioButtonKeepMetaknobPosition->setChecked(effectAdoptMetaknobValue); + radioButtonMetaknobLoadDefault->setChecked(!effectAdoptMetaknobValue); } void DlgPrefInterface::slotResetToDefaults() { @@ -280,6 +285,8 @@ void DlgPrefInterface::slotResetToDefaults() { // Tooltips on everywhere. radioButtonTooltipsLibraryAndSkin->setChecked(true); + + radioButtonKeepMetaknobPosition->setChecked(true); } void DlgPrefInterface::slotSetLocale(int pos) { @@ -360,6 +367,9 @@ void DlgPrefInterface::slotApply() { m_pConfig->set(ConfigKey("[Config]", "StartInFullscreen"), ConfigValue(checkBoxStartFullScreen->isChecked())); + m_pConfig->set(ConfigKey("[Effects]", "AdoptMetaknobValue"), + ConfigValue(radioButtonKeepMetaknobPosition->isChecked())); + m_mixxx->setToolTipsCfg(m_tooltipMode); // screensaver mode update diff --git a/src/preferences/dialog/dlgprefinterfacedlg.ui b/src/preferences/dialog/dlgprefinterfacedlg.ui index ebc2f23977fe..b91cd62f677f 100644 --- a/src/preferences/dialog/dlgprefinterfacedlg.ui +++ b/src/preferences/dialog/dlgprefinterfacedlg.ui @@ -225,6 +225,46 @@ + + + Effect options + + + + + + Load behavior + + + + + + + + + Keep metaknob position + + + buttonGroupEffectLoadBehavior + + + + + + + Reset metaknob to effect default + + + buttonGroupEffectLoadBehavior + + + + + + + + + Qt::Vertical @@ -249,7 +289,10 @@ radioButtonTooltipsLibrary radioButtonTooltipsLibraryAndSkin + + + diff --git a/src/test/effectslottest.cpp b/src/test/effectslottest.cpp index e2023a5eaea3..2b2ba87f1889 100644 --- a/src/test/effectslottest.cpp +++ b/src/test/effectslottest.cpp @@ -59,7 +59,7 @@ TEST_F(EffectSlotTest, ControlsReflectSlotState) { EXPECT_DOUBLE_EQ(0, ControlObject::get(ConfigKey(group, "enabled"))); EXPECT_DOUBLE_EQ(0, ControlObject::get(ConfigKey(group, "num_parameters"))); - pEffectSlot->loadEffect(pEffect); + pEffectSlot->loadEffect(pEffect, false); EXPECT_DOUBLE_EQ(0, ControlObject::get(ConfigKey(group, "enabled"))); EXPECT_DOUBLE_EQ(1, ControlObject::get(ConfigKey(group, "num_parameters"))); diff --git a/src/test/metaknob_link_test.cpp b/src/test/metaknob_link_test.cpp index db9d49a06459..4974b94e89d8 100644 --- a/src/test/metaknob_link_test.cpp +++ b/src/test/metaknob_link_test.cpp @@ -57,7 +57,7 @@ class MetaLinkTest : public BaseEffectTest { // Check the controls reflect the state of their loaded effect. EffectPointer pEffect = m_pEffectsManager->instantiateEffect(manifest.id()); - m_pEffectSlot->loadEffect(pEffect); + m_pEffectSlot->loadEffect(pEffect, false); QString itemPrefix = EffectParameterSlot::formatItemPrefix(0); @@ -220,7 +220,7 @@ TEST_F(MetaLinkTest, HalfLinkTakeover) { registerTestEffect(manifest, false); // Check the controls reflect the state of their loaded effect. EffectPointer pEffect = m_pEffectsManager->instantiateEffect(manifest.id()); - m_pEffectSlot->loadEffect(pEffect); + m_pEffectSlot->loadEffect(pEffect, false); QString itemPrefix = EffectParameterSlot::formatItemPrefix(0); m_pControlValue.reset(new ControlProxy(group, itemPrefix)); m_pControlLinkType.reset(new ControlProxy(group,