diff --git a/build/depends.py b/build/depends.py index eb7110dfc7e..7c039d59f96 100644 --- a/build/depends.py +++ b/build/depends.py @@ -743,19 +743,17 @@ def sources(self, build): "src/effects/effectmanifest.cpp", "src/effects/effectmanifestparameter.cpp", - "src/effects/effectchain.cpp", - "src/effects/effect.cpp", "src/effects/effectparameter.cpp", - "src/effects/effectrack.cpp", + "src/effects/effectchainpreset.cpp", + "src/effects/effectpreset.cpp", "src/effects/effectchainslot.cpp", + "src/effects/specialeffectchainslots.cpp", "src/effects/effectslot.cpp", "src/effects/effectparameterslotbase.cpp", - "src/effects/effectparameterslot.cpp", + "src/effects/effectknobparameterslot.cpp", "src/effects/effectbuttonparameterslot.cpp", "src/effects/effectsmanager.cpp", - "src/effects/effectchainmanager.cpp", - "src/effects/effectsbackend.cpp", "src/effects/builtin/builtinbackend.cpp", "src/effects/builtin/bitcrushereffect.cpp", @@ -779,7 +777,6 @@ def sources(self, build): "src/effects/builtin/tremoloeffect.cpp", "src/engine/effects/engineeffectsmanager.cpp", - "src/engine/effects/engineeffectrack.cpp", "src/engine/effects/engineeffectchain.cpp", "src/engine/effects/engineeffect.cpp", diff --git a/src/control/controleffectknob.cpp b/src/control/controleffectknob.cpp index 169cade841d..1c99d2f836f 100644 --- a/src/control/controleffectknob.cpp +++ b/src/control/controleffectknob.cpp @@ -7,19 +7,19 @@ ControlEffectKnob::ControlEffectKnob(ConfigKey key, double dMinValue, double dMa : ControlPotmeter(key, dMinValue, dMaxValue) { } -void ControlEffectKnob::setBehaviour(EffectManifestParameter::ControlHint type, +void ControlEffectKnob::setBehaviour(EffectManifestParameter::ValueScaler type, double dMinValue, double dMaxValue) { if (m_pControl == NULL) { return; } - if (type == EffectManifestParameter::ControlHint::KNOB_LINEAR) { + if (type == EffectManifestParameter::ValueScaler::LINEAR) { m_pControl->setBehavior(new ControlLinPotmeterBehavior( dMinValue, dMaxValue, false)); - } else if (type == EffectManifestParameter::ControlHint::KNOB_LINEAR_INVERSE) { + } else if (type == EffectManifestParameter::ValueScaler::LINEAR_INVERSE) { m_pControl->setBehavior(new ControlLinInvPotmeterBehavior( dMinValue, dMaxValue, false)); - } else if (type == EffectManifestParameter::ControlHint::KNOB_LOGARITHMIC) { + } else if (type == EffectManifestParameter::ValueScaler::LOGARITHMIC) { if (dMinValue == 0) { if (dMaxValue == 1.0) { // Volume like control @@ -37,7 +37,7 @@ void ControlEffectKnob::setBehaviour(EffectManifestParameter::ControlHint type, m_pControl->setBehavior( new ControlLogPotmeterBehavior(dMinValue, dMaxValue, -40)); } - } else if (type == EffectManifestParameter::ControlHint::KNOB_LOGARITHMIC_INVERSE) { + } else if (type == EffectManifestParameter::ValueScaler::LOGARITHMIC_INVERSE) { m_pControl->setBehavior( new ControlLogInvPotmeterBehavior(dMinValue, dMaxValue, -40)); } diff --git a/src/control/controleffectknob.h b/src/control/controleffectknob.h index eabb38e07b1..07f6d1a4cd6 100644 --- a/src/control/controleffectknob.h +++ b/src/control/controleffectknob.h @@ -9,7 +9,7 @@ class ControlEffectKnob : public ControlPotmeter { public: ControlEffectKnob(ConfigKey key, double dMinValue = 0.0, double dMaxValue = 1.0); - void setBehaviour(EffectManifestParameter::ControlHint type, + void setBehaviour(EffectManifestParameter::ValueScaler type, double dMinValue, double dMaxValue); }; diff --git a/src/controllers/controlpickermenu.cpp b/src/controllers/controlpickermenu.cpp index 16e41e89520..bde936bda5a 100644 --- a/src/controllers/controlpickermenu.cpp +++ b/src/controllers/controlpickermenu.cpp @@ -4,10 +4,9 @@ #include "mixer/playermanager.h" #include "engine/controls/cuecontrol.h" #include "engine/controls/loopingcontrol.h" -#include "effects/effectrack.h" -#include "effects/effectchainslot.h" +#include "effects/specialeffectchainslots.h" #include "effects/effectslot.h" -#include "effects/effectparameterslot.h" +#include "effects/effectknobparameterslot.h" ControlPickerMenu::ControlPickerMenu(QWidget* pParent) : QMenu(pParent) { @@ -150,38 +149,35 @@ ControlPickerMenu::ControlPickerMenu(QWidget* pParent) tr("Temporarily decrease speed (fine)"), speedMenu); // EQs - QMenu* eqMenu = addSubmenu(tr("Equalizers")); - const int kNumEqRacks = 1; + QMenu* eqMenu = addSubmenu(tr("Equalizers")); // const int kNumEqRacks = 1; const int iNumDecks = ControlObject::get(ConfigKey("[Master]", "num_decks")); - for (int iRackNumber = 0; iRackNumber < kNumEqRacks; ++iRackNumber) { - // TODO: Although there is a mode with 4-band EQs, it's not feasible - // right now to add support for learning both it and regular 3-band eqs. - // Since 3-band is by far the most common, stick with that. - const int kMaxEqs = 3; - QList eqNames; - eqNames.append(tr("Low EQ")); - eqNames.append(tr("Mid EQ")); - eqNames.append(tr("High EQ")); - for (int deck = 1; deck <= iNumDecks; ++deck) { - QMenu* deckMenu = addSubmenu(QString("Deck %1").arg(deck), eqMenu); - for (int effect = kMaxEqs - 1; effect >= 0; --effect) { - const QString group = EqualizerRack::formatEffectSlotGroupString( - iRackNumber, 0, QString("[Channel%1]").arg(deck)); - QMenu* bandMenu = addSubmenu(eqNames[effect], deckMenu); - QString control = "parameter%1"; - addPrefixedControl(group, control.arg(effect+1), - tr("Adjust %1").arg(eqNames[effect]), - tr("Adjust %1").arg(eqNames[effect]), - tr("Deck %1").arg(deck), - bandMenu, true); - - control = "button_parameter%1"; - addPrefixedControl(group, control.arg(effect+1), - tr("Kill %1").arg(eqNames[effect]), - tr("Kill %1").arg(eqNames[effect]), - tr("Deck %1").arg(deck), - bandMenu, false); - } + // TODO: Although there is a mode with 4-band EQs, it's not feasible + // right now to add support for learning both it and regular 3-band eqs. + // Since 3-band is by far the most common, stick with that. + const int kMaxEqs = 3; + QList eqNames; + eqNames.append(tr("Low EQ")); + eqNames.append(tr("Mid EQ")); + eqNames.append(tr("High EQ")); + for (int deck = 1; deck <= iNumDecks; ++deck) { + QMenu* deckMenu = addSubmenu(QString("Deck %1").arg(deck), eqMenu); + for (int effect = kMaxEqs - 1; effect >= 0; --effect) { + const QString group = EqualizerEffectChainSlot::formatEffectSlotGroup( + PlayerManager::groupForDeck(deck)); + QMenu* bandMenu = addSubmenu(eqNames[effect], deckMenu); + QString control = "parameter%1"; + addPrefixedControl(group, control.arg(effect+1), + tr("Adjust %1").arg(eqNames[effect]), + tr("Adjust %1").arg(eqNames[effect]), + tr("Deck %1").arg(deck), + bandMenu, true); + + control = "button_parameter%1"; + addPrefixedControl(group, control.arg(effect+1), + tr("Kill %1").arg(eqNames[effect]), + tr("Kill %1").arg(eqNames[effect]), + tr("Deck %1").arg(deck), + bandMenu, false); } } @@ -465,226 +461,220 @@ ControlPickerMenu::ControlPickerMenu(QWidget* pParent) quickEffectMenu); } - const int kNumEffectRacks = 1; - for (int iRackNumber = 1; iRackNumber <= kNumEffectRacks; ++iRackNumber) { - const QString rackGroup = StandardEffectRack::formatGroupString( - iRackNumber - 1); - QMenu* rackMenu = addSubmenu(m_effectRackStr.arg(iRackNumber), effectsMenu); - QString descriptionPrefix = m_effectRackStr.arg(iRackNumber); - - addPrefixedControl(rackGroup, "clear", - tr("Clear Effect Rack"), tr("Clear effect rack"), - descriptionPrefix, rackMenu); - - const int numEffectUnits = ControlObject::get( - ConfigKey(rackGroup, "num_effectunits")); - for (int iEffectUnitNumber = 1; iEffectUnitNumber <= numEffectUnits; - ++iEffectUnitNumber) { - const QString effectUnitGroup = - StandardEffectRack::formatEffectChainSlotGroupString( - iRackNumber - 1, iEffectUnitNumber - 1); - - descriptionPrefix = QString("%1, %2").arg(m_effectRackStr.arg(iRackNumber), - m_effectUnitStr.arg(iEffectUnitNumber)); - - QMenu* effectUnitMenu = addSubmenu(m_effectUnitStr.arg(iEffectUnitNumber), - rackMenu); - addPrefixedControl(effectUnitGroup, "clear", - tr("Clear Unit"), - tr("Clear effect unit"), descriptionPrefix, - effectUnitMenu); - addPrefixedControl(effectUnitGroup, "enabled", - tr("Toggle Unit"), - tr("Enable or disable effect processing"), descriptionPrefix, - effectUnitMenu, false); - addPrefixedControl(effectUnitGroup, "mix", - tr("Dry/Wet"), - tr("Adjust the balance between the original (dry) and processed (wet) signal."), descriptionPrefix, - effectUnitMenu, true); - addPrefixedControl(effectUnitGroup, "super1", - tr("Super Knob"), - tr("Super Knob (control effects' Meta Knobs)"), - descriptionPrefix, - effectUnitMenu, true); - addPrefixedControl(effectUnitGroup, "Mix Mode", - tr("Mix Mode Toggle"), - tr("Toggle effect unit between D/W and D+W modes"), - descriptionPrefix, - effectUnitMenu); - addPrefixedControl(effectUnitGroup, "next_chain", - tr("Next Chain"), - tr("Next chain preset"), descriptionPrefix, - effectUnitMenu); - addPrefixedControl(effectUnitGroup, "prev_chain", - tr("Previous Chain"), - tr("Previous chain preset"), descriptionPrefix, - effectUnitMenu); - addPrefixedControl(effectUnitGroup, "chain_selector", - tr("Next/Previous Chain"), - tr("Next or previous chain preset"), descriptionPrefix, - effectUnitMenu); - addPrefixedControl(effectUnitGroup, "show_parameters", - tr("Show Effect Parameters"), - tr("Show Effect Parameters"), descriptionPrefix, - effectUnitMenu); - - QString enableOn = tr("Toggle Effect Unit"); - QMenu* effectUnitGroups = addSubmenu(enableOn, - effectUnitMenu); - - QString groupDescriptionPrefix = QString("%1, %2 %3").arg( - m_effectRackStr.arg(iRackNumber), - m_effectUnitStr.arg(iEffectUnitNumber), - enableOn); - - addPrefixedControl(effectUnitGroup, "group_[Master]_enable", - m_effectMasterOutputStr, - m_effectMasterOutputStr, groupDescriptionPrefix, - effectUnitGroups); - addPrefixedControl(effectUnitGroup, "group_[Headphone]_enable", - m_effectHeadphoneOutputStr, - m_effectHeadphoneOutputStr, groupDescriptionPrefix, + const QString rackGroup = "[EffectRack1]"; + QMenu* rackMenu = addSubmenu(m_effectRackStr.arg(1), effectsMenu); + QString descriptionPrefix = m_effectRackStr.arg(1); + + addPrefixedControl(rackGroup, "clear", + tr("Clear Effect Rack"), tr("Clear effect rack"), + descriptionPrefix, rackMenu); + + const int numEffectUnits = ControlObject::get( + ConfigKey(rackGroup, "num_effectunits")); + for (int iEffectUnitNumber = 1; iEffectUnitNumber <= numEffectUnits; + ++iEffectUnitNumber) { + const QString effectUnitGroup = + StandardEffectChainSlot::formatEffectChainSlotGroup(iEffectUnitNumber - 1); + + descriptionPrefix = QString("%1, %2").arg(m_effectRackStr.arg(1), + m_effectUnitStr.arg(iEffectUnitNumber)); + + QMenu* effectUnitMenu = addSubmenu(m_effectUnitStr.arg(iEffectUnitNumber), + rackMenu); + addPrefixedControl(effectUnitGroup, "clear", + tr("Clear Unit"), + tr("Clear effect unit"), descriptionPrefix, + effectUnitMenu); + addPrefixedControl(effectUnitGroup, "enabled", + tr("Toggle Unit"), + tr("Enable or disable effect processing"), descriptionPrefix, + effectUnitMenu, false); + addPrefixedControl(effectUnitGroup, "mix", + tr("Dry/Wet"), + tr("Adjust the balance between the original (dry) and processed (wet) signal."), descriptionPrefix, + effectUnitMenu, true); + addPrefixedControl(effectUnitGroup, "super1", + tr("Super Knob"), + tr("Super Knob (control effects' Meta Knobs)"), + descriptionPrefix, + effectUnitMenu, true); + addPrefixedControl(effectUnitGroup, "Mix Mode", + tr("Mix Mode Toggle"), + tr("Toggle effect unit between D/W and D+W modes"), + descriptionPrefix, + effectUnitMenu); + addPrefixedControl(effectUnitGroup, "next_chain", + tr("Next Chain"), + tr("Next chain preset"), descriptionPrefix, + effectUnitMenu); + addPrefixedControl(effectUnitGroup, "prev_chain", + tr("Previous Chain"), + tr("Previous chain preset"), descriptionPrefix, + effectUnitMenu); + addPrefixedControl(effectUnitGroup, "chain_selector", + tr("Next/Previous Chain"), + tr("Next or previous chain preset"), descriptionPrefix, + effectUnitMenu); + addPrefixedControl(effectUnitGroup, "show_parameters", + tr("Show Effect Parameters"), + tr("Show Effect Parameters"), descriptionPrefix, + effectUnitMenu); + + QString enableOn = tr("Toggle Effect Unit"); + QMenu* effectUnitGroups = addSubmenu(enableOn, + effectUnitMenu); + + QString groupDescriptionPrefix = QString("%1, %2 %3").arg( + m_effectRackStr.arg(1), + m_effectUnitStr.arg(iEffectUnitNumber), + enableOn); + + addPrefixedControl(effectUnitGroup, "group_[Master]_enable", + m_effectMasterOutputStr, + m_effectMasterOutputStr, groupDescriptionPrefix, + effectUnitGroups); + addPrefixedControl(effectUnitGroup, "group_[Headphone]_enable", + m_effectHeadphoneOutputStr, + m_effectHeadphoneOutputStr, groupDescriptionPrefix, + effectUnitGroups); + + const int iNumDecks = ControlObject::get( + ConfigKey("[Master]", "num_decks")); + for (int iDeckNumber = 1; iDeckNumber <= iNumDecks; ++iDeckNumber) { + // PlayerManager::groupForDeck is 0-indexed. + QString playerGroup = PlayerManager::groupForDeck(iDeckNumber - 1); + // TODO(owen): Fix bad i18n here. + addPrefixedControl(effectUnitGroup, + QString("group_%1_enable").arg(playerGroup), + tr("Assign ") + m_deckStr.arg(iDeckNumber), + tr("Assign ") + m_deckStr.arg(iDeckNumber), + groupDescriptionPrefix, effectUnitGroups); + } - const int iNumDecks = ControlObject::get( - ConfigKey("[Master]", "num_decks")); - for (int iDeckNumber = 1; iDeckNumber <= iNumDecks; ++iDeckNumber) { - // PlayerManager::groupForDeck is 0-indexed. - QString playerGroup = PlayerManager::groupForDeck(iDeckNumber - 1); - // TODO(owen): Fix bad i18n here. - addPrefixedControl(effectUnitGroup, - QString("group_%1_enable").arg(playerGroup), - tr("Assign ") + m_deckStr.arg(iDeckNumber), - tr("Assign ") + m_deckStr.arg(iDeckNumber), - groupDescriptionPrefix, - effectUnitGroups); - } - - const int iNumSamplers = ControlObject::get( - ConfigKey("[Master]", "num_samplers")); - for (int iSamplerNumber = 1; iSamplerNumber <= iNumSamplers; - ++iSamplerNumber) { - // PlayerManager::groupForSampler is 0-indexed. - QString playerGroup = PlayerManager::groupForSampler(iSamplerNumber - 1); - // TODO(owen): Fix bad i18n here. - addPrefixedControl(effectUnitGroup, - QString("group_%1_enable").arg(playerGroup), - tr("Assign ") + m_samplerStr.arg(iSamplerNumber), - tr("Assign ") + m_samplerStr.arg(iSamplerNumber), - groupDescriptionPrefix, - effectUnitGroups); - - } + const int iNumSamplers = ControlObject::get( + ConfigKey("[Master]", "num_samplers")); + for (int iSamplerNumber = 1; iSamplerNumber <= iNumSamplers; + ++iSamplerNumber) { + // PlayerManager::groupForSampler is 0-indexed. + QString playerGroup = PlayerManager::groupForSampler(iSamplerNumber - 1); + // TODO(owen): Fix bad i18n here. + addPrefixedControl(effectUnitGroup, + QString("group_%1_enable").arg(playerGroup), + tr("Assign ") + m_samplerStr.arg(iSamplerNumber), + tr("Assign ") + m_samplerStr.arg(iSamplerNumber), + groupDescriptionPrefix, + effectUnitGroups); + } - const int iNumMicrophones = ControlObject::get( - ConfigKey("[Master]", "num_microphones")); - for (int iMicrophoneNumber = 1; iMicrophoneNumber <= iNumMicrophones; - ++iMicrophoneNumber) { - QString micGroup = PlayerManager::groupForMicrophone(iMicrophoneNumber - 1); - // TODO(owen): Fix bad i18n here. - addPrefixedControl(effectUnitGroup, - QString("group_%1_enable").arg(micGroup), - tr("Assign ") + m_microphoneStr.arg(iMicrophoneNumber), - tr("Assign ") + m_microphoneStr.arg(iMicrophoneNumber), - groupDescriptionPrefix, - effectUnitGroups); - } + const int iNumMicrophones = ControlObject::get( + ConfigKey("[Master]", "num_microphones")); + for (int iMicrophoneNumber = 1; iMicrophoneNumber <= iNumMicrophones; + ++iMicrophoneNumber) { + QString micGroup = PlayerManager::groupForMicrophone(iMicrophoneNumber - 1); + // TODO(owen): Fix bad i18n here. + addPrefixedControl(effectUnitGroup, + QString("group_%1_enable").arg(micGroup), + tr("Assign ") + m_microphoneStr.arg(iMicrophoneNumber), + tr("Assign ") + m_microphoneStr.arg(iMicrophoneNumber), + groupDescriptionPrefix, + effectUnitGroups); + } - const int iNumAuxiliaries = ControlObject::get( - ConfigKey("[Master]", "num_auxiliaries")); - for (int iAuxiliaryNumber = 1; iAuxiliaryNumber <= iNumAuxiliaries; - ++iAuxiliaryNumber) { - QString auxGroup = PlayerManager::groupForAuxiliary(iAuxiliaryNumber - 1); - // TODO(owen): Fix bad i18n here. - addPrefixedControl(effectUnitGroup, - QString("group_%1_enable").arg(auxGroup), - tr("Assign ") + m_auxStr.arg(iAuxiliaryNumber), - tr("Assign ") + m_auxStr.arg(iAuxiliaryNumber), - groupDescriptionPrefix, - effectUnitGroups); - } + const int iNumAuxiliaries = ControlObject::get( + ConfigKey("[Master]", "num_auxiliaries")); + for (int iAuxiliaryNumber = 1; iAuxiliaryNumber <= iNumAuxiliaries; + ++iAuxiliaryNumber) { + QString auxGroup = PlayerManager::groupForAuxiliary(iAuxiliaryNumber - 1); + // TODO(owen): Fix bad i18n here. + addPrefixedControl(effectUnitGroup, + QString("group_%1_enable").arg(auxGroup), + tr("Assign ") + m_auxStr.arg(iAuxiliaryNumber), + tr("Assign ") + m_auxStr.arg(iAuxiliaryNumber), + groupDescriptionPrefix, + effectUnitGroups); + } - const int numEffectSlots = ControlObject::get( - ConfigKey(effectUnitGroup, "num_effectslots")); - for (int iEffectSlotNumber = 1; iEffectSlotNumber <= numEffectSlots; - ++iEffectSlotNumber) { - const QString effectSlotGroup = - StandardEffectRack::formatEffectSlotGroupString( - iRackNumber - 1, iEffectUnitNumber - 1, + const int numEffectSlots = ControlObject::get( + ConfigKey(effectUnitGroup, "num_effectslots")); + for (int iEffectSlotNumber = 1; iEffectSlotNumber <= numEffectSlots; + ++iEffectSlotNumber) { + const QString effectSlotGroup = + StandardEffectChainSlot::formatEffectSlotGroup( + iEffectUnitNumber - 1, + iEffectSlotNumber - 1); + + QMenu* effectSlotMenu = addSubmenu(m_effectStr.arg(iEffectSlotNumber), + effectUnitMenu); + + QString slotDescriptionPrefix = + QString("%1, %2").arg(descriptionPrefix, + m_effectStr.arg(iEffectSlotNumber)); + + addPrefixedControl(effectSlotGroup, "clear", + tr("Clear"), tr("Clear the current effect"), + slotDescriptionPrefix, + effectSlotMenu); + addPrefixedControl(effectSlotGroup, "meta", + tr("Meta Knob"), tr("Effect Meta Knob (control linked effect parameters)"), + slotDescriptionPrefix, + effectSlotMenu); + addPrefixedControl(effectSlotGroup, "enabled", + tr("Toggle"), tr("Toggle the current effect"), + slotDescriptionPrefix, + effectSlotMenu); + addPrefixedControl(effectSlotGroup, "next_effect", + tr("Next"), tr("Switch to next effect"), + slotDescriptionPrefix, + effectSlotMenu); + addPrefixedControl(effectSlotGroup, "prev_effect", + tr("Previous"), tr("Switch to the previous effect"), + slotDescriptionPrefix, + effectSlotMenu); + addPrefixedControl(effectSlotGroup, "effect_selector", + tr("Next or Previous"), + tr("Switch to either next or previous effect"), + slotDescriptionPrefix, + effectSlotMenu); + + const int numParameterSlots = ControlObject::get( + ConfigKey(effectSlotGroup, "num_parameterslots")); + for (int iParameterSlotNumber = 1; iParameterSlotNumber <= numParameterSlots; + ++iParameterSlotNumber) { + // The parameter slot group is the same as the effect slot + // group on a standard effect rack. + const QString parameterSlotGroup = + StandardEffectChainSlot::formatEffectSlotGroup( + iEffectUnitNumber - 1, iEffectSlotNumber - 1); + const QString parameterSlotItemPrefix = EffectKnobParameterSlot::formatItemPrefix( + iParameterSlotNumber - 1); + QMenu* parameterSlotMenu = addSubmenu( + m_parameterStr.arg(iParameterSlotNumber), + effectSlotMenu); + + QString parameterDescriptionPrefix = + QString("%1, %2").arg(slotDescriptionPrefix, + m_parameterStr.arg(iParameterSlotNumber)); + + // Likely to change soon. + addPrefixedControl(parameterSlotGroup, parameterSlotItemPrefix, + tr("Parameter Value"), + tr("Parameter Value"), + parameterDescriptionPrefix, + parameterSlotMenu, true); + + addPrefixedControl(parameterSlotGroup, parameterSlotItemPrefix + "_link_type", + tr("Meta Knob Mode"), + tr("Set how linked effect parameters change when turning the Meta Knob."), + parameterDescriptionPrefix, + parameterSlotMenu); + addPrefixedControl(parameterSlotGroup, parameterSlotItemPrefix + "_link_inverse", + tr("Meta Knob Mode Invert"), + tr("Invert how linked effect parameters change when turning the Meta Knob."), + parameterDescriptionPrefix, + parameterSlotMenu); - QMenu* effectSlotMenu = addSubmenu(m_effectStr.arg(iEffectSlotNumber), - effectUnitMenu); - - QString slotDescriptionPrefix = - QString("%1, %2").arg(descriptionPrefix, - m_effectStr.arg(iEffectSlotNumber)); - - addPrefixedControl(effectSlotGroup, "clear", - tr("Clear"), tr("Clear the current effect"), - slotDescriptionPrefix, - effectSlotMenu); - addPrefixedControl(effectSlotGroup, "meta", - tr("Meta Knob"), tr("Effect Meta Knob (control linked effect parameters)"), - slotDescriptionPrefix, - effectSlotMenu); - addPrefixedControl(effectSlotGroup, "enabled", - tr("Toggle"), tr("Toggle the current effect"), - slotDescriptionPrefix, - effectSlotMenu); - addPrefixedControl(effectSlotGroup, "next_effect", - tr("Next"), tr("Switch to next effect"), - slotDescriptionPrefix, - effectSlotMenu); - addPrefixedControl(effectSlotGroup, "prev_effect", - tr("Previous"), tr("Switch to the previous effect"), - slotDescriptionPrefix, - effectSlotMenu); - addPrefixedControl(effectSlotGroup, "effect_selector", - tr("Next or Previous"), - tr("Switch to either next or previous effect"), - slotDescriptionPrefix, - effectSlotMenu); - - const int numParameterSlots = ControlObject::get( - ConfigKey(effectSlotGroup, "num_parameterslots")); - for (int iParameterSlotNumber = 1; iParameterSlotNumber <= numParameterSlots; - ++iParameterSlotNumber) { - // The parameter slot group is the same as the effect slot - // group on a standard effect rack. - const QString parameterSlotGroup = - StandardEffectRack::formatEffectSlotGroupString( - iRackNumber - 1, iEffectUnitNumber - 1, - iEffectSlotNumber - 1); - const QString parameterSlotItemPrefix = EffectParameterSlot::formatItemPrefix( - iParameterSlotNumber - 1); - QMenu* parameterSlotMenu = addSubmenu( - m_parameterStr.arg(iParameterSlotNumber), - effectSlotMenu); - - QString parameterDescriptionPrefix = - QString("%1, %2").arg(slotDescriptionPrefix, - m_parameterStr.arg(iParameterSlotNumber)); - - // Likely to change soon. - addPrefixedControl(parameterSlotGroup, parameterSlotItemPrefix, - tr("Parameter Value"), - tr("Parameter Value"), - parameterDescriptionPrefix, - parameterSlotMenu, true); - - addPrefixedControl(parameterSlotGroup, parameterSlotItemPrefix + "_link_type", - tr("Meta Knob Mode"), - tr("Set how linked effect parameters change when turning the Meta Knob."), - parameterDescriptionPrefix, - parameterSlotMenu); - addPrefixedControl(parameterSlotGroup, parameterSlotItemPrefix + "_link_inverse", - tr("Meta Knob Mode Invert"), - tr("Invert how linked effect parameters change when turning the Meta Knob."), - parameterDescriptionPrefix, - parameterSlotMenu); - - } } } } diff --git a/src/effects/builtin/autopaneffect.cpp b/src/effects/builtin/autopaneffect.cpp index b1b76df88c4..6b50782123d 100644 --- a/src/effects/builtin/autopaneffect.cpp +++ b/src/effects/builtin/autopaneffect.cpp @@ -34,14 +34,12 @@ EffectManifestPointer AutoPanEffect::getManifest() { "How fast the sound goes from one side to another\n" "1/4 - 4 beats rounded to 1/2 beat if tempo is detected\n" "1/4 - 4 seconds if no tempo is detected")); - period->setControlHint(EffectManifestParameter::ControlHint::KNOB_LINEAR); + period->setValueScaler(EffectManifestParameter::ValueScaler::LINEAR); period->setSemanticHint(EffectManifestParameter::SemanticHint::UNKNOWN); period->setUnitsHint(EffectManifestParameter::UnitsHint::UNKNOWN); period->setDefaultLinkType(EffectManifestParameter::LinkType::LINKED); period->setDefaultLinkInversion(EffectManifestParameter::LinkInversion::INVERTED); - period->setMinimum(0.0); - period->setMaximum(4.0); - period->setDefault(2.0); + period->setRange(0.0, 2.0, 4.0); EffectManifestParameterPointer smoothing = pManifest->addParameter(); smoothing->setId("smoothing"); @@ -49,13 +47,12 @@ EffectManifestPointer AutoPanEffect::getManifest() { smoothing->setShortName(QObject::tr("Smooth")); smoothing->setDescription(QObject::tr( "How smoothly the signal goes from one side to the other")); - smoothing->setControlHint(EffectManifestParameter::ControlHint::KNOB_LOGARITHMIC); + smoothing->setValueScaler(EffectManifestParameter::ValueScaler::LOGARITHMIC); smoothing->setSemanticHint(EffectManifestParameter::SemanticHint::UNKNOWN); smoothing->setUnitsHint(EffectManifestParameter::UnitsHint::UNKNOWN); smoothing->setDefaultLinkType(EffectManifestParameter::LinkType::LINKED); - smoothing->setMinimum(0.25); - smoothing->setMaximum(0.50); // there are two steps per period so max is half - smoothing->setDefault(0.50); + smoothing->setRange(0.25, 0.50, 0.50); // There are two steps per period so max is half + // TODO(Ferran Pujol): when KnobComposedMaskedRing branch is merged to master, // make the scaleStartParameter for this be 1. @@ -66,33 +63,31 @@ EffectManifestPointer AutoPanEffect::getManifest() { width->setShortName(QObject::tr("Width")); width->setDescription(QObject::tr( "How far the signal goes to each side")); - width->setControlHint(EffectManifestParameter::ControlHint::KNOB_LINEAR); + width->setValueScaler(EffectManifestParameter::ValueScaler::LINEAR); width->setSemanticHint(EffectManifestParameter::SemanticHint::UNKNOWN); width->setUnitsHint(EffectManifestParameter::UnitsHint::UNKNOWN); width->setDefaultLinkType(EffectManifestParameter::LinkType::LINKED); - width->setMinimum(0.0); - width->setMaximum(1.0); // 0.02 * sampleRate => 20ms - width->setDefault(0.5); + width->setRange(0.0, 0.5, 1.0); // 0.02 * sampleRate => 20ms return pManifest; } -AutoPanEffect::AutoPanEffect(EngineEffect* pEffect) - : m_pSmoothingParameter(pEffect->getParameterById("smoothing")), - m_pPeriodParameter(pEffect->getParameterById("period")), - m_pWidthParameter(pEffect->getParameterById("width")) { +void AutoPanEffect::loadEngineEffectParameters( + const QMap& parameters) { + m_pSmoothingParameter = parameters.value("smoothing"); + m_pPeriodParameter = parameters.value("period"); + m_pWidthParameter = parameters.value("width"); } AutoPanEffect::~AutoPanEffect() { } void AutoPanEffect::processChannel( - const ChannelHandle& handle, AutoPanGroupState* pGroupState, + AutoPanGroupState* pGroupState, const CSAMPLE* pInput, CSAMPLE* pOutput, const mixxx::EngineParameters& bufferParameters, const EffectEnableState enableState, const GroupFeatureState& groupFeatures) { - Q_UNUSED(handle); if (enableState == EffectEnableState::Disabled) { return; diff --git a/src/effects/builtin/autopaneffect.h b/src/effects/builtin/autopaneffect.h index dc4141a8bee..83ccf636fe4 100644 --- a/src/effects/builtin/autopaneffect.h +++ b/src/effects/builtin/autopaneffect.h @@ -79,18 +79,21 @@ class AutoPanGroupState : public EffectState { class AutoPanEffect : public EffectProcessorImpl { public: - AutoPanEffect(EngineEffect* pEffect); + AutoPanEffect() {}; virtual ~AutoPanEffect(); static QString getId(); static EffectManifestPointer getManifest(); - void processChannel(const ChannelHandle& handle, + void loadEngineEffectParameters( + const QMap& parameters) override; + + void processChannel( AutoPanGroupState* pState, const CSAMPLE* pInput, CSAMPLE* pOutput, const mixxx::EngineParameters& bufferParameters, const EffectEnableState enableState, - const GroupFeatureState& groupFeatures); + const GroupFeatureState& groupFeatures) override; double computeLawCoefficient(double position); @@ -100,9 +103,9 @@ class AutoPanEffect : public EffectProcessorImpl { return getId(); } - EngineEffectParameter* m_pSmoothingParameter; - EngineEffectParameter* m_pPeriodParameter; - EngineEffectParameter* m_pWidthParameter; + EngineEffectParameterPointer m_pSmoothingParameter; + EngineEffectParameterPointer m_pPeriodParameter; + EngineEffectParameterPointer m_pWidthParameter; DISALLOW_COPY_AND_ASSIGN(AutoPanEffect); }; diff --git a/src/effects/builtin/balanceeffect.cpp b/src/effects/builtin/balanceeffect.cpp index 41c23fe6bcb..a6405ddd362 100644 --- a/src/effects/builtin/balanceeffect.cpp +++ b/src/effects/builtin/balanceeffect.cpp @@ -30,13 +30,11 @@ EffectManifestPointer BalanceEffect::getManifest() { balance->setShortName(QObject::tr("Balance")); balance->setDescription(QObject::tr( "Adjust balance between left and right channels")); - balance->setControlHint(EffectManifestParameter::ControlHint::KNOB_LINEAR); + balance->setValueScaler(EffectManifestParameter::ValueScaler::LINEAR); balance->setSemanticHint(EffectManifestParameter::SemanticHint::UNKNOWN); balance->setUnitsHint(EffectManifestParameter::UnitsHint::UNKNOWN); balance->setDefaultLinkType(EffectManifestParameter::LinkType::LINKED); - balance->setMinimum(-1.0); - balance->setMaximum(+1.0); - balance->setDefault(0.0); + balance->setRange(-1.0, 0.0, +1.0); EffectManifestParameterPointer midSide = pManifest->addParameter(); midSide->setId("midSide"); @@ -47,13 +45,11 @@ EffectManifestPointer BalanceEffect::getManifest() { "Fully left: mono\n" "Fully right: only side ambiance\n" "Center: does not change the original signal.")); - midSide->setControlHint(EffectManifestParameter::ControlHint::KNOB_LINEAR); + midSide->setValueScaler(EffectManifestParameter::ValueScaler::LINEAR); midSide->setSemanticHint(EffectManifestParameter::SemanticHint::UNKNOWN); midSide->setUnitsHint(EffectManifestParameter::UnitsHint::UNKNOWN); midSide->setDefaultLinkType(EffectManifestParameter::LinkType::NONE); - midSide->setMinimum(-1.0); - midSide->setMaximum(+1.0); - midSide->setDefault(0.0); + midSide->setRange(-1.0, 0.0, +1.0); EffectManifestParameterPointer midLowPass = pManifest->addParameter(); midLowPass->setId("bypassFreq"); @@ -61,14 +57,12 @@ EffectManifestPointer BalanceEffect::getManifest() { midLowPass->setShortName(QObject::tr("Bypass Fr.")); midLowPass->setDescription(QObject::tr( "Frequencies below this cutoff are not adjusted in the stereo field")); - midLowPass->setControlHint(EffectManifestParameter::ControlHint::KNOB_LOGARITHMIC); + midLowPass->setValueScaler(EffectManifestParameter::ValueScaler::LOGARITHMIC); midLowPass->setSemanticHint(EffectManifestParameter::SemanticHint::UNKNOWN); midLowPass->setUnitsHint(EffectManifestParameter::UnitsHint::UNKNOWN); midLowPass->setDefaultLinkType(EffectManifestParameter::LinkType::NONE); midLowPass->setNeutralPointOnScale(1); - midLowPass->setDefault(kMinCornerHz); - midLowPass->setMinimum(kMinCornerHz); - midLowPass->setMaximum(kMaxCornerHz); + midLowPass->setRange(kMinCornerHz, kMinCornerHz, kMaxCornerHz); return pManifest; } @@ -95,22 +89,22 @@ void BalanceGroupState::setFilters(int sampleRate, int freq) { m_high->setFrequencyCorners(sampleRate, freq); } -BalanceEffect::BalanceEffect(EngineEffect* pEffect) - : m_pBalanceParameter(pEffect->getParameterById("balance")), - m_pMidSideParameter(pEffect->getParameterById("midSide")), - m_pBypassFreqParameter(pEffect->getParameterById("bypassFreq")) { +void BalanceEffect::loadEngineEffectParameters( + const QMap& parameters) { + m_pBalanceParameter = parameters.value("balance"); + m_pMidSideParameter = parameters.value("midSide"); + m_pBypassFreqParameter = parameters.value("bypassFreq"); } BalanceEffect::~BalanceEffect() { } -void BalanceEffect::processChannel(const ChannelHandle& handle, - BalanceGroupState* pGroupState, - const CSAMPLE* pInput, CSAMPLE* pOutput, - const mixxx::EngineParameters& bufferParameters, - const EffectEnableState enableState, - const GroupFeatureState& groupFeatures) { - Q_UNUSED(handle); +void BalanceEffect::processChannel( + BalanceGroupState* pGroupState, + const CSAMPLE* pInput, CSAMPLE* pOutput, + const mixxx::EngineParameters& bufferParameters, + const EffectEnableState enableState, + const GroupFeatureState& groupFeatures) { Q_UNUSED(groupFeatures); CSAMPLE_GAIN balance = 0; diff --git a/src/effects/builtin/balanceeffect.h b/src/effects/builtin/balanceeffect.h index 8e01dc31294..553fc919b9d 100644 --- a/src/effects/builtin/balanceeffect.h +++ b/src/effects/builtin/balanceeffect.h @@ -29,18 +29,21 @@ class BalanceGroupState : public EffectState { class BalanceEffect : public EffectProcessorImpl { public: - BalanceEffect(EngineEffect* pEffect); + BalanceEffect() {}; virtual ~BalanceEffect(); static QString getId(); static EffectManifestPointer getManifest(); - void processChannel(const ChannelHandle& handle, - BalanceGroupState* pState, - const CSAMPLE* pInput, CSAMPLE* pOutput, - const mixxx::EngineParameters& bufferParameters, - const EffectEnableState enableState, - const GroupFeatureState& groupFeatures); + void loadEngineEffectParameters( + const QMap& parameters) override; + + void processChannel( + BalanceGroupState* pState, + const CSAMPLE* pInput, CSAMPLE* pOutput, + const mixxx::EngineParameters& bufferParameters, + const EffectEnableState enableState, + const GroupFeatureState& groupFeatures) override; private: @@ -48,9 +51,9 @@ class BalanceEffect : public EffectProcessorImpl { return getId(); } - EngineEffectParameter* m_pBalanceParameter; - EngineEffectParameter* m_pMidSideParameter; - EngineEffectParameter* m_pBypassFreqParameter; + EngineEffectParameterPointer m_pBalanceParameter; + EngineEffectParameterPointer m_pMidSideParameter; + EngineEffectParameterPointer m_pBypassFreqParameter; DISALLOW_COPY_AND_ASSIGN(BalanceEffect); }; diff --git a/src/effects/builtin/bessel4lvmixeqeffect.cpp b/src/effects/builtin/bessel4lvmixeqeffect.cpp index d04873ca60f..d0e7973c04f 100644 --- a/src/effects/builtin/bessel4lvmixeqeffect.cpp +++ b/src/effects/builtin/bessel4lvmixeqeffect.cpp @@ -25,29 +25,32 @@ EffectManifestPointer Bessel4LVMixEQEffect::getManifest() { return pManifest; } -Bessel4LVMixEQEffect::Bessel4LVMixEQEffect(EngineEffect* pEffect) - : m_pPotLow(pEffect->getParameterById("low")), - m_pPotMid(pEffect->getParameterById("mid")), - m_pPotHigh(pEffect->getParameterById("high")), - m_pKillLow(pEffect->getParameterById("killLow")), - m_pKillMid(pEffect->getParameterById("killMid")), - m_pKillHigh(pEffect->getParameterById("killHigh")) { +Bessel4LVMixEQEffect::Bessel4LVMixEQEffect() { m_pLoFreqCorner = new ControlProxy("[Mixer Profile]", "LoEQFrequency"); m_pHiFreqCorner = new ControlProxy("[Mixer Profile]", "HiEQFrequency"); } +void Bessel4LVMixEQEffect::loadEngineEffectParameters( + const QMap& parameters) { + m_pPotLow = parameters.value("low"); + m_pPotMid = parameters.value("mid"); + m_pPotHigh = parameters.value("high"); + m_pKillLow = parameters.value("killLow"); + m_pKillMid = parameters.value("killMid"); + m_pKillHigh = parameters.value("killHigh"); +} + Bessel4LVMixEQEffect::~Bessel4LVMixEQEffect() { delete m_pLoFreqCorner; delete m_pHiFreqCorner; } -void Bessel4LVMixEQEffect::processChannel(const ChannelHandle& handle, - Bessel4LVMixEQEffectGroupState* pState, - const CSAMPLE* pInput, CSAMPLE* pOutput, - const mixxx::EngineParameters& bufferParameters, - const EffectEnableState enableState, - const GroupFeatureState& groupFeatures) { - Q_UNUSED(handle); +void Bessel4LVMixEQEffect::processChannel( + Bessel4LVMixEQEffectGroupState* pState, + const CSAMPLE* pInput, CSAMPLE* pOutput, + const mixxx::EngineParameters& bufferParameters, + const EffectEnableState enableState, + const GroupFeatureState& groupFeatures) { Q_UNUSED(groupFeatures); if (enableState == EffectEnableState::Disabling) { diff --git a/src/effects/builtin/bessel4lvmixeqeffect.h b/src/effects/builtin/bessel4lvmixeqeffect.h index 877cbd51fb1..6cf42c1c14f 100644 --- a/src/effects/builtin/bessel4lvmixeqeffect.h +++ b/src/effects/builtin/bessel4lvmixeqeffect.h @@ -4,7 +4,6 @@ #include #include "control/controlproxy.h" -#include "effects/effect.h" #include "effects/effectprocessor.h" #include "effects/builtin/lvmixeqbase.h" #include "engine/effects/engineeffect.h" @@ -25,32 +24,34 @@ class Bessel4LVMixEQEffectGroupState : class Bessel4LVMixEQEffect : public EffectProcessorImpl { public: - Bessel4LVMixEQEffect(EngineEffect* pEffect); + Bessel4LVMixEQEffect(); virtual ~Bessel4LVMixEQEffect(); static QString getId(); static EffectManifestPointer getManifest(); - // See effectprocessor.h - void processChannel(const ChannelHandle& handle, - Bessel4LVMixEQEffectGroupState* pState, - const CSAMPLE* pInput, CSAMPLE* pOutput, - const mixxx::EngineParameters& bufferParameters, - const EffectEnableState enableState, - const GroupFeatureState& groupFeatureState); + void loadEngineEffectParameters( + const QMap& parameters) override; + + void processChannel( + Bessel4LVMixEQEffectGroupState* pState, + const CSAMPLE* pInput, CSAMPLE* pOutput, + const mixxx::EngineParameters& bufferParameters, + const EffectEnableState enableState, + const GroupFeatureState& groupFeatureState) override; private: QString debugString() const { return getId(); } - EngineEffectParameter* m_pPotLow; - EngineEffectParameter* m_pPotMid; - EngineEffectParameter* m_pPotHigh; + EngineEffectParameterPointer m_pPotLow; + EngineEffectParameterPointer m_pPotMid; + EngineEffectParameterPointer m_pPotHigh; - EngineEffectParameter* m_pKillLow; - EngineEffectParameter* m_pKillMid; - EngineEffectParameter* m_pKillHigh; + EngineEffectParameterPointer m_pKillLow; + EngineEffectParameterPointer m_pKillMid; + EngineEffectParameterPointer m_pKillHigh; ControlProxy* m_pLoFreqCorner; ControlProxy* m_pHiFreqCorner; diff --git a/src/effects/builtin/bessel8lvmixeqeffect.cpp b/src/effects/builtin/bessel8lvmixeqeffect.cpp index 898a28f798b..75ef2558398 100644 --- a/src/effects/builtin/bessel8lvmixeqeffect.cpp +++ b/src/effects/builtin/bessel8lvmixeqeffect.cpp @@ -25,29 +25,33 @@ EffectManifestPointer Bessel8LVMixEQEffect::getManifest() { return pManifest; } -Bessel8LVMixEQEffect::Bessel8LVMixEQEffect(EngineEffect* pEffect) - : m_pPotLow(pEffect->getParameterById("low")), - m_pPotMid(pEffect->getParameterById("mid")), - m_pPotHigh(pEffect->getParameterById("high")), - m_pKillLow(pEffect->getParameterById("killLow")), - m_pKillMid(pEffect->getParameterById("killMid")), - m_pKillHigh(pEffect->getParameterById("killHigh")) { +Bessel8LVMixEQEffect::Bessel8LVMixEQEffect() { m_pLoFreqCorner = new ControlProxy("[Mixer Profile]", "LoEQFrequency"); m_pHiFreqCorner = new ControlProxy("[Mixer Profile]", "HiEQFrequency"); } +void Bessel8LVMixEQEffect::loadEngineEffectParameters( + const QMap& parameters) { + m_pPotLow = parameters.value("low"); + m_pPotMid = parameters.value("mid"); + m_pPotHigh = parameters.value("high"); + m_pKillLow = parameters.value("killLow"); + m_pKillMid = parameters.value("killMid"); + m_pKillHigh = parameters.value("killHigh"); +} + + Bessel8LVMixEQEffect::~Bessel8LVMixEQEffect() { delete m_pLoFreqCorner; delete m_pHiFreqCorner; } -void Bessel8LVMixEQEffect::processChannel(const ChannelHandle& handle, - Bessel8LVMixEQEffectGroupState* pState, - const CSAMPLE* pInput, CSAMPLE* pOutput, - const mixxx::EngineParameters& bufferParameters, - const EffectEnableState enableState, - const GroupFeatureState& groupFeatures) { - Q_UNUSED(handle); +void Bessel8LVMixEQEffect::processChannel( + Bessel8LVMixEQEffectGroupState* pState, + const CSAMPLE* pInput, CSAMPLE* pOutput, + const mixxx::EngineParameters& bufferParameters, + const EffectEnableState enableState, + const GroupFeatureState& groupFeatures) { Q_UNUSED(groupFeatures); if (enableState == EffectEnableState::Disabling) { diff --git a/src/effects/builtin/bessel8lvmixeqeffect.h b/src/effects/builtin/bessel8lvmixeqeffect.h index a44dfa5a873..d9f672d46d9 100644 --- a/src/effects/builtin/bessel8lvmixeqeffect.h +++ b/src/effects/builtin/bessel8lvmixeqeffect.h @@ -6,7 +6,6 @@ #include #include "control/controlproxy.h" -#include "effects/effect.h" #include "effects/effectprocessor.h" #include "engine/effects/engineeffect.h" #include "engine/effects/engineeffectparameter.h" @@ -28,32 +27,34 @@ class Bessel8LVMixEQEffectGroupState : class Bessel8LVMixEQEffect : public EffectProcessorImpl { public: - Bessel8LVMixEQEffect(EngineEffect* pEffect); + Bessel8LVMixEQEffect(); virtual ~Bessel8LVMixEQEffect(); static QString getId(); static EffectManifestPointer getManifest(); - // See effectprocessor.h - void processChannel(const ChannelHandle& handle, - Bessel8LVMixEQEffectGroupState* pState, - const CSAMPLE* pInput, CSAMPLE* pOutput, - const mixxx::EngineParameters& bufferParameters, - const EffectEnableState enableState, - const GroupFeatureState& groupFeatureState); + void loadEngineEffectParameters( + const QMap& parameters) override; + + void processChannel( + Bessel8LVMixEQEffectGroupState* pState, + const CSAMPLE* pInput, CSAMPLE* pOutput, + const mixxx::EngineParameters& bufferParameters, + const EffectEnableState enableState, + const GroupFeatureState& groupFeatureState) override; private: QString debugString() const { return getId(); } - EngineEffectParameter* m_pPotLow; - EngineEffectParameter* m_pPotMid; - EngineEffectParameter* m_pPotHigh; + EngineEffectParameterPointer m_pPotLow; + EngineEffectParameterPointer m_pPotMid; + EngineEffectParameterPointer m_pPotHigh; - EngineEffectParameter* m_pKillLow; - EngineEffectParameter* m_pKillMid; - EngineEffectParameter* m_pKillHigh; + EngineEffectParameterPointer m_pKillLow; + EngineEffectParameterPointer m_pKillMid; + EngineEffectParameterPointer m_pKillHigh; ControlProxy* m_pLoFreqCorner; ControlProxy* m_pHiFreqCorner; diff --git a/src/effects/builtin/biquadfullkilleqeffect.cpp b/src/effects/builtin/biquadfullkilleqeffect.cpp index 6adba364a12..b1a3c9c30e1 100644 --- a/src/effects/builtin/biquadfullkilleqeffect.cpp +++ b/src/effects/builtin/biquadfullkilleqeffect.cpp @@ -135,29 +135,31 @@ void BiquadFullKillEQEffectGroupState::setFilters( m_lvMixIso->setFilters(sampleRate, lowFreqCorner, highFreqCorner); } -BiquadFullKillEQEffect::BiquadFullKillEQEffect(EngineEffect* pEffect) - : m_pPotLow(pEffect->getParameterById("low")), - m_pPotMid(pEffect->getParameterById("mid")), - m_pPotHigh(pEffect->getParameterById("high")), - m_pKillLow(pEffect->getParameterById("killLow")), - m_pKillMid(pEffect->getParameterById("killMid")), - m_pKillHigh(pEffect->getParameterById("killHigh")) { +BiquadFullKillEQEffect::BiquadFullKillEQEffect() { m_pLoFreqCorner = std::make_unique("[Mixer Profile]", "LoEQFrequency"); m_pHiFreqCorner = std::make_unique("[Mixer Profile]", "HiEQFrequency"); } +void BiquadFullKillEQEffect::loadEngineEffectParameters( + const QMap& parameters) { + m_pPotLow = parameters.value("low"); + m_pPotMid = parameters.value("mid"); + m_pPotHigh = parameters.value("high"); + m_pKillLow = parameters.value("killLow"); + m_pKillMid = parameters.value("killMid"); + m_pKillHigh = parameters.value("killHigh"); +} + // BiquadFullKillEQEffect::~BiquadFullKillEQEffect() { // } void BiquadFullKillEQEffect::processChannel( - const ChannelHandle& handle, BiquadFullKillEQEffectGroupState* pState, const CSAMPLE* pInput, CSAMPLE* pOutput, const mixxx::EngineParameters& bufferParameters, const EffectEnableState enableState, const GroupFeatureState& groupFeatures) { - Q_UNUSED(handle); Q_UNUSED(groupFeatures); if (pState->m_oldSampleRate != bufferParameters.sampleRate() || diff --git a/src/effects/builtin/biquadfullkilleqeffect.h b/src/effects/builtin/biquadfullkilleqeffect.h index b8bdde98a19..9650ece5d80 100644 --- a/src/effects/builtin/biquadfullkilleqeffect.h +++ b/src/effects/builtin/biquadfullkilleqeffect.h @@ -2,7 +2,6 @@ #define BIQUADFULLKILLEQEFFECT_H #include "control/controlproxy.h" -#include "effects/effect.h" #include "effects/effectprocessor.h" #include "engine/effects/engineeffect.h" #include "engine/effects/engineeffectparameter.h" @@ -60,19 +59,22 @@ class BiquadFullKillEQEffectGroupState : public EffectState { class BiquadFullKillEQEffect : public EffectProcessorImpl { public: - BiquadFullKillEQEffect(EngineEffect* pEffect); + BiquadFullKillEQEffect(); static QString getId(); static EffectManifestPointer getManifest(); - void setFilters(int sampleRate, double lowFreqCorner, double highFreqCorner); + void loadEngineEffectParameters( + const QMap& parameters) override; + + void processChannel( + BiquadFullKillEQEffectGroupState* pState, + const CSAMPLE* pInput, CSAMPLE *pOutput, + const mixxx::EngineParameters& bufferParameters, + const EffectEnableState enableState, + const GroupFeatureState& groupFeatureState) override; - void processChannel(const ChannelHandle& handle, - BiquadFullKillEQEffectGroupState* pState, - const CSAMPLE* pInput, CSAMPLE *pOutput, - const mixxx::EngineParameters& bufferParameters, - const EffectEnableState enableState, - const GroupFeatureState& groupFeatureState) override; + void setFilters(int sampleRate, double lowFreqCorner, double highFreqCorner); private: BiquadFullKillEQEffect(const BiquadFullKillEQEffect&) = delete; @@ -82,13 +84,13 @@ class BiquadFullKillEQEffect : public EffectProcessorImpl m_pLoFreqCorner; std::unique_ptr m_pHiFreqCorner; diff --git a/src/effects/builtin/bitcrushereffect.cpp b/src/effects/builtin/bitcrushereffect.cpp index 04dc81884fa..6fdb2d40c53 100644 --- a/src/effects/builtin/bitcrushereffect.cpp +++ b/src/effects/builtin/bitcrushereffect.cpp @@ -26,17 +26,15 @@ EffectManifestPointer BitCrusherEffect::getManifest() { depth->setShortName(QObject::tr("Bit Depth")); depth->setDescription(QObject::tr( "The bit depth of the samples")); - depth->setControlHint(EffectManifestParameter::ControlHint::KNOB_LOGARITHMIC); + depth->setValueScaler(EffectManifestParameter::ValueScaler::LOGARITHMIC); depth->setSemanticHint(EffectManifestParameter::SemanticHint::UNKNOWN); depth->setUnitsHint(EffectManifestParameter::UnitsHint::UNKNOWN); depth->setDefaultLinkType(EffectManifestParameter::LinkType::LINKED); depth->setDefaultLinkInversion(EffectManifestParameter::LinkInversion::INVERTED); depth->setNeutralPointOnScale(1.0); - depth->setDefault(16); // for values -1 0 +1 // we do not allow a 1 bit version because this causes a distortion because of the missing sign bit - depth->setMinimum(2); - depth->setMaximum(16); + depth->setRange(2, 16, 16); EffectManifestParameterPointer frequency = pManifest->addParameter(); frequency->setId("downsample"); @@ -44,35 +42,33 @@ EffectManifestPointer BitCrusherEffect::getManifest() { frequency->setShortName(QObject::tr("Down")); frequency->setDescription(QObject::tr( "The sample rate to which the signal is downsampled")); - frequency->setControlHint(EffectManifestParameter::ControlHint::KNOB_LOGARITHMIC); + frequency->setValueScaler(EffectManifestParameter::ValueScaler::LOGARITHMIC); frequency->setSemanticHint(EffectManifestParameter::SemanticHint::UNKNOWN); frequency->setUnitsHint(EffectManifestParameter::UnitsHint::SAMPLERATE); frequency->setDefaultLinkType(EffectManifestParameter::LinkType::LINKED); frequency->setDefaultLinkInversion(EffectManifestParameter::LinkInversion::INVERTED); frequency->setNeutralPointOnScale(1.0); - frequency->setDefault(1.0); - frequency->setMinimum(0.02); - frequency->setMaximum(1.0); + frequency->setRange(0.02, 1.0, 1.0); return pManifest; } -BitCrusherEffect::BitCrusherEffect(EngineEffect* pEffect) - : m_pBitDepthParameter(pEffect->getParameterById("bit_depth")), - m_pDownsampleParameter(pEffect->getParameterById("downsample")) { +void BitCrusherEffect::loadEngineEffectParameters( + const QMap& parameters) { + m_pBitDepthParameter = parameters.value("bit_depth"); + m_pDownsampleParameter = parameters.value("downsample"); } BitCrusherEffect::~BitCrusherEffect() { //qDebug() << debugString() << "destroyed"; } -void BitCrusherEffect::processChannel(const ChannelHandle& handle, - BitCrusherGroupState* pState, - const CSAMPLE* pInput, CSAMPLE* pOutput, - const mixxx::EngineParameters& bufferParameters, - const EffectEnableState enableState, - const GroupFeatureState& groupFeatures) { - Q_UNUSED(handle); +void BitCrusherEffect::processChannel( + BitCrusherGroupState* pState, + const CSAMPLE* pInput, CSAMPLE* pOutput, + const mixxx::EngineParameters& bufferParameters, + const EffectEnableState enableState, + const GroupFeatureState& groupFeatures) { Q_UNUSED(groupFeatures); Q_UNUSED(enableState); // no need to ramp, it is just a bitcrusher ;-) diff --git a/src/effects/builtin/bitcrushereffect.h b/src/effects/builtin/bitcrushereffect.h index 88d102719cc..5a744b9dc88 100644 --- a/src/effects/builtin/bitcrushereffect.h +++ b/src/effects/builtin/bitcrushereffect.h @@ -3,7 +3,6 @@ #include -#include "effects/effect.h" #include "effects/effectprocessor.h" #include "engine/effects/engineeffect.h" #include "engine/effects/engineeffectparameter.h" @@ -25,27 +24,29 @@ struct BitCrusherGroupState : public EffectState { class BitCrusherEffect : public EffectProcessorImpl { public: - BitCrusherEffect(EngineEffect* pEffect); + BitCrusherEffect() {}; virtual ~BitCrusherEffect(); static QString getId(); static EffectManifestPointer getManifest(); - // See effectprocessor.h - void processChannel(const ChannelHandle& handle, - BitCrusherGroupState* pState, - const CSAMPLE* pInput, CSAMPLE *pOutput, - const mixxx::EngineParameters& bufferParameters, - const EffectEnableState enableState, - const GroupFeatureState& groupFeatureState); + void loadEngineEffectParameters( + const QMap& parameters) override; + + void processChannel( + BitCrusherGroupState* pState, + const CSAMPLE* pInput, CSAMPLE *pOutput, + const mixxx::EngineParameters& bufferParameters, + const EffectEnableState enableState, + const GroupFeatureState& groupFeatureState) override; private: QString debugString() const { return getId(); } - EngineEffectParameter* m_pBitDepthParameter; - EngineEffectParameter* m_pDownsampleParameter; + EngineEffectParameterPointer m_pBitDepthParameter; + EngineEffectParameterPointer m_pDownsampleParameter; DISALLOW_COPY_AND_ASSIGN(BitCrusherEffect); }; diff --git a/src/effects/builtin/builtinbackend.cpp b/src/effects/builtin/builtinbackend.cpp index 9c870a0aba1..0f3c98ae4d2 100644 --- a/src/effects/builtin/builtinbackend.cpp +++ b/src/effects/builtin/builtinbackend.cpp @@ -24,8 +24,7 @@ #include "effects/builtin/metronomeeffect.h" #include "effects/builtin/tremoloeffect.h" -BuiltInBackend::BuiltInBackend(QObject* pParent) - : EffectsBackend(pParent, EffectBackendType::BuiltIn) { +BuiltInBackend::BuiltInBackend() { // Keep this list in a reasonable order // Mixing EQs registerEffect(); @@ -54,6 +53,46 @@ BuiltInBackend::BuiltInBackend(QObject* pParent) registerEffect(); } +std::unique_ptr BuiltInBackend::createProcessor( + const EffectManifestPointer pManifest) const { + VERIFY_OR_DEBUG_ASSERT(m_registeredEffects.contains(pManifest->id())) { + return std::unique_ptr(nullptr); + } + return std::unique_ptr( + m_registeredEffects[pManifest->id()].initiator()->instantiate()); +} + BuiltInBackend::~BuiltInBackend() { //qDebug() << debugString() << "destroyed"; + m_registeredEffects.clear(); + m_effectIds.clear(); +} + +void BuiltInBackend::registerEffect(const QString& id, + EffectManifestPointer pManifest, + EffectProcessorInstantiatorPointer pInstantiator) { + VERIFY_OR_DEBUG_ASSERT(!m_registeredEffects.contains(id)) { + return; + } + + pManifest->setBackendType(getType()); + + m_registeredEffects[id] = RegisteredEffect(pManifest, pInstantiator); + m_effectIds.append(id); +} + +const QList BuiltInBackend::getEffectIds() const { + return m_effectIds; +} + +EffectManifestPointer BuiltInBackend::getManifest(const QString& effectId) const { + VERIFY_OR_DEBUG_ASSERT(m_registeredEffects.contains(effectId)) { + return EffectManifestPointer(); + } + return m_registeredEffects.value(effectId).manifest(); +} + + +bool BuiltInBackend::canInstantiateEffect(const QString& effectId) const { + return m_registeredEffects.contains(effectId); } diff --git a/src/effects/builtin/builtinbackend.h b/src/effects/builtin/builtinbackend.h index b797f293040..3f2602a4b1f 100644 --- a/src/effects/builtin/builtinbackend.h +++ b/src/effects/builtin/builtinbackend.h @@ -5,15 +5,74 @@ #include "effects/effectsbackend.h" class BuiltInBackend : public EffectsBackend { - Q_OBJECT public: - BuiltInBackend(QObject* pParent); + BuiltInBackend(); virtual ~BuiltInBackend(); + EffectBackendType getType() const { return EffectBackendType::BuiltIn; }; + + const QList getEffectIds() const; + EffectManifestPointer getManifest(const QString& effectId) const; + std::unique_ptr createProcessor( + const EffectManifestPointer pManifest) const; + bool canInstantiateEffect(const QString& effectId) const; + private: QString debugString() const { return "BuiltInBackend"; } + + // EffectProcessorInstantiator and RegisteredEffect associate the QString + // IDs of effects with EffectProcessorImpl subclasses + class EffectProcessorInstantiator { + public: + virtual ~EffectProcessorInstantiator() {}; + virtual EffectProcessor* instantiate() = 0; + }; + typedef QSharedPointer EffectProcessorInstantiatorPointer; + + template + class EffectProcessorSpecificInstantiator : public EffectProcessorInstantiator { + public: + EffectProcessor* instantiate() { + return new T(); + } + }; + + class RegisteredEffect { + public: + RegisteredEffect(EffectManifestPointer pManifest, + EffectProcessorInstantiatorPointer pInitator) + : m_pManifest(pManifest), + m_pInitator(pInitator) { + } + + RegisteredEffect() { + } + + EffectManifestPointer manifest() const { return m_pManifest; }; + EffectProcessorInstantiatorPointer initiator() const { return m_pInitator; }; + + private: + EffectManifestPointer m_pManifest; + EffectProcessorInstantiatorPointer m_pInitator; + }; + + void registerEffect(const QString& id, + EffectManifestPointer pManifest, + EffectProcessorInstantiatorPointer pInstantiator); + + template + void registerEffect() { + registerEffect( + EffectProcessorImpl::getId(), + EffectProcessorImpl::getManifest(), + EffectProcessorInstantiatorPointer( + new EffectProcessorSpecificInstantiator())); + } + + QMap m_registeredEffects; + QList m_effectIds; }; #endif /* BUILTINBACKEND_H */ diff --git a/src/effects/builtin/echoeffect.cpp b/src/effects/builtin/echoeffect.cpp index 08cc36d4ace..2f9cb6776cf 100644 --- a/src/effects/builtin/echoeffect.cpp +++ b/src/effects/builtin/echoeffect.cpp @@ -49,12 +49,10 @@ EffectManifestPointer EchoEffect::getManifest() { "Delay time\n" "1/8 - 2 beats if tempo is detected\n" "1/8 - 2 seconds if no tempo is detected")); - delay->setControlHint(EffectManifestParameter::ControlHint::KNOB_LINEAR); + delay->setValueScaler(EffectManifestParameter::ValueScaler::LINEAR); delay->setSemanticHint(EffectManifestParameter::SemanticHint::UNKNOWN); delay->setUnitsHint(EffectManifestParameter::UnitsHint::BEATS); - delay->setMinimum(0.0); - delay->setDefault(0.5); - delay->setMaximum(2.0); + delay->setRange(0.0, 0.5, 2.0); EffectManifestParameterPointer feedback = pManifest->addParameter(); feedback->setId("feedback_amount"); @@ -62,12 +60,10 @@ EffectManifestPointer EchoEffect::getManifest() { feedback->setShortName(QObject::tr("Feedback")); feedback->setDescription(QObject::tr( "Amount the echo fades each time it loops")); - feedback->setControlHint(EffectManifestParameter::ControlHint::KNOB_LINEAR); + feedback->setValueScaler(EffectManifestParameter::ValueScaler::LINEAR); feedback->setSemanticHint(EffectManifestParameter::SemanticHint::UNKNOWN); feedback->setUnitsHint(EffectManifestParameter::UnitsHint::UNKNOWN); - feedback->setMinimum(0.00); - feedback->setDefault(db2ratio(-3.0)); - feedback->setMaximum(1.00); + feedback->setRange(0.00, db2ratio(-3.0), 1.00); EffectManifestParameterPointer pingpong = pManifest->addParameter(); pingpong->setId("pingpong_amount"); @@ -75,12 +71,10 @@ EffectManifestPointer EchoEffect::getManifest() { pingpong->setShortName(QObject::tr("Ping Pong")); pingpong->setDescription(QObject::tr( "How much the echoed sound bounces between the left and right sides of the stereo field")); - pingpong->setControlHint(EffectManifestParameter::ControlHint::KNOB_LINEAR); + pingpong->setValueScaler(EffectManifestParameter::ValueScaler::LINEAR); pingpong->setSemanticHint(EffectManifestParameter::SemanticHint::UNKNOWN); pingpong->setUnitsHint(EffectManifestParameter::UnitsHint::UNKNOWN); - pingpong->setMinimum(0.0); - pingpong->setDefault(0.0); - pingpong->setMaximum(1.0); + pingpong->setRange(0.0, 0.0, 1.0); EffectManifestParameterPointer send = pManifest->addParameter(); send->setId("send_amount"); @@ -88,13 +82,11 @@ EffectManifestPointer EchoEffect::getManifest() { send->setShortName(QObject::tr("Send")); send->setDescription(QObject::tr( "How much of the signal to send into the delay buffer")); - send->setControlHint(EffectManifestParameter::ControlHint::KNOB_LINEAR); + send->setValueScaler(EffectManifestParameter::ValueScaler::LINEAR); send->setSemanticHint(EffectManifestParameter::SemanticHint::UNKNOWN); send->setUnitsHint(EffectManifestParameter::UnitsHint::UNKNOWN); send->setDefaultLinkType(EffectManifestParameter::LinkType::LINKED); - send->setMinimum(0.0); - send->setDefault(db2ratio(-3.0)); - send->setMaximum(1.0); + send->setRange(0.0, db2ratio(-3.0), 1.0); EffectManifestParameterPointer quantize = pManifest->addParameter(); quantize->setId("quantize"); @@ -102,12 +94,10 @@ EffectManifestPointer EchoEffect::getManifest() { quantize->setShortName(QObject::tr("Quantize")); quantize->setDescription(QObject::tr( "Round the Time parameter to the nearest 1/4 beat.")); - quantize->setControlHint(EffectManifestParameter::ControlHint::TOGGLE_STEPPING); + quantize->setValueScaler(EffectManifestParameter::ValueScaler::TOGGLE); quantize->setSemanticHint(EffectManifestParameter::SemanticHint::UNKNOWN); quantize->setUnitsHint(EffectManifestParameter::UnitsHint::UNKNOWN); - quantize->setDefault(1); - quantize->setMinimum(0); - quantize->setMaximum(1); + quantize->setRange(0, 1, 1); EffectManifestParameterPointer triplet = pManifest->addParameter(); triplet->setId("triplet"); @@ -115,33 +105,31 @@ EffectManifestPointer EchoEffect::getManifest() { triplet->setShortName(QObject::tr("Triplets")); triplet->setDescription(QObject::tr( "When the Quantize parameter is enabled, divide rounded 1/4 beats of Time parameter by 3.")); - triplet->setControlHint(EffectManifestParameter::ControlHint::TOGGLE_STEPPING); + triplet->setValueScaler(EffectManifestParameter::ValueScaler::TOGGLE); triplet->setSemanticHint(EffectManifestParameter::SemanticHint::UNKNOWN); triplet->setUnitsHint(EffectManifestParameter::UnitsHint::UNKNOWN); - triplet->setDefault(0); - triplet->setMinimum(0); - triplet->setMaximum(1); + triplet->setRange(0, 0, 1); return pManifest; } -EchoEffect::EchoEffect(EngineEffect* pEffect) - : m_pDelayParameter(pEffect->getParameterById("delay_time")), - m_pSendParameter(pEffect->getParameterById("send_amount")), - m_pFeedbackParameter(pEffect->getParameterById("feedback_amount")), - m_pPingPongParameter(pEffect->getParameterById("pingpong_amount")), - m_pQuantizeParameter(pEffect->getParameterById("quantize")), - m_pTripletParameter(pEffect->getParameterById("triplet")) { - } - -void EchoEffect::processChannel(const ChannelHandle& handle, EchoGroupState* pGroupState, - const CSAMPLE* pInput, - CSAMPLE* pOutput, - const mixxx::EngineParameters& bufferParameters, - const EffectEnableState enableState, - const GroupFeatureState& groupFeatures) { - Q_UNUSED(handle); +void EchoEffect::loadEngineEffectParameters( + const QMap& parameters) { + m_pDelayParameter = parameters.value("delay_time"); + m_pSendParameter = parameters.value("send_amount"); + m_pFeedbackParameter = parameters.value("feedback_amount"); + m_pPingPongParameter = parameters.value("pingpong_amount"); + m_pQuantizeParameter = parameters.value("quantize"); + m_pTripletParameter = parameters.value("triplet"); +} +void EchoEffect::processChannel( + EchoGroupState* pGroupState, + const CSAMPLE* pInput, + CSAMPLE* pOutput, + const mixxx::EngineParameters& bufferParameters, + const EffectEnableState enableState, + const GroupFeatureState& groupFeatures) { EchoGroupState& gs = *pGroupState; // The minimum of the parameter is zero so the exact center of the knob is 1 beat. double period = m_pDelayParameter->value(); diff --git a/src/effects/builtin/echoeffect.h b/src/effects/builtin/echoeffect.h index c1d9266a5fe..cd3ea5d813b 100644 --- a/src/effects/builtin/echoeffect.h +++ b/src/effects/builtin/echoeffect.h @@ -48,29 +48,32 @@ class EchoGroupState : public EffectState { class EchoEffect : public EffectProcessorImpl { public: - EchoEffect(EngineEffect* pEffect); + EchoEffect() {}; static QString getId(); static EffectManifestPointer getManifest(); - void processChannel(const ChannelHandle& handle, - EchoGroupState* pState, - const CSAMPLE* pInput, CSAMPLE* pOutput, - const mixxx::EngineParameters& bufferParameters, - const EffectEnableState enableState, - const GroupFeatureState& groupFeatures); + void loadEngineEffectParameters( + const QMap& parameters) override; + + void processChannel( + EchoGroupState* pState, + const CSAMPLE* pInput, CSAMPLE* pOutput, + const mixxx::EngineParameters& bufferParameters, + const EffectEnableState enableState, + const GroupFeatureState& groupFeatures) override; private: QString debugString() const { return getId(); } - EngineEffectParameter* m_pDelayParameter; - EngineEffectParameter* m_pSendParameter; - EngineEffectParameter* m_pFeedbackParameter; - EngineEffectParameter* m_pPingPongParameter; - EngineEffectParameter* m_pQuantizeParameter; - EngineEffectParameter* m_pTripletParameter; + EngineEffectParameterPointer m_pDelayParameter; + EngineEffectParameterPointer m_pSendParameter; + EngineEffectParameterPointer m_pFeedbackParameter; + EngineEffectParameterPointer m_pPingPongParameter; + EngineEffectParameterPointer m_pQuantizeParameter; + EngineEffectParameterPointer m_pTripletParameter; DISALLOW_COPY_AND_ASSIGN(EchoEffect); }; diff --git a/src/effects/builtin/equalizer_util.h b/src/effects/builtin/equalizer_util.h index 1ab188a826f..60deda21de9 100644 --- a/src/effects/builtin/equalizer_util.h +++ b/src/effects/builtin/equalizer_util.h @@ -9,11 +9,11 @@ class EqualizerUtil { public: // Creates common EQ parameters like low/mid/high gain and kill buttons. static void createCommonParameters(EffectManifest* pManifest, bool linear) { - EffectManifestParameter::ControlHint controlHint = - EffectManifestParameter::ControlHint::KNOB_LOGARITHMIC; + EffectManifestParameter::ValueScaler valueScaler = + EffectManifestParameter::ValueScaler::LOGARITHMIC; double maximum = 4.0; if (linear) { - controlHint = EffectManifestParameter::ControlHint::KNOB_LINEAR; + valueScaler = EffectManifestParameter::ValueScaler::LINEAR; maximum = 2.0; } @@ -21,70 +21,58 @@ class EqualizerUtil { low->setId("low"); low->setName(QObject::tr("Low")); low->setDescription(QObject::tr("Gain for Low Filter")); - low->setControlHint(controlHint); + low->setValueScaler(valueScaler); low->setSemanticHint(EffectManifestParameter::SemanticHint::UNKNOWN); low->setUnitsHint(EffectManifestParameter::UnitsHint::UNKNOWN); low->setNeutralPointOnScale(0.5); - low->setDefault(1.0); - low->setMinimum(0); - low->setMaximum(maximum); + low->setRange(0, 1.0, maximum); EffectManifestParameterPointer killLow = pManifest->addParameter(); killLow->setId("killLow"); killLow->setName(QObject::tr("Kill Low")); killLow->setDescription(QObject::tr("Kill the Low Filter")); - killLow->setControlHint(EffectManifestParameter::ControlHint::TOGGLE_STEPPING); + killLow->setValueScaler(EffectManifestParameter::ValueScaler::TOGGLE); killLow->setSemanticHint(EffectManifestParameter::SemanticHint::UNKNOWN); killLow->setUnitsHint(EffectManifestParameter::UnitsHint::UNKNOWN); - killLow->setDefault(0); - killLow->setMinimum(0); - killLow->setMaximum(1); + killLow->setRange(0, 0, 1); EffectManifestParameterPointer mid = pManifest->addParameter(); mid->setId("mid"); mid->setName(QObject::tr("Mid")); mid->setDescription(QObject::tr("Gain for Mid Filter")); - mid->setControlHint(controlHint); + mid->setValueScaler(valueScaler); mid->setSemanticHint(EffectManifestParameter::SemanticHint::UNKNOWN); mid->setUnitsHint(EffectManifestParameter::UnitsHint::UNKNOWN); mid->setNeutralPointOnScale(0.5); - mid->setDefault(1.0); - mid->setMinimum(0); - mid->setMaximum(maximum); + mid->setRange(0, 1.0, maximum); EffectManifestParameterPointer killMid = pManifest->addParameter(); killMid->setId("killMid"); killMid->setName(QObject::tr("Kill Mid")); killMid->setDescription(QObject::tr("Kill the Mid Filter")); - killMid->setControlHint(EffectManifestParameter::ControlHint::TOGGLE_STEPPING); + killMid->setValueScaler(EffectManifestParameter::ValueScaler::TOGGLE); killMid->setSemanticHint(EffectManifestParameter::SemanticHint::UNKNOWN); killMid->setUnitsHint(EffectManifestParameter::UnitsHint::UNKNOWN); - killMid->setDefault(0); - killMid->setMinimum(0); - killMid->setMaximum(1); + killMid->setRange(0, 0, 1); EffectManifestParameterPointer high = pManifest->addParameter(); high->setId("high"); high->setName(QObject::tr("High")); high->setDescription(QObject::tr("Gain for High Filter")); - high->setControlHint(controlHint); + high->setValueScaler(valueScaler); high->setSemanticHint(EffectManifestParameter::SemanticHint::UNKNOWN); high->setUnitsHint(EffectManifestParameter::UnitsHint::UNKNOWN); high->setNeutralPointOnScale(0.5); - high->setDefault(1.0); - high->setMinimum(0); - high->setMaximum(maximum); + high->setRange(0, 1.0, maximum); EffectManifestParameterPointer killHigh = pManifest->addParameter(); killHigh->setId("killHigh"); killHigh->setName(QObject::tr("Kill High")); killHigh->setDescription(QObject::tr("Kill the High Filter")); - killHigh->setControlHint(EffectManifestParameter::ControlHint::TOGGLE_STEPPING); + killHigh->setValueScaler(EffectManifestParameter::ValueScaler::TOGGLE); killHigh->setSemanticHint(EffectManifestParameter::SemanticHint::UNKNOWN); killHigh->setUnitsHint(EffectManifestParameter::UnitsHint::UNKNOWN); - killHigh->setDefault(0); - killHigh->setMinimum(0); - killHigh->setMaximum(1); + killHigh->setRange(0, 0, 1); } static QString adjustFrequencyShelvesTip() { diff --git a/src/effects/builtin/filtereffect.cpp b/src/effects/builtin/filtereffect.cpp index aece10b9a06..75ae701a0c7 100644 --- a/src/effects/builtin/filtereffect.cpp +++ b/src/effects/builtin/filtereffect.cpp @@ -29,14 +29,12 @@ EffectManifestPointer FilterEffect::getManifest() { lpf->setShortName(QObject::tr("LPF")); lpf->setDescription(QObject::tr( "Corner frequency ratio of the low pass filter")); - lpf->setControlHint(EffectManifestParameter::ControlHint::KNOB_LOGARITHMIC); + lpf->setValueScaler(EffectManifestParameter::ValueScaler::LOGARITHMIC); lpf->setSemanticHint(EffectManifestParameter::SemanticHint::UNKNOWN); lpf->setUnitsHint(EffectManifestParameter::UnitsHint::HERTZ); lpf->setDefaultLinkType(EffectManifestParameter::LinkType::LINKED_LEFT); lpf->setNeutralPointOnScale(1); - lpf->setDefault(kMaxCorner); - lpf->setMinimum(kMinCorner); - lpf->setMaximum(kMaxCorner); + lpf->setRange(kMinCorner, kMaxCorner, kMaxCorner); EffectManifestParameterPointer q = pManifest->addParameter(); q->setId("q"); @@ -45,12 +43,10 @@ EffectManifestPointer FilterEffect::getManifest() { q->setDescription(QObject::tr( "Resonance of the filters\n" "Default: flat top")); // What does this mean? - q->setControlHint(EffectManifestParameter::ControlHint::KNOB_LOGARITHMIC); + q->setValueScaler(EffectManifestParameter::ValueScaler::LOGARITHMIC); q->setSemanticHint(EffectManifestParameter::SemanticHint::UNKNOWN); q->setUnitsHint(EffectManifestParameter::UnitsHint::SAMPLERATE); - q->setDefault(0.707106781); // 0.707106781 = Butterworth - q->setMinimum(0.4); - q->setMaximum(4.0); + q->setRange(0.4, 0.707106781, 4.0); // 0.707106781 = Butterworth EffectManifestParameterPointer hpf = pManifest->addParameter(); hpf->setId("hpf"); @@ -58,14 +54,12 @@ EffectManifestPointer FilterEffect::getManifest() { hpf->setShortName(QObject::tr("HPF")); hpf->setDescription(QObject::tr( "Corner frequency ratio of the high pass filter")); - hpf->setControlHint(EffectManifestParameter::ControlHint::KNOB_LOGARITHMIC); + hpf->setValueScaler(EffectManifestParameter::ValueScaler::LOGARITHMIC); hpf->setSemanticHint(EffectManifestParameter::SemanticHint::UNKNOWN); hpf->setUnitsHint(EffectManifestParameter::UnitsHint::HERTZ); hpf->setDefaultLinkType(EffectManifestParameter::LinkType::LINKED_RIGHT); hpf->setNeutralPointOnScale(0.0); - hpf->setDefault(kMinCorner); - hpf->setMinimum(kMinCorner); - hpf->setMaximum(kMaxCorner); + hpf->setRange(kMinCorner, kMinCorner, kMaxCorner); return pManifest; } @@ -85,23 +79,23 @@ FilterGroupState::~FilterGroupState() { delete m_pHighFilter; } -FilterEffect::FilterEffect(EngineEffect* pEffect) - : m_pLPF(pEffect->getParameterById("lpf")), - m_pQ(pEffect->getParameterById("q")), - m_pHPF(pEffect->getParameterById("hpf")) { +void FilterEffect::loadEngineEffectParameters( + const QMap& parameters) { + m_pLPF = parameters.value("lpf"); + m_pQ = parameters.value("q"); + m_pHPF = parameters.value("hpf"); } FilterEffect::~FilterEffect() { //qDebug() << debugString() << "destroyed"; } -void FilterEffect::processChannel(const ChannelHandle& handle, - FilterGroupState* pState, - const CSAMPLE* pInput, CSAMPLE* pOutput, - const mixxx::EngineParameters& bufferParameters, - const EffectEnableState enableState, - const GroupFeatureState& groupFeatures) { - Q_UNUSED(handle); +void FilterEffect::processChannel( + FilterGroupState* pState, + const CSAMPLE* pInput, CSAMPLE* pOutput, + const mixxx::EngineParameters& bufferParameters, + const EffectEnableState enableState, + const GroupFeatureState& groupFeatures) { Q_UNUSED(groupFeatures); double hpf; diff --git a/src/effects/builtin/filtereffect.h b/src/effects/builtin/filtereffect.h index b37eaa5cb7b..383dd1a5424 100644 --- a/src/effects/builtin/filtereffect.h +++ b/src/effects/builtin/filtereffect.h @@ -1,7 +1,6 @@ #ifndef FILTEREFFECT_H #define FILTEREFFECT_H -#include "effects/effect.h" #include "effects/effectprocessor.h" #include "engine/effects/engineeffect.h" #include "engine/effects/engineeffectparameter.h" @@ -30,27 +29,30 @@ struct FilterGroupState : public EffectState { class FilterEffect : public EffectProcessorImpl { public: - FilterEffect(EngineEffect* pEffect); + FilterEffect() {}; virtual ~FilterEffect(); static QString getId(); static EffectManifestPointer getManifest(); - void processChannel(const ChannelHandle& handle, - FilterGroupState* pState, - const CSAMPLE* pInput, CSAMPLE *pOutput, - const mixxx::EngineParameters& bufferParameters, - const EffectEnableState enableState, - const GroupFeatureState& groupFeatures); + void loadEngineEffectParameters( + const QMap& parameters) override; + + void processChannel( + FilterGroupState* pState, + const CSAMPLE* pInput, CSAMPLE *pOutput, + const mixxx::EngineParameters& bufferParameters, + const EffectEnableState enableState, + const GroupFeatureState& groupFeatures) override; private: QString debugString() const { return getId(); } - EngineEffectParameter* m_pLPF; - EngineEffectParameter* m_pQ; - EngineEffectParameter* m_pHPF; + EngineEffectParameterPointer m_pLPF; + EngineEffectParameterPointer m_pQ; + EngineEffectParameterPointer m_pHPF; DISALLOW_COPY_AND_ASSIGN(FilterEffect); }; diff --git a/src/effects/builtin/flangereffect.cpp b/src/effects/builtin/flangereffect.cpp index a4e39d709dd..ae49811c93d 100644 --- a/src/effects/builtin/flangereffect.cpp +++ b/src/effects/builtin/flangereffect.cpp @@ -40,11 +40,9 @@ EffectManifestPointer FlangerEffect::getManifest() { "Speed of the LFO (low frequency oscillator)\n" "32 - 1/4 beats rounded to 1/2 beat per LFO cycle if tempo is detected\n" "1/32 - 4 Hz if no tempo is detected")); - speed->setControlHint(EffectManifestParameter::ControlHint::KNOB_LOGARITHMIC_INVERSE); + speed->setValueScaler(EffectManifestParameter::ValueScaler::LOGARITHMIC_INVERSE); speed->setSemanticHint(EffectManifestParameter::SemanticHint::UNKNOWN); - speed->setMinimum(kMinLfoBeats); - speed->setMaximum(kMaxLfoBeats); - speed->setDefault(8); + speed->setRange(kMinLfoBeats, 8, kMaxLfoBeats); EffectManifestParameterPointer width = pManifest->addParameter(); width->setId("width"); @@ -52,12 +50,10 @@ EffectManifestPointer FlangerEffect::getManifest() { width->setShortName(QObject::tr("Width")); width->setDescription(QObject::tr( "Delay amplitude of the LFO (low frequency oscillator)")); - width->setControlHint(EffectManifestParameter::ControlHint::KNOB_LOGARITHMIC); + width->setValueScaler(EffectManifestParameter::ValueScaler::LOGARITHMIC); width->setSemanticHint(EffectManifestParameter::SemanticHint::UNKNOWN); width->setUnitsHint(EffectManifestParameter::UnitsHint::UNKNOWN); - width->setDefault(kMaxLfoWidthMs / 2); - width->setMinimum(0.0); - width->setMaximum(kMaxLfoWidthMs); + width->setRange(0.0, kMaxLfoWidthMs / 2, kMaxLfoWidthMs); EffectManifestParameterPointer manual = pManifest->addParameter(); manual->setId("manual"); @@ -66,12 +62,10 @@ EffectManifestPointer FlangerEffect::getManifest() { manual->setDescription(QObject::tr( "Delay offset of the LFO (low frequency oscillator).\n" "With width at zero, this allows for manually sweeping over the entire delay range.")); - manual->setControlHint(EffectManifestParameter::ControlHint::KNOB_LOGARITHMIC); + manual->setValueScaler(EffectManifestParameter::ValueScaler::LOGARITHMIC); manual->setSemanticHint(EffectManifestParameter::SemanticHint::UNKNOWN); manual->setUnitsHint(EffectManifestParameter::UnitsHint::UNKNOWN); - manual->setDefault(kCenterDelayMs); - manual->setMinimum(kMinDelayMs); - manual->setMaximum(kMaxDelayMs); + manual->setRange(kMinDelayMs, kCenterDelayMs, kMaxDelayMs); EffectManifestParameterPointer regen = pManifest->addParameter(); regen->setId("regen"); @@ -79,12 +73,10 @@ EffectManifestPointer FlangerEffect::getManifest() { regen->setShortName(QObject::tr("Regen")); regen->setDescription(QObject::tr( "How much of the delay output is feed back into the input")); - regen->setControlHint(EffectManifestParameter::ControlHint::KNOB_LINEAR); + regen->setValueScaler(EffectManifestParameter::ValueScaler::LINEAR); regen->setSemanticHint(EffectManifestParameter::SemanticHint::UNKNOWN); regen->setUnitsHint(EffectManifestParameter::UnitsHint::UNKNOWN); - regen->setDefault(0.25); - regen->setMinimum(0.0); - regen->setMaximum(1.0); + regen->setRange(0.0, 0.25, 1.0); EffectManifestParameterPointer mix = pManifest->addParameter(); mix->setId("mix"); @@ -92,13 +84,11 @@ EffectManifestPointer FlangerEffect::getManifest() { mix->setShortName(QObject::tr("Mix")); mix->setDescription(QObject::tr( "Intensity of the effect")); - mix->setControlHint(EffectManifestParameter::ControlHint::KNOB_LINEAR); + mix->setValueScaler(EffectManifestParameter::ValueScaler::LINEAR); mix->setSemanticHint(EffectManifestParameter::SemanticHint::UNKNOWN); mix->setUnitsHint(EffectManifestParameter::UnitsHint::UNKNOWN); mix->setDefaultLinkType(EffectManifestParameter::LinkType::LINKED); - mix->setDefault(1.0); - mix->setMinimum(0.0); - mix->setMaximum(1.0); + mix->setRange(0.0, 1.0, 1.0); EffectManifestParameterPointer triplet = pManifest->addParameter(); triplet->setId("triplet"); @@ -106,36 +96,34 @@ EffectManifestPointer FlangerEffect::getManifest() { triplet->setShortName(QObject::tr("Triplets")); triplet->setDescription(QObject::tr( "Divide rounded 1/2 beats of the Period parameter by 3.")); - triplet->setControlHint(EffectManifestParameter::ControlHint::TOGGLE_STEPPING); + triplet->setValueScaler(EffectManifestParameter::ValueScaler::TOGGLE); triplet->setSemanticHint(EffectManifestParameter::SemanticHint::UNKNOWN); triplet->setUnitsHint(EffectManifestParameter::UnitsHint::UNKNOWN); - triplet->setDefault(0); - triplet->setMinimum(0); - triplet->setMaximum(1); + triplet->setRange(0, 0, 1); return pManifest; } -FlangerEffect::FlangerEffect(EngineEffect* pEffect) - : m_pSpeedParameter(pEffect->getParameterById("speed")), - m_pWidthParameter(pEffect->getParameterById("width")), - m_pManualParameter(pEffect->getParameterById("manual")), - m_pRegenParameter(pEffect->getParameterById("regen")), - m_pMixParameter(pEffect->getParameterById("mix")), - m_pTripletParameter(pEffect->getParameterById("triplet")) { +void FlangerEffect::loadEngineEffectParameters( + const QMap& parameters) { + m_pSpeedParameter = parameters.value("speed"); + m_pWidthParameter = parameters.value("width"); + m_pManualParameter = parameters.value("manual"); + m_pRegenParameter = parameters.value("regen"); + m_pMixParameter = parameters.value("mix"); + m_pTripletParameter = parameters.value("triplet"); } FlangerEffect::~FlangerEffect() { //qDebug() << debugString() << "destroyed"; } -void FlangerEffect::processChannel(const ChannelHandle& handle, - FlangerGroupState* pState, - const CSAMPLE* pInput, CSAMPLE* pOutput, - const mixxx::EngineParameters& bufferParameters, - const EffectEnableState enableState, - const GroupFeatureState& groupFeatures) { - Q_UNUSED(handle); +void FlangerEffect::processChannel( + FlangerGroupState* pState, + const CSAMPLE* pInput, CSAMPLE* pOutput, + const mixxx::EngineParameters& bufferParameters, + const EffectEnableState enableState, + const GroupFeatureState& groupFeatures) { double lfoPeriodParameter = m_pSpeedParameter->value(); double lfoPeriodFrames; diff --git a/src/effects/builtin/flangereffect.h b/src/effects/builtin/flangereffect.h index f87b2b30ef3..28d65f38b46 100644 --- a/src/effects/builtin/flangereffect.h +++ b/src/effects/builtin/flangereffect.h @@ -49,31 +49,33 @@ struct FlangerGroupState : public EffectState { class FlangerEffect : public EffectProcessorImpl { public: - FlangerEffect(EngineEffect* pEffect); + FlangerEffect() {}; virtual ~FlangerEffect(); static QString getId(); static EffectManifestPointer getManifest(); - // See effectprocessor.h - void processChannel(const ChannelHandle& handle, - FlangerGroupState* pState, - const CSAMPLE* pInput, CSAMPLE* pOutput, - const mixxx::EngineParameters& bufferParameters, - const EffectEnableState enableState, - const GroupFeatureState& groupFeatures); + void loadEngineEffectParameters( + const QMap& parameters) override; + + void processChannel( + FlangerGroupState* pState, + const CSAMPLE* pInput, CSAMPLE* pOutput, + const mixxx::EngineParameters& bufferParameters, + const EffectEnableState enableState, + const GroupFeatureState& groupFeatures) override; private: QString debugString() const { return getId(); } - EngineEffectParameter* m_pSpeedParameter; - EngineEffectParameter* m_pWidthParameter; - EngineEffectParameter* m_pManualParameter; - EngineEffectParameter* m_pRegenParameter; - EngineEffectParameter* m_pMixParameter; - EngineEffectParameter* m_pTripletParameter; + EngineEffectParameterPointer m_pSpeedParameter; + EngineEffectParameterPointer m_pWidthParameter; + EngineEffectParameterPointer m_pManualParameter; + EngineEffectParameterPointer m_pRegenParameter; + EngineEffectParameterPointer m_pMixParameter; + EngineEffectParameterPointer m_pTripletParameter; DISALLOW_COPY_AND_ASSIGN(FlangerEffect); }; diff --git a/src/effects/builtin/graphiceqeffect.cpp b/src/effects/builtin/graphiceqeffect.cpp index d73ea07c71f..38881e37f42 100644 --- a/src/effects/builtin/graphiceqeffect.cpp +++ b/src/effects/builtin/graphiceqeffect.cpp @@ -31,13 +31,11 @@ EffectManifestPointer GraphicEQEffect::getManifest() { low->setShortName(QString("%1 Hz").arg(centerFrequencies[0])); low->setDescription(QObject::tr( "Gain for Low Filter")); - low->setControlHint(EffectManifestParameter::ControlHint::KNOB_LINEAR); + low->setValueScaler(EffectManifestParameter::ValueScaler::LINEAR); low->setSemanticHint(EffectManifestParameter::SemanticHint::UNKNOWN); low->setUnitsHint(EffectManifestParameter::UnitsHint::UNKNOWN); low->setNeutralPointOnScale(0.5); - low->setDefault(0); - low->setMinimum(-12); - low->setMaximum(12); + low->setRange(-12, 0, 12); QString paramName; for (int i = 0; i < 6; i++) { @@ -53,13 +51,11 @@ EffectManifestPointer GraphicEQEffect::getManifest() { mid->setShortName(paramName); mid->setDescription(QObject::tr( "Gain for Band Filter %1").arg(i + 1)); - mid->setControlHint(EffectManifestParameter::ControlHint::KNOB_LINEAR); + mid->setValueScaler(EffectManifestParameter::ValueScaler::LINEAR); mid->setSemanticHint(EffectManifestParameter::SemanticHint::UNKNOWN); mid->setUnitsHint(EffectManifestParameter::UnitsHint::UNKNOWN); mid->setNeutralPointOnScale(0.5); - mid->setDefault(0); - mid->setMinimum(-12); - mid->setMaximum(12); + mid->setRange(-12, 0, 12); } EffectManifestParameterPointer high = pManifest->addParameter(); @@ -67,12 +63,10 @@ EffectManifestPointer GraphicEQEffect::getManifest() { high->setName(QString("%1 kHz").arg(centerFrequencies[7] / 1000)); high->setDescription(QObject::tr( "Gain for High Filter")); - high->setControlHint(EffectManifestParameter::ControlHint::KNOB_LINEAR); + high->setValueScaler(EffectManifestParameter::ValueScaler::LINEAR); high->setSemanticHint(EffectManifestParameter::SemanticHint::UNKNOWN); high->setUnitsHint(EffectManifestParameter::UnitsHint::UNKNOWN); - high->setDefault(0); - high->setMinimum(-12); - high->setMaximum(12); + high->setRange(-12, 0, 12); return pManifest; } @@ -133,25 +127,24 @@ void GraphicEQEffectGroupState::setFilters(int sampleRate) { } } -GraphicEQEffect::GraphicEQEffect(EngineEffect* pEffect) - : m_oldSampleRate(44100) { - m_pPotLow = pEffect->getParameterById("low"); +void GraphicEQEffect::loadEngineEffectParameters( + const QMap& parameters) { + m_pPotLow = parameters.value("low"); for (int i = 0; i < 6; i++) { - m_pPotMid.append(pEffect->getParameterById(QString("mid%1").arg(i))); + m_pPotMid.append(parameters.value(QString("mid%1").arg(i))); } - m_pPotHigh = pEffect->getParameterById("high"); + m_pPotHigh = parameters.value("high"); } GraphicEQEffect::~GraphicEQEffect() { } -void GraphicEQEffect::processChannel(const ChannelHandle& handle, - GraphicEQEffectGroupState* pState, - const CSAMPLE* pInput, CSAMPLE* pOutput, - const mixxx::EngineParameters& bufferParameters, - const EffectEnableState enableState, - const GroupFeatureState& groupFeatures) { - Q_UNUSED(handle); +void GraphicEQEffect::processChannel( + GraphicEQEffectGroupState* pState, + const CSAMPLE* pInput, CSAMPLE* pOutput, + const mixxx::EngineParameters& bufferParameters, + const EffectEnableState enableState, + const GroupFeatureState& groupFeatures) { Q_UNUSED(groupFeatures); // If the sample rate has changed, initialize the filters using the new diff --git a/src/effects/builtin/graphiceqeffect.h b/src/effects/builtin/graphiceqeffect.h index 29905cc040e..1a8877404f3 100644 --- a/src/effects/builtin/graphiceqeffect.h +++ b/src/effects/builtin/graphiceqeffect.h @@ -4,7 +4,6 @@ #include #include "control/controlproxy.h" -#include "effects/effect.h" #include "effects/effectprocessor.h" #include "engine/effects/engineeffect.h" #include "engine/effects/engineeffectparameter.h" @@ -33,27 +32,30 @@ class GraphicEQEffectGroupState : public EffectState { class GraphicEQEffect : public EffectProcessorImpl { public: - GraphicEQEffect(EngineEffect* pEffect); + GraphicEQEffect() {}; virtual ~GraphicEQEffect(); static QString getId(); static EffectManifestPointer getManifest(); - void processChannel(const ChannelHandle& handle, - GraphicEQEffectGroupState* pState, - const CSAMPLE* pInput, CSAMPLE *pOutput, - const mixxx::EngineParameters& bufferParameters, - const EffectEnableState enableState, - const GroupFeatureState& groupFeatureState); + void loadEngineEffectParameters( + const QMap& parameters) override; + + void processChannel( + GraphicEQEffectGroupState* pState, + const CSAMPLE* pInput, CSAMPLE *pOutput, + const mixxx::EngineParameters& bufferParameters, + const EffectEnableState enableState, + const GroupFeatureState& groupFeatureState) override; private: QString debugString() const { return getId(); } - EngineEffectParameter* m_pPotLow; - QList m_pPotMid; - EngineEffectParameter* m_pPotHigh; + EngineEffectParameterPointer m_pPotLow; + QList m_pPotMid; + EngineEffectParameterPointer m_pPotHigh; unsigned int m_oldSampleRate; DISALLOW_COPY_AND_ASSIGN(GraphicEQEffect); diff --git a/src/effects/builtin/linkwitzriley8eqeffect.cpp b/src/effects/builtin/linkwitzriley8eqeffect.cpp index 297f3147257..3f7da027890 100644 --- a/src/effects/builtin/linkwitzriley8eqeffect.cpp +++ b/src/effects/builtin/linkwitzriley8eqeffect.cpp @@ -66,29 +66,33 @@ void LinkwitzRiley8EQEffectGroupState::setFilters(int sampleRate, int lowFreq, m_high2->setFrequencyCorners(sampleRate, highFreq); } -LinkwitzRiley8EQEffect::LinkwitzRiley8EQEffect(EngineEffect* pEffect) - : m_pPotLow(pEffect->getParameterById("low")), - m_pPotMid(pEffect->getParameterById("mid")), - m_pPotHigh(pEffect->getParameterById("high")), - m_pKillLow(pEffect->getParameterById("killLow")), - m_pKillMid(pEffect->getParameterById("killMid")), - m_pKillHigh(pEffect->getParameterById("killHigh")) { +LinkwitzRiley8EQEffect::LinkwitzRiley8EQEffect() { m_pLoFreqCorner = new ControlProxy("[Mixer Profile]", "LoEQFrequency"); m_pHiFreqCorner = new ControlProxy("[Mixer Profile]", "HiEQFrequency"); } + +void LinkwitzRiley8EQEffect::loadEngineEffectParameters( + const QMap& parameters) { + m_pPotLow = parameters.value("low"); + m_pPotMid = parameters.value("mid"); + m_pPotHigh = parameters.value("high"); + m_pKillLow = parameters.value("killLow"); + m_pKillMid = parameters.value("killMid"); + m_pKillHigh = parameters.value("killHigh"); +} + LinkwitzRiley8EQEffect::~LinkwitzRiley8EQEffect() { delete m_pLoFreqCorner; delete m_pHiFreqCorner; } -void LinkwitzRiley8EQEffect::processChannel(const ChannelHandle& handle, - LinkwitzRiley8EQEffectGroupState* pState, - const CSAMPLE* pInput, CSAMPLE* pOutput, - const mixxx::EngineParameters& bufferParameters, - const EffectEnableState enableState, - const GroupFeatureState& groupFeatures) { - Q_UNUSED(handle); +void LinkwitzRiley8EQEffect::processChannel( + LinkwitzRiley8EQEffectGroupState* pState, + const CSAMPLE* pInput, CSAMPLE* pOutput, + const mixxx::EngineParameters& bufferParameters, + const EffectEnableState enableState, + const GroupFeatureState& groupFeatures) { Q_UNUSED(groupFeatures); float fLow = 0.f, fMid = 0.f, fHigh = 0.f; diff --git a/src/effects/builtin/linkwitzriley8eqeffect.h b/src/effects/builtin/linkwitzriley8eqeffect.h index a545edc1ad6..e1561510c41 100644 --- a/src/effects/builtin/linkwitzriley8eqeffect.h +++ b/src/effects/builtin/linkwitzriley8eqeffect.h @@ -4,7 +4,6 @@ #include #include "control/controlproxy.h" -#include "effects/effect.h" #include "effects/effectprocessor.h" #include "engine/effects/engineeffect.h" #include "engine/effects/engineeffectparameter.h" @@ -41,32 +40,34 @@ class LinkwitzRiley8EQEffectGroupState : public EffectState { class LinkwitzRiley8EQEffect : public EffectProcessorImpl { public: - LinkwitzRiley8EQEffect(EngineEffect* pEffect); + LinkwitzRiley8EQEffect(); virtual ~LinkwitzRiley8EQEffect(); static QString getId(); static EffectManifestPointer getManifest(); - // See effectprocessor.h - void processChannel(const ChannelHandle& handle, - LinkwitzRiley8EQEffectGroupState* pState, - const CSAMPLE* pInput, CSAMPLE *pOutput, - const mixxx::EngineParameters& bufferParameters, - const EffectEnableState enableState, - const GroupFeatureState& groupFeatureState); + void loadEngineEffectParameters( + const QMap& parameters) override; + + void processChannel( + LinkwitzRiley8EQEffectGroupState* pState, + const CSAMPLE* pInput, CSAMPLE *pOutput, + const mixxx::EngineParameters& bufferParameters, + const EffectEnableState enableState, + const GroupFeatureState& groupFeatureState) override; private: QString debugString() const { return getId(); } - EngineEffectParameter* m_pPotLow; - EngineEffectParameter* m_pPotMid; - EngineEffectParameter* m_pPotHigh; + EngineEffectParameterPointer m_pPotLow; + EngineEffectParameterPointer m_pPotMid; + EngineEffectParameterPointer m_pPotHigh; - EngineEffectParameter* m_pKillLow; - EngineEffectParameter* m_pKillMid; - EngineEffectParameter* m_pKillHigh; + EngineEffectParameterPointer m_pKillLow; + EngineEffectParameterPointer m_pKillMid; + EngineEffectParameterPointer m_pKillHigh; ControlProxy* m_pLoFreqCorner; ControlProxy* m_pHiFreqCorner; diff --git a/src/effects/builtin/loudnesscontoureffect.cpp b/src/effects/builtin/loudnesscontoureffect.cpp index fd1781f73ba..732f85fbc26 100644 --- a/src/effects/builtin/loudnesscontoureffect.cpp +++ b/src/effects/builtin/loudnesscontoureffect.cpp @@ -38,14 +38,12 @@ EffectManifestPointer LoudnessContourEffect::getManifest() { loudness->setShortName(QObject::tr("Loudness")); loudness->setDescription(QObject::tr( "Set the gain of the applied loudness contour")); - loudness->setControlHint(EffectManifestParameter::ControlHint::KNOB_LINEAR); + loudness->setValueScaler(EffectManifestParameter::ValueScaler::LINEAR); loudness->setSemanticHint(EffectManifestParameter::SemanticHint::UNKNOWN); loudness->setUnitsHint(EffectManifestParameter::UnitsHint::UNKNOWN); loudness->setDefaultLinkType(EffectManifestParameter::LinkType::LINKED); loudness->setNeutralPointOnScale(1); - loudness->setDefault(-kMaxLoGain / 2); - loudness->setMinimum(-kMaxLoGain); - loudness->setMaximum(0); + loudness->setRange(-kMaxLoGain, -kMaxLoGain / 2, 0); EffectManifestParameterPointer useGain = pManifest->addParameter(); useGain->setId("useGain"); @@ -53,12 +51,10 @@ EffectManifestPointer LoudnessContourEffect::getManifest() { useGain->setShortName(QObject::tr("Use Gain")); useGain->setDescription(QObject::tr( "Follow Gain Knob")); - useGain->setControlHint(EffectManifestParameter::ControlHint::TOGGLE_STEPPING); + useGain->setValueScaler(EffectManifestParameter::ValueScaler::TOGGLE); useGain->setSemanticHint(EffectManifestParameter::SemanticHint::UNKNOWN); useGain->setUnitsHint(EffectManifestParameter::UnitsHint::UNKNOWN); - useGain->setDefault(0); - useGain->setMinimum(0); - useGain->setMaximum(1); + useGain->setRange(0, 0, 1); return pManifest; } @@ -94,24 +90,22 @@ void LoudnessContourEffectGroupState::setFilters(int sampleRate, double gain) { } -LoudnessContourEffect::LoudnessContourEffect( - EngineEffect* pEffect) - : m_pLoudness(pEffect->getParameterById("loudness")), - m_pUseGain(pEffect->getParameterById("useGain")) { +void LoudnessContourEffect::loadEngineEffectParameters( + const QMap& parameters) { + m_pLoudness = parameters.value("loudness"); + m_pUseGain = parameters.value("useGain"); } LoudnessContourEffect::~LoudnessContourEffect() { } void LoudnessContourEffect::processChannel( - const ChannelHandle& handle, LoudnessContourEffectGroupState* pState, const CSAMPLE* pInput, CSAMPLE* pOutput, const mixxx::EngineParameters& bufferParameters, const EffectEnableState enableState, const GroupFeatureState& groupFeatures) { - Q_UNUSED(handle); Q_UNUSED(groupFeatures); double filterGainDb = pState->m_oldFilterGainDb; diff --git a/src/effects/builtin/loudnesscontoureffect.h b/src/effects/builtin/loudnesscontoureffect.h index b133a5b9831..fbc440aec73 100644 --- a/src/effects/builtin/loudnesscontoureffect.h +++ b/src/effects/builtin/loudnesscontoureffect.h @@ -2,7 +2,6 @@ #define LOUDNESSCONTOUREFFECT_H #include "control/controlproxy.h" -#include "effects/effect.h" #include "effects/effectprocessor.h" #include "engine/effects/engineeffect.h" #include "engine/effects/engineeffectparameter.h" @@ -34,20 +33,23 @@ class LoudnessContourEffectGroupState final : public EffectState { class LoudnessContourEffect : public EffectProcessorImpl { public: - LoudnessContourEffect(EngineEffect* pEffect); + LoudnessContourEffect() {}; ~LoudnessContourEffect() override; static QString getId(); static EffectManifestPointer getManifest(); - void setFilters(int sampleRate); + void loadEngineEffectParameters( + const QMap& parameters) override; + + void processChannel( + LoudnessContourEffectGroupState* pState, + const CSAMPLE* pInput, CSAMPLE *pOutput, + const mixxx::EngineParameters& bufferParameters, + const EffectEnableState enableState, + const GroupFeatureState& groupFeatureState) override; - void processChannel(const ChannelHandle& handle, - LoudnessContourEffectGroupState* pState, - const CSAMPLE* pInput, CSAMPLE *pOutput, - const mixxx::EngineParameters& bufferParameters, - const EffectEnableState enableState, - const GroupFeatureState& groupFeatureState); + void setFilters(int sampleRate); private: LoudnessContourEffect(const LoudnessContourEffect&) = delete; @@ -57,8 +59,8 @@ class LoudnessContourEffect return getId(); } - EngineEffectParameter* m_pLoudness; - EngineEffectParameter* m_pUseGain; + EngineEffectParameterPointer m_pLoudness; + EngineEffectParameterPointer m_pUseGain; }; #endif // LOUDNESSCONTOUREFFECT_H diff --git a/src/effects/builtin/metronomeeffect.cpp b/src/effects/builtin/metronomeeffect.cpp index 9bcc956b8c9..6156470ce34 100644 --- a/src/effects/builtin/metronomeeffect.cpp +++ b/src/effects/builtin/metronomeeffect.cpp @@ -29,12 +29,10 @@ EffectManifestPointer MetronomeEffect::getManifest() { period->setId("bpm"); period->setName(QObject::tr("BPM")); period->setDescription(QObject::tr("Set the beats per minute value of the click sound")); - period->setControlHint(EffectManifestParameter::ControlHint::KNOB_LOGARITHMIC); + period->setValueScaler(EffectManifestParameter::ValueScaler::LOGARITHMIC); period->setSemanticHint(EffectManifestParameter::SemanticHint::UNKNOWN); period->setUnitsHint(EffectManifestParameter::UnitsHint::UNKNOWN); - period->setMinimum(40); - period->setDefault(120); - period->setMaximum(208); + period->setRange(40, 120, 208); // Period unit @@ -42,32 +40,29 @@ EffectManifestPointer MetronomeEffect::getManifest() { periodUnit->setId("sync"); periodUnit->setName(QObject::tr("Sync")); periodUnit->setDescription(QObject::tr("Synchronizes the BPM with the track if it can be retrieved")); - periodUnit->setControlHint(EffectManifestParameter::ControlHint::TOGGLE_STEPPING); + periodUnit->setValueScaler(EffectManifestParameter::ValueScaler::TOGGLE); periodUnit->setSemanticHint(EffectManifestParameter::SemanticHint::UNKNOWN); periodUnit->setUnitsHint(EffectManifestParameter::UnitsHint::UNKNOWN); - periodUnit->setDefault(1); - periodUnit->setMinimum(0); - periodUnit->setMaximum(1); + periodUnit->setRange(0, 1, 1); return pManifest; } -MetronomeEffect::MetronomeEffect(EngineEffect* pEffect) - : m_pBpmParameter(pEffect->getParameterById("bpm")), - m_pSyncParameter(pEffect->getParameterById("sync")) { +void MetronomeEffect::loadEngineEffectParameters( + const QMap& parameters) { + m_pBpmParameter = parameters.value("bpm"); + m_pSyncParameter = parameters.value("sync"); } MetronomeEffect::~MetronomeEffect() { } void MetronomeEffect::processChannel( - const ChannelHandle& handle, MetronomeGroupState* pGroupState, const CSAMPLE* pInput, CSAMPLE* pOutput, const mixxx::EngineParameters& bufferParameters, const EffectEnableState enableState, const GroupFeatureState& groupFeatures) { - Q_UNUSED(handle); Q_UNUSED(pInput); MetronomeGroupState* gs = pGroupState; diff --git a/src/effects/builtin/metronomeeffect.h b/src/effects/builtin/metronomeeffect.h index 805bbf365dc..674d9f739d7 100644 --- a/src/effects/builtin/metronomeeffect.h +++ b/src/effects/builtin/metronomeeffect.h @@ -27,22 +27,25 @@ class MetronomeGroupState final : public EffectState { class MetronomeEffect : public EffectProcessorImpl { public: - MetronomeEffect(EngineEffect* pEffect); + MetronomeEffect() {}; virtual ~MetronomeEffect(); static QString getId(); static EffectManifestPointer getManifest(); - // See effectprocessor.h - void processChannel(const ChannelHandle& handle, - MetronomeGroupState* pState, - const CSAMPLE* pInput, CSAMPLE* pOutput, - const mixxx::EngineParameters& bufferParameters, - const EffectEnableState enableState, - const GroupFeatureState& groupFeatures); + void loadEngineEffectParameters( + const QMap& parameters) override; + + void processChannel( + MetronomeGroupState* pState, + const CSAMPLE* pInput, CSAMPLE* pOutput, + const mixxx::EngineParameters& bufferParameters, + const EffectEnableState enableState, + const GroupFeatureState& groupFeatures) override; + private: - EngineEffectParameter* m_pBpmParameter; - EngineEffectParameter* m_pSyncParameter; + EngineEffectParameterPointer m_pBpmParameter; + EngineEffectParameterPointer m_pSyncParameter; DISALLOW_COPY_AND_ASSIGN(MetronomeEffect); }; diff --git a/src/effects/builtin/moogladder4filtereffect.cpp b/src/effects/builtin/moogladder4filtereffect.cpp index d0d622d9de1..47ed2965ff6 100644 --- a/src/effects/builtin/moogladder4filtereffect.cpp +++ b/src/effects/builtin/moogladder4filtereffect.cpp @@ -26,39 +26,33 @@ EffectManifestPointer MoogLadder4FilterEffect::getManifest() { lpf->setId("lpf"); lpf->setName(QObject::tr("LPF")); lpf->setDescription(QObject::tr("Corner frequency ratio of the low pass filter")); - lpf->setControlHint(EffectManifestParameter::ControlHint::KNOB_LOGARITHMIC); + lpf->setValueScaler(EffectManifestParameter::ValueScaler::LOGARITHMIC); lpf->setSemanticHint(EffectManifestParameter::SemanticHint::UNKNOWN); lpf->setUnitsHint(EffectManifestParameter::UnitsHint::UNKNOWN); lpf->setDefaultLinkType(EffectManifestParameter::LinkType::LINKED_LEFT); lpf->setNeutralPointOnScale(1); - lpf->setDefault(kMaxCorner); - lpf->setMinimum(kMinCorner); - lpf->setMaximum(kMaxCorner); + lpf->setRange(kMinCorner, kMaxCorner, kMaxCorner); EffectManifestParameterPointer q = pManifest->addParameter(); q->setId("resonance"); q->setName(QObject::tr("Resonance")); q->setShortName(QObject::tr("Res")); q->setDescription(QObject::tr("Resonance of the filters. 4 = self oscillating")); - q->setControlHint(EffectManifestParameter::ControlHint::KNOB_LOGARITHMIC); + q->setValueScaler(EffectManifestParameter::ValueScaler::LOGARITHMIC); q->setSemanticHint(EffectManifestParameter::SemanticHint::UNKNOWN); q->setUnitsHint(EffectManifestParameter::UnitsHint::SAMPLERATE); - q->setMinimum(0.0); - q->setMaximum(4.0); - q->setDefault(1.0); + q->setRange(0.0, 1.0, 4.0); EffectManifestParameterPointer hpf = pManifest->addParameter(); hpf->setId("hpf"); hpf->setName(QObject::tr("HPF")); hpf->setDescription(QObject::tr("Corner frequency ratio of the high pass filter")); - hpf->setControlHint(EffectManifestParameter::ControlHint::KNOB_LOGARITHMIC); + hpf->setValueScaler(EffectManifestParameter::ValueScaler::LOGARITHMIC); hpf->setSemanticHint(EffectManifestParameter::SemanticHint::UNKNOWN); hpf->setUnitsHint(EffectManifestParameter::UnitsHint::UNKNOWN); hpf->setDefaultLinkType(EffectManifestParameter::LinkType::LINKED_RIGHT); hpf->setNeutralPointOnScale(0.0); - hpf->setDefault(kMinCorner); - hpf->setMinimum(kMinCorner); - hpf->setMaximum(kMaxCorner); + hpf->setRange(kMinCorner, kMinCorner, kMaxCorner); return pManifest; } @@ -85,10 +79,11 @@ MoogLadder4FilterGroupState::~MoogLadder4FilterGroupState() { delete m_pHighFilter; } -MoogLadder4FilterEffect::MoogLadder4FilterEffect(EngineEffect* pEffect) - : m_pLPF(pEffect->getParameterById("lpf")), - m_pResonance(pEffect->getParameterById("resonance")), - m_pHPF(pEffect->getParameterById("hpf")) { +void MoogLadder4FilterEffect::loadEngineEffectParameters( + const QMap& parameters) { + m_pLPF = parameters.value("lpf"); + m_pResonance = parameters.value("resonance"); + m_pHPF = parameters.value("hpf"); } MoogLadder4FilterEffect::~MoogLadder4FilterEffect() { @@ -96,13 +91,11 @@ MoogLadder4FilterEffect::~MoogLadder4FilterEffect() { } void MoogLadder4FilterEffect::processChannel( - const ChannelHandle& handle, MoogLadder4FilterGroupState* pState, const CSAMPLE* pInput, CSAMPLE* pOutput, const mixxx::EngineParameters& bufferParameters, const EffectEnableState enableState, const GroupFeatureState& groupFeatures) { - Q_UNUSED(handle); Q_UNUSED(groupFeatures); double resonance = m_pResonance->value(); diff --git a/src/effects/builtin/moogladder4filtereffect.h b/src/effects/builtin/moogladder4filtereffect.h index e6acf8d4987..bb2640dcb5f 100644 --- a/src/effects/builtin/moogladder4filtereffect.h +++ b/src/effects/builtin/moogladder4filtereffect.h @@ -1,7 +1,6 @@ #ifndef MOOGLADDER4FILTEREFFECT_H #define MOOGLADDER4FILTEREFFECT_H -#include "effects/effect.h" #include "effects/effectprocessor.h" #include "engine/effects/engineeffect.h" #include "engine/effects/engineeffectparameter.h" @@ -29,28 +28,30 @@ class MoogLadder4FilterGroupState : public EffectState { class MoogLadder4FilterEffect : public EffectProcessorImpl { public: - MoogLadder4FilterEffect(EngineEffect* pEffect); + MoogLadder4FilterEffect() {}; virtual ~MoogLadder4FilterEffect(); static QString getId(); static EffectManifestPointer getManifest(); - // See effectprocessor.h - void processChannel(const ChannelHandle& handle, - MoogLadder4FilterGroupState* pState, - const CSAMPLE* pInput, CSAMPLE *pOutput, - const mixxx::EngineParameters& bufferParameters, - const EffectEnableState enableState, - const GroupFeatureState& groupFeatures); + void loadEngineEffectParameters( + const QMap& parameters) override; + + void processChannel( + MoogLadder4FilterGroupState* pState, + const CSAMPLE* pInput, CSAMPLE *pOutput, + const mixxx::EngineParameters& bufferParameters, + const EffectEnableState enableState, + const GroupFeatureState& groupFeatures) override; private: QString debugString() const { return getId(); } - EngineEffectParameter* m_pLPF; - EngineEffectParameter* m_pResonance; - EngineEffectParameter* m_pHPF; + EngineEffectParameterPointer m_pLPF; + EngineEffectParameterPointer m_pResonance; + EngineEffectParameterPointer m_pHPF; DISALLOW_COPY_AND_ASSIGN(MoogLadder4FilterEffect); }; diff --git a/src/effects/builtin/parametriceqeffect.cpp b/src/effects/builtin/parametriceqeffect.cpp index c58c6de042d..65f0341748e 100644 --- a/src/effects/builtin/parametriceqeffect.cpp +++ b/src/effects/builtin/parametriceqeffect.cpp @@ -32,13 +32,11 @@ EffectManifestPointer ParametricEQEffect::getManifest() { gain1->setShortName(QObject::tr("Gain 1")); gain1->setDescription(QObject::tr( "Gain for Filter 1")); - gain1->setControlHint(EffectManifestParameter::ControlHint::KNOB_LINEAR); + gain1->setValueScaler(EffectManifestParameter::ValueScaler::LINEAR); gain1->setSemanticHint(EffectManifestParameter::SemanticHint::UNKNOWN); gain1->setUnitsHint(EffectManifestParameter::UnitsHint::UNKNOWN); gain1->setNeutralPointOnScale(0.5); - gain1->setDefault(0); - gain1->setMinimum(-18); - gain1->setMaximum(18); // dB + gain1->setRange(-18, 0, 18); // dB EffectManifestParameterPointer q1 = pManifest->addParameter(); q1->setId("q1"); @@ -48,13 +46,11 @@ EffectManifestPointer ParametricEQEffect::getManifest() { "Controls the bandwidth of Filter 1.\n" "A lower Q affects a wider band of frequencies,\n" "a higher Q affects a narrower band of frequencies.")); - q1->setControlHint(EffectManifestParameter::ControlHint::KNOB_LINEAR); + q1->setValueScaler(EffectManifestParameter::ValueScaler::LINEAR); q1->setSemanticHint(EffectManifestParameter::SemanticHint::UNKNOWN); q1->setUnitsHint(EffectManifestParameter::UnitsHint::UNKNOWN); q1->setNeutralPointOnScale(0.5); - q1->setDefault(1.75); - q1->setMinimum(0.5); - q1->setMaximum(3.0); + q1->setRange(0.5, 1.75, 3.0); EffectManifestParameterPointer center1 = pManifest->addParameter(); center1->setId("center1"); @@ -62,13 +58,11 @@ EffectManifestPointer ParametricEQEffect::getManifest() { center1->setShortName(QObject::tr("Center 1")); center1->setDescription(QObject::tr( "Center frequency for Filter 1, from 100 Hz to 14 kHz")); - center1->setControlHint(EffectManifestParameter::ControlHint::KNOB_LOGARITHMIC); + center1->setValueScaler(EffectManifestParameter::ValueScaler::LOGARITHMIC); center1->setSemanticHint(EffectManifestParameter::SemanticHint::UNKNOWN); center1->setUnitsHint(EffectManifestParameter::UnitsHint::HERTZ); center1->setNeutralPointOnScale(0.5); - center1->setDefault(kDefaultCenter1); - center1->setMinimum(100); - center1->setMaximum(14000); + center1->setRange(100, kDefaultCenter1, 14000); EffectManifestParameterPointer gain2 = pManifest->addParameter(); gain2->setId("gain2"); @@ -76,13 +70,11 @@ EffectManifestPointer ParametricEQEffect::getManifest() { gain2->setShortName(QObject::tr("Gain 2")); gain2->setDescription(QObject::tr( "Gain for Filter 2")); - gain2->setControlHint(EffectManifestParameter::ControlHint::KNOB_LINEAR); + gain2->setValueScaler(EffectManifestParameter::ValueScaler::LINEAR); gain2->setSemanticHint(EffectManifestParameter::SemanticHint::UNKNOWN); gain2->setUnitsHint(EffectManifestParameter::UnitsHint::UNKNOWN); gain2->setNeutralPointOnScale(0.5); - gain2->setDefault(0); - gain2->setMinimum(-18); - gain2->setMaximum(18); // dB + gain2->setRange(-18, 0, 18); // dB EffectManifestParameterPointer q2 = pManifest->addParameter(); q2->setId("q2"); @@ -92,13 +84,11 @@ EffectManifestPointer ParametricEQEffect::getManifest() { "Controls the bandwidth of Filter 2.\n" "A lower Q affects a wider band of frequencies,\n" "a higher Q affects a narrower band of frequencies.")); - q2->setControlHint(EffectManifestParameter::ControlHint::KNOB_LINEAR); + q2->setValueScaler(EffectManifestParameter::ValueScaler::LINEAR); q2->setSemanticHint(EffectManifestParameter::SemanticHint::UNKNOWN); q2->setUnitsHint(EffectManifestParameter::UnitsHint::UNKNOWN); q2->setNeutralPointOnScale(0.5); - q2->setDefault(1.75); - q2->setMinimum(0.5); - q2->setMaximum(3.0); + q2->setRange(0.5, 1.75, 3.0); EffectManifestParameterPointer center2 = pManifest->addParameter(); center2->setId("center2"); @@ -106,20 +96,19 @@ EffectManifestPointer ParametricEQEffect::getManifest() { center2->setShortName(QObject::tr("Center 2")); center2->setDescription(QObject::tr( "Center frequency for Filter 2, from 100 Hz to 14 kHz")); - center2->setControlHint(EffectManifestParameter::ControlHint::KNOB_LOGARITHMIC); + center2->setValueScaler(EffectManifestParameter::ValueScaler::LOGARITHMIC); center2->setSemanticHint(EffectManifestParameter::SemanticHint::UNKNOWN); center2->setUnitsHint(EffectManifestParameter::UnitsHint::HERTZ); center2->setNeutralPointOnScale(0.5); - center2->setDefault(kDefaultCenter2); - center2->setMinimum(100); - center2->setMaximum(14000); + center2->setRange(100, kDefaultCenter2, 14000); return pManifest; } ParametricEQEffectGroupState::ParametricEQEffectGroupState( const mixxx::EngineParameters& bufferParameters) - : EffectState(bufferParameters) { + : EffectState(bufferParameters), + m_oldSampleRate(44100) { for (int i = 0; i < kBandCount; i++) { m_oldGain.append(1.0); m_oldQ.append(1.75); @@ -142,32 +131,31 @@ void ParametricEQEffectGroupState::setFilters(int sampleRate) { } } -ParametricEQEffect::ParametricEQEffect(EngineEffect* pEffect) - : m_oldSampleRate(44100) { - m_pPotGain.append(pEffect->getParameterById("gain1")); - m_pPotQ.append(pEffect->getParameterById("q1")); - m_pPotCenter.append(pEffect->getParameterById("center1")); - m_pPotGain.append(pEffect->getParameterById("gain2")); - m_pPotQ.append(pEffect->getParameterById("q2")); - m_pPotCenter.append(pEffect->getParameterById("center2")); +void ParametricEQEffect::loadEngineEffectParameters( + const QMap& parameters) { + m_pPotGain.append(parameters.value("gain1")); + m_pPotQ.append(parameters.value("q1")); + m_pPotCenter.append(parameters.value("center1")); + m_pPotGain.append(parameters.value("gain2")); + m_pPotQ.append(parameters.value("q2")); + m_pPotCenter.append(parameters.value("center2")); } ParametricEQEffect::~ParametricEQEffect() { } -void ParametricEQEffect::processChannel(const ChannelHandle& handle, - ParametricEQEffectGroupState* pState, - const CSAMPLE* pInput, CSAMPLE* pOutput, - const mixxx::EngineParameters& bufferParameters, - const EffectEnableState enableState, - const GroupFeatureState& groupFeatures) { - Q_UNUSED(handle); +void ParametricEQEffect::processChannel( + ParametricEQEffectGroupState* pState, + const CSAMPLE* pInput, CSAMPLE* pOutput, + const mixxx::EngineParameters& bufferParameters, + const EffectEnableState enableState, + const GroupFeatureState& groupFeatures) { Q_UNUSED(groupFeatures); // If the sample rate has changed, initialize the filters using the new // sample rate - if (m_oldSampleRate != bufferParameters.sampleRate()) { - m_oldSampleRate = bufferParameters.sampleRate(); + if (pState->m_oldSampleRate != bufferParameters.sampleRate()) { + pState->m_oldSampleRate = bufferParameters.sampleRate(); pState->setFilters(bufferParameters.sampleRate()); } diff --git a/src/effects/builtin/parametriceqeffect.h b/src/effects/builtin/parametriceqeffect.h index dcbf103b245..c1241a524e2 100644 --- a/src/effects/builtin/parametriceqeffect.h +++ b/src/effects/builtin/parametriceqeffect.h @@ -5,7 +5,6 @@ #include #include "control/controlproxy.h" -#include "effects/effect.h" #include "effects/effectprocessor.h" #include "engine/effects/engineeffect.h" #include "engine/effects/engineeffectparameter.h" @@ -33,36 +32,37 @@ class ParametricEQEffectGroupState final : public EffectState { QList m_oldCenter; QList m_oldQ; + unsigned int m_oldSampleRate; + QList m_pBufs; }; class ParametricEQEffect : public EffectProcessorImpl { public: - ParametricEQEffect(EngineEffect* pEffect); + ParametricEQEffect() {}; virtual ~ParametricEQEffect(); static QString getId(); static EffectManifestPointer getManifest(); - // See effectprocessor.h - void processChannel(const ChannelHandle& handle, - ParametricEQEffectGroupState* pState, - const CSAMPLE* pInput, CSAMPLE *pOutput, - const mixxx::EngineParameters& bufferParameters, - const EffectEnableState enableState, - const GroupFeatureState& groupFeatureState); + void loadEngineEffectParameters( + const QMap& parameters) override; + + void processChannel( + ParametricEQEffectGroupState* pState, + const CSAMPLE* pInput, CSAMPLE *pOutput, + const mixxx::EngineParameters& bufferParameters, + const EffectEnableState enableState, + const GroupFeatureState& groupFeatureState) override; private: QString debugString() const { return getId(); } - QList m_pPotGain; - QList m_pPotQ; - QList m_pPotCenter; - - - unsigned int m_oldSampleRate; + QList m_pPotGain; + QList m_pPotQ; + QList m_pPotCenter; DISALLOW_COPY_AND_ASSIGN(ParametricEQEffect); }; diff --git a/src/effects/builtin/phasereffect.cpp b/src/effects/builtin/phasereffect.cpp index 1556d3b8aaf..29d33e25c67 100644 --- a/src/effects/builtin/phasereffect.cpp +++ b/src/effects/builtin/phasereffect.cpp @@ -32,12 +32,10 @@ EffectManifestPointer PhaserEffect::getManifest() { "Period of the LFO (low frequency oscillator)\n" "1/4 - 4 beats rounded to 1/2 beat if tempo is detected\n" "1/4 - 4 seconds if no tempo is detected")); - period->setControlHint(EffectManifestParameter::ControlHint::KNOB_LINEAR); + period->setValueScaler(EffectManifestParameter::ValueScaler::LINEAR); period->setSemanticHint(EffectManifestParameter::SemanticHint::UNKNOWN); period->setUnitsHint(EffectManifestParameter::UnitsHint::BEATS); - period->setMinimum(0.0); - period->setMaximum(4.0); - period->setDefault(1.0); + period->setRange(0.0, 1.0, 4.0); EffectManifestParameterPointer fb = pManifest->addParameter(); fb->setId("feedback"); @@ -45,12 +43,10 @@ EffectManifestPointer PhaserEffect::getManifest() { fb->setShortName(QObject::tr("Feedback")); fb->setDescription(QObject::tr( "Controls how much of the output signal is looped")); - fb->setControlHint(EffectManifestParameter::ControlHint::KNOB_LINEAR); + fb->setValueScaler(EffectManifestParameter::ValueScaler::LINEAR); fb->setSemanticHint(EffectManifestParameter::SemanticHint::UNKNOWN); fb->setUnitsHint(EffectManifestParameter::UnitsHint::UNKNOWN); - fb->setMinimum(-1.0); - fb->setMaximum(1.0); - fb->setDefault(0.0); + fb->setRange(-1.0, 0.0, 1.0); EffectManifestParameterPointer range = pManifest->addParameter(); range->setId("range"); @@ -58,12 +54,10 @@ EffectManifestPointer PhaserEffect::getManifest() { range->setShortName(QObject::tr("Range")); range->setDescription(QObject::tr( "Controls the frequency range across which the notches sweep.")); - range->setControlHint(EffectManifestParameter::ControlHint::KNOB_LINEAR); + range->setValueScaler(EffectManifestParameter::ValueScaler::LINEAR); range->setSemanticHint(EffectManifestParameter::SemanticHint::UNKNOWN); range->setUnitsHint(EffectManifestParameter::UnitsHint::UNKNOWN); - range->setMinimum(0.05); - range->setMaximum(1.0); - range->setDefault(1.0); + range->setRange(0.05, 1.0, 1.0); EffectManifestParameterPointer stages = pManifest->addParameter(); stages->setId("stages"); @@ -71,12 +65,10 @@ EffectManifestPointer PhaserEffect::getManifest() { stages->setShortName(QObject::tr("Stages")); stages->setDescription(QObject::tr( "Number of stages")); // stages of what? - stages->setControlHint(EffectManifestParameter::ControlHint::KNOB_LINEAR); + stages->setValueScaler(EffectManifestParameter::ValueScaler::LINEAR); stages->setSemanticHint(EffectManifestParameter::SemanticHint::UNKNOWN); stages->setUnitsHint(EffectManifestParameter::UnitsHint::UNKNOWN); - stages->setMinimum(1.0); - stages->setMaximum(6.0); - stages->setDefault(3.5); + stages->setRange(1.0, 3.5, 6.0); EffectManifestParameterPointer depth = pManifest->addParameter(); depth->setId("depth"); @@ -84,13 +76,11 @@ EffectManifestPointer PhaserEffect::getManifest() { depth->setShortName(QObject::tr("Depth")); depth->setDescription(QObject::tr( "Intensity of the effect")); - depth->setControlHint(EffectManifestParameter::ControlHint::KNOB_LINEAR); + depth->setValueScaler(EffectManifestParameter::ValueScaler::LINEAR); depth->setSemanticHint(EffectManifestParameter::SemanticHint::UNKNOWN); depth->setUnitsHint(EffectManifestParameter::UnitsHint::UNKNOWN); depth->setDefaultLinkType(EffectManifestParameter::LinkType::LINKED); - depth->setMinimum(0.5); - depth->setMaximum(1.0); - depth->setDefault(0.5); + depth->setRange(0.5, 0.5, 1.0); EffectManifestParameterPointer triplet = pManifest->addParameter(); triplet->setId("triplet"); @@ -98,12 +88,10 @@ EffectManifestPointer PhaserEffect::getManifest() { triplet->setShortName(QObject::tr("Triplets")); triplet->setDescription(QObject::tr( "Divide rounded 1/2 beats of the Period parameter by 3.")); - triplet->setControlHint(EffectManifestParameter::ControlHint::TOGGLE_STEPPING); + triplet->setValueScaler(EffectManifestParameter::ValueScaler::TOGGLE); triplet->setSemanticHint(EffectManifestParameter::SemanticHint::UNKNOWN); triplet->setUnitsHint(EffectManifestParameter::UnitsHint::UNKNOWN); - triplet->setDefault(0); - triplet->setMinimum(0); - triplet->setMaximum(1); + triplet->setRange(0, 0, 1); EffectManifestParameterPointer stereo = pManifest->addParameter(); stereo->setId("stereo"); @@ -111,38 +99,35 @@ EffectManifestPointer PhaserEffect::getManifest() { stereo->setShortName(QObject::tr("Stereo")); stereo->setDescription(QObject::tr( "Sets the LFOs (low frequency oscillators) for the left and right channels out of phase with each others")); - stereo->setControlHint(EffectManifestParameter::ControlHint::TOGGLE_STEPPING); + stereo->setValueScaler(EffectManifestParameter::ValueScaler::TOGGLE); stereo->setSemanticHint(EffectManifestParameter::SemanticHint::UNKNOWN); stereo->setUnitsHint(EffectManifestParameter::UnitsHint::UNKNOWN); - stereo->setMinimum(0); - stereo->setMaximum(1); - stereo->setDefault(0); + stereo->setRange(0, 0, 1); return pManifest; } -PhaserEffect::PhaserEffect(EngineEffect* pEffect) - : m_pStagesParameter(pEffect->getParameterById("stages")), - m_pLFOPeriodParameter(pEffect->getParameterById("lfo_period")), - m_pDepthParameter(pEffect->getParameterById("depth")), - m_pFeedbackParameter(pEffect->getParameterById("feedback")), - m_pRangeParameter(pEffect->getParameterById("range")), - m_pTripletParameter(pEffect->getParameterById("triplet")), - m_pStereoParameter(pEffect->getParameterById("stereo")) { +void PhaserEffect::loadEngineEffectParameters( + const QMap& parameters) { + m_pStagesParameter = parameters.value("stages"); + m_pLFOPeriodParameter = parameters.value("lfo_period"); + m_pDepthParameter = parameters.value("depth"); + m_pFeedbackParameter = parameters.value("feedback"); + m_pRangeParameter = parameters.value("range"); + m_pTripletParameter = parameters.value("triplet"); + m_pStereoParameter = parameters.value("stereo"); } PhaserEffect::~PhaserEffect() { //qDebug() << debugString() << "destroyed"; } -void PhaserEffect::processChannel(const ChannelHandle& handle, - PhaserGroupState* pState, - const CSAMPLE* pInput, CSAMPLE* pOutput, - const mixxx::EngineParameters& bufferParameters, - const EffectEnableState enableState, - const GroupFeatureState& groupFeatures) { - Q_UNUSED(handle); - +void PhaserEffect::processChannel( + PhaserGroupState* pState, + const CSAMPLE* pInput, CSAMPLE* pOutput, + const mixxx::EngineParameters& bufferParameters, + const EffectEnableState enableState, + const GroupFeatureState& groupFeatures) { if (enableState == EffectEnableState::Enabling) { pState->clear(); } diff --git a/src/effects/builtin/phasereffect.h b/src/effects/builtin/phasereffect.h index c85b59a5dc3..ea9cbdedcfb 100644 --- a/src/effects/builtin/phasereffect.h +++ b/src/effects/builtin/phasereffect.h @@ -41,32 +41,34 @@ class PhaserGroupState final : public EffectState { class PhaserEffect : public EffectProcessorImpl { public: - PhaserEffect(EngineEffect* pEffect); + PhaserEffect() {}; virtual ~PhaserEffect(); static QString getId(); static EffectManifestPointer getManifest(); - // See effectprocessor.h - void processChannel(const ChannelHandle& handle, - PhaserGroupState* pState, - const CSAMPLE* pInput, CSAMPLE* pOutput, - const mixxx::EngineParameters& bufferParameters, - const EffectEnableState enableState, - const GroupFeatureState& groupFeatures); + void loadEngineEffectParameters( + const QMap& parameters) override; + + void processChannel( + PhaserGroupState* pState, + const CSAMPLE* pInput, CSAMPLE* pOutput, + const mixxx::EngineParameters& bufferParameters, + const EffectEnableState enableState, + const GroupFeatureState& groupFeatures); private: QString debugString() const { return getId(); } - EngineEffectParameter* m_pStagesParameter; - EngineEffectParameter* m_pLFOPeriodParameter; - EngineEffectParameter* m_pDepthParameter; - EngineEffectParameter* m_pFeedbackParameter; - EngineEffectParameter* m_pRangeParameter; - EngineEffectParameter* m_pTripletParameter; - EngineEffectParameter* m_pStereoParameter; + EngineEffectParameterPointer m_pStagesParameter; + EngineEffectParameterPointer m_pLFOPeriodParameter; + EngineEffectParameterPointer m_pDepthParameter; + EngineEffectParameterPointer m_pFeedbackParameter; + EngineEffectParameterPointer m_pRangeParameter; + EngineEffectParameterPointer m_pTripletParameter; + EngineEffectParameterPointer m_pStereoParameter; //Passing the sample through a series of allpass filters inline CSAMPLE processSample(CSAMPLE input, CSAMPLE* oldIn, CSAMPLE* oldOut, diff --git a/src/effects/builtin/reverbeffect.cpp b/src/effects/builtin/reverbeffect.cpp index 7fdf3ade0fd..9c213576f34 100644 --- a/src/effects/builtin/reverbeffect.cpp +++ b/src/effects/builtin/reverbeffect.cpp @@ -28,12 +28,10 @@ EffectManifestPointer ReverbEffect::getManifest() { decay->setShortName(QObject::tr("Decay")); decay->setDescription(QObject::tr( "Lower decay values cause reverberations to fade out more quickly.")); - decay->setControlHint(EffectManifestParameter::ControlHint::KNOB_LINEAR); + decay->setValueScaler(EffectManifestParameter::ValueScaler::LINEAR); decay->setSemanticHint(EffectManifestParameter::SemanticHint::UNKNOWN); decay->setUnitsHint(EffectManifestParameter::UnitsHint::UNKNOWN); - decay->setMinimum(0); - decay->setDefault(0.5); - decay->setMaximum(1); + decay->setRange(0, 0.5, 1); EffectManifestParameterPointer bandwidth = pManifest->addParameter(); bandwidth->setId("bandwidth"); @@ -42,12 +40,10 @@ EffectManifestPointer ReverbEffect::getManifest() { bandwidth->setDescription(QObject::tr( "Bandwidth of the low pass filter at the input.\n" "Higher values result in less attenuation of high frequencies.")); - bandwidth->setControlHint(EffectManifestParameter::ControlHint::KNOB_LINEAR); + bandwidth->setValueScaler(EffectManifestParameter::ValueScaler::LINEAR); bandwidth->setSemanticHint(EffectManifestParameter::SemanticHint::UNKNOWN); bandwidth->setUnitsHint(EffectManifestParameter::UnitsHint::UNKNOWN); - bandwidth->setMinimum(0); - bandwidth->setDefault(1); - bandwidth->setMaximum(1); + bandwidth->setRange(0, 1, 1); EffectManifestParameterPointer damping = pManifest->addParameter(); damping->setId("damping"); @@ -55,12 +51,10 @@ EffectManifestPointer ReverbEffect::getManifest() { damping->setShortName(QObject::tr("Damping")); damping->setDescription(QObject::tr( "Higher damping values cause high frequencies to decay more quickly than low frequencies.")); - damping->setControlHint(EffectManifestParameter::ControlHint::KNOB_LINEAR); + damping->setValueScaler(EffectManifestParameter::ValueScaler::LINEAR); damping->setSemanticHint(EffectManifestParameter::SemanticHint::UNKNOWN); damping->setUnitsHint(EffectManifestParameter::UnitsHint::UNKNOWN); - damping->setMinimum(0); - damping->setDefault(0); - damping->setMaximum(1); + damping->setRange(0, 0, 1); EffectManifestParameterPointer send = pManifest->addParameter(); send->setId("send_amount"); @@ -68,36 +62,34 @@ EffectManifestPointer ReverbEffect::getManifest() { send->setShortName(QObject::tr("Send")); send->setDescription(QObject::tr( "How much of the signal to send in to the effect")); - send->setControlHint(EffectManifestParameter::ControlHint::KNOB_LINEAR); + send->setValueScaler(EffectManifestParameter::ValueScaler::LINEAR); send->setSemanticHint(EffectManifestParameter::SemanticHint::UNKNOWN); send->setUnitsHint(EffectManifestParameter::UnitsHint::UNKNOWN); send->setDefaultLinkType(EffectManifestParameter::LinkType::LINKED); send->setDefaultLinkInversion(EffectManifestParameter::LinkInversion::NOT_INVERTED); - send->setMinimum(0); - send->setDefault(0); - send->setMaximum(1); + send->setRange(0, 0, 1); return pManifest; } -ReverbEffect::ReverbEffect(EngineEffect* pEffect) - : m_pDecayParameter(pEffect->getParameterById("decay")), - m_pBandWidthParameter(pEffect->getParameterById("bandwidth")), - m_pDampingParameter(pEffect->getParameterById("damping")), - m_pSendParameter(pEffect->getParameterById("send_amount")) { +void ReverbEffect::loadEngineEffectParameters( + const QMap& parameters) { + m_pDecayParameter = parameters.value("decay"); + m_pBandWidthParameter = parameters.value("bandwidth"); + m_pDampingParameter = parameters.value("damping"); + m_pSendParameter = parameters.value("send_amount"); } ReverbEffect::~ReverbEffect() { //qDebug() << debugString() << "destroyed"; } -void ReverbEffect::processChannel(const ChannelHandle& handle, - ReverbGroupState* pState, - const CSAMPLE* pInput, CSAMPLE* pOutput, - const mixxx::EngineParameters& bufferParameters, - const EffectEnableState enableState, - const GroupFeatureState& groupFeatures) { - Q_UNUSED(handle); +void ReverbEffect::processChannel( + ReverbGroupState* pState, + const CSAMPLE* pInput, CSAMPLE* pOutput, + const mixxx::EngineParameters& bufferParameters, + const EffectEnableState enableState, + const GroupFeatureState& groupFeatures) { Q_UNUSED(groupFeatures); const auto decay = m_pDecayParameter->value(); diff --git a/src/effects/builtin/reverbeffect.h b/src/effects/builtin/reverbeffect.h index 1883b536804..4f6ce44b8d1 100644 --- a/src/effects/builtin/reverbeffect.h +++ b/src/effects/builtin/reverbeffect.h @@ -35,29 +35,31 @@ class ReverbGroupState : public EffectState { class ReverbEffect : public EffectProcessorImpl { public: - ReverbEffect(EngineEffect* pEffect); + ReverbEffect() {}; virtual ~ReverbEffect(); static QString getId(); static EffectManifestPointer getManifest(); - // See effectprocessor.h - void processChannel(const ChannelHandle& handle, - ReverbGroupState* pState, - const CSAMPLE* pInput, CSAMPLE* pOutput, - const mixxx::EngineParameters& bufferParameters, - const EffectEnableState enableState, - const GroupFeatureState& groupFeatures); + void loadEngineEffectParameters( + const QMap& parameters); + + void processChannel( + ReverbGroupState* pState, + const CSAMPLE* pInput, CSAMPLE* pOutput, + const mixxx::EngineParameters& bufferParameters, + const EffectEnableState enableState, + const GroupFeatureState& groupFeatures) override; private: QString debugString() const { return getId(); } - EngineEffectParameter* m_pDecayParameter; - EngineEffectParameter* m_pBandWidthParameter; - EngineEffectParameter* m_pDampingParameter; - EngineEffectParameter* m_pSendParameter; + EngineEffectParameterPointer m_pDecayParameter; + EngineEffectParameterPointer m_pBandWidthParameter; + EngineEffectParameterPointer m_pDampingParameter; + EngineEffectParameterPointer m_pSendParameter; DISALLOW_COPY_AND_ASSIGN(ReverbEffect); }; diff --git a/src/effects/builtin/threebandbiquadeqeffect.cpp b/src/effects/builtin/threebandbiquadeqeffect.cpp index c7c112c8bbf..d8eb9c95c99 100644 --- a/src/effects/builtin/threebandbiquadeqeffect.cpp +++ b/src/effects/builtin/threebandbiquadeqeffect.cpp @@ -124,29 +124,31 @@ void ThreeBandBiquadEQEffectGroupState::setFilters( } -ThreeBandBiquadEQEffect::ThreeBandBiquadEQEffect(EngineEffect* pEffect) - : m_pPotLow(pEffect->getParameterById("low")), - m_pPotMid(pEffect->getParameterById("mid")), - m_pPotHigh(pEffect->getParameterById("high")), - m_pKillLow(pEffect->getParameterById("killLow")), - m_pKillMid(pEffect->getParameterById("killMid")), - m_pKillHigh(pEffect->getParameterById("killHigh")) { +ThreeBandBiquadEQEffect::ThreeBandBiquadEQEffect() { m_pLoFreqCorner = std::make_unique("[Mixer Profile]", "LoEQFrequency"); m_pHiFreqCorner = std::make_unique("[Mixer Profile]", "HiEQFrequency"); } +void ThreeBandBiquadEQEffect::loadEngineEffectParameters( + const QMap& parameters) { + m_pPotLow = parameters.value("low"); + m_pPotMid = parameters.value("mid"); + m_pPotHigh = parameters.value("high"); + m_pKillLow = parameters.value("killLow"); + m_pKillMid = parameters.value("killMid"); + m_pKillHigh = parameters.value("killHigh"); +} + ThreeBandBiquadEQEffect::~ThreeBandBiquadEQEffect() { } void ThreeBandBiquadEQEffect::processChannel( - const ChannelHandle& handle, ThreeBandBiquadEQEffectGroupState* pState, const CSAMPLE* pInput, CSAMPLE* pOutput, const mixxx::EngineParameters& bufferParameters, const EffectEnableState enableState, const GroupFeatureState& groupFeatures) { - Q_UNUSED(handle); Q_UNUSED(groupFeatures); if (pState->m_oldSampleRate != bufferParameters.sampleRate() || diff --git a/src/effects/builtin/threebandbiquadeqeffect.h b/src/effects/builtin/threebandbiquadeqeffect.h index 73a00891ef2..28a57aa2b0b 100644 --- a/src/effects/builtin/threebandbiquadeqeffect.h +++ b/src/effects/builtin/threebandbiquadeqeffect.h @@ -2,7 +2,6 @@ #define THREEBANDBIQUADEQEFFECT_H #include "control/controlproxy.h" -#include "effects/effect.h" #include "effects/effectprocessor.h" #include "engine/effects/engineeffect.h" #include "engine/effects/engineeffectparameter.h" @@ -44,21 +43,23 @@ class ThreeBandBiquadEQEffectGroupState final : public EffectState { class ThreeBandBiquadEQEffect : public EffectProcessorImpl { public: - ThreeBandBiquadEQEffect(EngineEffect* pEffect); + ThreeBandBiquadEQEffect(); ~ThreeBandBiquadEQEffect() override; static QString getId(); static EffectManifestPointer getManifest(); - void setFilters(int sampleRate, double lowFreqCorner, double highFreqCorner); + void loadEngineEffectParameters( + const QMap& parameters) override; + + void processChannel( + ThreeBandBiquadEQEffectGroupState* pState, + const CSAMPLE* pInput, CSAMPLE *pOutput, + const mixxx::EngineParameters& bufferParameters, + const EffectEnableState enableState, + const GroupFeatureState& groupFeatureState) override; - // See effectprocessor.h - void processChannel(const ChannelHandle& handle, - ThreeBandBiquadEQEffectGroupState* pState, - const CSAMPLE* pInput, CSAMPLE *pOutput, - const mixxx::EngineParameters& bufferParameters, - const EffectEnableState enableState, - const GroupFeatureState& groupFeatureState); + void setFilters(int sampleRate, double lowFreqCorner, double highFreqCorner); private: ThreeBandBiquadEQEffect(const ThreeBandBiquadEQEffect&) = delete; @@ -68,13 +69,13 @@ class ThreeBandBiquadEQEffect : public EffectProcessorImpl m_pLoFreqCorner; std::unique_ptr m_pHiFreqCorner; diff --git a/src/effects/builtin/tremoloeffect.cpp b/src/effects/builtin/tremoloeffect.cpp index 17200a7d1cc..c84ae28cda6 100644 --- a/src/effects/builtin/tremoloeffect.cpp +++ b/src/effects/builtin/tremoloeffect.cpp @@ -28,13 +28,11 @@ EffectManifestPointer TremoloEffect::getManifest() { depth->setShortName(QObject::tr("Depth")); depth->setDescription(QObject::tr( "How much the effect changes the volume")); - depth->setControlHint(EffectManifestParameter::ControlHint::KNOB_LINEAR); + depth->setValueScaler(EffectManifestParameter::ValueScaler::LINEAR); depth->setSemanticHint(EffectManifestParameter::SemanticHint::UNKNOWN); depth->setUnitsHint(EffectManifestParameter::UnitsHint::UNKNOWN); depth->setDefaultLinkType(EffectManifestParameter::LinkType::LINKED); - depth->setDefault(1); - depth->setMinimum(0); - depth->setMaximum(1); + depth->setRange(0, 1, 1); EffectManifestParameterPointer rate = pManifest->addParameter(); rate->setId("rate"); @@ -44,13 +42,11 @@ EffectManifestPointer TremoloEffect::getManifest() { "Rate of the volume changes\n" "4 beats - 1/8 beat if tempo is detected\n" "1/4 Hz - 8 Hz if no tempo is detected")); - rate->setControlHint( - EffectManifestParameter::ControlHint::KNOB_LOGARITHMIC); + rate->setValueScaler( + EffectManifestParameter::ValueScaler::LOGARITHMIC); rate->setSemanticHint(EffectManifestParameter::SemanticHint::UNKNOWN); rate->setUnitsHint(EffectManifestParameter::UnitsHint::BEATS); - rate->setDefault(1); - rate->setMinimum(1.0/4); - rate->setMaximum(8); + rate->setRange(1.0/4, 1, 8); EffectManifestParameterPointer width = pManifest->addParameter(); width->setId("width"); @@ -59,12 +55,10 @@ EffectManifestPointer TremoloEffect::getManifest() { width->setDescription(QObject::tr( "Width of the volume peak\n" "10% - 90% of the effect period")); - width->setControlHint(EffectManifestParameter::ControlHint::KNOB_LINEAR); + width->setValueScaler(EffectManifestParameter::ValueScaler::LINEAR); width->setSemanticHint(EffectManifestParameter::SemanticHint::UNKNOWN); width->setUnitsHint(EffectManifestParameter::UnitsHint::UNKNOWN); - width->setMinimum(0.1); - width->setDefault(0.5); - width->setMaximum(0.9); + width->setRange(0.1, 0.5, 0.9); EffectManifestParameterPointer waveform = pManifest->addParameter(); waveform->setId("waveform"); @@ -74,13 +68,11 @@ EffectManifestPointer TremoloEffect::getManifest() { "Shape of the volume modulation wave\n" "Fully left: Square wave\n" "Fully right: Sine wave")); - waveform->setControlHint( - EffectManifestParameter::ControlHint::KNOB_LOGARITHMIC); + waveform->setValueScaler( + EffectManifestParameter::ValueScaler::LOGARITHMIC); waveform->setSemanticHint(EffectManifestParameter::SemanticHint::UNKNOWN); waveform->setUnitsHint(EffectManifestParameter::UnitsHint::UNKNOWN); - waveform->setMinimum(0.005); - waveform->setDefault(0.5); - waveform->setMaximum(1); + waveform->setRange(0.005, 0.5, 1); EffectManifestParameterPointer phase = pManifest->addParameter(); phase->setId("phase"); @@ -90,13 +82,11 @@ EffectManifestPointer TremoloEffect::getManifest() { "Shifts the position of the volume peak within the period\n" "Fully left: beginning of the effect period\n" "Fully right: end of the effect period")); - phase->setControlHint( - EffectManifestParameter::ControlHint::KNOB_LINEAR); + phase->setValueScaler( + EffectManifestParameter::ValueScaler::LINEAR); phase->setSemanticHint(EffectManifestParameter::SemanticHint::UNKNOWN); phase->setUnitsHint(EffectManifestParameter::UnitsHint::UNKNOWN); - phase->setDefault(0); - phase->setMinimum(0); - phase->setMaximum(1); + phase->setRange(0, 0, 1); EffectManifestParameterPointer quantize = pManifest->addParameter(); quantize->setId("quantize"); @@ -104,13 +94,11 @@ EffectManifestPointer TremoloEffect::getManifest() { quantize->setShortName(QObject::tr("Quantize")); quantize->setDescription(QObject::tr( "Round the Rate parameter to the nearest whole division of a beat.")); - quantize->setControlHint( - EffectManifestParameter::ControlHint::TOGGLE_STEPPING); + quantize->setValueScaler( + EffectManifestParameter::ValueScaler::TOGGLE); quantize->setSemanticHint(EffectManifestParameter::SemanticHint::UNKNOWN); quantize->setUnitsHint(EffectManifestParameter::UnitsHint::UNKNOWN); - quantize->setDefault(1); - quantize->setMinimum(0); - quantize->setMaximum(1); + quantize->setRange(0, 1, 1); EffectManifestParameterPointer triplet = pManifest->addParameter(); triplet->setId("triplet"); @@ -118,35 +106,32 @@ EffectManifestPointer TremoloEffect::getManifest() { triplet->setShortName(QObject::tr("Triplet")); triplet->setDescription(QObject::tr( "When the Quantize parameter is enabled, divide the effect period by 3.")); - triplet->setControlHint( - EffectManifestParameter::ControlHint::TOGGLE_STEPPING); + triplet->setValueScaler( + EffectManifestParameter::ValueScaler::TOGGLE); triplet->setSemanticHint(EffectManifestParameter::SemanticHint::UNKNOWN); triplet->setUnitsHint(EffectManifestParameter::UnitsHint::UNKNOWN); - triplet->setDefault(0); - triplet->setMinimum(0); - triplet->setMaximum(1); + triplet->setRange(0, 0, 1); return pManifest; } -TremoloEffect::TremoloEffect(EngineEffect* pEffect) - : m_pDepthParameter(pEffect->getParameterById("depth")), - m_pRateParameter(pEffect->getParameterById("rate")), - m_pWidthParameter(pEffect->getParameterById("width")), - m_pWaveformParameter(pEffect->getParameterById("waveform")), - m_pPhaseParameter(pEffect->getParameterById("phase")), - m_pQuantizeParameter(pEffect->getParameterById("quantize")), - m_pTripletParameter(pEffect->getParameterById("triplet")) { +void TremoloEffect::loadEngineEffectParameters( + const QMap& parameters) { + m_pDepthParameter = parameters.value("depth"); + m_pRateParameter = parameters.value("rate"); + m_pWidthParameter = parameters.value("width"); + m_pWaveformParameter = parameters.value("waveform"); + m_pPhaseParameter = parameters.value("phase"); + m_pQuantizeParameter = parameters.value("quantize"); + m_pTripletParameter = parameters.value("triplet"); } -void TremoloEffect::processChannel(const ChannelHandle& handle, - TremoloState* pState, - const CSAMPLE* pInput, CSAMPLE* pOutput, - const mixxx::EngineParameters& bufferParameters, - const EffectEnableState enableState, - const GroupFeatureState& groupFeatures) { - Q_UNUSED(handle); - +void TremoloEffect::processChannel( + TremoloState* pState, + const CSAMPLE* pInput, CSAMPLE* pOutput, + const mixxx::EngineParameters& bufferParameters, + const EffectEnableState enableState, + const GroupFeatureState& groupFeatures) { const double width = m_pWidthParameter->value(); const double smooth = m_pWaveformParameter->value(); const double depth = m_pDepthParameter->value(); diff --git a/src/effects/builtin/tremoloeffect.h b/src/effects/builtin/tremoloeffect.h index 571a02398f9..81ac103533b 100644 --- a/src/effects/builtin/tremoloeffect.h +++ b/src/effects/builtin/tremoloeffect.h @@ -22,31 +22,33 @@ class TremoloState : public EffectState { class TremoloEffect : public EffectProcessorImpl { public: - TremoloEffect(EngineEffect* pEffect); + TremoloEffect() {}; static QString getId(); static EffectManifestPointer getManifest(); - // See effectprocessor.h - void processChannel(const ChannelHandle& handle, - TremoloState* pState, - const CSAMPLE* pInput, CSAMPLE* pOutput, - const mixxx::EngineParameters& bufferParameters, - const EffectEnableState enableState, - const GroupFeatureState& groupFeatures); + void loadEngineEffectParameters( + const QMap& parameters) override; + + void processChannel( + TremoloState* pState, + const CSAMPLE* pInput, CSAMPLE* pOutput, + const mixxx::EngineParameters& bufferParameters, + const EffectEnableState enableState, + const GroupFeatureState& groupFeatures) override; private: QString debugString() const { return getId(); } - EngineEffectParameter* m_pDepthParameter; - EngineEffectParameter* m_pRateParameter; - EngineEffectParameter* m_pWidthParameter; - EngineEffectParameter* m_pWaveformParameter; - EngineEffectParameter* m_pPhaseParameter; - EngineEffectParameter* m_pQuantizeParameter; - EngineEffectParameter* m_pTripletParameter; + EngineEffectParameterPointer m_pDepthParameter; + EngineEffectParameterPointer m_pRateParameter; + EngineEffectParameterPointer m_pWidthParameter; + EngineEffectParameterPointer m_pWaveformParameter; + EngineEffectParameterPointer m_pPhaseParameter; + EngineEffectParameterPointer m_pQuantizeParameter; + EngineEffectParameterPointer m_pTripletParameter; DISALLOW_COPY_AND_ASSIGN(TremoloEffect); }; diff --git a/src/effects/defs.h b/src/effects/defs.h index c6ce474f90e..aa64e1d68bf 100644 --- a/src/effects/defs.h +++ b/src/effects/defs.h @@ -3,6 +3,7 @@ #include "engine/channelhandle.h" #include #include +#include enum class EffectEnableState { Disabled, @@ -17,6 +18,10 @@ enum class EffectBackendType { Unknown }; +inline uint qHash(const EffectBackendType& backendType) { + return static_cast(backendType); +} + enum class SignalProcessingStage { Prefader, Postfader @@ -39,31 +44,22 @@ constexpr int kNumEffectsPerUnit = 4; // enable this when debugging the effects system. constexpr bool kEffectDebugOutput = false; +class EffectsBackend; +typedef QSharedPointer EffectsBackendPointer; + class EffectState; // For sending EffectStates along the MessagePipe typedef ChannelHandleMap EffectStatesMap; typedef std::array EffectStatesMapArray; -class EffectRack; -typedef QSharedPointer EffectRackPointer; - -class StandardEffectRack; -typedef QSharedPointer StandardEffectRackPointer; - -class EqualizerRack; -typedef QSharedPointer EqualizerRackPointer; - -class QuickEffectRack; -typedef QSharedPointer QuickEffectRackPointer; - -class OutputEffectRack; -typedef QSharedPointer OutputEffectRackPointer; +class EngineEffectParameter; +typedef QSharedPointer EngineEffectParameterPointer; class EffectSlot; typedef QSharedPointer EffectSlotPointer; -class EffectParameterSlot; -typedef QSharedPointer EffectParameterSlotPointer; +class EffectKnobParameterSlot; +typedef QSharedPointer EffectKnobParameterSlotPointer; class EffectButtonParameterSlot; typedef QSharedPointer EffectButtonParameterSlotPointer; @@ -71,11 +67,26 @@ typedef QSharedPointer EffectButtonParameterSlotPoint class EffectManifest; typedef QSharedPointer EffectManifestPointer; -class Effect; -typedef QSharedPointer EffectPointer; - class EffectParameterSlotBase; typedef QSharedPointer EffectParameterSlotBasePointer; class EffectChainSlot; typedef QSharedPointer EffectChainSlotPointer; + +class EffectChainPreset; +typedef QSharedPointer EffectChainPresetPointer; + +class EffectPreset; +typedef QSharedPointer EffectPresetPointer; + +class StandardEffectChainSlot; +typedef QSharedPointer StandardEffectChainSlotPointer; + +class EqualizerEffectChainSlot; +typedef QSharedPointer EqualizerEffectChainSlotPointer; + +class OutputEffectChainSlot; +typedef QSharedPointer OutputEffectChainSlotPointer; + +class QuickEffectChainSlot; +typedef QSharedPointer QuickEffectChainSlotPointer; diff --git a/src/effects/effect.cpp b/src/effects/effect.cpp deleted file mode 100644 index 87b66516e44..00000000000 --- a/src/effects/effect.cpp +++ /dev/null @@ -1,218 +0,0 @@ -#include - -#include "effects/effect.h" -#include "effects/effectprocessor.h" -#include "effects/effectsmanager.h" -#include "effects/effectxmlelements.h" -#include "engine/effects/engineeffectchain.h" -#include "engine/effects/engineeffect.h" -#include "util/xml.h" - -Effect::Effect(EffectsManager* pEffectsManager, - EffectManifestPointer pManifest, - EffectInstantiatorPointer pInstantiator) - : QObject(), // no parent - m_pEffectsManager(pEffectsManager), - m_pManifest(pManifest), - m_pInstantiator(pInstantiator), - m_pEngineEffect(NULL), - m_bAddedToEngine(false), - m_bEnabled(false) { - for (const auto& pManifestParameter: m_pManifest->parameters()) { - EffectParameter* pParameter = new EffectParameter( - this, pEffectsManager, m_parameters.size(), pManifestParameter); - m_parameters.append(pParameter); - if (m_parametersById.contains(pParameter->id())) { - qWarning() << debugString() << "WARNING: Loaded EffectManifest that had parameters with duplicate IDs. Dropping one of them."; - } - m_parametersById[pParameter->id()] = pParameter; - } - //qDebug() << debugString() << "created" << this; -} - -Effect::~Effect() { - //qDebug() << debugString() << "destroyed" << this; - m_parametersById.clear(); - for (int i = 0; i < m_parameters.size(); ++i) { - EffectParameter* pParameter = m_parameters.at(i); - m_parameters[i] = NULL; - delete pParameter; - } -} - -EffectState* Effect::createState(const mixxx::EngineParameters& bufferParameters) { - return m_pEngineEffect->createState(bufferParameters); -} - -void Effect::addToEngine(EngineEffectChain* pChain, int iIndex, - const QSet& activeInputChannels) { - VERIFY_OR_DEBUG_ASSERT(pChain) { - return; - } - VERIFY_OR_DEBUG_ASSERT(m_pEngineEffect == nullptr) { - return; - } - VERIFY_OR_DEBUG_ASSERT(!m_bAddedToEngine) { - return; - } - - m_pEngineEffect = new EngineEffect(m_pManifest, - activeInputChannels, - m_pEffectsManager, - m_pInstantiator); - - EffectsRequest* request = new EffectsRequest(); - request->type = EffectsRequest::ADD_EFFECT_TO_CHAIN; - request->pTargetChain = pChain; - request->AddEffectToChain.pEffect = m_pEngineEffect; - request->AddEffectToChain.iIndex = iIndex; - m_pEffectsManager->writeRequest(request); - - m_bAddedToEngine = true; -} - -void Effect::removeFromEngine(EngineEffectChain* pChain, int iIndex) { - VERIFY_OR_DEBUG_ASSERT(pChain) { - return; - } - VERIFY_OR_DEBUG_ASSERT(m_pEngineEffect != nullptr) { - return; - } - VERIFY_OR_DEBUG_ASSERT(m_bAddedToEngine) { - return; - } - - EffectsRequest* request = new EffectsRequest(); - request->type = EffectsRequest::REMOVE_EFFECT_FROM_CHAIN; - request->pTargetChain = pChain; - request->RemoveEffectFromChain.pEffect = m_pEngineEffect; - request->RemoveEffectFromChain.iIndex = iIndex; - m_pEffectsManager->writeRequest(request); - m_pEngineEffect = NULL; - - m_bAddedToEngine = false; -} - -void Effect::updateEngineState() { - if (!m_pEngineEffect) { - return; - } - sendParameterUpdate(); - foreach (EffectParameter* pParameter, m_parameters) { - pParameter->updateEngineState(); - } -} - -EngineEffect* Effect::getEngineEffect() { - return m_pEngineEffect; -} - -EffectManifestPointer Effect::getManifest() const { - return m_pManifest; -} - -void Effect::setEnabled(bool enabled) { - if (enabled != m_bEnabled) { - m_bEnabled = enabled; - updateEngineState(); - emit(enabledChanged(m_bEnabled)); - } -} - -bool Effect::enabled() const { - return m_bEnabled; -} - -void Effect::sendParameterUpdate() { - if (!m_pEngineEffect) { - return; - } - EffectsRequest* pRequest = new EffectsRequest(); - pRequest->type = EffectsRequest::SET_EFFECT_PARAMETERS; - pRequest->pTargetEffect = m_pEngineEffect; - pRequest->SetEffectParameters.enabled = m_bEnabled; - m_pEffectsManager->writeRequest(pRequest); -} - -unsigned int Effect::numKnobParameters() const { - unsigned int num = 0; - foreach(const EffectParameter* parameter, m_parameters) { - if (parameter->manifest()->controlHint() != - EffectManifestParameter::ControlHint::TOGGLE_STEPPING) { - ++num; - } - } - return num; -} - -unsigned int Effect::numButtonParameters() const { - unsigned int num = 0; - foreach(const EffectParameter* parameter, m_parameters) { - if (parameter->manifest()->controlHint() == - EffectManifestParameter::ControlHint::TOGGLE_STEPPING) { - ++num; - } - } - return num; -} - -EffectParameter* Effect::getParameterById(const QString& id) const { - EffectParameter* pParameter = m_parametersById.value(id, NULL); - if (pParameter == NULL) { - qWarning() << debugString() << "getParameterById" - << "WARNING: parameter for id does not exist:" << id; - } - return pParameter; -} - -// static -bool Effect::isButtonParameter(EffectParameter* parameter) { - return parameter->manifest()->controlHint() == - EffectManifestParameter::ControlHint::TOGGLE_STEPPING; -} - -// static -bool Effect::isKnobParameter(EffectParameter* parameter) { - return !isButtonParameter(parameter); -} - -EffectParameter* Effect::getFilteredParameterForSlot(ParameterFilterFnc filterFnc, - unsigned int slotNumber) { - // It's normal to ask for a parameter that doesn't exist. Callers must check - // for NULL. - unsigned int num = 0; - for (const auto& parameter: m_parameters) { - if (parameter->manifest()->showInParameterSlot() && filterFnc(parameter)) { - if(num == slotNumber) { - return parameter; - } - ++num; - } - } - return NULL; -} - -EffectParameter* Effect::getKnobParameterForSlot(unsigned int slotNumber) { - return getFilteredParameterForSlot(isKnobParameter, slotNumber); -} - -EffectParameter* Effect::getButtonParameterForSlot(unsigned int slotNumber) { - return getFilteredParameterForSlot(isButtonParameter, slotNumber); -} - -// static -EffectPointer Effect::createFromXml(EffectsManager* pEffectsManager, - const QDomElement& element) { - // Empty elements are used to preserve chain order - // when there are empty slots at the beginning of the chain. - if (!element.hasChildNodes()) { - return EffectPointer(); - } - QString effectId = XmlParse::selectNodeQString(element, EffectXml::EffectId); - EffectPointer pEffect = pEffectsManager->instantiateEffect(effectId); - return pEffect; -} - -double Effect::getMetaknobDefault() { - return m_pManifest->metaknobDefault(); -} diff --git a/src/effects/effect.h b/src/effects/effect.h deleted file mode 100644 index 272cbfc3d10..00000000000 --- a/src/effects/effect.h +++ /dev/null @@ -1,89 +0,0 @@ -#ifndef EFFECT_H -#define EFFECT_H - -#include -#include - -#include "engine/channelhandle.h" -#include "engine/engine.h" -#include "effects/effectmanifest.h" -#include "effects/effectparameter.h" -#include "effects/effectinstantiator.h" -#include "util/class.h" - -class EffectState; -class EffectProcessor; -class EngineEffectChain; -class EngineEffect; -class EffectsManager; - -// The Effect class is the main-thread representation of an instantiation of an -// effect. This class is NOT thread safe and must only be used by the main -// thread. The getEngineEffect() method can be used to get a pointer to the -// Engine-thread representation of the effect. -class Effect : public QObject { - Q_OBJECT - public: - typedef bool (*ParameterFilterFnc)(EffectParameter*); - - Effect(EffectsManager* pEffectsManager, - EffectManifestPointer pManifest, - EffectInstantiatorPointer pInstantiator); - virtual ~Effect(); - - EffectState* createState(const mixxx::EngineParameters& bufferParameters); - - EffectManifestPointer getManifest() const; - - unsigned int numKnobParameters() const; - unsigned int numButtonParameters() const; - - static bool isButtonParameter(EffectParameter* parameter); - static bool isKnobParameter(EffectParameter* parameter); - - EffectParameter* getFilteredParameterForSlot( - ParameterFilterFnc filterFnc, unsigned int slotNumber); - EffectParameter* getKnobParameterForSlot(unsigned int slotNumber); - EffectParameter* getButtonParameterForSlot(unsigned int slotNumber); - - EffectParameter* getParameterById(const QString& id) const; - EffectParameter* getButtonParameterById(const QString& id) const; - - void setEnabled(bool enabled); - bool enabled() const; - - EngineEffect* getEngineEffect(); - - void addToEngine(EngineEffectChain* pChain, int iIndex, - const QSet& activeInputChannels); - void removeFromEngine(EngineEffectChain* pChain, int iIndex); - void updateEngineState(); - - static EffectPointer createFromXml(EffectsManager* pEffectsManager, - const QDomElement& element); - - double getMetaknobDefault(); - - signals: - void enabledChanged(bool enabled); - - private: - QString debugString() const { - return QString("Effect(%1)").arg(m_pManifest->name()); - } - - void sendParameterUpdate(); - - EffectsManager* m_pEffectsManager; - EffectManifestPointer m_pManifest; - EffectInstantiatorPointer m_pInstantiator; - EngineEffect* m_pEngineEffect; - bool m_bAddedToEngine; - bool m_bEnabled; - QList m_parameters; - QMap m_parametersById; - - DISALLOW_COPY_AND_ASSIGN(Effect); -}; - -#endif /* EFFECT_H */ diff --git a/src/effects/effectbuttonparameterslot.cpp b/src/effects/effectbuttonparameterslot.cpp index 94d83a23eb1..c74e6b9fb34 100644 --- a/src/effects/effectbuttonparameterslot.cpp +++ b/src/effects/effectbuttonparameterslot.cpp @@ -1,7 +1,8 @@ #include -#include "control/controleffectknob.h" +#include "effects/effectslot.h" #include "effects/effectbuttonparameterslot.h" +#include "control/controleffectknob.h" #include "effects/effectxmlelements.h" #include "control/controlobject.h" #include "control/controlpushbutton.h" @@ -10,8 +11,8 @@ EffectButtonParameterSlot::EffectButtonParameterSlot(const QString& group, const unsigned int iParameterSlotNumber) - : EffectParameterSlotBase(group, - iParameterSlotNumber) { + : EffectParameterSlotBase(group, iParameterSlotNumber, + EffectManifestParameter::ParameterType::BUTTON) { QString itemPrefix = formatItemPrefix(iParameterSlotNumber); m_pControlLoaded = new ControlObject( ConfigKey(m_group, itemPrefix + QString("_loaded"))); @@ -21,8 +22,8 @@ EffectButtonParameterSlot::EffectButtonParameterSlot(const QString& group, m_pControlType = new ControlObject( ConfigKey(m_group, itemPrefix + QString("_type"))); - connect(m_pControlValue, SIGNAL(valueChanged(double)), - this, SLOT(slotValueChanged(double))); + connect(m_pControlValue, &ControlObject::valueChanged, + this, &EffectButtonParameterSlot::slotValueChanged); // Read-only controls. m_pControlType->setReadOnly(); @@ -32,67 +33,62 @@ EffectButtonParameterSlot::EffectButtonParameterSlot(const QString& group, } EffectButtonParameterSlot::~EffectButtonParameterSlot() { - //qDebug() << debugString() << "destroyed"; + // qDebug() << debugString() << "destroyed"; // m_pControlLoaded and m_pControlType are deleted by ~EffectParameterSlotBase delete m_pControlValue; } -void EffectButtonParameterSlot::loadEffect(EffectPointer pEffect) { - //qDebug() << debugString() << "loadEffect" << (pEffect ? pEffect->getManifest().name() : "(null)"); +void EffectButtonParameterSlot::loadParameter(EffectParameter* pEffectParameter) { + // qDebug() << debugString() << "loadParameter" << (pEffectSlot ? pEffectSlot->getManifest().name() : "(null)"); if (m_pEffectParameter) { clear(); } - if (pEffect) { - m_pEffect = pEffect; - // Returns null if it doesn't have a parameter for that number - m_pEffectParameter = pEffect->getButtonParameterForSlot(m_iParameterSlotNumber); - - if (m_pEffectParameter) { - // Set the number of states - int numStates = math_max(m_pEffectParameter->manifest()->getSteps().size(), 2); - m_pControlValue->setStates(numStates); - //qDebug() << debugString() << "Loading effect parameter" << m_pEffectParameter->name(); - double dValue = m_pEffectParameter->getValue(); - double dMinimum = m_pEffectParameter->getMinimum(); - double dMinimumLimit = dMinimum; // TODO(rryan) expose limit from EffectParameter - double dMaximum = m_pEffectParameter->getMaximum(); - double dMaximumLimit = dMaximum; // TODO(rryan) expose limit from EffectParameter - double dDefault = m_pEffectParameter->getDefault(); - - if (dValue > dMaximum || dValue < dMinimum || - dMinimum < dMinimumLimit || dMaximum > dMaximumLimit || - dDefault > dMaximum || dDefault < dMinimum) { - qWarning() << debugString() << "WARNING: EffectParameter does not satisfy basic sanity checks."; - } - - // qDebug() << debugString() - // << QString("Val: %1 Min: %2 MinLimit: %3 Max: %4 MaxLimit: %5 Default: %6") - // .arg(dValue).arg(dMinimum).arg(dMinimumLimit).arg(dMaximum).arg(dMaximumLimit).arg(dDefault); - - m_pControlValue->set(dValue); - m_pControlValue->setDefaultValue(dDefault); - EffectManifestParameter::ControlHint type = m_pEffectParameter->getControlHint(); - // TODO(rryan) expose this from EffectParameter - m_pControlType->forceSet(static_cast(type)); - // Default loaded parameters to loaded and unlinked - m_pControlLoaded->forceSet(1.0); - - connect(m_pEffectParameter, SIGNAL(valueChanged(double)), - this, SLOT(slotParameterValueChanged(double))); - } + VERIFY_OR_DEBUG_ASSERT(pEffectParameter->manifest()->parameterType() == + EffectManifestParameter::ParameterType::BUTTON) { + return; } + + m_pEffectParameter = pEffectParameter; + + if (m_pEffectParameter) { + m_pManifestParameter = m_pEffectParameter->manifest(); + + // Set the number of states + int numStates = math_max(m_pEffectParameter->manifest()->getSteps().size(), 2); + m_pControlValue->setStates(numStates); + //qDebug() << debugString() << "Loading effect parameter" << m_pEffectParameter->name(); + double dValue = m_pEffectParameter->getValue(); + double dMinimum = m_pManifestParameter->getMinimum(); + double dMinimumLimit = dMinimum; // TODO(rryan) expose limit from EffectParameter + double dMaximum = m_pManifestParameter->getMaximum(); + double dMaximumLimit = dMaximum; // TODO(rryan) expose limit from EffectParameter + double dDefault = m_pManifestParameter->getDefault(); + + // qDebug() << debugString() + // << QString("Val: %1 Min: %2 MinLimit: %3 Max: %4 MaxLimit: %5 Default: %6") + // .arg(dValue).arg(dMinimum).arg(dMinimumLimit).arg(dMaximum).arg(dMaximumLimit).arg(dDefault); + + m_pControlValue->set(dValue); + m_pControlValue->setDefaultValue(dDefault); + EffectManifestParameter::ValueScaler type = m_pManifestParameter->valueScaler(); + // TODO(rryan) expose this from EffectParameter + m_pControlType->forceSet(static_cast(type)); + // Default loaded parameters to loaded and unlinked + m_pControlLoaded->forceSet(1.0); + } + emit(updated()); } void EffectButtonParameterSlot::clear() { //qDebug() << debugString() << "clear"; if (m_pEffectParameter) { - m_pEffectParameter->disconnect(this); - m_pEffectParameter = NULL; + m_pEffectParameter = nullptr; + m_pManifestParameter.clear(); } - m_pEffect.clear(); + m_pEffectSlot = nullptr; m_pControlLoaded->forceSet(0.0); m_pControlValue->set(0.0); m_pControlValue->setDefaultValue(0.0); @@ -105,41 +101,35 @@ void EffectButtonParameterSlot::slotParameterValueChanged(double value) { m_pControlValue->set(value); } -void EffectButtonParameterSlot::slotValueChanged(double v) { - if (m_pEffectParameter) { - m_pEffectParameter->setValue(v); - } -} - QDomElement EffectButtonParameterSlot::toXml(QDomDocument* doc) const { QDomElement parameterElement; - if (m_pEffectParameter != nullptr) { - parameterElement = doc->createElement(EffectXml::Parameter); - XmlParse::addElement(*doc, parameterElement, - EffectXml::ParameterValue, - QString::number(m_pControlValue->get())); - } + // if (m_pEffectParameter != nullptr) { + // parameterElement = doc->createElement(EffectXml::Parameter); + // XmlParse::addElement(*doc, parameterElement, + // EffectXml::ParameterValue, + // QString::number(m_pControlValue->get())); + // } return parameterElement; } void EffectButtonParameterSlot::loadParameterSlotFromXml(const QDomElement& parameterElement) { - if (m_pEffectParameter == nullptr) { - return; - } - if (!parameterElement.hasChildNodes()) { - m_pControlValue->reset(); - } else { - bool conversionWorked = false; - double value = XmlParse::selectNodeDouble(parameterElement, - EffectXml::ParameterValue, - &conversionWorked); - if (conversionWorked) { - // Need to use setParameterFrom(..., nullptr) here to - // trigger valueChanged() signal emission and execute slotValueChanged() - m_pControlValue->setParameterFrom(value, nullptr); - } - // If the conversion failed, the default value is kept. - } -} + // if (m_pEffectParameter == nullptr) { + // return; + // } + // if (!parameterElement.hasChildNodes()) { + // m_pControlValue->reset(); + // } else { + // bool conversionWorked = false; + // double value = XmlParse::selectNodeDouble(parameterElement, + // EffectXml::ParameterValue, + // &conversionWorked); + // if (conversionWorked) { + // // Need to use setParameterFrom(..., nullptr) here to + // // trigger valueChanged() signal emission and execute slotValueChanged() + // m_pControlValue->setParameterFrom(value, nullptr); + // } + // // If the conversion failed, the default value is kept. + // } +} \ No newline at end of file diff --git a/src/effects/effectbuttonparameterslot.h b/src/effects/effectbuttonparameterslot.h index 20a2a100085..f119ae18526 100644 --- a/src/effects/effectbuttonparameterslot.h +++ b/src/effects/effectbuttonparameterslot.h @@ -6,13 +6,14 @@ #include #include "control/controlobject.h" -#include "effects/effect.h" #include "effects/effectparameterslotbase.h" #include "util/class.h" class ControlObject; class ControlPushButton; +// EffectButtonParameterSlot is a wrapper around the parameterX ControlObject +// that loaded with an EffectParameter into itself by the EffectSlot. class EffectButtonParameterSlot : public EffectParameterSlotBase { Q_OBJECT public: @@ -24,7 +25,7 @@ class EffectButtonParameterSlot : public EffectParameterSlotBase { } // Load the parameter of the given effect into this EffectButtonParameterSlot - void loadEffect(EffectPointer pEffect); + void loadParameter(EffectParameter* pEffectParameter); // Clear the currently loaded effect void clear(); @@ -35,7 +36,6 @@ class EffectButtonParameterSlot : public EffectParameterSlotBase { private slots: // Solely for handling control changes void slotParameterValueChanged(double value); - void slotValueChanged(double v); private: QString debugString() const { diff --git a/src/effects/effectchain.cpp b/src/effects/effectchain.cpp deleted file mode 100644 index ef602743146..00000000000 --- a/src/effects/effectchain.cpp +++ /dev/null @@ -1,373 +0,0 @@ -#include "effects/effectchain.h" - -#include "engine/engine.h" -#include "effects/effectchainmanager.h" -#include "effects/effectsmanager.h" -#include "effects/effectprocessor.h" -#include "effects/effectxmlelements.h" -#include "engine/effects/engineeffectchain.h" -#include "engine/effects/engineeffectrack.h" -#include "engine/effects/message.h" -#include "util/defs.h" -#include "util/sample.h" -#include "util/xml.h" - -EffectChain::EffectChain(EffectsManager* pEffectsManager, const QString& id, - EffectChainPointer pPrototype) - : QObject(pEffectsManager), - m_pEffectsManager(pEffectsManager), - m_pPrototype(pPrototype), - m_bEnabled(true), - m_id(id), - m_name(""), - m_mixMode(EffectChainMixMode::DrySlashWet), - m_dMix(0), - m_pEngineEffectChain(nullptr), - m_bAddedToEngine(false) { -} - -EffectChain::~EffectChain() { - // Remove all effects. - for (int i = 0; i < m_effects.size(); ++i) { - removeEffect(i); - } -} - -void EffectChain::addToEngine(EngineEffectRack* pRack, int iIndex) { - m_pEngineEffectChain = new EngineEffectChain(m_id, - m_pEffectsManager->registeredInputChannels(), - m_pEffectsManager->registeredOutputChannels()); - EffectsRequest* pRequest = new EffectsRequest(); - pRequest->type = EffectsRequest::ADD_CHAIN_TO_RACK; - pRequest->pTargetRack = pRack; - pRequest->AddChainToRack.pChain = m_pEngineEffectChain; - pRequest->AddChainToRack.iIndex = iIndex; - m_pEffectsManager->writeRequest(pRequest); - m_bAddedToEngine = true; - - // Add all effects. - for (int i = 0; i < m_effects.size(); ++i) { - // Add the effect to the engine. - EffectPointer pEffect = m_effects[i]; - if (pEffect) { - pEffect->addToEngine(m_pEngineEffectChain, i, m_enabledInputChannels); - } - } -} - -void EffectChain::removeFromEngine(EngineEffectRack* pRack, int iIndex) { - if (!m_bAddedToEngine) { - return; - } - - // Order doesn't matter when removing. - for (int i = 0; i < m_effects.size(); ++i) { - EffectPointer pEffect = m_effects[i]; - if (pEffect) { - pEffect->removeFromEngine(m_pEngineEffectChain, i); - } - } - - EffectsRequest* pRequest = new EffectsRequest(); - pRequest->type = EffectsRequest::REMOVE_CHAIN_FROM_RACK; - pRequest->pTargetRack = pRack; - pRequest->RemoveChainFromRack.pChain = m_pEngineEffectChain; - pRequest->RemoveChainFromRack.iIndex = iIndex; - m_pEffectsManager->writeRequest(pRequest); - m_bAddedToEngine = false; - - m_pEngineEffectChain = nullptr; -} - -void EffectChain::updateEngineState() { - if (!m_bAddedToEngine) { - return; - } - // Update chain parameters in the engine. - sendParameterUpdate(); - for (int i = 0; i < m_effects.size(); ++i) { - EffectPointer pEffect = m_effects[i]; - if (pEffect) { - // Update effect parameters in the engine. - pEffect->updateEngineState(); - } - } -} - -// static -EffectChainPointer EffectChain::clone(EffectChainPointer pChain) { - if (!pChain) { - return EffectChainPointer(); - } - - EffectChain* pClone = new EffectChain( - pChain->m_pEffectsManager, pChain->id(), pChain); - pClone->setName(pChain->name()); - // Do not set the state of the chain because that information belongs - // to the EffectChainSlot. Leave that to EffectChainSlot::loadEffectChain. - for (const auto& pEffect : pChain->effects()) { - EffectPointer pClonedEffect; - if (pEffect == nullptr) { - // Insert empty effect to preserve chain order - pClonedEffect = EffectPointer(); - } else { - pClonedEffect = pChain->m_pEffectsManager->instantiateEffect( - pEffect->getManifest()->id()); - } - pClone->addEffect(pClonedEffect); - } - return EffectChainPointer(pClone); -} - -EffectChainPointer EffectChain::prototype() const { - return m_pPrototype; -} - -const QString& EffectChain::id() const { - return m_id; -} - -const QString& EffectChain::name() const { - return m_name; -} - -void EffectChain::setName(const QString& name) { - m_name = name; - emit(nameChanged(name)); -} - -QString EffectChain::description() const { - return m_description; -} - -void EffectChain::setDescription(const QString& description) { - m_description = description; - emit(descriptionChanged(description)); -} - -bool EffectChain::enabled() const { - return m_bEnabled; -} - -void EffectChain::setEnabled(bool enabled) { - m_bEnabled = enabled; - sendParameterUpdate(); - emit(enabledChanged(enabled)); -} - -void EffectChain::enableForInputChannel(const ChannelHandleAndGroup& handle_group) { - // TODO(Be): remove m_enabledChannels from this class and move this logic - // to EffectChainSlot - bool bWasAlreadyEnabled = m_enabledInputChannels.contains(handle_group); - if (!bWasAlreadyEnabled) { - m_enabledInputChannels.insert(handle_group); - } - - // The allocation of EffectStates below may be expensive, so avoid it if - // not needed. - if (!m_bAddedToEngine || bWasAlreadyEnabled) { - return; - } - - EffectsRequest* request = new EffectsRequest(); - request->type = EffectsRequest::ENABLE_EFFECT_CHAIN_FOR_INPUT_CHANNEL; - request->pTargetChain = m_pEngineEffectChain; - request->EnableInputChannelForChain.pChannelHandle = &handle_group.handle(); - - // Allocate EffectStates here in the main thread to avoid allocating - // memory in the realtime audio callback thread. Pointers to the - // EffectStates are passed to the EffectRequest and the EffectProcessorImpls - // store the pointers. The containers of EffectState* pointers get deleted - // by ~EffectsRequest, but the EffectStates are managed by EffectProcessorImpl. - auto pEffectStatesMapArray = new EffectStatesMapArray; - - //TODO: get actual configuration of engine - const mixxx::EngineParameters bufferParameters( - mixxx::AudioSignal::SampleRate(96000), - MAX_BUFFER_LEN / mixxx::kEngineChannelCount); - - for (int i = 0; i < m_effects.size(); ++i) { - auto& statesMap = (*pEffectStatesMapArray)[i]; - if (m_effects[i] != nullptr) { - for (const auto& outputChannel : m_pEffectsManager->registeredOutputChannels()) { - if (kEffectDebugOutput) { - qDebug() << debugString() << "EffectChain::enableForInputChannel creating EffectState for input" << handle_group << "output" << outputChannel; - } - statesMap.insert(outputChannel.handle(), - m_effects[i]->createState(bufferParameters)); - } - } else { - for (EffectState* pState : statesMap) { - if (pState != nullptr) { - delete pState; - } - } - statesMap.clear(); - } - } - request->EnableInputChannelForChain.pEffectStatesMapArray = pEffectStatesMapArray; - - m_pEffectsManager->writeRequest(request); - emit(channelStatusChanged(handle_group.name(), true)); -} - -bool EffectChain::enabledForChannel(const ChannelHandleAndGroup& handle_group) const { - return m_enabledInputChannels.contains(handle_group); -} - -void EffectChain::disableForInputChannel(const ChannelHandleAndGroup& handle_group) { - if (m_enabledInputChannels.remove(handle_group)) { - if (!m_bAddedToEngine) { - return; - } - EffectsRequest* request = new EffectsRequest(); - request->type = EffectsRequest::DISABLE_EFFECT_CHAIN_FOR_INPUT_CHANNEL; - request->pTargetChain = m_pEngineEffectChain; - request->DisableInputChannelForChain.pChannelHandle = &handle_group.handle(); - m_pEffectsManager->writeRequest(request); - - emit(channelStatusChanged(handle_group.name(), false)); - } -} - -double EffectChain::mix() const { - return m_dMix; -} - -void EffectChain::setMix(const double& dMix) { - m_dMix = dMix; - sendParameterUpdate(); - emit(mixChanged(dMix)); -} - -EffectChainMixMode EffectChain::mixMode() const { - return m_mixMode; -} - -void EffectChain::setMixMode(EffectChainMixMode mixMode) { - m_mixMode = mixMode; - sendParameterUpdate(); - emit(mixModeChanged(mixMode)); -} - -void EffectChain::addEffect(EffectPointer pEffect) { - //qDebug() << debugString() << "addEffect" << pEffect; - if (!pEffect) { - // Insert empty effects to preserve chain order - // when loading chains with empty effects - m_effects.append(pEffect); - return; - } - - VERIFY_OR_DEBUG_ASSERT(!m_effects.contains(pEffect)) { - return; - } - - m_effects.append(pEffect); - if (m_bAddedToEngine) { - pEffect->addToEngine(m_pEngineEffectChain, m_effects.size() - 1, m_enabledInputChannels); - } - emit(effectChanged(m_effects.size() - 1)); -} - -void EffectChain::replaceEffect(unsigned int effectSlotNumber, - EffectPointer pEffect) { - //qDebug() << debugString() << "replaceEffect" << effectSlotNumber << pEffect; - while (effectSlotNumber >= static_cast(m_effects.size())) { - if (pEffect.isNull()) { - return; - } - m_effects.append(EffectPointer()); - } - - EffectPointer pOldEffect = m_effects[effectSlotNumber]; - if (!pOldEffect.isNull()) { - if (m_bAddedToEngine) { - pOldEffect->removeFromEngine(m_pEngineEffectChain, effectSlotNumber); - } - } - - m_effects.replace(effectSlotNumber, pEffect); - if (!pEffect.isNull()) { - if (m_bAddedToEngine) { - pEffect->addToEngine(m_pEngineEffectChain, effectSlotNumber, m_enabledInputChannels); - } - } - - emit(effectChanged(effectSlotNumber)); -} - -void EffectChain::removeEffect(unsigned int effectSlotNumber) { - replaceEffect(effectSlotNumber, EffectPointer()); -} - -void EffectChain::refreshAllEffects() { - for (int i = 0; i < m_effects.size(); ++i) { - emit(effectChanged(i)); - } -} - -unsigned int EffectChain::numEffects() const { - return m_effects.size(); -} - -const QList& EffectChain::effects() const { - return m_effects; -} - -EngineEffectChain* EffectChain::getEngineEffectChain() { - return m_pEngineEffectChain; -} - -void EffectChain::sendParameterUpdate() { - if (!m_bAddedToEngine) { - return; - } - EffectsRequest* pRequest = new EffectsRequest(); - pRequest->type = EffectsRequest::SET_EFFECT_CHAIN_PARAMETERS; - pRequest->pTargetChain = m_pEngineEffectChain; - pRequest->SetEffectChainParameters.enabled = m_bEnabled; - pRequest->SetEffectChainParameters.mix_mode = m_mixMode; - pRequest->SetEffectChainParameters.mix = m_dMix; - m_pEffectsManager->writeRequest(pRequest); -} - -// static -EffectChainPointer EffectChain::createFromXml(EffectsManager* pEffectsManager, - const QDomElement& element) { - if (!element.hasChildNodes()) { - // An empty element is treated as an ejected Chain (null) - return EffectChainPointer(); - } - - QString id = XmlParse::selectNodeQString(element, - EffectXml::ChainId); - QString name = XmlParse::selectNodeQString(element, - EffectXml::ChainName); - QString description = XmlParse::selectNodeQString(element, - EffectXml::ChainDescription); - QString mixModeStr = XmlParse::selectNodeQString(element, - EffectXml::ChainMixMode); - - EffectChainPointer pChain(new EffectChain(pEffectsManager, id)); - pChain->setName(name); - pChain->setDescription(description); - EffectChainMixMode mixMode = mixModeFromString(mixModeStr); - if (mixMode < EffectChainMixMode::NumMixModes) { - pChain->setMixMode(mixMode); - } - - QDomElement effects = XmlParse::selectElement(element, EffectXml::EffectsRoot); - QDomNodeList effectChildren = effects.childNodes(); - - for (int i = 0; i < effectChildren.count(); ++i) { - QDomNode effect = effectChildren.at(i); - if (effect.isElement()) { - EffectPointer pEffect = Effect::createFromXml( - pEffectsManager, effect.toElement()); - pChain->addEffect(pEffect); - } - } - - return pChain; -} diff --git a/src/effects/effectchain.h b/src/effects/effectchain.h deleted file mode 100644 index 6b074ffa2a4..00000000000 --- a/src/effects/effectchain.h +++ /dev/null @@ -1,132 +0,0 @@ -#ifndef EFFECTCHAIN_H -#define EFFECTCHAIN_H - -#include -#include -#include -#include - -#include "effects/defs.h" -#include "engine/channelhandle.h" -#include "effects/effect.h" -#include "util/class.h" - -class EffectsManager; -class EngineEffectRack; -class EngineEffectChain; -class EffectChain; -typedef QSharedPointer EffectChainPointer; - -// The main-thread representation of an effect chain. This class is NOT -// thread-safe and must only be used from the main thread. -class EffectChain : public QObject { - Q_OBJECT - public: - EffectChain(EffectsManager* pEffectsManager, const QString& id, - EffectChainPointer prototype=EffectChainPointer()); - virtual ~EffectChain(); - - void addToEngine(EngineEffectRack* pRack, int iIndex); - void removeFromEngine(EngineEffectRack* pRack, int iIndex); - void updateEngineState(); - - // The ID of an EffectChain is a unique ID given to it to help associate it - // with the preset from which it was loaded. - const QString& id() const; - - // Whether the chain is enabled (eligible for processing). - bool enabled() const; - void setEnabled(bool enabled); - - // Activates EffectChain processing for the provided channel. - void enableForInputChannel(const ChannelHandleAndGroup& handle_group); - bool enabledForChannel(const ChannelHandleAndGroup& handle_group) const; - const QSet& enabledChannels() const; - void disableForInputChannel(const ChannelHandleAndGroup& handle_group); - - EffectChainPointer prototype() const; - - // Get the human-readable name of the EffectChain - const QString& name() const; - void setName(const QString& name); - - // Get the human-readable description of the EffectChain - QString description() const; - void setDescription(const QString& description); - - double mix() const; - void setMix(const double& dMix); - - static QString mixModeToString(EffectChainMixMode type) { - switch (type) { - case EffectChainMixMode::DrySlashWet: - return "DRY/WET"; - case EffectChainMixMode::DryPlusWet: - return "DRY+WET"; - default: - return "UNKNOWN"; - } - } - static EffectChainMixMode mixModeFromString(const QString& typeStr) { - if (typeStr == "DRY/WET") { - return EffectChainMixMode::DrySlashWet; - } else if (typeStr == "DRY+WET") { - return EffectChainMixMode::DryPlusWet; - } else { - return EffectChainMixMode::NumMixModes; - } - } - - EffectChainMixMode mixMode() const; - void setMixMode(EffectChainMixMode type); - - void addEffect(EffectPointer pEffect); - void replaceEffect(unsigned int effectSlotNumber, EffectPointer pEffect); - void removeEffect(unsigned int effectSlotNumber); - void refreshAllEffects(); - - const QList& effects() const; - unsigned int numEffects() const; - - EngineEffectChain* getEngineEffectChain(); - - static EffectChainPointer createFromXml(EffectsManager* pEffectsManager, - const QDomElement& element); - static EffectChainPointer clone(EffectChainPointer pChain); - - signals: - // Signal that indicates that an effect has been added or removed. - void effectChanged(unsigned int effectSlotNumber); - void nameChanged(const QString& name); - void descriptionChanged(const QString& name); - void enabledChanged(bool enabled); - void mixChanged(double v); - void mixModeChanged(EffectChainMixMode type); - void channelStatusChanged(const QString& group, bool enabled); - - private: - QString debugString() const { - return QString("EffectChain(%1)").arg(m_id); - } - - void sendParameterUpdate(); - - EffectsManager* m_pEffectsManager; - EffectChainPointer m_pPrototype; - - bool m_bEnabled; - QString m_id; - QString m_name; - QString m_description; - EffectChainMixMode m_mixMode; - double m_dMix; - - QSet m_enabledInputChannels; - QList m_effects; - EngineEffectChain* m_pEngineEffectChain; - bool m_bAddedToEngine; - - DISALLOW_COPY_AND_ASSIGN(EffectChain); -}; - -#endif /* EFFECTCHAIN_H */ diff --git a/src/effects/effectchainmanager.cpp b/src/effects/effectchainmanager.cpp deleted file mode 100644 index 595f5e010ff..00000000000 --- a/src/effects/effectchainmanager.cpp +++ /dev/null @@ -1,235 +0,0 @@ -#include "effects/effectchainmanager.h" -#include "effects/effectsmanager.h" -#include "effects/effectxmlelements.h" - -#include -#include -#include -#include - -EffectChainManager::EffectChainManager(UserSettingsPointer pConfig, - EffectsManager* pEffectsManager) - : QObject(pEffectsManager), - m_pConfig(pConfig), - m_pEffectsManager(pEffectsManager) { -} - -EffectChainManager::~EffectChainManager() { - //qDebug() << debugString() << "destroyed"; -} - -void EffectChainManager::registerInputChannel(const ChannelHandleAndGroup& handle_group) { - VERIFY_OR_DEBUG_ASSERT(!m_registeredInputChannels.contains(handle_group)) { - return; - } - m_registeredInputChannels.insert(handle_group); - - for (auto& pRack : m_standardEffectRacks) { - pRack->registerInputChannel(handle_group); - } -} - -void EffectChainManager::registerOutputChannel(const ChannelHandleAndGroup& handle_group) { - VERIFY_OR_DEBUG_ASSERT(!m_registeredOutputChannels.contains(handle_group)) { - return; - } - m_registeredOutputChannels.insert(handle_group); -} - -StandardEffectRackPointer EffectChainManager::addStandardEffectRack() { - StandardEffectRackPointer pRack(new StandardEffectRack( - m_pEffectsManager, this, m_standardEffectRacks.size())); - m_standardEffectRacks.append(pRack); - m_effectRacksByGroup.insert(pRack->getGroup(), pRack); - return pRack; -} - -StandardEffectRackPointer EffectChainManager::getStandardEffectRack(int i) { - if (i < 0 || i >= m_standardEffectRacks.size()) { - return StandardEffectRackPointer(); - } - return m_standardEffectRacks[i]; -} - -EqualizerRackPointer EffectChainManager::addEqualizerRack() { - EqualizerRackPointer pRack(new EqualizerRack( - m_pEffectsManager, this, m_equalizerEffectRacks.size())); - m_equalizerEffectRacks.append(pRack); - m_effectRacksByGroup.insert(pRack->getGroup(), pRack); - return pRack; -} - -EqualizerRackPointer EffectChainManager::getEqualizerRack(int i) { - if (i < 0 || i >= m_equalizerEffectRacks.size()) { - return EqualizerRackPointer(); - } - return m_equalizerEffectRacks[i]; -} - -QuickEffectRackPointer EffectChainManager::addQuickEffectRack() { - QuickEffectRackPointer pRack(new QuickEffectRack( - m_pEffectsManager, this, m_quickEffectRacks.size())); - m_quickEffectRacks.append(pRack); - m_effectRacksByGroup.insert(pRack->getGroup(), pRack); - return pRack; -} - -QuickEffectRackPointer EffectChainManager::getQuickEffectRack(int i) { - if (i < 0 || i >= m_quickEffectRacks.size()) { - return QuickEffectRackPointer(); - } - return m_quickEffectRacks[i]; -} - -OutputEffectRackPointer EffectChainManager::addOutputsEffectRack() { - OutputEffectRackPointer pRack(new OutputEffectRack( - m_pEffectsManager, this)); - m_pOutputEffectRack = pRack; - m_effectRacksByGroup.insert(pRack->getGroup(), pRack); - return m_pOutputEffectRack; -} - -OutputEffectRackPointer EffectChainManager::getMasterEffectRack() { - return m_pOutputEffectRack; -} - -EffectRackPointer EffectChainManager::getEffectRack(const QString& group) { - return m_effectRacksByGroup.value(group); -} - -void EffectChainManager::addEffectChain(EffectChainPointer pEffectChain) { - if (pEffectChain) { - m_effectChains.append(pEffectChain); - } -} - -void EffectChainManager::removeEffectChain(EffectChainPointer pEffectChain) { - if (pEffectChain) { - m_effectChains.removeAll(pEffectChain); - } -} - -EffectChainPointer EffectChainManager::getNextEffectChain(EffectChainPointer pEffectChain) { - if (m_effectChains.isEmpty()) - return EffectChainPointer(); - - if (!pEffectChain) { - return m_effectChains[0]; - } - - int indexOf = m_effectChains.lastIndexOf(pEffectChain); - if (indexOf == -1) { - qWarning() << debugString() << "WARNING: getNextEffectChain called for an unmanaged EffectChain"; - return m_effectChains[0]; - } - - return m_effectChains[(indexOf + 1) % m_effectChains.size()]; -} - -EffectChainPointer EffectChainManager::getPrevEffectChain(EffectChainPointer pEffectChain) { - if (m_effectChains.isEmpty()) - return EffectChainPointer(); - - if (!pEffectChain) { - return m_effectChains[m_effectChains.size()-1]; - } - - int indexOf = m_effectChains.lastIndexOf(pEffectChain); - if (indexOf == -1) { - qWarning() << debugString() << "WARNING: getPrevEffectChain called for an unmanaged EffectChain"; - return m_effectChains[m_effectChains.size()-1]; - } - - return m_effectChains[(indexOf - 1 + m_effectChains.size()) % m_effectChains.size()]; -} - -void EffectChainManager::refeshAllRacks() { - for (const auto& pRack: m_standardEffectRacks) { - pRack->refresh(); - } - for (const auto& pRack: m_equalizerEffectRacks) { - pRack->refresh(); - } - for (const auto& pRack: m_quickEffectRacks) { - pRack->refresh(); - } -} - -bool EffectChainManager::saveEffectChains() { - QDomDocument doc("MixxxEffects"); - - QString blank = "\n" - "<" + EffectXml::Root + " schemaVersion=\"" + - QString::number(EffectXml::kXmlSchemaVersion) + "\">\n" - "\n"; - doc.setContent(blank); - - QDomElement rootNode = doc.documentElement(); - - for (EffectRackPointer pRack : m_standardEffectRacks) { - rootNode.appendChild(pRack->toXml(&doc)); - } - // TODO? Save QuickEffects in effects.xml too, or keep stored in ConfigObjects? -// foreach(EffectRackPointer pRack, m_quickEffectRacks) { -// rootNode.appendChild(pRack->toXML(&doc)); -// } - - QDir settingsPath(m_pConfig->getSettingsPath()); - - if (!settingsPath.exists()) { - return false; - } - - QFile file(settingsPath.absoluteFilePath("effects.xml")); - - // TODO(rryan): overwrite the right way. - if (!file.open(QIODevice::Truncate | QIODevice::WriteOnly)) { - return false; - } - - QString effectsXml = doc.toString(); - file.write(effectsXml.toUtf8()); - file.close(); - return true; -} - -void EffectChainManager::loadEffectChains() { - QDir settingsPath(m_pConfig->getSettingsPath()); - QFile file(settingsPath.absoluteFilePath("effects.xml")); - QDomDocument doc; - - QDomElement emptyChainElement = doc.createElement(EffectXml::Chain); - // Check that XML file can be opened and is valid XML - if (!file.open(QIODevice::ReadOnly) || !doc.setContent(&file)) { - return; - } - - QDomElement root = doc.documentElement(); - QDomElement rackElement = XmlParse::selectElement(root, EffectXml::Rack); - QDomElement chainsElement = XmlParse::selectElement(rackElement, EffectXml::ChainsRoot); - QDomNodeList chainsList = chainsElement.elementsByTagName(EffectXml::Chain); - - for (int i = 0; i < chainsList.count(); ++i) { - QDomNode chainNode = chainsList.at(i); - - if (chainNode.isElement()) { - QDomElement chainElement = chainNode.toElement(); - EffectChainPointer pChain = EffectChain::createFromXml( - m_pEffectsManager, chainElement); - if (pChain) { // null = ejected chains. - EffectChainSlotPointer pChainSlot = getStandardEffectRack(0)->getEffectChainSlot(i); - if (pChainSlot) { - pChainSlot->loadEffectChainToSlot(pChain); - pChainSlot->loadChainSlotFromXml(chainElement); - pChain->addToEngine(getStandardEffectRack(0)->getEngineEffectRack(), i); - pChain->updateEngineState(); - pChainSlot->updateRoutingSwitches(); - } - } - } - } -} - -bool EffectChainManager::isAdoptMetaknobValueEnabled() const { - return m_pConfig->getValue(ConfigKey("[Effects]", "AdoptMetaknobValue"), true); -} diff --git a/src/effects/effectchainmanager.h b/src/effects/effectchainmanager.h deleted file mode 100644 index 12ea3fb3073..00000000000 --- a/src/effects/effectchainmanager.h +++ /dev/null @@ -1,89 +0,0 @@ -#ifndef EFFECTCHAINMANAGER_H -#define EFFECTCHAINMANAGER_H - -#include -#include -#include - -#include "preferences/usersettings.h" -#include "effects/effectchain.h" -#include "effects/effectrack.h" -#include "engine/channelhandle.h" -#include "util/class.h" -#include "util/xml.h" - -class EffectsManager; - -// A class for keeping track of all the user's EffectChains. Eventually will -// serialize/deserialize the EffectChains from storage but for Effects v1 we are -// hard-coding the available chains. -class EffectChainManager : public QObject { - Q_OBJECT - public: - EffectChainManager(UserSettingsPointer pConfig, - EffectsManager* pEffectsManager); - virtual ~EffectChainManager(); - - void registerInputChannel(const ChannelHandleAndGroup& handle_group); - const QSet& registeredInputChannels() const { - return m_registeredInputChannels; - } - - void registerOutputChannel(const ChannelHandleAndGroup& handle_group); - const QSet& registeredOutputChannels() const { - return m_registeredOutputChannels; - } - - StandardEffectRackPointer addStandardEffectRack(); - StandardEffectRackPointer getStandardEffectRack(int rack); - - EqualizerRackPointer addEqualizerRack(); - EqualizerRackPointer getEqualizerRack(int rack); - - QuickEffectRackPointer addQuickEffectRack(); - QuickEffectRackPointer getQuickEffectRack(int rack); - - OutputEffectRackPointer addOutputsEffectRack(); - OutputEffectRackPointer getMasterEffectRack(); - - EffectRackPointer getEffectRack(const QString& group); - - void addEffectChain(EffectChainPointer pEffectChain); - void removeEffectChain(EffectChainPointer pEffectChain); - - // To support cycling through effect chains, there is a global ordering of - // chains. These methods allow you to get the next or previous chain given - // your current chain. - // TODO(rryan): Prevent double-loading of a chain into a slot? - EffectChainPointer getNextEffectChain(EffectChainPointer pEffectChain); - EffectChainPointer getPrevEffectChain(EffectChainPointer pEffectChain); - - bool saveEffectChains(); - void loadEffectChains(); - - // Reloads all effect to the slots to update parameter assignments - void refeshAllRacks(); - - static const int kNumStandardEffectChains = 4; - - bool isAdoptMetaknobValueEnabled() const; - - private: - QString debugString() const { - return "EffectChainManager"; - } - - UserSettingsPointer m_pConfig; - EffectsManager* m_pEffectsManager; - QList m_standardEffectRacks; - QList m_equalizerEffectRacks; - QList m_quickEffectRacks; - OutputEffectRackPointer m_pOutputEffectRack; - QHash m_effectRacksByGroup; - QList m_effectChains; - QSet m_registeredInputChannels; - QSet m_registeredOutputChannels; - DISALLOW_COPY_AND_ASSIGN(EffectChainManager); -}; - -#endif /* EFFECTCHAINMANAGER_H */ diff --git a/src/effects/effectchainpreset.cpp b/src/effects/effectchainpreset.cpp new file mode 100644 index 00000000000..94b77b3107e --- /dev/null +++ b/src/effects/effectchainpreset.cpp @@ -0,0 +1,38 @@ +#include "effects/effectchainpreset.h" + +#include "effects/effectxmlelements.h" +#include "effects/effectchainslot.h" +#include "util/xml.h" + +EffectChainPreset::EffectChainPreset() { +} + +EffectChainPreset::EffectChainPreset(const QDomElement& element) { + if (!element.hasChildNodes()) { + return; + } + + m_id = XmlParse::selectNodeQString(element, EffectXml::ChainId); + m_name = XmlParse::selectNodeQString(element, EffectXml::ChainName); + m_description = XmlParse::selectNodeQString(element, EffectXml::ChainDescription); + + QString mixModeStr = XmlParse::selectNodeQString(element, EffectXml::ChainMixMode); + m_mixMode = EffectChainSlot::mixModeFromString(mixModeStr); + + m_dSuper = XmlParse::selectNodeDouble(element, EffectXml::ChainSuperParameter); + + QDomElement effectsElement = XmlParse::selectElement(element, EffectXml::EffectsRoot); + QDomNodeList effectList = effectsElement.childNodes(); + + for (int i = 0; i < effectList.count(); ++i) { + QDomNode effectNode = effectList.at(i); + if (effectNode.isElement()) { + QDomElement effectElement = effectNode.toElement(); + EffectPresetPointer pPreset(new EffectPreset(effectElement)); + m_effectPresets.append(pPreset); + } + } +} + +EffectChainPreset::~EffectChainPreset() { +} diff --git a/src/effects/effectchainpreset.h b/src/effects/effectchainpreset.h new file mode 100644 index 00000000000..bd6c324116e --- /dev/null +++ b/src/effects/effectchainpreset.h @@ -0,0 +1,29 @@ +#ifndef EFFECTCHAINPRESET_H +#define EFFECTCHAINPRESET_H + +#include + +#include "effects/defs.h" +#include "effects/effectpreset.h" + + +class EffectChainPreset { + public: + EffectChainPreset(); + EffectChainPreset(const QDomElement& element); + ~EffectChainPreset(); + + QString name() const { + return m_name; + } + + private: + QString m_id; + QString m_name; + QString m_description; + double m_dSuper; + EffectChainMixMode m_mixMode; + QList m_effectPresets; +}; + +#endif /* EFFECTCHAINPRESET_H */ \ No newline at end of file diff --git a/src/effects/effectchainslot.cpp b/src/effects/effectchainslot.cpp index da4396fb6de..8f456055f60 100644 --- a/src/effects/effectchainslot.cpp +++ b/src/effects/effectchainslot.cpp @@ -1,25 +1,41 @@ #include "effects/effectchainslot.h" -#include "effects/effectrack.h" -#include "effects/effectxmlelements.h" -#include "effects/effectslot.h" +#include "control/controlencoder.h" #include "control/controlpotmeter.h" #include "control/controlpushbutton.h" -#include "control/controlencoder.h" +#include "effects/effectprocessor.h" +#include "effects/effectslot.h" +#include "effects/effectsmanager.h" +#include "effects/effectxmlelements.h" +#include "effects/specialeffectchainslots.h" +#include "engine/effects/engineeffectchain.h" +#include "engine/effects/message.h" +#include "engine/engine.h" #include "mixer/playermanager.h" +#include "util/defs.h" #include "util/math.h" +#include "util/sample.h" #include "util/xml.h" -EffectChainSlot::EffectChainSlot(EffectRack* pRack, const QString& group, - unsigned int iChainNumber) - : m_iChainSlotNumber(iChainNumber), - // The control group names are 1-indexed while internally everything + +EffectChainSlot::EffectChainSlot(const QString& group, + EffectsManager* pEffectsManager, + SignalProcessingStage stage, + const QString& id) + : // The control group names are 1-indexed while internally everything // is 0-indexed. m_group(group), - m_pEffectRack(pRack) { + m_pEffectsManager(pEffectsManager), + m_signalProcessingStage(stage), + m_id(id), + m_name(""), + m_description(""), + m_pEngineEffectChain(nullptr) { + // qDebug() << "EffectChainSlot::EffectChainSlot " << group << ' ' << iChainNumber; + m_pControlClear = new ControlPushButton(ConfigKey(m_group, "clear")); - connect(m_pControlClear, SIGNAL(valueChanged(double)), - this, SLOT(slotControlClear(double))); + connect(m_pControlClear, &ControlObject::valueChanged, + this, &EffectChainSlot::slotControlClear); m_pControlNumEffects = new ControlObject(ConfigKey(m_group, "num_effects")); m_pControlNumEffects->setReadOnly(); @@ -29,47 +45,53 @@ EffectChainSlot::EffectChainSlot(EffectRack* pRack, const QString& group, m_pControlChainLoaded = new ControlObject(ConfigKey(m_group, "loaded")); m_pControlChainLoaded->setReadOnly(); + if (id != QString()) { + m_pControlChainLoaded->forceSet(1.0); + } m_pControlChainEnabled = new ControlPushButton(ConfigKey(m_group, "enabled")); m_pControlChainEnabled->setButtonMode(ControlPushButton::POWERWINDOW); // Default to enabled. The skin might not show these buttons. m_pControlChainEnabled->setDefaultValue(true); m_pControlChainEnabled->set(true); - connect(m_pControlChainEnabled, SIGNAL(valueChanged(double)), - this, SLOT(slotControlChainEnabled(double))); + connect(m_pControlChainEnabled, &ControlObject::valueChanged, + this, &EffectChainSlot::sendParameterUpdate); m_pControlChainMix = new ControlPotmeter(ConfigKey(m_group, "mix"), 0.0, 1.0, false, true, false, true, 1.0); - connect(m_pControlChainMix, SIGNAL(valueChanged(double)), - this, SLOT(slotControlChainMix(double))); + connect(m_pControlChainMix, &ControlObject::valueChanged, + this, &EffectChainSlot::sendParameterUpdate); m_pControlChainSuperParameter = new ControlPotmeter(ConfigKey(m_group, "super1"), 0.0, 1.0); - connect(m_pControlChainSuperParameter, SIGNAL(valueChanged(double)), - this, SLOT(slotControlChainSuperParameter(double))); + // QObject::connect cannot connect to slots with optional parameters using function + // pointer syntax if the slot has more parameters than the signal, so use a lambda + // to hack around this limitation. + connect(m_pControlChainSuperParameter, &ControlObject::valueChanged, + this, [=](double value){slotControlChainSuperParameter(value);} ); m_pControlChainSuperParameter->set(0.0); m_pControlChainSuperParameter->setDefaultValue(0.0); m_pControlChainMixMode = new ControlPushButton(ConfigKey(m_group, "mix_mode")); m_pControlChainMixMode->setButtonMode(ControlPushButton::TOGGLE); m_pControlChainMixMode->setStates(static_cast(EffectChainMixMode::NumMixModes)); - connect(m_pControlChainMixMode, SIGNAL(valueChanged(double)), - this, SLOT(slotControlChainMixMode(double))); + connect(m_pControlChainMixMode, &ControlObject::valueChanged, + this, &EffectChainSlot::sendParameterUpdate); m_pControlChainNextPreset = new ControlPushButton(ConfigKey(m_group, "next_chain")); - connect(m_pControlChainNextPreset, SIGNAL(valueChanged(double)), - this, SLOT(slotControlChainNextPreset(double))); + connect(m_pControlChainNextPreset, &ControlObject::valueChanged, + this, &EffectChainSlot::slotControlChainNextPreset); m_pControlChainPrevPreset = new ControlPushButton(ConfigKey(m_group, "prev_chain")); - connect(m_pControlChainPrevPreset, SIGNAL(valueChanged(double)), - this, SLOT(slotControlChainPrevPreset(double))); + connect(m_pControlChainPrevPreset, &ControlObject::valueChanged, + this, &EffectChainSlot::slotControlChainPrevPreset); // Ignoring no-ops is important since this is for +/- tickers. m_pControlChainSelector = new ControlEncoder(ConfigKey(m_group, "chain_selector"), false); - connect(m_pControlChainSelector, SIGNAL(valueChanged(double)), - this, SLOT(slotControlChainSelector(double))); + connect(m_pControlChainSelector, &ControlObject::valueChanged, + this, &EffectChainSlot::slotControlChainSelector); - connect(&m_channelStatusMapper, SIGNAL(mapped(const QString&)), - this, SLOT(slotChannelStatusChanged(const QString&))); + connect(&m_channelStatusMapper, QOverload::of(&QSignalMapper::mapped), + this, &EffectChainSlot::slotChannelStatusChanged); // ControlObjects for skin <-> controller mapping interaction. // Refer to comment in header for full explanation. @@ -86,11 +108,15 @@ EffectChainSlot::EffectChainSlot(EffectRack* pRack, const QString& group, ConfigKey(m_group, "focused_effect"), true); m_pControlChainFocusedEffect->setButtonMode(ControlPushButton::TOGGLE); + + addToEngine(); } EffectChainSlot::~EffectChainSlot() { //qDebug() << debugString() << "destroyed"; - clear(); + + m_effectSlots.clear(); + delete m_pControlClear; delete m_pControlNumEffects; delete m_pControlNumEffectSlots; @@ -112,310 +138,184 @@ EffectChainSlot::~EffectChainSlot() { it = m_channelInfoByName.erase(it); } - m_slots.clear(); - m_pEffectChain.clear(); + removeFromEngine(); } -QString EffectChainSlot::id() const { - if (m_pEffectChain) - return m_pEffectChain->id(); - return ""; -} +void EffectChainSlot::addToEngine() { + m_pEngineEffectChain = new EngineEffectChain(m_id, + m_pEffectsManager->registeredInputChannels(), + m_pEffectsManager->registeredOutputChannels()); + EffectsRequest* pRequest = new EffectsRequest(); + pRequest->type = EffectsRequest::ADD_EFFECT_CHAIN; + pRequest->AddEffectChain.signalProcessingStage = m_signalProcessingStage; + pRequest->AddEffectChain.pChain = m_pEngineEffectChain; + m_pEffectsManager->writeRequest(pRequest); -double EffectChainSlot::getSuperParameter() const { - return m_pControlChainSuperParameter->get(); -} + VERIFY_OR_DEBUG_ASSERT(!m_enabledInputChannels.size()); -void EffectChainSlot::setSuperParameter(double value, bool force) { - m_pControlChainSuperParameter->set(value); - slotControlChainSuperParameter(value, force); + sendParameterUpdate(); } -void EffectChainSlot::setSuperParameterDefaultValue(double value) { - m_pControlChainSuperParameter->setDefaultValue(value); +void EffectChainSlot::removeFromEngine() { + VERIFY_OR_DEBUG_ASSERT(m_effectSlots.isEmpty()) { + m_effectSlots.clear(); + } + + EffectsRequest* pRequest = new EffectsRequest(); + pRequest->type = EffectsRequest::REMOVE_EFFECT_CHAIN; + pRequest->RemoveEffectChain.signalProcessingStage = m_signalProcessingStage; + pRequest->RemoveEffectChain.pChain = m_pEngineEffectChain; + m_pEffectsManager->writeRequest(pRequest); + + m_pEngineEffectChain = nullptr; } -void EffectChainSlot::slotChainNameChanged(const QString&) { - emit(updated()); +const QString& EffectChainSlot::name() const { + return m_name; } -void EffectChainSlot::slotChainEnabledChanged(bool bEnabled) { - m_pControlChainEnabled->set(bEnabled); +void EffectChainSlot::setName(const QString& name) { + m_name = name; emit(updated()); } -void EffectChainSlot::slotChainMixChanged(double mix) { - m_pControlChainMix->set(mix); - emit(updated()); +QString EffectChainSlot::description() const { + return m_description; } -void EffectChainSlot::slotChainMixModeChanged(EffectChainMixMode mixMode) { - m_pControlChainMixMode->set(static_cast(mixMode)); +void EffectChainSlot::setDescription(const QString& description) { + m_description = description; emit(updated()); } -void EffectChainSlot::slotChainChannelStatusChanged(const QString& group, - bool enabled) { - ChannelInfo* pInfo = m_channelInfoByName.value(group, NULL); - if (pInfo != NULL && pInfo->pEnabled != NULL) { - pInfo->pEnabled->set(enabled); - emit(updated()); - } +void EffectChainSlot::loadEffect(const unsigned int iEffectSlotNumber, + const EffectManifestPointer pManifest, + std::unique_ptr pProcessor) { + m_effectSlots[iEffectSlotNumber]->loadEffect(pManifest, std::move(pProcessor), + m_enabledInputChannels); } -void EffectChainSlot::slotChainEffectChanged(unsigned int effectSlotNumber, - bool shouldEmit) { - //qDebug() << debugString() << "slotChainEffectChanged" << effectSlotNumber; - if (m_pEffectChain) { - const QList effects = m_pEffectChain->effects(); - EffectSlotPointer pSlot; - EffectPointer pEffect; - - if (effects.size() > m_slots.size()) { - qWarning() << debugString() << "has too few slots for effect"; - } - - if (effectSlotNumber < (unsigned) m_slots.size()) { - pSlot = m_slots.at(effectSlotNumber); - } - if (effectSlotNumber < (unsigned) effects.size()) { - pEffect = effects.at(effectSlotNumber); - } - if (pSlot != nullptr) { - pSlot->loadEffect(pEffect, m_pEffectRack->isAdoptMetaknobValueEnabled()); - } - - m_pControlNumEffects->forceSet(math_min( - static_cast(m_slots.size()), - m_pEffectChain->numEffects())); - - if (shouldEmit) { - emit(updated()); +void EffectChainSlot::hideEffectParameter(EffectManifestPointer pManifest, + const unsigned int position) { + for (EffectSlotPointer pEffectSlot : m_effectSlots) { + if (pEffectSlot->getManifest() == pManifest) { + pEffectSlot->hideEffectParameter(position); } } } -void EffectChainSlot::loadEffectChainToSlot(EffectChainPointer pEffectChain) { - //qDebug() << debugString() << "loadEffectChainToSlot" << (pEffectChain ? pEffectChain->id() : "(null)"); - clear(); - - if (pEffectChain) { - m_pEffectChain = pEffectChain; - - connect(m_pEffectChain.data(), SIGNAL(effectChanged(unsigned int)), - this, SLOT(slotChainEffectChanged(unsigned int))); - connect(m_pEffectChain.data(), SIGNAL(nameChanged(const QString&)), - this, SLOT(slotChainNameChanged(const QString&))); - connect(m_pEffectChain.data(), SIGNAL(enabledChanged(bool)), - this, SLOT(slotChainEnabledChanged(bool))); - connect(m_pEffectChain.data(), SIGNAL(mixChanged(double)), - this, SLOT(slotChainMixChanged(double))); - connect(m_pEffectChain.data(), SIGNAL(mixModeChanged(EffectChainMixMode)), - this, SLOT(slotChainMixModeChanged(EffectChainMixMode))); - connect(m_pEffectChain.data(), SIGNAL(channelStatusChanged(const QString&, bool)), - this, SLOT(slotChainChannelStatusChanged(const QString&, bool))); - - m_pControlChainLoaded->forceSet(true); - m_pControlChainMixMode->set( - static_cast(m_pEffectChain->mixMode())); - - // Mix and enabled channels are persistent properties of the chain slot, - // not of the chain. Propagate the current settings to the chain. - m_pEffectChain->setMix(m_pControlChainMix->get()); - m_pEffectChain->setEnabled(m_pControlChainEnabled->get() > 0.0); - - // Don't emit because we will below. - for (int i = 0; i < m_slots.size(); ++i) { - slotChainEffectChanged(i, false); +void EffectChainSlot::setEffectParameterPosition(EffectManifestPointer pManifest, + const unsigned int parameterId, const unsigned int position) { + for (EffectSlotPointer pEffectSlot : m_effectSlots) { + if (pEffectSlot->getManifest() == pManifest) { + pEffectSlot->setEffectParameterPosition(parameterId, position); } } +} - emit(effectChainLoaded(pEffectChain)); - emit(updated()); +void EffectChainSlot::sendParameterUpdate() { + EffectsRequest* pRequest = new EffectsRequest(); + pRequest->type = EffectsRequest::SET_EFFECT_CHAIN_PARAMETERS; + pRequest->pTargetChain = m_pEngineEffectChain; + pRequest->SetEffectChainParameters.enabled = m_pControlChainEnabled->get(); + pRequest->SetEffectChainParameters.mix_mode = static_cast( + static_cast(m_pControlChainMixMode->get())); + pRequest->SetEffectChainParameters.mix = m_pControlChainMix->get(); + m_pEffectsManager->writeRequest(pRequest); } -void EffectChainSlot::updateRoutingSwitches() { - VERIFY_OR_DEBUG_ASSERT(m_pEffectChain) { - return; - } - for (const ChannelInfo* pChannelInfo : m_channelInfoByName) { - if (pChannelInfo->pEnabled->toBool()) { - m_pEffectChain->enableForInputChannel(pChannelInfo->handle_group); - } else { - m_pEffectChain->disableForInputChannel(pChannelInfo->handle_group); - } - } +QString EffectChainSlot::id() const { + return m_id; } -EffectChainPointer EffectChainSlot::getEffectChain() const { - return m_pEffectChain; +QString EffectChainSlot::group() const { + return m_group; } -EffectChainPointer EffectChainSlot::getOrCreateEffectChain( - EffectsManager* pEffectsManager) { - if (!m_pEffectChain) { - EffectChainPointer pEffectChain( - new EffectChain(pEffectsManager, QString())); - //: Name for an empty effect chain, that is created after eject - pEffectChain->setName(tr("Empty Chain")); - loadEffectChainToSlot(pEffectChain); - pEffectChain->addToEngine(m_pEffectRack->getEngineEffectRack(), m_iChainSlotNumber); - pEffectChain->updateEngineState(); - updateRoutingSwitches(); - } - return m_pEffectChain; +double EffectChainSlot::getSuperParameter() const { + return m_pControlChainSuperParameter->get(); } -void EffectChainSlot::clear() { - // Stop listening to signals from any loaded effect - if (m_pEffectChain) { - m_pEffectChain->removeFromEngine(m_pEffectRack->getEngineEffectRack(), - m_iChainSlotNumber); - for (EffectSlotPointer pSlot : m_slots) { - pSlot->clear(); - } - m_pEffectChain->disconnect(this); - m_pEffectChain.clear(); - } - m_pControlNumEffects->forceSet(0.0); - m_pControlChainLoaded->forceSet(0.0); - m_pControlChainMixMode->set( - static_cast(EffectChainMixMode::DrySlashWet)); - emit(updated()); +void EffectChainSlot::setSuperParameter(double value, bool force) { + m_pControlChainSuperParameter->set(value); + slotControlChainSuperParameter(value, force); } -unsigned int EffectChainSlot::numSlots() const { - //qDebug() << debugString() << "numSlots"; - return m_slots.size(); +void EffectChainSlot::setSuperParameterDefaultValue(double value) { + m_pControlChainSuperParameter->setDefaultValue(value); } EffectSlotPointer EffectChainSlot::addEffectSlot(const QString& group) { - //qDebug() << debugString() << "addEffectSlot" << group; - - EffectSlot* pEffectSlot = new EffectSlot(group, m_iChainSlotNumber, - m_slots.size()); - // Rebroadcast effectLoaded signals - connect(pEffectSlot, SIGNAL(effectLoaded(EffectPointer, unsigned int)), - this, SLOT(slotEffectLoaded(EffectPointer, unsigned int))); - connect(pEffectSlot, SIGNAL(clearEffect(unsigned int)), - this, SLOT(slotClearEffect(unsigned int))); - connect(pEffectSlot, SIGNAL(nextEffect(unsigned int, unsigned int, EffectPointer)), - this, SIGNAL(nextEffect(unsigned int, unsigned int, EffectPointer))); - connect(pEffectSlot, SIGNAL(prevEffect(unsigned int, unsigned int, EffectPointer)), - this, SIGNAL(prevEffect(unsigned int, unsigned int, EffectPointer))); - - EffectSlotPointer pSlot(pEffectSlot); - m_slots.append(pSlot); + // qDebug() << debugString() << "addEffectSlot" << group; + EffectSlotPointer pEffectSlot = EffectSlotPointer( + new EffectSlot(group, m_pEffectsManager, m_effectSlots.size(), m_pEngineEffectChain)); + + m_effectSlots.append(pEffectSlot); int numEffectSlots = m_pControlNumEffectSlots->get() + 1; m_pControlNumEffectSlots->forceSet(numEffectSlots); m_pControlChainFocusedEffect->setStates(numEffectSlots); - return pSlot; + return pEffectSlot; } -void EffectChainSlot::registerInputChannel(const ChannelHandleAndGroup& handle_group) { +void EffectChainSlot::registerInputChannel(const ChannelHandleAndGroup& handle_group, + const double initialValue) { VERIFY_OR_DEBUG_ASSERT(!m_channelInfoByName.contains(handle_group.name())) { return; } - double initialValue = 0.0; - int deckNumber; - if (PlayerManager::isDeckGroup(handle_group.name(), &deckNumber) && - (m_iChainSlotNumber + 1) == (unsigned) deckNumber) { - initialValue = 1.0; - } ControlPushButton* pEnableControl = new ControlPushButton( ConfigKey(m_group, QString("group_%1_enable").arg(handle_group.name())), true, initialValue); pEnableControl->setButtonMode(ControlPushButton::POWERWINDOW); + if (pEnableControl->toBool()) { + enableForInputChannel(handle_group); + } ChannelInfo* pInfo = new ChannelInfo(handle_group, pEnableControl); m_channelInfoByName[handle_group.name()] = pInfo; - m_channelStatusMapper.setMapping(pEnableControl, handle_group.name()); - connect(pEnableControl, SIGNAL(valueChanged(double)), - &m_channelStatusMapper, SLOT(map())); -} - -void EffectChainSlot::slotEffectLoaded(EffectPointer pEffect, unsigned int slotNumber) { - // const int is a safe read... don't bother locking - emit(effectLoaded(pEffect, m_iChainSlotNumber, slotNumber)); -} -void EffectChainSlot::slotClearEffect(unsigned int iEffectSlotNumber) { - if (m_pEffectChain) { - m_pEffectChain->removeEffect(iEffectSlotNumber); - } + // m_channelStatusMapper will emit a mapped(handle_group.name()) signal whenever + // the valueChanged(double) signal is emitted by pEnableControl + m_channelStatusMapper.setMapping(pEnableControl, handle_group.name()); + connect(pEnableControl, &ControlObject::valueChanged, + &m_channelStatusMapper, static_cast(&QSignalMapper::map)); } EffectSlotPointer EffectChainSlot::getEffectSlot(unsigned int slotNumber) { //qDebug() << debugString() << "getEffectSlot" << slotNumber; - if (slotNumber >= static_cast(m_slots.size())) { + if (slotNumber >= static_cast(m_effectSlots.size())) { qWarning() << "WARNING: slotNumber out of range"; return EffectSlotPointer(); } - return m_slots[slotNumber]; + return m_effectSlots[slotNumber]; } void EffectChainSlot::slotControlClear(double v) { - if (v > 0) { - clear(); - } -} - -void EffectChainSlot::slotControlChainEnabled(double v) { - //qDebug() << debugString() << "slotControlChainEnabled" << v; - if (m_pEffectChain) { - m_pEffectChain->setEnabled(v > 0); - } -} - -void EffectChainSlot::slotControlChainMix(double v) { - //qDebug() << debugString() << "slotControlChainMix" << v; - - // Clamp to [0.0, 1.0] - if (v < 0.0 || v > 1.0) { - qWarning() << debugString() << "value out of limits"; - v = math_clamp(v, 0.0, 1.0); - m_pControlChainMix->set(v); - } - if (m_pEffectChain) { - m_pEffectChain->setMix(v); + for (EffectSlotPointer pEffectSlot : m_effectSlots) { + pEffectSlot->slotClear(v); } } void EffectChainSlot::slotControlChainSuperParameter(double v, bool force) { - //qDebug() << debugString() << "slotControlChainSuperParameter" << v; - - // Clamp to [0.0, 1.0] - if (v < 0.0 || v > 1.0) { - qWarning() << debugString() << "value out of limits"; - v = math_clamp(v, 0.0, 1.0); - m_pControlChainSuperParameter->set(v); - } - for (const auto& pSlot : m_slots) { - pSlot->setMetaParameter(v, force); - } -} + // qDebug() << debugString() << "slotControlChainSuperParameter" << v; -void EffectChainSlot::slotControlChainMixMode(double v) { - // Intermediate cast to integer is needed for VC++. - EffectChainMixMode type = static_cast(int(v)); - (void)v; // this avoids a false warning with g++ 4.8.1 - if (m_pEffectChain && type < EffectChainMixMode::NumMixModes) { - m_pEffectChain->setMixMode(type); + m_pControlChainSuperParameter->set(v); + for (const auto& pEffectSlot : m_effectSlots) { + pEffectSlot->setMetaParameter(v, force); } } void EffectChainSlot::slotControlChainSelector(double v) { - //qDebug() << debugString() << "slotControlChainSelector" << v; - if (v > 0) { - emit(nextChain(m_iChainSlotNumber, m_pEffectChain)); - } else if (v < 0) { - emit(prevChain(m_iChainSlotNumber, m_pEffectChain)); - } +// qDebug() << debugString() << "slotControlChainSelector" << v; +// if (v > 0) { +// emit(nextChain(m_iChainSlotNumber, m_pEffectChain)); +// } else if (v < 0) { +// emit(prevChain(m_iChainSlotNumber, m_pEffectChain)); +// } } void EffectChainSlot::slotControlChainNextPreset(double v) { - //qDebug() << debugString() << "slotControlChainNextPreset" << v; + // qDebug() << debugString() << "slotControlChainNextPreset" << v; if (v > 0) { slotControlChainSelector(1); } @@ -429,81 +329,132 @@ void EffectChainSlot::slotControlChainPrevPreset(double v) { } void EffectChainSlot::slotChannelStatusChanged(const QString& group) { - if (m_pEffectChain) { - ChannelInfo* pChannelInfo = m_channelInfoByName.value(group, NULL); - if (pChannelInfo != NULL && pChannelInfo->pEnabled != NULL) { - bool bEnable = pChannelInfo->pEnabled->toBool(); - if (bEnable) { - m_pEffectChain->enableForInputChannel(pChannelInfo->handle_group); - } else { - m_pEffectChain->disableForInputChannel(pChannelInfo->handle_group); - } + ChannelInfo* pChannelInfo = m_channelInfoByName.value(group, NULL); + if (pChannelInfo != NULL && pChannelInfo->pEnabled != NULL) { + bool bEnable = pChannelInfo->pEnabled->toBool(); + if (bEnable) { + enableForInputChannel(pChannelInfo->handle_group); + } else { + disableForInputChannel(pChannelInfo->handle_group); } } } -unsigned int EffectChainSlot::getChainSlotNumber() const { - return m_iChainSlotNumber; -} - -QDomElement EffectChainSlot::toXml(QDomDocument* doc) const { - QDomElement chainElement = doc->createElement(EffectXml::Chain); - if (m_pEffectChain == nullptr) { - // ejected chains are stored empty - return chainElement; +void EffectChainSlot::enableForInputChannel(const ChannelHandleAndGroup& handle_group) { + if (m_enabledInputChannels.contains(handle_group)) { + return; } - XmlParse::addElement(*doc, chainElement, EffectXml::ChainId, - m_pEffectChain->id()); - XmlParse::addElement(*doc, chainElement, EffectXml::ChainName, - m_pEffectChain->name()); - XmlParse::addElement(*doc, chainElement, EffectXml::ChainDescription, - m_pEffectChain->description()); - XmlParse::addElement(*doc, chainElement, EffectXml::ChainMixMode, - EffectChain::mixModeToString( - static_cast( - static_cast(m_pControlChainMixMode->get())))); - XmlParse::addElement(*doc, chainElement, EffectXml::ChainSuperParameter, - QString::number(m_pControlChainSuperParameter->get())); - - QDomElement effectsElement = doc->createElement(EffectXml::EffectsRoot); - for (const auto& pEffectSlot : m_slots) { - QDomElement effectNode; - if (pEffectSlot->getEffect()) { - effectNode = pEffectSlot->toXml(doc); + EffectsRequest* request = new EffectsRequest(); + request->type = EffectsRequest::ENABLE_EFFECT_CHAIN_FOR_INPUT_CHANNEL; + request->pTargetChain = m_pEngineEffectChain; + request->EnableInputChannelForChain.pChannelHandle = &handle_group.handle(); + + // Allocate EffectStates here in the main thread to avoid allocating + // memory in the realtime audio callback thread. Pointers to the + // EffectStates are passed to the EffectRequest and the EffectProcessorImpls + // store the pointers. The containers of EffectState* pointers get deleted + // by ~EffectsRequest, but the EffectStates are managed by EffectProcessorImpl. + auto pEffectStatesMapArray = new EffectStatesMapArray; + + //TODO: get actual configuration of engine + const mixxx::EngineParameters bufferParameters( + mixxx::AudioSignal::SampleRate(96000), + MAX_BUFFER_LEN / mixxx::kEngineChannelCount); + + // TODO: Simplify by defining a method to create an EffectState for the input channel + for (int i = 0; i < m_effectSlots.size(); ++i) { + auto& statesMap = (*pEffectStatesMapArray)[i]; + if (m_effectSlots[i]->isLoaded()) { + for (const auto& outputChannel : m_pEffectsManager->registeredOutputChannels()) { + if (kEffectDebugOutput) { + qDebug() << debugString() << "EffectChain::enableForInputChannel creating EffectState for input" << handle_group << "output" << outputChannel; + } + statesMap.insert(outputChannel.handle(), + m_effectSlots[i]->createState(bufferParameters)); + } } else { - // Create empty element to ensure effects stay in order - // if there are empty slots before loaded slots. - effectNode = doc->createElement(EffectXml::Effect); + for (EffectState* pState : statesMap) { + if (pState != nullptr) { + delete pState; + } + } + statesMap.clear(); } - effectsElement.appendChild(effectNode); } - chainElement.appendChild(effectsElement); + request->EnableInputChannelForChain.pEffectStatesMapArray = pEffectStatesMapArray; - return chainElement; + m_pEffectsManager->writeRequest(request); + + m_enabledInputChannels.insert(handle_group); } -void EffectChainSlot::loadChainSlotFromXml(const QDomElement& effectChainElement) { - if (!effectChainElement.hasChildNodes()) { +void EffectChainSlot::disableForInputChannel(const ChannelHandleAndGroup& handle_group) { + if (!m_enabledInputChannels.remove(handle_group)) { return; } - // FIXME: mix mode is set in EffectChain::createFromXml - - m_pControlChainSuperParameter->set(XmlParse::selectNodeDouble( - effectChainElement, - EffectXml::ChainSuperParameter)); - - QDomElement effectsElement = XmlParse::selectElement(effectChainElement, - EffectXml::EffectsRoot); - QDomNodeList effectsNodeList = effectsElement.childNodes(); - for (int i = 0; i < m_slots.size(); ++i) { - if (m_slots[i] != nullptr) { - QDomNode effectNode = effectsNodeList.at(i); - if (effectNode.isElement()) { - QDomElement effectElement = effectNode.toElement(); - m_slots[i]->loadEffectSlotFromXml(effectElement); - } - } - } + EffectsRequest* request = new EffectsRequest(); + request->type = EffectsRequest::DISABLE_EFFECT_CHAIN_FOR_INPUT_CHANNEL; + request->pTargetChain = m_pEngineEffectChain; + request->DisableInputChannelForChain.pChannelHandle = &handle_group.handle(); + m_pEffectsManager->writeRequest(request); +} + +QDomElement EffectChainSlot::toXml(QDomDocument* doc) const { + QDomElement chainElement = doc->createElement(EffectXml::Chain); + + // XmlParse::addElement(*doc, chainElement, EffectXml::ChainId, + // m_pEffectChain->id()); + // XmlParse::addElement(*doc, chainElement, EffectXml::ChainName, + // m_pEffectChain->name()); + // XmlParse::addElement(*doc, chainElement, EffectXml::ChainDescription, + // m_pEffectChain->description()); + // XmlParse::addElement(*doc, chainElement, EffectXml::ChainMixMode, + // EffectChain::mixModeToString( + // static_cast( + // static_cast(m_pControlChainMixMode->get())))); + // XmlParse::addElement(*doc, chainElement, EffectXml::ChainSuperParameter, + // QString::number(m_pControlChainSuperParameter->get())); + + // QDomElement effectsElement = doc->createElement(EffectXml::EffectsRoot); + // for (const auto& pEffectSlot : m_effectSlots) { + // QDomElement effectNode; + // if (pEffectSlot->getEffect()) { + // effectNode = pEffectSlot->toXml(doc); + // } else { + // // Create empty element to ensure effects stay in order + // // if there are empty slots before loaded slots. + // effectNode = doc->createElement(EffectXml::Effect); + // } + // effectsElement.appendChild(effectNode); + // } + // chainElement.appendChild(effectsElement); + + return chainElement; +} + +void EffectChainSlot::loadChainSlotFromXml(const QDomElement& effectChainElement) { + // if (!effectChainElement.hasChildNodes()) { + // return; + // } + + // // FIXME: mix mode is set in EffectChain::createFromXml + + // m_pControlChainSuperParameter->set(XmlParse::selectNodeDouble( + // effectChainElement, + // EffectXml::ChainSuperParameter)); + + // QDomElement effectsElement = XmlParse::selectElement(effectChainElement, + // EffectXml::EffectsRoot); + // QDomNodeList effectsNodeList = effectsElement.childNodes(); + // for (int i = 0; i < m_effectSlots.size(); ++i) { + // if (m_effectSlots[i] != nullptr) { + // QDomNode effectNode = effectsNodeList.at(i); + // if (effectNode.isElement()) { + // QDomElement effectElement = effectNode.toElement(); + // m_effectSlots[i]->loadEffectSlotFromXml(effectElement); + // } + // } + // } } diff --git a/src/effects/effectchainslot.h b/src/effects/effectchainslot.h index cc869830fc0..91f0e5d7005 100644 --- a/src/effects/effectchainslot.h +++ b/src/effects/effectchainslot.h @@ -5,47 +5,46 @@ #include #include #include +#include +#include "control/controlobject.h" +#include "effects/defs.h" #include "engine/channelhandle.h" #include "util/class.h" -#include "effects/effectchain.h" +#include "util/memory.h" -class ControlObject; class ControlPushButton; class ControlEncoder; class EffectChainSlot; +class EffectsManager; +class EffectProcessor; +class EngineEffectChain; class EffectChainSlot : public QObject { Q_OBJECT public: - EffectChainSlot(EffectRack* pRack, - const QString& group, - const unsigned int iChainNumber); + EffectChainSlot(const QString& group, + EffectsManager* pEffectsManager, + SignalProcessingStage stage = SignalProcessingStage::Postfader, + const QString& id = QString()); virtual ~EffectChainSlot(); // Get the ID of the loaded EffectChain QString id() const; + QString group() const; - unsigned int numSlots() const; - EffectSlotPointer addEffectSlot(const QString& group); EffectSlotPointer getEffectSlot(unsigned int slotNumber); - void loadEffectChainToSlot(EffectChainPointer pEffectChain); - void updateRoutingSwitches(); - EffectChainPointer getEffectChain() const; - EffectChainPointer getOrCreateEffectChain(EffectsManager* pEffectsManager); - - void registerInputChannel(const ChannelHandleAndGroup& handle_group); + void registerInputChannel(const ChannelHandleAndGroup& handle_group, + const double initialValue = 0.0); + QSet getActiveChannels() const { + return m_enabledInputChannels; + } double getSuperParameter() const; void setSuperParameter(double value, bool force = false); void setSuperParameterDefaultValue(double value); - // Unload the loaded EffectChain. - void clear(); - - unsigned int getChainSlotNumber() const; - const QString& getGroup() const { return m_group; } @@ -53,64 +52,80 @@ class EffectChainSlot : public QObject { QDomElement toXml(QDomDocument* doc) const; void loadChainSlotFromXml(const QDomElement& effectChainElement); - signals: - // Indicates that the effect pEffect has been loaded into slotNumber of - // EffectChainSlot chainNumber. pEffect may be an invalid pointer, which - // indicates that a previously loaded effect was removed from the slot. - void effectLoaded(EffectPointer pEffect, unsigned int chainNumber, - unsigned int slotNumber); + // Get the human-readable name of the EffectChain + const QString& name() const; + void setName(const QString& name); + + // Get the human-readable description of the EffectChain + QString description() const; + void setDescription(const QString& description); + + static QString mixModeToString(EffectChainMixMode type) { + switch (type) { + case EffectChainMixMode::DrySlashWet: + return "DRY/WET"; + case EffectChainMixMode::DryPlusWet: + return "DRY+WET"; + default: + return "UNKNOWN"; + } + } + static EffectChainMixMode mixModeFromString(const QString& typeStr) { + if (typeStr == "DRY/WET") { + return EffectChainMixMode::DrySlashWet; + } else if (typeStr == "DRY+WET") { + return EffectChainMixMode::DryPlusWet; + } else { + return EffectChainMixMode::NumMixModes; + } + } - // Indicates that the given EffectChain was loaded into this - // EffectChainSlot - void effectChainLoaded(EffectChainPointer pEffectChain); + virtual void loadEffect(const unsigned int iEffectSlotNumber, + const EffectManifestPointer pManifest, + std::unique_ptr pProcessor); + // TODO : Remove these functions once the GUI for parameter rearrangement is implemented + void hideEffectParameter(EffectManifestPointer pManifest, + const unsigned int position); + void setEffectParameterPosition(EffectManifestPointer pManifest, + const unsigned int parameterId, const unsigned int position); + + signals: // Signal that whoever is in charge of this EffectChainSlot should load the // next EffectChain into it. void nextChain(unsigned int iChainSlotNumber, - EffectChainPointer pEffectChain); + EffectChainSlotPointer pEffectChain); // Signal that whoever is in charge of this EffectChainSlot should load the // previous EffectChain into it. void prevChain(unsigned int iChainSlotNumber, - EffectChainPointer pEffectChain); + EffectChainSlotPointer pEffectChain); // Signal that whoever is in charge of this EffectChainSlot should clear // this EffectChain (by removing the chain from this EffectChainSlot). - void clearChain(unsigned int iChainNumber, EffectChainPointer pEffectChain); - - // Signal that whoever is in charge of this EffectChainSlot should load the - // next Effect into the specified EffectSlot. - void nextEffect(unsigned int iChainSlotNumber, - unsigned int iEffectSlotNumber, - EffectPointer pEffect); - - // Signal that whoever is in charge of this EffectChainSlot should load the - // previous Effect into the specified EffectSlot. - void prevEffect(unsigned int iChainSlotNumber, - unsigned int iEffectSlotNumber, - EffectPointer pEffect); + void clearChain(unsigned int iChainNumber, EffectChainSlotPointer pEffectChain); // Signal that indicates that the EffectChainSlot has been updated. void updated(); + protected slots: + void sendParameterUpdate(); + void slotControlChainSuperParameter(double v, bool force = false); - private slots: - void slotChainEffectChanged(unsigned int effectSlotNumber, bool shouldEmit=true); - void slotChainNameChanged(const QString& name); - void slotChainEnabledChanged(bool enabled); - void slotChainMixChanged(double mix); - void slotChainMixModeChanged(EffectChainMixMode mixMode); - void slotChainChannelStatusChanged(const QString& group, bool enabled); + protected: + EffectSlotPointer addEffectSlot(const QString& group); + + // Activates EffectChain processing for the provided channel. + void enableForInputChannel(const ChannelHandleAndGroup& handle_group); + void disableForInputChannel(const ChannelHandleAndGroup& handle_group); - void slotEffectLoaded(EffectPointer pEffect, unsigned int slotNumber); - // Clears the effect in the given position in the loaded EffectChain. - void slotClearEffect(unsigned int iEffectSlotNumber); + EffectsManager* m_pEffectsManager; + ControlObject* m_pControlChainMix; + ControlObject* m_pControlChainSuperParameter; + QList m_effectSlots; + private slots: void slotControlClear(double v); - void slotControlChainEnabled(double v); - void slotControlChainMix(double v); - void slotControlChainSuperParameter(double v, bool force = false); - void slotControlChainMixMode(double v); void slotControlChainSelector(double v); void slotControlChainNextPreset(double v); void slotControlChainPrevPreset(double v); @@ -121,19 +136,16 @@ class EffectChainSlot : public QObject { return QString("EffectChainSlot(%1)").arg(m_group); } - const unsigned int m_iChainSlotNumber; - const QString m_group; - EffectRack* m_pEffectRack; + void addToEngine(); + void removeFromEngine(); - EffectChainPointer m_pEffectChain; + const QString m_group; ControlPushButton* m_pControlClear; ControlObject* m_pControlNumEffects; ControlObject* m_pControlNumEffectSlots; ControlObject* m_pControlChainLoaded; ControlPushButton* m_pControlChainEnabled; - ControlObject* m_pControlChainMix; - ControlObject* m_pControlChainSuperParameter; ControlPushButton* m_pControlChainMixMode; ControlEncoder* m_pControlChainSelector; ControlPushButton* m_pControlChainNextPreset; @@ -164,11 +176,15 @@ class EffectChainSlot : public QObject { ChannelHandleAndGroup handle_group; ControlObject* pEnabled; }; - QMap m_channelInfoByName; - QList m_slots; + QMap m_channelInfoByName; QSignalMapper m_channelStatusMapper; - + QString m_id; + QString m_name; + QString m_description; + SignalProcessingStage m_signalProcessingStage; + QSet m_enabledInputChannels; + EngineEffectChain* m_pEngineEffectChain; DISALLOW_COPY_AND_ASSIGN(EffectChainSlot); }; diff --git a/src/effects/effectinstantiator.h b/src/effects/effectinstantiator.h deleted file mode 100644 index 483dd4cc2f7..00000000000 --- a/src/effects/effectinstantiator.h +++ /dev/null @@ -1,53 +0,0 @@ -#ifndef EFFECTINSTANTIATOR_H -#define EFFECTINSTANTIATOR_H - -#include -#include "effects/effectmanifest.h" -#include "effects/effectprocessor.h" - -#ifdef __LILV__ -#include "effects/lv2/lv2effectprocessor.h" -#endif /* __LILV__ */ - -class EffectInstantiator { - public: - virtual ~EffectInstantiator() {} - virtual EffectProcessor* instantiate(EngineEffect* pEngineEffect, - EffectManifestPointer pManifest) = 0; -}; -typedef QSharedPointer EffectInstantiatorPointer; - -template -class EffectProcessorInstantiator : public EffectInstantiator { - public: - EffectProcessor* instantiate(EngineEffect* pEngineEffect, - EffectManifestPointer pManifest) { - Q_UNUSED(pManifest); - return new T(pEngineEffect); - } -}; - -#ifdef __LILV__ -class LV2EffectProcessorInstantiator : public EffectInstantiator { - public: - LV2EffectProcessorInstantiator(const LilvPlugin* plugin, - QList audioPortIndices, - QList controlPortIndices) - : m_pPlugin(plugin), - m_audioPortIndices(audioPortIndices), - m_controlPortIndices(controlPortIndices) { } - - EffectProcessor* instantiate(EngineEffect* pEngineEffect, - EffectManifestPointer pManifest) { - return new LV2EffectProcessor(pEngineEffect, pManifest, m_pPlugin, - m_audioPortIndices, m_controlPortIndices); - } - private: - const LilvPlugin* m_pPlugin; - const QList m_audioPortIndices; - const QList m_controlPortIndices; - -}; -#endif /* __LILV__ */ - -#endif /* EFFECTINSTANTIATOR_H */ diff --git a/src/effects/effectknobparameterslot.cpp b/src/effects/effectknobparameterslot.cpp new file mode 100644 index 00000000000..ec0c644c5af --- /dev/null +++ b/src/effects/effectknobparameterslot.cpp @@ -0,0 +1,309 @@ +#include + +#include "effects/effectknobparameterslot.h" + +#include "effects/effectslot.h" +#include "effects/effectparameter.h" +#include "control/controleffectknob.h" +#include "effects/effectxmlelements.h" +#include "control/controlobject.h" +#include "control/controlpushbutton.h" +#include "controllers/softtakeover.h" +#include "util/xml.h" + +EffectKnobParameterSlot::EffectKnobParameterSlot(const QString& group, const unsigned int iParameterSlotNumber) + : EffectParameterSlotBase(group, iParameterSlotNumber, + EffectManifestParameter::ParameterType::KNOB) { + QString itemPrefix = formatItemPrefix(iParameterSlotNumber); + + m_pControlValue = new ControlEffectKnob( + ConfigKey(m_group, itemPrefix)); + connect(m_pControlValue, &ControlObject::valueChanged, + this, &EffectKnobParameterSlot::slotValueChanged); + + m_pControlLoaded = new ControlObject( + ConfigKey(m_group, itemPrefix + QString("_loaded"))); + m_pControlLoaded->setReadOnly(); + + m_pControlType = new ControlObject( + ConfigKey(m_group, itemPrefix + QString("_type"))); + m_pControlType->setReadOnly(); + + m_pControlLinkType = new ControlPushButton( + ConfigKey(m_group, itemPrefix + QString("_link_type"))); + m_pControlLinkType->setButtonMode(ControlPushButton::TOGGLE); + m_pControlLinkType->setStates( + static_cast(EffectManifestParameter::LinkType::NUM_LINK_TYPES)); + m_pControlLinkType->connectValueChangeRequest( + this, &EffectKnobParameterSlot::slotLinkTypeChanging); + + m_pControlLinkInverse = new ControlPushButton( + ConfigKey(m_group, itemPrefix + QString("_link_inverse"))); + m_pControlLinkInverse->setButtonMode(ControlPushButton::TOGGLE); + connect(m_pControlLinkInverse, &ControlObject::valueChanged, + this, &EffectKnobParameterSlot::slotLinkInverseChanged); + + m_pMetaknobSoftTakeover = new SoftTakeover(); + + clear(); +} + +EffectKnobParameterSlot::~EffectKnobParameterSlot() { + // qDebug() << debugString() << "destroyed"; + delete m_pControlValue; + // m_pControlLoaded and m_pControlType are deleted by ~EffectParameterSlotBase + delete m_pControlLinkType; + delete m_pControlLinkInverse; + delete m_pMetaknobSoftTakeover; +} + +void EffectKnobParameterSlot::loadParameter(EffectParameter* pEffectParameter) { + // qDebug() << debugString() << "loadParameter" << (pEffectSlot ? pEffectSlot->getManifest().name() : "(null)"); + clear(); + + VERIFY_OR_DEBUG_ASSERT(pEffectParameter->manifest()->parameterType() == + EffectManifestParameter::ParameterType::KNOB) { + return; + } + + m_pEffectParameter = pEffectParameter; + + if (m_pEffectParameter) { + m_pManifestParameter = m_pEffectParameter->manifest(); + + // qDebug() << debugString() << "Loading effect parameter" << m_pEffectParameter->name(); + double dValue = m_pEffectParameter->getValue(); + double dMinimum = m_pManifestParameter->getMinimum(); + double dMinimumLimit = dMinimum; // TODO(rryan) expose limit from EffectParameter + double dMaximum = m_pManifestParameter->getMaximum(); + double dMaximumLimit = dMaximum; // TODO(rryan) expose limit from EffectParameter + double dDefault = m_pManifestParameter->getDefault(); + + // qDebug() << debugString() + // << QString("Val: %1 Min: %2 MinLimit: %3 Max: %4 MaxLimit: %5 Default: %6") + // .arg(dValue).arg(dMinimum).arg(dMinimumLimit).arg(dMaximum).arg(dMaximumLimit).arg(dDefault); + + EffectManifestParameter::ValueScaler type = m_pManifestParameter->valueScaler(); + m_pControlValue->setBehaviour(type, dMinimum, dMaximum); + m_pControlValue->setDefaultValue(dDefault); + m_pControlValue->set(dValue); + // TODO(rryan) expose this from EffectParameter + m_pControlType->forceSet(static_cast(type)); + // Default loaded parameters to loaded and unlinked + m_pControlLoaded->forceSet(1.0); + + m_pControlLinkType->set( + static_cast(m_pManifestParameter->defaultLinkType())); + m_pControlLinkInverse->set( + static_cast(m_pManifestParameter->defaultLinkInversion())); + } + + emit(updated()); +} + +void EffectKnobParameterSlot::clear() { + //qDebug() << debugString() << "clear"; + if (m_pEffectParameter) { + m_pEffectParameter = nullptr; + m_pManifestParameter.clear(); + } + + m_pControlLoaded->forceSet(0.0); + m_pControlValue->set(0.0); + m_pControlValue->setDefaultValue(0.0); + m_pControlType->forceSet(0.0); + m_pControlLinkType->setAndConfirm( + static_cast(EffectManifestParameter::LinkType::NONE)); + m_pMetaknobSoftTakeover->setThreshold(SoftTakeover::kDefaultTakeoverThreshold); + m_pControlLinkInverse->set(0.0); + emit(updated()); +} + +void EffectKnobParameterSlot::slotParameterValueChanged(double value) { + //qDebug() << debugString() << "slotParameterValueChanged" << value.toDouble(); + m_pControlValue->set(value); +} + +void EffectKnobParameterSlot::slotLinkTypeChanging(double v) { + m_pMetaknobSoftTakeover->ignoreNext(); + EffectManifestParameter::LinkType newType = + static_cast( + static_cast(v)); + if (newType == EffectManifestParameter::LinkType::LINKED_LEFT || + newType == EffectManifestParameter::LinkType::LINKED_RIGHT || + newType == EffectManifestParameter::LinkType::LINKED_LEFT_RIGHT) { + double neutral = m_pManifestParameter->neutralPointOnScale(); + if (neutral > 0.0 && neutral < 1.0) { + // Knob is already a split knob, meaning it has a positive and + // negative effect if it's twisted above the neutral point or + // below the neutral point. + // Toggle back to 0 + newType = EffectManifestParameter::LinkType::NONE; + } + } + if (newType == EffectManifestParameter::LinkType::LINKED_LEFT || + newType == EffectManifestParameter::LinkType::LINKED_RIGHT) { + m_pMetaknobSoftTakeover->setThreshold( + SoftTakeover::kDefaultTakeoverThreshold * 2.0); + } else { + m_pMetaknobSoftTakeover->setThreshold(SoftTakeover::kDefaultTakeoverThreshold); + } + m_pControlLinkType->setAndConfirm(static_cast(newType)); +} + +void EffectKnobParameterSlot::slotLinkInverseChanged(double v) { + Q_UNUSED(v); + m_pMetaknobSoftTakeover->ignoreNext(); +} + +void EffectKnobParameterSlot::onEffectMetaParameterChanged(double parameter, bool force) { + m_dChainParameter = parameter; + if (m_pEffectParameter != nullptr) { + // Intermediate cast to integer is needed for VC++. + EffectManifestParameter::LinkType type = + static_cast( + static_cast(m_pControlLinkType->get())); + + bool inverse = m_pControlLinkInverse->toBool(); + double neutral = m_pManifestParameter->neutralPointOnScale(); + + switch (type) { + case EffectManifestParameter::LinkType::LINKED: + if (parameter < 0.0 || parameter > 1.0) { + return; + } + if (neutral > 0.0 && neutral < 1.0) { + if (inverse) { + // the neutral position must stick where it is + neutral = 1.0 - neutral; + } + // Knob is already a split knob + // Match to center position of meta knob + if (parameter <= 0.5) { + parameter /= 0.5; + parameter *= neutral; + } else { + parameter -= 0.5; + parameter /= 0.5; + parameter *= 1 - neutral; + parameter += neutral; + } + } + break; + case EffectManifestParameter::LinkType::LINKED_LEFT: + if (parameter >= 0.5 && parameter <= 1.0) { + parameter = 1; + } else if (parameter >= 0.0 && parameter <= 0.5) { + parameter *= 2; + } else { + return; + } + break; + case EffectManifestParameter::LinkType::LINKED_RIGHT: + if (parameter >= 0.5 && parameter <= 1.0) { + parameter -= 0.5; + parameter *= 2; + } else if (parameter >= 0.0 && parameter < 0.5) { + parameter = 0.0; + } else { + return; + } + break; + case EffectManifestParameter::LinkType::LINKED_LEFT_RIGHT: + if (parameter >= 0.5 && parameter <= 1.0) { + parameter -= 0.5; + parameter *= 2; + } else if (parameter >= 0.0 && parameter < 0.5) { + parameter *= 2; + parameter = 1.0 - parameter; + } else { + return; + } + break; + case EffectManifestParameter::LinkType::NONE: + default: + return; + } + + if (inverse) { + parameter = 1.0 - parameter; + } + + //qDebug() << "onEffectMetaParameterChanged" << debugString() << parameter << "force?" << force; + if (force) { + m_pControlValue->setParameterFrom(parameter, NULL); + // This ensures that softtakover is in sync for following updates + m_pMetaknobSoftTakeover->ignore(m_pControlValue, parameter); + } else if (!m_pMetaknobSoftTakeover->ignore(m_pControlValue, parameter)) { + m_pControlValue->setParameterFrom(parameter, NULL); + } + } +} + +void EffectKnobParameterSlot::syncSofttakeover() { + double parameter = m_pControlValue->getParameter(); + m_pMetaknobSoftTakeover->ignore(m_pControlValue, parameter); +} + +double EffectKnobParameterSlot::getValueParameter() const { + return m_pControlValue->getParameter(); +} + +QDomElement EffectKnobParameterSlot::toXml(QDomDocument* doc) const { + QDomElement parameterElement; + // if (m_pEffectParameter != nullptr) { + // parameterElement = doc->createElement(EffectXml::Parameter); + // XmlParse::addElement(*doc, parameterElement, + // EffectXml::ParameterValue, + // QString::number(m_pControlValue->getParameter())); + // XmlParse::addElement(*doc, parameterElement, + // EffectXml::ParameterLinkType, + // EffectManifestParameter::LinkTypeToString( + // static_cast( + // static_cast(m_pControlLinkType->get())))); + // XmlParse::addElement(*doc, parameterElement, + // EffectXml::ParameterLinkInversion, + // QString::number(m_pControlLinkInverse->get())); + // } + + return parameterElement; +} + +void EffectKnobParameterSlot::loadParameterSlotFromXml(const QDomElement& parameterElement) { + // if (m_pEffectParameter == nullptr) { + // return; + // } + // if (!parameterElement.hasChildNodes()) { + // m_pControlValue->reset(); + // m_pControlLinkType->set( + // static_cast(m_pEffectParameter->getDefaultLinkType())); + // m_pControlLinkInverse->set( + // static_cast(m_pEffectParameter->getDefaultLinkInversion())); + // } else { + // // Need to use setParameterFrom(..., nullptr) here to + // // trigger valueChanged() signal emission and execute slotValueChanged() + // bool conversionWorked = false; + // double value = XmlParse::selectNodeDouble(parameterElement, + // EffectXml::ParameterValue, &conversionWorked); + // if (conversionWorked) { + // // Need to use setParameterFrom(..., nullptr) here to + // // trigger valueChanged() signal emission and execute slotValueChanged() + // m_pControlValue->setParameterFrom(value, nullptr); + // } + // // If the conversion failed, the default value is kept. + + // QString linkTypeString = XmlParse::selectNodeQString(parameterElement, + // EffectXml::ParameterLinkType); + // if (!linkTypeString.isEmpty()) { + // m_pControlLinkType->set(static_cast( + // EffectManifestParameter::LinkTypeFromString(linkTypeString))); + // } + + // conversionWorked = false; + // double linkInversion = XmlParse::selectNodeDouble(parameterElement, + // EffectXml::ParameterLinkInversion, &conversionWorked); + // if (conversionWorked) { + // m_pControlLinkInverse->set(linkInversion); + // } + // } +} diff --git a/src/effects/effectparameterslot.h b/src/effects/effectknobparameterslot.h similarity index 63% rename from src/effects/effectparameterslot.h rename to src/effects/effectknobparameterslot.h index fdb5ec9c9a5..e67da685326 100644 --- a/src/effects/effectparameterslot.h +++ b/src/effects/effectknobparameterslot.h @@ -1,12 +1,11 @@ -#ifndef EFFECTPARAMETERSLOT_H -#define EFFECTPARAMETERSLOT_H +#ifndef EFFECTKNOBPARAMETERSLOT_H +#define EFFECTKNOBPARAMETERSLOT_H #include #include #include #include "control/controlobject.h" -#include "effects/effect.h" #include "effects/effectparameterslotbase.h" #include "util/class.h" @@ -14,19 +13,22 @@ class ControlObject; class ControlPushButton; class ControlEffectKnob; class SoftTakeover; +class EffectSlot; -class EffectParameterSlot : public EffectParameterSlotBase { +// EffectKnobParameterSlot is a wrapper around the parameterX ControlObject +// that loaded with an EffectParameter into itself by the EffectSlot. +class EffectKnobParameterSlot : public EffectParameterSlotBase { Q_OBJECT public: - EffectParameterSlot(const QString& group, const unsigned int iParameterSlotNumber); - virtual ~EffectParameterSlot(); + EffectKnobParameterSlot(const QString& group, const unsigned int iParameterSlotNumber); + virtual ~EffectKnobParameterSlot(); static QString formatItemPrefix(const unsigned int iParameterSlotNumber) { return QString("parameter%1").arg(iParameterSlotNumber + 1); } - // Load the parameter of the given effect into this EffectParameterSlot - void loadEffect(EffectPointer pEffect); + // Load the parameter of the given effect into this EffectKnobParameterSlot + void loadParameter(EffectParameter* pEffectParameter); double getValueParameter() const; @@ -46,23 +48,22 @@ class EffectParameterSlot : public EffectParameterSlotBase { private slots: // Solely for handling control changes void slotParameterValueChanged(double value); - void slotValueChanged(double v); void slotLinkTypeChanging(double v); void slotLinkInverseChanged(double v); private: QString debugString() const { - return QString("EffectParameterSlot(%1,%2)").arg(m_group).arg(m_iParameterSlotNumber); + return QString("EffectKnobParameterSlot(%1,%2)").arg(m_group).arg(m_iParameterSlotNumber); } - SoftTakeover* m_pSoftTakeover; + SoftTakeover* m_pMetaknobSoftTakeover; // Control exposed to the rest of Mixxx ControlEffectKnob* m_pControlValue; ControlPushButton* m_pControlLinkType; ControlPushButton* m_pControlLinkInverse; - DISALLOW_COPY_AND_ASSIGN(EffectParameterSlot); + DISALLOW_COPY_AND_ASSIGN(EffectKnobParameterSlot); }; -#endif // EFFECTPARAMETERSLOT_H +#endif // EFFECTKNOBPARAMETERSLOT_H diff --git a/src/effects/effectmanifest.h b/src/effects/effectmanifest.h index 63337697972..f608d7d5a27 100644 --- a/src/effects/effectmanifest.h +++ b/src/effects/effectmanifest.h @@ -18,10 +18,8 @@ // EffectManifest is const, it should be completely immutable. EffectManifest is // meant to be used in most cases as a reference, and in Qt collections, so it // is important that the implicit copy and assign constructors work, and that -// the no-argument constructor be non-explicit. All methods are left virtual to -// allow a backend to replace the entire functionality with its own (for -// example, a database-backed manifest) -class EffectManifest final { +// the no-argument constructor be non-explicit. +class EffectManifest { public: EffectManifest() : m_backendType(EffectBackendType::Unknown), @@ -32,6 +30,15 @@ class EffectManifest final { m_metaknobDefault(0.5) { } + // Hack to store unique IDs in QComboBox models + const QString uniqueId() const { + return m_id + " " + backendName(); + } + + // WARNING! Effects must not be identified solely by ID string or name. + // ID strings and names are only unique among EffectManifests from one + // EffectsBackend. Use EffectManifest::operator== to compare both ID string + // and EffectBackendType. const QString& id() const { return m_id; } @@ -142,7 +149,7 @@ class EffectManifest final { m_metaknobDefault = metaknobDefault; } - QString backendName() { + QString backendName() const { switch (m_backendType) { case EffectBackendType::BuiltIn: return QString("Built-in"); @@ -154,7 +161,7 @@ class EffectManifest final { } // Use this when showing the string in the GUI - QString translatedBackendName() { + QString translatedBackendName() const { switch (m_backendType) { case EffectBackendType::BuiltIn: //: Used for effects that are built into Mixxx @@ -175,6 +182,17 @@ class EffectManifest final { } } + bool operator==(const EffectManifest& other) const { + return other.id() == m_id && other.backendType() == m_backendType; + } + + bool operator<(const EffectManifest& other) const { + if (other.backendType() != m_backendType) { + return other.backendType() < m_backendType; + } + return other.id() < m_id; + } + private: QString debugString() const { return QString("EffectManifest(%1)").arg(m_id); diff --git a/src/effects/effectmanifestparameter.h b/src/effects/effectmanifestparameter.h index baee35ccc07..69518030f4d 100644 --- a/src/effects/effectmanifestparameter.h +++ b/src/effects/effectmanifestparameter.h @@ -6,21 +6,32 @@ #include #include +#include "util/assert.h" +#include "effects/defs.h" + class EffectManifestParameter; typedef QSharedPointer EffectManifestParameterPointer; + class EffectManifestParameter { public: - enum class ControlHint { + enum class ParameterType { + KNOB, + BUTTON, + + NUM_TYPES + }; + + enum class ValueScaler { UNKNOWN = 0, - KNOB_LINEAR, - KNOB_LINEAR_INVERSE, - KNOB_LOGARITHMIC, - KNOB_LOGARITHMIC_INVERSE, - KNOB_STEPPING, // A step rotary, steps given by m_steps - // are arranged with equal distance on scale - TOGGLE_STEPPING // For button and enum controls, not accessible - // from many controllers, no linking to meta knob + LINEAR, + LINEAR_INVERSE, + LOGARITHMIC, + LOGARITHMIC_INVERSE, + INTEGRAL, // A step rotary, steps given by m_steps + // are arranged with equal distance on scale + TOGGLE // For button and enum controls, not accessible + // from many controllers, no linking to meta knob }; enum class SemanticHint { @@ -80,7 +91,7 @@ class EffectManifestParameter { }; EffectManifestParameter() - : m_controlHint(ControlHint::UNKNOWN), + : m_valueScaler(ValueScaler::UNKNOWN), m_semanticHint(SemanticHint::UNKNOWN), m_unitsHint(UnitsHint::UNKNOWN), m_defaultLinkType(LinkType::NONE), @@ -92,7 +103,7 @@ class EffectManifestParameter { m_showInParametertSlot(true) { } - virtual ~EffectManifestParameter() { + ~EffectManifestParameter() { //qDebug() << debugString() << "destroyed"; } @@ -100,31 +111,31 @@ class EffectManifestParameter { // Parameter Information //////////////////////////////////////////////////////////////////////////////// - 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& description() const { + const QString& description() const { return m_description; } - virtual void setDescription(const QString& description) { + void setDescription(const QString& description) { m_description = description; } @@ -132,38 +143,51 @@ class EffectManifestParameter { // Usage hints //////////////////////////////////////////////////////////////////////////////// - virtual ControlHint controlHint() const { - return m_controlHint; + const ParameterType& parameterType() const { + return m_parameterType; } - virtual void setControlHint(ControlHint controlHint) { - m_controlHint = controlHint; + + void setParameterType(const ParameterType parameterType) { + m_parameterType = parameterType; + } + + ValueScaler valueScaler() const { + return m_valueScaler; + } + void setValueScaler(ValueScaler valueScaler) { + m_valueScaler = valueScaler; + if (valueScaler == ValueScaler::TOGGLE) { + setParameterType(ParameterType::BUTTON); + } else { + setParameterType(ParameterType::KNOB); + } } - virtual SemanticHint semanticHint() const { + SemanticHint semanticHint() const { return m_semanticHint; } - virtual void setSemanticHint(SemanticHint semanticHint) { + void setSemanticHint(SemanticHint semanticHint) { m_semanticHint = semanticHint; } - virtual UnitsHint unitsHint() const { + UnitsHint unitsHint() const { return m_unitsHint; } - virtual void setUnitsHint(UnitsHint unitsHint) { + void setUnitsHint(UnitsHint unitsHint) { m_unitsHint = unitsHint; } - virtual LinkType defaultLinkType() const { + LinkType defaultLinkType() const { return m_defaultLinkType; } - virtual void setDefaultLinkType(const LinkType linkType) { + void setDefaultLinkType(const LinkType linkType) { m_defaultLinkType = linkType; } - virtual LinkInversion defaultLinkInversion() const { + LinkInversion defaultLinkInversion() const { return m_defaultLinkInversion; } - virtual void setDefaultLinkInversion(const LinkInversion linkInversion) { + void setDefaultLinkInversion(const LinkInversion linkInversion) { m_defaultLinkInversion = linkInversion; } @@ -176,10 +200,10 @@ class EffectManifestParameter { // A EQ Gain has usually a neutral point of 0.5 (0 dB) while a delay knob // has a neutral point of 0.0 (no delay) // A EQ Gain knob cannot be used on a split meta knob. - virtual double neutralPointOnScale() const { + double neutralPointOnScale() const { return m_neutralPointOnScale; } - virtual void setNeutralPointOnScale(double neutralPoint) { + void setNeutralPointOnScale(double neutralPoint) { m_neutralPointOnScale = neutralPoint; } @@ -188,10 +212,10 @@ class EffectManifestParameter { // the effective parameter which is loaded onto the slot. // This is required because we have only 8 parameter slots, but // LV2 or VST effects can have more then 8. - virtual bool showInParameterSlot() const { + bool showInParameterSlot() const { return m_showInParametertSlot; } - virtual void setShowInParameterSlot(double show) { + void setShowInParameterSlot(double show) { m_showInParametertSlot = show; } @@ -199,31 +223,32 @@ class EffectManifestParameter { // Value Settings //////////////////////////////////////////////////////////////////////////////// - virtual const double& getDefault() const { + const double& getDefault() const { return m_default; } - virtual void setDefault(const double& defaultValue) { - m_default = defaultValue; - } - virtual const double& getMinimum() const { + const double& getMinimum() const { return m_minimum; } - virtual void setMinimum(const double& minimum) { - m_minimum = minimum; - } - virtual const double& getMaximum() const { + const double& getMaximum() const { return m_maximum; } - virtual void setMaximum(const double& maximum) { + + void setRange(const double& minimum, const double& defaultValue, const double& maximum) { + VERIFY_OR_DEBUG_ASSERT(minimum <= defaultValue && defaultValue <= maximum) { + qWarning() << "Invalid Parameter Range: " << minimum << ' ' << defaultValue << ' ' << maximum; + return; + } + m_minimum = minimum; + m_default = defaultValue; m_maximum = maximum; } - virtual void appendStep(const QPair& step) { + void appendStep(const QPair& step) { m_steps.append(step); } - virtual const QList >& getSteps() const { + const QList >& getSteps() const { return m_steps; } @@ -237,7 +262,8 @@ class EffectManifestParameter { QString m_shortName; QString m_description; - ControlHint m_controlHint; + ParameterType m_parameterType; + ValueScaler m_valueScaler; SemanticHint m_semanticHint; UnitsHint m_unitsHint; LinkType m_defaultLinkType; @@ -249,7 +275,7 @@ class EffectManifestParameter { double m_maximum; // Used to describe steps of - // CONTROL_KNOB_STEPPING and CONTROL_TOGGLE_STEPPING + // CONTROL_INTEGRAL and CONTROL_TOGGLE // effect parameters // Each pair has the following form: // name - value @@ -258,6 +284,11 @@ class EffectManifestParameter { bool m_showInParametertSlot; }; +inline uint qHash(const EffectManifestParameter::ParameterType& parameterType) { + return static_cast(parameterType); +} + QDebug operator<<(QDebug dbg, const EffectManifestParameter& parameter); + #endif /* EFFECTMANIFESTPARAMETER_H */ diff --git a/src/effects/effectparameter.cpp b/src/effects/effectparameter.cpp index dab7239a0ca..34777e7f970 100644 --- a/src/effects/effectparameter.cpp +++ b/src/effects/effectparameter.cpp @@ -2,38 +2,19 @@ #include "effects/effectparameter.h" #include "effects/effectsmanager.h" -#include "effects/effect.h" #include "util/assert.h" -EffectParameter::EffectParameter(Effect* pEffect, EffectsManager* pEffectsManager, - int iParameterNumber, - EffectManifestParameterPointer pParameter) - : QObject(), // no parent - m_pEffect(pEffect), +EffectParameter::EffectParameter(EngineEffect* pEngineEffect, EffectsManager* pEffectsManager, + int iParameterNumber, EffectManifestParameterPointer pParameter) + : m_pEngineEffect(pEngineEffect), m_pEffectsManager(pEffectsManager), m_iParameterNumber(iParameterNumber), - m_pParameter(pParameter), - m_bAddedToEngine(false) { + m_pParameter(pParameter) { // qDebug() << debugString() << "Constructing new EffectParameter from EffectManifestParameter:" // << m_parameter.id(); - m_minimum = m_pParameter->getMinimum(); - m_maximum = m_pParameter->getMaximum(); - // Sanity check the maximum and minimum - if (m_minimum > m_maximum) { - qWarning() << debugString() << "WARNING: Parameter maximum is less than the minimum."; - m_maximum = m_minimum; - } - // If the parameter specifies a default, set that. Otherwise use the minimum - // value. - m_default = m_pParameter->getDefault(); - if (m_default < m_minimum || m_default > m_maximum) { - qWarning() << debugString() << "WARNING: Parameter default is outside of minimum/maximum range."; - m_default = m_minimum; - } - - // Finally, set the value to the default. - m_value = m_default; + // Set the value to the default. + m_value = m_pParameter->getDefault(); } EffectParameter::~EffectParameter() { @@ -44,22 +25,6 @@ EffectManifestParameterPointer EffectParameter::manifest() const { return m_pParameter; } -const QString& EffectParameter::id() const { - return m_pParameter->id(); -} - -const QString& EffectParameter::name() const { - return m_pParameter->name(); -} - -const QString& EffectParameter::shortName() const { - return m_pParameter->shortName(); -} - -const QString& EffectParameter::description() const { - return m_pParameter->description(); -} - // static bool EffectParameter::clampValue(double* pValue, const double& minimum, const double& maximum) { @@ -74,31 +39,7 @@ bool EffectParameter::clampValue(double* pValue, } bool EffectParameter::clampValue() { - return clampValue(&m_value, m_minimum, m_maximum); -} - -bool EffectParameter::clampDefault() { - return clampValue(&m_default, m_minimum, m_maximum); -} - -bool EffectParameter::clampRanges() { - if (m_minimum > m_maximum) { - m_maximum = m_minimum; - return true; - } - return false; -} - -EffectManifestParameter::LinkType EffectParameter::getDefaultLinkType() const { - return m_pParameter->defaultLinkType(); -} - -EffectManifestParameter::LinkInversion EffectParameter::getDefaultLinkInversion() const { - return m_pParameter->defaultLinkInversion(); -} - -double EffectParameter::getNeutralPointOnScale() const { - return m_pParameter->neutralPointOnScale(); + return clampValue(&m_value, m_pParameter->getMinimum(), m_pParameter->getMaximum()); } double EffectParameter::getValue() const { @@ -114,113 +55,19 @@ void EffectParameter::setValue(double value) { } updateEngineState(); - emit(valueChanged(m_value)); -} - -double EffectParameter::getDefault() const { - return m_default; -} - -void EffectParameter::setDefault(double dflt) { - m_default = dflt; - - if (clampDefault()) { - qWarning() << debugString() << "WARNING: Default parameter value was outside of range, clamped."; - } - - m_default = dflt; - - updateEngineState(); -} - -double EffectParameter::getMinimum() const { - return m_minimum; -} - -void EffectParameter::setMinimum(double minimum) { - // There's a degenerate case here where the maximum could be lower - // than the manifest minimum. If that's the case, then the minimum - // value is currently below the manifest minimum. Since similar - // guards exist in the setMaximum call, this should not be able to - // happen. - VERIFY_OR_DEBUG_ASSERT(m_minimum >= m_pParameter->getMinimum()) { - return; - } - - m_minimum = minimum; - if (m_minimum < m_pParameter->getMinimum()) { - qWarning() << debugString() << "WARNING: Minimum value is less than plugin's absolute minimum, clamping."; - m_minimum = m_pParameter->getMinimum(); - } - - if (m_minimum > m_maximum) { - qWarning() << debugString() << "WARNING: New minimum was above maximum, clamped."; - m_minimum = m_maximum; - } - - if (clampValue()) { - qWarning() << debugString() << "WARNING: Value was outside of new minimum, clamped."; - } - - if (clampDefault()) { - qWarning() << debugString() << "WARNING: Default was outside of new minimum, clamped."; - } - - updateEngineState(); -} - -double EffectParameter::getMaximum() const { - return m_maximum; -} - -void EffectParameter::setMaximum(double maximum) { - // There's a degenerate case here where the minimum could be larger - // than the manifest maximum. If that's the case, then the maximum - // value is currently above the manifest maximum. Since similar - // guards exist in the setMinimum call, this should not be able to - // happen. - VERIFY_OR_DEBUG_ASSERT(m_maximum <= m_pParameter->getMaximum()) { - return; - } - - m_maximum = maximum; - if (m_maximum > m_pParameter->getMaximum()) { - qWarning() << debugString() << "WARNING: Maximum value is less than plugin's absolute maximum, clamping."; - m_maximum = m_pParameter->getMaximum(); - } - - if (m_maximum < m_minimum) { - qWarning() << debugString() << "WARNING: New maximum was below the minimum, clamped."; - m_maximum = m_minimum; - } - - if (clampValue()) { - qWarning() << debugString() << "WARNING: Value was outside of new maximum, clamped."; - } - - if (clampDefault()) { - qWarning() << debugString() << "WARNING: Default was outside of new maximum, clamped."; - } - - updateEngineState(); -} - -EffectManifestParameter::ControlHint EffectParameter::getControlHint() const { - return m_pParameter->controlHint(); } void EffectParameter::updateEngineState() { - EngineEffect* pEngineEffect = m_pEffect->getEngineEffect(); - if (!pEngineEffect) { + if (!m_pEngineEffect) { return; } EffectsRequest* pRequest = new EffectsRequest(); pRequest->type = EffectsRequest::SET_PARAMETER_PARAMETERS; - pRequest->pTargetEffect = pEngineEffect; + pRequest->pTargetEffect = m_pEngineEffect; pRequest->SetParameterParameters.iParameter = m_iParameterNumber; pRequest->value = m_value; - pRequest->minimum = m_minimum; - pRequest->maximum = m_maximum; - pRequest->default_value = m_default; + pRequest->minimum = m_pParameter->getMinimum(); + pRequest->maximum = m_pParameter->getMaximum(); + pRequest->default_value = m_pParameter->getDefault(); m_pEffectsManager->writeRequest(pRequest); } diff --git a/src/effects/effectparameter.h b/src/effects/effectparameter.h index f6565258fa1..03b32c8d659 100644 --- a/src/effects/effectparameter.h +++ b/src/effects/effectparameter.h @@ -5,64 +5,32 @@ #include #include "effects/effectmanifestparameter.h" +#include "effects/effectslot.h" #include "util/class.h" class Effect; class EffectsManager; - -// An EffectParameter is an instance of an EffectManifestParameter, which is in -// charge of keeping track of the instance values for the default, minimum, -// maximum and value for each Effect's parameter, and validating that they are -// always within acceptable ranges. This class is NOT thread-safe and must only -// be used from the main thread. -class EffectParameter : public QObject { - Q_OBJECT +class EngineEffect; + +// An EffectParameter is a wrapper around EffectManifestParameter that tracks a +// mutable value state and communicates that state to the engine. This class is +// NOT thread-safe and must only be used from the main thread. Separating this +// from the parameterX ControlObjects in EffectParameterSlot allows for decoupling +// the state of the parameters from the ControlObject states, which is required for +// parameter hiding and rearrangement. +class EffectParameter { public: - EffectParameter(Effect* pEffect, EffectsManager* pEffectsManager, + EffectParameter(EngineEffect* pEngineEffect, EffectsManager* pEffectsManager, int iParameterNumber, EffectManifestParameterPointer pParameter); virtual ~EffectParameter(); - void addToEngine(); - void removeFromEngine(); - - /////////////////////////////////////////////////////////////////////////// - // Parameter Information - /////////////////////////////////////////////////////////////////////////// - EffectManifestParameterPointer manifest() const; - const QString& id() const; - const QString& name() const; - const QString& shortName() const; - const QString& description() const; - - /////////////////////////////////////////////////////////////////////////// - // Value Settings - /////////////////////////////////////////////////////////////////////////// - - EffectManifestParameter::LinkType getDefaultLinkType() const; - EffectManifestParameter::LinkInversion getDefaultLinkInversion() const; - double getNeutralPointOnScale() const; double getValue() const; - void setValue(double value); - double getDefault() const; - void setDefault(double defaultValue); - - double getMinimum() const; - void setMinimum(double minimum); - - double getMaximum() const; - void setMaximum(double maximum); - - EffectManifestParameter::ControlHint getControlHint() const; - void updateEngineState(); - signals: - void valueChanged(double value); - private: QString debugString() const { return QString("EffectParameter(%1)").arg(m_pParameter->name()); @@ -71,18 +39,12 @@ class EffectParameter : public QObject { static bool clampValue(double* pValue, const double& minimum, const double& maximum); bool clampValue(); - bool clampDefault(); - bool clampRanges(); - Effect* m_pEffect; + EngineEffect* m_pEngineEffect; EffectsManager* m_pEffectsManager; int m_iParameterNumber; EffectManifestParameterPointer m_pParameter; - double m_minimum; - double m_maximum; - double m_default; double m_value; - bool m_bAddedToEngine; DISALLOW_COPY_AND_ASSIGN(EffectParameter); }; diff --git a/src/effects/effectparameterslot.cpp b/src/effects/effectparameterslot.cpp deleted file mode 100644 index d229d341764..00000000000 --- a/src/effects/effectparameterslot.cpp +++ /dev/null @@ -1,316 +0,0 @@ -#include - -#include "control/controleffectknob.h" -#include "effects/effectparameterslot.h" -#include "effects/effectxmlelements.h" -#include "control/controlobject.h" -#include "control/controlpushbutton.h" -#include "controllers/softtakeover.h" -#include "util/xml.h" - -EffectParameterSlot::EffectParameterSlot(const QString& group, const unsigned int iParameterSlotNumber) - : EffectParameterSlotBase(group, iParameterSlotNumber) { - QString itemPrefix = formatItemPrefix(iParameterSlotNumber); - - m_pControlValue = new ControlEffectKnob( - ConfigKey(m_group, itemPrefix)); - connect(m_pControlValue, SIGNAL(valueChanged(double)), - this, SLOT(slotValueChanged(double))); - - m_pControlLoaded = new ControlObject( - ConfigKey(m_group, itemPrefix + QString("_loaded"))); - m_pControlLoaded->setReadOnly(); - - m_pControlType = new ControlObject( - ConfigKey(m_group, itemPrefix + QString("_type"))); - m_pControlType->setReadOnly(); - - m_pControlLinkType = new ControlPushButton( - ConfigKey(m_group, itemPrefix + QString("_link_type"))); - m_pControlLinkType->setButtonMode(ControlPushButton::TOGGLE); - m_pControlLinkType->setStates( - static_cast(EffectManifestParameter::LinkType::NUM_LINK_TYPES)); - m_pControlLinkType->connectValueChangeRequest( - this, &EffectParameterSlot::slotLinkTypeChanging); - - m_pControlLinkInverse = new ControlPushButton( - ConfigKey(m_group, itemPrefix + QString("_link_inverse"))); - m_pControlLinkInverse->setButtonMode(ControlPushButton::TOGGLE); - connect(m_pControlLinkInverse, SIGNAL(valueChanged(double)), - this, SLOT(slotLinkInverseChanged(double))); - - m_pSoftTakeover = new SoftTakeover(); - - clear(); -} - -EffectParameterSlot::~EffectParameterSlot() { - //qDebug() << debugString() << "destroyed"; - delete m_pControlValue; - // m_pControlLoaded and m_pControlType are deleted by ~EffectParameterSlotBase - delete m_pControlLinkType; - delete m_pControlLinkInverse; - delete m_pSoftTakeover; -} - -void EffectParameterSlot::loadEffect(EffectPointer pEffect) { - //qDebug() << debugString() << "loadEffect" << (pEffect ? pEffect->getManifest().name() : "(null)"); - clear(); - if (pEffect) { - // Returns null if it doesn't have a parameter for that number - m_pEffectParameter = pEffect->getKnobParameterForSlot(m_iParameterSlotNumber); - - if (m_pEffectParameter) { - //qDebug() << debugString() << "Loading effect parameter" << m_pEffectParameter->name(); - double dValue = m_pEffectParameter->getValue(); - double dMinimum = m_pEffectParameter->getMinimum(); - double dMinimumLimit = dMinimum; // TODO(rryan) expose limit from EffectParameter - double dMaximum = m_pEffectParameter->getMaximum(); - double dMaximumLimit = dMaximum; // TODO(rryan) expose limit from EffectParameter - double dDefault = m_pEffectParameter->getDefault(); - - if (dValue > dMaximum || dValue < dMinimum || - dMinimum < dMinimumLimit || dMaximum > dMaximumLimit || - dDefault > dMaximum || dDefault < dMinimum) { - qWarning() << debugString() << "WARNING: EffectParameter does not satisfy basic sanity checks."; - } - - //qDebug() << debugString() - // << QString("Val: %1 Min: %2 MinLimit: %3 Max: %4 MaxLimit: %5 Default: %6") - // .arg(dValue).arg(dMinimum).arg(dMinimumLimit).arg(dMaximum).arg(dMaximumLimit).arg(dDefault); - - EffectManifestParameter::ControlHint type = m_pEffectParameter->getControlHint(); - m_pControlValue->setBehaviour(type, dMinimum, dMaximum); - m_pControlValue->setDefaultValue(dDefault); - m_pControlValue->set(dValue); - // TODO(rryan) expose this from EffectParameter - m_pControlType->forceSet(static_cast(type)); - // Default loaded parameters to loaded and unlinked - m_pControlLoaded->forceSet(1.0); - - m_pControlLinkType->set( - static_cast(m_pEffectParameter->getDefaultLinkType())); - m_pControlLinkInverse->set( - static_cast(m_pEffectParameter->getDefaultLinkInversion())); - - connect(m_pEffectParameter, SIGNAL(valueChanged(double)), - this, SLOT(slotParameterValueChanged(double))); - } - } - emit(updated()); -} - -void EffectParameterSlot::clear() { - //qDebug() << debugString() << "clear"; - if (m_pEffectParameter) { - m_pEffectParameter->disconnect(this); - m_pEffectParameter = NULL; - } - - m_pControlLoaded->forceSet(0.0); - m_pControlValue->set(0.0); - m_pControlValue->setDefaultValue(0.0); - m_pControlType->forceSet(0.0); - m_pControlLinkType->setAndConfirm( - static_cast(EffectManifestParameter::LinkType::NONE)); - m_pSoftTakeover->setThreshold(SoftTakeover::kDefaultTakeoverThreshold); - m_pControlLinkInverse->set(0.0); - emit(updated()); -} - -void EffectParameterSlot::slotParameterValueChanged(double value) { - //qDebug() << debugString() << "slotParameterValueChanged" << value.toDouble(); - m_pControlValue->set(value); -} - -void EffectParameterSlot::slotLinkTypeChanging(double v) { - m_pSoftTakeover->ignoreNext(); - EffectManifestParameter::LinkType newType = - static_cast( - static_cast(v)); - if (newType == EffectManifestParameter::LinkType::LINKED_LEFT || - newType == EffectManifestParameter::LinkType::LINKED_RIGHT || - newType == EffectManifestParameter::LinkType::LINKED_LEFT_RIGHT) { - double neutral = m_pEffectParameter->getNeutralPointOnScale(); - if (neutral > 0.0 && neutral < 1.0) { - // Knob is already a split knob, meaning it has a positive and - // negative effect if it's twisted above the neutral point or - // below the neutral point. - // Toggle back to 0 - newType = EffectManifestParameter::LinkType::NONE; - } - } - if (newType == EffectManifestParameter::LinkType::LINKED_LEFT || - newType == EffectManifestParameter::LinkType::LINKED_RIGHT) { - m_pSoftTakeover->setThreshold( - SoftTakeover::kDefaultTakeoverThreshold * 2.0); - } else { - m_pSoftTakeover->setThreshold(SoftTakeover::kDefaultTakeoverThreshold); - } - m_pControlLinkType->setAndConfirm(static_cast(newType)); -} - -void EffectParameterSlot::slotLinkInverseChanged(double v) { - Q_UNUSED(v); - m_pSoftTakeover->ignoreNext(); -} - -void EffectParameterSlot::onEffectMetaParameterChanged(double parameter, bool force) { - m_dChainParameter = parameter; - if (m_pEffectParameter != NULL) { - // Intermediate cast to integer is needed for VC++. - EffectManifestParameter::LinkType type = - static_cast( - static_cast(m_pControlLinkType->get())); - - bool inverse = m_pControlLinkInverse->toBool(); - - switch (type) { - case EffectManifestParameter::LinkType::LINKED: - if (parameter < 0.0 || parameter > 1.0) { - return; - } - { - double neutral = m_pEffectParameter->getNeutralPointOnScale(); - if (neutral > 0.0 && neutral < 1.0) { - if (inverse) { - // the neutral position must stick where it is - neutral = 1.0 - neutral; - } - // Knob is already a split knob - // Match to center position of meta knob - if (parameter <= 0.5) { - parameter /= 0.5; - parameter *= neutral; - } else { - parameter -= 0.5; - parameter /= 0.5; - parameter *= 1 - neutral; - parameter += neutral; - } - } - } - break; - case EffectManifestParameter::LinkType::LINKED_LEFT: - if (parameter >= 0.5 && parameter <= 1.0) { - parameter = 1; - } else if (parameter >= 0.0 && parameter <= 0.5) { - parameter *= 2; - } else { - return; - } - break; - case EffectManifestParameter::LinkType::LINKED_RIGHT: - if (parameter >= 0.5 && parameter <= 1.0) { - parameter -= 0.5; - parameter *= 2; - } else if (parameter >= 0.0 && parameter < 0.5) { - parameter = 0.0; - } else { - return; - } - break; - case EffectManifestParameter::LinkType::LINKED_LEFT_RIGHT: - if (parameter >= 0.5 && parameter <= 1.0) { - parameter -= 0.5; - parameter *= 2; - } else if (parameter >= 0.0 && parameter < 0.5) { - parameter *= 2; - parameter = 1.0 - parameter; - } else { - return; - } - break; - case EffectManifestParameter::LinkType::NONE: - default: - return; - } - - if (inverse) { - parameter = 1.0 - parameter; - } - - //qDebug() << "onEffectMetaParameterChanged" << debugString() << parameter << "force?" << force; - if (force) { - m_pControlValue->setParameterFrom(parameter, NULL); - // This ensures that softtakover is in sync for following updates - m_pSoftTakeover->ignore(m_pControlValue, parameter); - } else if (!m_pSoftTakeover->ignore(m_pControlValue, parameter)) { - m_pControlValue->setParameterFrom(parameter, NULL); - } - } -} - -void EffectParameterSlot::syncSofttakeover() { - double parameter = m_pControlValue->getParameter(); - m_pSoftTakeover->ignore(m_pControlValue, parameter); -} - -double EffectParameterSlot::getValueParameter() const { - return m_pControlValue->getParameter(); -} - -void EffectParameterSlot::slotValueChanged(double v) { - if (m_pEffectParameter) { - m_pEffectParameter->setValue(v); - } -} - -QDomElement EffectParameterSlot::toXml(QDomDocument* doc) const { - QDomElement parameterElement; - if (m_pEffectParameter != nullptr) { - parameterElement = doc->createElement(EffectXml::Parameter); - XmlParse::addElement(*doc, parameterElement, - EffectXml::ParameterValue, - QString::number(m_pControlValue->getParameter())); - XmlParse::addElement(*doc, parameterElement, - EffectXml::ParameterLinkType, - EffectManifestParameter::LinkTypeToString( - static_cast( - static_cast(m_pControlLinkType->get())))); - XmlParse::addElement(*doc, parameterElement, - EffectXml::ParameterLinkInversion, - QString::number(m_pControlLinkInverse->get())); - } - - return parameterElement; -} - -void EffectParameterSlot::loadParameterSlotFromXml(const QDomElement& parameterElement) { - if (m_pEffectParameter == nullptr) { - return; - } - if (!parameterElement.hasChildNodes()) { - m_pControlValue->reset(); - m_pControlLinkType->set( - static_cast(m_pEffectParameter->getDefaultLinkType())); - m_pControlLinkInverse->set( - static_cast(m_pEffectParameter->getDefaultLinkInversion())); - } else { - // Need to use setParameterFrom(..., nullptr) here to - // trigger valueChanged() signal emission and execute slotValueChanged() - bool conversionWorked = false; - double value = XmlParse::selectNodeDouble(parameterElement, - EffectXml::ParameterValue, &conversionWorked); - if (conversionWorked) { - // Need to use setParameterFrom(..., nullptr) here to - // trigger valueChanged() signal emission and execute slotValueChanged() - m_pControlValue->setParameterFrom(value, nullptr); - } - // If the conversion failed, the default value is kept. - - QString linkTypeString = XmlParse::selectNodeQString(parameterElement, - EffectXml::ParameterLinkType); - if (!linkTypeString.isEmpty()) { - m_pControlLinkType->set(static_cast( - EffectManifestParameter::LinkTypeFromString(linkTypeString))); - } - - conversionWorked = false; - double linkInversion = XmlParse::selectNodeDouble(parameterElement, - EffectXml::ParameterLinkInversion, &conversionWorked); - if (conversionWorked) { - m_pControlLinkInverse->set(linkInversion); - } - } -} diff --git a/src/effects/effectparameterslotbase.cpp b/src/effects/effectparameterslotbase.cpp index 4f1b3204903..453cf2f75a2 100644 --- a/src/effects/effectparameterslotbase.cpp +++ b/src/effects/effectparameterslotbase.cpp @@ -1,52 +1,73 @@ #include +#include "effects/effectparameter.h" #include "control/controleffectknob.h" #include "effects/effectparameterslotbase.h" #include "control/controlobject.h" #include "control/controlpushbutton.h" EffectParameterSlotBase::EffectParameterSlotBase(const QString& group, - const unsigned int iParameterSlotNumber) + const unsigned int iParameterSlotNumber, + const EffectManifestParameter::ParameterType parameterType) : m_iParameterSlotNumber(iParameterSlotNumber), + m_parameterType(parameterType), m_group(group), - m_pEffectParameter(NULL), - m_pControlLoaded(NULL), - m_pControlType(NULL), + m_pEffectParameter(nullptr), + m_pManifestParameter(nullptr), + m_pControlLoaded(nullptr), + m_pControlType(nullptr), m_dChainParameter(0.0) { } EffectParameterSlotBase::~EffectParameterSlotBase() { - m_pEffectParameter = NULL; - m_pEffect.clear(); + m_pEffectParameter = nullptr; + m_pManifestParameter.clear(); + m_pEffectSlot = nullptr; delete m_pControlLoaded; delete m_pControlType; } QString EffectParameterSlotBase::name() const { - if (m_pEffectParameter) { - return m_pEffectParameter->name(); + if (m_pManifestParameter) { + return m_pManifestParameter->name(); } return QString(); } QString EffectParameterSlotBase::shortName() const { - if (m_pEffectParameter) { - return m_pEffectParameter->shortName(); + if (m_pManifestParameter) { + return m_pManifestParameter->shortName(); } return QString(); } QString EffectParameterSlotBase::description() const { - if (m_pEffectParameter) { - return m_pEffectParameter->description(); + if (m_pManifestParameter) { + return m_pManifestParameter->description(); } return tr("No effect loaded."); } +EffectManifestParameter::ParameterType EffectParameterSlotBase::parameterType() const { + return m_parameterType; +} + EffectManifestParameterPointer EffectParameterSlotBase::getManifest() { - if (m_pEffectParameter) { - return m_pEffectParameter->manifest(); + if (m_pManifestParameter) { + return m_pManifestParameter; } return EffectManifestParameterPointer(); } + +void EffectParameterSlotBase::syncSofttakeover() { +} + +void EffectParameterSlotBase::onEffectMetaParameterChanged(double parameter, bool force) { +} + +void EffectParameterSlotBase::slotValueChanged(double v) { + if (m_pEffectParameter) { + m_pEffectParameter->setValue(v); + } +} diff --git a/src/effects/effectparameterslotbase.h b/src/effects/effectparameterslotbase.h index fcdf1c854fd..e76d673f5dc 100644 --- a/src/effects/effectparameterslotbase.h +++ b/src/effects/effectparameterslotbase.h @@ -6,22 +6,43 @@ #include #include "control/controlobject.h" -#include "effects/effect.h" +#include "effects/effectmanifest.h" #include "util/class.h" class ControlObject; class ControlPushButton; +class EffectParameter; +class EffectSlot; + +// EffectParameterSlotBase is a wrapper around the parameterX ControlObject +// that loaded with an EffectParameter into itself by the EffectSlot. class EffectParameterSlotBase : public QObject { Q_OBJECT public: - EffectParameterSlotBase(const QString& group, const unsigned int iParameterSlotNumber); + EffectParameterSlotBase(const QString& group, const unsigned int iParameterSlotNumber, + const EffectManifestParameter::ParameterType parameterType); + virtual ~EffectParameterSlotBase(); + virtual void loadParameter(EffectParameter* pEffectParameter) = 0; + + // Clear the currently loaded effect + virtual void clear() = 0; + + virtual void syncSofttakeover(); + + virtual void onEffectMetaParameterChanged(double parameter, bool force=false); + QString name() const; QString shortName() const; QString description() const; + EffectManifestParameter::ParameterType parameterType() const; EffectManifestParameterPointer getManifest(); + inline bool isLoaded() const { + return m_pManifestParameter != nullptr; + } + virtual QDomElement toXml(QDomDocument* doc) const = 0; virtual void loadParameterSlotFromXml(const QDomElement& parameterElement) = 0; @@ -30,11 +51,18 @@ class EffectParameterSlotBase : public QObject { // Signal that indicates that the EffectParameterSlotBase has been updated. void updated(); + public slots: + // Solely for handling control changes + void slotValueChanged(double v); + virtual void slotParameterValueChanged(double value) = 0; + protected: const unsigned int m_iParameterSlotNumber; QString m_group; - EffectPointer m_pEffect; + EffectSlot* m_pEffectSlot; EffectParameter* m_pEffectParameter; + EffectManifestParameterPointer m_pManifestParameter; + EffectManifestParameter::ParameterType m_parameterType; // Controls exposed to the rest of Mixxx ControlObject* m_pControlLoaded; diff --git a/src/effects/effectpreset.cpp b/src/effects/effectpreset.cpp new file mode 100644 index 00000000000..d3734cf194e --- /dev/null +++ b/src/effects/effectpreset.cpp @@ -0,0 +1,32 @@ +#include "effects/effectpreset.h" + +#include "effects/effectxmlelements.h" +#include "util/xml.h" + +EffectPreset::EffectPreset() { +} + +EffectPreset::EffectPreset(const QDomElement& element) { + if (!element.hasChildNodes()) { + return; + } + + m_id = XmlParse::selectNodeQString(element, EffectXml::EffectId); + m_version = XmlParse::selectNodeQString(element, EffectXml::EffectVersion); + m_dMetaParameter = XmlParse::selectNodeDouble(element, EffectXml::EffectMetaParameter); + + QDomElement parametersElement = XmlParse::selectElement(element, EffectXml::ParametersRoot); + QDomNodeList parametersList = parametersElement.childNodes(); + + for (int i = 0; i < parametersList.count(); ++i) { + QDomNode parameterNode = parametersList.at(i); + if (parameterNode.isElement()) { + QDomElement parameterElement = parameterNode.toElement(); + // EffectParameterPresetPointer pPreset(new EffectParameterPreset(parameterElement)); + // m_effectParameterPresets.append(pPreset); + } + } +} + +EffectPreset::~EffectPreset() { +} diff --git a/src/effects/effectpreset.h b/src/effects/effectpreset.h new file mode 100644 index 00000000000..1cf6d4e5496 --- /dev/null +++ b/src/effects/effectpreset.h @@ -0,0 +1,23 @@ +#ifndef EFFECTPRESET_H +#define EFFECTPRESET_H + +#include + +#include "effects/defs.h" + + +class EffectPreset { + public: + EffectPreset(); + EffectPreset(const QDomElement& element); + ~EffectPreset(); + + private: + QString m_id; + QString m_version; + double m_dMetaParameter; + + // QList m_effectParameterPresets; +}; + +#endif /* EFFECTPRESET_H */ \ No newline at end of file diff --git a/src/effects/effectprocessor.h b/src/effects/effectprocessor.h index b493511aa28..946f76052a5 100644 --- a/src/effects/effectprocessor.h +++ b/src/effects/effectprocessor.h @@ -1,4 +1,3 @@ - #ifndef EFFECTPROCESSOR_H #define EFFECTPROCESSOR_H @@ -13,9 +12,6 @@ #include "engine/effects/groupfeaturestate.h" #include "engine/effects/message.h" #include "engine/channelhandle.h" -#include "effects/effectsmanager.h" - -class EngineEffect; // Effects are implemented as two separate classes, an EffectState subclass and // an EffectProcessorImpl subclass. Separating state from the DSP code allows @@ -57,7 +53,7 @@ class EffectProcessor { // Called from main thread to avoid allocating memory in the audio callback thread virtual void initialize( const QSet& activeInputChannels, - EffectsManager* pEffectsManager, + const QSet& registeredOutputChannels, const mixxx::EngineParameters& bufferParameters) = 0; virtual EffectState* createState(const mixxx::EngineParameters& bufferParameters) = 0; virtual bool loadStatesForInputChannel(const ChannelHandle* inputChannel, @@ -66,6 +62,9 @@ class EffectProcessor { // callback executes process() with EffectEnableState::Disabling virtual void deleteStatesForInputChannel(const ChannelHandle* inputChannel) = 0; + virtual void loadEngineEffectParameters( + const QMap& parameters) = 0; + // Take a buffer of audio samples as pInput, process the buffer according to // Effect-specific logic, and output it to the buffer pOutput. Both pInput // and pOutput are represented as stereo interleaved samples for now, but @@ -91,8 +90,7 @@ class EffectProcessor { template class EffectProcessorImpl : public EffectProcessor { public: - EffectProcessorImpl() - : m_pEffectsManager(nullptr) { + EffectProcessorImpl() { } // Subclasses should not implement their own destructor. All state should // be stored in the EffectState subclass, not the EffectProcessorImpl subclass. @@ -127,11 +125,7 @@ class EffectProcessorImpl : public EffectProcessor { // static EffectManifest getManifest(); // This is the only non-static method that subclasses need to implement. - // TODO(Be): remove ChannelHandle& argument? No (built-in) effects use it. Why should - // effects be concerned with the ChannelHandle& when process() takes care of giving - // it the appropriate ChannelStateHolder? - virtual void processChannel(const ChannelHandle& handle, - EffectSpecificState* channelState, + virtual void processChannel(EffectSpecificState* channelState, const CSAMPLE* pInput, CSAMPLE* pOutput, const mixxx::EngineParameters& bufferParameters, const EffectEnableState enableState, @@ -154,21 +148,22 @@ class EffectProcessorImpl : public EffectProcessor { pState = createSpecificState(bufferParameters); m_channelStateMatrix[inputHandle][outputHandle] = pState; } - processChannel(inputHandle, pState, pInput, pOutput, bufferParameters, - enableState, groupFeatures); + processChannel(pState, pInput, pOutput, + bufferParameters, enableState, groupFeatures); } void initialize(const QSet& activeInputChannels, - EffectsManager* pEffectsManager, + const QSet& registeredOutputChannels, const mixxx::EngineParameters& bufferParameters) final { + m_registeredOutputChannels = registeredOutputChannels; + for (const ChannelHandleAndGroup& inputChannel : activeInputChannels) { if (kEffectDebugOutput) { qDebug() << this << "EffectProcessorImpl::initialize allocating " "EffectStates for input" << inputChannel; } ChannelHandleMap outputChannelMap; - for (const ChannelHandleAndGroup& outputChannel : - pEffectsManager->registeredOutputChannels()) { + for (const ChannelHandleAndGroup& outputChannel : m_registeredOutputChannels) { outputChannelMap.insert(outputChannel.handle(), createSpecificState(bufferParameters)); if (kEffectDebugOutput) { @@ -178,8 +173,6 @@ class EffectProcessorImpl : public EffectProcessor { } m_channelStateMatrix.insert(inputChannel.handle(), outputChannelMap); } - m_pEffectsManager = pEffectsManager; - DEBUG_ASSERT(m_pEffectsManager != nullptr); }; EffectState* createState(const mixxx::EngineParameters& bufferParameters) final { @@ -217,8 +210,8 @@ class EffectProcessorImpl : public EffectProcessor { } } - for (const ChannelHandleAndGroup& outputChannel : - m_pEffectsManager->registeredOutputChannels()) { + QSet receivedOutputChannels = m_registeredOutputChannels; + for (const ChannelHandleAndGroup& outputChannel : m_registeredOutputChannels) { if (kEffectDebugOutput) { qDebug() << "EffectProcessorImpl::loadStatesForInputChannel" << this << "output" << outputChannel; @@ -230,7 +223,11 @@ class EffectProcessorImpl : public EffectProcessor { return false; } effectSpecificStatesMap.insert(outputChannel.handle(), pState); + receivedOutputChannels.insert(outputChannel); } + // Output channels are hardcoded in EngineMaster and should not + // be registered after Mixxx initializes. + DEBUG_ASSERT(receivedOutputChannels == m_registeredOutputChannels); return true; }; @@ -262,9 +259,11 @@ class EffectProcessorImpl : public EffectProcessor { stateMap.clear(); }; - private: - - EffectSpecificState* createSpecificState(const mixxx::EngineParameters& bufferParameters) { + protected: + // Subclasses for external effects plugins may reimplement this, but + // subclasses for built-in effects should not. + virtual EffectSpecificState* createSpecificState( + const mixxx::EngineParameters& bufferParameters) { EffectSpecificState* pState = new EffectSpecificState(bufferParameters); if (kEffectDebugOutput) { qDebug() << this << "EffectProcessorImpl creating EffectState" << pState; @@ -272,7 +271,8 @@ class EffectProcessorImpl : public EffectProcessor { return pState; }; - EffectsManager* m_pEffectsManager; + private: + QSet m_registeredOutputChannels; ChannelHandleMap> m_channelStateMatrix; }; diff --git a/src/effects/effectrack.cpp b/src/effects/effectrack.cpp deleted file mode 100644 index 95dda5e90d8..00000000000 --- a/src/effects/effectrack.cpp +++ /dev/null @@ -1,467 +0,0 @@ -#include "effects/effectrack.h" - -#include "effects/effectsmanager.h" -#include "effects/effectchainmanager.h" -#include "effects/effectslot.h" -#include "engine/effects/engineeffectrack.h" - -#include "util/assert.h" - -EffectRack::EffectRack(EffectsManager* pEffectsManager, - EffectChainManager* pEffectChainManager, - const unsigned int iRackNumber, - const QString& group, SignalProcessingStage stage) - : m_pEngineEffectRack(nullptr), - m_pEffectsManager(pEffectsManager), - m_pEffectChainManager(pEffectChainManager), - m_signalProcessingStage(stage), - m_iRackNumber(iRackNumber), - m_group(group), - m_controlNumEffectChainSlots(ConfigKey(m_group, "num_effectunits")), - m_controlClearRack(ConfigKey(m_group, "clear")) { - connect(&m_controlClearRack, SIGNAL(valueChanged(double)), - this, SLOT(slotClearRack(double))); - m_controlNumEffectChainSlots.setReadOnly(); - addToEngine(); -} - -EffectRack::~EffectRack() { - removeFromEngine(); - //qDebug() << "EffectRack::~EffectRack()"; -} - -EngineEffectRack* EffectRack::getEngineEffectRack() { - return m_pEngineEffectRack; -} - -void EffectRack::addToEngine() { - m_pEngineEffectRack = new EngineEffectRack(m_iRackNumber); - EffectsRequest* pRequest = new EffectsRequest(); - pRequest->type = EffectsRequest::ADD_EFFECT_RACK; - pRequest->AddEffectRack.pRack = m_pEngineEffectRack; - pRequest->AddEffectRack.signalProcessingStage = m_signalProcessingStage; - m_pEffectsManager->writeRequest(pRequest); - - // Add all effect chains. - for (int i = 0; i < m_effectChainSlots.size(); ++i) { - EffectChainSlotPointer pSlot = m_effectChainSlots[i]; - EffectChainPointer pChain = pSlot->getEffectChain(); - if (pChain) { - // Add the effect to the engine. - pChain->addToEngine(m_pEngineEffectRack, i); - // Update its parameters in the engine. - pChain->updateEngineState(); - } - } -} - -void EffectRack::removeFromEngine() { - // Order doesn't matter when removing. - for (int i = 0; i < m_effectChainSlots.size(); ++i) { - EffectChainSlotPointer pSlot = m_effectChainSlots[i]; - EffectChainPointer pChain = pSlot->getEffectChain(); - if (pChain) { - pChain->removeFromEngine(m_pEngineEffectRack, i); - } - } - - EffectsRequest* pRequest = new EffectsRequest(); - pRequest->type = EffectsRequest::REMOVE_EFFECT_RACK; - pRequest->RemoveEffectRack.signalProcessingStage = m_signalProcessingStage; - pRequest->RemoveEffectRack.pRack = m_pEngineEffectRack; - m_pEffectsManager->writeRequest(pRequest); - m_pEngineEffectRack = NULL; -} - -void EffectRack::registerInputChannel(const ChannelHandleAndGroup& handle_group) { - foreach (EffectChainSlotPointer pChainSlot, m_effectChainSlots) { - pChainSlot->registerInputChannel(handle_group); - } -} - -void EffectRack::slotClearRack(double v) { - if (v > 0) { - foreach (EffectChainSlotPointer pChainSlot, m_effectChainSlots) { - pChainSlot->clear(); - } - } -} - -int EffectRack::numEffectChainSlots() const { - return m_effectChainSlots.size(); -} - -void EffectRack::addEffectChainSlotInternal(EffectChainSlotPointer pChainSlot) { - m_effectChainSlots.append(pChainSlot); - m_controlNumEffectChainSlots.forceSet( - m_controlNumEffectChainSlots.get() + 1); -} - -EffectChainSlotPointer EffectRack::getEffectChainSlot(int i) { - if (i < 0 || i >= m_effectChainSlots.size()) { - qWarning() << "WARNING: Invalid index for getEffectChainSlot"; - return EffectChainSlotPointer(); - } - return m_effectChainSlots[i]; -} - -void EffectRack::loadNextChain(const unsigned int iChainSlotNumber, - EffectChainPointer pLoadedChain) { - if (pLoadedChain) { - pLoadedChain = pLoadedChain->prototype(); - } - - EffectChainPointer pNextChain = m_pEffectChainManager->getNextEffectChain( - pLoadedChain); - - pNextChain = EffectChain::clone(pNextChain); - pNextChain->addToEngine(m_pEngineEffectRack, iChainSlotNumber); - m_effectChainSlots[iChainSlotNumber]->loadEffectChainToSlot(pNextChain); - m_effectChainSlots[iChainSlotNumber]->updateRoutingSwitches(); -} - - -void EffectRack::loadPrevChain(const unsigned int iChainSlotNumber, - EffectChainPointer pLoadedChain) { - if (pLoadedChain) { - pLoadedChain = pLoadedChain->prototype(); - } - - EffectChainPointer pPrevChain = m_pEffectChainManager->getPrevEffectChain( - pLoadedChain); - - pPrevChain = EffectChain::clone(pPrevChain); - pPrevChain->addToEngine(m_pEngineEffectRack, iChainSlotNumber); - m_effectChainSlots[iChainSlotNumber]->loadEffectChainToSlot(pPrevChain); - m_effectChainSlots[iChainSlotNumber]->updateRoutingSwitches(); -} - -void EffectRack::maybeLoadEffect(const unsigned int iChainSlotNumber, - const unsigned int iEffectSlotNumber, - const QString& id) { - if (iChainSlotNumber >= static_cast(m_effectChainSlots.size())) { - return; - } - - EffectChainSlotPointer pChainSlot = m_effectChainSlots[iChainSlotNumber]; - if (pChainSlot == nullptr) { - return; - } - EffectSlotPointer pEffectSlot = pChainSlot->getEffectSlot(iEffectSlotNumber); - - bool loadNew = false; - if (pEffectSlot == nullptr || pEffectSlot->getEffect() == nullptr) { - loadNew = true; - } else if (id != pEffectSlot->getEffect()->getManifest()->id()) { - loadNew = true; - } - - if (loadNew) { - EffectChainPointer pChain = pChainSlot->getOrCreateEffectChain(m_pEffectsManager); - EffectPointer pEffect = m_pEffectsManager->instantiateEffect(id); - pChain->replaceEffect(iEffectSlotNumber, pEffect); - } -} - -void EffectRack::loadNextEffect(const unsigned int iChainSlotNumber, - const unsigned int iEffectSlotNumber, - EffectPointer pEffect) { - if (iChainSlotNumber >= static_cast(m_effectChainSlots.size())) { - return; - } - - QString effectId = pEffect ? pEffect->getManifest()->id() : QString(); - QString nextEffectId = m_pEffectsManager->getNextEffectId(effectId); - EffectPointer pNextEffect = m_pEffectsManager->instantiateEffect(nextEffectId); - - EffectChainSlotPointer pChainSlot = m_effectChainSlots[iChainSlotNumber]; - EffectChainPointer pChain = pChainSlot->getOrCreateEffectChain(m_pEffectsManager); - pChain->replaceEffect(iEffectSlotNumber, pNextEffect); -} - - -void EffectRack::loadPrevEffect(const unsigned int iChainSlotNumber, - const unsigned int iEffectSlotNumber, - EffectPointer pEffect) { - if (iChainSlotNumber >= static_cast(m_effectChainSlots.size())) { - return; - } - - QString effectId = pEffect ? pEffect->getManifest()->id() : QString(); - QString prevEffectId = m_pEffectsManager->getPrevEffectId(effectId); - EffectPointer pPrevEffect = m_pEffectsManager->instantiateEffect(prevEffectId); - - EffectChainSlotPointer pChainSlot = m_effectChainSlots[iChainSlotNumber]; - EffectChainPointer pChain = pChainSlot->getOrCreateEffectChain(m_pEffectsManager); - pChain->replaceEffect(iEffectSlotNumber, pPrevEffect); -} - -QDomElement EffectRack::toXml(QDomDocument* doc) const { - QDomElement rackElement = doc->createElement("Rack"); - QDomElement groupElement = doc->createElement("Group"); - QDomText groupText = doc->createTextNode(m_group); - groupElement.appendChild(groupText); - rackElement.appendChild(groupElement); - - QDomElement chainsElement = doc->createElement("Chains"); - for (EffectChainSlotPointer pChainSlot : m_effectChainSlots) { - QDomElement chain = pChainSlot->toXml(doc); - chainsElement.appendChild(chain); - } - rackElement.appendChild(chainsElement); - return rackElement; -} - -void EffectRack::refresh() { - for (const auto& pChainSlot: m_effectChainSlots) { - EffectChainPointer pChain = pChainSlot->getOrCreateEffectChain(m_pEffectsManager); - pChain->refreshAllEffects(); - } -} - -bool EffectRack::isAdoptMetaknobValueEnabled() const { - return m_pEffectChainManager->isAdoptMetaknobValueEnabled(); -} - -StandardEffectRack::StandardEffectRack(EffectsManager* pEffectsManager, - EffectChainManager* pChainManager, - const unsigned int iRackNumber) - : EffectRack(pEffectsManager, pChainManager, iRackNumber, - formatGroupString(iRackNumber), SignalProcessingStage::Postfader) { - for (int i = 0; i < EffectChainManager::kNumStandardEffectChains; ++i) { - addEffectChainSlot(); - } -} - -EffectChainSlotPointer StandardEffectRack::addEffectChainSlot() { - int iChainSlotNumber = numEffectChainSlots(); - - QString group = formatEffectChainSlotGroupString(getRackNumber(), - iChainSlotNumber); - EffectChainSlot* pChainSlot = - new EffectChainSlot(this, group, iChainSlotNumber); - - for (int i = 0; i < kNumEffectsPerUnit; ++i) { - pChainSlot->addEffectSlot( - StandardEffectRack::formatEffectSlotGroupString( - getRackNumber(), iChainSlotNumber, i)); - } - - connect(pChainSlot, SIGNAL(nextChain(unsigned int, EffectChainPointer)), - this, SLOT(loadNextChain(unsigned int, EffectChainPointer))); - connect(pChainSlot, SIGNAL(prevChain(unsigned int, EffectChainPointer)), - this, SLOT(loadPrevChain(unsigned int, EffectChainPointer))); - - connect(pChainSlot, SIGNAL(nextEffect(unsigned int, unsigned int, EffectPointer)), - this, SLOT(loadNextEffect(unsigned int, unsigned int, EffectPointer))); - connect(pChainSlot, SIGNAL(prevEffect(unsigned int, unsigned int, EffectPointer)), - this, SLOT(loadPrevEffect(unsigned int, unsigned int, EffectPointer))); - - // Register all the existing channels with the new EffectChain. - const QSet& registeredChannels = - m_pEffectChainManager->registeredInputChannels(); - for (const ChannelHandleAndGroup& handle_group : registeredChannels) { - pChainSlot->registerInputChannel(handle_group); - } - - EffectChainSlotPointer pChainSlotPointer = EffectChainSlotPointer(pChainSlot); - addEffectChainSlotInternal(pChainSlotPointer); - - return pChainSlotPointer; -} - -OutputEffectRack::OutputEffectRack(EffectsManager* pEffectsManager, - EffectChainManager* pChainManager) - : EffectRack(pEffectsManager, pChainManager, 0, - "[OutputEffectRack]", SignalProcessingStage::Postfader) { - - const QString unitGroup = "[OutputEffectRack_[Master]]"; - // Hard code only one EffectChainSlot - EffectChainSlot* pChainSlot = new EffectChainSlot(this, unitGroup, 0); - EffectChainPointer pChain(new EffectChain(m_pEffectsManager, unitGroup)); - pChainSlot->loadEffectChainToSlot(pChain); - pChain->addToEngine(getEngineEffectRack(), 0); - // Add a single EffectSlot for the master EQ effect - pChainSlot->addEffectSlot("[OutputEffectRack_[Master]_Effect1]"); - - connect(pChainSlot, SIGNAL(nextChain(unsigned int, EffectChainPointer)), - this, SLOT(loadNextChain(unsigned int, EffectChainPointer))); - connect(pChainSlot, SIGNAL(prevChain(unsigned int, EffectChainPointer)), - this, SLOT(loadPrevChain(unsigned int, EffectChainPointer))); - - connect(pChainSlot, SIGNAL(nextEffect(unsigned int, unsigned int, EffectPointer)), - this, SLOT(loadNextEffect(unsigned int, unsigned int, EffectPointer))); - connect(pChainSlot, SIGNAL(prevEffect(unsigned int, unsigned int, EffectPointer)), - this, SLOT(loadPrevEffect(unsigned int, unsigned int, EffectPointer))); - - // Register the master channel. - const ChannelHandleAndGroup* masterHandleAndGroup = nullptr; - - // TODO(Be): Remove this hideous hack to get the ChannelHandleAndGroup - const QSet& registeredChannels = - m_pEffectChainManager->registeredInputChannels(); - for (const ChannelHandleAndGroup& handle_group : registeredChannels) { - if (handle_group.name() == "[MasterOutput]") { - masterHandleAndGroup = &handle_group; - break; - } - } - DEBUG_ASSERT(masterHandleAndGroup != nullptr); - - pChainSlot->registerInputChannel(*masterHandleAndGroup); - pChain->enableForInputChannel(*masterHandleAndGroup); - pChain->setMix(1.0); - - EffectChainSlotPointer pChainSlotPointer = EffectChainSlotPointer(pChainSlot); - addEffectChainSlotInternal(pChainSlotPointer); -} - -PerGroupRack::PerGroupRack(EffectsManager* pEffectsManager, - EffectChainManager* pChainManager, - const unsigned int iRackNumber, - const QString& group) - : EffectRack(pEffectsManager, pChainManager, iRackNumber, group, - SignalProcessingStage::Prefader) { -} - -void PerGroupRack::setupForGroup(const QString& groupName) { - VERIFY_OR_DEBUG_ASSERT(!m_groupToChainSlot.contains(groupName)) { - return; - } - - int iChainSlotNumber = m_groupToChainSlot.size(); - QString chainSlotGroup = formatEffectChainSlotGroupForGroup( - getRackNumber(), iChainSlotNumber, groupName); - EffectChainSlot* pChainSlot = new EffectChainSlot(this, chainSlotGroup, - iChainSlotNumber); - EffectChainSlotPointer pChainSlotPointer(pChainSlot); - addEffectChainSlotInternal(pChainSlotPointer); - m_groupToChainSlot[groupName] = pChainSlotPointer; - - // TODO(rryan): Set up next/prev signals. - - EffectChainPointer pChain(new EffectChain(m_pEffectsManager, chainSlotGroup)); - pChainSlot->loadEffectChainToSlot(pChain); - pChain->addToEngine(getEngineEffectRack(), iChainSlotNumber); - // Set the chain to be fully wet. - pChain->setMix(1.0); - pChain->updateEngineState(); - - // TODO(rryan): remove. - const ChannelHandleAndGroup* handleAndGroup = nullptr; - for (const ChannelHandleAndGroup& handle_group : - m_pEffectChainManager->registeredInputChannels()) { - if (handle_group.name() == groupName) { - handleAndGroup = &handle_group; - break; - } - } - DEBUG_ASSERT(handleAndGroup != nullptr); - - // Register this channel alone with the chain slot. - pChainSlot->registerInputChannel(*handleAndGroup); - pChainSlot->updateRoutingSwitches(); - - // Add a single effect slot - pChainSlot->addEffectSlot(formatEffectSlotGroupString(0, groupName)); - // DlgPrefEq loads the Effect with loadEffectToGroup - - configureEffectChainSlotForGroup(pChainSlotPointer, groupName); -} - -bool PerGroupRack::loadEffectToGroup(const QString& groupName, EffectPointer pEffect) { - EffectChainSlotPointer pChainSlot = getGroupEffectChainSlot(groupName); - VERIFY_OR_DEBUG_ASSERT(pChainSlot) { - return false; - } - - EffectChainPointer pChain = pChainSlot->getOrCreateEffectChain(m_pEffectsManager); - pChain->replaceEffect(0, pEffect); - pChainSlot->updateRoutingSwitches(); - - if (pEffect != nullptr) { - pEffect->setEnabled(true); - } - return true; -} - -EffectChainSlotPointer PerGroupRack::getGroupEffectChainSlot(const QString& group) { - return m_groupToChainSlot[group]; -} - -QuickEffectRack::QuickEffectRack(EffectsManager* pEffectsManager, - EffectChainManager* pChainManager, - const unsigned int iRackNumber) - : PerGroupRack(pEffectsManager, pChainManager, iRackNumber, - QuickEffectRack::formatGroupString(iRackNumber)) { -} - -void QuickEffectRack::configureEffectChainSlotForGroup( - EffectChainSlotPointer pSlot, const QString& groupName) { - Q_UNUSED(groupName); - // Set the parameter default value to 0.5 (neutral). - pSlot->setSuperParameter(0.5); - pSlot->setSuperParameterDefaultValue(0.5); -} - -bool QuickEffectRack::loadEffectToGroup(const QString& groupName, - EffectPointer pEffect) { - PerGroupRack::loadEffectToGroup(groupName, pEffect); - EffectChainSlotPointer pChainSlot = getGroupEffectChainSlot(groupName); - // Force update metaknobs and parameters to match state of superknob - pChainSlot->setSuperParameter(pChainSlot->getSuperParameter(), true); - return true; -} - -EqualizerRack::EqualizerRack(EffectsManager* pEffectsManager, - EffectChainManager* pChainManager, - const unsigned int iRackNumber) - : PerGroupRack(pEffectsManager, pChainManager, iRackNumber, - EqualizerRack::formatGroupString(iRackNumber)) { -} - -void EqualizerRack::configureEffectChainSlotForGroup(EffectChainSlotPointer pSlot, - const QString& groupName) { - // Create aliases for legacy EQ controls. - // NOTE(rryan): If we ever add a second EqualizerRack then we need to make - // these only apply to the first. - EffectSlotPointer pEffectSlot = pSlot->getEffectSlot(0); - if (pEffectSlot) { - const QString& effectSlotGroup = pEffectSlot->getGroup(); - ControlDoublePrivate::insertAlias(ConfigKey(groupName, "filterLow"), - ConfigKey(effectSlotGroup, "parameter1")); - - ControlDoublePrivate::insertAlias(ConfigKey(groupName, "filterMid"), - ConfigKey(effectSlotGroup, "parameter2")); - - ControlDoublePrivate::insertAlias(ConfigKey(groupName, "filterHigh"), - ConfigKey(effectSlotGroup, "parameter3")); - - ControlDoublePrivate::insertAlias(ConfigKey(groupName, "filterLowKill"), - ConfigKey(effectSlotGroup, "button_parameter1")); - - ControlDoublePrivate::insertAlias(ConfigKey(groupName, "filterMidKill"), - ConfigKey(effectSlotGroup, "button_parameter2")); - - ControlDoublePrivate::insertAlias(ConfigKey(groupName, "filterHighKill"), - ConfigKey(effectSlotGroup, "button_parameter3")); - - ControlDoublePrivate::insertAlias(ConfigKey(groupName, "filterLow_loaded"), - ConfigKey(effectSlotGroup, "parameter1_loaded")); - - ControlDoublePrivate::insertAlias(ConfigKey(groupName, "filterMid_loaded"), - ConfigKey(effectSlotGroup, "parameter2_loaded")); - - ControlDoublePrivate::insertAlias(ConfigKey(groupName, "filterHigh_loaded"), - ConfigKey(effectSlotGroup, "parameter3_loaded")); - - ControlDoublePrivate::insertAlias(ConfigKey(groupName, "filterLowKill_loaded"), - ConfigKey(effectSlotGroup, "button_parameter1_loaded")); - - ControlDoublePrivate::insertAlias(ConfigKey(groupName, "filterMidKill_loaded"), - ConfigKey(effectSlotGroup, "button_parameter2_loaded")); - - ControlDoublePrivate::insertAlias(ConfigKey(groupName, "filterHighKill_loaded"), - ConfigKey(effectSlotGroup, "button_parameter3_loaded")); - } -} diff --git a/src/effects/effectrack.h b/src/effects/effectrack.h deleted file mode 100644 index 1f97f9f1d8a..00000000000 --- a/src/effects/effectrack.h +++ /dev/null @@ -1,263 +0,0 @@ -#ifndef EFFECTRACK_H -#define EFFECTRACK_H - -#include -#include -#include -#include - -#include "control/controlobject.h" -#include "engine/channelhandle.h" -#include "effects/defs.h" - -class EngineEffectRack; -class EffectsManager; -class EffectChainManager; - -#include "effects/effectchainslot.h" - -//TODO(Be): Remove these superfluous classes. -class EffectRack : public QObject { - Q_OBJECT - public: - EffectRack(EffectsManager* pEffectsManager, - EffectChainManager* pChainManager, - const unsigned int iRackNumber, - const QString& group, SignalProcessingStage stage); - virtual ~EffectRack(); - - void addToEngine(); - void removeFromEngine(); - EngineEffectRack* getEngineEffectRack(); - - void registerInputChannel(const ChannelHandleAndGroup& handle_group); - int numEffectChainSlots() const; - EffectChainSlotPointer getEffectChainSlot(int i); - - void maybeLoadEffect(const unsigned int iChainSlotNumber, - const unsigned int iEffectSlotNumber, - const QString& id); - - unsigned int getRackNumber() const { - return m_iRackNumber; - } - - const QString& getGroup() const { - return m_group; - } - - void refresh(); - - QDomElement toXml(QDomDocument* doc) const; - - virtual bool isAdoptMetaknobValueEnabled() const; - - public slots: - void slotClearRack(double v); - - private slots: - void loadNextChain(const unsigned int iChainSlotNumber, - EffectChainPointer pLoadedChain); - void loadPrevChain(const unsigned int iChainSlotNumber, - EffectChainPointer pLoadedChain); - - void loadNextEffect(const unsigned int iChainSlotNumber, - const unsigned int iEffectSlotNumber, - EffectPointer pEffect); - void loadPrevEffect(const unsigned int iChainSlotNumber, - const unsigned int iEffectSlotNumber, - EffectPointer pEffect); - - protected: - void addEffectChainSlotInternal(EffectChainSlotPointer pChainSlot); - - EngineEffectRack* m_pEngineEffectRack; - - // We could make accessors for these for sub-classes. Doesn't really matter. - EffectsManager* m_pEffectsManager; - EffectChainManager* m_pEffectChainManager; - - private: - SignalProcessingStage m_signalProcessingStage; - const unsigned int m_iRackNumber; - const QString m_group; - QList m_effectChainSlots; - ControlObject m_controlNumEffectChainSlots; - ControlObject m_controlClearRack; -}; - -class StandardEffectRack : public EffectRack { - Q_OBJECT - public: - StandardEffectRack(EffectsManager* pEffectsManager, - EffectChainManager* pChainManager, - const unsigned int iRackNumber); - virtual ~StandardEffectRack() {} - - static QString formatGroupString(const unsigned int iRackNumber) { - return QString("[EffectRack%1]") - .arg(QString::number(iRackNumber + 1)); - } - - static QString formatEffectChainSlotGroupString(const unsigned int iRackNumber, - const unsigned int iChainSlotNumber) { - return QString("[EffectRack%1_EffectUnit%2]") - .arg(QString::number(iRackNumber + 1)) - .arg(QString::number(iChainSlotNumber + 1)); - } - - static QString formatEffectSlotGroupString(const unsigned int iRackNumber, - const unsigned int iChainSlotNumber, - const unsigned int iEffectSlotNumber) { - return QString("[EffectRack%1_EffectUnit%2_Effect%3]") - .arg(QString::number(iRackNumber + 1)) - .arg(QString::number(iChainSlotNumber + 1)) - .arg(QString::number(iEffectSlotNumber + 1)); - } - - EffectChainSlotPointer addEffectChainSlot(); -}; - -class OutputEffectRack : public EffectRack { - Q_OBJECT - public: - OutputEffectRack(EffectsManager* pEffectsManager, - EffectChainManager* pChainManager); - virtual ~OutputEffectRack() {}; -}; - -class PerGroupRack : public EffectRack { - Q_OBJECT - public: - PerGroupRack(EffectsManager* pEffectsManager, - EffectChainManager* pChainManager, - const unsigned int iRackNumber, - const QString& group); - virtual ~PerGroupRack() {} - - - void setupForGroup(const QString& group); - EffectChainSlotPointer getGroupEffectChainSlot(const QString& group); - virtual bool loadEffectToGroup(const QString& group, EffectPointer pEffect); - - protected: - virtual void configureEffectChainSlotForGroup(EffectChainSlotPointer pSlot, - const QString& group) = 0; - - virtual QString formatEffectChainSlotGroupForGroup(const unsigned int iRackNumber, - const unsigned int iChainSlotNumber, - const QString& group) const = 0; - - virtual QString formatEffectSlotGroupString(const unsigned int iEffectSlotNumber, - const QString& group) const = 0; - - private: - QHash m_groupToChainSlot; -}; - -class QuickEffectRack : public PerGroupRack { - Q_OBJECT - public: - QuickEffectRack(EffectsManager* pEffectsManager, - EffectChainManager* pChainManager, - const unsigned int iRackNumber); - virtual ~QuickEffectRack() {} - - bool loadEffectToGroup(const QString& group, EffectPointer pEffect) override; - - static QString formatGroupString(const unsigned int iRackNumber) { - return QString("[QuickEffectRack%1]") - .arg(QString::number(iRackNumber + 1)); - } - - static QString formatEffectChainSlotGroupString(const unsigned int iRackNumber, - const QString& group) { - return QString("[QuickEffectRack%1_%2]") - .arg(QString::number(iRackNumber + 1)) - .arg(group); - } - - static QString formatEffectSlotGroupString(const unsigned int iRackNumber, - const unsigned int iEffectSlotNumber, - const QString& group) { - return QString("[QuickEffectRack%1_%2_Effect%3]") - .arg(QString::number(iRackNumber + 1)) - .arg(group) - .arg(QString::number(iEffectSlotNumber + 1)); - } - - QString formatEffectSlotGroupString(const unsigned int iEffectSlotNumber, - const QString& group) const { - return formatEffectSlotGroupString(getRackNumber(), iEffectSlotNumber, - group); - } - - bool isAdoptMetaknobValueEnabled() const override { - // No visible Metaknobs to adopt - return false; - } - - protected: - void configureEffectChainSlotForGroup(EffectChainSlotPointer pSlot, - const QString& group) override; - - virtual QString formatEffectChainSlotGroupForGroup(const unsigned int iRackNumber, - const unsigned int iChainSlotNumber, - const QString& group) const { - Q_UNUSED(iChainSlotNumber); - return formatEffectChainSlotGroupString(iRackNumber, group); - } -}; - -class EqualizerRack : public PerGroupRack { - Q_OBJECT - public: - EqualizerRack(EffectsManager* pEffectsManager, - EffectChainManager* pChainManager, - const unsigned int iRackNumber); - virtual ~EqualizerRack() {} - - static QString formatGroupString(const unsigned int iRackNumber) { - return QString("[EqualizerRack%1]") - .arg(QString::number(iRackNumber + 1)); - } - - static QString formatEffectChainSlotGroupString(const unsigned int iRackNumber, - const QString& group) { - return QString("[EqualizerRack%1_%2]") - .arg(QString::number(iRackNumber + 1)) - .arg(group); - } - - static QString formatEffectSlotGroupString(const unsigned int iRackNumber, - const unsigned int iEffectSlotNumber, - const QString& group) { - return QString("[EqualizerRack%1_%2_Effect%3]") - .arg(QString::number(iRackNumber + 1)) - .arg(group) - .arg(QString::number(iEffectSlotNumber + 1)); - } - - QString formatEffectSlotGroupString(const unsigned int iEffectSlotNumber, - const QString& group) const { - return formatEffectSlotGroupString(getRackNumber(), iEffectSlotNumber, - group); - } - - bool isAdoptMetaknobValueEnabled() const override { - // No visible Metaknobs to adopt - return false; - } - - protected: - void configureEffectChainSlotForGroup(EffectChainSlotPointer pSlot, - const QString& group) override; - virtual QString formatEffectChainSlotGroupForGroup(const unsigned int iRackNumber, - const unsigned int iChainSlotNumber, - const QString& group) const { - Q_UNUSED(iChainSlotNumber); - return formatEffectChainSlotGroupString(iRackNumber, group); - } -}; - -#endif /* EFFECTRACK_H */ diff --git a/src/effects/effectsbackend.cpp b/src/effects/effectsbackend.cpp deleted file mode 100644 index dc2e9974fd0..00000000000 --- a/src/effects/effectsbackend.cpp +++ /dev/null @@ -1,59 +0,0 @@ -#include - -#include "effects/effectsbackend.h" -#include "effects/effectsmanager.h" - -EffectsBackend::EffectsBackend(QObject* pParent, - EffectBackendType type) - : QObject(pParent), - m_type(type) { -} - -EffectsBackend::~EffectsBackend() { - m_registeredEffects.clear(); - m_effectIds.clear(); -} - -void EffectsBackend::registerEffect(const QString& id, - EffectManifestPointer pManifest, - EffectInstantiatorPointer pInstantiator) { - if (m_registeredEffects.contains(id)) { - qWarning() << "WARNING: Effect" << id << "already registered"; - return; - } - - pManifest->setBackendType(m_type); - - m_registeredEffects[id] = RegisteredEffect(pManifest, pInstantiator); - m_effectIds.append(id); - emit(effectRegistered(pManifest)); -} - -const QList EffectsBackend::getEffectIds() const { - return m_effectIds; -} - -EffectManifestPointer EffectsBackend::getManifest(const QString& effectId) const { - if (!m_registeredEffects.contains(effectId)) { - qWarning() << "WARNING: Effect" << effectId << "is not registered."; - return EffectManifestPointer(); - } - return m_registeredEffects[effectId].manifest(); -} - -bool EffectsBackend::canInstantiateEffect(const QString& effectId) const { - return m_registeredEffects.contains(effectId); -} - -EffectPointer EffectsBackend::instantiateEffect(EffectsManager* pEffectsManager, - const QString& effectId) { - if (!m_registeredEffects.contains(effectId)) { - qWarning() << "WARNING: Effect" << effectId << "is not registered."; - return EffectPointer(); - } - RegisteredEffect& effectInfo = m_registeredEffects[effectId]; - - return EffectPointer(new Effect(pEffectsManager, - effectInfo.manifest(), - effectInfo.initiator())); -} diff --git a/src/effects/effectsbackend.h b/src/effects/effectsbackend.h index e1d2c327b6c..770985cf600 100644 --- a/src/effects/effectsbackend.h +++ b/src/effects/effectsbackend.h @@ -7,70 +7,27 @@ #include #include "effects/defs.h" -#include "effects/effect.h" -#include "effects/effectinstantiator.h" +#include "effects/effectslot.h" #include "preferences/usersettings.h" -class EffectsManager; -class EffectsBackend; +#include "util/memory.h" + class EffectProcessor; -// An EffectsBackend is an implementation of a provider of Effect's for use -// within the rest of Mixxx. The job of the EffectsBackend is to both enumerate -// and instantiate effects. -class EffectsBackend : public QObject { - Q_OBJECT +// EffectsBackend enumerates available effects and instantiates EffectProcessors +class EffectsBackend { public: - EffectsBackend(QObject* pParent, EffectBackendType type); - virtual ~EffectsBackend(); - - // returns a list sorted like it should be displayed in the GUI - virtual const QList getEffectIds() const; - virtual EffectManifestPointer getManifest(const QString& effectId) const; - virtual bool canInstantiateEffect(const QString& effectId) const; - virtual EffectPointer instantiateEffect( - EffectsManager* pEffectsManager, const QString& effectId); - - signals: - void effectRegistered(EffectManifestPointer); - - protected: - void registerEffect(const QString& id, - EffectManifestPointer pManifest, - EffectInstantiatorPointer pInstantiator); - - template - void registerEffect() { - registerEffect( - EffectProcessorImpl::getId(), - EffectProcessorImpl::getManifest(), - EffectInstantiatorPointer( - new EffectProcessorInstantiator())); - } - - EffectBackendType m_type; - - private: - class RegisteredEffect { - public: - RegisteredEffect(EffectManifestPointer pManifest, EffectInstantiatorPointer pInitator) - : m_pManifest(pManifest), - m_pInitator(pInitator) { - } - - RegisteredEffect() { - } + virtual ~EffectsBackend() {}; - EffectManifestPointer manifest() const { return m_pManifest; }; - EffectInstantiatorPointer initiator() const { return m_pInitator; }; + virtual EffectBackendType getType() const = 0; - private: - EffectManifestPointer m_pManifest; - EffectInstantiatorPointer m_pInitator; - }; + // returns a list sorted like it should be displayed in the GUI + virtual const QList getEffectIds() const = 0; + virtual EffectManifestPointer getManifest(const QString& effectId) const = 0; + virtual bool canInstantiateEffect(const QString& effectId) const = 0; - QMap m_registeredEffects; - QList m_effectIds; + virtual std::unique_ptr createProcessor( + const EffectManifestPointer pManifest) const = 0; }; #endif /* EFFECTSBACKEND_H */ diff --git a/src/effects/effectslot.cpp b/src/effects/effectslot.cpp index 3b338cb2699..0f827519702 100644 --- a/src/effects/effectslot.cpp +++ b/src/effects/effectslot.cpp @@ -3,6 +3,7 @@ #include +#include "effects/defs.h" #include "control/controlpushbutton.h" #include "control/controlencoder.h" #include "control/controlproxy.h" @@ -13,209 +14,354 @@ const unsigned int kDefaultMaxParameters = 16; EffectSlot::EffectSlot(const QString& group, - const unsigned int iChainNumber, - const unsigned int iEffectnumber) - : m_iChainNumber(iChainNumber), - m_iEffectNumber(iEffectnumber), - m_group(group) { + EffectsManager* pEffectsManager, + const unsigned int iEffectnumber, + EngineEffectChain* pEngineEffectChain) + : m_iEffectNumber(iEffectnumber), + m_group(group), + m_pEffectsManager(pEffectsManager), + m_pEngineEffectChain(pEngineEffectChain), + m_pEngineEffect(nullptr) { + VERIFY_OR_DEBUG_ASSERT(m_pEngineEffectChain != nullptr) { + return; + } + m_pControlLoaded = new ControlObject(ConfigKey(m_group, "loaded")); m_pControlLoaded->setReadOnly(); - m_pControlNumParameters = new ControlObject(ConfigKey(m_group, "num_parameters")); - m_pControlNumParameters->setReadOnly(); - - m_pControlNumParameterSlots = new ControlObject(ConfigKey(m_group, "num_parameterslots")); - m_pControlNumParameterSlots->setReadOnly(); - - m_pControlNumButtonParameters = new ControlObject(ConfigKey(m_group, "num_button_parameters")); - m_pControlNumButtonParameters->setReadOnly(); + m_pControlNumParameters.insert(EffectManifestParameter::ParameterType::KNOB, + new ControlObject(ConfigKey(m_group, "num_parameters"))); + m_pControlNumParameters.insert(EffectManifestParameter::ParameterType::BUTTON, + new ControlObject(ConfigKey(m_group, "num_button_parameters"))); + for (const auto& pControlNumParameters : m_pControlNumParameters) { + pControlNumParameters->setReadOnly(); + } - m_pControlNumButtonParameterSlots = new ControlObject(ConfigKey(m_group, "num_button_parameterslots")); - m_pControlNumButtonParameterSlots->setReadOnly(); + m_pControlNumParameterSlots.insert(EffectManifestParameter::ParameterType::KNOB, + new ControlObject(ConfigKey(m_group, "num_parameterslots"))); + m_pControlNumParameterSlots.insert(EffectManifestParameter::ParameterType::BUTTON, + new ControlObject(ConfigKey(m_group, "num_button_parameterslots"))); + for (const auto& pControlNumParameterSlots : m_pControlNumParameterSlots) { + pControlNumParameterSlots->setReadOnly(); + } // Default to disabled to prevent accidental activation of effects // at the beginning of a set. m_pControlEnabled = new ControlPushButton(ConfigKey(m_group, "enabled")); m_pControlEnabled->setButtonMode(ControlPushButton::POWERWINDOW); - connect(m_pControlEnabled, SIGNAL(valueChanged(double)), - this, SLOT(slotEnabled(double))); + connect(m_pControlEnabled, &ControlObject::valueChanged, + this, &EffectSlot::updateEngineState); m_pControlNextEffect = new ControlPushButton(ConfigKey(m_group, "next_effect")); - connect(m_pControlNextEffect, SIGNAL(valueChanged(double)), - this, SLOT(slotNextEffect(double))); + connect(m_pControlNextEffect, &ControlObject::valueChanged, + this, &EffectSlot::slotNextEffect); m_pControlPrevEffect = new ControlPushButton(ConfigKey(m_group, "prev_effect")); - connect(m_pControlPrevEffect, SIGNAL(valueChanged(double)), - this, SLOT(slotPrevEffect(double))); + connect(m_pControlPrevEffect, &ControlObject::valueChanged, + this, &EffectSlot::slotPrevEffect); // Ignoring no-ops is important since this is for +/- tickers. m_pControlEffectSelector = new ControlEncoder(ConfigKey(m_group, "effect_selector"), false); - connect(m_pControlEffectSelector, SIGNAL(valueChanged(double)), - this, SLOT(slotEffectSelector(double))); + connect(m_pControlEffectSelector, &ControlObject::valueChanged, + this, &EffectSlot::slotEffectSelector); m_pControlClear = new ControlPushButton(ConfigKey(m_group, "clear")); - connect(m_pControlClear, SIGNAL(valueChanged(double)), - this, SLOT(slotClear(double))); + connect(m_pControlClear, &ControlObject::valueChanged, + this, &EffectSlot::slotClear); for (unsigned int i = 0; i < kDefaultMaxParameters; ++i) { - addEffectParameterSlot(); - addEffectButtonParameterSlot(); + addEffectParameterSlot(EffectManifestParameter::ParameterType::KNOB); + addEffectParameterSlot(EffectManifestParameter::ParameterType::BUTTON); } m_pControlMetaParameter = new ControlPotmeter(ConfigKey(m_group, "meta"), 0.0, 1.0); - connect(m_pControlMetaParameter, SIGNAL(valueChanged(double)), - this, SLOT(slotEffectMetaParameter(double))); + // QObject::connect cannot connect to slots with optional parameters using function + // pointer syntax if the slot has more parameters than the signal, so use a lambda + // to hack around this limitation. + connect(m_pControlMetaParameter, &ControlObject::valueChanged, + this, [=](double value){slotEffectMetaParameter(value);} ); m_pControlMetaParameter->set(0.0); m_pControlMetaParameter->setDefaultValue(0.0); - m_pSoftTakeover = new SoftTakeover(); + m_pMetaknobSoftTakeover = new SoftTakeover(); - clear(); + m_pControlLoaded->forceSet(0.0); } EffectSlot::~EffectSlot() { //qDebug() << debugString() << "destroyed"; - clear(); + unloadEffect(); delete m_pControlLoaded; - delete m_pControlNumParameters; - delete m_pControlNumParameterSlots; - delete m_pControlNumButtonParameters; - delete m_pControlNumButtonParameterSlots; + for (const auto& pControlNumParameters : m_pControlNumParameters) { + delete pControlNumParameters; + } + for (const auto& pControlNumParameterSlots : m_pControlNumParameterSlots) { + delete pControlNumParameterSlots; + } delete m_pControlNextEffect; delete m_pControlPrevEffect; delete m_pControlEffectSelector; delete m_pControlClear; delete m_pControlEnabled; delete m_pControlMetaParameter; - delete m_pSoftTakeover; + delete m_pMetaknobSoftTakeover; +} + +void EffectSlot::addToEngine(std::unique_ptr pProcessor, + const QSet& activeInputChannels) { + VERIFY_OR_DEBUG_ASSERT(!isLoaded()) { + return; + } + + VERIFY_OR_DEBUG_ASSERT(m_pEngineEffect == nullptr) { + return; + } + + m_pEngineEffect = new EngineEffect(m_pManifest, + activeInputChannels, + m_pEffectsManager, + std::move(pProcessor)); + + EffectsRequest* request = new EffectsRequest(); + request->type = EffectsRequest::ADD_EFFECT_TO_CHAIN; + request->pTargetChain = m_pEngineEffectChain; + request->AddEffectToChain.pEffect = m_pEngineEffect; + request->AddEffectToChain.iIndex = m_iEffectNumber; + m_pEffectsManager->writeRequest(request); } -EffectParameterSlotPointer EffectSlot::addEffectParameterSlot() { - EffectParameterSlotPointer pParameter = EffectParameterSlotPointer( - new EffectParameterSlot(m_group, m_parameters.size())); - m_parameters.append(pParameter); - m_pControlNumParameterSlots->forceSet( - m_pControlNumParameterSlots->get() + 1); - return pParameter; +void EffectSlot::removeFromEngine() { + VERIFY_OR_DEBUG_ASSERT(isLoaded()) { + return; + } + + EffectsRequest* request = new EffectsRequest(); + request->type = EffectsRequest::REMOVE_EFFECT_FROM_CHAIN; + request->pTargetChain = m_pEngineEffectChain; + request->RemoveEffectFromChain.pEffect = m_pEngineEffect; + request->RemoveEffectFromChain.iIndex = m_iEffectNumber; + m_pEffectsManager->writeRequest(request); + + m_pEngineEffect = nullptr; } -EffectButtonParameterSlotPointer EffectSlot::addEffectButtonParameterSlot() { - EffectButtonParameterSlotPointer pParameter = EffectButtonParameterSlotPointer( - new EffectButtonParameterSlot(m_group, m_buttonParameters.size())); - m_buttonParameters.append(pParameter); - m_pControlNumButtonParameterSlots->forceSet( - m_pControlNumButtonParameterSlots->get() + 1); - return pParameter; +void EffectSlot::updateEngineState() { + if (!m_pEngineEffect) { + return; + } + + EffectsRequest* pRequest = new EffectsRequest(); + pRequest->type = EffectsRequest::SET_EFFECT_PARAMETERS; + pRequest->pTargetEffect = m_pEngineEffect; + pRequest->SetEffectParameters.enabled = m_pControlEnabled->get(); + m_pEffectsManager->writeRequest(pRequest); + + for (auto const& pParameter : m_parameters) { + pParameter->updateEngineState(); + } } -EffectPointer EffectSlot::getEffect() const { - return m_pEffect; +EffectState* EffectSlot::createState(const mixxx::EngineParameters& bufferParameters) { + VERIFY_OR_DEBUG_ASSERT(m_pEngineEffect != nullptr) { + return new EffectState(bufferParameters); + } + return m_pEngineEffect->createState(bufferParameters); } -unsigned int EffectSlot::numParameterSlots() const { - return m_parameters.size(); +EffectManifestPointer EffectSlot::getManifest() const { + return m_pManifest; } -unsigned int EffectSlot::numButtonParameterSlots() const { - return m_buttonParameters.size(); +void EffectSlot::addEffectParameterSlot(EffectManifestParameter::ParameterType parameterType) { + EffectParameterSlotBasePointer pParameterSlot = EffectParameterSlotBasePointer(); + if (parameterType == EffectManifestParameter::ParameterType::KNOB) { + pParameterSlot = static_cast( + new EffectKnobParameterSlot(m_group, m_iNumParameterSlots[parameterType])); + } else if (parameterType == EffectManifestParameter::ParameterType::BUTTON) { + pParameterSlot = static_cast( + new EffectButtonParameterSlot(m_group, m_iNumParameterSlots[parameterType])); + } + ++m_iNumParameterSlots[parameterType]; + m_pControlNumParameterSlots[parameterType]->forceSet( + m_pControlNumParameterSlots[parameterType]->get() + 1); + VERIFY_OR_DEBUG_ASSERT(m_iNumParameterSlots[parameterType] == + m_pControlNumParameterSlots[parameterType]->get()) { + return; + } + m_parameterSlots.append(pParameterSlot); } -void EffectSlot::slotEnabled(double v) { - //qDebug() << debugString() << "slotEnabled" << v; - if (m_pEffect) { - m_pEffect->setEnabled(v > 0); +unsigned int EffectSlot::numParameters(EffectManifestParameter::ParameterType parameterType) const { + unsigned int num = 0; + for (auto const& pParameter : m_parameters) { + if (parameterType == pParameter->manifest()->parameterType()) { + ++num; + } } + return num; } -void EffectSlot::slotEffectEnabledChanged(bool enabled) { +void EffectSlot::setEnabled(bool enabled) { m_pControlEnabled->set(enabled); } -EffectParameterSlotPointer EffectSlot::getEffectParameterSlot(unsigned int slotNumber) { - //qDebug() << debugString() << "getEffectParameterSlot" << slotNumber; - if (slotNumber >= static_cast(m_parameters.size())) { - qWarning() << "WARNING: slotNumber out of range"; - return EffectParameterSlotPointer(); +EffectParameterSlotBasePointer EffectSlot::getEffectParameterSlot(EffectManifestParameter::ParameterType parameterType, + unsigned int slotNumber) { + // qDebug() << debugString() << "getEffectParameterSlot" << static_cast(parameterType) << ' ' << slotNumber; + + int iSlotNumber = 0; + for (const auto& pParameterSlot : m_parameterSlots) { + if (pParameterSlot->parameterType() == parameterType) { + if (iSlotNumber == slotNumber) { + return pParameterSlot; + } + ++iSlotNumber; + } } - return m_parameters[slotNumber]; + return EffectParameterSlotBasePointer(); } -EffectButtonParameterSlotPointer EffectSlot::getEffectButtonParameterSlot(unsigned int slotNumber) { - //qDebug() << debugString() << "getEffectParameterSlot" << slotNumber; - if (slotNumber >= static_cast(m_buttonParameters.size())) { - qWarning() << "WARNING: slotNumber out of range"; - return EffectButtonParameterSlotPointer(); +void EffectSlot::loadEffect(const EffectManifestPointer pManifest, + std::unique_ptr pProcessor, + const QSet& activeChannels) { + unloadEffect(); + + m_pManifest = pManifest; + + if (pManifest == EffectManifestPointer()) { + // No new effect to load; just unload the old effect and return. + emit(effectChanged()); + return; } - return m_buttonParameters[slotNumber]; -} -void EffectSlot::loadEffect(EffectPointer pEffect, bool adoptMetaknobPosition) { - //qDebug() << debugString() << "loadEffect" - // << (pEffect ? pEffect->getManifest().name() : "(null)"); - if (pEffect) { - m_pEffect = pEffect; - m_pControlLoaded->forceSet(1.0); - m_pControlNumParameters->forceSet(pEffect->numKnobParameters()); - m_pControlNumButtonParameters->forceSet(pEffect->numButtonParameters()); - - // The enabled status persists in the EffectSlot when loading a new - // EffectPointer to the EffectSlot. Effects and EngineEffects default to - // disabled, so if this EffectSlot was enabled, enable the Effect and EngineEffect. - pEffect->setEnabled(m_pControlEnabled->toBool()); - - connect(pEffect.data(), SIGNAL(enabledChanged(bool)), - this, SLOT(slotEffectEnabledChanged(bool))); - - while (static_cast(m_parameters.size()) - < pEffect->numKnobParameters()) { - addEffectParameterSlot(); - } + for (auto& parameterMapping : m_mapForParameterType) { + parameterMapping.clear(); + } - while (static_cast(m_buttonParameters.size()) - < pEffect->numButtonParameters()) { - addEffectButtonParameterSlot(); - } + addToEngine(std::move(pProcessor), activeChannels); - for (const auto& pParameter : m_parameters) { - pParameter->loadEffect(pEffect); - } - for (const auto& pParameter : m_buttonParameters) { - pParameter->loadEffect(pEffect); - } + int index = 0; + for (const auto& pManifestParameter: m_pManifest->parameters()) { + EffectParameter* pParameter = new EffectParameter( + m_pEngineEffect, m_pEffectsManager, m_parameters.size(), pManifestParameter); + m_parameters.append(pParameter); + m_mapForParameterType[pManifestParameter->parameterType()].push_back(index); + ++index; + } - if (adoptMetaknobPosition) { - slotEffectMetaParameter(m_pControlMetaParameter->get(), true); - } else { - m_pControlMetaParameter->set(pEffect->getMetaknobDefault()); - slotEffectMetaParameter(pEffect->getMetaknobDefault(), true); - } + m_pControlLoaded->forceSet(1.0); - emit(effectLoaded(pEffect, m_iEffectNumber)); + loadParameters(); + + if (m_pEffectsManager->isAdoptMetaknobValueEnabled()) { + slotEffectMetaParameter(m_pControlMetaParameter->get(), true); } else { - clear(); - // Broadcasts a null effect pointer - emit(effectLoaded(EffectPointer(), m_iEffectNumber)); + m_pControlMetaParameter->set(m_pManifest->metaknobDefault()); + slotEffectMetaParameter(m_pManifest->metaknobDefault(), true); } - emit(updated()); + + emit(effectChanged()); + updateEngineState(); } -void EffectSlot::clear() { - if (m_pEffect) { - m_pEffect->disconnect(this); +void EffectSlot::unloadEffect() { + if (!isLoaded()) { + return; } + m_pControlLoaded->forceSet(0.0); - m_pControlNumParameters->forceSet(0.0); - m_pControlNumButtonParameters->forceSet(0.0); - for (const auto& pParameter : m_parameters) { - pParameter->clear(); + for (const auto& pControlNumParameters : m_pControlNumParameters) { + pControlNumParameters->forceSet(0.0); + } + + for (const auto& pParameterSlot : m_parameterSlots) { + pParameterSlot->clear(); } - for (const auto& pParameter : m_buttonParameters) { - pParameter->clear(); + + for (int i = 0; i < m_parameters.size(); ++i) { + EffectParameter* pParameter = m_parameters.at(i); + m_parameters[i] = nullptr; + delete pParameter; + } + m_parameters.clear(); + m_pManifest.clear(); + for (auto& parameterMapping : m_mapForParameterType) { + parameterMapping.clear(); + } + + removeFromEngine(); +} + +void EffectSlot::loadParameters() { + int numTypes = static_cast(EffectManifestParameter::ParameterType::NUM_TYPES); + for (int parameterTypeId=0 ; parameterTypeId(parameterTypeId); + + m_pControlNumParameters[parameterType]->forceSet(numParameters(parameterType)); + + unsigned int parameterSlotIndex = 0; + unsigned int numParameterSlots = m_iNumParameterSlots[parameterType]; + + // Load EffectParameters into the slot indicated by m_mapForParameterType + for (int i=0 ; iloadParameter(pParameter); + ++parameterSlotIndex; + } + + // Clear any EffectParameterSlots that still have a loaded parameter from before + // but the loop above did not load a new parameter into them + while (parameterSlotIndex < numParameterSlots) { + auto pParameterSlot = getEffectParameterSlot(parameterType, parameterSlotIndex); + VERIFY_OR_DEBUG_ASSERT(pParameterSlot != nullptr) { + ++parameterSlotIndex; + continue; + } + pParameterSlot->clear(); + ++parameterSlotIndex; + } + } +} + +void EffectSlot::hideEffectParameter(const unsigned int parameterId) { + for (auto& parameterMapping : m_mapForParameterType) { + parameterMapping.removeAll(parameterId); + } + + loadParameters(); +} + +void EffectSlot::setEffectParameterPosition(const unsigned int parameterId, + const unsigned int position) { + for (auto& parameterMapping : m_mapForParameterType) { + parameterMapping.removeAll(parameterId); + } + + auto pParameter = m_parameters.at(parameterId); + if (pParameter) { + m_mapForParameterType[pParameter->manifest()->parameterType()].insert(position, parameterId); + loadParameters(); } - m_pEffect.clear(); - emit(updated()); } void EffectSlot::slotPrevEffect(double v) { @@ -231,22 +377,26 @@ void EffectSlot::slotNextEffect(double v) { } void EffectSlot::slotEffectSelector(double v) { - if (v > 0) { - emit(nextEffect(m_iChainNumber, m_iEffectNumber, m_pEffect)); - } else if (v < 0) { - emit(prevEffect(m_iChainNumber, m_iEffectNumber, m_pEffect)); - } + // TODO: reimplement + // if (v > 0) { + // emit(nextEffect(m_iChainNumber, m_iEffectNumber, m_pEffect)); + // } else if (v < 0) { + // emit(prevEffect(m_iChainNumber, m_iEffectNumber, m_pEffect)); + // } } void EffectSlot::slotClear(double v) { if (v > 0) { - emit(clearEffect(m_iEffectNumber)); + unloadEffect(); + emit(effectChanged()); } } void EffectSlot::syncSofttakeover() { - for (const auto& pParameterSlot : m_parameters) { - pParameterSlot->syncSofttakeover(); + for (const auto pParameterSlot : m_parameterSlots) { + if (pParameterSlot->parameterType() == EffectManifestParameter::ParameterType::KNOB) { + pParameterSlot->syncSofttakeover(); + } } } @@ -257,7 +407,7 @@ double EffectSlot::getMetaParameter() const { // This function is for the superknob to update individual effects' meta knobs // slotEffectMetaParameter does not need to update m_pControlMetaParameter's value void EffectSlot::setMetaParameter(double v, bool force) { - if (!m_pSoftTakeover->ignore(m_pControlMetaParameter, v) + if (!m_pMetaknobSoftTakeover->ignore(m_pControlMetaParameter, v) || !m_pControlEnabled->toBool() || force) { m_pControlMetaParameter->set(v); @@ -275,112 +425,114 @@ void EffectSlot::slotEffectMetaParameter(double v, bool force) { if (!m_pControlEnabled->toBool()) { force = true; } - for (const auto& pParameterSlot : m_parameters) { - pParameterSlot->onEffectMetaParameterChanged(v, force); + for (const auto& pParameterSlot : m_parameterSlots) { + if (pParameterSlot->parameterType() == EffectManifestParameter::ParameterType::KNOB) { + pParameterSlot->onEffectMetaParameterChanged(v, force); + } } } QDomElement EffectSlot::toXml(QDomDocument* doc) const { QDomElement effectElement = doc->createElement(EffectXml::Effect); - if (!m_pEffect) { - return effectElement; - } - - QDomElement metaKnobElement = doc->createElement(EffectXml::EffectMetaParameter); - XmlParse::addElement(*doc, effectElement, - EffectXml::EffectMetaParameter, - QString::number(m_pControlMetaParameter->get())); - EffectManifestPointer pManifest = m_pEffect->getManifest(); - XmlParse::addElement(*doc, effectElement, - EffectXml::EffectId, pManifest->id()); - XmlParse::addElement(*doc, effectElement, - EffectXml::EffectVersion, pManifest->version()); - - QDomElement parametersElement = doc->createElement(EffectXml::ParametersRoot); - - for (const auto& pParameter : m_parameters) { - QDomElement parameterElement = pParameter->toXml(doc); - if (!parameterElement.hasChildNodes()) { - continue; - } - EffectManifestParameterPointer manifest = pParameter->getManifest(); - if (!manifest) { - continue; - } - XmlParse::addElement(*doc, parameterElement, - EffectXml::ParameterId, - manifest->id()); - parametersElement.appendChild(parameterElement); - } - for (const auto& pParameter : m_buttonParameters) { - QDomElement parameterElement = pParameter->toXml(doc); - if (!parameterElement.hasChildNodes()) { - continue; - } - EffectManifestParameterPointer manifest = pParameter->getManifest(); - if (!manifest) { - continue; - } - XmlParse::addElement(*doc, parameterElement, - EffectXml::ParameterId, - pParameter->getManifest()->id()); - parametersElement.appendChild(parameterElement); - } - - effectElement.appendChild(parametersElement); + // if (!m_pEffect) { + // return effectElement; + // } + + // QDomElement metaKnobElement = doc->createElement(EffectXml::EffectMetaParameter); + // XmlParse::addElement(*doc, effectElement, + // EffectXml::EffectMetaParameter, + // QString::number(m_pControlMetaParameter->get())); + // EffectManifestPointer pManifest = m_pEffect->getManifest(); + // XmlParse::addElement(*doc, effectElement, + // EffectXml::EffectId, pManifest->id()); + // XmlParse::addElement(*doc, effectElement, + // EffectXml::EffectVersion, pManifest->version()); + + // QDomElement parametersElement = doc->createElement(EffectXml::ParametersRoot); + + // for (const auto& pParameter : m_knobParameterSlots) { + // QDomElement parameterElement = pParameter->toXml(doc); + // if (!parameterElement.hasChildNodes()) { + // continue; + // } + // EffectManifestParameterPointer manifest = pParameter->getManifest(); + // if (!manifest) { + // continue; + // } + // XmlParse::addElement(*doc, parameterElement, + // EffectXml::ParameterId, + // manifest->id()); + // parametersElement.appendChild(parameterElement); + // } + // for (const auto& pParameter : m_buttonParameterSlots) { + // QDomElement parameterElement = pParameter->toXml(doc); + // if (!parameterElement.hasChildNodes()) { + // continue; + // } + // EffectManifestParameterPointer manifest = pParameter->getManifest(); + // if (!manifest) { + // continue; + // } + // XmlParse::addElement(*doc, parameterElement, + // EffectXml::ParameterId, + // pParameter->getManifest()->id()); + // parametersElement.appendChild(parameterElement); + // } + + // effectElement.appendChild(parametersElement); return effectElement; } void EffectSlot::loadEffectSlotFromXml(const QDomElement& effectElement) { - if (!m_pEffect) { - return; - } - - if (!effectElement.hasChildNodes()) { - return; - } - - QDomElement effectIdElement = XmlParse::selectElement(effectElement, - EffectXml::EffectId); - if (m_pEffect->getManifest()->id() != effectIdElement.text()) { - qWarning() << "EffectSlot::loadEffectSlotFromXml" - << "effect ID in XML does not match presently loaded effect, ignoring."; - return; - } - - m_pControlMetaParameter->set(XmlParse::selectNodeDouble( - effectElement, EffectXml::EffectMetaParameter)); - QDomElement parametersElement = XmlParse::selectElement( - effectElement, EffectXml::ParametersRoot); - if (!parametersElement.hasChildNodes()) { - return; - } - - QMap parametersById; - for (const auto& pParameter : m_parameters) { - EffectManifestParameterPointer manifest = pParameter->getManifest(); - if (manifest) { - parametersById.insert(manifest->id(), pParameter); - } - } - for (const auto& pParameter : m_buttonParameters) { - EffectManifestParameterPointer manifest = pParameter->getManifest(); - if (manifest) { - parametersById.insert(manifest->id(), pParameter); - } - } - - QDomNodeList parametersNodeList = parametersElement.childNodes(); - for (int i = 0; i < parametersNodeList.size(); ++i) { - QDomNode parameterNode = parametersNodeList.at(i); - if (parameterNode.isElement()) { - const QString id = XmlParse::selectNodeQString(parameterNode, - EffectXml::ParameterId); - EffectParameterSlotBasePointer pParameterSlot = parametersById.value(id); - if (pParameterSlot != nullptr) { - pParameterSlot->loadParameterSlotFromXml(parameterNode.toElement()); - } - } - } + // if (!m_pEffect) { + // return; + // } + + // if (!effectElement.hasChildNodes()) { + // return; + // } + + // QDomElement effectIdElement = XmlParse::selectElement(effectElement, + // EffectXml::EffectId); + // if (m_pEffect->getManifest()->id() != effectIdElement.text()) { + // qWarning() << "EffectSlot::loadEffectSlotFromXml" + // << "effect ID in XML does not match presently loaded effect, ignoring."; + // return; + // } + + // m_pControlMetaParameter->set(XmlParse::selectNodeDouble( + // effectElement, EffectXml::EffectMetaParameter)); + // QDomElement parametersElement = XmlParse::selectElement( + // effectElement, EffectXml::ParametersRoot); + // if (!parametersElement.hasChildNodes()) { + // return; + // } + + // QMap parametersById; + // for (const auto& pParameter : m_knobParameterSlots) { + // EffectManifestParameterPointer manifest = pParameter->getManifest(); + // if (manifest) { + // parametersById.insert(manifest->id(), pParameter); + // } + // } + // for (const auto& pParameter : m_buttonParameterSlots) { + // EffectManifestParameterPointer manifest = pParameter->getManifest(); + // if (manifest) { + // parametersById.insert(manifest->id(), pParameter); + // } + // } + + // QDomNodeList parametersNodeList = parametersElement.childNodes(); + // for (int i = 0; i < parametersNodeList.size(); ++i) { + // QDomNode parameterNode = parametersNodeList.at(i); + // if (parameterNode.isElement()) { + // const QString id = XmlParse::selectNodeQString(parameterNode, + // EffectXml::ParameterId); + // EffectParameterSlotBasePointer pParameterSlot = parametersById.value(id); + // if (pParameterSlot != nullptr) { + // pParameterSlot->loadParameterSlotFromXml(parameterNode.toElement()); + // } + // } + // } } diff --git a/src/effects/effectslot.h b/src/effects/effectslot.h index 1afc2a7f7a0..a14a7cdc3ee 100644 --- a/src/effects/effectslot.h +++ b/src/effects/effectslot.h @@ -10,59 +10,57 @@ #include "control/controlpotmeter.h" #include "control/controlpushbutton.h" #include "controllers/softtakeover.h" -#include "effects/effect.h" -#include "effects/effectparameterslot.h" +#include "engine/channelhandle.h" +#include "engine/engine.h" +#include "engine/effects/engineeffect.h" #include "effects/effectbuttonparameterslot.h" +#include "effects/effectmanifest.h" +#include "effects/effectparameter.h" +#include "effects/effectknobparameterslot.h" #include "util/class.h" +class EffectProcessor; class EffectSlot; +class EffectState; +class EffectsManager; +class EngineEffect; +class EngineEffectChain; class ControlProxy; - +class EffectParameter; +class EffectKnobParameterSlot; class EffectSlot : public QObject { Q_OBJECT public: EffectSlot(const QString& group, - const unsigned int iChainNumber, - const unsigned int iEffectNumber); + EffectsManager* pEffectsManager, + const unsigned int iEffectNumber, + EngineEffectChain* pEngineEffectChain); virtual ~EffectSlot(); - // Return the currently loaded effect, if any. If no effect is loaded, - // returns a null EffectPointer. - EffectPointer getEffect() const; - - inline bool getEnableState() const { - return m_pControlEnabled->toBool(); - } + // Call with nullptr for pManifest and pProcessor to unload an effect + void loadEffect(const EffectManifestPointer pManifest, + std::unique_ptr pProcessor, + const QSet& activeChannels); inline int getEffectSlotNumber() const { return m_iEffectNumber; } - unsigned int numParameterSlots() const; - EffectParameterSlotPointer addEffectParameterSlot(); - EffectParameterSlotPointer getEffectParameterSlot(unsigned int slotNumber); - EffectParameterSlotPointer getEffectParameterSlotForConfigKey(unsigned int slotNumber); - inline const QList& getEffectParameterSlots() const { - return m_parameters; - }; - - unsigned int numButtonParameterSlots() const; - EffectButtonParameterSlotPointer addEffectButtonParameterSlot(); - EffectButtonParameterSlotPointer getEffectButtonParameterSlot(unsigned int slotNumber); - inline const QList& getEffectButtonParameterSlots() const { - return m_buttonParameters; - }; + inline bool isLoaded() const { + return m_pEngineEffect != nullptr; + } + + void addEffectParameterSlot(EffectManifestParameter::ParameterType parameterType); + EffectParameterSlotBasePointer getEffectParameterSlot( + EffectManifestParameter::ParameterType parameterType, unsigned int slotNumber); double getMetaParameter() const; - // ensures that Softtakover is bypassed for the following + // Ensures that Softtakover is bypassed for the following // ChainParameterChange. Uses for testing only void syncSofttakeover(); - // Unload the currently loaded effect - void clear(); - const QString& getGroup() const { return m_group; } @@ -70,68 +68,70 @@ class EffectSlot : public QObject { QDomElement toXml(QDomDocument* doc) const; void loadEffectSlotFromXml(const QDomElement& effectElement); + EffectState* createState(const mixxx::EngineParameters& bufferParameters); + + EffectManifestPointer getManifest() const; + + unsigned int numParameters(EffectManifestParameter::ParameterType parameterType) const; + + void setEnabled(bool enabled); + + // static EffectPointer createFromXml(EffectsManager* pEffectsManager, + // const QDomElement& element); + void addToEngine(std::unique_ptr, + const QSet& activeInputChannels); + void removeFromEngine(); + + void hideEffectParameter(const unsigned int parameterId); + void setEffectParameterPosition(const unsigned int parameterId, + const unsigned int position); + public slots: - // Request that this EffectSlot load the given Effect - void loadEffect(EffectPointer pEffect, bool adoptMetaknobPosition); void setMetaParameter(double v, bool force = false); - void slotEnabled(double v); void slotNextEffect(double v); void slotPrevEffect(double v); void slotClear(double v); void slotEffectSelector(double v); - void slotEffectEnabledChanged(bool enabled); void slotEffectMetaParameter(double v, bool force = false); signals: - // Indicates that the effect pEffect has been loaded into this - // EffectSlot. The effectSlotNumber is provided for the convenience of - // listeners. pEffect may be an invalid pointer, which indicates that a - // previously loaded effect was removed from the slot. - void effectLoaded(EffectPointer pEffect, unsigned int effectSlotNumber); + void effectChanged(); - // Signal that whoever is in charge of this EffectSlot should load the next - // Effect into it. - void nextEffect(unsigned int iChainNumber, unsigned int iEffectNumber, - EffectPointer pEffect); - - // Signal that whoever is in charge of this EffectSlot should load the - // previous Effect into it. - void prevEffect(unsigned int iChainNumber, unsigned int iEffectNumber, - EffectPointer pEffect); - - // Signal that whoever is in charge of this EffectSlot should clear this - // EffectSlot (by deleting the effect from the underlying chain). - void clearEffect(unsigned int iEffectNumber); - - void updated(); + private slots: + void updateEngineState(); private: QString debugString() const { return QString("EffectSlot(%1)").arg(m_group); } - const unsigned int m_iChainNumber; + void loadParameters(); + void unloadEffect(); + const unsigned int m_iEffectNumber; + QHash m_iNumParameterSlots; const QString m_group; UserSettingsPointer m_pConfig; - EffectPointer m_pEffect; + EffectsManager* m_pEffectsManager; + EffectManifestPointer m_pManifest; + EngineEffectChain* m_pEngineEffectChain; + EngineEffect* m_pEngineEffect; + QList m_parameters; + QList m_parameterSlots; + QHash> m_mapForParameterType; ControlObject* m_pControlLoaded; + QHash m_pControlNumParameters; + QHash m_pControlNumParameterSlots; ControlPushButton* m_pControlEnabled; - ControlObject* m_pControlNumParameters; - ControlObject* m_pControlNumParameterSlots; - ControlObject* m_pControlNumButtonParameters; - ControlObject* m_pControlNumButtonParameterSlots; ControlObject* m_pControlNextEffect; ControlObject* m_pControlPrevEffect; ControlEncoder* m_pControlEffectSelector; ControlObject* m_pControlClear; ControlPotmeter* m_pControlMetaParameter; - QList m_parameters; - QList m_buttonParameters; - SoftTakeover* m_pSoftTakeover; + SoftTakeover* m_pMetaknobSoftTakeover; DISALLOW_COPY_AND_ASSIGN(EffectSlot); }; diff --git a/src/effects/effectsmanager.cpp b/src/effects/effectsmanager.cpp index 9f2f2af3f4d..62b7f726358 100644 --- a/src/effects/effectsmanager.cpp +++ b/src/effects/effectsmanager.cpp @@ -1,20 +1,25 @@ #include "effects/effectsmanager.h" +#include #include #include #include #include "engine/effects/engineeffectsmanager.h" -#include "effects/effectchainmanager.h" +#include "effects/effectchainpreset.h" #include "effects/effectsbackend.h" #include "effects/effectslot.h" +#include "effects/effectxmlelements.h" #include "engine/effects/engineeffect.h" -#include "engine/effects/engineeffectrack.h" #include "engine/effects/engineeffectchain.h" #include "util/assert.h" namespace { +const QString kStandardEffectRackGroup = "[EffectRack1]"; +const QString kOutputEffectRackGroup = "[OutputEffectRack]"; +const QString kQuickEffectRackGroup = "[QuickEffectRack1]"; +const QString kEqualizerEffectRackGroup = "[EqualizerRack1]"; const QString kEffectGroupSeparator = "_"; const QString kGroupClose = "]"; const unsigned int kEffectMessagPipeFifoSize = 2048; @@ -25,10 +30,10 @@ EffectsManager::EffectsManager(QObject* pParent, UserSettingsPointer pConfig, ChannelHandleFactory* pChannelHandleFactory) : QObject(pParent), m_pChannelHandleFactory(pChannelHandleFactory), - m_pEffectChainManager(new EffectChainManager(pConfig, this)), + m_pConfig(pConfig), m_nextRequestId(0), - m_pLoEqFreq(NULL), - m_pHiEqFreq(NULL), + m_loEqFreq(ConfigKey("[Mixer Profile]", "LoEQFrequency"), 0., 22040), + m_hiEqFreq(ConfigKey("[Mixer Profile]", "HiEQFrequency"), 0., 22040), m_underDestruction(false) { qRegisterMetaType("EffectChainMixMode"); QPair requestPipes = @@ -44,23 +49,30 @@ EffectsManager::EffectsManager(QObject* pParent, UserSettingsPointer pConfig, EffectsManager::~EffectsManager() { m_underDestruction = true; - m_pEffectChainManager->saveEffectChains(); - delete m_pEffectChainManager; - // This must be done here, since the engineRacks are deleted via - // the queue + + // NOTE(Kshitij) : Use new functions for saving XML files + // saveEffectChains(); + + // The EffectChainSlots must be deleted before the EffectsBackends in case + // there is an LV2 effect currently loaded. + // ~LV2GroupState calls lilv_instance_free, which will segfault if called + // after ~LV2Backend calls lilv_world_free. + m_equalizerEffectChainSlots.clear(); + m_quickEffectChainSlots.clear(); + m_standardEffectChainSlots.clear(); + m_outputEffectChainSlot.clear(); + m_effectChainSlotsByGroup.clear(); processEffectsResponses(); - while (!m_effectsBackends.isEmpty()) { - EffectsBackend* pBackend = m_effectsBackends.takeLast(); - delete pBackend; - } + + m_effectsBackends.clear(); for (QHash::iterator it = m_activeRequests.begin(); it != m_activeRequests.end();) { delete it.value(); it = m_activeRequests.erase(it); } - delete m_pHiEqFreq; - delete m_pLoEqFreq; + // delete m_pHiEqFreq; + // delete m_pLoEqFreq; delete m_pNumEffectsAvailable; // Safe because the Engine is deleted before EffectsManager. Also, it holds // a bare pointer to m_pRequestPipe so it is critical that it does not @@ -76,11 +88,11 @@ bool alphabetizeEffectManifests(EffectManifestPointer pManifest1, return (backendNameComparision ? (backendNameComparision < 0) : (displayNameComparision < 0)); } -void EffectsManager::addEffectsBackend(EffectsBackend* pBackend) { +void EffectsManager::addEffectsBackend(EffectsBackendPointer pBackend) { VERIFY_OR_DEBUG_ASSERT(pBackend) { return; } - m_effectsBackends.append(pBackend); + m_effectsBackends.insert(pBackend->getType(), pBackend); QList backendEffects = pBackend->getEffectIds(); for (const QString& effectId : backendEffects) { @@ -91,36 +103,83 @@ void EffectsManager::addEffectsBackend(EffectsBackend* pBackend) { qSort(m_availableEffectManifests.begin(), m_availableEffectManifests.end(), alphabetizeEffectManifests); +} - connect(pBackend, SIGNAL(effectRegistered(EffectManifestPointer)), - this, SLOT(slotBackendRegisteredEffect(EffectManifestPointer))); +bool EffectsManager::isAdoptMetaknobValueEnabled() const { + return m_pConfig->getValue(ConfigKey("[Effects]", "AdoptMetaknobValue"), true); +} - connect(pBackend, SIGNAL(effectRegistered(EffectManifestPointer)), - this, SIGNAL(availableEffectsUpdated(EffectManifestPointer))); +void EffectsManager::registerInputChannel(const ChannelHandleAndGroup& handle_group) { + VERIFY_OR_DEBUG_ASSERT(!m_registeredInputChannels.contains(handle_group)) { + return; + } + m_registeredInputChannels.insert(handle_group); + + foreach (EffectChainSlotPointer pChainSlot, m_standardEffectChainSlots) { + pChainSlot->registerInputChannel(handle_group); + } } -void EffectsManager::slotBackendRegisteredEffect(EffectManifestPointer pManifest) { - auto insertion_point = std::lower_bound(m_availableEffectManifests.begin(), - m_availableEffectManifests.end(), - pManifest, alphabetizeEffectManifests); - m_availableEffectManifests.insert(insertion_point, pManifest); - m_pNumEffectsAvailable->forceSet(m_availableEffectManifests.size()); +void EffectsManager::registerOutputChannel(const ChannelHandleAndGroup& handle_group) { + VERIFY_OR_DEBUG_ASSERT(!m_registeredOutputChannels.contains(handle_group)) { + return; + } + m_registeredOutputChannels.insert(handle_group); } -void EffectsManager::registerInputChannel(const ChannelHandleAndGroup& handle_group) { - m_pEffectChainManager->registerInputChannel(handle_group); +void EffectsManager::loadStandardEffect(const int iChainSlotNumber, + const int iEffectSlotNumber, const EffectManifestPointer pManifest) { + auto pChainSlot = getStandardEffectChainSlot(iChainSlotNumber); + if (pChainSlot) { + loadEffect(pChainSlot, iEffectSlotNumber, pManifest); + } } -const QSet& EffectsManager::registeredInputChannels() const { - return m_pEffectChainManager->registeredInputChannels(); +void EffectsManager::loadOutputEffect(const int iEffectSlotNumber, + const EffectManifestPointer pManifest) { + if (m_outputEffectChainSlot) { + loadEffect(m_outputEffectChainSlot, iEffectSlotNumber, pManifest); + } } -void EffectsManager::registerOutputChannel(const ChannelHandleAndGroup& handle_group) { - m_pEffectChainManager->registerOutputChannel(handle_group); +void EffectsManager::loadQuickEffect(const QString& deckGroup, + const int iEffectSlotNumber, const EffectManifestPointer pManifest) { + auto pChainSlot = m_quickEffectChainSlots.value(deckGroup); + VERIFY_OR_DEBUG_ASSERT(pChainSlot) { + return; + } + loadEffect(pChainSlot, iEffectSlotNumber, pManifest); +} + +void EffectsManager::loadEqualizerEffect(const QString& deckGroup, + const int iEffectSlotNumber, const EffectManifestPointer pManifest) { + auto pChainSlot = m_equalizerEffectChainSlots.value(deckGroup); + VERIFY_OR_DEBUG_ASSERT(pChainSlot) { + return; + } + loadEffect(pChainSlot, iEffectSlotNumber, pManifest); } -const QSet& EffectsManager::registeredOutputChannels() const { - return m_pEffectChainManager->registeredOutputChannels(); +void EffectsManager::loadEffect(EffectChainSlotPointer pChainSlot, + const int iEffectSlotNumber, const EffectManifestPointer pManifest) { + if (kEffectDebugOutput) { + qDebug() << debugString() << "loading effect" << iEffectSlotNumber << pManifest; + } + pChainSlot->loadEffect(iEffectSlotNumber, pManifest, + createProcessor(pManifest)); +} + +std::unique_ptr EffectsManager::createProcessor( + const EffectManifestPointer pManifest) { + if (!pManifest) { + // This can be a valid request to unload an effect, so do not DEBUG_ASSERT. + return std::unique_ptr(nullptr); + } + EffectsBackendPointer pBackend = m_effectsBackends.value(pManifest->backendType()); + VERIFY_OR_DEBUG_ASSERT(pBackend) { + return std::unique_ptr(nullptr); + } + return pBackend->createProcessor(pManifest); } const QList EffectsManager::getAvailableEffectManifestsFiltered( @@ -138,11 +197,6 @@ const QList EffectsManager::getAvailableEffectManifestsFi return list; } -bool EffectsManager::isEQ(const QString& effectId) const { - EffectManifestPointer pManifest = getEffectManifest(effectId); - return pManifest ? pManifest->isMixingEQ() : false; -} - QString EffectsManager::getNextEffectId(const QString& effectId) { if (m_availableEffectManifests.isEmpty()) { return QString(); @@ -186,67 +240,99 @@ QString EffectsManager::getPrevEffectId(const QString& effectId) { void EffectsManager::getEffectManifestAndBackend( const QString& effectId, EffectManifestPointer* ppManifest, EffectsBackend** ppBackend) const { - foreach (EffectsBackend* pBackend, m_effectsBackends) { + for (const auto& pBackend : m_effectsBackends) { if (pBackend->canInstantiateEffect(effectId)) { *ppManifest = pBackend->getManifest(effectId); - *ppBackend = pBackend; + *ppBackend = pBackend.data(); } } } -EffectManifestPointer EffectsManager::getEffectManifest(const QString& effectId) const { - EffectManifestPointer pMainifest; - EffectsBackend* pEffectBackend; - getEffectManifestAndBackend(effectId, &pMainifest, &pEffectBackend); - return pMainifest; +EffectManifestPointer EffectsManager::getManifestFromUniqueId(const QString& uid) const { + if (kEffectDebugOutput) { + qDebug() << "EffectsManager::getManifestFromUniqueId" << uid; + } + if (uid.isEmpty()) { + // Do not DEBUG_ASSERT, this may be a valid request for a nullptr to + // unload an effect. + return EffectManifestPointer(); + } + int delimiterIndex = uid.lastIndexOf(" "); + EffectBackendType backendType = EffectManifest::backendTypeFromString( + uid.mid(delimiterIndex+1)); + VERIFY_OR_DEBUG_ASSERT(backendType != EffectBackendType::Unknown) { + // Mixxx 2.0 - 2.2 did not store the backend type in mixxx.cfg, + // so this code will be executed once when upgrading to Mixxx 2.3. + // This debug assertion is safe to ignore in that case. If it is + // triggered at any later time, there is a bug somewhere. + // Do not manipulate the string passed to this function, just pass + // it directly to BuiltInBackend. + return m_effectsBackends.value(EffectBackendType::BuiltIn)->getManifest(uid); + } + return m_effectsBackends.value(backendType)->getManifest( + uid.mid(-1, delimiterIndex+1)); } -EffectPointer EffectsManager::instantiateEffect(const QString& effectId) { - if (effectId.isEmpty()) { - return EffectPointer(); - } - for (const auto& pBackend: m_effectsBackends) { - if (pBackend->canInstantiateEffect(effectId)) { - return pBackend->instantiateEffect(this, effectId); +void EffectsManager::addStandardEffectChainSlots() { + for (int i = 0; i < EffectsManager::kNumStandardEffectChains; ++i) { + VERIFY_OR_DEBUG_ASSERT(!m_effectChainSlotsByGroup.contains( + StandardEffectChainSlot::formatEffectChainSlotGroup(i))) { + continue; } + + auto pChainSlot = StandardEffectChainSlotPointer( + new StandardEffectChainSlot(i, this)); + + m_standardEffectChainSlots.append(pChainSlot); + m_effectChainSlotsByGroup.insert(pChainSlot->group(), pChainSlot); } - return EffectPointer(); } -StandardEffectRackPointer EffectsManager::addStandardEffectRack() { - return m_pEffectChainManager->addStandardEffectRack(); +void EffectsManager::addOutputEffectChainSlot() { + m_outputEffectChainSlot = OutputEffectChainSlotPointer(new OutputEffectChainSlot(this)); + m_effectChainSlotsByGroup.insert(m_outputEffectChainSlot->group(), m_outputEffectChainSlot); } -StandardEffectRackPointer EffectsManager::getStandardEffectRack(int rack) { - return m_pEffectChainManager->getStandardEffectRack(rack); +EffectChainSlotPointer EffectsManager::getOutputEffectChainSlot() const { + return m_outputEffectChainSlot; } -EqualizerRackPointer EffectsManager::addEqualizerRack() { - return m_pEffectChainManager->addEqualizerRack(); +EffectChainSlotPointer EffectsManager::getStandardEffectChainSlot(int unitNumber) const { + VERIFY_OR_DEBUG_ASSERT(0 <= unitNumber || unitNumber < m_standardEffectChainSlots.size()) { + return EffectChainSlotPointer(); + } + return m_standardEffectChainSlots.at(unitNumber); } -EqualizerRackPointer EffectsManager::getEqualizerRack(int rack) { - return m_pEffectChainManager->getEqualizerRack(rack); -} +void EffectsManager::addEqualizerEffectChainSlot(const QString& deckGroupName) { + VERIFY_OR_DEBUG_ASSERT(!m_equalizerEffectChainSlots.contains( + EqualizerEffectChainSlot::formatEffectChainSlotGroup(deckGroupName))) { + return; + } -QuickEffectRackPointer EffectsManager::addQuickEffectRack() { - return m_pEffectChainManager->addQuickEffectRack(); -} + auto pChainSlot = EqualizerEffectChainSlotPointer( + new EqualizerEffectChainSlot(deckGroupName, this)); + m_equalizerEffectChainSlots.insert(deckGroupName, pChainSlot); -QuickEffectRackPointer EffectsManager::getQuickEffectRack(int rack) { - return m_pEffectChainManager->getQuickEffectRack(rack); + m_effectChainSlotsByGroup.insert(pChainSlot->group(), pChainSlot); } -OutputEffectRackPointer EffectsManager::addOutputsEffectRack() { - return m_pEffectChainManager->addOutputsEffectRack(); -} +void EffectsManager::addQuickEffectChainSlot(const QString& deckGroupName) { + VERIFY_OR_DEBUG_ASSERT(!m_quickEffectChainSlots.contains( + QuickEffectChainSlot::formatEffectChainSlotGroup(deckGroupName))) { + return; + } + + auto pChainSlot = QuickEffectChainSlotPointer( + new QuickEffectChainSlot(deckGroupName, this)); -OutputEffectRackPointer EffectsManager::getOutputsEffectRack() { - return m_pEffectChainManager->getMasterEffectRack(); + m_quickEffectChainSlots.insert(deckGroupName, pChainSlot); + m_effectChainSlotsByGroup.insert(pChainSlot->group(), pChainSlot); } -EffectRackPointer EffectsManager::getEffectRack(const QString& group) { - return m_pEffectChainManager->getEffectRack(group); +EffectChainSlotPointer EffectsManager::getEffectChainSlot( + const QString& group) const { + return m_effectChainSlotsByGroup.value(group); } EffectSlotPointer EffectsManager::getEffectSlot( @@ -255,27 +341,9 @@ EffectSlotPointer EffectsManager::getEffectSlot( QStringList parts = group.split(kEffectGroupSeparator); - EffectRackPointer pRack = getEffectRack(parts.at(0) + kGroupClose); - VERIFY_OR_DEBUG_ASSERT(pRack) { - return EffectSlotPointer(); - } - - EffectChainSlotPointer pChainSlot; - if (parts.at(0) == "[EffectRack1") { - intRegEx.indexIn(parts.at(1)); - pChainSlot = pRack->getEffectChainSlot(intRegEx.cap(1).toInt() - 1); - } else { - // Assume a PerGroupRack - const QString chainGroup = - parts.at(0) + kEffectGroupSeparator + parts.at(1) + kGroupClose; - for (int i = 0; i < pRack->numEffectChainSlots(); ++i) { - EffectChainSlotPointer pSlot = pRack->getEffectChainSlot(i); - if (pSlot->getGroup() == chainGroup) { - pChainSlot = pSlot; - break; - } - } - } + // NOTE(Kshitij) : Assuming the group is valid + const QString chainGroup = parts.at(0) + kEffectGroupSeparator + parts.at(1) + kGroupClose; + EffectChainSlotPointer pChainSlot = getEffectChainSlot(chainGroup); VERIFY_OR_DEBUG_ASSERT(pChainSlot) { return EffectSlotPointer(); } @@ -286,33 +354,18 @@ EffectSlotPointer EffectsManager::getEffectSlot( return pEffectSlot; } -EffectParameterSlotPointer EffectsManager::getEffectParameterSlot( - const ConfigKey& configKey) { +EffectParameterSlotBasePointer EffectsManager::getEffectParameterSlot( + const EffectManifestParameter::ParameterType parameterType, const ConfigKey& configKey) { EffectSlotPointer pEffectSlot = getEffectSlot(configKey.group); VERIFY_OR_DEBUG_ASSERT(pEffectSlot) { - return EffectParameterSlotPointer(); + return EffectParameterSlotBasePointer(); } QRegExp intRegEx(".*(\\d+).*"); intRegEx.indexIn(configKey.item); - EffectParameterSlotPointer pParameterSlot = - pEffectSlot->getEffectParameterSlot(intRegEx.cap(1).toInt() - 1); - return pParameterSlot; -} - -EffectButtonParameterSlotPointer EffectsManager::getEffectButtonParameterSlot( - const ConfigKey& configKey) { - EffectSlotPointer pEffectSlot = - getEffectSlot(configKey.group); - VERIFY_OR_DEBUG_ASSERT(pEffectSlot) { - return EffectButtonParameterSlotPointer(); - } - - QRegExp intRegEx(".*(\\d+).*"); - intRegEx.indexIn(configKey.item); - EffectButtonParameterSlotPointer pParameterSlot = - pEffectSlot->getEffectButtonParameterSlot(intRegEx.cap(1).toInt() - 1); + EffectParameterSlotBasePointer pParameterSlot = pEffectSlot->getEffectParameterSlot( + parameterType, intRegEx.cap(1).toInt() - 1); return pParameterSlot; } @@ -334,80 +387,36 @@ bool EffectsManager::getEffectVisibility(EffectManifestPointer pManifest) { } void EffectsManager::setup() { - // These controls are used inside EQ Effects - m_pLoEqFreq = new ControlPotmeter(ConfigKey("[Mixer Profile]", "LoEQFrequency"), 0., 22040); - m_pHiEqFreq = new ControlPotmeter(ConfigKey("[Mixer Profile]", "HiEQFrequency"), 0., 22040); - - // NOTE(Be): Effect racks are processed in the order they are added here. - - // Add prefader effect racks - addEqualizerRack(); - addQuickEffectRack(); - - // Add postfader effect racks - addStandardEffectRack(); - addOutputsEffectRack(); - - EffectChainPointer pChain(new EffectChain( - this, "org.mixxx.effectchain.flanger")); - pChain->setName(tr("Flanger")); - EffectPointer pEffect = instantiateEffect( - "org.mixxx.effects.flanger"); - pChain->addEffect(pEffect); - m_pEffectChainManager->addEffectChain(pChain); - - pChain = EffectChainPointer(new EffectChain( - this, "org.mixxx.effectchain.bitcrusher")); - pChain->setName(tr("BitCrusher")); - pEffect = instantiateEffect("org.mixxx.effects.bitcrusher"); - pChain->addEffect(pEffect); - m_pEffectChainManager->addEffectChain(pChain); - - pChain = EffectChainPointer(new EffectChain( - this, "org.mixxx.effectchain.filter")); - pChain->setName(tr("Filter")); - pEffect = instantiateEffect("org.mixxx.effects.filter"); - pChain->addEffect(pEffect); - m_pEffectChainManager->addEffectChain(pChain); - -#ifndef __MACAPPSTORE__ - pChain = EffectChainPointer(new EffectChain( - this, "org.mixxx.effectchain.reverb")); - pChain->setName(tr("Reverb")); - pEffect = instantiateEffect("org.mixxx.effects.reverb"); - pChain->addEffect(pEffect); - m_pEffectChainManager->addEffectChain(pChain); -#endif - - pChain = EffectChainPointer(new EffectChain( - this, "org.mixxx.effectchain.echo")); - pChain->setName(tr("Echo")); - pEffect = instantiateEffect("org.mixxx.effects.echo"); - pChain->addEffect(pEffect); - m_pEffectChainManager->addEffectChain(pChain); - - pChain = EffectChainPointer(new EffectChain( - this, "org.mixxx.effectchain.autopan")); - pChain->setName(tr("AutoPan")); - pEffect = instantiateEffect("org.mixxx.effects.autopan"); - pChain->addEffect(pEffect); - m_pEffectChainManager->addEffectChain(pChain); - - pChain = EffectChainPointer(new EffectChain( - this, "org.mixxx.effectchain.tremolo")); - pChain->setName(tr("Tremolo")); - pEffect = instantiateEffect("org.mixxx.effects.tremolo"); - pChain->addEffect(pEffect); - m_pEffectChainManager->addEffectChain(pChain); -} - -void EffectsManager::loadEffectChains() { - // populate rack and restore state from effects.xml - m_pEffectChainManager->loadEffectChains(); -} - -void EffectsManager::refeshAllRacks() { - m_pEffectChainManager->refeshAllRacks(); + loadEffectChainPresets(); + // Add postfader effect chain slots + addStandardEffectChainSlots(); + addOutputEffectChainSlot(); +} + +void EffectsManager::setEffectParameterPosition(EffectManifestPointer pManifest, + const unsigned int parameterId, const unsigned int position) { + for (auto& pChainSlot : m_standardEffectChainSlots) { + pChainSlot->setEffectParameterPosition(pManifest, parameterId, position); + } + for (auto& pChainSlot : m_equalizerEffectChainSlots) { + pChainSlot->setEffectParameterPosition(pManifest, parameterId, position); + } + for (auto& pChainSlot : m_quickEffectChainSlots) { + pChainSlot->setEffectParameterPosition(pManifest, parameterId, position); + } +} + +void EffectsManager::hideEffectParameter(EffectManifestPointer pManifest, + const unsigned int position) { + for (auto& pChainSlot : m_standardEffectChainSlots) { + pChainSlot->hideEffectParameter(pManifest, position); + } + for (auto& pChainSlot : m_equalizerEffectChainSlots) { + pChainSlot->hideEffectParameter(pManifest, position); + } + for (auto& pChainSlot : m_quickEffectChainSlots) { + pChainSlot->hideEffectParameter(pManifest, position); + } } bool EffectsManager::writeRequest(EffectsRequest* request) { @@ -474,16 +483,11 @@ void EffectsManager::collectGarbage(const EffectsRequest* pRequest) { qDebug() << debugString() << "delete" << pRequest->RemoveEffectFromChain.pEffect; } delete pRequest->RemoveEffectFromChain.pEffect; - } else if (pRequest->type == EffectsRequest::REMOVE_CHAIN_FROM_RACK) { - if (kEffectDebugOutput) { - qDebug() << debugString() << "delete" << pRequest->RemoveEffectFromChain.pEffect; - } - delete pRequest->RemoveChainFromRack.pChain; - } else if (pRequest->type == EffectsRequest::REMOVE_EFFECT_RACK) { + } else if (pRequest->type == EffectsRequest::REMOVE_EFFECT_CHAIN) { if (kEffectDebugOutput) { - qDebug() << debugString() << "delete" << pRequest->RemoveEffectRack.pRack; + qDebug() << debugString() << "delete" << pRequest->RemoveEffectChain.pChain; } - delete pRequest->RemoveEffectRack.pRack; + delete pRequest->RemoveEffectChain.pChain; } else if (pRequest->type == EffectsRequest::DISABLE_EFFECT_CHAIN_FOR_INPUT_CHANNEL) { if (kEffectDebugOutput) { qDebug() << debugString() << "deleting states for input channel" << pRequest->DisableInputChannelForChain.pChannelHandle << "for EngineEffectChain" << pRequest->pTargetChain; @@ -492,3 +496,32 @@ void EffectsManager::collectGarbage(const EffectsRequest* pRequest) { pRequest->DisableInputChannelForChain.pChannelHandle); } } + +void EffectsManager::loadEffectChainPresets() { + QDir settingsPath(m_pConfig->getSettingsPath()); + QFile file(settingsPath.absoluteFilePath("effects.xml")); + QDomDocument doc; + + if (!file.open(QIODevice::ReadOnly)) { + return; + } else if (!doc.setContent(&file)) { + file.close(); + return; + } + file.close(); + + QDomElement root = doc.documentElement(); + QDomElement rackElement = XmlParse::selectElement(root, EffectXml::Rack); + QDomElement chainsElement = XmlParse::selectElement(rackElement, EffectXml::ChainsRoot); + QDomNodeList chainsList = chainsElement.elementsByTagName(EffectXml::Chain); + + for (int i=0; iname(), pPreset); + } + } +} \ No newline at end of file diff --git a/src/effects/effectsmanager.h b/src/effects/effectsmanager.h index 24f4cd9024c..06d7c926099 100644 --- a/src/effects/effectsmanager.h +++ b/src/effects/effectsmanager.h @@ -8,18 +8,20 @@ #include #include -#include "preferences/usersettings.h" #include "control/controlpotmeter.h" #include "control/controlpushbutton.h" +#include "effects/specialeffectchainslots.h" +#include "effects/effectmanifestparameter.h" #include "engine/channelhandle.h" #include "engine/effects/message.h" +#include "preferences/usersettings.h" #include "util/class.h" #include "util/fifo.h" +#include "util/memory.h" +#include "util/xml.h" class EngineEffectsManager; -class EffectChainManager; class EffectManifest; -class EffectsBackend; class EffectsManager : public QObject { Q_OBJECT @@ -34,10 +36,6 @@ class EffectsManager : public QObject { return m_pEngineEffectsManager; } - EffectChainManager* getEffectChainManager() { - return m_pEffectChainManager; - } - const ChannelHandle getMasterHandle() { return m_pChannelHandleFactory->getOrCreateHandle("[Master]"); } @@ -45,33 +43,75 @@ class EffectsManager : public QObject { // Add an effect backend to be managed by EffectsManager. EffectsManager // takes ownership of the backend, and will delete it when EffectsManager is // being deleted. Not thread safe -- use only from the GUI thread. - void addEffectsBackend(EffectsBackend* pEffectsBackend); + void addEffectsBackend(EffectsBackendPointer pEffectsBackend); + + // To support cycling through effect chains, there is a global ordering of + // chains. These methods allow you to get the next or previous chain given + // your current chain. + // EffectChainSlotPointer getNextEffectChain(EffectChainSlotPointer pEffectChainSlot); + // EffectChainSlotPointer getPrevEffectChain(EffectChainSlotPointer pEffectChainSlot); + + // NOTE(Kshitij) : New functions for saving and loading + // bool saveEffectChains(); + + static const int kNumStandardEffectChains = 4; + + bool isAdoptMetaknobValueEnabled() const; + void registerInputChannel(const ChannelHandleAndGroup& handle_group); + const QSet& registeredInputChannels() const { + return m_registeredInputChannels; + } + void registerOutputChannel(const ChannelHandleAndGroup& handle_group); - const QSet& registeredInputChannels() const; - const QSet& registeredOutputChannels() const; + const QSet& registeredOutputChannels() const { + return m_registeredOutputChannels; + } + + void loadStandardEffect( + const int iChainSlotNumber, + const int iEffectSlotNumber, + const EffectManifestPointer pManifest); + + void loadOutputEffect( + const int iEffectSlotNumber, + const EffectManifestPointer pManifest); + + void loadQuickEffect( + const QString& group, + const int iEffectSlotNumber, + const EffectManifestPointer pManifest); + + void loadEqualizerEffect(const QString& group, + const int iEffectSlotNumber, + const EffectManifestPointer pManifest); + + void loadEffect( + EffectChainSlotPointer pChainSlot, + const int iEffectSlotNumber, + const EffectManifestPointer pManifest); - StandardEffectRackPointer addStandardEffectRack(); - StandardEffectRackPointer getStandardEffectRack(int rack); + std::unique_ptr createProcessor( + const EffectManifestPointer pManifest); - EqualizerRackPointer addEqualizerRack(); - EqualizerRackPointer getEqualizerRack(int rack); + void addStandardEffectChainSlots(); + EffectChainSlotPointer getStandardEffectChainSlot(int unitNumber) const; - QuickEffectRackPointer addQuickEffectRack(); - QuickEffectRackPointer getQuickEffectRack(int rack); + void addOutputEffectChainSlot(); + EffectChainSlotPointer getOutputEffectChainSlot() const; - OutputEffectRackPointer addOutputsEffectRack(); - OutputEffectRackPointer getOutputsEffectRack(); + void addEqualizerEffectChainSlot(const QString& deckGroupName); + void addQuickEffectChainSlot(const QString& deckGroupName); - void loadEffectChains(); + void loadEffectChainPresets(); - EffectRackPointer getEffectRack(const QString& group); + // TODO: Remove these methods to reduce coupling between GUI and + // effects system implementation details. + EffectChainSlotPointer getEffectChainSlot(const QString& group) const; EffectSlotPointer getEffectSlot(const QString& group); - EffectParameterSlotPointer getEffectParameterSlot( - const ConfigKey& configKey); - EffectButtonParameterSlotPointer getEffectButtonParameterSlot( - const ConfigKey& configKey); + EffectParameterSlotBasePointer getEffectParameterSlot( + const EffectManifestParameter::ParameterType parameterType, const ConfigKey& configKey); QString getNextEffectId(const QString& effectId); QString getPrevEffectId(const QString& effectId); @@ -85,33 +125,29 @@ class EffectsManager : public QObject { const QList getAvailableEffectManifestsFiltered( EffectManifestFilterFnc filter) const; bool isEQ(const QString& effectId) const; + void getEffectManifestAndBackend( const QString& effectId, EffectManifestPointer* ppManifest, EffectsBackend** ppBackend) const; - EffectManifestPointer getEffectManifest(const QString& effectId) const; - EffectPointer instantiateEffect(const QString& effectId); + EffectManifestPointer getManifestFromUniqueId(const QString& uid) const; void setEffectVisibility(EffectManifestPointer pManifest, bool visibility); - bool getEffectVisibility(EffectManifestPointer pManifest); + bool getEffectVisibility(EffectManifestPointer pManifest); - // Temporary, but for setting up all the default EffectChains and EffectRacks void setup(); - // Reloads all effect to the slots to update parameter assignments - void refeshAllRacks(); + // TODO : Remove these functions once the GUI for parameter rearrangement is implemented + void hideEffectParameter(EffectManifestPointer pManifest, const unsigned int position); + void setEffectParameterPosition(EffectManifestPointer pManifest, + const unsigned int parameterId, const unsigned int position); // Write an EffectsRequest to the EngineEffectsManager. EffectsManager takes // ownership of request and deletes it once a response is received. bool writeRequest(EffectsRequest* request); signals: - // TODO() Not connected. Can be used when we implement effect PlugIn loading at runtime - void availableEffectsUpdated(EffectManifestPointer); void visibleEffectsUpdated(); - private slots: - void slotBackendRegisteredEffect(EffectManifestPointer pManifest); - private: QString debugString() const { return "EffectsManager"; @@ -122,8 +158,7 @@ class EffectsManager : public QObject { ChannelHandleFactory* m_pChannelHandleFactory; - EffectChainManager* m_pEffectChainManager; - QList m_effectsBackends; + QHash m_effectsBackends; QList m_availableEffectManifests; QList m_visibleEffectManifests; @@ -135,11 +170,23 @@ class EffectsManager : public QObject { ControlObject* m_pNumEffectsAvailable; // We need to create Control Objects for Equalizers' frequencies - ControlPotmeter* m_pLoEqFreq; - ControlPotmeter* m_pHiEqFreq; + ControlPotmeter m_loEqFreq; + ControlPotmeter m_hiEqFreq; bool m_underDestruction; + QSet m_registeredInputChannels; + QSet m_registeredOutputChannels; + UserSettingsPointer m_pConfig; + QHash m_effectChainSlotsByGroup; + + QList m_standardEffectChainSlots; + OutputEffectChainSlotPointer m_outputEffectChainSlot; + QHash m_equalizerEffectChainSlots; + QHash m_quickEffectChainSlots; + + QHash m_effectChainPresets; + DISALLOW_COPY_AND_ASSIGN(EffectsManager); }; diff --git a/src/effects/lv2/lv2backend.cpp b/src/effects/lv2/lv2backend.cpp index 2a5090805ce..0f13b2d4d59 100644 --- a/src/effects/lv2/lv2backend.cpp +++ b/src/effects/lv2/lv2backend.cpp @@ -1,8 +1,8 @@ #include "effects/lv2/lv2backend.h" #include "effects/lv2/lv2manifest.h" +#include "effects/lv2/lv2effectprocessor.h" -LV2Backend::LV2Backend(QObject* pParent) - : EffectsBackend(pParent, EffectBackendType::LV2) { +LV2Backend::LV2Backend() { m_pWorld = lilv_world_new(); initializeProperties(); lilv_world_load_all(m_pWorld); @@ -10,13 +10,11 @@ LV2Backend::LV2Backend(QObject* pParent) } LV2Backend::~LV2Backend() { - foreach(LilvNode* node, m_properties) { + for (LilvNode* node : m_properties) { lilv_node_free(node); } lilv_world_free(m_pWorld); - foreach(LV2Manifest* lv2Manifest, m_registeredEffects) { - delete lv2Manifest; - } + m_registeredEffects.clear(); } void LV2Backend::enumeratePlugins() { @@ -26,10 +24,9 @@ void LV2Backend::enumeratePlugins() { if (lilv_plugin_is_replaced(plug)) { continue; } - LV2Manifest* lv2Manifest = new LV2Manifest(plug, m_properties); - lv2Manifest->getEffectManifest()->setBackendType(m_type); - m_registeredEffects.insert(lv2Manifest->getEffectManifest()->id(), - lv2Manifest); + LV2EffectManifestPointer lv2Manifest(new LV2Manifest(plug, m_properties)); + lv2Manifest->setBackendType(getType()); + m_registeredEffects.insert(lv2Manifest->id(), lv2Manifest); } } @@ -45,9 +42,9 @@ void LV2Backend::initializeProperties() { const QList LV2Backend::getEffectIds() const { QList availableEffects; - foreach (LV2Manifest* lv2Manifest, m_registeredEffects) { + for (const auto& lv2Manifest : m_registeredEffects) { if (lv2Manifest->isValid()) { - availableEffects.append(lv2Manifest->getEffectManifest()->id()); + availableEffects.append(lv2Manifest->id()); } } return availableEffects; @@ -71,32 +68,22 @@ bool LV2Backend::canInstantiateEffect(const QString& effectId) const { } EffectManifestPointer LV2Backend::getManifest(const QString& effectId) const { - LV2Manifest* pLV2Mainfest = getLV2Manifest(effectId); - if (pLV2Mainfest != nullptr) { - return pLV2Mainfest->getEffectManifest(); + VERIFY_OR_DEBUG_ASSERT(m_registeredEffects.contains(effectId)) { + return EffectManifestPointer(); } - return EffectManifestPointer(); -} - -LV2Manifest* LV2Backend::getLV2Manifest(const QString& effectId) const { - return m_registeredEffects[effectId]; + return m_registeredEffects.value(effectId); } -EffectPointer LV2Backend::instantiateEffect(EffectsManager* pEffectsManager, - const QString& effectId) { - if (!canInstantiateEffect(effectId)) { - qWarning() << "WARNING: Effect" << effectId << "is not registered."; - return EffectPointer(); +std::unique_ptr LV2Backend::createProcessor( + const EffectManifestPointer pManifest) const { + LV2EffectManifestPointer pLV2Manifest = m_registeredEffects.value(pManifest->id()); + VERIFY_OR_DEBUG_ASSERT(pLV2Manifest) { + return std::unique_ptr(nullptr); } - LV2Manifest* lv2manifest = m_registeredEffects[effectId]; + return std::unique_ptr( + new LV2EffectProcessor(pLV2Manifest)); +} - return EffectPointer( - new Effect( - pEffectsManager, - lv2manifest->getEffectManifest(), - EffectInstantiatorPointer( - new LV2EffectProcessorInstantiator( - lv2manifest->getPlugin(), - lv2manifest->getAudioPortIndices(), - lv2manifest->getControlPortIndices())))); +LV2EffectManifestPointer LV2Backend::getLV2Manifest(const QString& effectId) const { + return m_registeredEffects[effectId]; } diff --git a/src/effects/lv2/lv2backend.h b/src/effects/lv2/lv2backend.h index 1a8c3e74791..3b9062b9dda 100644 --- a/src/effects/lv2/lv2backend.h +++ b/src/effects/lv2/lv2backend.h @@ -8,25 +8,26 @@ #include class LV2Backend : public EffectsBackend { - Q_OBJECT public: - LV2Backend(QObject* pParent); + LV2Backend(); virtual ~LV2Backend(); - void enumeratePlugins(); + EffectBackendType getType() const { return EffectBackendType::LV2; }; + const QList getEffectIds() const; const QSet getDiscoveredPluginIds() const; EffectManifestPointer getManifest(const QString& effectId) const; - LV2Manifest* getLV2Manifest(const QString& effectId) const; + LV2EffectManifestPointer getLV2Manifest(const QString& effectId) const; + std::unique_ptr createProcessor( + const EffectManifestPointer pManifest) const; bool canInstantiateEffect(const QString& effectId) const; - EffectPointer instantiateEffect(EffectsManager* pEffectsManager, - const QString& effectId); private: + void enumeratePlugins(); void initializeProperties(); LilvWorld* m_pWorld; QHash m_properties; - QHash m_registeredEffects; + QHash m_registeredEffects; QString debugString() const { return "LV2Backend"; diff --git a/src/effects/lv2/lv2effectprocessor.cpp b/src/effects/lv2/lv2effectprocessor.cpp index 16fb6336b8c..e9d39ad3d56 100644 --- a/src/effects/lv2/lv2effectprocessor.cpp +++ b/src/effects/lv2/lv2effectprocessor.cpp @@ -4,120 +4,51 @@ #include "util/sample.h" #include "util/defs.h" -LV2EffectProcessor::LV2EffectProcessor(EngineEffect* pEngineEffect, - EffectManifestPointer pManifest, - const LilvPlugin* plugin, - QList audioPortIndices, - QList controlPortIndices) - : m_pPlugin(plugin), - m_audioPortIndices(audioPortIndices), - m_controlPortIndices(controlPortIndices), - m_pEffectsManager(nullptr) { +LV2EffectProcessor::LV2EffectProcessor(LV2EffectManifestPointer pManifest) + : m_pManifest(pManifest), + m_pPlugin(pManifest->getPlugin()), + m_audioPortIndices(pManifest->getAudioPortIndices()), + m_controlPortIndices(pManifest->getControlPortIndices()) { m_inputL = new float[MAX_BUFFER_LEN]; m_inputR = new float[MAX_BUFFER_LEN]; m_outputL = new float[MAX_BUFFER_LEN]; m_outputR = new float[MAX_BUFFER_LEN]; - m_params = new float[pManifest->parameters().size()]; - - const QList& effectManifestParameterList = - pManifest->parameters(); +} - // Initialize EngineEffectParameters - for (const auto& pParam: effectManifestParameterList) { - m_parameters.append(pEngineEffect->getParameterById(pParam->id())); +void LV2EffectProcessor::loadEngineEffectParameters( + const QMap& parameters) { + m_LV2parameters = new float[parameters.size()]; + + // EngineEffect passes the EngineEffectParameters indexed by ID string, which + // is used directly by built-in EffectProcessorImpl subclasseses to access + // specific named parameters. However, LV2EffectProcessor::process iterates + // over the EngineEffectParameters to copy their values to the LV2 control + // ports. To avoid slow string comparisons in the audio engine thread in + // LV2EffectProcessor::process, rearrange the QMap of EngineEffectParameters by + // ID string to an ordered QList. + for (const auto& pManifestParameter : m_pManifest->parameters()) { + m_engineEffectParameters.append(parameters.value(pManifestParameter->id())); } } LV2EffectProcessor::~LV2EffectProcessor() { - if (kEffectDebugOutput) { - qDebug() << "~LV2EffectProcessor" << this; - } - int inputChannelHandleNumber = 0; - for (auto& outputsMap : m_channelStateMatrix) { - int outputChannelHandleNumber = 0; - for (LV2EffectGroupState* pState : outputsMap) { - VERIFY_OR_DEBUG_ASSERT(pState != nullptr) { - continue; - } - if (kEffectDebugOutput) { - qDebug() << "~LV2EffectProcessor deleting LilvInstance" << pState - << "for input ChannelHandle(" << inputChannelHandleNumber << ")" - << "and output ChannelHandle(" << outputChannelHandleNumber << ")"; - } - delete pState; - outputChannelHandleNumber++; - } - outputsMap.clear(); - } - m_channelStateMatrix.clear(); - delete[] m_inputL; delete[] m_inputR; delete[] m_outputL; delete[] m_outputR; - delete[] m_params; + delete[] m_LV2parameters; } -void LV2EffectProcessor::initialize( - const QSet& activeInputChannels, - EffectsManager* pEffectsManager, - const mixxx::EngineParameters& bufferParameters) { - Q_UNUSED(pEffectsManager); - Q_UNUSED(bufferParameters); - - - for (const ChannelHandleAndGroup& inputChannel : activeInputChannels) { - if (kEffectDebugOutput) { - qDebug() << this << "LV2EffectProcessor::initialize allocating " - "EffectStates for input" << inputChannel; - } - ChannelHandleMap outputChannelMap; - for (const ChannelHandleAndGroup& outputChannel : - pEffectsManager->registeredOutputChannels()) { - LV2EffectGroupState* pGroupState = createGroupState(bufferParameters); - if (pGroupState) { - outputChannelMap.insert(outputChannel.handle(), pGroupState); - if (kEffectDebugOutput) { - qDebug() << this << "EffectProcessorImpl::initialize " - "registering output" << outputChannel << outputChannelMap[outputChannel.handle()]; - } - } - } - m_channelStateMatrix.insert(inputChannel.handle(), outputChannelMap); - } - m_pEffectsManager = pEffectsManager; - DEBUG_ASSERT(m_pEffectsManager != nullptr); -} - -void LV2EffectProcessor::process(const ChannelHandle& inputHandle, - const ChannelHandle& outputHandle, +void LV2EffectProcessor::processChannel( + LV2EffectGroupState* channelState, const CSAMPLE* pInput, CSAMPLE* pOutput, const mixxx::EngineParameters& bufferParameters, const EffectEnableState enableState, const GroupFeatureState& groupFeatures) { Q_UNUSED(groupFeatures); - Q_UNUSED(enableState); - - LV2EffectGroupState* pState = m_channelStateMatrix[inputHandle][outputHandle]; - VERIFY_OR_DEBUG_ASSERT(pState != nullptr) { - if (kEffectDebugOutput) { - qWarning() << "LV2EffectProcessor::process could not retrieve" - "handle for input" << inputHandle - << "and output" << outputHandle - << "Handle should have been preallocated in the" - "main thread."; - } - pState = createGroupState(bufferParameters); - m_channelStateMatrix[inputHandle][outputHandle] = pState; - } - - if (!pState) { - SampleUtil::copyWithGain(pOutput, pInput, 1.0, bufferParameters.samplesPerBuffer()); - return; - } - for (int i = 0; i < m_parameters.size(); i++) { - m_params[i] = m_parameters[i]->value(); + for (int i = 0; i < m_engineEffectParameters.size(); i++) { + m_LV2parameters[i] = m_engineEffectParameters[i]->value(); } int j = 0; @@ -127,7 +58,13 @@ void LV2EffectProcessor::process(const ChannelHandle& inputHandle, j++; } - lilv_instance_run(pState->lilvIinstance(), bufferParameters.framesPerBuffer()); + LilvInstance* instance = channelState->lilvInstance(m_pPlugin, bufferParameters); + + if (enableState == EffectEnableState::Enabling) { + lilv_instance_activate(instance); + } + + lilv_instance_run(instance, bufferParameters.framesPerBuffer()); j = 0; for (unsigned int i = 0; i < bufferParameters.samplesPerBuffer(); i += 2) { @@ -135,111 +72,37 @@ void LV2EffectProcessor::process(const ChannelHandle& inputHandle, pOutput[i + 1] = m_outputR[j]; j++; } -} - -LV2EffectGroupState* LV2EffectProcessor::createGroupState(const mixxx::EngineParameters& bufferParameters) { - LV2EffectGroupState * pState = new LV2EffectGroupState(bufferParameters, m_pPlugin); - LilvInstance* handle = pState->lilvIinstance(); - if (handle) { - for (int i = 0; i < m_parameters.size(); i++) { - m_params[i] = m_parameters[i]->value(); - lilv_instance_connect_port(handle, m_controlPortIndices[i], &m_params[i]); - } - - // We assume the audio ports are in the following order: - // input_left, input_right, output_left, output_right - lilv_instance_connect_port(handle, m_audioPortIndices[0], m_inputL); - lilv_instance_connect_port(handle, m_audioPortIndices[1], m_inputR); - lilv_instance_connect_port(handle, m_audioPortIndices[2], m_outputL); - lilv_instance_connect_port(handle, m_audioPortIndices[3], m_outputR); - lilv_instance_activate(handle); - } - if (kEffectDebugOutput) { - qDebug() << this << "LV2EffectProcessor creating EffectState" << pState; + if (enableState == EffectEnableState::Disabling) { + lilv_instance_deactivate(instance); } - return pState; -}; - -EffectState* LV2EffectProcessor::createState(const mixxx::EngineParameters& bufferParameters) { - return createGroupState(bufferParameters); -}; +} -bool LV2EffectProcessor::loadStatesForInputChannel(const ChannelHandle* inputChannel, - const EffectStatesMap* pStatesMap) { - if (kEffectDebugOutput) { - qDebug() << "LV2EffectProcessor::loadStatesForInputChannel" << this - << "input" << *inputChannel; +LV2EffectGroupState* LV2EffectProcessor::createSpecificState( + const mixxx::EngineParameters& bufferParameters) { + LV2EffectGroupState* pState = new LV2EffectGroupState(bufferParameters); + LilvInstance* pInstance = pState->lilvInstance(m_pPlugin, bufferParameters); + VERIFY_OR_DEBUG_ASSERT(pInstance) { + return pState; } - // NOTE: ChannelHandleMap is like a map in that it associates an - // object with a ChannelHandle key, but it actually backed by a - // QVarLengthArray, not a QMap. So it is okay that - // m_channelStateMatrix may be accessed concurrently in the main - // thread in deleteStatesForInputChannel. - - // Can't directly cast a ChannelHandleMap from containing the base - // EffectState* type to EffectSpecificState* type, so iterate through - // pStatesMap to build a new ChannelHandleMap with - // dynamic_cast'ed states. - ChannelHandleMap& effectSpecificStatesMap = - m_channelStateMatrix[*inputChannel]; - - // deleteStatesForInputChannel should have been called before a new - // map of EffectStates was sent to this function, or this is the first - // time states are being loaded for this input channel, so - // effectSpecificStatesMap should be empty and this loop should - // not go through any iterations. - for (LV2EffectGroupState* pState : effectSpecificStatesMap) { - VERIFY_OR_DEBUG_ASSERT(pState == nullptr) { - delete pState; - qDebug() << "for effectSpecificStatesMap"; - } + if (kEffectDebugOutput) { + qDebug() << this << "LV2EffectProcessor creating LV2EffectGroupState" << pState; } - for (const ChannelHandleAndGroup& outputChannel : - m_pEffectsManager->registeredOutputChannels()) { - if (kEffectDebugOutput) { - qDebug() << "LV2EffectProcessor::loadStatesForInputChannel" - << this << "output" << outputChannel; + if (pInstance) { + for (int i = 0; i < m_engineEffectParameters.size(); i++) { + m_LV2parameters[i] = m_engineEffectParameters[i]->value(); + lilv_instance_connect_port(pInstance, + m_controlPortIndices[i], &m_LV2parameters[i]); } - auto pState = dynamic_cast( - pStatesMap->at(outputChannel.handle())); - VERIFY_OR_DEBUG_ASSERT(pState != nullptr) { - return false; - } - effectSpecificStatesMap.insert(outputChannel.handle(), pState); - } - return true; -} - -// Called from main thread for garbage collection after the last audio thread -// callback executes process() with EffectEnableState::Disabling -void LV2EffectProcessor::deleteStatesForInputChannel(const ChannelHandle* inputChannel) { - if (kEffectDebugOutput) { - qDebug() << "LV2EffectProcessor::deleteStatesForInputChannel" - << this << *inputChannel; - } - - // NOTE: ChannelHandleMap is like a map in that it associates an - // object with a ChannelHandle key, but it actually backed by a - // QVarLengthArray, not a QMap. So it is okay that - // m_channelStateMatrix may be accessed concurrently in the audio - // engine thread in loadStatesForInputChannel. - - ChannelHandleMap& stateMap = - m_channelStateMatrix[*inputChannel]; - for (LV2EffectGroupState* pState : stateMap) { - VERIFY_OR_DEBUG_ASSERT(pState != nullptr) { - continue; - } - if (kEffectDebugOutput) { - qDebug() << "LV2EffectProcessor::deleteStatesForInputChannel" - << this << "deleting state" << pState; - } - delete pState; - qDebug() << "inputChannel" << inputChannel; + // We assume the audio ports are in the following order: + // input_left, input_right, output_left, output_right + lilv_instance_connect_port(pInstance, m_audioPortIndices[0], m_inputL); + lilv_instance_connect_port(pInstance, m_audioPortIndices[1], m_inputR); + lilv_instance_connect_port(pInstance, m_audioPortIndices[2], m_outputL); + lilv_instance_connect_port(pInstance, m_audioPortIndices[3], m_outputR); } - stateMap.clear(); -} + return pState; +}; diff --git a/src/effects/lv2/lv2effectprocessor.h b/src/effects/lv2/lv2effectprocessor.h index 3cebc56d12e..923546fa8a8 100644 --- a/src/effects/lv2/lv2effectprocessor.h +++ b/src/effects/lv2/lv2effectprocessor.h @@ -2,71 +2,67 @@ #define LV2EFFECTPROCESSOR_H #include "effects/effectprocessor.h" -#include "effects/effectmanifest.h" +#include "effects/lv2/lv2manifest.h" #include "engine/effects/engineeffectparameter.h" #include #include "effects/defs.h" #include "engine/engine.h" -class LV2EffectGroupState : public EffectState { +class LV2EffectGroupState final: public EffectState { public: - LV2EffectGroupState(const mixxx::EngineParameters& bufferParameters, const LilvPlugin* pPlugin) - : EffectState(bufferParameters) { - m_pInstance = lilv_plugin_instantiate(pPlugin, bufferParameters.sampleRate(), nullptr); + LV2EffectGroupState(const mixxx::EngineParameters& bufferParameters) + : EffectState(bufferParameters), + m_pInstance(nullptr) { } ~LV2EffectGroupState() { - lilv_instance_deactivate(m_pInstance); - lilv_instance_free(m_pInstance); + if (m_pInstance) { + lilv_instance_deactivate(m_pInstance); + lilv_instance_free(m_pInstance); + } } - LilvInstance* lilvIinstance() { + LilvInstance* lilvInstance(const LilvPlugin* pPlugin, + const mixxx::EngineParameters& bufferParameters) { + if (!m_pInstance) { + m_pInstance = lilv_plugin_instantiate( + pPlugin, bufferParameters.sampleRate(), nullptr); + } return m_pInstance; } + private: LilvInstance* m_pInstance; }; -class LV2EffectProcessor : public EffectProcessor { +class LV2EffectProcessor final : public EffectProcessorImpl { public: - LV2EffectProcessor(EngineEffect* pEngineEffect, - EffectManifestPointer pManifest, - const LilvPlugin* plugin, - QList audioPortIndices, - QList controlPortIndices); + LV2EffectProcessor(LV2EffectManifestPointer pManifest); ~LV2EffectProcessor(); - void initialize( - const QSet& activeInputChannels, - EffectsManager* pEffectsManager, - const mixxx::EngineParameters& bufferParameters) override; - EffectState* createState(const mixxx::EngineParameters& bufferParameters) final; - bool loadStatesForInputChannel(const ChannelHandle* inputChannel, - const EffectStatesMap* pStatesMap) override; - // Called from main thread for garbage collection after the last audio thread - // callback executes process() with EffectEnableState::Disabling - void deleteStatesForInputChannel(const ChannelHandle* inputChannel) override; + void loadEngineEffectParameters( + const QMap& parameters) override; - void process(const ChannelHandle& inputHandle, - const ChannelHandle& outputHandle, + void processChannel( + LV2EffectGroupState* channelState, const CSAMPLE* pInput, CSAMPLE* pOutput, const mixxx::EngineParameters& bufferParameters, const EffectEnableState enableState, const GroupFeatureState& groupFeatures) override; + private: - LV2EffectGroupState* createGroupState(const mixxx::EngineParameters& bufferParameters); + LV2EffectGroupState* createSpecificState( + const mixxx::EngineParameters& bufferParameters) override; - QList m_parameters; + LV2EffectManifestPointer m_pManifest; + QList m_engineEffectParameters; float* m_inputL; float* m_inputR; float* m_outputL; float* m_outputR; - float* m_params; + float* m_LV2parameters; const LilvPlugin* m_pPlugin; const QList m_audioPortIndices; const QList m_controlPortIndices; - - EffectsManager* m_pEffectsManager; - ChannelHandleMap> m_channelStateMatrix; }; diff --git a/src/effects/lv2/lv2manifest.cpp b/src/effects/lv2/lv2manifest.cpp index b41915fe819..fab234144f6 100644 --- a/src/effects/lv2/lv2manifest.cpp +++ b/src/effects/lv2/lv2manifest.cpp @@ -4,23 +4,22 @@ LV2Manifest::LV2Manifest(const LilvPlugin* plug, QHash& properties) - : m_pEffectManifest(new EffectManifest()), + : EffectManifest(), m_status(AVAILABLE) { - m_pLV2plugin = plug; // Get and set the ID const LilvNode* id = lilv_plugin_get_uri(m_pLV2plugin); - m_pEffectManifest->setId(lilv_node_as_string(id)); + setId(lilv_node_as_string(id)); // Get and set the name LilvNode* info = lilv_plugin_get_name(m_pLV2plugin); - m_pEffectManifest->setName(lilv_node_as_string(info)); + setName(lilv_node_as_string(info)); lilv_node_free(info); // Get and set the author info = lilv_plugin_get_author_name(m_pLV2plugin); - m_pEffectManifest->setAuthor(lilv_node_as_string(info)); + setAuthor(lilv_node_as_string(info)); lilv_node_free(info); int numPorts = lilv_plugin_get_num_ports(plug); @@ -55,7 +54,7 @@ LV2Manifest::LV2Manifest(const LilvPlugin* plug, && !lilv_port_has_property(m_pLV2plugin, port, properties["enumeration_port"]) && !lilv_port_has_property(m_pLV2plugin, port, properties["button_port"])) { controlPortIndices.append(i); - EffectManifestParameterPointer param = m_pEffectManifest->addParameter(); + EffectManifestParameterPointer param = addParameter(); // Get and set the parameter name info = lilv_port_get_name(m_pLV2plugin, port); @@ -70,20 +69,18 @@ LV2Manifest::LV2Manifest(const LilvPlugin* plug, param->setSemanticHint(EffectManifestParameter::SemanticHint::UNKNOWN); param->setUnitsHint(EffectManifestParameter::UnitsHint::UNKNOWN); - param->setDefault(m_default[i]); - param->setMinimum(m_minimum[i]); - param->setMaximum(m_maximum[i]); + param->setRange(m_minimum[i], m_default[i], m_maximum[i]); // Set the appropriate Hints if (lilv_port_has_property(m_pLV2plugin, port, properties["button_port"])) { - param->setControlHint(EffectManifestParameter::ControlHint::TOGGLE_STEPPING); + param->setValueScaler(EffectManifestParameter::ValueScaler::TOGGLE); } else if (lilv_port_has_property(m_pLV2plugin, port, properties["enumeration_port"])) { buildEnumerationOptions(port, param); - param->setControlHint(EffectManifestParameter::ControlHint::TOGGLE_STEPPING); + param->setValueScaler(EffectManifestParameter::ValueScaler::TOGGLE); } else if (lilv_port_has_property(m_pLV2plugin, port, properties["integer_port"])) { - param->setControlHint(EffectManifestParameter::ControlHint::KNOB_STEPPING); + param->setValueScaler(EffectManifestParameter::ValueScaler::INTEGRAL); } else { - param->setControlHint(EffectManifestParameter::ControlHint::KNOB_LINEAR); + param->setValueScaler(EffectManifestParameter::ValueScaler::LINEAR); } } } @@ -96,7 +93,7 @@ LV2Manifest::LV2Manifest(const LilvPlugin* plug, (lilv_port_has_property(m_pLV2plugin, port, properties["enumeration_port"]) || lilv_port_has_property(m_pLV2plugin, port, properties["button_port"]))) { controlPortIndices.append(i); - EffectManifestParameterPointer param = m_pEffectManifest->addParameter(); + EffectManifestParameterPointer param = addParameter(); // Get and set the parameter name info = lilv_port_get_name(m_pLV2plugin, port); @@ -111,7 +108,7 @@ LV2Manifest::LV2Manifest(const LilvPlugin* plug, param->setSemanticHint(EffectManifestParameter::SemanticHint::UNKNOWN); param->setUnitsHint(EffectManifestParameter::UnitsHint::UNKNOWN); - param->setControlHint(EffectManifestParameter::ControlHint::TOGGLE_STEPPING); + param->setValueScaler(EffectManifestParameter::ValueScaler::TOGGLE); if (lilv_port_has_property(m_pLV2plugin, port, properties["enumeration_port"])) { buildEnumerationOptions(port, param); } else { @@ -122,23 +119,21 @@ LV2Manifest::LV2Manifest(const LilvPlugin* plug, // Some plugins don't specify minimum, maximum and default values // In this case set the minimum and default values to 0 and // the maximum to the number of scale points - if (isnan(m_default[i])) { - param->setDefault(0); - } else { - param->setDefault(m_default[i]); - } + double minimum = 0; + double defaultValue = 0; + double maximum = param->getSteps().size() - 1; - if (isnan(m_minimum[i])) { - param->setMinimum(0); - } else { - param->setMinimum(m_minimum[i]); + if (!isnan(m_minimum[i])) { + minimum = m_minimum[i]; } - - if (isnan(m_maximum[i])) { - param->setMaximum(param->getSteps().size() - 1); - } else { - param->setMaximum(m_maximum[i]); + if (!isnan(m_default[i])) { + defaultValue = m_default[i]; + } + if (!isnan(m_maximum[i])) { + maximum = m_maximum[i]; } + + param->setRange(minimum, defaultValue, maximum); } } @@ -161,10 +156,6 @@ LV2Manifest::~LV2Manifest() { delete m_default; } -EffectManifestPointer LV2Manifest::getEffectManifest() const { - return m_pEffectManifest; -} - QList LV2Manifest::getAudioPortIndices() { return audioPortIndices; } @@ -193,8 +184,8 @@ void LV2Manifest::buildEnumerationOptions(const LilvPort* port, const LilvNode* description = lilv_scale_point_get_label(option); const LilvNode* value = lilv_scale_point_get_value(option); QString strDescription(lilv_node_as_string(description)); - param->appendStep(qMakePair(strDescription, - (double)lilv_node_as_float(value))); + param->appendStep(qMakePair( + strDescription, (double)lilv_node_as_float(value))); } if (options != NULL) { diff --git a/src/effects/lv2/lv2manifest.h b/src/effects/lv2/lv2manifest.h index ec81d88ee1c..f9d85a28c73 100644 --- a/src/effects/lv2/lv2manifest.h +++ b/src/effects/lv2/lv2manifest.h @@ -1,11 +1,13 @@ #ifndef LV2MANIFEST_H #define LV2MANIFEST_H +#include + #include "effects/effectmanifest.h" #include "effects/defs.h" #include -class LV2Manifest { +class LV2Manifest : public EffectManifest { public: enum Status { AVAILABLE, @@ -15,7 +17,7 @@ class LV2Manifest { LV2Manifest(const LilvPlugin* plug, QHash& properties); ~LV2Manifest(); - EffectManifestPointer getEffectManifest() const; + QList getAudioPortIndices(); QList getControlPortIndices(); const LilvPlugin* getPlugin(); @@ -26,7 +28,6 @@ class LV2Manifest { void buildEnumerationOptions(const LilvPort* port, EffectManifestParameterPointer param); const LilvPlugin* m_pLV2plugin; - EffectManifestPointer m_pEffectManifest; // This list contains: // position 0 -> input_left port index @@ -45,4 +46,6 @@ class LV2Manifest { bool m_isValid; }; +typedef QSharedPointer LV2EffectManifestPointer; + #endif // LV2MANIFEST_H diff --git a/src/effects/specialeffectchainslots.cpp b/src/effects/specialeffectchainslots.cpp new file mode 100644 index 00000000000..dc7b947081c --- /dev/null +++ b/src/effects/specialeffectchainslots.cpp @@ -0,0 +1,208 @@ +#include "effects/specialeffectchainslots.h" + +#include "effects/effectchainslot.h" +#include "mixer/playermanager.h" + +StandardEffectChainSlot::StandardEffectChainSlot(unsigned int iChainNumber, + EffectsManager* pEffectsManager, + const QString& id) + : EffectChainSlot(formatEffectChainSlotGroup(iChainNumber), + pEffectsManager, + SignalProcessingStage::Postfader, + formatEffectChainSlotGroup(iChainNumber)) { + for (int i = 0; i < kNumEffectsPerUnit; ++i) { + addEffectSlot(formatEffectSlotGroup(iChainNumber, i)); + } + + const QSet& registeredChannels = + m_pEffectsManager->registeredInputChannels(); + for (const ChannelHandleAndGroup& handle_group : registeredChannels) { + int deckNumber; + if (PlayerManager::isDeckGroup(handle_group.name(), &deckNumber) && + (iChainNumber + 1) == (unsigned) deckNumber) { + registerInputChannel(handle_group, 1.0); + } else { + registerInputChannel(handle_group, 0.0); + } + } +} + +QString StandardEffectChainSlot::formatEffectChainSlotGroup(const int iChainNumber) { + return QString("[EffectRack1_EffectUnit%1]") + .arg(QString::number(iChainNumber + 1)); +} + +QString StandardEffectChainSlot::formatEffectSlotGroup(const int iChainSlotNumber, + const int iEffectSlotNumber) { + return QString("[EffectRack1_EffectUnit%1_Effect%2]") + .arg(QString::number(iChainSlotNumber + 1)) + .arg(QString::number(iEffectSlotNumber + 1)); +} + + +OutputEffectChainSlot::OutputEffectChainSlot(EffectsManager* pEffectsManager) + : EffectChainSlot(formatEffectChainSlotGroup("[Master]"), + pEffectsManager, + SignalProcessingStage::Postfader, + formatEffectChainSlotGroup("[Master]")) { + addEffectSlot("[OutputEffectRack_[Master]_Effect1]"); + m_effectSlots[0]->setEnabled(true); + + // Register the master channel + const ChannelHandleAndGroup* masterHandleAndGroup = nullptr; + + // TODO(Be): Remove this hideous hack to get the ChannelHandleAndGroup + const QSet& registeredChannels = + m_pEffectsManager->registeredInputChannels(); + for (const ChannelHandleAndGroup& handle_group : registeredChannels) { + if (handle_group.name() == "[MasterOutput]") { + masterHandleAndGroup = &handle_group; + break; + } + } + DEBUG_ASSERT(masterHandleAndGroup != nullptr); + + registerInputChannel(*masterHandleAndGroup); + enableForInputChannel(*masterHandleAndGroup); + m_pControlChainMix->set(1.0); + sendParameterUpdate(); +} + +QString OutputEffectChainSlot::formatEffectChainSlotGroup(const QString& group) { + return QString("[OutputEffectRack_%1]").arg(group); +} + + +PerGroupEffectChainSlot::PerGroupEffectChainSlot(const QString& group, + const QString& chainSlotGroup, + EffectsManager* pEffectsManager) + : EffectChainSlot(chainSlotGroup, pEffectsManager, + SignalProcessingStage::Prefader, + chainSlotGroup) { + // Set the chain to be fully wet. + m_pControlChainMix->set(1.0); + sendParameterUpdate(); + + // TODO(rryan): remove. + const ChannelHandleAndGroup* handleAndGroup = nullptr; + for (const ChannelHandleAndGroup& handle_group : + m_pEffectsManager->registeredInputChannels()) { + if (handle_group.name() == group) { + handleAndGroup = &handle_group; + break; + } + } + DEBUG_ASSERT(handleAndGroup != nullptr); + + // Register this channel alone with the chain slot. + registerInputChannel(*handleAndGroup); + enableForInputChannel(*handleAndGroup); +} + +QuickEffectChainSlot::QuickEffectChainSlot(const QString& group, + EffectsManager* pEffectsManager) + : PerGroupEffectChainSlot(group, formatEffectChainSlotGroup(group), + pEffectsManager) { + // Add a single effect slot + addEffectSlot(formatEffectSlotGroup(group)); + m_effectSlots[0]->setEnabled(true); + // DlgPrefEq loads the Effect with loadEffectToGroup + + setSuperParameter(0.5); + setSuperParameterDefaultValue(0.5); +} + +void QuickEffectChainSlot::loadEffect( + const unsigned int iEffectSlotNumber, + const EffectManifestPointer pManifest, + std::unique_ptr pProcessor) { + EffectChainSlot::loadEffect(iEffectSlotNumber, pManifest, std::move(pProcessor)); + slotControlChainSuperParameter(m_pControlChainSuperParameter->get(), true); +} + +QString QuickEffectChainSlot::formatEffectChainSlotGroup(const QString& group) { + return QString("[QuickEffectRack1_%1]").arg(group); +} + +QString QuickEffectChainSlot::formatEffectSlotGroup(const QString& group, + const int iEffectSlotNumber) { + return QString("[QuickEffectRack1_%1_Effect%2]") + .arg(group) + .arg(QString::number(iEffectSlotNumber + 1)); +} + + +EqualizerEffectChainSlot::EqualizerEffectChainSlot(const QString& group, + EffectsManager* pEffectsManager) + : PerGroupEffectChainSlot(group, formatEffectChainSlotGroup(group), + pEffectsManager), + m_pCOFilterWaveform(new ControlObject(ConfigKey(group, "filterWaveformEnable"))) { + // Add a single effect slot + addEffectSlot(formatEffectSlotGroup(group)); + m_effectSlots[0]->setEnabled(true); + // DlgPrefEq loads the Effect with loadEffectToGroup + + setupLegacyAliasesForGroup(group); +} + +void EqualizerEffectChainSlot::loadEffect( + const unsigned int iEffectSlotNumber, + const EffectManifestPointer pManifest, + std::unique_ptr pProcessor) { + // TODO: preserve effect parameters when loading new effect. This will allow + // for easy comparison of the sound of different equalizer effects. + EffectChainSlot::loadEffect(iEffectSlotNumber, pManifest, std::move(pProcessor)); + m_pCOFilterWaveform->set(pManifest->isMixingEQ()); +} + +QString EqualizerEffectChainSlot::formatEffectChainSlotGroup(const QString& group) { + return QString("[EqualizerRack1_%1]").arg(group); +} + +QString EqualizerEffectChainSlot::formatEffectSlotGroup(const QString& group) { + return QString("[EqualizerRack1_%1_Effect1]") + .arg(group); +} + +void EqualizerEffectChainSlot::setupLegacyAliasesForGroup(const QString& group) { + // Create aliases for legacy EQ controls. + EffectSlotPointer pEffectSlot = getEffectSlot(0); + if (pEffectSlot) { + const QString& effectSlotGroup = pEffectSlot->getGroup(); + ControlDoublePrivate::insertAlias(ConfigKey(group, "filterLow"), + ConfigKey(effectSlotGroup, "parameter1")); + + ControlDoublePrivate::insertAlias(ConfigKey(group, "filterMid"), + ConfigKey(effectSlotGroup, "parameter2")); + + ControlDoublePrivate::insertAlias(ConfigKey(group, "filterHigh"), + ConfigKey(effectSlotGroup, "parameter3")); + + ControlDoublePrivate::insertAlias(ConfigKey(group, "filterLowKill"), + ConfigKey(effectSlotGroup, "button_parameter1")); + + ControlDoublePrivate::insertAlias(ConfigKey(group, "filterMidKill"), + ConfigKey(effectSlotGroup, "button_parameter2")); + + ControlDoublePrivate::insertAlias(ConfigKey(group, "filterHighKill"), + ConfigKey(effectSlotGroup, "button_parameter3")); + + ControlDoublePrivate::insertAlias(ConfigKey(group, "filterLow_loaded"), + ConfigKey(effectSlotGroup, "parameter1_loaded")); + + ControlDoublePrivate::insertAlias(ConfigKey(group, "filterMid_loaded"), + ConfigKey(effectSlotGroup, "parameter2_loaded")); + + ControlDoublePrivate::insertAlias(ConfigKey(group, "filterHigh_loaded"), + ConfigKey(effectSlotGroup, "parameter3_loaded")); + + ControlDoublePrivate::insertAlias(ConfigKey(group, "filterLowKill_loaded"), + ConfigKey(effectSlotGroup, "button_parameter1_loaded")); + + ControlDoublePrivate::insertAlias(ConfigKey(group, "filterMidKill_loaded"), + ConfigKey(effectSlotGroup, "button_parameter2_loaded")); + + ControlDoublePrivate::insertAlias(ConfigKey(group, "filterHighKill_loaded"), + ConfigKey(effectSlotGroup, "button_parameter3_loaded")); + } +} diff --git a/src/effects/specialeffectchainslots.h b/src/effects/specialeffectchainslots.h new file mode 100644 index 00000000000..780b492e1ba --- /dev/null +++ b/src/effects/specialeffectchainslots.h @@ -0,0 +1,66 @@ +#ifndef SPECIALEFFECTCHAINSLOTS_H +#define SPECIALEFFECTCHAINSLOTS_H + +#include "effects/effectchainslot.h" +#include "effects/effectsmanager.h" +#include "effects/effectslot.h" +#include "effects/defs.h" +#include "util/memory.h" + +class StandardEffectChainSlot : public EffectChainSlot { + public: + StandardEffectChainSlot(unsigned int iChainNumber, + EffectsManager* pEffectsManager, + const QString& id = QString()); + static QString formatEffectChainSlotGroup(const int iChainNumber); + static QString formatEffectSlotGroup(const int iChainSlotNumber, + const int iEffectSlotNumber); +}; + +class OutputEffectChainSlot : public EffectChainSlot { + public: + OutputEffectChainSlot(EffectsManager* pEffectsManager); + + private: + static QString formatEffectChainSlotGroup(const QString& group); +}; + +class PerGroupEffectChainSlot : public EffectChainSlot { + public: + PerGroupEffectChainSlot(const QString& group, + const QString& chainSlotGroup, + EffectsManager* pEffectsManager); +}; + +class QuickEffectChainSlot : public PerGroupEffectChainSlot { + public: + QuickEffectChainSlot(const QString& group, + EffectsManager* pEffectsManager); + + void loadEffect(const unsigned int iEffectSlotNumber, + const EffectManifestPointer pManifest, + std::unique_ptr pProcessor) override; + + static QString formatEffectChainSlotGroup(const QString& group); + static QString formatEffectSlotGroup(const QString& group, + const int iEffectSlotNumber = 0); +}; + +class EqualizerEffectChainSlot : public PerGroupEffectChainSlot { + public: + EqualizerEffectChainSlot(const QString& group, + EffectsManager* pEffectsManager); + + void loadEffect(const unsigned int iEffectSlotNumber, + const EffectManifestPointer pManifest, + std::unique_ptr pProcessor) override; + + static QString formatEffectChainSlotGroup(const QString& group); + static QString formatEffectSlotGroup(const QString& group); + + private: + void setupLegacyAliasesForGroup(const QString& group); + std::unique_ptr m_pCOFilterWaveform; +}; + +#endif /* SPECIALEFFECTCHAINSLOTS_H */ diff --git a/src/engine/effects/engineeffect.cpp b/src/engine/effects/engineeffect.cpp index 8fccbb7740e..2b4d85daf8e 100644 --- a/src/engine/effects/engineeffect.cpp +++ b/src/engine/effects/engineeffect.cpp @@ -7,15 +7,15 @@ EngineEffect::EngineEffect(EffectManifestPointer pManifest, const QSet& activeInputChannels, EffectsManager* pEffectsManager, - EffectInstantiatorPointer pInstantiator) + std::unique_ptr pProcessor) : m_pManifest(pManifest), + m_pProcessor(std::move(pProcessor)), m_parameters(pManifest->parameters().size()), m_pEffectsManager(pEffectsManager) { const QList& parameters = m_pManifest->parameters(); for (int i = 0; i < parameters.size(); ++i) { EffectManifestParameterPointer param = parameters.at(i); - EngineEffectParameter* pParameter = - new EngineEffectParameter(param); + EngineEffectParameterPointer pParameter(new EngineEffectParameter(param)); m_parameters[i] = pParameter; m_parametersById[param->id()] = pParameter; } @@ -30,13 +30,14 @@ EngineEffect::EngineEffect(EffectManifestPointer pManifest, m_effectEnableStateForChannelMatrix.insert(inputChannel.handle(), outputChannelMap); } - // Creating the processor must come last. - m_pProcessor = pInstantiator->instantiate(this, pManifest); + m_pProcessor->loadEngineEffectParameters(m_parametersById); + //TODO: get actual configuration of engine const mixxx::EngineParameters bufferParameters( mixxx::AudioSignal::SampleRate(96000), MAX_BUFFER_LEN / mixxx::kEngineChannelCount); - m_pProcessor->initialize(activeInputChannels, pEffectsManager, bufferParameters); + m_pProcessor->initialize(activeInputChannels, + pEffectsManager->registeredOutputChannels(), bufferParameters); m_effectRampsFromDry = pManifest->effectRampsFromDry(); } @@ -44,13 +45,8 @@ EngineEffect::~EngineEffect() { if (kEffectDebugOutput) { qDebug() << debugString() << "destroyed"; } - delete m_pProcessor; m_parametersById.clear(); - for (int i = 0; i < m_parameters.size(); ++i) { - EngineEffectParameter* pParameter = m_parameters.at(i); - m_parameters[i] = NULL; - delete pParameter; - } + m_parameters.clear(); } EffectState* EngineEffect::createState(const mixxx::EngineParameters& bufferParameters) { @@ -61,7 +57,7 @@ EffectState* EngineEffect::createState(const mixxx::EngineParameters& bufferPara } void EngineEffect::loadStatesForInputChannel(const ChannelHandle* inputChannel, - EffectStatesMap* pStatesMap) { + EffectStatesMap* pStatesMap) { if (kEffectDebugOutput) { qDebug() << "EngineEffect::loadStatesForInputChannel" << this << "loading states for input" << *inputChannel; @@ -76,7 +72,7 @@ void EngineEffect::deleteStatesForInputChannel(const ChannelHandle* inputChannel bool EngineEffect::processEffectsRequest(EffectsRequest& message, EffectsResponsePipe* pResponsePipe) { - EngineEffectParameter* pParameter = NULL; + EngineEffectParameterPointer pParameter; EffectsResponse response(message); switch (message.type) { @@ -117,7 +113,7 @@ bool EngineEffect::processEffectsRequest(EffectsRequest& message, << "value" << message.value; } pParameter = m_parameters.value( - message.SetParameterParameters.iParameter, NULL); + message.SetParameterParameters.iParameter, EngineEffectParameterPointer()); if (pParameter) { pParameter->setMinimum(message.minimum); pParameter->setMaximum(message.maximum); diff --git a/src/engine/effects/engineeffect.h b/src/engine/effects/engineeffect.h index d42c1a6759c..f7dfb264f61 100644 --- a/src/engine/effects/engineeffect.h +++ b/src/engine/effects/engineeffect.h @@ -11,28 +11,25 @@ #include "effects/effectsmanager.h" #include "effects/effectmanifest.h" #include "effects/effectprocessor.h" -#include "effects/effectinstantiator.h" #include "engine/channelhandle.h" #include "engine/effects/engineeffectparameter.h" #include "engine/effects/message.h" #include "engine/effects/groupfeaturestate.h" +#include "util/memory.h" + class EngineEffect : public EffectsRequestHandler { public: EngineEffect(EffectManifestPointer pManifest, const QSet& activeInputChannels, EffectsManager* pEffectsManager, - EffectInstantiatorPointer pInstantiator); + std::unique_ptr pProcessor); virtual ~EngineEffect(); const QString& name() const { return m_pManifest->name(); } - EngineEffectParameter* getParameterById(const QString& id) { - return m_parametersById.value(id, NULL); - } - EffectState* createState(const mixxx::EngineParameters& bufferParameters); void loadStatesForInputChannel(const ChannelHandle* inputChannel, @@ -60,12 +57,12 @@ class EngineEffect : public EffectsRequestHandler { } EffectManifestPointer m_pManifest; - EffectProcessor* m_pProcessor; + std::unique_ptr m_pProcessor; ChannelHandleMap> m_effectEnableStateForChannelMatrix; bool m_effectRampsFromDry; // Must not be modified after construction. - QVector m_parameters; - QMap m_parametersById; + QVector m_parameters; + QMap m_parametersById; const EffectsManager* m_pEffectsManager; diff --git a/src/engine/effects/engineeffectchain.cpp b/src/engine/effects/engineeffectchain.cpp index 11e57d17783..002b909a54b 100644 --- a/src/engine/effects/engineeffectchain.cpp +++ b/src/engine/effects/engineeffectchain.cpp @@ -113,7 +113,8 @@ bool EngineEffectChain::processEffectsRequest(EffectsRequest& message, if (kEffectDebugOutput) { qDebug() << debugString() << this << "SET_EFFECT_CHAIN_PARAMETERS" << "enabled" << message.SetEffectChainParameters.enabled - << "mix" << message.SetEffectChainParameters.mix; + << "mix" << message.SetEffectChainParameters.mix + << "mix_mode" << static_cast(message.SetEffectChainParameters.mix_mode); } response.success = updateParameters(message); break; diff --git a/src/engine/effects/engineeffectchain.h b/src/engine/effects/engineeffectchain.h index 51b971ffa70..1908c9f9628 100644 --- a/src/engine/effects/engineeffectchain.h +++ b/src/engine/effects/engineeffectchain.h @@ -12,7 +12,6 @@ #include "engine/channelhandle.h" #include "engine/effects/message.h" #include "engine/effects/groupfeaturestate.h" -#include "effects/effectchain.h" class EngineEffect; diff --git a/src/engine/effects/engineeffectrack.cpp b/src/engine/effects/engineeffectrack.cpp deleted file mode 100644 index e9e648b6113..00000000000 --- a/src/engine/effects/engineeffectrack.cpp +++ /dev/null @@ -1,140 +0,0 @@ -#include "engine/effects/engineeffectrack.h" -#include "engine/effects/engineeffectchain.h" -#include "util/defs.h" -#include "util/sample.h" - -EngineEffectRack::EngineEffectRack(int iRackNumber) - : m_iRackNumber(iRackNumber), - m_buffer1(MAX_BUFFER_LEN), - m_buffer2(MAX_BUFFER_LEN) { - // Try to prevent memory allocation. - m_chains.reserve(256); -} - -EngineEffectRack::~EngineEffectRack() { - //qDebug() << "EngineEffectRack::~EngineEffectRack()" << this; -} - -bool EngineEffectRack::processEffectsRequest(EffectsRequest& message, - EffectsResponsePipe* pResponsePipe) { - EffectsResponse response(message); - switch (message.type) { - case EffectsRequest::ADD_CHAIN_TO_RACK: - if (kEffectDebugOutput) { - qDebug() << debugString() << "ADD_CHAIN_TO_RACK" - << message.AddChainToRack.pChain - << message.AddChainToRack.iIndex; - } - response.success = addEffectChain(message.AddChainToRack.pChain, - message.AddChainToRack.iIndex); - break; - case EffectsRequest::REMOVE_CHAIN_FROM_RACK: - if (kEffectDebugOutput) { - qDebug() << debugString() << "REMOVE_CHAIN_FROM_RACK" - << message.RemoveChainFromRack.pChain - << message.RemoveChainFromRack.iIndex; - } - response.success = removeEffectChain(message.RemoveChainFromRack.pChain, - message.RemoveChainFromRack.iIndex); - break; - default: - return false; - } - pResponsePipe->writeMessages(&response, 1); - return true; -} - -bool EngineEffectRack::process(const ChannelHandle& inputHandle, - const ChannelHandle& outputHandle, - CSAMPLE* pIn, CSAMPLE* pOut, - const unsigned int numSamples, - const unsigned int sampleRate, - const GroupFeatureState& groupFeatures) { - bool processingOccured = false; - if (pIn == pOut) { - // Effects are applied to the buffer in place - for (EngineEffectChain* pChain : m_chains) { - if (pChain != nullptr) { - if (pChain->process(inputHandle, outputHandle, - pIn, pOut, - numSamples, sampleRate, groupFeatures)) { - processingOccured = true; - } - } - } - } else { - // Do not modify the input buffer; only fill the output buffer. - CSAMPLE* pIntermediateInput = pIn; - CSAMPLE* pIntermediateOutput; - - for (EngineEffectChain* pChain : m_chains) { - if (pChain != nullptr) { - // Select an unused intermediate buffer for the next output - if (pIntermediateInput == m_buffer1.data()) { - pIntermediateOutput = m_buffer2.data(); - } else { - pIntermediateOutput = m_buffer1.data(); - } - - if (pChain->process(inputHandle, outputHandle, - pIntermediateInput, pIntermediateOutput, - numSamples, sampleRate, groupFeatures)) { - processingOccured = true; - // Output of this chain becomes the input of the next chain. - pIntermediateInput = pIntermediateOutput; - } - } - } - // pIntermediateInput is the output of the last processed chain. It would be the - // intermediate input of the next chain if there was one. - if (processingOccured) { - SampleUtil::copy(pOut, pIntermediateInput, numSamples); - } - } - return processingOccured; -} - -bool EngineEffectRack::addEffectChain(EngineEffectChain* pChain, int iIndex) { - if (iIndex < 0) { - if (kEffectDebugOutput) { - qDebug() << debugString() - << "WARNING: ADD_CHAIN_TO_RACK message with invalid index:" - << iIndex; - } - return false; - } - if (m_chains.contains(pChain)) { - if (kEffectDebugOutput) { - qDebug() << debugString() << "WARNING: chain already added to EngineEffectRack:" - << pChain->id(); - } - return false; - } - while (iIndex >= m_chains.size()) { - m_chains.append(NULL); - } - m_chains.replace(iIndex, pChain); - return true; -} - -bool EngineEffectRack::removeEffectChain(EngineEffectChain* pChain, int iIndex) { - VERIFY_OR_DEBUG_ASSERT(iIndex < m_chains.size()) { - if (kEffectDebugOutput) { - qDebug() << debugString() - << "WARNING: REMOVE_CHAIN_FROM_RACK message with invalid index:" - << iIndex; - } - return false; - } - - if (m_chains.at(iIndex) != pChain) { - qDebug() << debugString() - << "WARNING: REMOVE_CHAIN_FROM_RACK consistency error" - << m_chains.at(iIndex) << "loaded but received request to remove" - << pChain; - return false; - } - - m_chains.replace(iIndex, NULL); - return true; -} diff --git a/src/engine/effects/engineeffectrack.h b/src/engine/effects/engineeffectrack.h deleted file mode 100644 index 1ff4d542522..00000000000 --- a/src/engine/effects/engineeffectrack.h +++ /dev/null @@ -1,51 +0,0 @@ -#ifndef ENGINEEFFECTRACK_H -#define ENGINEEFFECTRACK_H - -#include - -#include "engine/channelhandle.h" -#include "engine/effects/message.h" -#include "engine/effects/groupfeaturestate.h" -#include "util/samplebuffer.h" - -class EngineEffectChain; - -//TODO(Be): Remove this superfluous class. -class EngineEffectRack : public EffectsRequestHandler { - public: - EngineEffectRack(int iRackNumber); - virtual ~EngineEffectRack(); - - bool processEffectsRequest( - EffectsRequest& message, - EffectsResponsePipe* pResponsePipe); - - bool process(const ChannelHandle& inputHandle, - const ChannelHandle& outputHandle, - CSAMPLE* pIn, CSAMPLE* pOut, - const unsigned int numSamples, - const unsigned int sampleRate, - const GroupFeatureState& groupFeatures); - - int number() const { - return m_iRackNumber; - } - - private: - bool addEffectChain(EngineEffectChain* pChain, int iIndex); - bool removeEffectChain(EngineEffectChain* pChain, int iIndex); - - QString debugString() const { - return QString("EngineEffectRack%1").arg(m_iRackNumber); - } - - int m_iRackNumber; - QList m_chains; - - mixxx::SampleBuffer m_buffer1; - mixxx::SampleBuffer m_buffer2; - - DISALLOW_COPY_AND_ASSIGN(EngineEffectRack); -}; - -#endif /* ENGINEEFFECTRACK_H */ diff --git a/src/engine/effects/engineeffectsmanager.cpp b/src/engine/effects/engineeffectsmanager.cpp index 0e07c662776..92fa9b5b74b 100644 --- a/src/engine/effects/engineeffectsmanager.cpp +++ b/src/engine/effects/engineeffectsmanager.cpp @@ -1,6 +1,5 @@ #include "engine/effects/engineeffectsmanager.h" -#include "engine/effects/engineeffectrack.h" #include "engine/effects/engineeffectchain.h" #include "engine/effects/engineeffect.h" @@ -12,7 +11,6 @@ EngineEffectsManager::EngineEffectsManager(EffectsResponsePipe* pResponsePipe) m_buffer1(MAX_BUFFER_LEN), m_buffer2(MAX_BUFFER_LEN) { // Try to prevent memory allocation. - m_chains.reserve(256); m_effects.reserve(256); } @@ -25,52 +23,31 @@ void EngineEffectsManager::onCallbackStart() { EffectsResponse response(*request); bool processed = false; switch (request->type) { - case EffectsRequest::ADD_EFFECT_RACK: - case EffectsRequest::REMOVE_EFFECT_RACK: + case EffectsRequest::ADD_EFFECT_CHAIN: + case EffectsRequest::REMOVE_EFFECT_CHAIN: if (processEffectsRequest(*request, m_pResponsePipe.data())) { processed = true; } break; - case EffectsRequest::ADD_CHAIN_TO_RACK: - case EffectsRequest::REMOVE_CHAIN_FROM_RACK: - VERIFY_OR_DEBUG_ASSERT(request->pTargetRack) { - response.success = false; - response.status = EffectsResponse::NO_SUCH_RACK; - break; - } - - processed = request->pTargetRack->processEffectsRequest( - *request, m_pResponsePipe.data()); - - if (processed) { - // When an effect-chain becomes active (part of a rack), keep - // it in our master list so that we can respond to - // requests about it. - if (request->type == EffectsRequest::ADD_CHAIN_TO_RACK) { - m_chains.append(request->AddChainToRack.pChain); - } else if (request->type == EffectsRequest::REMOVE_CHAIN_FROM_RACK) { - m_chains.removeAll(request->RemoveChainFromRack.pChain); - } - } else { - if (!processed) { - // If we got here, the message was not handled for - // an unknown reason. - response.success = false; - response.status = EffectsResponse::INVALID_REQUEST; - } - } - break; case EffectsRequest::ADD_EFFECT_TO_CHAIN: case EffectsRequest::REMOVE_EFFECT_FROM_CHAIN: case EffectsRequest::SET_EFFECT_CHAIN_PARAMETERS: case EffectsRequest::ENABLE_EFFECT_CHAIN_FOR_INPUT_CHANNEL: case EffectsRequest::DISABLE_EFFECT_CHAIN_FOR_INPUT_CHANNEL: - VERIFY_OR_DEBUG_ASSERT(m_chains.contains(request->pTargetChain)) { - response.success = false; - response.status = EffectsResponse::NO_SUCH_CHAIN; - break; - } + { + bool chainExists = false; + for (auto &chains : m_chainsByStage) { + if (chains.contains(request->pTargetChain)) { + chainExists = true; + } + } + VERIFY_OR_DEBUG_ASSERT(chainExists) { + response.success = false; + response.status = EffectsResponse::NO_SUCH_CHAIN; + break; + } + } processed = request->pTargetChain->processEffectsRequest( *request, m_pResponsePipe.data()); if (processed) { @@ -126,9 +103,9 @@ void EngineEffectsManager::processPreFaderInPlace(const ChannelHandle& inputHand const unsigned int sampleRate) { // Feature state is gathered after prefader effects processing. // This is okay because the equalizer and filter effects do not make use of it. - // However, if an effect is loaded into a QuickEffectRack that could make use + // However, if an effect is loaded into a QuickEffectChainSlot that could make use // of the GroupFeatureState, it will not sound the same as if it is loaded into - // a StandardEffectRack. + // a StandardEffectChainSlot. GroupFeatureState featureState; processInner(SignalProcessingStage::Prefader, inputHandle, outputHandle, @@ -179,16 +156,20 @@ void EngineEffectsManager::processInner( const CSAMPLE_GAIN oldGain, const CSAMPLE_GAIN newGain) { - const QList& racks = m_racksByStage.value(stage); + const QList& chains = m_chainsByStage.value(stage); + + bool processingOccured = false; if (pIn == pOut) { // Gain and effects are applied to the buffer in place, // modifying the original input buffer SampleUtil::applyRampingGain(pIn, oldGain, newGain, numSamples); - for (EngineEffectRack* pRack : racks) { - if (pRack != nullptr) { - pRack->process(inputHandle, outputHandle, - pIn, pIn, - numSamples, sampleRate, groupFeatures); + for (EngineEffectChain* pChain : chains) { + if (pChain != nullptr) { + if (pChain->process(inputHandle, outputHandle, + pIn, pOut, + numSamples, sampleRate, groupFeatures)) { + processingOccured = true; + } } } } else { @@ -201,7 +182,7 @@ void EngineEffectsManager::processInner( // this to mix channels into pOut regardless of whether any effects were processed. CSAMPLE* pIntermediateInput = m_buffer1.data(); if (oldGain == CSAMPLE_GAIN_ONE && newGain == CSAMPLE_GAIN_ONE) { - // Avoid an unnecessary copy. EngineEffectRack::process does not modify the + // Avoid an unnecessary copy. EngineEffectChain::process does not modify the // input buffer when its input & output buffers are different, so this is okay. pIntermediateInput = pIn; } else { @@ -210,8 +191,8 @@ void EngineEffectsManager::processInner( } CSAMPLE* pIntermediateOutput; - for (EngineEffectRack* pRack : racks) { - if (pRack != nullptr) { + for (EngineEffectChain* pChain : chains) { + if (pChain != nullptr) { // Select an unused intermediate buffer for the next output if (pIntermediateInput == m_buffer1.data()) { pIntermediateOutput = m_buffer2.data(); @@ -219,58 +200,64 @@ void EngineEffectsManager::processInner( pIntermediateOutput = m_buffer1.data(); } - if (pRack->process(inputHandle, outputHandle, - pIntermediateInput, pIntermediateOutput, - numSamples, sampleRate, groupFeatures)) { - // Output of this rack becomes the input of the next rack. + if (pChain->process(inputHandle, outputHandle, + pIntermediateInput, pIntermediateOutput, + numSamples, sampleRate, groupFeatures)) { + processingOccured = true; + // Output of this chain becomes the input of the next chain. pIntermediateInput = pIntermediateOutput; } } } - // pIntermediateInput is the output of the last processed rack. It would be the - // intermediate input of the next rack if there was one. - SampleUtil::add(pOut, pIntermediateInput, numSamples); + + // NOTE(Kshitij) : Check if we are required to add or copy the input samples to pOut + + // pIntermediateInput is the output of the last processed chain. It would be the + // intermediate input of the next chain if there was one. + if (processingOccured) { + SampleUtil::copy(pOut, pIntermediateInput, numSamples); + } } } -bool EngineEffectsManager::addEffectRack(EngineEffectRack* pRack, +bool EngineEffectsManager::addEffectChain(EngineEffectChain* pChain, SignalProcessingStage stage) { - QList& rackList = m_racksByStage[stage]; - VERIFY_OR_DEBUG_ASSERT(!rackList.contains(pRack)) { + QList& chains = m_chainsByStage[stage]; + VERIFY_OR_DEBUG_ASSERT(!chains.contains(pChain)) { return false; } - rackList.append(pRack); + chains.append(pChain); return true; } -bool EngineEffectsManager::removeEffectRack(EngineEffectRack* pRack, +bool EngineEffectsManager::removeEffectChain(EngineEffectChain* pChain, SignalProcessingStage stage) { - QList& rackList = m_racksByStage[stage]; - VERIFY_OR_DEBUG_ASSERT(rackList.contains(pRack)) { + QList& chains = m_chainsByStage[stage]; + VERIFY_OR_DEBUG_ASSERT(chains.contains(pChain)) { return false; } - return rackList.removeAll(pRack) > 0; + return chains.removeAll(pChain) > 0; } bool EngineEffectsManager::processEffectsRequest(EffectsRequest& message, EffectsResponsePipe* pResponsePipe) { EffectsResponse response(message); switch (message.type) { - case EffectsRequest::ADD_EFFECT_RACK: + case EffectsRequest::ADD_EFFECT_CHAIN: if (kEffectDebugOutput) { - qDebug() << debugString() << "ADD_EFFECT_RACK" - << message.AddEffectRack.pRack; + qDebug() << debugString() << "ADD_EFFECT_CHAIN" + << message.AddEffectChain.pChain; } - response.success = addEffectRack(message.AddEffectRack.pRack, - message.AddEffectRack.signalProcessingStage); + response.success = addEffectChain(message.AddEffectChain.pChain, + message.AddEffectChain.signalProcessingStage); break; - case EffectsRequest::REMOVE_EFFECT_RACK: + case EffectsRequest::REMOVE_EFFECT_CHAIN: if (kEffectDebugOutput) { - qDebug() << debugString() << "REMOVE_EFFECT_RACK" - << message.RemoveEffectRack.pRack; + qDebug() << debugString() << "REMOVE_EFFECT_CHAIN" + << message.RemoveEffectChain.pChain; } - response.success = removeEffectRack(message.AddEffectRack.pRack, - message.AddEffectRack.signalProcessingStage); + response.success = removeEffectChain(message.RemoveEffectChain.pChain, + message.RemoveEffectChain.signalProcessingStage); break; default: return false; diff --git a/src/engine/effects/engineeffectsmanager.h b/src/engine/effects/engineeffectsmanager.h index d40406c281d..c7c754d161c 100644 --- a/src/engine/effects/engineeffectsmanager.h +++ b/src/engine/effects/engineeffectsmanager.h @@ -10,7 +10,6 @@ #include "engine/effects/groupfeaturestate.h" #include "engine/channelhandle.h" -class EngineEffectRack; class EngineEffectChain; class EngineEffect; @@ -64,14 +63,8 @@ class EngineEffectsManager : public EffectsRequestHandler { return QString("EngineEffectsManager"); } - bool addEffectRack(EngineEffectRack* pRack, SignalProcessingStage stage); - bool removeEffectRack(EngineEffectRack* pRack, SignalProcessingStage stage); - - bool addPreFaderEffectRack(EngineEffectRack* pRack); - bool removePreFaderEffectRack(EngineEffectRack* pRack); - - bool addPostFaderEffectRack(EngineEffectRack* pRack); - bool removePostFaderEffectRack(EngineEffectRack* pRack); + bool addEffectChain(EngineEffectChain* pChain, SignalProcessingStage stage); + bool removeEffectChain(EngineEffectChain* pChain, SignalProcessingStage stage); void processInner(const SignalProcessingStage stage, const ChannelHandle& inputHandle, @@ -84,8 +77,7 @@ class EngineEffectsManager : public EffectsRequestHandler { const CSAMPLE_GAIN newGain = CSAMPLE_GAIN_ONE); QScopedPointer m_pResponsePipe; - QHash> m_racksByStage; - QList m_chains; + QHash> m_chainsByStage; QList m_effects; mixxx::SampleBuffer m_buffer1; diff --git a/src/engine/effects/message.h b/src/engine/effects/message.h index 08a974ebe5d..e340c7fc333 100644 --- a/src/engine/effects/message.h +++ b/src/engine/effects/message.h @@ -10,21 +10,14 @@ #include "effects/defs.h" #include "engine/channelhandle.h" -class EngineEffectRack; class EngineEffectChain; class EngineEffect; struct EffectsRequest { enum MessageType { - // Messages for EngineEffectsManager - ADD_EFFECT_RACK = 0, - REMOVE_EFFECT_RACK, - - // Messages for EngineEffectRack - ADD_CHAIN_TO_RACK, - REMOVE_CHAIN_FROM_RACK, - // Messages for EngineEffectChain + ADD_EFFECT_CHAIN, + REMOVE_EFFECT_CHAIN, SET_EFFECT_CHAIN_PARAMETERS, ADD_EFFECT_TO_CHAIN, REMOVE_EFFECT_FROM_CHAIN, @@ -48,14 +41,11 @@ struct EffectsRequest { maximum(0.0), default_value(0.0), value(0.0) { - pTargetRack = nullptr; pTargetChain = nullptr; pTargetEffect = nullptr; #define CLEAR_STRUCT(x) memset(&x, 0, sizeof(x)); - CLEAR_STRUCT(AddEffectRack); - CLEAR_STRUCT(RemoveEffectRack); - CLEAR_STRUCT(AddChainToRack); - CLEAR_STRUCT(RemoveChainFromRack); + CLEAR_STRUCT(AddEffectChain); + CLEAR_STRUCT(RemoveEffectChain); CLEAR_STRUCT(EnableInputChannelForChain); CLEAR_STRUCT(DisableInputChannelForChain); CLEAR_STRUCT(AddEffectToChain); @@ -85,10 +75,6 @@ struct EffectsRequest { // Target of the message. union { - // Used by: - // - ADD_CHAIN_TO_RACK - // - REMOVE_CHAIN_FROM_RACK - EngineEffectRack* pTargetRack; // Used by: // - ADD_EFFECT_TO_CHAIN // - REMOVE_EFFECT_FROM_CHAIN @@ -103,22 +89,15 @@ struct EffectsRequest { // Message-specific data. union { - struct { - EngineEffectRack* pRack; - SignalProcessingStage signalProcessingStage; - } AddEffectRack; - struct { - EngineEffectRack* pRack; - SignalProcessingStage signalProcessingStage; - } RemoveEffectRack; struct { EngineEffectChain* pChain; - int iIndex; - } AddChainToRack; + SignalProcessingStage signalProcessingStage; + } AddEffectChain; struct { EngineEffectChain* pChain; int iIndex; - } RemoveChainFromRack; + SignalProcessingStage signalProcessingStage; + } RemoveEffectChain; struct { EffectStatesMapArray* pEffectStatesMapArray; const ChannelHandle* pChannelHandle; @@ -158,7 +137,6 @@ struct EffectsResponse { enum StatusCode { OK, UNHANDLED_MESSAGE_TYPE, - NO_SUCH_RACK, NO_SUCH_CHAIN, NO_SUCH_EFFECT, NO_SUCH_PARAMETER, diff --git a/src/mixer/playermanager.cpp b/src/mixer/playermanager.cpp index 4d95dd9bc7c..4022f8a0fb8 100644 --- a/src/mixer/playermanager.cpp +++ b/src/mixer/playermanager.cpp @@ -7,7 +7,6 @@ #include "control/controlobject.h" #include "control/controlobject.h" #include "effects/effectsmanager.h" -#include "effects/effectrack.h" #include "engine/channels/enginedeck.h" #include "engine/enginemaster.h" #include "library/library.h" @@ -391,11 +390,7 @@ void PlayerManager::addDeckInner() { AudioInput(AudioInput::VINYLCONTROL, 0, 2, number - 1), pEngineDeck); // Setup equalizer rack for this deck. - EqualizerRackPointer pEqRack = m_pEffectsManager->getEqualizerRack(0); - VERIFY_OR_DEBUG_ASSERT(pEqRack) { - return; - } - pEqRack->setupForGroup(group); + m_pEffectsManager->addEqualizerEffectChainSlot(group); // BaseTrackPlayer needs to delay until we have setup the equalizer rack for // this deck to fetch the legacy EQ controls. @@ -403,11 +398,7 @@ void PlayerManager::addDeckInner() { pDeck->setupEqControls(); // Setup quick effect rack for this deck. - QuickEffectRackPointer pQuickEffectRack = m_pEffectsManager->getQuickEffectRack(0); - VERIFY_OR_DEBUG_ASSERT(pQuickEffectRack) { - return; - } - pQuickEffectRack->setupForGroup(group); + m_pEffectsManager->addQuickEffectChainSlot(group); } void PlayerManager::loadSamplers() { diff --git a/src/mixxx.cpp b/src/mixxx.cpp index 4debd9be332..9095cac7ab9 100644 --- a/src/mixxx.cpp +++ b/src/mixxx.cpp @@ -244,18 +244,15 @@ void MixxxMainWindow::initialize(QApplication* pApp, const CmdlineArgs& args) { // Create effect backends. We do this after creating EngineMaster to allow // effect backends to refer to controls that are produced by the engine. - BuiltInBackend* pBuiltInBackend = new BuiltInBackend(m_pEffectsManager); - m_pEffectsManager->addEffectsBackend(pBuiltInBackend); + BuiltInBackend* pBuiltInBackend = new BuiltInBackend(); + m_pEffectsManager->addEffectsBackend(EffectsBackendPointer(pBuiltInBackend)); #ifdef __LILV__ - LV2Backend* pLV2Backend = new LV2Backend(m_pEffectsManager); - m_pEffectsManager->addEffectsBackend(pLV2Backend); + LV2Backend* pLV2Backend = new LV2Backend(); + m_pEffectsManager->addEffectsBackend(EffectsBackendPointer(pLV2Backend)); #else LV2Backend* pLV2Backend = nullptr; #endif - // Sets up the EffectChains and EffectRacks (long) - m_pEffectsManager->setup(); - launchProgress(8); // Although m_pSoundManager is created here, m_pSoundManager->setupDevices() @@ -310,7 +307,7 @@ void MixxxMainWindow::initialize(QApplication* pApp, const CmdlineArgs& args) { launchProgress(30); - m_pEffectsManager->loadEffectChains(); + m_pEffectsManager->setup(); #ifdef __VINYLCONTROL__ m_pVCManager->init(); diff --git a/src/preferences/dialog/dlgprefeffects.cpp b/src/preferences/dialog/dlgprefeffects.cpp index 8af7c85de41..1f9797cab88 100644 --- a/src/preferences/dialog/dlgprefeffects.cpp +++ b/src/preferences/dialog/dlgprefeffects.cpp @@ -86,10 +86,10 @@ void DlgPrefEffects::clear() { void DlgPrefEffects::availableEffectsListItemSelected(const QModelIndex& selected) { QString effectId = m_availableEffectsModel.data(selected, Qt::UserRole).toString(); - EffectManifestPointer pManifest = m_pEffectsManager->getEffectManifest(effectId); - if (!pManifest) { + if (effectId == QVariant().toString()) return; - } + + EffectManifestPointer pManifest = m_pEffectsManager->getManifestFromUniqueId(effectId); effectName->setText(pManifest->name()); effectAuthor->setText(pManifest->author()); diff --git a/src/preferences/dialog/dlgprefeq.cpp b/src/preferences/dialog/dlgprefeq.cpp index 90ad1c0107a..5cf13d42304 100644 --- a/src/preferences/dialog/dlgprefeq.cpp +++ b/src/preferences/dialog/dlgprefeq.cpp @@ -28,15 +28,15 @@ #include "control/controlproxy.h" #include "util/math.h" #include "mixer/playermanager.h" -#include "effects/effectrack.h" +#include "effects/specialeffectchainslots.h" const QString kConfigKey = "[Mixer Profile]"; const QString kEnableEqs = "EnableEQs"; const QString kEqsOnly = "EQsOnly"; const QString kSingleEq = "SingleEQEffect"; -const QString kDefaultEqId = BiquadFullKillEQEffect::getId(); +const QString kDefaultEqId = BiquadFullKillEQEffect::getId() + " Built-in"; const QString kDefaultMasterEqId = QString(); -const QString kDefaultQuickEffectId = FilterEffect::getId(); +const QString kDefaultQuickEffectId = FilterEffect::getId() + " Built-in"; const int kFrequencyUpperLimit = 20050; const int kFrequencyLowerLimit = 16; @@ -55,10 +55,6 @@ DlgPrefEQ::DlgPrefEQ(QWidget* pParent, EffectsManager* pEffectsManager, m_inSlotPopulateDeckEffectSelectors(false), m_bEqAutoReset(false), m_bGainAutoReset(false) { - m_pEQEffectRack = m_pEffectsManager->getEqualizerRack(0); - m_pQuickEffectRack = m_pEffectsManager->getQuickEffectRack(0); - m_pOutputEffectRack = m_pEffectsManager->getOutputsEffectRack(); - setupUi(this); // Connection connect(SliderHiEQ, SIGNAL(valueChanged(int)), this, SLOT(slotUpdateHiEQ())); @@ -98,9 +94,6 @@ DlgPrefEQ::~DlgPrefEQ() { qDeleteAll(m_deckQuickEffectSelectors); m_deckQuickEffectSelectors.clear(); - - qDeleteAll(m_filterWaveformEnableCOs); - m_filterWaveformEnableCOs.clear(); } void DlgPrefEQ::slotNumDecksChanged(double numDecks) { @@ -114,21 +107,17 @@ void DlgPrefEQ::slotNumDecksChanged(double numDecks) { QString group = PlayerManager::groupForDeck( m_deckEqEffectSelectors.size()); - m_filterWaveformEnableCOs.append( - new ControlObject(ConfigKey(group, "filterWaveformEnable"))); - m_filterWaveformEffectLoaded.append(false); - // Create the drop down list for EQs QComboBox* eqComboBox = new QComboBox(this); m_deckEqEffectSelectors.append(eqComboBox); connect(eqComboBox, SIGNAL(currentIndexChanged(int)), - this, SLOT(slotEqEffectChangedOnDeck(int))); + this, SLOT(slotEffectChangedOnDeck(int))); // Create the drop down list for EQs QComboBox* quickEffectComboBox = new QComboBox(this); m_deckQuickEffectSelectors.append(quickEffectComboBox); connect(quickEffectComboBox, SIGNAL(currentIndexChanged(int)), - this, SLOT(slotQuickEffectChangedOnDeck(int))); + this, SLOT(slotEffectChangedOnDeck(int))); if (deckNo == 1) { m_firstSelectorLabel = label; @@ -147,30 +136,38 @@ void DlgPrefEQ::slotNumDecksChanged(double numDecks) { } slotPopulateDeckEffectSelectors(); for (int i = oldDecks; i < static_cast(numDecks); ++i) { - // Set the configured effect for box and simpleBox or Bessel8 LV-Mix EQ + // Set the configured effect for box and simpleBox or default // if none is configured QString group = PlayerManager::groupForDeck(i); QString configuredEffect = m_pConfig->getValue(ConfigKey(kConfigKey, "EffectForGroup_" + group), kDefaultEqId); - int selectedEffectIndex = m_deckEqEffectSelectors[i]->findData(configuredEffect); - if (selectedEffectIndex < 0) { - selectedEffectIndex = m_deckEqEffectSelectors[i]->findData(kDefaultEqId); - configuredEffect = kDefaultEqId; + + const EffectManifestPointer pEQManifest = + m_pEffectsManager->getManifestFromUniqueId(configuredEffect); + + int selectedEQEffectIndex = 0; + if (pEQManifest) { + selectedEQEffectIndex = m_deckEqEffectSelectors[i]->findData( + QVariant(pEQManifest->uniqueId())); + } else { + // Select "None" + selectedEQEffectIndex = m_deckEqEffectSelectors[i]->count() - 1; } - m_deckEqEffectSelectors[i]->setCurrentIndex(selectedEffectIndex); - m_filterWaveformEffectLoaded[i] = m_pEffectsManager->isEQ(configuredEffect); - m_filterWaveformEnableCOs[i]->set( - m_filterWaveformEffectLoaded[i] && - !CheckBoxBypass->checkState()); + + m_deckEqEffectSelectors[i]->setCurrentIndex(selectedEQEffectIndex); QString configuredQuickEffect = m_pConfig->getValue(ConfigKey(kConfigKey, "QuickEffectForGroup_" + group), kDefaultQuickEffectId); - int selectedQuickEffectIndex = - m_deckQuickEffectSelectors[i]->findData(configuredQuickEffect); - if (selectedQuickEffectIndex < 0) { - selectedQuickEffectIndex = - m_deckEqEffectSelectors[i]->findData(kDefaultQuickEffectId); - configuredEffect = kDefaultQuickEffectId; + const EffectManifestPointer pQuickEffectManifest = + m_pEffectsManager->getManifestFromUniqueId(configuredQuickEffect); + + int selectedQuickEffectIndex = 0; + if (pQuickEffectManifest) { + selectedQuickEffectIndex = m_deckQuickEffectSelectors[i]->findData( + QVariant(pQuickEffectManifest->uniqueId())); + } else { + // Select "None" + selectedQuickEffectIndex = m_deckQuickEffectSelectors[i]->count() - 1; } m_deckQuickEffectSelectors[i]->setCurrentIndex(selectedQuickEffectIndex); } @@ -208,80 +205,62 @@ void DlgPrefEQ::slotPopulateDeckEffectSelectors() { filterEQ = nullptr; // take all } - const QList availableEQEffects = - m_pEffectsManager->getAvailableEffectManifestsFiltered(filterEQ); - const QList availableQuickEffects = - m_pEffectsManager->getAvailableEffectManifestsFiltered(hasSuperKnobLinking); + populateDeckBoxList(m_deckEqEffectSelectors, filterEQ); + populateDeckBoxList(m_deckQuickEffectSelectors, hasSuperKnobLinking); - for (QComboBox* box : m_deckEqEffectSelectors) { - // Populate comboboxes with all available effects - // Save current selection - QString selectedEffectId = box->itemData(box->currentIndex()).toString(); - QString selectedEffectName = box->itemText(box->currentIndex()); - box->clear(); - int currentIndex = -1; // Nothing selected - - int i; - for (i = 0; i < availableEQEffects.size(); ++i) { - EffectManifestPointer pManifest = availableEQEffects.at(i); - box->addItem(pManifest->name(), QVariant(pManifest->id())); - if (selectedEffectId == pManifest->id()) { - currentIndex = i; - } - } - //: Displayed when no effect is selected - box->addItem(tr("None"), QVariant(QString(""))); - if (selectedEffectId.isNull()) { - currentIndex = availableEQEffects.size(); // selects "None" - } - if (currentIndex < 0 && !selectedEffectName.isEmpty()) { - // current selection is not part of the new list - // So we need to add it - box->addItem(selectedEffectName, QVariant(selectedEffectId)); - currentIndex = i + 1; - } - box->setCurrentIndex(currentIndex); - } + m_inSlotPopulateDeckEffectSelectors = false; +} - for (QComboBox* box : m_deckQuickEffectSelectors) { +void DlgPrefEQ::populateDeckBoxList( + const QList boxList, + EffectsManager::EffectManifestFilterFnc filterFunc) { + const QList pManifestList = + m_pEffectsManager->getAvailableEffectManifestsFiltered(filterFunc); + for (QComboBox* box : boxList) { // Populate comboboxes with all available effects // Save current selection - QString selectedEffectId = box->itemData(box->currentIndex()).toString(); - QString selectedEffectName = box->itemText(box->currentIndex()); + const EffectManifestPointer pCurrentlySelectedManifest = + m_pEffectsManager->getManifestFromUniqueId( + box->itemData(box->currentIndex()).toString()); + box->clear(); - int currentIndex = -1;// Nothing selected + int currentIndex = -1; // Nothing selected - int i; - for (i = 0; i < availableQuickEffects.size(); ++i) { - EffectManifestPointer pManifest = availableQuickEffects.at(i); - box->addItem(pManifest->name(), QVariant(pManifest->id())); - if (selectedEffectId == pManifest->id()) { + int i = 0; + for (const auto& pManifest : pManifestList) { + box->addItem(pManifest->name(), QVariant(pManifest->uniqueId())); + if (pCurrentlySelectedManifest && + pCurrentlySelectedManifest.data() == pManifest.data()) { currentIndex = i; } + ++i; } //: Displayed when no effect is selected - box->addItem(tr("None"), QVariant(QString(""))); - if (selectedEffectId.isNull()) { - currentIndex = availableQuickEffects.size(); // selects "None" + box->addItem(tr("None"), QVariant()); + if (pCurrentlySelectedManifest == nullptr) { + currentIndex = box->count() - 1; // selects "None" } - if (currentIndex < 0 && !selectedEffectName.isEmpty()) { + if (currentIndex < 0) { // current selection is not part of the new list // So we need to add it - box->addItem(selectedEffectName, QVariant(selectedEffectId)); + box->addItem(pCurrentlySelectedManifest->shortName(), + QVariant(pCurrentlySelectedManifest->uniqueId())); currentIndex = i + 1; } box->setCurrentIndex(currentIndex); } - - m_inSlotPopulateDeckEffectSelectors = false; } void DlgPrefEQ::slotSingleEqChecked(int checked) { bool do_hide = static_cast(checked); m_pConfig->set(ConfigKey(kConfigKey, kSingleEq), do_hide ? QString("yes") : QString("no")); + int deck1EQIndex = m_deckEqEffectSelectors.at(0)->currentIndex(); + int deck1QuickEffectIndex = m_deckQuickEffectSelectors.at(0)->currentIndex(); for (int i = 2; i < m_deckEqEffectSelectors.size() + 1; ++i) { if (do_hide) { + m_deckEqEffectSelectors.at(i-1)->setCurrentIndex(deck1EQIndex); + m_deckQuickEffectSelectors.at(i-1)->setCurrentIndex(deck1QuickEffectIndex); gridLayout_3->itemAtPosition(i, 0)->widget()->hide(); gridLayout_3->itemAtPosition(i, 1)->widget()->hide(); gridLayout_3->itemAtPosition(i, 2)->widget()->hide(); @@ -352,8 +331,7 @@ void DlgPrefEQ::loadSettings() { } } -void DlgPrefEQ::setDefaultShelves() -{ +void DlgPrefEQ::setDefaultShelves() { m_pConfig->set(ConfigKey(kConfigKey, "HiEQFrequency"), ConfigValue(2500)); m_pConfig->set(ConfigKey(kConfigKey, "LoEQFrequency"), ConfigValue(250)); m_pConfig->set(ConfigKey(kConfigKey, "HiEQFrequencyPrecise"), ConfigValue(2500.0)); @@ -363,11 +341,11 @@ void DlgPrefEQ::setDefaultShelves() void DlgPrefEQ::slotResetToDefaults() { slotMasterEQToDefault(); setDefaultShelves(); - foreach(QComboBox* pCombo, m_deckEqEffectSelectors) { + for (QComboBox* pCombo : m_deckEqEffectSelectors) { pCombo->setCurrentIndex( pCombo->findData(kDefaultEqId)); } - foreach(QComboBox* pCombo, m_deckQuickEffectSelectors) { + for (QComboBox* pCombo : m_deckQuickEffectSelectors) { pCombo->setCurrentIndex( pCombo->findData(kDefaultQuickEffectId)); } @@ -383,52 +361,33 @@ void DlgPrefEQ::slotResetToDefaults() { slotApply(); } -void DlgPrefEQ::slotEqEffectChangedOnDeck(int effectIndex) { +void DlgPrefEQ::slotEffectChangedOnDeck(int effectIndex) { QComboBox* c = qobject_cast(sender()); // Check if qobject_cast was successful - if (c && !m_inSlotPopulateDeckEffectSelectors) { - int deckNumber = m_deckEqEffectSelectors.indexOf(c); - QString effectId = c->itemData(effectIndex).toString(); - - // If we are in single-effect mode and the first effect was changed, - // change the others as well. - if (deckNumber == 0 && CheckBoxSingleEqEffect->isChecked()) { - for (int otherDeck = 1; - otherDeck < static_cast(m_pNumDecks->get()); - ++otherDeck) { - QComboBox* box = m_deckEqEffectSelectors[otherDeck]; - box->setCurrentIndex(effectIndex); - } - } + if (!c || m_inSlotPopulateDeckEffectSelectors) { + return; + } - // This is required to remove a previous selected effect that does not - // fit to the current ShowAllEffects checkbox - slotPopulateDeckEffectSelectors(); + QList* pBoxList = &m_deckEqEffectSelectors; + if (m_deckQuickEffectSelectors.contains(c)) { + pBoxList = &m_deckQuickEffectSelectors; } -} -void DlgPrefEQ::slotQuickEffectChangedOnDeck(int effectIndex) { - QComboBox* c = qobject_cast(sender()); - // Check if qobject_cast was successful - if (c && !m_inSlotPopulateDeckEffectSelectors) { - int deckNumber = m_deckQuickEffectSelectors.indexOf(c); - QString effectId = c->itemData(effectIndex).toString(); - - // If we are in single-effect mode and the first effect was changed, - // change the others as well. - if (deckNumber == 0 && CheckBoxSingleEqEffect->isChecked()) { - for (int otherDeck = 1; - otherDeck < static_cast(m_pNumDecks->get()); - ++otherDeck) { - QComboBox* box = m_deckQuickEffectSelectors[otherDeck]; - box->setCurrentIndex(effectIndex); - } + int deckNumber = pBoxList->indexOf(c); + // If we are in single-effect mode and the first effect was changed, + // change the others as well. + if (deckNumber == 0 && CheckBoxSingleEqEffect->isChecked()) { + for (int otherDeck = 1; + otherDeck < static_cast(m_pNumDecks->get()); + ++otherDeck) { + QComboBox* box = (*pBoxList)[otherDeck]; + box->setCurrentIndex(effectIndex); } - - // This is required to remove a previous selected effect that does not - // fit to the current ShowAllEffects checkbox - slotPopulateDeckEffectSelectors(); } + + // This is required to remove a previous selected effect that does not + // fit to the current ShowAllEffects checkbox + slotPopulateDeckEffectSelectors(); } void DlgPrefEQ::applySelections() { @@ -436,87 +395,49 @@ void DlgPrefEQ::applySelections() { return; } - int deck = 0; - QString firstEffectId; - int firstEffectIndex = 0; - for (QComboBox* box : m_deckEqEffectSelectors) { - QString effectId = box->itemData(box->currentIndex()).toString(); - if (deck == 0) { - firstEffectId = effectId; - firstEffectIndex = box->currentIndex(); - } else if (CheckBoxSingleEqEffect->isChecked()) { - effectId = firstEffectId; - box->setCurrentIndex(firstEffectIndex); - } - QString group = PlayerManager::groupForDeck(deck); + loadEffectFunction loadFunc = std::bind( + &EffectsManager::loadEqualizerEffect, m_pEffectsManager, + std::placeholders::_1, std::placeholders::_2, std::placeholders::_3); + applySelectionsToDecks(m_deckEqEffectSelectors, m_eqIndiciesOnUpdate, + loadFunc, "EffectForGroup_"); - // Only apply the effect if it changed -- so first interrogate the - // loaded effect if any. - bool need_load = true; - if (m_pEQEffectRack->numEffectChainSlots() > deck) { - // It's not correct to get a chainslot by index number -- get by - // group name instead. - EffectChainSlotPointer chainslot = - m_pEQEffectRack->getGroupEffectChainSlot(group); - if (chainslot && chainslot->numSlots()) { - EffectPointer effectpointer = - chainslot->getEffectSlot(0)->getEffect(); - if (effectpointer && - effectpointer->getManifest()->id() == effectId) { - need_load = false; - } - } - } - if (need_load) { - EffectPointer pEffect = m_pEffectsManager->instantiateEffect(effectId); - m_pEQEffectRack->loadEffectToGroup(group, pEffect); - m_pConfig->set(ConfigKey(kConfigKey, "EffectForGroup_" + group), - ConfigValue(effectId)); - m_filterWaveformEnableCOs[deck]->set(m_pEffectsManager->isEQ(effectId)); + loadFunc = std::bind(&EffectsManager::loadQuickEffect, m_pEffectsManager, + std::placeholders::_1, std::placeholders::_2, std::placeholders::_3); + applySelectionsToDecks(m_deckQuickEffectSelectors, m_quickEffectIndiciesOnUpdate, + loadFunc, "QuickEffectForGroup_"); +} - // This is required to remove a previous selected effect that does not - // fit to the current ShowAllEffects checkbox - slotPopulateDeckEffectSelectors(); - } - ++deck; - } +void DlgPrefEQ::applySelectionsToDecks( + const QList& boxList, + QList& indiciesOnUpdate, + loadEffectFunction loadFunc, + const QString& configKeyPrefix) { + int deck = 0; + for (QComboBox* box : boxList) { + const EffectManifestPointer pManifest = + m_pEffectsManager->getManifestFromUniqueId( + box->itemData(box->currentIndex()).toString()); - deck = 0; - for (QComboBox* box : m_deckQuickEffectSelectors) { - QString effectId = box->itemData(box->currentIndex()).toString(); QString group = PlayerManager::groupForDeck(deck); - if (deck == 0) { - firstEffectId = effectId; - firstEffectIndex = box->currentIndex(); - } else if (CheckBoxSingleEqEffect->isChecked()) { - effectId = firstEffectId; - box->setCurrentIndex(firstEffectIndex); + bool needLoad = true; + bool startingUp = (indiciesOnUpdate.size() < (deck + 1)); + if (!startingUp) { + needLoad = (box->currentIndex() != indiciesOnUpdate[deck]); } + if (needLoad) { + loadFunc(group, 0, pManifest); - // Only apply the effect if it changed -- so first interrogate the - // loaded effect if any. - bool need_load = true; - if (m_pQuickEffectRack->numEffectChainSlots() > deck) { - // It's not correct to get a chainslot by index number -- get by - // group name instead. - EffectChainSlotPointer chainslot = - m_pQuickEffectRack->getGroupEffectChainSlot(group); - if (chainslot && chainslot->numSlots()) { - EffectPointer effectpointer = - chainslot->getEffectSlot(0)->getEffect(); - if (effectpointer && - effectpointer->getManifest()->id() == effectId) { - need_load = false; - } + if (!startingUp) { + indiciesOnUpdate[deck] = box->currentIndex(); } - } - if (need_load) { - EffectPointer pEffect = m_pEffectsManager->instantiateEffect(effectId); - m_pQuickEffectRack->loadEffectToGroup(group, pEffect); - m_pConfig->set(ConfigKey(kConfigKey, "QuickEffectForGroup_" + group), - ConfigValue(effectId)); + QString configString; + if (pManifest) { + configString = pManifest->uniqueId(); + } + m_pConfig->set(ConfigKey(kConfigKey, configKeyPrefix + group), + configString); // This is required to remove a previous selected effect that does not // fit to the current ShowAllEffects checkbox @@ -571,14 +492,16 @@ void DlgPrefEQ::slotUpdateLoEQ() { } void DlgPrefEQ::slotUpdateMasterEQParameter(int value) { - EffectPointer effect(m_pEffectMasterEQ); - if (!effect.isNull()) { + EffectSlotPointer pEffectSlot(m_pEffectMasterEQ); + if (!pEffectSlot.isNull()) { QSlider* slider = qobject_cast(sender()); int index = slider->property("index").toInt(); - EffectParameter* param = effect->getKnobParameterForSlot(index); - if (param) { + auto pParameterSlot = pEffectSlot->getEffectParameterSlot( + EffectManifestParameter::ParameterType::KNOB, index); + + if (pParameterSlot->isLoaded()) { double dValue = value / 100.0; - param->setValue(dValue); + pParameterSlot->slotParameterValueChanged(dValue); QLabel* valueLabel = m_masterEQValues[index]; QString valueText = QString::number(dValue); valueLabel->setText(valueText); @@ -618,6 +541,16 @@ void DlgPrefEQ::slotUpdate() { slotPopulateDeckEffectSelectors(); CheckBoxEqAutoReset->setChecked(m_bEqAutoReset); CheckBoxGainAutoReset->setChecked(m_bGainAutoReset); + + m_eqIndiciesOnUpdate.clear(); + for (const auto& box : m_deckEqEffectSelectors) { + m_eqIndiciesOnUpdate.append(box->currentIndex()); + } + + m_quickEffectIndiciesOnUpdate.clear(); + for (const auto& box : m_deckQuickEffectSelectors) { + m_quickEffectIndiciesOnUpdate.append(box->currentIndex()); + } } void DlgPrefEQ::slotUpdateEqAutoReset(int i) { @@ -637,7 +570,6 @@ void DlgPrefEQ::slotBypass(int state) { for (const auto& box: m_deckEqEffectSelectors) { QString group = getEQEffectGroupForDeck(deck); ControlObject::set(ConfigKey(group, "enabled"), 0); - m_filterWaveformEnableCOs[deck]->set(0); deck++; box->setEnabled(false); } @@ -649,7 +581,6 @@ void DlgPrefEQ::slotBypass(int state) { for (const auto& box: m_deckEqEffectSelectors) { QString group = getEQEffectGroupForDeck(deck); ControlObject::set(ConfigKey(group, "enabled"), 1); - m_filterWaveformEnableCOs[deck]->set(m_filterWaveformEffectLoaded[deck]); deck++; box->setEnabled(true); } @@ -665,31 +596,35 @@ void DlgPrefEQ::setUpMasterEQ() { connect(comboBoxMasterEq, SIGNAL(currentIndexChanged(int)), this, SLOT(slotMasterEqEffectChanged(int))); - QString configuredEffect = m_pConfig->getValue(ConfigKey(kConfigKey, + const QString configuredEffectId = m_pConfig->getValue(ConfigKey(kConfigKey, "EffectForGroup_[Master]"), kDefaultMasterEqId); + const EffectManifestPointer configuredEffectManifest = + m_pEffectsManager->getManifestFromUniqueId(configuredEffectId); const QList availableMasterEQEffects = - m_pEffectsManager->getAvailableEffectManifestsFiltered(isMasterEQ); + m_pEffectsManager->getAvailableEffectManifestsFiltered(isMasterEQ); for (const auto& pManifest : availableMasterEQEffects) { - comboBoxMasterEq->addItem(pManifest->name(), QVariant(pManifest->id())); + comboBoxMasterEq->addItem(pManifest->name(), QVariant(pManifest->uniqueId())); } //: Displayed when no effect is selected comboBoxMasterEq->addItem(tr("None"), QVariant()); - int masterEqIndex = comboBoxMasterEq->findData(configuredEffect); - if (masterEqIndex < 0) { - masterEqIndex = availableMasterEQEffects.size(); // selects "None" + int masterEqIndex = availableMasterEQEffects.size(); // selects "None" by default + if (configuredEffectManifest) { + masterEqIndex = comboBoxMasterEq->findData(configuredEffectManifest->uniqueId()); } comboBoxMasterEq->setCurrentIndex(masterEqIndex); // Load parameters from preferences: - EffectPointer effect(m_pEffectMasterEQ); - if (!effect.isNull()) { - int knobNum = effect->numKnobParameters(); + EffectSlotPointer pEffectSlot(m_pEffectMasterEQ); + if (!pEffectSlot.isNull()) { + int knobNum = pEffectSlot->numParameters(EffectManifestParameter::ParameterType::KNOB); for (int i = 0; i < knobNum; i++) { - EffectParameter* param = effect->getKnobParameterForSlot(i); - if (param) { + auto pParameterSlot = pEffectSlot->getEffectParameterSlot( + EffectManifestParameter::ParameterType::KNOB, i); + + if (pParameterSlot->isLoaded()) { QString strValue = m_pConfig->getValueString(ConfigKey(kConfigKey, QString("EffectForGroup_[Master]_parameter%1").arg(i + 1))); bool ok; @@ -711,47 +646,50 @@ void DlgPrefEQ::slotMasterEqEffectChanged(int effectIndex) { qDeleteAll(m_masterEQLabels); m_masterEQLabels.clear(); - QString effectId = comboBoxMasterEq->itemData(effectIndex).toString(); + const EffectManifestPointer pManifest = + m_pEffectsManager->getManifestFromUniqueId( + comboBoxMasterEq->itemData( + effectIndex).toString()); - if (effectId.isNull()) { + if (pManifest == nullptr) { pbResetMasterEq->hide(); } else { pbResetMasterEq->show(); } - EffectChainSlotPointer pChainSlot = m_pOutputEffectRack->getEffectChainSlot(0); - + auto pChainSlot = m_pEffectsManager->getOutputEffectChainSlot(); if (pChainSlot) { - EffectChainPointer pChain = pChainSlot->getEffectChain(); - VERIFY_OR_DEBUG_ASSERT(pChain) { - pChain = pChainSlot->getOrCreateEffectChain(m_pEffectsManager); - } - EffectPointer pEffect = m_pEffectsManager->instantiateEffect(effectId); - pChain->replaceEffect(0, pEffect); + m_pEffectsManager->loadOutputEffect(0, pManifest); + + auto pEffectSlot = pChainSlot->getEffectSlot(0); - if (pEffect) { - pEffect->setEnabled(true); - m_pEffectMasterEQ = pEffect; + if (pEffectSlot) { + pEffectSlot->setEnabled(true); + m_pEffectMasterEQ = pEffectSlot; - int knobNum = pEffect->numKnobParameters(); + int knobNum = pEffectSlot->numParameters(EffectManifestParameter::ParameterType::KNOB); // Create and set up Master EQ's sliders int i; for (i = 0; i < knobNum; i++) { - EffectParameter* param = pEffect->getKnobParameterForSlot(i); - if (param) { + auto pParameterSlot = pEffectSlot->getEffectParameterSlot( + EffectManifestParameter::ParameterType::KNOB, i); + + if (pParameterSlot->isLoaded()) { + EffectManifestParameterPointer pManifestParameter = pParameterSlot->getManifest(); + // Setup Label QLabel* centerFreqLabel = new QLabel(this); - QString labelText = param->manifest()->name(); + QString labelText = pParameterSlot->getManifest()->name(); m_masterEQLabels.append(centerFreqLabel); centerFreqLabel->setText(labelText); slidersGridLayout->addWidget(centerFreqLabel, 0, i + 1, Qt::AlignCenter); QSlider* slider = new QSlider(this); - slider->setMinimum(param->getMinimum() * 100); - slider->setMaximum(param->getMaximum() * 100); + slider->setMinimum(pManifestParameter->getMinimum() * 100); + slider->setMaximum(pManifestParameter->getMaximum() * 100); slider->setSingleStep(1); - slider->setValue(param->getDefault() * 100); + slider->setValue(pManifestParameter->getDefault() * 100); slider->setMinimumHeight(90); // Set the index as a property because we need it inside slotUpdateFilter() slider->setProperty("index", QVariant(i)); @@ -764,15 +702,16 @@ void DlgPrefEQ::slotMasterEqEffectChanged(int effectIndex) { QString valueText = QString::number((double)slider->value() / 100); valueLabel->setText(valueText); slidersGridLayout->addWidget(valueLabel, 2, i + 1, Qt::AlignCenter); - } } } } // Update the configured effect for the current QComboBox - m_pConfig->set(ConfigKey(kConfigKey, "EffectForGroup_[Master]"), - ConfigValue(effectId)); + if (pManifest) { + m_pConfig->set(ConfigKey(kConfigKey, "EffectForGroup_[Master]"), + ConfigValue(pManifest->uniqueId())); + } } double DlgPrefEQ::getEqFreq(int sliderVal, int minValue, int maxValue) { @@ -806,31 +745,23 @@ void DlgPrefEQ::validate_levels() { } QString DlgPrefEQ::getEQEffectGroupForDeck(int deck) const { - // The EQ effect is loaded in effect slot 0. - if (m_pEQEffectRack) { - return m_pEQEffectRack->formatEffectSlotGroupString( - 0, PlayerManager::groupForDeck(deck)); - } - return QString(); + return EqualizerEffectChainSlot::formatEffectSlotGroup( + PlayerManager::groupForDeck(deck)); } QString DlgPrefEQ::getQuickEffectGroupForDeck(int deck) const { - // The quick effect is loaded in effect slot 0. - if (m_pQuickEffectRack) { - return m_pQuickEffectRack->formatEffectSlotGroupString( - 0, PlayerManager::groupForDeck(deck)); - } - return QString(); + return QuickEffectChainSlot::formatEffectSlotGroup( + PlayerManager::groupForDeck(deck)); } void DlgPrefEQ::slotMasterEQToDefault() { - EffectPointer effect(m_pEffectMasterEQ); - if (!effect.isNull()) { - int knobNum = effect->numKnobParameters(); + EffectSlotPointer pEffectSlot(m_pEffectMasterEQ); + if (!pEffectSlot.isNull()) { + int knobNum = pEffectSlot->numParameters(EffectManifestParameter::ParameterType::KNOB); for (int i = 0; i < knobNum; i++) { - EffectParameter* param = effect->getKnobParameterForSlot(i); - if (param) { - double defaultValue = param->getDefault(); + auto pParameterSlot = pEffectSlot->getEffectParameterSlot(EffectManifestParameter::ParameterType::KNOB, i); + if (pParameterSlot->isLoaded()) { + double defaultValue = pParameterSlot->getManifest()->getDefault(); setMasterEQParameter(i, defaultValue); } } @@ -838,11 +769,13 @@ void DlgPrefEQ::slotMasterEQToDefault() { } void DlgPrefEQ::setMasterEQParameter(int i, double value) { - EffectPointer effect(m_pEffectMasterEQ); - if (!effect.isNull()) { - EffectParameter* param = effect->getKnobParameterForSlot(i); - if (param) { - param->setValue(value); + EffectSlotPointer pEffectSlot(m_pEffectMasterEQ); + if (!pEffectSlot.isNull()) { + auto pParameterSlot = pEffectSlot->getEffectParameterSlot( + EffectManifestParameter::ParameterType::KNOB, i); + + if (pParameterSlot->isLoaded()) { + pParameterSlot->slotParameterValueChanged(value); m_masterEQSliders[i]->setValue(value * 100); QLabel* valueLabel = m_masterEQValues[i]; diff --git a/src/preferences/dialog/dlgprefeq.h b/src/preferences/dialog/dlgprefeq.h index 67f4dee52b8..a3f57ee8a08 100644 --- a/src/preferences/dialog/dlgprefeq.h +++ b/src/preferences/dialog/dlgprefeq.h @@ -18,6 +18,8 @@ #ifndef DLGPREFEQ_H #define DLGPREFEQ_H +#include + #include #include @@ -26,7 +28,6 @@ #include "control/controlproxy.h" #include "preferences/dlgpreferencepage.h" #include "effects/effectsmanager.h" -#include "effects/effectrack.h" /** *@author John Sully @@ -42,8 +43,13 @@ class DlgPrefEQ : public DlgPreferencePage, public Ui::DlgPrefEQDlg { QString getQuickEffectGroupForDeck(int deck) const; public slots: - void slotEqEffectChangedOnDeck(int effectIndex); - void slotQuickEffectChangedOnDeck(int effectIndex); + // Apply changes to widget + void slotApply(); + void slotUpdate(); + void slotResetToDefaults(); + + private slots: + void slotEffectChangedOnDeck(int effectIndex); void slotNumDecksChanged(double numDecks); void slotSingleEqChecked(int checked); // Slot for toggling between advanced and basic views @@ -52,10 +58,6 @@ class DlgPrefEQ : public DlgPreferencePage, public Ui::DlgPrefEQDlg { void slotUpdateHiEQ(); // Update Lo EQ void slotUpdateLoEQ(); - // Apply changes to widget - void slotApply(); - void slotUpdate(); - void slotResetToDefaults(); void slotUpdateEqAutoReset(int); void slotUpdateGainAutoReset(int); void slotBypass(int state); @@ -65,10 +67,6 @@ class DlgPrefEQ : public DlgPreferencePage, public Ui::DlgPrefEQDlg { void setMasterEQParameter(int i, double value); void slotMasterEqEffectChanged(int effectIndex); - signals: - void apply(const QString &); - void effectOnChainSlot(const unsigned int, const unsigned int, QString); - private: void loadSettings(); void setDefaultShelves(); @@ -78,6 +76,16 @@ class DlgPrefEQ : public DlgPreferencePage, public Ui::DlgPrefEQDlg { void updateBandFilter(int index, double value); void setUpMasterEQ(); void applySelections(); + void populateDeckBoxList( + const QList boxList, + EffectsManager::EffectManifestFilterFnc filterFunc); + + typedef std::function loadEffectFunction; + void applySelectionsToDecks( + const QList& boxList, + QList& indiciesOnUpdate, + loadEffectFunction loadFunc, + const QString& configKeyPrefix); ControlProxy m_COLoFreq; ControlProxy m_COHiFreq; @@ -86,14 +94,9 @@ class DlgPrefEQ : public DlgPreferencePage, public Ui::DlgPrefEQDlg { // Members needed for changing the effects loaded on the EQ Effect Rack EffectsManager* m_pEffectsManager; - EqualizerRackPointer m_pEQEffectRack; - QuickEffectRackPointer m_pQuickEffectRack; - OutputEffectRackPointer m_pOutputEffectRack; QLabel* m_firstSelectorLabel; QList m_deckEqEffectSelectors; QList m_deckQuickEffectSelectors; - QList m_filterWaveformEffectLoaded; - QList m_filterWaveformEnableCOs; ControlProxy* m_pNumDecks; bool m_inSlotPopulateDeckEffectSelectors; @@ -102,10 +105,13 @@ class DlgPrefEQ : public DlgPreferencePage, public Ui::DlgPrefEQDlg { QList m_masterEQSliders; QList m_masterEQValues; QList m_masterEQLabels; - QWeakPointer m_pEffectMasterEQ; + QWeakPointer m_pEffectMasterEQ; bool m_bEqAutoReset; bool m_bGainAutoReset; + + QList m_eqIndiciesOnUpdate; + QList m_quickEffectIndiciesOnUpdate; }; #endif diff --git a/src/preferences/dialog/dlgprefeqdlg.ui b/src/preferences/dialog/dlgprefeqdlg.ui index 3eec8bef5bd..0313ed7824f 100644 --- a/src/preferences/dialog/dlgprefeqdlg.ui +++ b/src/preferences/dialog/dlgprefeqdlg.ui @@ -15,11 +15,11 @@ - + - Equalizer Rack + Deck Equalizers and Quick Effects - + diff --git a/src/preferences/dialog/dlgpreflv2.cpp b/src/preferences/dialog/dlgpreflv2.cpp index 7373346a16c..fc56c7b70f0 100644 --- a/src/preferences/dialog/dlgpreflv2.cpp +++ b/src/preferences/dialog/dlgpreflv2.cpp @@ -30,15 +30,14 @@ DlgPrefLV2::DlgPrefLV2(QWidget* pParent, LV2Backend* lv2Backend, qSort(allPlugins.begin(), allPlugins.end()); for (const auto& effectId: allPlugins) { - LV2Manifest* lv2Manifest = m_pLV2Backend->getLV2Manifest(effectId); - EffectManifestPointer pEffectManifest = lv2Manifest->getEffectManifest(); + LV2EffectManifestPointer pManifest = m_pLV2Backend->getLV2Manifest(effectId); QPushButton* button = new QPushButton(this); - button->setText(pEffectManifest->name()); + button->setText(pManifest->name()); if (!m_pLV2Backend->canInstantiateEffect(effectId)) { // Tooltip displaying why this effect is disabled - LV2Manifest::Status status = lv2Manifest->getStatus(); + LV2Manifest::Status status = pManifest->getStatus(); switch (status) { case LV2Manifest::IO_NOT_STEREO: button->setToolTip(QObject::tr("This plugin does not support " @@ -57,7 +56,7 @@ DlgPrefLV2::DlgPrefLV2(QWidget* pParent, LV2Backend* lv2Backend, } lv2_vertical_layout_left->addWidget(button); - button->setProperty("id", QVariant(pEffectManifest->id())); + button->setProperty("id", QVariant(pManifest->id())); connect(button, SIGNAL(clicked()), this, SLOT(slotDisplayParameters())); } } @@ -112,16 +111,23 @@ void DlgPrefLV2::slotDisplayParameters() { } void DlgPrefLV2::slotApply() { + if (m_currentEffectId.isEmpty()) { + return; + } + EffectManifestPointer pCurrentEffectManifest = m_pLV2Backend->getManifest(m_currentEffectId); + qDebug() << "DlgPrefLV2::slotApply" << pCurrentEffectManifest.data(); - if (pCurrentEffectManifest) { - for (int i = 0; i < m_pluginParameters.size(); i++) { - EffectManifestParameterPointer pParameter = pCurrentEffectManifest->parameter(i); - pParameter->setShowInParameterSlot(m_pluginParameters[i]->isChecked()); + unsigned int position = 0; + for (int i = 0; i < m_pluginParameters.size(); i++) { + if (m_pluginParameters[i]->isChecked()) { + m_pEffectsManager->setEffectParameterPosition(pCurrentEffectManifest, i, position); + ++position; + } else { + m_pEffectsManager->hideEffectParameter(pCurrentEffectManifest, i); } } - m_pEffectsManager->refeshAllRacks(); } void DlgPrefLV2::slotUpdateOnParameterCheck(int state) { diff --git a/src/preferences/effectsettingsmodel.cpp b/src/preferences/effectsettingsmodel.cpp index 48e87ba020e..0a02e653e86 100644 --- a/src/preferences/effectsettingsmodel.cpp +++ b/src/preferences/effectsettingsmodel.cpp @@ -73,7 +73,7 @@ QVariant EffectSettingsModel::data(const QModelIndex& index, int role) const { EffectProfilePtr profile = m_profiles.at(rowIndex); if (profile) { if (role == Qt::UserRole) { - return profile->pManifest->id(); + return profile->pManifest->uniqueId(); } int column = index.column(); if (column == kColumnEnabled) { diff --git a/src/test/baseeffecttest.h b/src/test/baseeffecttest.h index 0102f5fc8dd..ee5a546ba7a 100644 --- a/src/test/baseeffecttest.h +++ b/src/test/baseeffecttest.h @@ -6,8 +6,7 @@ #include -#include "effects/effectchain.h" -#include "effects/effect.h" +#include "effects/effectslot.h" #include "effects/effectsmanager.h" #include "effects/effectmanifest.h" #include "effects/effectsbackend.h" @@ -35,7 +34,7 @@ class MockEffectProcessor : public EffectProcessor { MockEffectProcessor() {} MOCK_METHOD3(initialize, void(const QSet& activeInputChannels, - EffectsManager* pEffectsManager, + const QSet& registeredOutputChannels, const mixxx::EngineParameters& bufferParameters)); MOCK_METHOD1(createState, EffectState*(const mixxx::EngineParameters& bufferParameters)); MOCK_METHOD2(loadStatesForInputChannel, bool(const ChannelHandle* inputChannel, diff --git a/src/test/effectchainslottest.cpp b/src/test/effectchainslottest.cpp deleted file mode 100644 index 9169e8943fe..00000000000 --- a/src/test/effectchainslottest.cpp +++ /dev/null @@ -1,113 +0,0 @@ -#include -#include - -#include -#include - -#include "mixxxtest.h" -#include "control/controlobject.h" -#include "effects/effectchain.h" -#include "effects/effectchainslot.h" -#include "effects/effectrack.h" -#include "effects/effectsmanager.h" -#include "test/baseeffecttest.h" - -using ::testing::Return; -using ::testing::_; - -class EffectChainSlotTest : public BaseEffectTest { - protected: - EffectChainSlotTest() - : m_master(m_factory.getOrCreateHandle("[Master]"), "[Master]"), - m_headphone(m_factory.getOrCreateHandle("[Headphone]"), "[Headphone]") { - } - - ChannelHandleFactory m_factory; - ChannelHandleAndGroup m_master; - ChannelHandleAndGroup m_headphone; -}; - -TEST_F(EffectChainSlotTest, ChainSlotMirrorsLoadedChain) { - EffectChainPointer pChain(new EffectChain(m_pEffectsManager.data(), - "org.mixxx.test.chain1")); - int iRackNumber = 0; - int iChainNumber = 0; - - StandardEffectRackPointer pRack = m_pEffectsManager->addStandardEffectRack(); - EffectChainSlotPointer pChainSlot = pRack->getEffectChainSlot(iChainNumber); - - QString group = StandardEffectRack::formatEffectChainSlotGroupString( - iRackNumber, iChainNumber); - pChainSlot->loadEffectChainToSlot(pChain); - - pChain->setEnabled(true); - EXPECT_LT(0.0, ControlObject::get(ConfigKey(group, "enabled"))); - - pChain->setEnabled(false); - EXPECT_DOUBLE_EQ(0.0, ControlObject::get(ConfigKey(group, "enabled"))); - - ControlObject::set(ConfigKey(group, "enabled"), 1.0); - EXPECT_TRUE(pChain->enabled()); - - // Loaded is read-only. Sets to it should not do anything. - ControlObject::set(ConfigKey(group, "loaded"), 0); - EXPECT_TRUE(ControlObject::get(ConfigKey(group, "loaded")) > 0.0); - - // numEffects is read-only. Sets to it should not do anything. - ControlObject::set(ConfigKey(group, "num_effects"), 1); - EXPECT_EQ(0U, pChain->numEffects()); - - pChain->setMix(1.0); - EXPECT_DOUBLE_EQ(pChain->mix(), - ControlObject::get(ConfigKey(group, "mix"))); - - ControlObject::set(ConfigKey(group, "mix"), 0.5); - EXPECT_DOUBLE_EQ(0.5, pChain->mix()); - - pChain->setMixMode(EffectChainMixMode::DryPlusWet); - EXPECT_DOUBLE_EQ(static_cast(pChain->mixMode()), - ControlObject::get(ConfigKey(group, "mix_mode"))); - - ControlObject::set(ConfigKey(group, "mix_mode"), - static_cast(EffectChainMixMode::DrySlashWet)); - EXPECT_EQ(EffectChainMixMode::DrySlashWet, pChain->mixMode()); - - EXPECT_FALSE(pChain->enabledForChannel(m_master)); - EXPECT_DOUBLE_EQ(0.0, ControlObject::get(ConfigKey(group, "group_[Master]_enable"))); - - ControlObject::set(ConfigKey(group, "group_[Master]_enable"), 0); - EXPECT_FALSE(pChain->enabledForChannel(m_master)); -} - -TEST_F(EffectChainSlotTest, ChainSlotMirrorsLoadedChain_StartsWithChainLoaded) { - EffectChainPointer pChain(new EffectChain(m_pEffectsManager.data(), - "org.mixxx.test.chain1")); - int iRackNumber = 0; - int iChainNumber = 0; - - StandardEffectRackPointer pRack = m_pEffectsManager->addStandardEffectRack(); - EffectChainSlotPointer pChainSlot = pRack->getEffectChainSlot(iChainNumber); - pChainSlot->loadEffectChainToSlot(pChain); - QString group = StandardEffectRack::formatEffectChainSlotGroupString( - iRackNumber, iChainNumber); - EXPECT_DOUBLE_EQ(1.0, ControlObject::get(ConfigKey(group, "loaded"))); -} - -TEST_F(EffectChainSlotTest, ChainSlotMirrorsLoadedChain_Clear) { - EffectChainPointer pChain(new EffectChain(m_pEffectsManager.data(), - "org.mixxx.test.chain1")); - - int iRackNumber = 0; - int iChainNumber = 0; - - StandardEffectRackPointer pRack = m_pEffectsManager->addStandardEffectRack(); - EffectChainSlotPointer pChainSlot = pRack->getEffectChainSlot(iChainNumber); - - QString group = StandardEffectRack::formatEffectChainSlotGroupString( - iRackNumber, iChainNumber); - EXPECT_DOUBLE_EQ(0.0, ControlObject::get(ConfigKey(group, "loaded"))); - pChainSlot->loadEffectChainToSlot(pChain); - EXPECT_DOUBLE_EQ(1.0, ControlObject::get(ConfigKey(group, "loaded"))); - ControlObject::set(ConfigKey(group, "clear"), 1.0); - EXPECT_DOUBLE_EQ(0.0, ControlObject::get(ConfigKey(group, "loaded"))); -} diff --git a/src/test/effectslottest.cpp b/src/test/effectslottest.cpp index 10e25db965c..4ce5f1a1b66 100644 --- a/src/test/effectslottest.cpp +++ b/src/test/effectslottest.cpp @@ -6,11 +6,9 @@ #include "mixxxtest.h" #include "control/controlobject.h" -#include "effects/effectchain.h" #include "effects/effectchainslot.h" #include "effects/effectsmanager.h" #include "effects/effectmanifest.h" -#include "effects/effectrack.h" #include "effects/effectslot.h" #include "test/baseeffecttest.h" @@ -32,22 +30,18 @@ class EffectSlotTest : public BaseEffectTest { }; TEST_F(EffectSlotTest, ControlsReflectSlotState) { - EffectChainPointer pChain(new EffectChain(m_pEffectsManager.data(), - "org.mixxx.test.chain1")); - int iRackNumber = 0; int iChainNumber = 0; int iEffectNumber = 0; - StandardEffectRackPointer pRack = m_pEffectsManager->addStandardEffectRack(); - EffectChainSlotPointer pChainSlot = pRack->getEffectChainSlot(iChainNumber); - pChainSlot->loadEffectChainToSlot(pChain); - // StandardEffectRack::addEffectChainSlot automatically adds 4 effect + m_pEffectsManager->addStandardEffectChainSlots(); + EffectChainSlotPointer pChainSlot = m_pEffectsManager->getStandardEffectChainSlot(iChainNumber); + // StandardEffectChainSlot::addEffectChainSlot automatically adds 4 effect // slots. In the future we will probably remove this so this will just start // segfaulting. EffectSlotPointer pEffectSlot = pChainSlot->getEffectSlot(0); - QString group = StandardEffectRack::formatEffectSlotGroupString( - iRackNumber, iChainNumber, iEffectNumber); + QString group = StandardEffectChainSlot::formatEffectSlotGroup( + iChainNumber, iEffectNumber); EffectManifestPointer pManifest(new EffectManifest()); pManifest->setId("org.mixxx.test.effect"); @@ -55,18 +49,16 @@ TEST_F(EffectSlotTest, ControlsReflectSlotState) { pManifest->addParameter(); registerTestEffect(pManifest, false); - // Check the controls reflect the state of their loaded effect. - EffectPointer pEffect = m_pEffectsManager->instantiateEffect(pManifest->id()); // Enabled defaults to false in effect, slot, and engine effect. EXPECT_DOUBLE_EQ(0, ControlObject::get(ConfigKey(group, "enabled"))); EXPECT_DOUBLE_EQ(0, ControlObject::get(ConfigKey(group, "num_parameters"))); - pEffectSlot->loadEffect(pEffect, false); + m_pEffectsManager->loadEffect(pChainSlot, iEffectNumber, + pManifest->id(), EffectBackendType::Unknown); EXPECT_DOUBLE_EQ(0, ControlObject::get(ConfigKey(group, "enabled"))); EXPECT_DOUBLE_EQ(1, ControlObject::get(ConfigKey(group, "num_parameters"))); - pEffect->setEnabled(true); - EXPECT_TRUE(pEffect->enabled()); + pEffectSlot->setEnabled(true); EXPECT_DOUBLE_EQ(1, ControlObject::get(ConfigKey(group, "enabled"))); EXPECT_DOUBLE_EQ(1, ControlObject::get(ConfigKey(group, "num_parameters"))); @@ -77,4 +69,4 @@ TEST_F(EffectSlotTest, ControlsReflectSlotState) { // num_parameters is read-only. ControlObject::set(ConfigKey(group, "num_parameters"), 2.0); EXPECT_DOUBLE_EQ(1, ControlObject::get(ConfigKey(group, "num_parameters"))); -} +} \ No newline at end of file diff --git a/src/test/effectsmanagertest.cpp b/src/test/effectsmanagertest.cpp deleted file mode 100644 index f93c4e45dce..00000000000 --- a/src/test/effectsmanagertest.cpp +++ /dev/null @@ -1,38 +0,0 @@ -#include -#include - -#include -#include - -#include "test/mixxxtest.h" -#include "effects/effectchain.h" -#include "effects/effectchainslot.h" -#include "effects/effectsmanager.h" -#include "effects/effectmanifest.h" - -#include "test/baseeffecttest.h" - -using ::testing::Return; -using ::testing::_; - -class EffectsManagerTest : public BaseEffectTest { - protected: - void SetUp() override { - registerTestBackend(); - } -}; - -TEST_F(EffectsManagerTest, CanInstantiateEffectsFromBackend) { - EffectManifestPointer pManifest(new EffectManifest()); - pManifest->setId("org.mixxx.test.effect"); - pManifest->setName("Test Effect"); - registerTestEffect(pManifest, false); - - // Check we can get the same manifest that we registered back. - EffectManifestPointer effect_to_load = m_pEffectsManager->getEffectManifest(pManifest->id()); - EXPECT_QSTRING_EQ(effect_to_load->name(), pManifest->name()); - - // Check we can instantiate the effect. - EffectPointer pEffect = m_pEffectsManager->instantiateEffect(pManifest->id()); - EXPECT_FALSE(pEffect.isNull()); -} diff --git a/src/test/metaknob_link_test.cpp b/src/test/metaknob_link_test.cpp index 17f2f2fc0c4..09b469044b9 100644 --- a/src/test/metaknob_link_test.cpp +++ b/src/test/metaknob_link_test.cpp @@ -4,10 +4,9 @@ #include #include "controllers/softtakeover.h" -#include "effects/effectparameterslot.h" +#include "effects/effectknobparameterslot.h" #include "effects/effectchainslot.h" -#include "effects/effectrack.h" -#include "effects/effect.h" +#include "effects/specialeffectchainslots.h" #include "effects/effectslot.h" #include "mixxxtest.h" #include "test/baseeffecttest.h" @@ -25,19 +24,15 @@ class MetaLinkTest : public BaseEffectTest { m_pEffectsManager->registerInputChannel(m_headphone); registerTestBackend(); - EffectChainPointer pChain(new EffectChain(m_pEffectsManager.data(), - "org.mixxx.test.chain1")); - int iRackNumber = 0; int iChainNumber = 0; int iEffectNumber = 0; - StandardEffectRackPointer pRack = m_pEffectsManager->addStandardEffectRack(); - m_pChainSlot = pRack->getEffectChainSlot(iChainNumber); - m_pChainSlot->loadEffectChainToSlot(pChain); + m_pEffectsManager->addStandardEffectChainSlots(); + m_pChainSlot = m_pEffectsManager->getStandardEffectChainSlot(iChainNumber); m_pEffectSlot = m_pChainSlot->getEffectSlot(iEffectNumber); - QString group = StandardEffectRack::formatEffectSlotGroupString( - iRackNumber, iChainNumber, iEffectNumber); + QString group = StandardEffectChainSlot::formatEffectSlotGroup( + iChainNumber, iEffectNumber); EffectManifestPointer pManifest(new EffectManifest()); pManifest->setId("org.mixxx.test.effect"); @@ -48,7 +43,7 @@ class MetaLinkTest : public BaseEffectTest { low->setId("low"); low->setName(QObject::tr("Low")); low->setDescription(QObject::tr("Gain for Low Filter")); - low->setControlHint(EffectManifestParameter::ControlHint::KNOB_LINEAR); + low->setValueScaler(EffectManifestParameter::ValueScaler::LINEAR); low->setSemanticHint(EffectManifestParameter::SemanticHint::UNKNOWN); low->setUnitsHint(EffectManifestParameter::UnitsHint::UNKNOWN); low->setNeutralPointOnScale(0.25); @@ -58,12 +53,10 @@ class MetaLinkTest : public BaseEffectTest { registerTestEffect(pManifest, false); - // Check the controls reflect the state of their loaded effect. - EffectPointer pEffect = m_pEffectsManager->instantiateEffect(pManifest->id()); + m_pEffectsManager->loadEffect(m_pChainSlot, iEffectNumber, + pManifest->id(), EffectBackendType::Unknown); - m_pEffectSlot->loadEffect(pEffect, false); - - QString itemPrefix = EffectParameterSlot::formatItemPrefix(0); + QString itemPrefix = EffectKnobParameterSlot::formatItemPrefix(0); m_pControlValue.reset(new ControlProxy(group, itemPrefix)); @@ -122,7 +115,7 @@ TEST_F(MetaLinkTest, MetaToParameter_Softtakeover_EffectEnabled) { m_pControlLinkType->set( static_cast(EffectManifestParameter::LinkType::LINKED)); // Soft takeover should only occur when the effect is enabled. - m_pEffectSlot->slotEnabled(1.0); + m_pEffectSlot->setEnabled(1.0); // Soft takeover always ignores the first change. m_pEffectSlot->slotEffectMetaParameter(0.5); @@ -162,7 +155,7 @@ TEST_F(MetaLinkTest, MetaToParameter_Softtakeover_EffectDisabled) { TEST_F(MetaLinkTest, SuperToMeta_Softtakeover_EffectEnabled) { // Soft takeover should only occur when the effect is enabled. - m_pEffectSlot->slotEnabled(1.0); + m_pEffectSlot->setEnabled(1.0); // Soft takeover always ignores the first change. m_pChainSlot->setSuperParameter(0.5); @@ -201,12 +194,11 @@ TEST_F(MetaLinkTest, HalfLinkTakeover) { // An effect that is linked to half of a knob should be more tolerant of // takeover changes. - m_pEffectSlot->slotEnabled(1.0); + m_pEffectSlot->setEnabled(1.0); // We have to recreate the effect because we want a neutral point at // 0 or 1. - QString group = StandardEffectRack::formatEffectSlotGroupString( - 0, 0, 0); + QString group = StandardEffectChainSlot::formatEffectSlotGroup(0, 0); EffectManifestPointer pManifest(new EffectManifest()); pManifest->setId("org.mixxx.test.effect2"); pManifest->setName("Test Effect2"); @@ -214,7 +206,7 @@ TEST_F(MetaLinkTest, HalfLinkTakeover) { low->setId("low"); low->setName(QObject::tr("Low")); low->setDescription(QObject::tr("Gain for Low Filter (neutral at 1.0)")); - low->setControlHint(EffectManifestParameter::ControlHint::KNOB_LINEAR); + low->setValueScaler(EffectManifestParameter::ValueScaler::LINEAR); low->setSemanticHint(EffectManifestParameter::SemanticHint::UNKNOWN); low->setUnitsHint(EffectManifestParameter::UnitsHint::UNKNOWN); low->setNeutralPointOnScale(1.0); @@ -222,10 +214,10 @@ TEST_F(MetaLinkTest, HalfLinkTakeover) { low->setMinimum(0); low->setMaximum(1.0); registerTestEffect(pManifest, false); - // Check the controls reflect the state of their loaded effect. - EffectPointer pEffect = m_pEffectsManager->instantiateEffect(pManifest->id()); - m_pEffectSlot->loadEffect(pEffect, false); - QString itemPrefix = EffectParameterSlot::formatItemPrefix(0); + + m_pEffectsManager->loadEffect(m_pChainSlot, 0, pManifest->id(), EffectBackendType::Unknown); + + QString itemPrefix = EffectKnobParameterSlot::formatItemPrefix(0); m_pControlValue.reset(new ControlProxy(group, itemPrefix)); m_pControlLinkType.reset(new ControlProxy(group, itemPrefix + QString("_link_type"))); @@ -260,4 +252,4 @@ TEST_F(MetaLinkTest, HalfLinkTakeover) { newParam = 0.5 + SoftTakeover::kDefaultTakeoverThreshold * 1.5; m_pEffectSlot->slotEffectMetaParameter(newParam); EXPECT_FLOAT_EQ(0.0703125, m_pControlValue->get()); -} +} \ No newline at end of file diff --git a/src/widget/effectwidgetutils.h b/src/widget/effectwidgetutils.h index f2fd08c1c75..c65e3c0ebfd 100644 --- a/src/widget/effectwidgetutils.h +++ b/src/widget/effectwidgetutils.h @@ -5,43 +5,16 @@ #include "effects/effectsmanager.h" #include "effects/defs.h" -#include "effects/effectrack.h" #include "effects/effectslot.h" #include "skin/skincontext.h" class EffectWidgetUtils { public: - static EffectRackPointer getEffectRackFromNode( + static EffectChainSlotPointer getEffectChainSlotFromNode( const QDomNode& node, const SkinContext& context, EffectsManager* pEffectsManager) { if (pEffectsManager == nullptr) { - return EffectRackPointer(); - } - - // If specified, EffectRack always refers to a StandardEffectRack index. - bool rackNumberOk = false; - int rackNumber = context.selectInt(node, "EffectRack", - &rackNumberOk); - if (rackNumberOk) { - // XML effect nodes are 1-indexed. - return pEffectsManager->getStandardEffectRack(rackNumber - 1); - } - - // For custom racks, users can specify EffectRackGroup explicitly - // instead. - QString rackGroup; - if (!context.hasNodeSelectString(node, "EffectRackGroup", &rackGroup)) { - return EffectRackPointer(); - } - return pEffectsManager->getEffectRack(rackGroup); - } - - static EffectChainSlotPointer getEffectChainSlotFromNode( - const QDomNode& node, - const SkinContext& context, - EffectRackPointer pRack) { - if (pRack.isNull()) { return EffectChainSlotPointer(); } @@ -50,7 +23,7 @@ class EffectWidgetUtils { &unitNumberOk); if (unitNumberOk) { // XML effect nodes are 1-indexed. - return pRack->getEffectChainSlot(unitNumber - 1); + return pEffectsManager->getStandardEffectChainSlot(unitNumber - 1); } QString unitGroup; @@ -58,13 +31,7 @@ class EffectWidgetUtils { return EffectChainSlotPointer(); } - for (int i = 0; i < pRack->numEffectChainSlots(); ++i) { - EffectChainSlotPointer pSlot = pRack->getEffectChainSlot(i); - if (pSlot->getGroup() == unitGroup) { - return pSlot; - } - } - return EffectChainSlotPointer(); + return pEffectsManager->getEffectChainSlot(unitGroup); } static EffectSlotPointer getEffectSlotFromNode( @@ -96,7 +63,7 @@ class EffectWidgetUtils { ¶meterNumberOk); if (parameterNumberOk) { // XML effect nodes are 1-indexed. - return pEffectSlot->getEffectParameterSlot(parameterNumber - 1); + return pEffectSlot->getEffectParameterSlot(EffectManifestParameter::ParameterType::KNOB, parameterNumber - 1); } return EffectParameterSlotBasePointer(); } @@ -113,7 +80,7 @@ class EffectWidgetUtils { ¶meterNumberOk); if (parameterNumberOk) { // XML effect nodes are 1-indexed. - return pEffectSlot->getEffectButtonParameterSlot(parameterNumber - 1); + return pEffectSlot->getEffectParameterSlot(EffectManifestParameter::ParameterType::BUTTON, parameterNumber - 1); } return EffectParameterSlotBasePointer(); } diff --git a/src/widget/weffect.cpp b/src/widget/weffect.cpp index 8754a99987d..294762baf6d 100644 --- a/src/widget/weffect.cpp +++ b/src/widget/weffect.cpp @@ -14,10 +14,8 @@ WEffect::WEffect(QWidget* pParent, EffectsManager* pEffectsManager) void WEffect::setup(const QDomNode& node, const SkinContext& context) { WLabel::setup(node, context); // EffectWidgetUtils propagates NULLs so this is all safe. - EffectRackPointer pRack = EffectWidgetUtils::getEffectRackFromNode( - node, context, m_pEffectsManager); EffectChainSlotPointer pChainSlot = EffectWidgetUtils::getEffectChainSlotFromNode( - node, context, pRack); + node, context, m_pEffectsManager); EffectSlotPointer pEffectSlot = EffectWidgetUtils::getEffectSlotFromNode( node, context, pChainSlot); if (pEffectSlot) { @@ -31,7 +29,7 @@ void WEffect::setup(const QDomNode& node, const SkinContext& context) { void WEffect::setEffectSlot(EffectSlotPointer pEffectSlot) { if (pEffectSlot) { m_pEffectSlot = pEffectSlot; - connect(pEffectSlot.data(), SIGNAL(updated()), + connect(pEffectSlot.data(), SIGNAL(effectChanged()), this, SLOT(effectUpdated())); effectUpdated(); } @@ -40,14 +38,11 @@ void WEffect::setEffectSlot(EffectSlotPointer pEffectSlot) { void WEffect::effectUpdated() { QString name; QString description; - if (m_pEffectSlot) { - EffectPointer pEffect = m_pEffectSlot->getEffect(); - if (pEffect) { - EffectManifestPointer pManifest = pEffect->getManifest(); - name = pManifest->displayName(); - //: %1 = effect name; %2 = effect description - description = tr("%1: %2").arg(pManifest->name(), pManifest->description()); - } + if (m_pEffectSlot && m_pEffectSlot->isLoaded()) { + EffectManifestPointer pManifest = m_pEffectSlot->getManifest(); + name = pManifest->displayName(); + //: %1 = effect name; %2 = effect description + description = tr("%1: %2").arg(pManifest->name(), pManifest->description()); } else { name = tr("None"); description = tr("No effect loaded."); diff --git a/src/widget/weffectbuttonparameter.cpp b/src/widget/weffectbuttonparameter.cpp index c7847447647..f9ccfc64b3f 100644 --- a/src/widget/weffectbuttonparameter.cpp +++ b/src/widget/weffectbuttonparameter.cpp @@ -11,17 +11,15 @@ WEffectButtonParameter::WEffectButtonParameter(QWidget* pParent, EffectsManager* void WEffectButtonParameter::setup(const QDomNode& node, const SkinContext& context) { WLabel::setup(node, context); // EffectWidgetUtils propagates NULLs so this is all safe. - EffectRackPointer pRack = EffectWidgetUtils::getEffectRackFromNode( - node, context, m_pEffectsManager); EffectChainSlotPointer pChainSlot = EffectWidgetUtils::getEffectChainSlotFromNode( - node, context, pRack); + node, context, m_pEffectsManager); EffectSlotPointer pEffectSlot = EffectWidgetUtils::getEffectSlotFromNode( node, context, pChainSlot); EffectParameterSlotBasePointer pParameterSlot = EffectWidgetUtils::getButtonParameterSlotFromNode( node, context, pEffectSlot); if (pParameterSlot) { - setEffectParameterSlot(pParameterSlot); + setEffectKnobParameterSlot(pParameterSlot); } else { SKIN_WARNING(node, context) << "EffectButtonParameter node could not attach to effect parameter"; diff --git a/src/widget/weffectchain.cpp b/src/widget/weffectchain.cpp index cf6ccda72a7..b0441779c87 100644 --- a/src/widget/weffectchain.cpp +++ b/src/widget/weffectchain.cpp @@ -13,10 +13,8 @@ WEffectChain::WEffectChain(QWidget* pParent, EffectsManager* pEffectsManager) void WEffectChain::setup(const QDomNode& node, const SkinContext& context) { WLabel::setup(node, context); // EffectWidgetUtils propagates NULLs so this is all safe. - EffectRackPointer pRack = EffectWidgetUtils::getEffectRackFromNode( - node, context, m_pEffectsManager); EffectChainSlotPointer pChainSlot = EffectWidgetUtils::getEffectChainSlotFromNode( - node, context, pRack); + node, context, m_pEffectsManager); if (pChainSlot) { setEffectChainSlot(pChainSlot); } else { @@ -35,14 +33,12 @@ void WEffectChain::setEffectChainSlot(EffectChainSlotPointer pEffectChainSlot) { } void WEffectChain::chainUpdated() { + // qDebug() << "chainUpdated()"; QString name = tr("None"); QString description = tr("No effect chain loaded."); if (m_pEffectChainSlot) { - EffectChainPointer pChain = m_pEffectChainSlot->getEffectChain(); - if (pChain) { - name = pChain->name(); - description = pChain->description(); - } + name = m_pEffectChainSlot->name(); + description = m_pEffectChainSlot->description(); } setText(name); setBaseTooltip(description); diff --git a/src/widget/weffectparameter.cpp b/src/widget/weffectparameter.cpp index 4d4a22faf3f..ee9515eb40d 100644 --- a/src/widget/weffectparameter.cpp +++ b/src/widget/weffectparameter.cpp @@ -11,17 +11,15 @@ WEffectParameter::WEffectParameter(QWidget* pParent, EffectsManager* pEffectsMan void WEffectParameter::setup(const QDomNode& node, const SkinContext& context) { WLabel::setup(node, context); // EffectWidgetUtils propagates NULLs so this is all safe. - EffectRackPointer pRack = EffectWidgetUtils::getEffectRackFromNode( - node, context, m_pEffectsManager); EffectChainSlotPointer pChainSlot = EffectWidgetUtils::getEffectChainSlotFromNode( - node, context, pRack); + node, context, m_pEffectsManager); EffectSlotPointer pEffectSlot = EffectWidgetUtils::getEffectSlotFromNode( node, context, pChainSlot); EffectParameterSlotBasePointer pParameterSlot = EffectWidgetUtils::getParameterSlotFromNode( node, context, pEffectSlot); if (pParameterSlot) { - setEffectParameterSlot(pParameterSlot); + setEffectKnobParameterSlot(pParameterSlot); } else { SKIN_WARNING(node, context) << "EffectParameter node could not attach to effect parameter"; diff --git a/src/widget/weffectparameterbase.cpp b/src/widget/weffectparameterbase.cpp index f2b46be289d..9c52ea716e6 100644 --- a/src/widget/weffectparameterbase.cpp +++ b/src/widget/weffectparameterbase.cpp @@ -9,9 +9,9 @@ WEffectParameterBase::WEffectParameterBase(QWidget* pParent, EffectsManager* pEf parameterUpdated(); } -void WEffectParameterBase::setEffectParameterSlot( - EffectParameterSlotBasePointer pEffectParameterSlot) { - m_pEffectParameterSlot = pEffectParameterSlot; +void WEffectParameterBase::setEffectKnobParameterSlot( + EffectParameterSlotBasePointer pEffectKnobParameterSlot) { + m_pEffectParameterSlot = pEffectKnobParameterSlot; if (m_pEffectParameterSlot) { connect(m_pEffectParameterSlot.data(), SIGNAL(updated()), this, SLOT(parameterUpdated())); diff --git a/src/widget/weffectparameterbase.h b/src/widget/weffectparameterbase.h index 2b6c9497e22..d14f1bae72a 100644 --- a/src/widget/weffectparameterbase.h +++ b/src/widget/weffectparameterbase.h @@ -20,9 +20,9 @@ class WEffectParameterBase : public WLabel { void parameterUpdated(); protected: - // Set the EffectParameterSlot that should be monitored by this + // Set the EffectKnobParameterSlot that should be monitored by this // WEffectParameterBase. - void setEffectParameterSlot(EffectParameterSlotBasePointer pEffectParameterSlot); + void setEffectKnobParameterSlot(EffectParameterSlotBasePointer pEffectKnobParameterSlot); EffectsManager* m_pEffectsManager; EffectParameterSlotBasePointer m_pEffectParameterSlot; diff --git a/src/widget/weffectparameterknob.cpp b/src/widget/weffectparameterknob.cpp index aafd7a6c217..d32a1f705cf 100644 --- a/src/widget/weffectparameterknob.cpp +++ b/src/widget/weffectparameterknob.cpp @@ -2,18 +2,18 @@ #include "widget/weffectparameterknob.h" void WEffectParameterKnob::setupEffectParameterSlot(const ConfigKey& configKey) { - EffectParameterSlotPointer pParameterSlot = - m_pEffectsManager->getEffectParameterSlot(configKey); + EffectParameterSlotBasePointer pParameterSlot = + m_pEffectsManager->getEffectParameterSlot(EffectManifestParameter::ParameterType::KNOB, configKey); if (!pParameterSlot) { qWarning() << "EffectParameterKnob" << configKey << "is not an effect parameter."; return; } - setEffectParameterSlot(pParameterSlot); + setEffectKnobParameterSlot(pParameterSlot); } -void WEffectParameterKnob::setEffectParameterSlot( - EffectParameterSlotPointer pParameterSlot) { +void WEffectParameterKnob::setEffectKnobParameterSlot( + EffectParameterSlotBasePointer pParameterSlot) { m_pEffectParameterSlot = pParameterSlot; if (m_pEffectParameterSlot) { connect(m_pEffectParameterSlot.data(), SIGNAL(updated()), diff --git a/src/widget/weffectparameterknob.h b/src/widget/weffectparameterknob.h index 6fdeaf8afe3..460fbcfd1bb 100644 --- a/src/widget/weffectparameterknob.h +++ b/src/widget/weffectparameterknob.h @@ -2,7 +2,9 @@ #define WEFFECTKNOB_H #include "widget/wknob.h" -#include "effects/effectparameterslot.h" +#include "effects/effectknobparameterslot.h" + +class EffectsManager; // This is used for effect parameter knobs with dynamic // tooltips, if the knob value is displayed by one of e.g. @@ -23,9 +25,9 @@ class WEffectParameterKnob : public WKnob { void parameterUpdated(); private: - // Set the EffectParameterSlot that should be monitored by this + // Set the EffectKnobParameterSlot that should be monitored by this // WEffectKnobComposed. - void setEffectParameterSlot(EffectParameterSlotPointer pParameterSlot); + void setEffectKnobParameterSlot(EffectParameterSlotBasePointer pParameterSlot); EffectsManager* m_pEffectsManager; EffectParameterSlotBasePointer m_pEffectParameterSlot; diff --git a/src/widget/weffectparameterknobcomposed.cpp b/src/widget/weffectparameterknobcomposed.cpp index 92be02f01e3..8a839a7fa69 100644 --- a/src/widget/weffectparameterknobcomposed.cpp +++ b/src/widget/weffectparameterknobcomposed.cpp @@ -7,18 +7,18 @@ const QString groupClose = "]"; } // anonymous namespace void WEffectParameterKnobComposed::setupEffectParameterSlot(const ConfigKey& configKey) { - EffectParameterSlotPointer pParameterSlot = - m_pEffectsManager->getEffectParameterSlot(configKey); + EffectParameterSlotBasePointer pParameterSlot = + m_pEffectsManager->getEffectParameterSlot(EffectManifestParameter::ParameterType::KNOB, configKey); if (!pParameterSlot) { qWarning() << "EffectParameterKnobComposed" << configKey << "is not an effect parameter."; return; } - setEffectParameterSlot(pParameterSlot); + setEffectKnobParameterSlot(pParameterSlot); } -void WEffectParameterKnobComposed::setEffectParameterSlot( - EffectParameterSlotPointer pParameterSlot) { +void WEffectParameterKnobComposed::setEffectKnobParameterSlot( + EffectParameterSlotBasePointer pParameterSlot) { m_pEffectParameterSlot = pParameterSlot; if (m_pEffectParameterSlot) { connect(m_pEffectParameterSlot.data(), SIGNAL(updated()), diff --git a/src/widget/weffectparameterknobcomposed.h b/src/widget/weffectparameterknobcomposed.h index 4449ffccfec..00471a83f44 100644 --- a/src/widget/weffectparameterknobcomposed.h +++ b/src/widget/weffectparameterknobcomposed.h @@ -2,7 +2,9 @@ #define WEFFECTKNOBCOMPOSED_H #include "widget/wknobcomposed.h" -#include "effects/effectparameterslot.h" +#include "effects/effectknobparameterslot.h" + +class EffectsManager; // This is used for effect parameter knobs with dynamic // tooltips, if the knob value is displayed by rotating a @@ -24,9 +26,9 @@ class WEffectParameterKnobComposed : public WKnobComposed { void parameterUpdated(); private: - // Set the EffectParameterSlot that should be monitored by this + // Set the EffectKnobParameterSlot that should be monitored by this // WEffectKnobComposed. - void setEffectParameterSlot(EffectParameterSlotPointer pParameterSlot); + void setEffectKnobParameterSlot(EffectParameterSlotBasePointer pParameterSlot); EffectsManager* m_pEffectsManager; EffectParameterSlotBasePointer m_pEffectParameterSlot; diff --git a/src/widget/weffectpushbutton.cpp b/src/widget/weffectpushbutton.cpp index 5ef08375a29..f9e57ada0a6 100644 --- a/src/widget/weffectpushbutton.cpp +++ b/src/widget/weffectpushbutton.cpp @@ -20,18 +20,18 @@ void WEffectPushButton::setup(const QDomNode& node, const SkinContext& context) } void WEffectPushButton::setupEffectParameterSlot(const ConfigKey& configKey) { - EffectButtonParameterSlotPointer pParameterSlot = - m_pEffectsManager->getEffectButtonParameterSlot(configKey); + EffectParameterSlotBasePointer pParameterSlot = + m_pEffectsManager->getEffectParameterSlot(EffectManifestParameter::ParameterType::BUTTON, configKey); if (!pParameterSlot) { qWarning() << "EffectPushButton" << configKey << "is not an effect button parameter."; return; } - setEffectParameterSlot(pParameterSlot); + setEffectKnobParameterSlot(pParameterSlot); } -void WEffectPushButton::setEffectParameterSlot( - EffectButtonParameterSlotPointer pParameterSlot) { +void WEffectPushButton::setEffectKnobParameterSlot( + EffectParameterSlotBasePointer pParameterSlot) { m_pEffectParameterSlot = pParameterSlot; if (m_pEffectParameterSlot) { connect(m_pEffectParameterSlot.data(), SIGNAL(updated()), diff --git a/src/widget/weffectpushbutton.h b/src/widget/weffectpushbutton.h index 595486f8f01..85747e0601b 100644 --- a/src/widget/weffectpushbutton.h +++ b/src/widget/weffectpushbutton.h @@ -32,9 +32,9 @@ class WEffectPushButton : public WPushButton { void slotActionChosen(QAction* action); private: - // Set the EffectParameterSlot that should be monitored by this + // Set the EffectKnobParameterSlot that should be monitored by this // WEffectKnobComposed. - void setEffectParameterSlot(EffectButtonParameterSlotPointer pParameterSlot); + void setEffectKnobParameterSlot(EffectParameterSlotBasePointer pParameterSlot); EffectsManager* m_pEffectsManager; diff --git a/src/widget/weffectselector.cpp b/src/widget/weffectselector.cpp index 11aaf2f330c..558f33ba806 100644 --- a/src/widget/weffectselector.cpp +++ b/src/widget/weffectselector.cpp @@ -19,19 +19,17 @@ void WEffectSelector::setup(const QDomNode& node, const SkinContext& context) { m_scaleFactor = context.getScaleFactor(); // EffectWidgetUtils propagates NULLs so this is all safe. - m_pRack = EffectWidgetUtils::getEffectRackFromNode( - node, context, m_pEffectsManager); m_pChainSlot = EffectWidgetUtils::getEffectChainSlotFromNode( - node, context, m_pRack); + node, context, m_pEffectsManager); m_pEffectSlot = EffectWidgetUtils::getEffectSlotFromNode( node, context, m_pChainSlot); if (m_pEffectSlot != nullptr) { connect(m_pEffectsManager, SIGNAL(visibleEffectsUpdated()), this, SLOT(populate())); - connect(m_pEffectSlot.data(), SIGNAL(updated()), + connect(m_pEffectSlot.data(), SIGNAL(effectChanged()), this, SLOT(slotEffectUpdated())); - connect(this, SIGNAL(currentIndexChanged(int)), + connect(this, SIGNAL(activated(int)), this, SLOT(slotEffectSelected(int))); } else { SKIN_WARNING(node, context) @@ -55,7 +53,7 @@ void WEffectSelector::populate() { QString elidedDisplayName = metrics.elidedText(pManifest->displayName(), Qt::ElideMiddle, width() - 2); - addItem(elidedDisplayName, QVariant(pManifest->id())); + addItem(elidedDisplayName, QVariant(pManifest->uniqueId())); // NOTE(Be): Using \n instead of : as the separator does not work in // QComboBox item tooltips. @@ -78,12 +76,14 @@ void WEffectSelector::populate() { } void WEffectSelector::slotEffectSelected(int newIndex) { - const QString id = itemData(newIndex).toString(); + const EffectManifestPointer pManifest = + m_pEffectsManager->getManifestFromUniqueId( + itemData(newIndex).toString()); - m_pRack->maybeLoadEffect( - m_pChainSlot->getChainSlotNumber(), + m_pEffectsManager->loadEffect( + m_pChainSlot, m_pEffectSlot->getEffectSlotNumber(), - id); + pManifest); setBaseTooltip(itemData(newIndex, Qt::ToolTipRole).toString()); } @@ -92,10 +92,9 @@ void WEffectSelector::slotEffectUpdated() { int newIndex; if (m_pEffectSlot != nullptr) { - EffectPointer pEffect = m_pEffectSlot->getEffect(); - if (pEffect != nullptr) { - EffectManifestPointer pManifest = pEffect->getManifest(); - newIndex = findData(QVariant(pManifest->id())); + if (m_pEffectSlot->getManifest() != nullptr) { + EffectManifestPointer pManifest = m_pEffectSlot->getManifest(); + newIndex = findData(QVariant(pManifest->uniqueId())); } else { newIndex = findData(QVariant()); } @@ -103,6 +102,12 @@ void WEffectSelector::slotEffectUpdated() { newIndex = findData(QVariant()); } + if (kEffectDebugOutput) { + qDebug() << "WEffectSelector::slotEffectUpdated" + << "old" << itemData(currentIndex()) + << "new" << itemData(newIndex); + } + if (newIndex != -1 && newIndex != currentIndex()) { setCurrentIndex(newIndex); setBaseTooltip(itemData(newIndex, Qt::ToolTipRole).toString()); diff --git a/src/widget/weffectselector.h b/src/widget/weffectselector.h index a9816f62f2f..26474849198 100644 --- a/src/widget/weffectselector.h +++ b/src/widget/weffectselector.h @@ -3,7 +3,6 @@ #include #include -#include "effects/effectrack.h" #include "effects/effectslot.h" #include "skin/skincontext.h" @@ -28,7 +27,6 @@ class WEffectSelector : public QComboBox, public WBaseWidget { EffectsManager* m_pEffectsManager; EffectSlotPointer m_pEffectSlot; EffectChainSlotPointer m_pChainSlot; - EffectRackPointer m_pRack; double m_scaleFactor; };