diff --git a/CMakeLists.txt b/CMakeLists.txt
index 2927b28c1015..2df00dae6e56 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -527,41 +527,51 @@ add_library(mixxx-lib STATIC EXCLUDE_FROM_ALL
src/dialog/dlgkeywheel.ui
src/dialog/dlgreplacecuecolor.cpp
src/dialog/dlgreplacecuecolordlg.ui
- src/effects/builtin/autopaneffect.cpp
- src/effects/builtin/balanceeffect.cpp
- src/effects/builtin/bessel4lvmixeqeffect.cpp
- src/effects/builtin/bessel8lvmixeqeffect.cpp
- src/effects/builtin/biquadfullkilleqeffect.cpp
- src/effects/builtin/bitcrushereffect.cpp
- src/effects/builtin/builtinbackend.cpp
- src/effects/builtin/echoeffect.cpp
- src/effects/builtin/filtereffect.cpp
- src/effects/builtin/flangereffect.cpp
- src/effects/builtin/graphiceqeffect.cpp
- src/effects/builtin/linkwitzriley8eqeffect.cpp
- src/effects/builtin/loudnesscontoureffect.cpp
- src/effects/builtin/metronomeeffect.cpp
- src/effects/builtin/whitenoiseeffect.cpp
- src/effects/builtin/moogladder4filtereffect.cpp
- src/effects/builtin/parametriceqeffect.cpp
- src/effects/builtin/phasereffect.cpp
- src/effects/builtin/reverbeffect.cpp
- src/effects/builtin/threebandbiquadeqeffect.cpp
- src/effects/builtin/tremoloeffect.cpp
- src/effects/effect.cpp
src/effects/effectbuttonparameterslot.cpp
src/effects/effectchain.cpp
- src/effects/effectchainmanager.cpp
- src/effects/effectchainslot.cpp
- src/effects/effectmanifest.cpp
- src/effects/effectmanifestparameter.cpp
+ src/effects/effectchainmixmode.cpp
src/effects/effectparameter.cpp
- src/effects/effectparameterslot.cpp
+ src/effects/effectknobparameterslot.cpp
src/effects/effectparameterslotbase.cpp
- src/effects/effectrack.cpp
- src/effects/effectsbackend.cpp
src/effects/effectslot.cpp
src/effects/effectsmanager.cpp
+ src/effects/effectsmessenger.cpp
+ src/effects/visibleeffectslist.cpp
+ src/effects/backends/effectsbackend.cpp
+ src/effects/backends/effectmanifest.cpp
+ src/effects/backends/effectmanifestparameter.cpp
+ src/effects/backends/builtin/autopaneffect.cpp
+ src/effects/backends/builtin/balanceeffect.cpp
+ src/effects/backends/builtin/bessel4lvmixeqeffect.cpp
+ src/effects/backends/builtin/bessel8lvmixeqeffect.cpp
+ src/effects/backends/builtin/biquadfullkilleqeffect.cpp
+ src/effects/backends/builtin/bitcrushereffect.cpp
+ src/effects/backends/builtin/builtinbackend.cpp
+ src/effects/backends/builtin/echoeffect.cpp
+ src/effects/backends/builtin/filtereffect.cpp
+ src/effects/backends/builtin/flangereffect.cpp
+ src/effects/backends/builtin/graphiceqeffect.cpp
+ src/effects/backends/builtin/linkwitzriley8eqeffect.cpp
+ src/effects/backends/builtin/loudnesscontoureffect.cpp
+ src/effects/backends/builtin/metronomeeffect.cpp
+ src/effects/backends/builtin/moogladder4filtereffect.cpp
+ src/effects/backends/builtin/parametriceqeffect.cpp
+ src/effects/backends/builtin/phasereffect.cpp
+ src/effects/backends/builtin/reverbeffect.cpp
+ src/effects/backends/builtin/threebandbiquadeqeffect.cpp
+ src/effects/backends/builtin/tremoloeffect.cpp
+ src/effects/backends/builtin/whitenoiseeffect.cpp
+ src/effects/backends/effectsbackendmanager.cpp
+ src/effects/chains/equalizereffectchain.cpp
+ src/effects/chains/outputeffectchain.cpp
+ src/effects/chains/pergroupeffectchain.cpp
+ src/effects/chains/quickeffectchain.cpp
+ src/effects/chains/standardeffectchain.cpp
+ src/effects/presets/effectchainpreset.cpp
+ src/effects/presets/effectchainpresetmanager.cpp
+ src/effects/presets/effectparameterpreset.cpp
+ src/effects/presets/effectpreset.cpp
+ src/effects/presets/effectpresetmanager.cpp
src/encoder/encoder.cpp
src/encoder/encoderfdkaac.cpp
src/encoder/encoderfdkaacsettings.cpp
@@ -595,7 +605,6 @@ add_library(mixxx-lib STATIC EXCLUDE_FROM_ALL
src/engine/controls/ratecontrol.cpp
src/engine/effects/engineeffect.cpp
src/engine/effects/engineeffectchain.cpp
- src/engine/effects/engineeffectrack.cpp
src/engine/effects/engineeffectsmanager.cpp
src/engine/enginebuffer.cpp
src/engine/enginedelay.cpp
@@ -756,7 +765,6 @@ add_library(mixxx-lib STATIC EXCLUDE_FROM_ALL
src/preferences/dialog/dlgprefkeydlg.ui
src/preferences/dialog/dlgpreflibrary.cpp
src/preferences/dialog/dlgpreflibrarydlg.ui
- src/preferences/dialog/dlgpreflv2dlg.ui
src/preferences/dialog/dlgprefrecord.cpp
src/preferences/dialog/dlgprefrecorddlg.ui
src/preferences/dialog/dlgprefreplaygain.cpp
@@ -768,7 +776,8 @@ add_library(mixxx-lib STATIC EXCLUDE_FROM_ALL
src/preferences/dialog/dlgprefvinyldlg.ui
src/preferences/dialog/dlgprefwaveform.cpp
src/preferences/dialog/dlgprefwaveformdlg.ui
- src/preferences/effectsettingsmodel.cpp
+ src/preferences/effectchainpresetlistmodel.cpp
+ src/preferences/effectmanifesttablemodel.cpp
src/preferences/colorpaletteeditor.cpp
src/preferences/colorpaletteeditormodel.cpp
src/preferences/colorpalettesettings.cpp
@@ -870,6 +879,7 @@ add_library(mixxx-lib STATIC EXCLUDE_FROM_ALL
src/util/experiment.cpp
src/util/fileaccess.cpp
src/util/fileinfo.cpp
+ src/util/filename.cpp
src/util/imageutils.cpp
src/util/indexrange.cpp
src/util/logger.cpp
@@ -1008,13 +1018,15 @@ if(NOT QT6)
src/widget/wcoverartmenu.cpp
src/widget/wcuemenupopup.cpp
src/widget/wdisplay.cpp
- src/widget/weffect.cpp
- src/widget/weffectbuttonparameter.cpp
+ src/widget/weffectbuttonparametername.cpp
src/widget/weffectchain.cpp
- src/widget/weffectparameter.cpp
- src/widget/weffectparameterbase.cpp
+ src/widget/weffectchainpresetbutton.cpp
+ src/widget/weffectchainpresetselector.cpp
+ src/widget/weffectknobparametername.cpp
+ src/widget/weffectname.cpp
src/widget/weffectparameterknob.cpp
src/widget/weffectparameterknobcomposed.cpp
+ src/widget/weffectparameternamebase.cpp
src/widget/weffectpushbutton.cpp
src/widget/weffectselector.cpp
src/widget/whotcuebutton.cpp
@@ -1350,6 +1362,14 @@ install(
"${MIXXX_INSTALL_DATADIR}"
)
+# Effect presets
+install(
+ DIRECTORY
+ "${CMAKE_CURRENT_SOURCE_DIR}/res/effects"
+ DESTINATION
+ "${MIXXX_INSTALL_DATADIR}"
+)
+
# Translation files
install(
DIRECTORY
@@ -1554,7 +1574,6 @@ add_executable(mixxx-test
src/test/analyzersilence_test.cpp
src/test/audiotaperpot_test.cpp
src/test/autodjprocessor_test.cpp
- src/test/baseeffecttest.cpp
src/test/beatgridtest.cpp
src/test/beatmaptest.cpp
src/test/beatstranslatetest.cpp
@@ -1582,9 +1601,8 @@ add_executable(mixxx-test
src/test/directorydaotest.cpp
src/test/duration_test.cpp
src/test/durationutiltest.cpp
- src/test/effectchainslottest.cpp
- src/test/effectslottest.cpp
- src/test/effectsmanagertest.cpp
+ #TODO: write useful tests for refactored effects system
+ #src/test/effectchainslottest.cpp
src/test/enginebufferscalelineartest.cpp
src/test/enginebuffertest.cpp
src/test/enginefilterbiquadtest.cpp
@@ -1606,7 +1624,8 @@ add_executable(mixxx-test
src/test/main.cpp
src/test/mathutiltest.cpp
src/test/metadatatest.cpp
- src/test/metaknob_link_test.cpp
+ #TODO: make this build again
+ #src/test/metaknob_link_test.cpp
src/test/midicontrollertest.cpp
src/test/mixxxtest.cpp
src/test/movinginterquartilemean_test.cpp
@@ -2580,10 +2599,9 @@ if(LILV)
message(FATAL_ERROR "Lilv (LV2) support requires the liblilv-0 and its development headers.")
endif()
target_sources(mixxx-lib PRIVATE
- src/effects/lv2/lv2backend.cpp
- src/effects/lv2/lv2effectprocessor.cpp
- src/effects/lv2/lv2manifest.cpp
- src/preferences/dialog/dlgpreflv2.cpp
+ src/effects/backends/lv2/lv2backend.cpp
+ src/effects/backends/lv2/lv2effectprocessor.cpp
+ src/effects/backends/lv2/lv2manifest.cpp
)
target_compile_definitions(mixxx-lib PUBLIC __LILV__)
target_link_libraries(mixxx-lib PRIVATE lilv::lilv)
diff --git a/res/effects/chains/Echoverb HP.xml b/res/effects/chains/Echoverb HP.xml
new file mode 100644
index 000000000000..7c9a8db2b1f0
--- /dev/null
+++ b/res/effects/chains/Echoverb HP.xml
@@ -0,0 +1,142 @@
+
+
+ Echoverb HP
+ DRY+WET
+ 0
+
+
+ 0
+ org.mixxx.effects.threebandbiquadeq
+ Built-In
+
+
+ low
+ 0.34375
+ NONE
+ 0
+ 0
+
+
+ mid
+ 1
+ NONE
+ 0
+ 0
+
+
+ high
+ 1
+ NONE
+ 0
+ 0
+
+
+ killLow
+ 0
+ NONE
+ 0
+ 0
+
+
+ killMid
+ 0
+ NONE
+ 0
+ 0
+
+
+ killHigh
+ 0
+ NONE
+ 0
+ 0
+
+
+
+
+ 0
+ org.mixxx.effects.echo
+ Built-In
+
+
+ delay_time
+ 0.5
+ NONE
+ 0
+ 0
+
+
+ feedback_amount
+ 0.707946
+ NONE
+ 0
+ 0
+
+
+ pingpong_amount
+ 0
+ NONE
+ 0
+ 0
+
+
+ send_amount
+ 0
+ LINKED
+ 0
+ 0
+
+
+ quantize
+ 1
+ NONE
+ 0
+ 0
+
+
+ triplet
+ 0
+ NONE
+ 0
+ 0
+
+
+
+
+ 0
+ org.mixxx.effects.reverb
+ Built-In
+
+
+ decay
+ 0.5
+ NONE
+ 0
+ 0
+
+
+ bandwidth
+ 1
+ NONE
+ 0
+ 0
+
+
+ damping
+ 0.277905
+ NONE
+ 0
+ 0
+
+
+ send_amount
+ 1
+ NONE
+ 0
+ 0
+
+
+
+
+
+
diff --git a/res/effects/chains/Filter Echo.xml b/res/effects/chains/Filter Echo.xml
new file mode 100644
index 000000000000..5dc15ccfa8c0
--- /dev/null
+++ b/res/effects/chains/Filter Echo.xml
@@ -0,0 +1,87 @@
+
+
+ Filter Echo
+ DRY/WET
+ 0.5
+
+
+ 0.5
+ org.mixxx.effects.filter
+ Built-In
+
+
+ lpf
+ 22050
+ LINKED_LEFT
+ 0
+ 0
+
+
+ q
+ 0.707107
+ NONE
+ 0
+ 0
+
+
+ hpf
+ 13
+ LINKED_RIGHT
+ 0
+ 0
+
+
+
+
+ 0.5
+ org.mixxx.effects.echo
+ Built-In
+
+
+ delay_time
+ 1.0
+ NONE
+ 0
+ 0
+
+
+ feedback_amount
+ 0.707946
+ NONE
+ 0
+ 0
+
+
+ pingpong_amount
+ 0
+ NONE
+ 0
+ 0
+
+
+ send_amount
+ 0
+ LINKED_LEFT_RIGHT
+ 0
+ 0
+
+
+ quantize
+ 1
+ NONE
+ 0
+ 0
+
+
+ triplet
+ 0
+ NONE
+ 0
+ 0
+
+
+
+
+
+
+
diff --git a/res/effects/chains/Mid-Side.xml b/res/effects/chains/Mid-Side.xml
new file mode 100644
index 000000000000..2c7735b6fc66
--- /dev/null
+++ b/res/effects/chains/Mid-Side.xml
@@ -0,0 +1,39 @@
+
+
+ Mid/Side
+ DRY/WET
+ 0.5
+
+
+ 0.5
+ org.mixxx.effects.balance
+ Built-In
+
+
+ balance
+ 0
+ NONE
+ 0
+ 0
+
+
+ midSide
+ 0
+ LINKED
+ 0
+ 0
+
+
+ bypassFreq
+ 16
+ NONE
+ 0
+ 0
+
+
+
+
+
+
+
+
diff --git a/res/effects/chains/Side Reverb HP.xml b/res/effects/chains/Side Reverb HP.xml
new file mode 100644
index 000000000000..ba39975e88e3
--- /dev/null
+++ b/res/effects/chains/Side Reverb HP.xml
@@ -0,0 +1,121 @@
+
+
+ Side Reverb HP
+ DRY+WET
+ 0
+
+
+ 0
+ org.mixxx.effects.threebandbiquadeq
+ Built-In
+
+
+ low
+ 0.28125
+ NONE
+ 0
+ 0
+
+
+ mid
+ 0.96875
+ NONE
+ 0
+ 0
+
+
+ high
+ 0.984375
+ NONE
+ 0
+ 0
+
+
+ killLow
+ 0
+ NONE
+ 0
+ 0
+
+
+ killMid
+ 0
+ NONE
+ 0
+ 0
+
+
+ killHigh
+ 0
+ NONE
+ 0
+ 0
+
+
+
+
+ 0
+ org.mixxx.effects.reverb
+ Built-In
+
+
+ decay
+ 0.690476
+ NONE
+ 0
+ 0
+
+
+ bandwidth
+ 1
+ NONE
+ 0
+ 0
+
+
+ damping
+ 0.15625
+ NONE
+ 0
+ 0
+
+
+ send_amount
+ 0
+ LINKED
+ 0
+ 0
+
+
+
+
+ 0
+ org.mixxx.effects.balance
+ Built-In
+
+
+ balance
+ -0.015625
+ NONE
+ 0
+ 0
+
+
+ midSide
+ 0.508312
+ NONE
+ 0
+ 0
+
+
+ bypassFreq
+ 26.0248
+ NONE
+ 0
+ 0
+
+
+
+
+
+
diff --git a/res/effects/chains/Smooth Growl.xml b/res/effects/chains/Smooth Growl.xml
new file mode 100644
index 000000000000..6f8ef6145817
--- /dev/null
+++ b/res/effects/chains/Smooth Growl.xml
@@ -0,0 +1,107 @@
+
+
+ Smooth Growl
+ DRY/WET
+ 0
+
+
+ 0
+ org.mixxx.effects.bitcrusher
+ Built-In
+
+
+ bit_depth
+ 16
+ LINKED
+ 1
+ 0
+
+
+ downsample
+ 1
+ LINKED
+ 1
+ 0
+
+
+
+
+ 0
+ org.mixxx.effects.moogladder4filter
+ Built-In
+
+
+ lpf
+ 0.5
+ LINKED
+ 1
+ 0
+
+
+ resonance
+ 1.54534
+ NONE
+ 0
+ 0
+
+
+ hpf
+ 0.0003
+ NONE
+ 0
+ 0
+
+
+
+
+ 0
+ org.mixxx.effects.echo
+ Built-In
+
+
+ delay_time
+ 0.996914
+ NONE
+ 0
+ 0
+
+
+ feedback_amount
+ 0.707946
+ NONE
+ 0
+ 0
+
+
+ pingpong_amount
+ 0.169252
+ NONE
+ 0
+ 0
+
+
+ send_amount
+ 0
+ LINKED
+ 0
+ 0
+
+
+ quantize
+ 1
+ NONE
+ 0
+ 0
+
+
+ triplet
+ 0
+ NONE
+ 0
+ 0
+
+
+
+
+
+
diff --git a/res/qml/EffectSlot.qml b/res/qml/EffectSlot.qml
index f3004d376bab..da767a616bff 100644
--- a/res/qml/EffectSlot.qml
+++ b/res/qml/EffectSlot.qml
@@ -6,7 +6,7 @@ import "Theme"
Item {
id: root
- property Mixxx.EffectSlotProxy slot: Mixxx.EffectsManager.getEffectSlot(1, unitNumber, effectNumber)
+ property Mixxx.EffectSlotProxy slot: Mixxx.EffectsManager.getEffectSlot(unitNumber, effectNumber)
property int unitNumber // required
property int effectNumber // required
property bool expanded: false
@@ -111,8 +111,8 @@ Item {
// TODO: Use null coalescing when we switch to Qt >= 5.15
property string label: shortName ? shortName : name
property string key: controlKey
- property bool isButton: controlHint > 0 && controlHint == 6
- property bool isKnob: controlHint > 0 && controlHint < 6
+ property bool isKnob: type == 0
+ property bool isButton: type == 1
width: 50
height: 50
diff --git a/res/skins/Deere/effect_parameter_button.xml b/res/skins/Deere/effect_parameter_button.xml
index 220679253bef..0a65466d64ee 100644
--- a/res/skins/Deere/effect_parameter_button.xml
+++ b/res/skins/Deere/effect_parameter_button.xml
@@ -9,6 +9,7 @@
EffectButtonParameter: the button parameter
-->
+ [EffectRack_EffectUnit]
vertical
EffectButtonParameter
@@ -21,6 +22,9 @@
58,15
me,f
EffectButton
+
+
+
2
0
diff --git a/res/skins/Deere/effect_parameter_knob.xml b/res/skins/Deere/effect_parameter_knob.xml
index 2ca30c558520..2f73f9b44541 100644
--- a/res/skins/Deere/effect_parameter_knob.xml
+++ b/res/skins/Deere/effect_parameter_knob.xml
@@ -9,6 +9,7 @@
EffectParameter: the parameter
-->
+ [EffectRack_EffectUnit]
vertical
34,
@@ -26,6 +27,9 @@
knob_small.svg
-230
50
+
+
+
[EffectRack_EffectUnit_Effect],parameter
diff --git a/res/skins/Deere/equalizer_rack_parameter_left.xml b/res/skins/Deere/equalizer_rack_parameter_left.xml
index d0e67f0f5fe2..ad2df1b208ee 100644
--- a/res/skins/Deere/equalizer_rack_parameter_left.xml
+++ b/res/skins/Deere/equalizer_rack_parameter_left.xml
@@ -24,6 +24,9 @@
15f,20f
EQKillButton
2
+
+
+
0
@@ -63,6 +66,9 @@
-135
135
1.602
+
+
+
,parameter
diff --git a/res/skins/Deere/equalizer_rack_parameter_right.xml b/res/skins/Deere/equalizer_rack_parameter_right.xml
index 2ce0e4087c19..2e33904572b3 100644
--- a/res/skins/Deere/equalizer_rack_parameter_right.xml
+++ b/res/skins/Deere/equalizer_rack_parameter_right.xml
@@ -32,6 +32,9 @@
-135
135
1.602
+
+
+
,parameter
@@ -44,6 +47,9 @@
15f,20f
EQKillButton
2
+
+
+
0
diff --git a/res/skins/Deere/style.qss b/res/skins/Deere/style.qss
index 33e40b8510c8..db763b0ea9ba 100644
--- a/res/skins/Deere/style.qss
+++ b/res/skins/Deere/style.qss
@@ -818,7 +818,7 @@ WTrackMenu,
WTrackMenu QMenu,
WTrackMenu QMenu QCheckBox,
WOverview /* Hotcue labels in the overview */,
-WEffect,
+WEffectName,
WEffectSelector,
WEffectSelector QAbstractScrollArea,
#fadeModeCombobox,
@@ -1230,7 +1230,7 @@ WBeatSpinBox,
qproperty-layoutSpacing: 2;
}
-#EffectMetaKnob, WEffect {
+#EffectMetaKnob, WEffectName {
font-size: 12px;
background-color: none;
border: none;
diff --git a/res/skins/LateNight/fx/parameter_button.xml b/res/skins/LateNight/fx/parameter_button.xml
index 3175bf4448ac..275797f3d110 100644
--- a/res/skins/LateNight/fx/parameter_button.xml
+++ b/res/skins/LateNight/fx/parameter_button.xml
@@ -9,6 +9,7 @@
EffectParameter: the parameter
-->
+ [EffectRack1_EffectUnit]
[_Effect]
@@ -28,6 +29,9 @@
35f,20f
2
false
+
+
+
0
skin://buttons/btn__fx_parameter.svg
@@ -58,8 +62,7 @@
1me,0min
FxButtonLabel
- 1
-
+
center
diff --git a/res/skins/LateNight/fx/parameter_knob.xml b/res/skins/LateNight/fx/parameter_knob.xml
index a8e0f35ba2fc..84ee2aa90875 100644
--- a/res/skins/LateNight/fx/parameter_knob.xml
+++ b/res/skins/LateNight/fx/parameter_knob.xml
@@ -9,6 +9,7 @@
EffectParameter: the parameter
-->
+ [EffectRack1_EffectUnit]
_Effect
@@ -29,6 +30,9 @@
skin://knobs/knob_bg_fx.svg
+
+
+
diff --git a/res/skins/LateNight/mixer/channel_4decks.xml b/res/skins/LateNight/mixer/channel_4decks.xml
index 0754836a817c..9f665a85b032 100644
--- a/res/skins/LateNight/mixer/channel_4decks.xml
+++ b/res/skins/LateNight/mixer/channel_4decks.xml
@@ -1,5 +1,6 @@
[Channel]
+ [EqualizerRack1_]
[EqualizerRack1__Effect1]
regular
diff --git a/res/skins/LateNight/mixer/channel_left.xml b/res/skins/LateNight/mixer/channel_left.xml
index 492ab1f8ad71..a4c08f47a834 100644
--- a/res/skins/LateNight/mixer/channel_left.xml
+++ b/res/skins/LateNight/mixer/channel_left.xml
@@ -3,6 +3,7 @@ vertical layout and a side-by-side layout for two-deck mode -->
[Channel]
+ [EqualizerRack1_]
[EqualizerRack1__Effect1]
regular
diff --git a/res/skins/LateNight/mixer/channel_right.xml b/res/skins/LateNight/mixer/channel_right.xml
index 95b0fe58308e..d49e0d3284b1 100644
--- a/res/skins/LateNight/mixer/channel_right.xml
+++ b/res/skins/LateNight/mixer/channel_right.xml
@@ -3,6 +3,7 @@ vertical layout and a reversed side-by-side layout for two-deck mode -->
[Channel]
+ [EqualizerRack1_]
[EqualizerRack1__Effect1]
regular
diff --git a/res/skins/LateNight/mixer/eq_knob_4decks.xml b/res/skins/LateNight/mixer/eq_knob_4decks.xml
index 3402d5fa9e1b..e048da3acf40 100644
--- a/res/skins/LateNight/mixer/eq_knob_4decks.xml
+++ b/res/skins/LateNight/mixer/eq_knob_4decks.xml
@@ -32,6 +32,9 @@
EQKillButton_
18f,18f
2
+
+ 1
+
0
skin://buttons/btn__eqkill.svg
@@ -81,6 +84,9 @@
1.998
+
+ 1
+
,parameter
diff --git a/res/skins/LateNight/mixer/eq_knob_left.xml b/res/skins/LateNight/mixer/eq_knob_left.xml
index b630f75cdf1c..551f9788f417 100644
--- a/res/skins/LateNight/mixer/eq_knob_left.xml
+++ b/res/skins/LateNight/mixer/eq_knob_left.xml
@@ -23,6 +23,9 @@
EQKillButton_
18f,18f
2
+
+ 1
+
0
skin://buttons/btn__eqkill.svg
@@ -61,6 +64,9 @@
1.998
+
+ 1
+
,parameter
diff --git a/res/skins/LateNight/mixer/eq_knob_right.xml b/res/skins/LateNight/mixer/eq_knob_right.xml
index 4b2082421e56..cb2ed24d2281 100644
--- a/res/skins/LateNight/mixer/eq_knob_right.xml
+++ b/res/skins/LateNight/mixer/eq_knob_right.xml
@@ -27,6 +27,9 @@
1.998
+
+ 1
+
,parameter
@@ -70,6 +73,9 @@
EQKillButton_
18f,18f
2
+
+ 1
+
0
skin://buttons/btn__eqkill.svg
diff --git a/res/skins/LateNight/style.qss b/res/skins/LateNight/style.qss
index b20fc09cb9c5..3d0d17072be1 100644
--- a/res/skins/LateNight/style.qss
+++ b/res/skins/LateNight/style.qss
@@ -19,7 +19,7 @@ WCueMenuPopup,
WCueMenuPopup QLabel,
WCueMenuPopup QLineEdit,
WOverview, /* Hotcue labels in the overview */
-WEffect,
+WEffectName,
WEffectSelector,
WEffectSelector QAbstractScrollArea,
#fadeModeCombobox,
diff --git a/res/skins/Shade/effect_parameter_button.xml b/res/skins/Shade/effect_parameter_button.xml
index a3d5bc249bbc..c330878e682d 100644
--- a/res/skins/Shade/effect_parameter_button.xml
+++ b/res/skins/Shade/effect_parameter_button.xml
@@ -9,59 +9,61 @@
EffectParameter: the parameter
-->
-
- EffectParameterButton
- vertical
- me,f
- 38,45
- 60,45
-
-
-
- right
- ButtonLabel
- 1
-
-
-
-
-
- vertical
- 38,26
-
-
- 2
-
- 0
- skin:/btn/btn_kill_down.png
- skin:/btn/btn_kill.png
-
-
- 1
- skin:/btn/btn_kill_overdown.png
- skin:/btn/btn_kill_over.png
-
- 11,57
-
- [EffectRack1_EffectUnit_Effect],button_parameter
- LeftButton
-
-
-
-
-
-
- [EffectRack1_EffectUnit_Effect],button_parameter_loaded
- visible
-
-
+ background-color: transparent;
+ color: #191F24;
+ padding-left: 1px;
+ }
+ QLabel { qproperty-alignment: AlignCenter; }
+
+ ButtonLabel
+ 1
+
+
+
+
+
+ vertical
+ 38,26
+
+
+
+
+
+ 2
+
+ 0
+ skin:/btn/btn_kill_down.png
+ skin:/btn/btn_kill.png
+
+
+ 1
+ skin:/btn/btn_kill_overdown.png
+ skin:/btn/btn_kill_over.png
+
+ 11,57
+
+ [EffectRack1_EffectUnit_Effect],button_parameter
+ LeftButton
+
+
+
+
+
+
+ [EffectRack1_EffectUnit_Effect],button_parameter_loaded
+ visible
+
+
diff --git a/res/skins/Shade/effect_parameter_knob.xml b/res/skins/Shade/effect_parameter_knob.xml
index 7a64bfefd429..709901caa0df 100644
--- a/res/skins/Shade/effect_parameter_knob.xml
+++ b/res/skins/Shade/effect_parameter_knob.xml
@@ -9,115 +9,115 @@
EffectParameter: the parameter
-->
-
- EffectParameterKnob
- vertical
- me,f
- 38,46
- -1,46
-
-
-
- right
- me,f
- -1,46
- KnobLabel
- 1
-
-
-
-
+ background-color: transparent;
+ color: #191F24;
+ padding-left: 1px;
+ }
+ QLabel { qproperty-alignment: AlignCenter; }
+
+ KnobLabel
+ 1
+
+
+
+
-
- vertical
-
-
- horizontal
-
-
- 64
- knobs_no_center/knob_rotary_s%1.png
-
- [EffectRack1_EffectUnit_Effect],parameter
-
-
-
-
+
+ vertical
+
+
+ horizontal
+
+
+ 64
+ knobs/knob_rotary_s%1.png
+
+
+
+
+ [EffectRack1_EffectUnit_Effect],parameter
+
+
+
+
-
- horizontal
-
+
+ horizontal
+
0min,0min
-
- EffectSlot_parameter_inversion
- 2
-
- 0
- skin:/btn_link_type/btn_link_inversion_off.png
- skin:/btn_link_type/btn_link_inversion_off.png
-
-
- 1
- skin:/btn_link_type/btn_link_inversion_on.png
- skin:/btn_link_type/btn_link_inversion_on.png
-
-
- [EffectRack1_EffectUnit_Effect],parameter_link_inverse
- LeftButton
-
-
-
- EffectSlot_parameter_link_type
- 5
-
- 0
- skin:/btn_link_type/btn_link_type_none.png
- skin:/btn_link_type/btn_link_type_none.png
-
-
- 1
- skin:/btn_link_type/btn_link_type_linked.png
- skin:/btn_link_type/btn_link_type_linked.png
-
-
- 2
- skin:/btn_link_type/btn_link_type_left.png
- skin:/btn_link_type/btn_link_type_left.png
-
-
- 3
- skin:/btn_link_type/btn_link_type_right.png
- skin:/btn_link_type/btn_link_type_right.png
-
-
- 4
- skin:/btn_link_type/btn_link_type_left_right.png
- skin:/btn_link_type/btn_link_type_left_right.png
-
-
- [EffectRack1_EffectUnit_Effect],parameter_link_type
- LeftButton
-
-
+
+ EffectSlot_parameter_inversion
+ 2
+
+ 0
+ skin:/btn_link_type/btn_link_inversion_off.png
+ skin:/btn_link_type/btn_link_inversion_off.png
+
+
+ 1
+ skin:/btn_link_type/btn_link_inversion_on.png
+ skin:/btn_link_type/btn_link_inversion_on.png
+
+
+ [EffectRack1_EffectUnit_Effect],parameter_link_inverse
+ LeftButton
+
+
+
+ EffectSlot_parameter_link_type
+ 5
+
+ 0
+ skin:/btn_link_type/btn_link_type_none.png
+ skin:/btn_link_type/btn_link_type_none.png
+
+
+ 1
+ skin:/btn_link_type/btn_link_type_linked.png
+ skin:/btn_link_type/btn_link_type_linked.png
+
+
+ 2
+ skin:/btn_link_type/btn_link_type_left.png
+ skin:/btn_link_type/btn_link_type_left.png
+
+
+ 3
+ skin:/btn_link_type/btn_link_type_right.png
+ skin:/btn_link_type/btn_link_type_right.png
+
+
+ 4
+ skin:/btn_link_type/btn_link_type_left_right.png
+ skin:/btn_link_type/btn_link_type_left_right.png
+
+
+ [EffectRack1_EffectUnit_Effect],parameter_link_type
+ LeftButton
+
+
0min,0min
-
-
-
-
+
+
+
+
-
-
- [EffectRack1_EffectUnit_Effect],parameter_loaded
- visible
-
-
+
+
+ [EffectRack1_EffectUnit_Effect],parameter_loaded
+ visible
+
+
diff --git a/res/skins/Shade/mixer_panel.xml b/res/skins/Shade/mixer_panel.xml
index 71db10c361ad..91855abdec23 100644
--- a/res/skins/Shade/mixer_panel.xml
+++ b/res/skins/Shade/mixer_panel.xml
@@ -323,6 +323,9 @@
**********************************************
-->
+ [EqualizerRack1_[Channel1]]
+ 1
+ 3
2
0
@@ -346,6 +349,9 @@
+ [EqualizerRack1_[Channel1]]
+ 1
+ 2
2
0
@@ -369,6 +375,9 @@
+ [EqualizerRack1_[Channel1]]
+ 1
+ 1
2
0
@@ -393,6 +402,9 @@
+ [EqualizerRack1_[Channel1]]
+ 1
+ 3
2
0
@@ -416,6 +428,9 @@
+ [EqualizerRack1_[Channel1]]
+ 1
+ 2
2
0
@@ -439,6 +454,9 @@
+ [EqualizerRack1_[Channel1]]
+ 1
+ 1
2
0
@@ -703,6 +721,9 @@
+ [EqualizerRack1_[Channel1]]
+ 1
+ 3
64
knobs/knob_rotary_s%1.png
32,76
@@ -715,6 +736,9 @@
+ [EqualizerRack1_[Channel1]]
+ 1
+ 2
64
knobs/knob_rotary_s%1.png
32,105
@@ -727,6 +751,9 @@
+ [EqualizerRack1_[Channel1]]
+ 1
+ 1
64
knobs/knob_rotary_s%1.png
32,134
@@ -749,6 +776,9 @@
+ [EqualizerRack1_[Channel2]]
+ 1
+ 3
64
knobs/knob_rotary_s%1.png
197,76
@@ -761,6 +791,9 @@
+ [EqualizerRack1_[Channel2]]
+ 1
+ 2
filterMid
64
knobs/knob_rotary_s%1.png
@@ -774,6 +807,9 @@
+ [EqualizerRack1_[Channel2]]
+ 1
+ 1
filterLow
64
knobs/knob_rotary_s%1.png
diff --git a/res/skins/Shade/style.qss b/res/skins/Shade/style.qss
index 20fa46b8cc9f..8a347f52063c 100644
--- a/res/skins/Shade/style.qss
+++ b/res/skins/Shade/style.qss
@@ -14,7 +14,7 @@
padding: 5px 0px;
}
#Mixxx, WWidget,
-WEffect,
+WEffectName,
WKey,
WLabel, QLabel,
WNumber, WNumberPos,
diff --git a/res/skins/Tango/buttons/btn_fx_selector_list.svg b/res/skins/Tango/buttons/btn_menu_arrow.svg
similarity index 100%
rename from res/skins/Tango/buttons/btn_fx_selector_list.svg
rename to res/skins/Tango/buttons/btn_menu_arrow.svg
diff --git a/res/skins/Tango/buttons/btn_fx_selector_list_hover.svg b/res/skins/Tango/buttons/btn_menu_arrow_hover.svg
similarity index 100%
rename from res/skins/Tango/buttons/btn_fx_selector_list_hover.svg
rename to res/skins/Tango/buttons/btn_menu_arrow_hover.svg
diff --git a/res/skins/Tango/decks/deck_left.xml b/res/skins/Tango/decks/deck_left.xml
index 91d4bed5a134..d76bd6f103f2 100644
--- a/res/skins/Tango/decks/deck_left.xml
+++ b/res/skins/Tango/decks/deck_left.xml
@@ -111,21 +111,23 @@ Variables:
-
+
+ 0i,22f
vertical
- me,i
- Spacer1e1me,3f
-
- horizontal
- me,i
-
- Spacer1e3f,1me
- RoundFiller251me,22me
-
-
+
+ EffectChainselectorLeft
+ 40me,22f
+ [QuickEffectRack1_]
+
+
+ [Skin],show_eq_knobs
+ visible
+
+
+ Spacer1e0min,0me
[Master],show_mixer
diff --git a/res/skins/Tango/decks/deck_right.xml b/res/skins/Tango/decks/deck_right.xml
index 4e1bf836ffe7..1557a4542705 100644
--- a/res/skins/Tango/decks/deck_right.xml
+++ b/res/skins/Tango/decks/deck_right.xml
@@ -147,21 +147,22 @@ Variables:
-
+
+ 0i,22f
vertical
- me,i
- Spacer1e1me,3f
-
- horizontal
- me,i
-
- RoundFiller251me,22me
- Spacer1e3f,1me
-
-
+
+ 40me,22f
+ [QuickEffectRack1_]
+
+
+ [Skin],show_eq_knobs
+ visible
+
+
+ Spacer1e0min,0me
[Master],show_mixer
diff --git a/res/skins/Tango/eq_button.xml b/res/skins/Tango/eq_button.xml
new file mode 100644
index 000000000000..68d1d5f368b6
--- /dev/null
+++ b/res/skins/Tango/eq_button.xml
@@ -0,0 +1,39 @@
+
+
+
+
+
+ 2
+
+
+
+
+ 0
+ buttons/btn_.svg
+ buttons/btn_.svg
+
+
+ 1
+ buttons/btn_.svg
+ buttons/btn_.svg
+
+
+ ,button_parameter
+ LeftButton
+
+
+
diff --git a/res/skins/Tango/fx/button.xml b/res/skins/Tango/fx/button.xml
index 6857f28d1625..ec45beb420f8 100644
--- a/res/skins/Tango/fx/button.xml
+++ b/res/skins/Tango/fx/button.xml
@@ -18,6 +18,9 @@ Variables:
2
+
+
+
0
skin:../Tango/buttons/btn_.svg
@@ -29,7 +32,7 @@ Variables:
skin:../Tango/buttons/btn_.svg
- ,
+ ,button_parameter
LeftButton
diff --git a/res/skins/Tango/fx/parameter_button.xml b/res/skins/Tango/fx/parameter_button.xml
index c9b276f13a09..79ef425ccc46 100644
--- a/res/skins/Tango/fx/parameter_button.xml
+++ b/res/skins/Tango/fx/parameter_button.xml
@@ -11,24 +11,23 @@ Variables:
parameter : the parameter
-->
- [_Effect]
+ [_Effect]
- stacked
+ vertical
FxParameterButton
- 52f,26f
+ 52f,32f
- FxParameterButtonOverlay
+ []
+ FxParameterPushButton
51f,18f
- button_parameter
-
- 51f,18f
+ min,me
FxParameterButtonName
@@ -36,22 +35,11 @@ Variables:
center
right
-
- ,button_parameter
- highlight
-
-
-
-
- FxParameterButtonUnderlay
- 51f,18f
- button_parameter
-
- ,button_parameter_loaded
+ ,button_parameter_loaded
visible
diff --git a/res/skins/Tango/fx/parameter_knob.xml b/res/skins/Tango/fx/parameter_knob.xml
index ac2ebcb1b079..c2950bf37349 100644
--- a/res/skins/Tango/fx/parameter_knob.xml
+++ b/res/skins/Tango/fx/parameter_knob.xml
@@ -41,6 +41,9 @@ Variables:
1.500
+
+
+
,parameter
diff --git a/res/skins/Tango/fx/parameter_row.xml b/res/skins/Tango/fx/parameter_row.xml
index 049fc8c2ddb7..33a4e14f9a79 100644
--- a/res/skins/Tango/fx/parameter_row.xml
+++ b/res/skins/Tango/fx/parameter_row.xml
@@ -15,59 +15,52 @@ Variables passed through from fx_unit:
1
-
- 1
-
-
2
-
- 2
-
-
3
-
- 3
-
-
4
-
- 4
-
-
5
-
- 5
-
-
6
-
- 6
-
-
7
-
- 7
-
-
8
+
+
+ 1
+
+
+ 2
+
+
+ 3
+
+
+ 4
+
+
+ 5
+
+
+ 6
+
+
+ 7
+
8
-
diff --git a/res/skins/Tango/fx/unit_left.xml b/res/skins/Tango/fx/unit_left.xml
index f209399c0d14..0bdf26fba28d 100644
--- a/res/skins/Tango/fx/unit_left.xml
+++ b/res/skins/Tango/fx/unit_left.xml
@@ -232,10 +232,16 @@ Variables:
[EffectRack1_EffectUnit],mix_mode
- 1min,0me
+
+
+ 30f,18f
+ EffectChainSelector
+
+
+ 1min,2me
- min,min
+ min,me
vertical
@@ -246,6 +252,7 @@ Variables:
super1
blue
+ 0min,2me
[Skin],show_superknobs
@@ -253,14 +260,6 @@ Variables:
-
- min,me
-
- [Skin],show_superknobs
- visible
-
-
-
AlignCenter
min,max
diff --git a/res/skins/Tango/fx/unit_left_mini.xml b/res/skins/Tango/fx/unit_left_mini.xml
index 87bdda3795d7..6900d4274caa 100644
--- a/res/skins/Tango/fx/unit_left_mini.xml
+++ b/res/skins/Tango/fx/unit_left_mini.xml
@@ -224,7 +224,20 @@ Variables:
-
+
+ AlignCenter
+ max,min
+ horizontal
+
+
+ EffectChainPresetButtonLeft
+
+ 18f,18f
+
+
+
+
+
MixModeButton
EffectUnit_mix_mode
30f,18f
diff --git a/res/skins/Tango/fx/unit_right.xml b/res/skins/Tango/fx/unit_right.xml
index 9e187c72f355..96b94a87c437 100644
--- a/res/skins/Tango/fx/unit_right.xml
+++ b/res/skins/Tango/fx/unit_right.xml
@@ -66,20 +66,27 @@ Variables:
[EffectRack1_EffectUnit],mix_mode
+
+
+ 30f,18f
+ EffectChainSelector
+
+
1min,0me
- min,min
+ min,me
vertical
EffectUnit_super1
SuperWetDryKnob
- 30f,30f
+ 30f,26f
[]
super1
blue
+ 0min,2me
[Skin],show_superknobs
@@ -87,14 +94,6 @@ Variables:
-
- min,me
-
- [Skin],show_superknobs
- visible
-
-
-
AlignCenter
min,max
diff --git a/res/skins/Tango/fx/unit_right_mini.xml b/res/skins/Tango/fx/unit_right_mini.xml
index edbf6acea67b..4513e5ca6c92 100644
--- a/res/skins/Tango/fx/unit_right_mini.xml
+++ b/res/skins/Tango/fx/unit_right_mini.xml
@@ -58,6 +58,19 @@ Variables:
[EffectRack1_EffectUnit],mix_mode
+
+ AlignCenter
+ max,min
+ horizontal
+
+
+ EffectChainPresetButtonRight
+
+ 18f,18f
+
+
+
+
3f,1min
diff --git a/res/skins/Tango/mixer/eq_knob_left.xml b/res/skins/Tango/mixer/eq_knob_left.xml
index f3f862b2fcdf..43f31e69f3cc 100644
--- a/res/skins/Tango/mixer/eq_knob_left.xml
+++ b/res/skins/Tango/mixer/eq_knob_left.xml
@@ -9,8 +9,9 @@ Variables:
parameter : 1, 2, 3 (low, mid, high)
-->
+ [EqualizerRack1_]
1
- [EqualizerRack1__Effect1]
+ [EqualizerRack1__Effect]
EQKnobContainerLeft
@@ -27,10 +28,9 @@ Variables:
min,min
horizontal
-
+
EQKillButton
12f,30f
- button_parameter
@@ -51,22 +51,24 @@ Variables:
2.000
+
+
+
- ,parameter
+ ,parameter
-
+
EQKilledUnderlay
30f,26f
- button_parameter
- ,loaded
+ ,loaded
visible
@@ -74,7 +76,7 @@ Variables:
0min,26min
- ,loaded
+ ,loaded
visible
diff --git a/res/skins/Tango/mixer/eq_knob_right.xml b/res/skins/Tango/mixer/eq_knob_right.xml
index d64e2376883f..d17786611578 100644
--- a/res/skins/Tango/mixer/eq_knob_right.xml
+++ b/res/skins/Tango/mixer/eq_knob_right.xml
@@ -9,8 +9,9 @@ Variables:
parameter : 1, 2, 3 (low, mid, high)
-->
+ [EqualizerRack1_]
1
- [EqualizerRack1__Effect1]
+ [EqualizerRack1__Effect]
EQKnobContainerRight
@@ -35,15 +36,17 @@ Variables:
2.000
+
+
+
- ,parameter
+ ,parameter
-
+
EQKilledUnderlay
30f,26f
- button_parameter
@@ -53,10 +56,9 @@ Variables:
min,min
horizontal
-
+
EQKillButton
12f,30f
- button_parameter
@@ -67,7 +69,7 @@ Variables:
- ,loaded
+ ,loaded
visible
@@ -75,7 +77,7 @@ Variables:
0min,26min
- ,loaded
+ ,loaded
visible
diff --git a/res/skins/Tango/mixer/quick_fx_knob_left.xml b/res/skins/Tango/mixer/quick_fx_knob_left.xml
index 9a6fd4be6c86..dec6a06d7b1e 100644
--- a/res/skins/Tango/mixer/quick_fx_knob_left.xml
+++ b/res/skins/Tango/mixer/quick_fx_knob_left.xml
@@ -40,7 +40,7 @@ Variables:
QuickEffectRack_enabled
QuickFXButton
12f,24f
- ,enabled
+ ,enabled
@@ -99,7 +99,7 @@ Variables:
QuickEffectRack_enabled
QuickFXButton
24f,12f
- ,enabled
+ ,enabled
@@ -126,7 +126,7 @@ Variables:
QuickEffectRack_enabled
QuickFXButton
24f,12f
- ,enabled
+ ,enabled
@@ -138,20 +138,7 @@ Variables:
-
- ,loaded
- visible
-
-
-
- 0min,30f
-
- ,loaded
-
- visible
-
-
diff --git a/res/skins/Tango/mixer/quick_fx_knob_right.xml b/res/skins/Tango/mixer/quick_fx_knob_right.xml
index cf86ed3eafd9..ba60e0b4b0ca 100644
--- a/res/skins/Tango/mixer/quick_fx_knob_right.xml
+++ b/res/skins/Tango/mixer/quick_fx_knob_right.xml
@@ -45,7 +45,7 @@ Variables:
QuickFxDisabledUnderlay
30f,26f
- ,enabled
+ ,enabled
@@ -66,7 +66,7 @@ Variables:
QuickEffectRack_enabled
QuickFXButton
12f,24f
- ,enabled
+ ,enabled
@@ -99,7 +99,7 @@ Variables:
QuickEffectRack_enabled
QuickFXButton
24f,12f
- ,enabled
+ ,enabled
@@ -126,7 +126,7 @@ Variables:
QuickEffectRack_enabled
QuickFXButton
24f,12f
- ,enabled
+ ,enabled
@@ -138,20 +138,7 @@ Variables:
-
- ,loaded
- visible
-
-
-
- 0min,30f
-
- ,loaded
-
- visible
-
-
diff --git a/res/skins/Tango/style.qss b/res/skins/Tango/style.qss
index 278abc22da45..526e4174472c 100644
--- a/res/skins/Tango/style.qss
+++ b/res/skins/Tango/style.qss
@@ -27,9 +27,11 @@ QSpinBox,
WBeatSpinBox,
WOverview #PassthroughLabel,
WCueMenuPopup,
-WEffect,
+WEffectName,
WEffectSelector,
WEffectSelector QAbstractScrollArea,
+WEffectChainPresetSelector,
+WEffectChainPresetSelector QAbstractScrollArea,
#fadeModeCombobox,
#fadeModeCombobox QAbstractScrollArea,
WLibraryTextBrowser,
@@ -607,7 +609,7 @@ WWidgetGroup {
#DeckMini2,
#DeckMini3,
#DeckMini4 {
- background-color: #0f0f0f;
+ background-color: #1e1e1e;
}
#DeckContainer {
@@ -1708,11 +1710,13 @@ decks, samplers, mic, aux, fx */
}
WEffectSelector,
+ WEffectChainPresetSelector,
#fadeModeCombobox {
font-size: 13px/13px;
/* On Linux this is applied to both effect name and effect list. */
}
- WEffectSelector {
+ WEffectSelector,
+ WEffectChainPresetSelector {
/* Fixes the white bars on the top/bottom of the popup on Mac OS X */
margin: 0px;
/* If you use margin top/bottom 0, the combo box shrinks in width (go figure) and
@@ -1722,6 +1726,7 @@ decks, samplers, mic, aux, fx */
border: 0px solid transparent;
border-radius: 3px;
}
+ WEffectChainPresetSelector,
#fadeModeCombobox {
border: 1px solid #666;
margin: 0px 0px 2px 1px;
@@ -1729,10 +1734,16 @@ decks, samplers, mic, aux, fx */
border-radius: 2px;
height: 20px;
}
- WEffectSelector:hover {
+ WEffectChainPresetSelector {
+ background-color: #252525;
+ color: #888;
+ }
+ WEffectSelector:hover,
+ WEffectChainPresetSelector:hover {
background-color: #0f0f0f;
}
WEffectSelector::drop-down,
+ WEffectChainPresetSelector::drop-down,
#fadeModeCombobox::drop-down {
border: 0px;
margin: 0px;
@@ -1741,26 +1752,65 @@ decks, samplers, mic, aux, fx */
WEffectSelector::drop-down {
margin-right: -2px;
}
+ /* QuickEffect selector in left-hand decks has it's down arrow
+ on the left side, below the QuickEffect toggle */
+ #EffectChainselectorLeft::drop-down {
+ subcontrol-origin: margin;
+ subcontrol-position: left center;
+ }
+ WEffectChainPresetButton {
+ padding: 0px;
+ margin: 0px;
+ border-color: #0f0f0f;
+ border-style: solid;
+ border-width: 0px 1px 1px 1px;
+ border-radius: 2px;
+ background-color: #333;
+ }
+ WEffectChainPresetButton#EffectChainPresetButtonLeft {
+ border-width: 1px 0px 1px 1px;
+ }
+ WEffectChainPresetButton#EffectChainPresetButtonRight {
+ border-width: 1px 1px 1px 0px;
+ }
+ WEffectChainPresetButton:hover {
+ background-color: #151515;
+ }
+ WEffectChainPresetButton::menu-indicator {
+ subcontrol-position: center center;
+ subcontrol-origin: margin;
+ margin: 0px 2px 0px 0px;
+ padding: 0px;
+ border: 0px;
+ outline: none;
+ }
+
+ WEffectChainPresetButton::menu-indicator,
WEffectSelector::down-arrow,
+ WEffectChainPresetSelector::down-arrow,
#fadeModeCombobox::down-arrow {
/* When the skin is scaled, bg-color would be applied
to the (not scaled) button image only:
background-color: #101010;
width: 11px;
height: 20px; */
- image: url(skin:/../Tango/buttons/btn_fx_selector_list.svg) no-repeat center center;
+ image: url(skin:/../Tango/buttons/btn_arrow_down.svg) no-repeat center center;
}
+ WEffectChainPresetButton::menu-indicator:hover,
WEffectSelector::down-arrow:hover,
+ WEffectChainPresetSelector::down-arrow:hover,
#fadeModeCombobox::down-arrow:hover {
- image: url(skin:/../Tango/buttons/btn_fx_selector_list_hover.svg) no-repeat center center;
+ image: url(skin:/../Tango/buttons/btn_arrow_down_hover.svg) no-repeat center center;
}
WEffectSelector QAbstractScrollArea,
+ WEffectChainPresetSelector QAbstractScrollArea,
#fadeModeCombobox QAbstractScrollArea {
border-radius: 2px;
margin: 0px;
}
- WEffectSelector QAbstractScrollArea{
+ WEffectSelector QAbstractScrollArea,
+ WEffectChainPresetSelector QAbstractScrollArea {
min-width: 140px;
}
#fadeModeCombobox QAbstractScrollArea {
@@ -1768,6 +1818,7 @@ decks, samplers, mic, aux, fx */
}
/* selected item */
WEffectSelector::checked,
+ WEffectChainPresetSelector::checked,
#fadeModeCombobox::checked {
/* not applied
padding-left: 5px;
@@ -1778,6 +1829,7 @@ decks, samplers, mic, aux, fx */
}
/* tick mark frame */
WEffectSelector::indicator:checked,
+ WEffectChainPresetSelector::indicator:checked,
#fadeModeCombobox::indicator:checked {
/* This is sufficient to completely hide the tick mark,
but this alone would show an empty, shadowed box instead of tick mark: */
@@ -1796,6 +1848,7 @@ decks, samplers, mic, aux, fx */
image: url(skin:/../Tango/buttons/btn_lib_checkmark_white.svg) no-repeat center center;
}
WEffectSelector::indicator:!checked,
+ WEffectChainPresetSelector::indicator:!checked,
#fadeModeCombobox::indicator:!checked {
image: url(skin:/../Tango/buttons/btn_.svg) no-repeat center center;
}
@@ -1825,17 +1878,17 @@ decks, samplers, mic, aux, fx */
qproperty-layoutAlignment: 'AlignLeft | AlignVCenter';
margin-right: 1px;
}
- #FxParameterButtonOverlay[displayValue="0"]:hover {
+ #FxParameterPushButton[displayValue="0"]:hover {
border: 1px solid #888;
}
- #FxParameterButtonOverlay[displayValue="1"]:hover {
+ #FxParameterPushButton[displayValue="1"]:hover {
border: 1px solid #eeeeee;
}
- #FxParameterButtonUnderlay[displayValue="0"] {
+ #FxParameterPushButton[displayValue="0"] {
background-color: #4b4b4b;
}
- #FxParameterButtonUnderlay[displayValue="1"] {
+ #FxParameterPushButton[displayValue="1"] {
background-color: #006596;
}
#FxParameterButtonName {
@@ -2161,13 +2214,15 @@ WEffectSelector::indicator:unchecked,
}
#MainMenu QMenu::right-arrow,
WTrackMenu::right-arrow,
- WTrackMenu QMenu::right-arrow {
+ WTrackMenu QMenu::right-arrow,
+ WEffectChainPresetButton QMenu::right-arrow {
width: 0.35em;
height: 0.7em;
margin-right: 0.2em;
image: url(skin:/../Tango/buttons/btn_arrow_right.svg);
}
#MainMenu QMenu::right-arrow:selected,
+ WEffectChainPresetButton QMenu::right-arrow,
WTrackMenu::right-arrow:selected,
WTrackMenu QMenu::right-arrow:selected {
image: url(skin:/../Tango/buttons/btn_arrow_right_hover.svg);
@@ -2207,6 +2262,10 @@ WCueMenuPopup QLabel,
#SkinSettingsButton,
#SkinSettingsButtonMulti,
WEffectSelector, WEffectSelector QAbstractScrollArea,
+WEffectChainPresetButton QMenu,
+WEffectChainPresetButton QMenu::item,
+WEffectChainPresetButton QMenu QCheckBox,
+WEffectChainPresetSelector QAbstractScrollArea,
#fadeModeCombobox, #fadeModeCombobox QAbstractScrollArea,
#fadeModeCombobox QAbstractScrollArea::item {
background-color: #1a1a1a;
@@ -2223,6 +2282,8 @@ QLineEdit QMenu,
WCueMenuPopup,
WCoverArtMenu,
WEffectSelector QAbstractScrollArea,
+WEffectChainPresetButton QMenu,
+WEffectChainPresetSelector QAbstractScrollArea,
#fadeModeCombobox QAbstractScrollArea {
border: 1px solid #888;
border-radius: 2px;
@@ -2585,11 +2646,13 @@ WLibraryTextBrowser {
/* Scroll bars */
#LibraryContainer QScrollBar,
WEffectSelector QAbstractScrollArea QScrollBar,
+WEffectChainPresetSelector QAbstractScrollArea QScrollBar,
#fadeModeCombobox QAbstractScrollArea QScrollBar {
padding: 1px;
}
#LibraryContainer QScrollBar:horizontal,
WEffectSelector QAbstractScrollArea QScrollBar:horizontal,
+WEffectChainPresetSelector QAbstractScrollArea QScrollBar:horizontal,
#fadeModeCombobox QAbstractScrollArea QScrollBar:horizontal {
min-width: 12px;
height: 10px;
@@ -2598,6 +2661,7 @@ WEffectSelector QAbstractScrollArea QScrollBar:horizontal,
}
#LibraryContainer QScrollBar:vertical,
WEffectSelector QAbstractScrollArea QScrollBar:vertical,
+ WEffectChainPresetSelector QAbstractScrollArea QScrollBar:vertical,
#fadeModeCombobox QAbstractScrollArea QScrollBar:vertical {
min-height: 12px;
width: 10px;
@@ -2609,6 +2673,8 @@ WEffectSelector QAbstractScrollArea QScrollBar:horizontal,
#LibraryContainer QScrollBar::sub-page,
WEffectSelector QAbstractScrollArea QScrollBar::add-page,
WEffectSelector QAbstractScrollArea QScrollBar::sub-page,
+ WEffectChainPresetSelector QAbstractScrollArea QScrollBar::add-page,
+ WEffectChainPresetSelector QAbstractScrollArea QScrollBar::sub-page,
#fadeModeCombobox QAbstractScrollArea QScrollBar::add-page,
#fadeModeCombobox QAbstractScrollArea QScrollBar::sub-page {
min-width: 15px;
@@ -2617,6 +2683,7 @@ WEffectSelector QAbstractScrollArea QScrollBar:horizontal,
}
#LibraryContainer QScrollBar::handle:horizontal,
WEffectSelector QAbstractScrollArea QScrollBar::handle:horizontal,
+ WEffectChainPresetSelector QAbstractScrollArea QScrollBar::handle:horizontal,
#fadeModeCombobox QAbstractScrollArea QScrollBar::handle:horizontal {
min-width: 25px;
background: #595959;
@@ -2624,11 +2691,13 @@ WEffectSelector QAbstractScrollArea QScrollBar:horizontal,
}
#LibraryContainer QScrollBar::handle:horizontal:hover,
WEffectSelector QAbstractScrollArea QScrollBar::handle:horizontal:hover,
+ WEffectChainPresetSelector QAbstractScrollArea QScrollBar::handle:horizontal:hover,
#fadeModeCombobox QAbstractScrollArea QScrollBar::handle:horizontal:hover {
background: #888;
}
#LibraryContainer QScrollBar::handle:vertical,
WEffectSelector QAbstractScrollArea QScrollBar::handle:vertical,
+ WEffectChainPresetSelector QAbstractScrollArea QScrollBar::handle:vertical,
#fadeModeCombobox QAbstractScrollArea QScrollBar::handle:vertical {
min-height: 25px;
background: #595959;
@@ -2636,6 +2705,7 @@ WEffectSelector QAbstractScrollArea QScrollBar:horizontal,
}
#LibraryContainer QScrollBar::handle:vertical:hover,
WEffectSelector QAbstractScrollArea QScrollBar::handle:vertical:hover,
+ WEffectChainPresetSelector QAbstractScrollArea QScrollBar::handle:vertical:hover,
#fadeModeCombobox QAbstractScrollArea QScrollBar::handle:vertical:hover {
background: #888;
}
@@ -2644,6 +2714,8 @@ WEffectSelector QAbstractScrollArea QScrollBar:horizontal,
#LibraryContainer QScrollBar::add-line:vertical,
WEffectSelector QAbstractScrollArea QScrollBar::add-line:horizontal,
WEffectSelector QAbstractScrollArea QScrollBar::add-line:vertical,
+ WEffectChainPresetSelector QAbstractScrollArea QScrollBar::add-line:horizontal,
+ WEffectChainPresetSelector QAbstractScrollArea QScrollBar::add-line:vertical,
#fadeModeCombobox QAbstractScrollArea QScrollBar::add-line:horizontal,
#fadeModeCombobox QAbstractScrollArea QScrollBar::add-line:vertical {
width: 0px;
@@ -2653,6 +2725,8 @@ WEffectSelector QAbstractScrollArea QScrollBar:horizontal,
#LibraryContainer QScrollBar::sub-line:vertical,
WEffectSelector QAbstractScrollArea QScrollBar::sub-line:horizontal,
WEffectSelector QAbstractScrollArea QScrollBar::sub-line:vertical,
+ WEffectChainPresetSelector QAbstractScrollArea QScrollBar::sub-line:horizontal,
+ WEffectChainPresetSelector QAbstractScrollArea QScrollBar::sub-line:vertical,
#fadeModeCombobox QAbstractScrollArea QScrollBar::sub-line:horizontal,
#fadeModeCombobox QAbstractScrollArea QScrollBar::sub-line:vertical {
width: 0px;
@@ -2661,6 +2735,7 @@ WEffectSelector QAbstractScrollArea QScrollBar:horizontal,
/* Corner in between two scrollbars */
#LibraryContainer QAbstractScrollArea::corner,
WEffectSelector QAbstractScrollArea::corner,
+ WEffectChainPresetSelector QAbstractScrollArea::corner,
#fadeModeCombobox QAbstractScrollArea::corner {
background-color: #0f0f0f;
border: 0px;
@@ -2726,6 +2801,7 @@ Library features and their buttons:
#LibraryFeatureControls QPushButton:!enabled {
color: #888;
}
+ WEffectChainPresetSelector:hover,
#LibraryFeatureControls QPushButton:hover,
#fadeModeCombobox:hover {
border: 1px solid #888;
diff --git a/src/control/controleffectknob.cpp b/src/control/controleffectknob.cpp
index d2f14bf15955..0aaad17ceb8c 100644
--- a/src/control/controleffectknob.cpp
+++ b/src/control/controleffectknob.cpp
@@ -1,6 +1,6 @@
#include "control/controleffectknob.h"
-#include "effects/effectmanifestparameter.h"
+#include "effects/backends/effectmanifestparameter.h"
#include "moc_controleffectknob.cpp"
#include "util/math.h"
@@ -8,19 +8,20 @@ ControlEffectKnob::ControlEffectKnob(const ConfigKey& key, double dMinValue, dou
: ControlPotmeter(key, dMinValue, dMaxValue) {
}
-void ControlEffectKnob::setBehaviour(EffectManifestParameter::ControlHint type,
- double dMinValue, double dMaxValue) {
+void ControlEffectKnob::setBehaviour(EffectManifestParameter::ValueScaler type,
+ double dMinValue,
+ double dMaxValue) {
if (m_pControl == nullptr) {
return;
}
- if (type == EffectManifestParameter::ControlHint::KNOB_LINEAR) {
- m_pControl->setBehavior(new ControlLinPotmeterBehavior(
- dMinValue, dMaxValue, false));
- } else if (type == EffectManifestParameter::ControlHint::KNOB_LINEAR_INVERSE) {
- m_pControl->setBehavior(new ControlLinInvPotmeterBehavior(
- dMinValue, dMaxValue, false));
- } else if (type == EffectManifestParameter::ControlHint::KNOB_LOGARITHMIC) {
+ if (type == EffectManifestParameter::ValueScaler::Linear) {
+ m_pControl->setBehavior(new ControlLinPotmeterBehavior(
+ dMinValue, dMaxValue, false));
+ } else if (type == EffectManifestParameter::ValueScaler::LinearInverse) {
+ m_pControl->setBehavior(new ControlLinInvPotmeterBehavior(
+ dMinValue, dMaxValue, false));
+ } else if (type == EffectManifestParameter::ValueScaler::Logarithmic) {
if (dMinValue == 0) {
if (dMaxValue == 1.0) {
// Volume like control
@@ -38,7 +39,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::LogarithmicInverse) {
m_pControl->setBehavior(
new ControlLogInvPotmeterBehavior(dMinValue, dMaxValue, -40));
}
diff --git a/src/control/controleffectknob.h b/src/control/controleffectknob.h
index 43e7cc3720f1..149efc0fdd9b 100644
--- a/src/control/controleffectknob.h
+++ b/src/control/controleffectknob.h
@@ -1,13 +1,14 @@
#pragma once
#include "control/controlpotmeter.h"
-#include "effects/effectmanifestparameter.h"
+#include "effects/backends/effectmanifestparameter.h"
class ControlEffectKnob : public ControlPotmeter {
Q_OBJECT
public:
ControlEffectKnob(const ConfigKey& key, double dMinValue = 0.0, double dMaxValue = 1.0);
- void setBehaviour(EffectManifestParameter::ControlHint type,
- double dMinValue, double dMaxValue);
+ void setBehaviour(EffectManifestParameter::ValueScaler type,
+ double dMinValue,
+ double dMaxValue);
};
diff --git a/src/controllers/controlpickermenu.cpp b/src/controllers/controlpickermenu.cpp
index 973264201d65..19f3d55fe373 100644
--- a/src/controllers/controlpickermenu.cpp
+++ b/src/controllers/controlpickermenu.cpp
@@ -1,8 +1,8 @@
#include "controllers/controlpickermenu.h"
-#include "effects/effectchainslot.h"
-#include "effects/effectparameterslot.h"
-#include "effects/effectrack.h"
+#include "effects/chains/equalizereffectchain.h"
+#include "effects/chains/standardeffectchain.h"
+#include "effects/defs.h"
#include "effects/effectslot.h"
#include "engine/controls/cuecontrol.h"
#include "engine/controls/loopingcontrol.h"
@@ -25,6 +25,7 @@ ControlPickerMenu::ControlPickerMenu(QWidget* pParent)
m_effectUnitStr = tr("Effect Unit %1");
m_effectStr = tr("Slot %1");
m_parameterStr = tr("Parameter %1");
+ m_buttonParameterStr = tr("Button Parameter %1");
m_libraryStr = tr("Library");
// Mixer Controls
@@ -107,7 +108,7 @@ ControlPickerMenu::ControlPickerMenu(QWidget* pParent)
// 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.
- constexpr int kMaxEqs = 3;
+ const int kMaxEqs = 3;
QList eqNames;
eqNames.append(tr("Low EQ"));
eqNames.append(tr("Mid EQ"));
@@ -115,8 +116,8 @@ ControlPickerMenu::ControlPickerMenu(QWidget* pParent)
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));
+ const QString group = EqualizerEffectChain::formatEffectSlotGroup(
+ QString("[Channel%1]").arg(deck));
QMenu* bandMenu = addSubmenu(eqNames[effect], deckMenu);
QString control = "parameter%1";
addControl(group,
@@ -168,17 +169,25 @@ ControlPickerMenu::ControlPickerMenu(QWidget* pParent)
addDeckAndSamplerAndPreviewDeckControl("play", tr("Play"), tr("Play button"), transportMenu);
addDeckAndSamplerAndPreviewDeckControl("back", tr("Fast Rewind"), tr("Fast Rewind button"), transportMenu);
addDeckAndSamplerAndPreviewDeckControl("fwd", tr("Fast Forward"), tr("Fast Forward button"), transportMenu);
- addDeckAndSamplerAndPreviewDeckControl("playposition", tr("Strip Search"),
- tr("Strip-search through track"), transportMenu);
+ addDeckAndSamplerAndPreviewDeckControl("playposition",
+ tr("Strip Search"),
+ tr("Strip-search through track"),
+ transportMenu);
addDeckAndSamplerAndPreviewDeckControl("reverse", tr("Play Reverse"), tr("Play Reverse button"), transportMenu);
- addDeckAndSamplerAndPreviewDeckControl("reverseroll", tr("Reverse Roll (Censor)"),
- tr("Reverse roll (Censor) button"), transportMenu);
+ addDeckAndSamplerAndPreviewDeckControl("reverseroll",
+ tr("Reverse Roll (Censor)"),
+ tr("Reverse roll (Censor) button"),
+ transportMenu);
addDeckAndSamplerAndPreviewDeckControl("start", tr("Jump To Start"), tr("Jumps to start of track"), transportMenu);
- addDeckAndSamplerAndPreviewDeckControl("start_play", tr("Play From Start"),
- tr("Jump to start of track and play"), transportMenu);
+ addDeckAndSamplerAndPreviewDeckControl("start_play",
+ tr("Play From Start"),
+ tr("Jump to start of track and play"),
+ transportMenu);
addDeckAndSamplerAndPreviewDeckControl("stop", tr("Stop"), tr("Stop button"), transportMenu);
- addDeckAndSamplerAndPreviewDeckControl("start_stop", tr("Stop And Jump To Start"),
- tr("Stop playback and jump to start of track"), transportMenu);
+ addDeckAndSamplerAndPreviewDeckControl("start_stop",
+ tr("Stop And Jump To Start"),
+ tr("Stop playback and jump to start of track"),
+ transportMenu);
addDeckAndSamplerAndPreviewDeckControl("end", tr("Jump To End"), tr("Jump to end of track"), transportMenu);
transportMenu->addSeparator();
addDeckAndSamplerAndPreviewDeckControl("eject", tr("Eject"), tr("Eject track"), transportMenu);
@@ -198,10 +207,14 @@ ControlPickerMenu::ControlPickerMenu(QWidget* pParent)
addDeckAndSamplerControl("beats_adjust_slower", tr("Adjust Beatgrid Slower -.01"), tr("Decrease track's average BPM by 0.01"), bpmMenu);
addDeckAndSamplerControl("beats_translate_earlier", tr("Move Beatgrid Earlier"), tr("Adjust the beatgrid to the left"), bpmMenu);
addDeckAndSamplerControl("beats_translate_later", tr("Move Beatgrid Later"), tr("Adjust the beatgrid to the right"), bpmMenu);
- addDeckControl("beats_translate_curpos", tr("Adjust Beatgrid"),
- tr("Align beatgrid to current position"), bpmMenu);
- addDeckControl("beats_translate_match_alignment", tr("Adjust Beatgrid - Match Alignment"),
- tr("Adjust beatgrid to match another playing deck."), bpmMenu);
+ addDeckControl("beats_translate_curpos",
+ tr("Adjust Beatgrid"),
+ tr("Align beatgrid to current position"),
+ bpmMenu);
+ addDeckControl("beats_translate_match_alignment",
+ tr("Adjust Beatgrid - Match Alignment"),
+ tr("Adjust beatgrid to match another playing deck."),
+ bpmMenu);
bpmMenu->addSeparator();
addDeckAndSamplerControl("quantize", tr("Quantize Mode"), tr("Toggle quantize mode"), bpmMenu);
@@ -265,26 +278,45 @@ ControlPickerMenu::ControlPickerMenu(QWidget* pParent)
// Speed
QMenu* speedMenu = addSubmenu(tr("Speed"));
- addDeckAndSamplerControl("rate", tr("Playback Speed"),
- tr("Playback speed control (Vinyl \"Pitch\" slider)"), speedMenu, true);
+ addDeckAndSamplerControl("rate",
+ tr("Playback Speed"),
+ tr("Playback speed control (Vinyl \"Pitch\" slider)"),
+ speedMenu,
+ true);
speedMenu->addSeparator();
- addDeckAndSamplerControl("rate_perm_up", tr("Increase Speed"),
- tr("Adjust speed faster (coarse)"), speedMenu);
- addDeckAndSamplerControl("rate_perm_up_small", tr("Increase Speed (Fine)"),
- tr("Adjust speed faster (fine)"), speedMenu);
- addDeckAndSamplerControl("rate_perm_down", tr("Decrease Speed"),
- tr("Adjust speed slower (coarse)"), speedMenu);
- addDeckAndSamplerControl("rate_perm_down_small", tr("Increase Speed (Fine)"),
- tr("Adjust speed slower (fine)"), speedMenu);
+ addDeckAndSamplerControl("rate_perm_up",
+ tr("Increase Speed"),
+ tr("Adjust speed faster (coarse)"),
+ speedMenu);
+ addDeckAndSamplerControl("rate_perm_up_small",
+ tr("Increase Speed (Fine)"),
+ tr("Adjust speed faster (fine)"),
+ speedMenu);
+ addDeckAndSamplerControl("rate_perm_down",
+ tr("Decrease Speed"),
+ tr("Adjust speed slower (coarse)"),
+ speedMenu);
+ addDeckAndSamplerControl("rate_perm_down_small",
+ tr("Increase Speed (Fine)"),
+ tr("Adjust speed slower (fine)"),
+ speedMenu);
speedMenu->addSeparator();
- addDeckAndSamplerControl("rate_temp_up", tr("Temporarily Increase Speed"),
- tr("Temporarily increase speed (coarse)"), speedMenu);
- addDeckAndSamplerControl("rate_temp_up_small", tr("Temporarily Increase Speed (Fine)"),
- tr("Temporarily increase speed (fine)"), speedMenu);
- addDeckAndSamplerControl("rate_temp_down", tr("Temporarily Decrease Speed"),
- tr("Temporarily decrease speed (coarse)"), speedMenu);
- addDeckAndSamplerControl("rate_temp_down_small", tr("Temporarily Decrease Speed (Fine)"),
- tr("Temporarily decrease speed (fine)"), speedMenu);
+ addDeckAndSamplerControl("rate_temp_up",
+ tr("Temporarily Increase Speed"),
+ tr("Temporarily increase speed (coarse)"),
+ speedMenu);
+ addDeckAndSamplerControl("rate_temp_up_small",
+ tr("Temporarily Increase Speed (Fine)"),
+ tr("Temporarily increase speed (fine)"),
+ speedMenu);
+ addDeckAndSamplerControl("rate_temp_down",
+ tr("Temporarily Decrease Speed"),
+ tr("Temporarily decrease speed (coarse)"),
+ speedMenu);
+ addDeckAndSamplerControl("rate_temp_down_small",
+ tr("Temporarily Decrease Speed (Fine)"),
+ tr("Temporarily decrease speed (fine)"),
+ speedMenu);
// Pitch (Musical Key)
QMenu* pitchMenu = addSubmenu(tr("Pitch (Musical Key)"));
addDeckAndSamplerControl("pitch",
@@ -321,34 +353,48 @@ ControlPickerMenu::ControlPickerMenu(QWidget* pParent)
// Vinyl Control
QMenu* vinylControlMenu = addSubmenu(tr("Vinyl Control"));
- addDeckControl("vinylcontrol_enabled", tr("Toggle Vinyl Control"),
- tr("Toggle Vinyl Control (ON/OFF)"), vinylControlMenu);
- addDeckControl("vinylcontrol_mode", tr("Vinyl Control Mode"),
- tr("Toggle vinyl-control mode (ABS/REL/CONST)"), vinylControlMenu);
- addDeckControl("vinylcontrol_cueing", tr("Vinyl Control Cueing Mode"),
- tr("Toggle vinyl-control cueing mode (OFF/ONE/HOT)"), vinylControlMenu);
- addDeckControl("passthrough", tr("Vinyl Control Passthrough"),
- tr("Pass through external audio into the internal mixer"), vinylControlMenu);
- addControl(VINYL_PREF_KEY, "Toggle", tr("Vinyl Control Next Deck"),
- tr("Single deck mode - Switch vinyl control to next deck"), vinylControlMenu);
+ addDeckControl("vinylcontrol_enabled",
+ tr("Toggle Vinyl Control"),
+ tr("Toggle Vinyl Control (ON/OFF)"),
+ vinylControlMenu);
+ addDeckControl("vinylcontrol_mode",
+ tr("Vinyl Control Mode"),
+ tr("Toggle vinyl-control mode (ABS/REL/CONST)"),
+ vinylControlMenu);
+ addDeckControl("vinylcontrol_cueing",
+ tr("Vinyl Control Cueing Mode"),
+ tr("Toggle vinyl-control cueing mode (OFF/ONE/HOT)"),
+ vinylControlMenu);
+ addDeckControl("passthrough",
+ tr("Vinyl Control Passthrough"),
+ tr("Pass through external audio into the internal mixer"),
+ vinylControlMenu);
+ addControl(VINYL_PREF_KEY,
+ "Toggle",
+ tr("Vinyl Control Next Deck"),
+ tr("Single deck mode - Switch vinyl control to next deck"),
+ vinylControlMenu);
// Cues
QMenu* cueMenu = addSubmenu(tr("Cues"));
addDeckControl("cue_default", tr("Cue"), tr("Cue button"), cueMenu);
addDeckControl("cue_set", tr("Set Cue"), tr("Set cue point"), cueMenu);
addDeckControl("cue_goto", tr("Go-To Cue"), tr("Go to cue point"), cueMenu);
- addDeckAndSamplerAndPreviewDeckControl("cue_gotoandplay", tr("Go-To Cue And Play"),
- tr("Go to cue point and play"), cueMenu);
- addDeckControl("cue_gotoandstop", tr("Go-To Cue And Stop"),
- tr("Go to cue point and stop"), cueMenu);
- addDeckControl("cue_preview", tr("Preview Cue"),
- tr("Preview from cue point"), cueMenu);
- addDeckControl("cue_cdj", tr("Cue (CDJ Mode)"),
- tr("Cue button (CDJ mode)"), cueMenu);
- addDeckControl("play_stutter", tr("Stutter Cue"),
- tr("Stutter cue"), cueMenu);
- addDeckControl("cue_play", tr("CUP (Cue + Play)"),
- tr("Go to cue point and play after release"), cueMenu);
+ addDeckAndSamplerAndPreviewDeckControl("cue_gotoandplay",
+ tr("Go-To Cue And Play"),
+ tr("Go to cue point and play"),
+ cueMenu);
+ addDeckControl("cue_gotoandstop",
+ tr("Go-To Cue And Stop"),
+ tr("Go to cue point and stop"),
+ cueMenu);
+ addDeckControl("cue_preview", tr("Preview Cue"), tr("Preview from cue point"), cueMenu);
+ addDeckControl("cue_cdj", tr("Cue (CDJ Mode)"), tr("Cue button (CDJ mode)"), cueMenu);
+ addDeckControl("play_stutter", tr("Stutter Cue"), tr("Stutter cue"), cueMenu);
+ addDeckControl("cue_play",
+ tr("CUP (Cue + Play)"),
+ tr("Go to cue point and play after release"),
+ cueMenu);
// Hotcues
QMenu* hotcueMainMenu = addSubmenu(tr("Hotcues"));
@@ -402,33 +448,33 @@ ControlPickerMenu::ControlPickerMenu(QWidget* pParent)
}
QMenu* hotcueSubMenu = addSubmenu(tr("Hotcue %1").arg(QString::number(i)), parentMenu);
addDeckAndSamplerControl(QString("hotcue_%1_activate").arg(i),
- hotcueActivateTitle.arg(QString::number(i)),
- hotcueActivateDescription.arg(QString::number(i)),
- hotcueSubMenu);
+ hotcueActivateTitle.arg(QString::number(i)),
+ hotcueActivateDescription.arg(QString::number(i)),
+ hotcueSubMenu);
addDeckAndSamplerControl(QString("hotcue_%1_clear").arg(i),
- hotcueClearTitle.arg(QString::number(i)),
- hotcueClearDescription.arg(QString::number(i)),
- hotcueSubMenu);
+ hotcueClearTitle.arg(QString::number(i)),
+ hotcueClearDescription.arg(QString::number(i)),
+ hotcueSubMenu);
addDeckAndSamplerControl(QString("hotcue_%1_set").arg(i),
- hotcueSetTitle.arg(QString::number(i)),
- hotcueSetDescription.arg(QString::number(i)),
- hotcueSubMenu);
+ hotcueSetTitle.arg(QString::number(i)),
+ hotcueSetDescription.arg(QString::number(i)),
+ hotcueSubMenu);
addDeckAndSamplerControl(QString("hotcue_%1_goto").arg(i),
- hotcueGotoTitle.arg(QString::number(i)),
- hotcueGotoDescription.arg(QString::number(i)),
- hotcueSubMenu);
+ hotcueGotoTitle.arg(QString::number(i)),
+ hotcueGotoDescription.arg(QString::number(i)),
+ hotcueSubMenu);
addDeckAndSamplerControl(QString("hotcue_%1_gotoandstop").arg(i),
- hotcueGotoAndStopTitle.arg(QString::number(i)),
- hotcueGotoAndStopDescription.arg(QString::number(i)),
- hotcueSubMenu);
+ hotcueGotoAndStopTitle.arg(QString::number(i)),
+ hotcueGotoAndStopDescription.arg(QString::number(i)),
+ hotcueSubMenu);
addDeckAndSamplerControl(QString("hotcue_%1_gotoandplay").arg(i),
- hotcueGotoAndPlayTitle.arg(QString::number(i)),
- hotcueGotoAndPlayDescription.arg(QString::number(i)),
- hotcueSubMenu);
+ hotcueGotoAndPlayTitle.arg(QString::number(i)),
+ hotcueGotoAndPlayDescription.arg(QString::number(i)),
+ hotcueSubMenu);
addDeckAndSamplerControl(QString("hotcue_%1_activate_preview").arg(i),
- hotcuePreviewTitle.arg(QString::number(i)),
- hotcuePreviewDescription.arg(QString::number(i)),
- hotcueSubMenu);
+ hotcuePreviewTitle.arg(QString::number(i)),
+ hotcuePreviewDescription.arg(QString::number(i)),
+ hotcueSubMenu);
}
if (moreHotcues) {
hotcueMainMenu->addSeparator();
@@ -692,10 +738,14 @@ ControlPickerMenu::ControlPickerMenu(QWidget* pParent)
false,
m_libraryStr);
libraryMenu->addSeparator();
- addControl("[Library]", "GoToItem",
- tr("Go to the currently selected item"),
- tr("Choose the currently selected item and advance forward one pane if appropriate"),
- libraryMenu, false, m_libraryStr);
+ addControl("[Library]",
+ "GoToItem",
+ tr("Go to the currently selected item"),
+ tr("Choose the currently selected item and advance forward one "
+ "pane if appropriate"),
+ libraryMenu,
+ false,
+ m_libraryStr);
// Load track (these can be loaded into any channel)
addDeckAndSamplerControl("LoadSelectedTrack",
tr("Load Track"),
@@ -707,18 +757,27 @@ ControlPickerMenu::ControlPickerMenu(QWidget* pParent)
libraryMenu);
libraryMenu->addSeparator();
// Auto DJ
- addControl("[Library]", "AutoDjAddBottom",
- tr("Add to Auto DJ Queue (bottom)"),
- tr("Append the selected track to the Auto DJ Queue"),
- libraryMenu, false, m_libraryStr);
- addControl("[Library]", "AutoDjAddTop",
- tr("Add to Auto DJ Queue (top)"),
- tr("Prepend selected track to the Auto DJ Queue"),
- libraryMenu, false, m_libraryStr);
- addControl("[Library]", "AutoDjAddReplace",
- tr("Add to Auto DJ Queue (replace)"),
- tr("Replace Auto DJ Queue with selected tracks"),
- libraryMenu, false, m_libraryStr);
+ addControl("[Library]",
+ "AutoDjAddBottom",
+ tr("Add to Auto DJ Queue (bottom)"),
+ tr("Append the selected track to the Auto DJ Queue"),
+ libraryMenu,
+ false,
+ m_libraryStr);
+ addControl("[Library]",
+ "AutoDjAddTop",
+ tr("Add to Auto DJ Queue (top)"),
+ tr("Prepend selected track to the Auto DJ Queue"),
+ libraryMenu,
+ false,
+ m_libraryStr);
+ addControl("[Library]",
+ "AutoDjAddReplace",
+ tr("Add to Auto DJ Queue (replace)"),
+ tr("Replace Auto DJ Queue with selected tracks"),
+ libraryMenu,
+ false,
+ m_libraryStr);
libraryMenu->addSeparator();
addControl("[Library]",
"search_history_next",
@@ -751,10 +810,13 @@ ControlPickerMenu::ControlPickerMenu(QWidget* pParent)
m_libraryStr);
libraryMenu->addSeparator();
- addControl("[Recording]", "toggle_recording",
- tr("Record Mix"),
- tr("Toggle mix recording"),
- libraryMenu, false, m_libraryStr);
+ addControl("[Recording]",
+ "toggle_recording",
+ tr("Record Mix"),
+ tr("Toggle mix recording"),
+ libraryMenu,
+ false,
+ m_libraryStr);
// Effect Controls
QMenu* effectsMenu = addSubmenu(tr("Effects"));
@@ -762,317 +824,376 @@ ControlPickerMenu::ControlPickerMenu(QWidget* pParent)
// Quick Effect Rack COs
QMenu* quickEffectMenu = addSubmenu(tr("Quick Effects"), effectsMenu);
for (int i = 1; i <= iNumDecks; ++i) {
- addControl(QString("[QuickEffectRack1_[Channel%1]]").arg(i), "super1",
- tr("Deck %1 Quick Effect Super Knob").arg(i),
- tr("Quick Effect Super Knob (control linked effect parameters)"),
- quickEffectMenu, false, tr("Quick Effect"));
- addControl(QString("[QuickEffectRack1_[Channel%1]_Effect1]").arg(i), "enabled",
- tr("Deck %1 Quick Effect Enable Button").arg(i),
- tr("Quick Effect Enable Button"),
- quickEffectMenu, false, tr("Quick Effect"));
+ addControl(QString("[QuickEffectRack1_[Channel%1]]").arg(i),
+ "super1",
+ tr("Deck %1 Quick Effect Super Knob").arg(i),
+ tr("Quick Effect Super Knob (control linked effect "
+ "parameters)"),
+ quickEffectMenu,
+ false,
+ tr("Quick Effect"));
+ addControl(QString("[QuickEffectRack1_[Channel%1]_Effect1]").arg(i),
+ "enabled",
+ tr("Deck %1 Quick Effect Enable Button").arg(i),
+ tr("Quick Effect Enable Button"),
+ quickEffectMenu,
+ false,
+ tr("Quick Effect"));
}
effectsMenu->addSeparator();
- // When kNumEffectRacks is changed to >1 put effect unit actions into
- // separate "Effect Rack N" submenus.
- constexpr int kNumEffectRacks = 1;
- for (int iRackNumber = 1; iRackNumber <= kNumEffectRacks; ++iRackNumber) {
- const QString rackGroup = StandardEffectRack::formatGroupString(
- iRackNumber - 1);
- QString descriptionPrefix = m_effectRackStr.arg(iRackNumber);
-
- const int numEffectUnits = static_cast(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").arg(m_effectUnitStr.arg(iEffectUnitNumber));
-
- QMenu* effectUnitMenu = addSubmenu(m_effectUnitStr.arg(iEffectUnitNumber),
- effectsMenu);
- addControl(effectUnitGroup, "clear",
- tr("Clear Unit"),
- tr("Clear effect unit"),
- effectUnitMenu, false, descriptionPrefix);
- addControl(effectUnitGroup, "enabled",
- tr("Toggle Unit"),
- tr("Enable or disable effect processing"),
- effectUnitMenu, false, descriptionPrefix);
- addControl(effectUnitGroup, "mix",
- tr("Dry/Wet"),
- tr("Adjust the balance between the original (dry) and processed (wet) signal."),
- effectUnitMenu, true, descriptionPrefix);
- addControl(effectUnitGroup, "super1",
- tr("Super Knob"),
- tr("Super Knob (control effects' Meta Knobs)"),
- effectUnitMenu, true, descriptionPrefix);
+ for (int iEffectUnitNumber = 1; iEffectUnitNumber <= kNumStandardEffectUnits;
+ ++iEffectUnitNumber) {
+ const QString effectUnitGroup =
+ StandardEffectChain::formatEffectChainGroup(iEffectUnitNumber - 1);
+
+ const QString descriptionPrefix = QString("%1").arg(m_effectUnitStr.arg(iEffectUnitNumber));
+
+ QMenu* effectUnitMenu = addSubmenu(m_effectUnitStr.arg(iEffectUnitNumber),
+ effectsMenu);
+ addControl(effectUnitGroup,
+ "clear",
+ tr("Clear Unit"),
+ tr("Clear effect unit"),
+ effectUnitMenu,
+ false,
+ descriptionPrefix);
+ addControl(effectUnitGroup,
+ "enabled",
+ tr("Toggle Unit"),
+ tr("Enable or disable effect processing"),
+ effectUnitMenu,
+ false,
+ descriptionPrefix);
+ addControl(effectUnitGroup,
+ "mix",
+ tr("Dry/Wet"),
+ tr("Adjust the balance between the original (dry) and "
+ "processed (wet) signal."),
+ effectUnitMenu,
+ true,
+ descriptionPrefix);
+ addControl(effectUnitGroup,
+ "super1",
+ tr("Super Knob"),
+ tr("Super Knob (control effects' Meta Knobs)"),
+ effectUnitMenu,
+ true,
+ descriptionPrefix);
+ addControl(effectUnitGroup,
+ "mix_mode",
+ tr("Mix Mode Toggle"),
+ tr("Toggle effect unit between D/W and D+W modes"),
+ effectUnitMenu,
+ false,
+ descriptionPrefix);
+ addControl(effectUnitGroup,
+ "next_chain",
+ tr("Next Chain"),
+ tr("Next chain preset"),
+ effectUnitMenu,
+ false,
+ descriptionPrefix);
+ addControl(effectUnitGroup,
+ "prev_chain",
+ tr("Previous Chain"),
+ tr("Previous chain preset"),
+ effectUnitMenu,
+ false,
+ descriptionPrefix);
+ addControl(effectUnitGroup,
+ "chain_selector",
+ tr("Next/Previous Chain"),
+ tr("Next or previous chain preset"),
+ effectUnitMenu,
+ false,
+ descriptionPrefix);
+ addControl(effectUnitGroup,
+ "show_parameters",
+ tr("Show Effect Parameters"),
+ tr("Show Effect Parameters"),
+ effectUnitMenu,
+ false,
+ descriptionPrefix);
+
+ QString assignMenuTitle = tr("Effect Unit Assignment");
+ QString assignString = tr("Assign ");
+ QMenu* effectUnitGroups = addSubmenu(assignMenuTitle,
+ effectUnitMenu);
+
+ QString groupDescriptionPrefix = QString("%1").arg(
+ m_effectUnitStr.arg(iEffectUnitNumber));
+
+ addControl(effectUnitGroup, "group_[Master]_enable",
+ assignString + m_effectMasterOutputStr, // in ComboBox
+ assignString + m_effectMasterOutputStr, // description below
+ effectUnitGroups,
+ false,
+ groupDescriptionPrefix);
+ addControl(effectUnitGroup,
+ "group_[Headphone]_enable",
+ assignString + m_effectHeadphoneOutputStr,
+ assignString + m_effectHeadphoneOutputStr,
+ effectUnitGroups,
+ false,
+ groupDescriptionPrefix);
+
+ for (int iDeckNumber = 1; iDeckNumber <= iNumDecks; ++iDeckNumber) {
+ // PlayerManager::groupForDeck is 0-indexed.
+ QString playerGroup = PlayerManager::groupForDeck(iDeckNumber - 1);
+ // TODO(owen): Fix bad i18n here.
addControl(effectUnitGroup,
- "mix_mode",
- tr("Mix Mode Toggle"),
- tr("Toggle effect unit between D/W and D+W modes"),
- effectUnitMenu,
+ QString("group_%1_enable").arg(playerGroup),
+ assignString + m_deckStr.arg(iDeckNumber),
+ assignString + m_deckStr.arg(iDeckNumber),
+ effectUnitGroups,
false,
- descriptionPrefix);
- addControl(effectUnitGroup, "next_chain",
- tr("Next Chain"),
- tr("Next chain preset"),
- effectUnitMenu, false, descriptionPrefix);
- addControl(effectUnitGroup, "prev_chain",
- tr("Previous Chain"),
- tr("Previous chain preset"),
- effectUnitMenu, false, descriptionPrefix);
- addControl(effectUnitGroup, "chain_selector",
- tr("Next/Previous Chain"),
- tr("Next or previous chain preset"),
- effectUnitMenu, false, descriptionPrefix);
- addControl(effectUnitGroup, "show_parameters",
- tr("Show Effect Parameters"),
- tr("Show Effect Parameters"),
- effectUnitMenu, false, descriptionPrefix);
-
- QString assignMenuTitle = tr("Effect Unit Assignment");
- QString assignString = tr("Assign ");
- QMenu* effectUnitGroups = addSubmenu(assignMenuTitle,
- effectUnitMenu);
+ groupDescriptionPrefix);
+ }
- QString groupDescriptionPrefix = QString("%1").arg(
- m_effectUnitStr.arg(iEffectUnitNumber));
+ const int iNumSamplers = static_cast(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.
+ addControl(effectUnitGroup,
+ QString("group_%1_enable").arg(playerGroup),
+ assignString + m_samplerStr.arg(iSamplerNumber),
+ assignString + m_samplerStr.arg(iSamplerNumber),
+ effectUnitGroups,
+ false,
+ groupDescriptionPrefix);
+ }
- addControl(effectUnitGroup, "group_[Master]_enable",
- assignString + m_effectMasterOutputStr, // in ComboBox
- assignString + m_effectMasterOutputStr, // description below
+ const int iNumMicrophones = static_cast(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.
+ addControl(effectUnitGroup,
+ QString("group_%1_enable").arg(micGroup),
+ assignString + m_microphoneStr.arg(iMicrophoneNumber),
+ assignString + m_microphoneStr.arg(iMicrophoneNumber),
effectUnitGroups,
false,
groupDescriptionPrefix);
+ }
+
+ const int iNumAuxiliaries = static_cast(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.
addControl(effectUnitGroup,
- "group_[Headphone]_enable",
- assignString + m_effectHeadphoneOutputStr,
- assignString + m_effectHeadphoneOutputStr,
+ QString("group_%1_enable").arg(auxGroup),
+ assignString + m_auxStr.arg(iAuxiliaryNumber),
+ assignString + m_auxStr.arg(iAuxiliaryNumber),
effectUnitGroups,
false,
groupDescriptionPrefix);
+ }
- for (int iDeckNumber = 1; iDeckNumber <= iNumDecks; ++iDeckNumber) {
- // PlayerManager::groupForDeck is 0-indexed.
- QString playerGroup = PlayerManager::groupForDeck(iDeckNumber - 1);
- // TODO(owen): Fix bad i18n here.
- addControl(effectUnitGroup,
- QString("group_%1_enable").arg(playerGroup),
- assignString + m_deckStr.arg(iDeckNumber),
- assignString + m_deckStr.arg(iDeckNumber),
- effectUnitGroups,
- false,
- groupDescriptionPrefix);
- }
+ const int numEffectSlots = static_cast(ControlObject::get(
+ ConfigKey(effectUnitGroup, "num_effectslots")));
+ for (int iEffectSlotNumber = 1; iEffectSlotNumber <= numEffectSlots;
+ ++iEffectSlotNumber) {
+ const QString effectSlotGroup =
+ StandardEffectChain::formatEffectSlotGroup(
+ iEffectUnitNumber - 1, iEffectSlotNumber - 1);
- const int iNumSamplers = static_cast(ControlObject::get(
- ConfigKey("[Master]", "num_samplers")));
- for (int iSamplerNumber = 1; iSamplerNumber <= iNumSamplers;
- ++iSamplerNumber) {
- // PlayerManager::groupForSampler is 0-indexed.
- QString samplerGroup = PlayerManager::groupForSampler(iSamplerNumber - 1);
- // TODO(owen): Fix bad i18n here.
- addControl(effectUnitGroup,
- QString("group_%1_enable").arg(samplerGroup),
- assignString + m_samplerStr.arg(iSamplerNumber),
- assignString + m_samplerStr.arg(iSamplerNumber),
- effectUnitGroups,
- false,
- groupDescriptionPrefix);
- }
+ QMenu* effectSlotMenu = addSubmenu(m_effectStr.arg(iEffectSlotNumber),
+ effectUnitMenu);
- const int iNumMicrophones = static_cast(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.
- addControl(effectUnitGroup,
- QString("group_%1_enable").arg(micGroup),
- assignString + m_microphoneStr.arg(iMicrophoneNumber),
- assignString + m_microphoneStr.arg(iMicrophoneNumber),
- effectUnitGroups,
- false,
- groupDescriptionPrefix);
- }
+ QString slotDescriptionPrefix =
+ QString("%1, %2").arg(descriptionPrefix,
+ m_effectStr.arg(iEffectSlotNumber));
+
+ addControl(effectSlotGroup,
+ "clear",
+ tr("Clear"),
+ tr("Clear the current effect"),
+ effectSlotMenu,
+ false,
+ slotDescriptionPrefix);
+ addControl(effectSlotGroup,
+ "meta",
+ tr("Meta Knob"),
+ tr("Effect Meta Knob (control linked effect parameters)"),
+ effectSlotMenu,
+ false,
+ slotDescriptionPrefix);
+ addControl(effectSlotGroup,
+ "enabled",
+ tr("Toggle"),
+ tr("Toggle the current effect"),
+ effectSlotMenu,
+ false,
+ slotDescriptionPrefix);
+ addControl(effectSlotGroup,
+ "next_effect",
+ tr("Next"),
+ tr("Switch to next effect"),
+ effectSlotMenu,
+ false,
+ slotDescriptionPrefix);
+ addControl(effectSlotGroup,
+ "prev_effect",
+ tr("Previous"),
+ tr("Switch to the previous effect"),
+ effectSlotMenu,
+ false,
+ slotDescriptionPrefix);
+ addControl(effectSlotGroup,
+ "effect_selector",
+ tr("Next or Previous"),
+ tr("Switch to either next or previous effect"),
+ effectSlotMenu,
+ false,
+ slotDescriptionPrefix);
+
+ // Effect parameter knobs
+ const int numParameterSlots = static_cast(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 =
+ StandardEffectChain::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));
- const int iNumAuxiliaries = static_cast(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.
- addControl(effectUnitGroup,
- QString("group_%1_enable").arg(auxGroup),
- assignString + m_auxStr.arg(iAuxiliaryNumber),
- assignString + m_auxStr.arg(iAuxiliaryNumber),
- effectUnitGroups,
+ // Likely to change soon.
+ addControl(parameterSlotGroup,
+ parameterSlotItemPrefix,
+ tr("Parameter Value"),
+ tr("Parameter Value"),
+ parameterSlotMenu,
+ true,
+ parameterDescriptionPrefix);
+ addControl(parameterSlotGroup,
+ parameterSlotItemPrefix + "_link_type",
+ tr("Meta Knob Mode"),
+ tr("Set how linked effect parameters change when "
+ "turning the Meta Knob."),
+ parameterSlotMenu,
false,
- groupDescriptionPrefix);
+ parameterDescriptionPrefix);
+ addControl(parameterSlotGroup,
+ parameterSlotItemPrefix + "_link_inverse",
+ tr("Meta Knob Mode Invert"),
+ tr("Invert how linked effect parameters change when "
+ "turning the Meta Knob."),
+ parameterSlotMenu,
+ false,
+ parameterDescriptionPrefix);
}
- const int numEffectSlots = static_cast(ControlObject::get(
- ConfigKey(effectUnitGroup, "num_effectslots")));
- for (int iEffectSlotNumber = 1; iEffectSlotNumber <= numEffectSlots;
- ++iEffectSlotNumber) {
- const QString effectSlotGroup =
- StandardEffectRack::formatEffectSlotGroupString(
- iRackNumber - 1, iEffectUnitNumber - 1,
- iEffectSlotNumber - 1);
-
- QMenu* effectSlotMenu = addSubmenu(m_effectStr.arg(iEffectSlotNumber),
- effectUnitMenu);
-
- QString slotDescriptionPrefix =
- QString("%1, %2").arg(descriptionPrefix,
- m_effectStr.arg(iEffectSlotNumber));
-
- addControl(effectSlotGroup, "clear",
- tr("Clear"), tr("Clear the current effect"),
- effectSlotMenu, false, slotDescriptionPrefix);
- addControl(effectSlotGroup, "meta",
- tr("Meta Knob"), tr("Effect Meta Knob (control linked effect parameters)"),
- effectSlotMenu, false, slotDescriptionPrefix);
- addControl(effectSlotGroup, "enabled",
- tr("Toggle"), tr("Toggle the current effect"),
- effectSlotMenu, false, slotDescriptionPrefix);
- addControl(effectSlotGroup, "next_effect",
- tr("Next"), tr("Switch to next effect"),
- effectSlotMenu, false, slotDescriptionPrefix);
- addControl(effectSlotGroup, "prev_effect",
- tr("Previous"), tr("Switch to the previous effect"),
- effectSlotMenu, false, slotDescriptionPrefix);
- addControl(effectSlotGroup, "effect_selector",
- tr("Next or Previous"),
- tr("Switch to either next or previous effect"),
- effectSlotMenu, false, slotDescriptionPrefix);
-
- // Effect parameter knobs
- const int numParameterSlots = static_cast(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),
+ // Effect parameter buttons
+ const int numButtonParameterSlots = static_cast(ControlObject::get(
+ ConfigKey(effectSlotGroup, "num_button_parameterslots")));
+ for (int iParameterSlotNumber = 1; iParameterSlotNumber <= numButtonParameterSlots;
+ ++iParameterSlotNumber) {
+ // The parameter slot group is the same as the effect slot
+ // group on a standard effect rack.
+ const QString parameterSlotGroup =
+ StandardEffectChain::formatEffectSlotGroup(
+ iEffectUnitNumber - 1, iEffectSlotNumber - 1);
+ const QString parameterSlotItemPrefix =
+ EffectButtonParameterSlot::formatItemPrefix(
+ iParameterSlotNumber - 1);
+ QMenu* parameterSlotMenu = addSubmenu(
+ m_buttonParameterStr.arg(iParameterSlotNumber),
effectSlotMenu);
- QString parameterDescriptionPrefix =
- QString("%1, %2").arg(slotDescriptionPrefix,
- m_parameterStr.arg(iParameterSlotNumber));
-
- // Likely to change soon.
- addControl(parameterSlotGroup, parameterSlotItemPrefix,
- tr("Parameter Value"),
- tr("Parameter Value"),
- parameterSlotMenu, true,
- parameterDescriptionPrefix);
- addControl(parameterSlotGroup, parameterSlotItemPrefix + "_link_type",
- tr("Meta Knob Mode"),
- tr("Set how linked effect parameters change when turning the Meta Knob."),
- parameterSlotMenu, false,
- parameterDescriptionPrefix);
- addControl(parameterSlotGroup, parameterSlotItemPrefix + "_link_inverse",
- tr("Meta Knob Mode Invert"),
- tr("Invert how linked effect parameters change when turning the Meta Knob."),
- parameterSlotMenu, false,
- parameterDescriptionPrefix);
- }
-
- // Effect parameter buttons
- const int numButtonParameterSlots = static_cast(ControlObject::get(
- ConfigKey(effectSlotGroup, "num_button_parameterslots")));
- for (int iParameterSlotNumber = 1; iParameterSlotNumber <= numButtonParameterSlots;
- ++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 =
- EffectButtonParameterSlot::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.
- addControl(parameterSlotGroup,
- parameterSlotItemPrefix,
- tr("Button Parameter Value"),
- tr("Button Parameter Value"),
- parameterSlotMenu,
- true,
- parameterDescriptionPrefix);
- }
+ QString parameterDescriptionPrefix =
+ QString("%1, %2").arg(slotDescriptionPrefix,
+ m_buttonParameterStr.arg(iParameterSlotNumber));
+
+ // Likely to change soon.
+ addControl(parameterSlotGroup,
+ parameterSlotItemPrefix,
+ tr("Button Parameter Value"),
+ tr("Button Parameter Value"),
+ parameterSlotMenu,
+ true,
+ parameterDescriptionPrefix);
}
}
- // Clear Effect Rack
- addControl(rackGroup,
- "clear",
- tr("Clear Effect Rack"),
- tr("Clear effect rack"),
- effectsMenu,
- false,
- descriptionPrefix);
}
// Microphone Controls
QMenu* microphoneMenu = addSubmenu(tr("Microphone / Auxiliary"));
addMicrophoneAndAuxControl("talkover",
- tr("Microphone On/Off"),
- tr("Microphone on/off"), microphoneMenu,
- true, false);
- addControl("[Master]", "duckStrength",
- tr("Microphone Ducking Strength"),
- tr("Microphone Ducking Strength"),
- microphoneMenu, true);
- addControl("[Master]", "talkoverDucking",
- tr("Microphone Ducking Mode"),
- tr("Toggle microphone ducking mode (OFF, AUTO, MANUAL)"),
- microphoneMenu);
+ tr("Microphone On/Off"),
+ tr("Microphone on/off"),
+ microphoneMenu,
+ true,
+ false);
+ addControl("[Master]",
+ "duckStrength",
+ tr("Microphone Ducking Strength"),
+ tr("Microphone Ducking Strength"),
+ microphoneMenu,
+ true);
+ addControl("[Master]",
+ "talkoverDucking",
+ tr("Microphone Ducking Mode"),
+ tr("Toggle microphone ducking mode (OFF, AUTO, MANUAL)"),
+ microphoneMenu);
addMicrophoneAndAuxControl("passthrough",
- tr("Auxiliary On/Off"),
- tr("Auxiliary on/off"),
- microphoneMenu,
- false, true);
+ tr("Auxiliary On/Off"),
+ tr("Auxiliary on/off"),
+ microphoneMenu,
+ false,
+ true);
microphoneMenu->addSeparator();
addMicrophoneAndAuxControl("pregain",
- tr("Gain"),
- tr("Gain knob"), microphoneMenu,
- true, true, true);
+ tr("Gain"),
+ tr("Gain knob"),
+ microphoneMenu,
+ true,
+ true,
+ true);
addMicrophoneAndAuxControl("volume",
- tr("Volume Fader"),
- tr("Volume Fader"), microphoneMenu,
- true, true, true);
+ tr("Volume Fader"),
+ tr("Volume Fader"),
+ microphoneMenu,
+ true,
+ true,
+ true);
addMicrophoneAndAuxControl("volume_set_one",
- tr("Full Volume"),
- tr("Set to full volume"), microphoneMenu,
- true, true);
+ tr("Full Volume"),
+ tr("Set to full volume"),
+ microphoneMenu,
+ true,
+ true);
addMicrophoneAndAuxControl("volume_set_zero",
- tr("Zero Volume"),
- tr("Set to zero volume"), microphoneMenu,
- true, true);
+ tr("Zero Volume"),
+ tr("Set to zero volume"),
+ microphoneMenu,
+ true,
+ true);
addMicrophoneAndAuxControl("mute",
- tr("Mute"),
- tr("Mute button"), microphoneMenu,
- true, true);
+ tr("Mute"),
+ tr("Mute button"),
+ microphoneMenu,
+ true,
+ true);
addMicrophoneAndAuxControl("pfl",
tr("Headphone Listen"),
tr("Headphone listen button"),
@@ -1081,42 +1202,57 @@ ControlPickerMenu::ControlPickerMenu(QWidget* pParent)
true);
microphoneMenu->addSeparator();
addMicrophoneAndAuxControl("orientation",
- tr("Orientation"),
- tr("Mix orientation (e.g. left, right, center)"),
- microphoneMenu, true, true);
+ tr("Orientation"),
+ tr("Mix orientation (e.g. left, right, center)"),
+ microphoneMenu,
+ true,
+ true);
addMicrophoneAndAuxControl("orientation_left",
- tr("Orient Left"),
- tr("Set mix orientation to left"),
- microphoneMenu,
- true, true);
+ tr("Orient Left"),
+ tr("Set mix orientation to left"),
+ microphoneMenu,
+ true,
+ true);
addMicrophoneAndAuxControl("orientation_center",
- tr("Orient Center"),
- tr("Set mix orientation to center"), microphoneMenu,
- true, true);
+ tr("Orient Center"),
+ tr("Set mix orientation to center"),
+ microphoneMenu,
+ true,
+ true);
addMicrophoneAndAuxControl("orientation_right",
- tr("Orient Right"),
- tr("Set mix orientation to right"), microphoneMenu,
- true, true);
+ tr("Orient Right"),
+ tr("Set mix orientation to right"),
+ microphoneMenu,
+ true,
+ true);
// AutoDJ Controls
QMenu* autodjMenu = addSubmenu(tr("Auto DJ"));
- addControl("[AutoDJ]", "shuffle_playlist",
- tr("Auto DJ Shuffle"),
- tr("Shuffle the content of the Auto DJ queue"), autodjMenu);
- addControl("[AutoDJ]", "skip_next",
- tr("Auto DJ Skip Next"),
- tr("Skip the next track in the Auto DJ queue"), autodjMenu);
+ addControl("[AutoDJ]",
+ "shuffle_playlist",
+ tr("Auto DJ Shuffle"),
+ tr("Shuffle the content of the Auto DJ queue"),
+ autodjMenu);
+ addControl("[AutoDJ]",
+ "skip_next",
+ tr("Auto DJ Skip Next"),
+ tr("Skip the next track in the Auto DJ queue"),
+ autodjMenu);
addControl("[AutoDJ]",
"add_random_track",
tr("Auto DJ Add Random Track"),
tr("Add a random track to the Auto DJ queue"),
autodjMenu);
- addControl("[AutoDJ]", "fade_now",
- tr("Auto DJ Fade To Next"),
- tr("Trigger the transition to the next track"), autodjMenu);
- addControl("[AutoDJ]", "enabled",
- tr("Auto DJ Toggle"),
- tr("Toggle Auto DJ On/Off"), autodjMenu);
+ addControl("[AutoDJ]",
+ "fade_now",
+ tr("Auto DJ Fade To Next"),
+ tr("Trigger the transition to the next track"),
+ autodjMenu);
+ addControl("[AutoDJ]",
+ "enabled",
+ tr("Auto DJ Toggle"),
+ tr("Toggle Auto DJ On/Off"),
+ autodjMenu);
// Skin Controls
QMenu* guiMenu = addSubmenu(tr("User Interface"));
@@ -1212,10 +1348,14 @@ ControlPickerMenu::ControlPickerMenu(QWidget* pParent)
guiMenu->addSeparator();
// Controls to change a deck's star rating
- addDeckAndPreviewDeckControl("stars_up", tr("Star Rating Up"),
- tr("Increase the track rating by one star"), guiMenu);
- addDeckAndPreviewDeckControl("stars_down", tr("Star Rating Down"),
- tr("Decrease the track rating by one star"), guiMenu);
+ addDeckAndPreviewDeckControl("stars_up",
+ tr("Star Rating Up"),
+ tr("Increase the track rating by one star"),
+ guiMenu);
+ addDeckAndPreviewDeckControl("stars_down",
+ tr("Star Rating Down"),
+ tr("Decrease the track rating by one star"),
+ guiMenu);
// Misc. controls
addControl("[Shoutcast]",
@@ -1251,8 +1391,9 @@ void ControlPickerMenu::addSingleControl(const QString& group,
}
auto pAction = make_parented(actionTitle.isEmpty() ? title : actionTitle, pMenu);
- connect(pAction, &QAction::triggered,
- this, [this, controlIndex] { controlChosen(controlIndex); });
+ connect(pAction, &QAction::triggered, this, [this, controlIndex] {
+ controlChosen(controlIndex);
+ });
pMenu->addAction(pAction);
}
@@ -1303,14 +1444,24 @@ void ControlPickerMenu::addPlayerControl(const QString& control,
// PlayerManager::groupForDeck is 0-indexed.
QString prefix = m_deckStr.arg(i);
QString group = PlayerManager::groupForDeck(i - 1);
- addSingleControl(group, control, controlTitle, controlDescription,
- controlMenu, prefix, prefix);
+ addSingleControl(group,
+ control,
+ controlTitle,
+ controlDescription,
+ controlMenu,
+ prefix,
+ prefix);
if (resetControlMenu) {
QString resetTitle = QString("%1 (%2)").arg(controlTitle, m_resetStr);
QString resetDescription = QString("%1 (%2)").arg(controlDescription, m_resetStr);
- addSingleControl(group, resetControl, resetTitle, resetDescription,
- resetControlMenu, prefix, prefix);
+ addSingleControl(group,
+ resetControl,
+ resetTitle,
+ resetDescription,
+ resetControlMenu,
+ prefix,
+ prefix);
}
}
@@ -1323,14 +1474,24 @@ void ControlPickerMenu::addPlayerControl(const QString& control,
prefix = m_previewdeckStr.arg(i);
}
QString group = PlayerManager::groupForPreviewDeck(i - 1);
- addSingleControl(group, control, controlTitle, controlDescription,
- controlMenu, prefix, prefix);
+ addSingleControl(group,
+ control,
+ controlTitle,
+ controlDescription,
+ controlMenu,
+ prefix,
+ prefix);
if (resetControlMenu) {
QString resetTitle = QString("%1 (%2)").arg(controlTitle, m_resetStr);
QString resetDescription = QString("%1 (%2)").arg(controlDescription, m_resetStr);
- addSingleControl(group, resetControl, resetTitle, resetDescription,
- resetControlMenu, prefix, prefix);
+ addSingleControl(group,
+ resetControl,
+ resetTitle,
+ resetDescription,
+ resetControlMenu,
+ prefix,
+ prefix);
}
}
@@ -1393,14 +1554,24 @@ void ControlPickerMenu::addMicrophoneAndAuxControl(const QString& control,
for (int i = 1; i <= kNumMicrophones; ++i) {
QString prefix = m_microphoneStr.arg(i);
QString group = PlayerManager::groupForMicrophone(i - 1);
- addSingleControl(group, control, controlTitle, controlDescription,
- controlMenu, prefix, prefix);
+ addSingleControl(group,
+ control,
+ controlTitle,
+ controlDescription,
+ controlMenu,
+ prefix,
+ prefix);
if (resetControlMenu) {
QString resetTitle = QString("%1 (%2)").arg(controlTitle, m_resetStr);
QString resetDescription = QString("%1 (%2)").arg(controlDescription, m_resetStr);
- addSingleControl(group, resetControl, resetTitle, resetDescription,
- resetControlMenu, prefix, prefix);
+ addSingleControl(group,
+ resetControl,
+ resetTitle,
+ resetDescription,
+ resetControlMenu,
+ prefix,
+ prefix);
}
}
}
@@ -1411,14 +1582,24 @@ void ControlPickerMenu::addMicrophoneAndAuxControl(const QString& control,
for (int i = 1; i <= kNumAuxiliaries; ++i) {
QString prefix = m_auxStr.arg(i);
QString group = PlayerManager::groupForAuxiliary(i - 1);
- addSingleControl(group, control, controlTitle, controlDescription,
- controlMenu, prefix, prefix);
+ addSingleControl(group,
+ control,
+ controlTitle,
+ controlDescription,
+ controlMenu,
+ prefix,
+ prefix);
if (resetControlMenu) {
QString resetTitle = QString("%1 (%2)").arg(controlTitle, m_resetStr);
QString resetDescription = QString("%1 (%2)").arg(controlDescription, m_resetStr);
- addSingleControl(group, resetControl, resetTitle, resetDescription,
- resetControlMenu, prefix, prefix);
+ addSingleControl(group,
+ resetControl,
+ resetTitle,
+ resetDescription,
+ resetControlMenu,
+ prefix,
+ prefix);
}
}
}
diff --git a/src/controllers/controlpickermenu.h b/src/controllers/controlpickermenu.h
index 62b9430388b1..4b7a0c247f7f 100644
--- a/src/controllers/controlpickermenu.h
+++ b/src/controllers/controlpickermenu.h
@@ -28,7 +28,7 @@ class ControlPickerMenu : public QMenu {
void controlChosen(int controlIndex);
private:
- QMenu* addSubmenu(QString title, QMenu* pParent=NULL);
+ QMenu* addSubmenu(QString title, QMenu* pParent = NULL);
void addSingleControl(const QString& group,
const QString& control,
const QString& title,
@@ -103,6 +103,7 @@ class ControlPickerMenu : public QMenu {
QString m_effectUnitStr;
QString m_effectStr;
QString m_parameterStr;
+ QString m_buttonParameterStr;
QString m_libraryStr;
QList m_controlsAvailable;
diff --git a/src/coreservices.cpp b/src/coreservices.cpp
index 3abfef80452a..3d46eec316ce 100644
--- a/src/coreservices.cpp
+++ b/src/coreservices.cpp
@@ -12,11 +12,7 @@
#include "controllers/controllermanager.h"
#include "controllers/keyboard/keyboardeventfilter.h"
#include "database/mixxxdb.h"
-#include "effects/builtin/builtinbackend.h"
#include "effects/effectsmanager.h"
-#ifdef __LILV__
-#include "effects/lv2/lv2backend.h"
-#endif
#include "engine/enginemaster.h"
#include "library/coverartcache.h"
#include "library/library.h"
@@ -256,7 +252,7 @@ void CoreServices::initialize(QApplication* pApp) {
auto pChannelHandleFactory = std::make_shared();
emit initializationProgressUpdate(20, tr("effects"));
- m_pEffectsManager = std::make_shared(this, pConfig, pChannelHandleFactory);
+ m_pEffectsManager = std::make_shared(pConfig, pChannelHandleFactory);
m_pEngine = std::make_shared(
pConfig,
@@ -265,20 +261,6 @@ void CoreServices::initialize(QApplication* pApp) {
pChannelHandleFactory,
true);
- // 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.get());
- m_pEffectsManager->addEffectsBackend(pBuiltInBackend);
-#ifdef __LILV__
- m_pLV2Backend = new LV2Backend(m_pEffectsManager.get());
- // EffectsManager takes ownership
- m_pEffectsManager->addEffectsBackend(m_pLV2Backend);
-#else
- m_pLV2Backend = nullptr;
-#endif
-
- m_pEffectsManager->setup();
-
emit initializationProgressUpdate(30, tr("audio interface"));
// Although m_pSoundManager is created here, m_pSoundManager->setupDevices()
// needs to be called after m_pPlayerManager registers sound IO for each EngineChannel.
@@ -324,7 +306,7 @@ void CoreServices::initialize(QApplication* pApp) {
m_pPlayerManager->addSampler();
m_pPlayerManager->addPreviewDeck();
- m_pEffectsManager->loadEffectChains();
+ m_pEffectsManager->setup();
#ifdef __VINYLCONTROL__
m_pVCManager->init();
diff --git a/src/effects/builtin/autopaneffect.cpp b/src/effects/backends/builtin/autopaneffect.cpp
similarity index 75%
rename from src/effects/builtin/autopaneffect.cpp
rename to src/effects/backends/builtin/autopaneffect.cpp
index d425e5ca6e47..286772e053cf 100644
--- a/src/effects/builtin/autopaneffect.cpp
+++ b/src/effects/backends/builtin/autopaneffect.cpp
@@ -1,4 +1,4 @@
-#include "effects/builtin/autopaneffect.h"
+#include "effects/backends/builtin/autopaneffect.h"
#include
@@ -6,8 +6,7 @@
#include "util/math.h"
#include "util/sample.h"
-const float kPositionRampingThreshold = 0.002f;
-
+constexpr float kPositionRampingThreshold = 0.002f;
// static
QString AutoPanEffect::getId() {
@@ -23,7 +22,7 @@ EffectManifestPointer AutoPanEffect::getManifest() {
pManifest->setAuthor("The Mixxx Team");
pManifest->setVersion("1.0");
pManifest->setDescription(QObject::tr(
- "Bounce the sound left and right across the stereo field"));
+ "Bounce the sound left and right across the stereo field"));
// Period
EffectManifestParameterPointer period = pManifest->addParameter();
@@ -31,31 +30,26 @@ EffectManifestPointer AutoPanEffect::getManifest() {
period->setName(QObject::tr("Period"));
period->setShortName(QObject::tr("Period"));
period->setDescription(QObject::tr(
- "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->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);
+ "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->setValueScaler(EffectManifestParameter::ValueScaler::Linear);
+ period->setUnitsHint(EffectManifestParameter::UnitsHint::Unknown);
+ period->setDefaultLinkType(EffectManifestParameter::LinkType::Linked);
+ period->setDefaultLinkInversion(EffectManifestParameter::LinkInversion::Inverted);
+ period->setRange(0.0, 2.0, 4.0);
EffectManifestParameterPointer smoothing = pManifest->addParameter();
smoothing->setId("smoothing");
smoothing->setName(QObject::tr("Smoothing"));
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->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);
+ "How smoothly the signal goes from one side to the other"));
+ smoothing->setValueScaler(EffectManifestParameter::ValueScaler::Logarithmic);
+ smoothing->setUnitsHint(EffectManifestParameter::UnitsHint::Unknown);
+ smoothing->setDefaultLinkType(EffectManifestParameter::LinkType::Linked);
+ 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.
@@ -65,35 +59,32 @@ EffectManifestPointer AutoPanEffect::getManifest() {
width->setName(QObject::tr("Width"));
width->setShortName(QObject::tr("Width"));
width->setDescription(QObject::tr(
- "How far the signal goes to each side"));
- width->setControlHint(EffectManifestParameter::ControlHint::KNOB_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);
+ "How far the signal goes to each side"));
+ width->setValueScaler(EffectManifestParameter::ValueScaler::Linear);
+ width->setUnitsHint(EffectManifestParameter::UnitsHint::Unknown);
+ width->setDefaultLinkType(EffectManifestParameter::LinkType::Linked);
+ 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,
- const CSAMPLE* pInput, CSAMPLE* pOutput,
- const mixxx::EngineParameters& bufferParameters,
- const EffectEnableState enableState,
- const GroupFeatureState& groupFeatures) {
- Q_UNUSED(handle);
-
+ AutoPanGroupState* pGroupState,
+ const CSAMPLE* pInput,
+ CSAMPLE* pOutput,
+ const mixxx::EngineParameters& bufferParameters,
+ const EffectEnableState enableState,
+ const GroupFeatureState& groupFeatures) {
if (enableState == EffectEnableState::Disabled) {
return;
}
diff --git a/src/effects/builtin/autopaneffect.h b/src/effects/backends/builtin/autopaneffect.h
similarity index 80%
rename from src/effects/builtin/autopaneffect.h
rename to src/effects/backends/builtin/autopaneffect.h
index 97c4e3da8028..ab1b28481a35 100644
--- a/src/effects/builtin/autopaneffect.h
+++ b/src/effects/backends/builtin/autopaneffect.h
@@ -2,7 +2,7 @@
#include
-#include "effects/effectprocessor.h"
+#include "effects/backends/effectprocessor.h"
#include "engine/effects/engineeffect.h"
#include "engine/effects/engineeffectparameter.h"
#include "engine/filters/enginefilterpansingle.h"
@@ -17,11 +17,11 @@
// somewhere else (I hear clicks when I change the period of flanger for example).
class RampedSample {
public:
-
inline RampedSample()
- : ramped(false),
- maxDifference(1.0f),
- initialized(false) {}
+ : ramped(false),
+ maxDifference(1.0f),
+ initialized(false) {
+ }
virtual ~RampedSample(){};
@@ -78,30 +78,33 @@ class AutoPanGroupState : public EffectState {
class AutoPanEffect : public EffectProcessorImpl {
public:
- AutoPanEffect(EngineEffect* pEffect);
+ AutoPanEffect() = default;
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 CSAMPLE* pInput,
+ CSAMPLE* pOutput,
const mixxx::EngineParameters& bufferParameters,
const EffectEnableState enableState,
- const GroupFeatureState& groupFeatures);
+ const GroupFeatureState& groupFeatures) override;
double computeLawCoefficient(double position);
private:
-
QString debugString() const {
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/backends/builtin/balanceeffect.cpp
similarity index 61%
rename from src/effects/builtin/balanceeffect.cpp
rename to src/effects/backends/builtin/balanceeffect.cpp
index 024f454ccd32..82227c0da9b3 100644
--- a/src/effects/builtin/balanceeffect.cpp
+++ b/src/effects/backends/builtin/balanceeffect.cpp
@@ -21,54 +21,46 @@ EffectManifestPointer BalanceEffect::getManifest() {
pManifest->setAuthor("The Mixxx Team");
pManifest->setVersion("1.0");
pManifest->setDescription(QObject::tr(
- "Adjust the left/right balance and stereo width"));
+ "Adjust the left/right balance and stereo width"));
pManifest->setEffectRampsFromDry(true);
+ pManifest->setMetaknobDefault(0.5);
EffectManifestParameterPointer balance = pManifest->addParameter();
balance->setId("balance");
balance->setName(QObject::tr("Balance"));
balance->setShortName(QObject::tr("Balance"));
balance->setDescription(QObject::tr(
- "Adjust balance between left and right channels"));
- balance->setControlHint(EffectManifestParameter::ControlHint::KNOB_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);
+ "Adjust balance between left and right channels"));
+ balance->setValueScaler(EffectManifestParameter::ValueScaler::Linear);
+ balance->setUnitsHint(EffectManifestParameter::UnitsHint::Unknown);
+ balance->setDefaultLinkType(EffectManifestParameter::LinkType::Linked);
+ balance->setRange(-1.0, 0.0, +1.0);
EffectManifestParameterPointer midSide = pManifest->addParameter();
midSide->setId("midSide");
midSide->setName(QObject::tr("Mid/Side"));
midSide->setShortName(QObject::tr("Mid/Side"));
midSide->setDescription(QObject::tr(
- "Adjust stereo width by changing balance between middle and side of the signal.\n"
- "Fully left: mono\n"
- "Fully right: only side ambiance\n"
- "Center: does not change the original signal."));
- midSide->setControlHint(EffectManifestParameter::ControlHint::KNOB_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);
+ "Adjust stereo width by changing balance between middle and side of the signal.\n"
+ "Fully left: mono\n"
+ "Fully right: only side ambiance\n"
+ "Center: does not change the original signal."));
+ midSide->setValueScaler(EffectManifestParameter::ValueScaler::Linear);
+ midSide->setUnitsHint(EffectManifestParameter::UnitsHint::Unknown);
+ midSide->setDefaultLinkType(EffectManifestParameter::LinkType::None);
+ midSide->setRange(-1.0, 0.0, +1.0);
EffectManifestParameterPointer midLowPass = pManifest->addParameter();
midLowPass->setId("bypassFreq");
midLowPass->setName(QObject::tr("Bypass Frequency"));
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->setSemanticHint(EffectManifestParameter::SemanticHint::UNKNOWN);
- midLowPass->setUnitsHint(EffectManifestParameter::UnitsHint::UNKNOWN);
- midLowPass->setDefaultLinkType(EffectManifestParameter::LinkType::NONE);
+ "Frequencies below this cutoff are not adjusted in the stereo field"));
+ midLowPass->setValueScaler(EffectManifestParameter::ValueScaler::Logarithmic);
+ 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;
}
@@ -81,9 +73,9 @@ BalanceGroupState::BalanceGroupState(const mixxx::EngineParameters& bufferParame
m_oldBalance(0),
m_oldMidSide(0) {
m_low = std::make_unique(bufferParameters.sampleRate(),
- kMinCornerHz);
+ kMinCornerHz);
m_high = std::make_unique(bufferParameters.sampleRate(),
- kMinCornerHz);
+ kMinCornerHz);
m_high->setStartFromDry(true);
}
@@ -95,22 +87,23 @@ void BalanceGroupState::setFilters(int sampleRate, double 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;
@@ -120,10 +113,10 @@ void BalanceEffect::processChannel(const ChannelHandle& handle,
midSide = static_cast(m_pMidSideParameter->value());
}
- CSAMPLE_GAIN balanceDelta = (balance - pGroupState->m_oldBalance)
- / CSAMPLE_GAIN(bufferParameters.framesPerBuffer());
- CSAMPLE_GAIN midSideDelta = (midSide - pGroupState->m_oldMidSide)
- / CSAMPLE_GAIN(bufferParameters.framesPerBuffer());
+ CSAMPLE_GAIN balanceDelta = (balance - pGroupState->m_oldBalance) /
+ CSAMPLE_GAIN(bufferParameters.framesPerBuffer());
+ CSAMPLE_GAIN midSideDelta = (midSide - pGroupState->m_oldMidSide) /
+ CSAMPLE_GAIN(bufferParameters.framesPerBuffer());
CSAMPLE_GAIN balanceStart = pGroupState->m_oldBalance + balanceDelta;
CSAMPLE_GAIN midSideStart = pGroupState->m_oldMidSide + midSideDelta;
@@ -138,16 +131,25 @@ void BalanceEffect::processChannel(const ChannelHandle& handle,
if (pGroupState->m_freq > kMinCornerHz) {
if (freq > kMinCornerHz && enableState != EffectEnableState::Disabling) {
- pGroupState->m_high->process(pInput, pGroupState->m_pHighBuf.data(), bufferParameters.samplesPerBuffer());
+ pGroupState->m_high->process(pInput,
+ pGroupState->m_pHighBuf.data(),
+ bufferParameters.samplesPerBuffer());
pGroupState->m_low->process(pInput, pOutput, bufferParameters.samplesPerBuffer());
} else {
- pGroupState->m_high->processAndPauseFilter(pInput, pGroupState->m_pHighBuf.data(), bufferParameters.samplesPerBuffer());
- pGroupState->m_low->processAndPauseFilter(pInput, pOutput, bufferParameters.samplesPerBuffer());
+ pGroupState->m_high->processAndPauseFilter(pInput,
+ pGroupState->m_pHighBuf.data(),
+ bufferParameters.samplesPerBuffer());
+ pGroupState->m_low->processAndPauseFilter(
+ pInput, pOutput, bufferParameters.samplesPerBuffer());
}
for (SINT i = 0; i < bufferParameters.samplesPerBuffer() / 2; ++i) {
- CSAMPLE mid = (pGroupState->m_pHighBuf[i * 2] + pGroupState->m_pHighBuf[i * 2 + 1]) / 2.0f;
- CSAMPLE side = (pGroupState->m_pHighBuf[i * 2 + 1] - pGroupState->m_pHighBuf[i * 2]) / 2.0f;
+ CSAMPLE mid = (pGroupState->m_pHighBuf[i * 2] +
+ pGroupState->m_pHighBuf[i * 2 + 1]) /
+ 2.0f;
+ CSAMPLE side = (pGroupState->m_pHighBuf[i * 2 + 1] -
+ pGroupState->m_pHighBuf[i * 2]) /
+ 2.0f;
CSAMPLE_GAIN currentMidSide = midSideStart + midSideDelta * i;
if (currentMidSide > 0) {
mid *= (1 - currentMidSide);
@@ -168,21 +170,21 @@ void BalanceEffect::processChannel(const ChannelHandle& handle,
pGroupState->m_low->pauseFilter();
for (SINT i = 0; i < bufferParameters.samplesPerBuffer() / 2; ++i) {
- CSAMPLE mid = (pInput[i * 2] + pInput[i * 2 + 1]) / 2.0f;
+ CSAMPLE mid = (pInput[i * 2] + pInput[i * 2 + 1]) / 2.0f;
CSAMPLE side = (pInput[i * 2 + 1] - pInput[i * 2]) / 2.0f;
CSAMPLE_GAIN currentMidSide = midSideStart + midSideDelta * i;
if (currentMidSide > 0) {
- mid *= (1 - currentMidSide);
+ mid *= (1 - currentMidSide);
} else {
- side *= (1 + currentMidSide);
+ side *= (1 + currentMidSide);
}
CSAMPLE_GAIN currentBalance = (balanceStart + balanceDelta * i);
if (currentBalance > 0) {
- pOutput[i * 2] = (mid - side) * (1 - currentBalance);
- pOutput[i * 2 + 1] = (mid + side);
+ pOutput[i * 2] = (mid - side) * (1 - currentBalance);
+ pOutput[i * 2 + 1] = (mid + side);
} else {
- pOutput[i * 2] = (mid - side);
- pOutput[i * 2 + 1] = (mid + side) * (1 + currentBalance);
+ pOutput[i * 2] = (mid - side);
+ pOutput[i * 2 + 1] = (mid + side) * (1 + currentBalance);
}
}
}
diff --git a/src/effects/builtin/balanceeffect.h b/src/effects/backends/builtin/balanceeffect.h
similarity index 60%
rename from src/effects/builtin/balanceeffect.h
rename to src/effects/backends/builtin/balanceeffect.h
index 4562c93a0ea6..f85deaa7c702 100644
--- a/src/effects/builtin/balanceeffect.h
+++ b/src/effects/backends/builtin/balanceeffect.h
@@ -1,11 +1,11 @@
#pragma once
-#include "effects/effectprocessor.h"
+#include "effects/backends/effectprocessor.h"
#include "engine/effects/engineeffect.h"
#include "engine/effects/engineeffectparameter.h"
#include "engine/filters/enginefilterlinkwitzriley4.h"
-#include "util/samplebuffer.h"
#include "util/memory.h"
+#include "util/samplebuffer.h"
class BalanceGroupState : public EffectState {
public:
@@ -28,28 +28,31 @@ class BalanceGroupState : public EffectState {
class BalanceEffect : public EffectProcessorImpl {
public:
- BalanceEffect(EngineEffect* pEffect);
+ BalanceEffect() = default;
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;
- private:
+ void processChannel(
+ BalanceGroupState* 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_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/backends/builtin/bessel4lvmixeqeffect.cpp
similarity index 51%
rename from src/effects/builtin/bessel4lvmixeqeffect.cpp
rename to src/effects/backends/builtin/bessel4lvmixeqeffect.cpp
index d04873ca60f1..89f46e3dd580 100644
--- a/src/effects/builtin/bessel4lvmixeqeffect.cpp
+++ b/src/effects/backends/builtin/bessel4lvmixeqeffect.cpp
@@ -1,6 +1,6 @@
-#include "effects/builtin/bessel4lvmixeqeffect.h"
+#include "effects/backends/builtin/bessel4lvmixeqeffect.h"
-#include "effects/builtin/equalizer_util.h"
+#include "effects/backends/builtin/equalizer_util.h"
#include "util/math.h"
// static
@@ -16,8 +16,11 @@ EffectManifestPointer Bessel4LVMixEQEffect::getManifest() {
pManifest->setShortName(QObject::tr("Bessel4 ISO"));
pManifest->setAuthor("The Mixxx Team");
pManifest->setVersion("1.0");
- pManifest->setDescription(QObject::tr(
- "A Bessel 4th-order filter isolator with Lipshitz and Vanderkooy mix (bit perfect unity, roll-off -24 dB/octave).") + " " + EqualizerUtil::adjustFrequencyShelvesTip());
+ pManifest->setDescription(
+ QObject::tr("A Bessel 4th-order filter isolator with Lipshitz and "
+ "Vanderkooy mix (bit perfect unity, roll-off -24 "
+ "dB/octave).") +
+ " " + EqualizerUtil::adjustFrequencyShelvesTip());
pManifest->setIsMixingEQ(true);
pManifest->setEffectRampsFromDry(true);
@@ -25,29 +28,33 @@ 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) {
@@ -72,10 +79,14 @@ void Bessel4LVMixEQEffect::processChannel(const ChannelHandle& handle,
} else {
fHigh = 0;
}
- pState->processChannel(pInput, pOutput,
- bufferParameters.samplesPerBuffer(),
- bufferParameters.sampleRate(),
- fLow, fMid, fHigh,
- m_pLoFreqCorner->get(), m_pHiFreqCorner->get());
+ pState->processChannel(pInput,
+ pOutput,
+ bufferParameters.samplesPerBuffer(),
+ bufferParameters.sampleRate(),
+ fLow,
+ fMid,
+ fHigh,
+ m_pLoFreqCorner->get(),
+ m_pHiFreqCorner->get());
}
}
diff --git a/src/effects/backends/builtin/bessel4lvmixeqeffect.h b/src/effects/backends/builtin/bessel4lvmixeqeffect.h
new file mode 100644
index 000000000000..826c7e76f0d9
--- /dev/null
+++ b/src/effects/backends/builtin/bessel4lvmixeqeffect.h
@@ -0,0 +1,58 @@
+#pragma once
+#include
+
+#include "control/controlproxy.h"
+#include "effects/backends/builtin/lvmixeqbase.h"
+#include "effects/backends/effectprocessor.h"
+#include "engine/effects/engineeffect.h"
+#include "engine/effects/engineeffectparameter.h"
+#include "engine/filters/enginefilterbessel4.h"
+#include "engine/filters/enginefilterdelay.h"
+#include "util/class.h"
+#include "util/defs.h"
+#include "util/types.h"
+
+class Bessel4LVMixEQEffectGroupState : public LVMixEQEffectGroupState {
+ public:
+ Bessel4LVMixEQEffectGroupState(const mixxx::EngineParameters& bufferParameters)
+ : LVMixEQEffectGroupState(bufferParameters) {
+ }
+};
+
+class Bessel4LVMixEQEffect : public EffectProcessorImpl {
+ public:
+ Bessel4LVMixEQEffect();
+ virtual ~Bessel4LVMixEQEffect();
+
+ static QString getId();
+ static EffectManifestPointer getManifest();
+
+ 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();
+ }
+
+ EngineEffectParameterPointer m_pPotLow;
+ EngineEffectParameterPointer m_pPotMid;
+ EngineEffectParameterPointer m_pPotHigh;
+
+ EngineEffectParameterPointer m_pKillLow;
+ EngineEffectParameterPointer m_pKillMid;
+ EngineEffectParameterPointer m_pKillHigh;
+
+ ControlProxy* m_pLoFreqCorner;
+ ControlProxy* m_pHiFreqCorner;
+
+ DISALLOW_COPY_AND_ASSIGN(Bessel4LVMixEQEffect);
+};
diff --git a/src/effects/builtin/bessel8lvmixeqeffect.cpp b/src/effects/backends/builtin/bessel8lvmixeqeffect.cpp
similarity index 52%
rename from src/effects/builtin/bessel8lvmixeqeffect.cpp
rename to src/effects/backends/builtin/bessel8lvmixeqeffect.cpp
index 898a28f798bb..ee15e60ad986 100644
--- a/src/effects/builtin/bessel8lvmixeqeffect.cpp
+++ b/src/effects/backends/builtin/bessel8lvmixeqeffect.cpp
@@ -1,6 +1,6 @@
-#include "effects/builtin/bessel8lvmixeqeffect.h"
+#include "effects/backends/builtin/bessel8lvmixeqeffect.h"
-#include "effects/builtin/equalizer_util.h"
+#include "effects/backends/builtin/equalizer_util.h"
#include "util/math.h"
// static
@@ -16,8 +16,11 @@ EffectManifestPointer Bessel8LVMixEQEffect::getManifest() {
pManifest->setShortName(QObject::tr("Bessel8 ISO"));
pManifest->setAuthor("The Mixxx Team");
pManifest->setVersion("1.0");
- pManifest->setDescription(QObject::tr(
- "A Bessel 8th-order filter isolator with Lipshitz and Vanderkooy mix (bit perfect unity, roll-off -48 dB/octave).") + " " + EqualizerUtil::adjustFrequencyShelvesTip());
+ pManifest->setDescription(
+ QObject::tr("A Bessel 8th-order filter isolator with Lipshitz and "
+ "Vanderkooy mix (bit perfect unity, roll-off -48 "
+ "dB/octave).") +
+ " " + EqualizerUtil::adjustFrequencyShelvesTip());
pManifest->setIsMixingEQ(true);
pManifest->setEffectRampsFromDry(true);
@@ -25,29 +28,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) {
@@ -72,10 +79,14 @@ void Bessel8LVMixEQEffect::processChannel(const ChannelHandle& handle,
} else {
fHigh = 0;
}
- pState->processChannel(
- pInput, pOutput,
- bufferParameters.samplesPerBuffer(), bufferParameters.sampleRate(),
- fLow, fMid, fHigh,
- m_pLoFreqCorner->get(), m_pHiFreqCorner->get());
+ pState->processChannel(pInput,
+ pOutput,
+ bufferParameters.samplesPerBuffer(),
+ bufferParameters.sampleRate(),
+ fLow,
+ fMid,
+ fHigh,
+ m_pLoFreqCorner->get(),
+ m_pHiFreqCorner->get());
}
}
diff --git a/src/effects/backends/builtin/bessel8lvmixeqeffect.h b/src/effects/backends/builtin/bessel8lvmixeqeffect.h
new file mode 100644
index 000000000000..00e81473f363
--- /dev/null
+++ b/src/effects/backends/builtin/bessel8lvmixeqeffect.h
@@ -0,0 +1,60 @@
+#pragma once
+
+#include
+
+#include "control/controlproxy.h"
+#include "effects/backends/builtin/lvmixeqbase.h"
+#include "effects/backends/effectprocessor.h"
+#include "engine/effects/engineeffect.h"
+#include "engine/effects/engineeffectparameter.h"
+#include "engine/filters/enginefilterbessel8.h"
+#include "engine/filters/enginefilterdelay.h"
+#include "util/class.h"
+#include "util/defs.h"
+#include "util/sample.h"
+#include "util/types.h"
+
+class Bessel8LVMixEQEffectGroupState : public LVMixEQEffectGroupState {
+ public:
+ Bessel8LVMixEQEffectGroupState(const mixxx::EngineParameters& bufferParameters)
+ : LVMixEQEffectGroupState(bufferParameters) {
+ }
+};
+
+class Bessel8LVMixEQEffect : public EffectProcessorImpl {
+ public:
+ Bessel8LVMixEQEffect();
+ virtual ~Bessel8LVMixEQEffect();
+
+ static QString getId();
+ static EffectManifestPointer getManifest();
+
+ 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();
+ }
+
+ EngineEffectParameterPointer m_pPotLow;
+ EngineEffectParameterPointer m_pPotMid;
+ EngineEffectParameterPointer m_pPotHigh;
+
+ EngineEffectParameterPointer m_pKillLow;
+ EngineEffectParameterPointer m_pKillMid;
+ EngineEffectParameterPointer m_pKillHigh;
+
+ ControlProxy* m_pLoFreqCorner;
+ ControlProxy* m_pHiFreqCorner;
+
+ DISALLOW_COPY_AND_ASSIGN(Bessel8LVMixEQEffect);
+};
diff --git a/src/effects/builtin/biquadfullkilleqeffect.cpp b/src/effects/backends/builtin/biquadfullkilleqeffect.cpp
similarity index 90%
rename from src/effects/builtin/biquadfullkilleqeffect.cpp
rename to src/effects/backends/builtin/biquadfullkilleqeffect.cpp
index 4c3845562846..c4672ff0a360 100644
--- a/src/effects/builtin/biquadfullkilleqeffect.cpp
+++ b/src/effects/backends/builtin/biquadfullkilleqeffect.cpp
@@ -1,6 +1,6 @@
-#include "effects/builtin/biquadfullkilleqeffect.h"
+#include "effects/backends/builtin/biquadfullkilleqeffect.h"
-#include "effects/builtin/equalizer_util.h"
+#include "effects/backends/builtin/equalizer_util.h"
#include "util/math.h"
namespace {
@@ -23,7 +23,7 @@ double getCenterFrequency(double low, double high) {
return pow(10, scaleCenter);
}
-double knobValueToBiquadGainDb (double value, bool kill) {
+double knobValueToBiquadGainDb(double value, bool kill) {
if (kill) {
return kKillGain;
}
@@ -33,10 +33,9 @@ double knobValueToBiquadGainDb (double value, bool kill) {
double startDB = ratio2db(kBesselStartRatio);
value = 1 - (value / kBesselStartRatio);
return (kKillGain - startDB) * value + startDB;
-
}
-double knobValueToBesselRatio (double value, bool kill) {
+double knobValueToBesselRatio(double value, bool kill) {
if (kill) {
return 0.0;
}
@@ -45,7 +44,6 @@ double knobValueToBesselRatio (double value, bool kill) {
} // anonymous namespace
-
// static
QString BiquadFullKillEQEffect::getId() {
return "org.mixxx.effects.biquadfullkilleq";
@@ -59,8 +57,11 @@ EffectManifestPointer BiquadFullKillEQEffect::getManifest() {
pManifest->setShortName(QObject::tr("BQ EQ/ISO"));
pManifest->setAuthor("The Mixxx Team");
pManifest->setVersion("1.0");
- pManifest->setDescription(QObject::tr(
- "A 3-band Equalizer that combines an Equalizer and an Isolator circuit to offer gentle slopes and full kill.") + " " + EqualizerUtil::adjustFrequencyShelvesTip());
+ pManifest->setDescription(
+ QObject::tr(
+ "A 3-band Equalizer that combines an Equalizer and an "
+ "Isolator circuit to offer gentle slopes and full kill.") +
+ " " + EqualizerUtil::adjustFrequencyShelvesTip());
pManifest->setEffectRampsFromDry(true);
pManifest->setIsMixingEQ(true);
@@ -125,7 +126,6 @@ void BiquadFullKillEQEffectGroupState::setFilters(
double midCenter = getCenterFrequency(lowFreqCorner, highFreqCorner);
double highCenter = getCenterFrequency(highFreqCorner, kMaximumFrequency);
-
m_lowBoost->setFrequencyCorners(
sampleRate, lowCenter, kQBoost, m_oldLowBoost);
m_midBoost->setFrequencyCorners(
@@ -142,29 +142,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() ||
@@ -174,7 +176,8 @@ void BiquadFullKillEQEffect::processChannel(
pState->m_highFreqCorner = m_pHiFreqCorner->get();
pState->m_oldSampleRate = bufferParameters.sampleRate();
pState->setFilters(bufferParameters.sampleRate(),
- pState->m_loFreqCorner, pState->m_highFreqCorner);
+ pState->m_loFreqCorner,
+ pState->m_highFreqCorner);
}
// Ramp to dry, when disabling, this will ramp from dry when enabling as well
@@ -232,9 +235,7 @@ void BiquadFullKillEQEffect::processChannel(
inBuffer.append(pState->m_tempBuf.data());
outBuffer.append(pOutput);
- }
- else
- {
+ } else {
inBuffer.append(pInput);
outBuffer.append(pOutput);
@@ -276,7 +277,6 @@ void BiquadFullKillEQEffect::processChannel(
pState->m_lowBoost->pauseFilter();
}
-
if (bqGainLow < 0.0 || pState->m_oldLowKill < 0.0) {
if (bqGainLow != pState->m_oldLowKill) {
double lowCenter = getCenterFrequency(
@@ -295,7 +295,6 @@ void BiquadFullKillEQEffect::processChannel(
++bufIndex;
} else {
pState->m_lowKill->pauseFilter();
-
}
if (bqGainMid > 0.0 || pState->m_oldMidBoost > 0.0) {
@@ -392,7 +391,8 @@ void BiquadFullKillEQEffect::processChannel(
}
if (enableState == EffectEnableState::Disabling) {
- pState->m_lvMixIso->processChannelAndPause(pOutput, pOutput, bufferParameters.samplesPerBuffer());
+ pState->m_lvMixIso->processChannelAndPause(
+ pOutput, pOutput, bufferParameters.samplesPerBuffer());
} else {
double fLow = knobValueToBesselRatio(
m_pPotLow->value(), m_pKillLow->toBool());
@@ -400,10 +400,14 @@ void BiquadFullKillEQEffect::processChannel(
m_pPotMid->value(), m_pKillMid->toBool());
double fHigh = knobValueToBesselRatio(
m_pPotHigh->value(), m_pKillHigh->toBool());
- pState->m_lvMixIso->processChannel(
- pOutput, pOutput,
- bufferParameters.samplesPerBuffer(), bufferParameters.sampleRate(),
- fLow, fMid, fHigh,
- m_pLoFreqCorner->get(), m_pHiFreqCorner->get());
+ pState->m_lvMixIso->processChannel(pOutput,
+ pOutput,
+ bufferParameters.samplesPerBuffer(),
+ bufferParameters.sampleRate(),
+ fLow,
+ fMid,
+ fHigh,
+ m_pLoFreqCorner->get(),
+ m_pHiFreqCorner->get());
}
}
diff --git a/src/effects/builtin/biquadfullkilleqeffect.h b/src/effects/backends/builtin/biquadfullkilleqeffect.h
similarity index 71%
rename from src/effects/builtin/biquadfullkilleqeffect.h
rename to src/effects/backends/builtin/biquadfullkilleqeffect.h
index 3a2a4063a2a5..55239882e06e 100644
--- a/src/effects/builtin/biquadfullkilleqeffect.h
+++ b/src/effects/backends/builtin/biquadfullkilleqeffect.h
@@ -1,20 +1,19 @@
#pragma once
#include "control/controlproxy.h"
-#include "effects/effect.h"
-#include "effects/effectprocessor.h"
+#include "effects/backends/builtin/lvmixeqbase.h"
+#include "effects/backends/effectprocessor.h"
#include "engine/effects/engineeffect.h"
#include "engine/effects/engineeffectparameter.h"
-#include "engine/filters/enginefilterbiquad1.h"
#include "engine/filters/enginefilterbessel4.h"
-#include "effects/builtin/lvmixeqbase.h"
+#include "engine/filters/enginefilterbiquad1.h"
#include "engine/filters/enginefilterdelay.h"
#include "util/class.h"
#include "util/defs.h"
-#include "util/sample.h"
-#include "util/types.h"
#include "util/memory.h"
+#include "util/sample.h"
#include "util/samplebuffer.h"
+#include "util/types.h"
class BiquadFullKillEQEffectGroupState : public EffectState {
public:
@@ -59,23 +58,26 @@ class BiquadFullKillEQEffectGroupState : public EffectState {
class BiquadFullKillEQEffect : public EffectProcessorImpl {
public:
- BiquadFullKillEQEffect(EngineEffect* pEffect);
+ BiquadFullKillEQEffect();
static QString getId();
static EffectManifestPointer getManifest();
- void setFilters(
- mixxx::audio::SampleRate sampleRate,
+ 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 setFilters(mixxx::audio::SampleRate sampleRate,
double lowFreqCorner,
double highFreqCorner);
- void processChannel(const ChannelHandle& handle,
- BiquadFullKillEQEffectGroupState* pState,
- const CSAMPLE* pInput, CSAMPLE *pOutput,
- const mixxx::EngineParameters& bufferParameters,
- const EffectEnableState enableState,
- const GroupFeatureState& groupFeatureState) override;
-
private:
BiquadFullKillEQEffect(const BiquadFullKillEQEffect&) = delete;
void operator=(const BiquadFullKillEQEffect&) = delete;
@@ -84,13 +86,13 @@ class BiquadFullKillEQEffect : public EffectProcessorImpl m_pLoFreqCorner;
std::unique_ptr m_pHiFreqCorner;
diff --git a/src/effects/builtin/bitcrushereffect.cpp b/src/effects/backends/builtin/bitcrushereffect.cpp
similarity index 62%
rename from src/effects/builtin/bitcrushereffect.cpp
rename to src/effects/backends/builtin/bitcrushereffect.cpp
index 0f41fd054f3e..161572acda9f 100644
--- a/src/effects/builtin/bitcrushereffect.cpp
+++ b/src/effects/backends/builtin/bitcrushereffect.cpp
@@ -1,4 +1,4 @@
-#include "effects/builtin/bitcrushereffect.h"
+#include "effects/backends/builtin/bitcrushereffect.h"
#include "util/sample.h"
@@ -16,63 +16,57 @@ EffectManifestPointer BitCrusherEffect::getManifest() {
pManifest->setAuthor("The Mixxx Team");
pManifest->setVersion("1.0");
pManifest->setDescription(QObject::tr(
- "Adds noise by the reducing the bit depth and sample rate"));
+ "Adds noise by the reducing the bit depth and sample rate"));
pManifest->setEffectRampsFromDry(true);
- pManifest->setMetaknobDefault(0.0);
EffectManifestParameterPointer depth = pManifest->addParameter();
depth->setId("bit_depth");
depth->setName(QObject::tr("Bit Depth"));
depth->setShortName(QObject::tr("Bit Depth"));
depth->setDescription(QObject::tr(
- "The bit depth of the samples"));
- depth->setControlHint(EffectManifestParameter::ControlHint::KNOB_LOGARITHMIC);
- depth->setSemanticHint(EffectManifestParameter::SemanticHint::UNKNOWN);
- depth->setUnitsHint(EffectManifestParameter::UnitsHint::UNKNOWN);
- depth->setDefaultLinkType(EffectManifestParameter::LinkType::LINKED);
- depth->setDefaultLinkInversion(EffectManifestParameter::LinkInversion::INVERTED);
+ "The bit depth of the samples"));
+ depth->setValueScaler(EffectManifestParameter::ValueScaler::Logarithmic);
+ 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");
frequency->setName(QObject::tr("Downsampling"));
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->setSemanticHint(EffectManifestParameter::SemanticHint::UNKNOWN);
- frequency->setUnitsHint(EffectManifestParameter::UnitsHint::SAMPLERATE);
- frequency->setDefaultLinkType(EffectManifestParameter::LinkType::LINKED);
- frequency->setDefaultLinkInversion(EffectManifestParameter::LinkInversion::INVERTED);
+ "The sample rate to which the signal is downsampled"));
+ frequency->setValueScaler(EffectManifestParameter::ValueScaler::Logarithmic);
+ 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 ;-)
@@ -96,18 +90,25 @@ void BitCrusherEffect::processChannel(const ChannelHandle& handle,
if (pState->accumulator >= 1.0) {
pState->accumulator -= 1.0f;
if (bit_depth < 16) {
-
- pState->hold_l = floorf(SampleUtil::clampSample(pInput[i] * gainCorrection) * scale + 0.5f) / scale / gainCorrection;
- pState->hold_r = floorf(SampleUtil::clampSample(pInput[i+1] * gainCorrection) * scale + 0.5f) / scale / gainCorrection;
+ pState->hold_l = floorf(SampleUtil::clampSample(
+ pInput[i] * gainCorrection) *
+ scale +
+ 0.5f) /
+ scale / gainCorrection;
+ pState->hold_r = floorf(SampleUtil::clampSample(pInput[i + 1] *
+ gainCorrection) *
+ scale +
+ 0.5f) /
+ scale / gainCorrection;
} else {
// Mixxx float has 24 bit depth, Audio CDs are 16 bit
// here we do not change the depth
pState->hold_l = pInput[i];
- pState->hold_r = pInput[i+1];
+ pState->hold_r = pInput[i + 1];
}
}
pOutput[i] = pState->hold_l;
- pOutput[i+1] = pState->hold_r;
+ pOutput[i + 1] = pState->hold_r;
}
}
diff --git a/src/effects/builtin/bitcrushereffect.h b/src/effects/backends/builtin/bitcrushereffect.h
similarity index 60%
rename from src/effects/builtin/bitcrushereffect.h
rename to src/effects/backends/builtin/bitcrushereffect.h
index b7888032a655..d45967c1a80d 100644
--- a/src/effects/builtin/bitcrushereffect.h
+++ b/src/effects/backends/builtin/bitcrushereffect.h
@@ -2,8 +2,7 @@
#include
-#include "effects/effect.h"
-#include "effects/effectprocessor.h"
+#include "effects/backends/effectprocessor.h"
#include "engine/effects/engineeffect.h"
#include "engine/effects/engineeffectparameter.h"
#include "util/class.h"
@@ -24,27 +23,30 @@ struct BitCrusherGroupState : public EffectState {
class BitCrusherEffect : public EffectProcessorImpl {
public:
- BitCrusherEffect(EngineEffect* pEffect);
+ BitCrusherEffect() = default;
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/backends/builtin/builtinbackend.cpp b/src/effects/backends/builtin/builtinbackend.cpp
new file mode 100644
index 000000000000..ac99e897505e
--- /dev/null
+++ b/src/effects/backends/builtin/builtinbackend.cpp
@@ -0,0 +1,107 @@
+
+#include "effects/backends/builtin/builtinbackend.h"
+
+#include
+
+#include "effects/backends/builtin/balanceeffect.h"
+#include "effects/backends/builtin/bessel4lvmixeqeffect.h"
+#include "effects/backends/builtin/bessel8lvmixeqeffect.h"
+#include "effects/backends/builtin/biquadfullkilleqeffect.h"
+#include "effects/backends/builtin/bitcrushereffect.h"
+#include "effects/backends/builtin/filtereffect.h"
+#include "effects/backends/builtin/flangereffect.h"
+#include "effects/backends/builtin/graphiceqeffect.h"
+#include "effects/backends/builtin/linkwitzriley8eqeffect.h"
+#include "effects/backends/builtin/moogladder4filtereffect.h"
+#include "effects/backends/builtin/parametriceqeffect.h"
+#include "effects/backends/builtin/threebandbiquadeqeffect.h"
+#ifndef __MACAPPSTORE__
+#include "effects/backends/builtin/reverbeffect.h"
+#endif
+#include "effects/backends/builtin/autopaneffect.h"
+#include "effects/backends/builtin/echoeffect.h"
+#include "effects/backends/builtin/loudnesscontoureffect.h"
+#include "effects/backends/builtin/metronomeeffect.h"
+#include "effects/backends/builtin/phasereffect.h"
+#include "effects/backends/builtin/tremoloeffect.h"
+#include "effects/backends/builtin/whitenoiseeffect.h"
+
+BuiltInBackend::BuiltInBackend() {
+ // Keep this list in a reasonable order
+ // Mixing EQs
+ registerEffect();
+ registerEffect();
+ registerEffect();
+ registerEffect();
+ registerEffect();
+ // Compensations EQs
+ registerEffect();
+ registerEffect();
+ registerEffect();
+ // Fading Effects
+ registerEffect();
+ registerEffect();
+ registerEffect();
+ registerEffect();
+ registerEffect();
+ // Fancy effects
+ registerEffect();
+ registerEffect();
+ registerEffect();
+#ifndef __MACAPPSTORE__
+ registerEffect();
+#endif
+ registerEffect();
+ registerEffect();
+ registerEffect();
+}
+
+std::unique_ptr BuiltInBackend::createProcessor(
+ const EffectManifestPointer pManifest) const {
+ VERIFY_OR_DEBUG_ASSERT(m_registeredEffects.contains(pManifest->id())) {
+ return nullptr;
+ }
+ return m_registeredEffects[pManifest->id()].instantiator();
+}
+
+BuiltInBackend::~BuiltInBackend() {
+ m_registeredEffects.clear();
+ m_effectIds.clear();
+}
+
+void BuiltInBackend::registerEffectInner(
+ const QString& id,
+ EffectManifestPointer pManifest,
+ EffectProcessorInstantiator instantiator) {
+ VERIFY_OR_DEBUG_ASSERT(!m_registeredEffects.contains(id)) {
+ return;
+ }
+
+ pManifest->setBackendType(getType());
+
+ m_registeredEffects[id] = RegisteredEffect{pManifest, instantiator};
+ 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).pManifest;
+}
+
+const QList BuiltInBackend::getManifests() const {
+ QList list;
+ for (const auto& registeredEffect : m_registeredEffects) {
+ list.append(registeredEffect.pManifest);
+ }
+ return list;
+}
+
+bool BuiltInBackend::canInstantiateEffect(const QString& effectId) const {
+ return m_registeredEffects.contains(effectId);
+}
diff --git a/src/effects/backends/builtin/builtinbackend.h b/src/effects/backends/builtin/builtinbackend.h
new file mode 100644
index 000000000000..c79405a46677
--- /dev/null
+++ b/src/effects/backends/builtin/builtinbackend.h
@@ -0,0 +1,52 @@
+#pragma once
+
+#include "effects/backends/effectsbackend.h"
+#include "effects/defs.h"
+
+/// Refer to EffectsBackend for documentation
+class BuiltInBackend : public EffectsBackend {
+ public:
+ BuiltInBackend();
+ virtual ~BuiltInBackend();
+
+ EffectBackendType getType() const {
+ return EffectBackendType::BuiltIn;
+ };
+
+ const QList getEffectIds() const;
+ EffectManifestPointer getManifest(const QString& effectId) const;
+ const QList getManifests() const;
+ std::unique_ptr createProcessor(
+ const EffectManifestPointer pManifest) const;
+ bool canInstantiateEffect(const QString& effectId) const;
+
+ private:
+ QString debugString() const {
+ return "BuiltInBackend";
+ }
+
+ typedef std::unique_ptr (*EffectProcessorInstantiator)();
+
+ struct RegisteredEffect {
+ EffectManifestPointer pManifest;
+ EffectProcessorInstantiator instantiator;
+ };
+
+ void registerEffectInner(const QString& id,
+ EffectManifestPointer pManifest,
+ EffectProcessorInstantiator instantiator);
+
+ template
+ void registerEffect() {
+ registerEffectInner(
+ EffectProcessorImpl::getId(),
+ EffectProcessorImpl::getManifest(),
+ []() {
+ return static_cast>(
+ std::make_unique());
+ });
+ };
+
+ QMap m_registeredEffects;
+ QList m_effectIds;
+};
diff --git a/src/effects/builtin/echoeffect.cpp b/src/effects/backends/builtin/echoeffect.cpp
similarity index 68%
rename from src/effects/builtin/echoeffect.cpp
rename to src/effects/backends/builtin/echoeffect.cpp
index f7ffcc4a0d0e..4c6148137368 100644
--- a/src/effects/builtin/echoeffect.cpp
+++ b/src/effects/backends/builtin/echoeffect.cpp
@@ -1,10 +1,10 @@
-#include "effects/builtin/echoeffect.h"
+#include "effects/backends/builtin/echoeffect.h"
#include
-#include "util/sample.h"
#include "util/math.h"
#include "util/rampingvalue.h"
+#include "util/sample.h"
constexpr int EchoGroupState::kMaxDelaySeconds;
@@ -38,110 +38,93 @@ EffectManifestPointer EchoEffect::getManifest() {
pManifest->setAuthor("The Mixxx Team");
pManifest->setVersion("1.0");
pManifest->setDescription(QObject::tr(
- "Stores the input signal in a temporary buffer and outputs it after a short time"));
- pManifest->setMetaknobDefault(db2ratio(-3.0));
+ "Stores the input signal in a temporary buffer and outputs it after a short time"));
EffectManifestParameterPointer delay = pManifest->addParameter();
delay->setId("delay_time");
delay->setName(QObject::tr("Time"));
delay->setShortName(QObject::tr("Time"));
delay->setDescription(QObject::tr(
- "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->setSemanticHint(EffectManifestParameter::SemanticHint::UNKNOWN);
- delay->setUnitsHint(EffectManifestParameter::UnitsHint::BEATS);
- delay->setMinimum(0.0);
- delay->setDefault(0.5);
- delay->setMaximum(2.0);
+ "Delay time\n"
+ "1/8 - 2 beats if tempo is detected\n"
+ "1/8 - 2 seconds if no tempo is detected"));
+ delay->setValueScaler(EffectManifestParameter::ValueScaler::Linear);
+ delay->setUnitsHint(EffectManifestParameter::UnitsHint::Beats);
+ delay->setRange(0.0, 0.5, 2.0);
EffectManifestParameterPointer feedback = pManifest->addParameter();
feedback->setId("feedback_amount");
feedback->setName(QObject::tr("Feedback"));
feedback->setShortName(QObject::tr("Feedback"));
feedback->setDescription(QObject::tr(
- "Amount the echo fades each time it loops"));
- feedback->setControlHint(EffectManifestParameter::ControlHint::KNOB_LINEAR);
- feedback->setSemanticHint(EffectManifestParameter::SemanticHint::UNKNOWN);
- feedback->setUnitsHint(EffectManifestParameter::UnitsHint::UNKNOWN);
- feedback->setMinimum(0.00);
- feedback->setDefault(db2ratio(-3.0));
- feedback->setMaximum(1.00);
+ "Amount the echo fades each time it loops"));
+ feedback->setValueScaler(EffectManifestParameter::ValueScaler::Linear);
+ feedback->setUnitsHint(EffectManifestParameter::UnitsHint::Unknown);
+ feedback->setRange(0.00, db2ratio(-3.0), 1.00);
EffectManifestParameterPointer pingpong = pManifest->addParameter();
pingpong->setId("pingpong_amount");
pingpong->setName(QObject::tr("Ping Pong"));
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->setSemanticHint(EffectManifestParameter::SemanticHint::UNKNOWN);
- pingpong->setUnitsHint(EffectManifestParameter::UnitsHint::UNKNOWN);
- pingpong->setMinimum(0.0);
- pingpong->setDefault(0.0);
- pingpong->setMaximum(1.0);
+ pingpong->setDescription(
+ QObject::tr("How much the echoed sound bounces between the left "
+ "and right sides of the stereo field"));
+ pingpong->setValueScaler(EffectManifestParameter::ValueScaler::Linear);
+ pingpong->setUnitsHint(EffectManifestParameter::UnitsHint::Unknown);
+ pingpong->setRange(0.0, 0.0, 1.0);
EffectManifestParameterPointer send = pManifest->addParameter();
send->setId("send_amount");
send->setName(QObject::tr("Send"));
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->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);
+ "How much of the signal to send into the delay buffer"));
+ send->setValueScaler(EffectManifestParameter::ValueScaler::Linear);
+ send->setUnitsHint(EffectManifestParameter::UnitsHint::Unknown);
+ send->setDefaultLinkType(EffectManifestParameter::LinkType::Linked);
+ send->setRange(0.0, db2ratio(-3.0), 1.0);
EffectManifestParameterPointer quantize = pManifest->addParameter();
quantize->setId("quantize");
quantize->setName(QObject::tr("Quantize"));
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->setSemanticHint(EffectManifestParameter::SemanticHint::UNKNOWN);
- quantize->setUnitsHint(EffectManifestParameter::UnitsHint::UNKNOWN);
- quantize->setDefault(1);
- quantize->setMinimum(0);
- quantize->setMaximum(1);
+ "Round the Time parameter to the nearest 1/4 beat."));
+ quantize->setValueScaler(EffectManifestParameter::ValueScaler::Toggle);
+ quantize->setUnitsHint(EffectManifestParameter::UnitsHint::Unknown);
+ quantize->setRange(0, 1, 1);
EffectManifestParameterPointer triplet = pManifest->addParameter();
triplet->setId("triplet");
triplet->setName(QObject::tr("Triplets"));
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->setSemanticHint(EffectManifestParameter::SemanticHint::UNKNOWN);
- triplet->setUnitsHint(EffectManifestParameter::UnitsHint::UNKNOWN);
- triplet->setDefault(0);
- triplet->setMinimum(0);
- triplet->setMaximum(1);
+ triplet->setDescription(
+ QObject::tr("When the Quantize parameter is enabled, divide "
+ "rounded 1/4 beats of Time parameter by 3."));
+ triplet->setValueScaler(EffectManifestParameter::ValueScaler::Toggle);
+ triplet->setUnitsHint(EffectManifestParameter::UnitsHint::Unknown);
+ 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) {
// The minimum of the parameter is zero so the exact center of the knob is 1 beat.
double period = m_pDelayParameter->value();
const auto send_current = static_cast(m_pSendParameter->value());
@@ -152,18 +135,18 @@ void EchoEffect::processChannel(const ChannelHandle& handle, EchoGroupState* pGr
if (groupFeatures.has_beat_length_sec) {
// period is a number of beats
if (m_pQuantizeParameter->toBool()) {
- period = std::max(roundToFraction(period, 4), 1/8.0);
+ period = std::max(roundToFraction(period, 4), 1 / 8.0);
if (m_pTripletParameter->toBool()) {
period /= 3.0;
}
- } else if (period < 1/8.0) {
- period = 1/8.0;
+ } else if (period < 1 / 8.0) {
+ period = 1 / 8.0;
}
delay_frames = static_cast(period * groupFeatures.beat_length_sec *
bufferParameters.sampleRate());
} else {
// period is a number of seconds
- period = std::max(period, 1/8.0);
+ period = std::max(period, 1 / 8.0);
delay_frames = static_cast(period * bufferParameters.sampleRate());
}
VERIFY_OR_DEBUG_ASSERT(delay_frames > 0) {
diff --git a/src/effects/builtin/echoeffect.h b/src/effects/backends/builtin/echoeffect.h
similarity index 56%
rename from src/effects/builtin/echoeffect.h
rename to src/effects/backends/builtin/echoeffect.h
index a3a04fb617c5..ac5949b5995e 100644
--- a/src/effects/builtin/echoeffect.h
+++ b/src/effects/backends/builtin/echoeffect.h
@@ -2,10 +2,10 @@
#include
-#include "effects/effectprocessor.h"
-#include "engine/engine.h"
+#include "effects/backends/effectprocessor.h"
#include "engine/effects/engineeffect.h"
#include "engine/effects/engineeffectparameter.h"
+#include "engine/engine.h"
#include "util/class.h"
#include "util/defs.h"
#include "util/sample.h"
@@ -20,18 +20,19 @@ class EchoGroupState : public EffectState {
EchoGroupState(const mixxx::EngineParameters& bufferParameters)
: EffectState(bufferParameters) {
audioParametersChanged(bufferParameters);
- clear();
+ clear();
}
void audioParametersChanged(const mixxx::EngineParameters& bufferParameters) {
- delay_buf = mixxx::SampleBuffer(kMaxDelaySeconds
- * bufferParameters.sampleRate() * bufferParameters.channelCount());
+ delay_buf = mixxx::SampleBuffer(kMaxDelaySeconds *
+ bufferParameters.sampleRate() *
+ bufferParameters.channelCount());
};
void clear() {
delay_buf.clear();
prev_send = 0.0f;
- prev_feedback= 0.0f;
+ prev_feedback = 0.0f;
prev_delay_samples = 0;
write_position = 0;
ping_pong = 0;
@@ -47,29 +48,33 @@ class EchoGroupState : public EffectState {
class EchoEffect : public EffectProcessorImpl {
public:
- EchoEffect(EngineEffect* pEffect);
+ EchoEffect() = default;
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/backends/builtin/equalizer_util.h
similarity index 52%
rename from src/effects/builtin/equalizer_util.h
rename to src/effects/backends/builtin/equalizer_util.h
index 96700ce59657..fe4d252ebf33 100644
--- a/src/effects/builtin/equalizer_util.h
+++ b/src/effects/backends/builtin/equalizer_util.h
@@ -2,17 +2,17 @@
#include
-#include "effects/effectmanifest.h"
+#include "effects/backends/effectmanifest.h"
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;
}
@@ -20,74 +20,56 @@ class EqualizerUtil {
low->setId("low");
low->setName(QObject::tr("Low"));
low->setDescription(QObject::tr("Gain for Low Filter"));
- low->setControlHint(controlHint);
- low->setSemanticHint(EffectManifestParameter::SemanticHint::UNKNOWN);
- low->setUnitsHint(EffectManifestParameter::UnitsHint::UNKNOWN);
+ low->setValueScaler(valueScaler);
+ 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->setSemanticHint(EffectManifestParameter::SemanticHint::UNKNOWN);
- killLow->setUnitsHint(EffectManifestParameter::UnitsHint::UNKNOWN);
- killLow->setDefault(0);
- killLow->setMinimum(0);
- killLow->setMaximum(1);
+ killLow->setValueScaler(EffectManifestParameter::ValueScaler::Toggle);
+ killLow->setUnitsHint(EffectManifestParameter::UnitsHint::Unknown);
+ 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->setSemanticHint(EffectManifestParameter::SemanticHint::UNKNOWN);
- mid->setUnitsHint(EffectManifestParameter::UnitsHint::UNKNOWN);
+ mid->setValueScaler(valueScaler);
+ 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->setSemanticHint(EffectManifestParameter::SemanticHint::UNKNOWN);
- killMid->setUnitsHint(EffectManifestParameter::UnitsHint::UNKNOWN);
- killMid->setDefault(0);
- killMid->setMinimum(0);
- killMid->setMaximum(1);
+ killMid->setValueScaler(EffectManifestParameter::ValueScaler::Toggle);
+ killMid->setUnitsHint(EffectManifestParameter::UnitsHint::Unknown);
+ 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->setSemanticHint(EffectManifestParameter::SemanticHint::UNKNOWN);
- high->setUnitsHint(EffectManifestParameter::UnitsHint::UNKNOWN);
+ high->setValueScaler(valueScaler);
+ 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->setSemanticHint(EffectManifestParameter::SemanticHint::UNKNOWN);
- killHigh->setUnitsHint(EffectManifestParameter::UnitsHint::UNKNOWN);
- killHigh->setDefault(0);
- killHigh->setMinimum(0);
- killHigh->setMaximum(1);
+ killHigh->setValueScaler(EffectManifestParameter::ValueScaler::Toggle);
+ killHigh->setUnitsHint(EffectManifestParameter::UnitsHint::Unknown);
+ killHigh->setRange(0, 0, 1);
}
static QString adjustFrequencyShelvesTip() {
return QObject::tr(
- "To adjust frequency shelves, go to Preferences -> Equalizers.");
+ "To adjust frequency shelves, go to Preferences -> Equalizers.");
}
};
diff --git a/src/effects/builtin/filtereffect.cpp b/src/effects/backends/builtin/filtereffect.cpp
similarity index 70%
rename from src/effects/builtin/filtereffect.cpp
rename to src/effects/backends/builtin/filtereffect.cpp
index 831b48e6140b..c1f606140a85 100644
--- a/src/effects/builtin/filtereffect.cpp
+++ b/src/effects/backends/builtin/filtereffect.cpp
@@ -1,4 +1,5 @@
-#include "effects/builtin/filtereffect.h"
+#include "effects/backends/builtin/filtereffect.h"
+
#include "util/math.h"
namespace {
@@ -20,52 +21,44 @@ EffectManifestPointer FilterEffect::getManifest() {
pManifest->setAuthor("The Mixxx Team");
pManifest->setVersion("1.0");
pManifest->setDescription(QObject::tr(
- "Allows only high or low frequencies to play."));
+ "Allows only high or low frequencies to play."));
pManifest->setEffectRampsFromDry(true);
+ pManifest->setMetaknobDefault(0.5);
EffectManifestParameterPointer lpf = pManifest->addParameter();
lpf->setId("lpf");
lpf->setName(QObject::tr("Low Pass Filter Cutoff"));
lpf->setShortName(QObject::tr("LPF"));
lpf->setDescription(QObject::tr(
- "Corner frequency ratio of the low pass filter"));
- lpf->setControlHint(EffectManifestParameter::ControlHint::KNOB_LOGARITHMIC);
- lpf->setSemanticHint(EffectManifestParameter::SemanticHint::UNKNOWN);
- lpf->setUnitsHint(EffectManifestParameter::UnitsHint::HERTZ);
- lpf->setDefaultLinkType(EffectManifestParameter::LinkType::LINKED_LEFT);
+ "Corner frequency ratio of the low pass filter"));
+ lpf->setValueScaler(EffectManifestParameter::ValueScaler::Logarithmic);
+ lpf->setUnitsHint(EffectManifestParameter::UnitsHint::Hertz);
+ lpf->setDefaultLinkType(EffectManifestParameter::LinkType::LinkedLeft);
lpf->setNeutralPointOnScale(1);
- lpf->setDefault(kMaxCorner);
- lpf->setMinimum(kMinCorner);
- lpf->setMaximum(kMaxCorner);
+ lpf->setRange(kMinCorner, kMaxCorner, kMaxCorner);
EffectManifestParameterPointer q = pManifest->addParameter();
q->setId("q");
q->setName(QObject::tr("Resonance"));
q->setShortName(QObject::tr("Q"));
q->setDescription(QObject::tr(
- "Resonance of the filters\n"
- "Default: flat top")); // What does this mean?
- q->setControlHint(EffectManifestParameter::ControlHint::KNOB_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);
+ "Resonance of the filters\n"
+ "Default: flat top")); // What does this mean?
+ q->setValueScaler(EffectManifestParameter::ValueScaler::Logarithmic);
+ q->setUnitsHint(EffectManifestParameter::UnitsHint::SampleRate);
+ q->setRange(0.4, 0.707106781, 4.0); // 0.707106781 = Butterworth
EffectManifestParameterPointer hpf = pManifest->addParameter();
hpf->setId("hpf");
hpf->setName(QObject::tr("High Pass Filter Cutoff"));
hpf->setShortName(QObject::tr("HPF"));
hpf->setDescription(QObject::tr(
- "Corner frequency ratio of the high pass filter"));
- hpf->setControlHint(EffectManifestParameter::ControlHint::KNOB_LOGARITHMIC);
- hpf->setSemanticHint(EffectManifestParameter::SemanticHint::UNKNOWN);
- hpf->setUnitsHint(EffectManifestParameter::UnitsHint::HERTZ);
- hpf->setDefaultLinkType(EffectManifestParameter::LinkType::LINKED_RIGHT);
+ "Corner frequency ratio of the high pass filter"));
+ hpf->setValueScaler(EffectManifestParameter::ValueScaler::Logarithmic);
+ hpf->setUnitsHint(EffectManifestParameter::UnitsHint::Hertz);
+ hpf->setDefaultLinkType(EffectManifestParameter::LinkType::LinkedRight);
hpf->setNeutralPointOnScale(0.0);
- hpf->setDefault(kMinCorner);
- hpf->setMinimum(kMinCorner);
- hpf->setMaximum(kMaxCorner);
+ hpf->setRange(kMinCorner, kMinCorner, kMaxCorner);
return pManifest;
}
@@ -85,23 +78,24 @@ 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;
@@ -154,9 +148,10 @@ void FilterEffect::processChannel(const ChannelHandle& handle,
// hpf enabled, fade-in is handled in the filter when starting from pause
pState->m_pHighFilter->process(pInput, pHpfOutput, bufferParameters.samplesPerBuffer());
} else if (pState->m_hiFreq > minCornerNormalized) {
- // hpf disabling
- pState->m_pHighFilter->processAndPauseFilter(pInput,
- pHpfOutput, bufferParameters.samplesPerBuffer());
+ // hpf disabling
+ pState->m_pHighFilter->processAndPauseFilter(pInput,
+ pHpfOutput,
+ bufferParameters.samplesPerBuffer());
} else {
// paused LP uses input directly
pLpfInput = pInput;
@@ -168,7 +163,8 @@ void FilterEffect::processChannel(const ChannelHandle& handle,
} else if (pState->m_loFreq < maxCornerNormalized) {
// hpf disabling
pState->m_pLowFilter->processAndPauseFilter(pLpfInput,
- pOutput, bufferParameters.samplesPerBuffer());
+ pOutput,
+ bufferParameters.samplesPerBuffer());
} else if (pLpfInput == pInput) {
// Both disabled
if (pOutput != pInput) {
diff --git a/src/effects/builtin/filtereffect.h b/src/effects/backends/builtin/filtereffect.h
similarity index 61%
rename from src/effects/builtin/filtereffect.h
rename to src/effects/backends/builtin/filtereffect.h
index a7ba64c5570c..bcf4f8940e34 100644
--- a/src/effects/builtin/filtereffect.h
+++ b/src/effects/backends/builtin/filtereffect.h
@@ -1,7 +1,6 @@
#pragma once
-#include "effects/effect.h"
-#include "effects/effectprocessor.h"
+#include "effects/backends/effectprocessor.h"
#include "engine/effects/engineeffect.h"
#include "engine/effects/engineeffectparameter.h"
#include "engine/filters/enginefilterbiquad1.h"
@@ -24,32 +23,35 @@ struct FilterGroupState : public EffectState {
double m_loFreq;
double m_q;
double m_hiFreq;
-
};
class FilterEffect : public EffectProcessorImpl {
public:
- FilterEffect(EngineEffect* pEffect);
+ FilterEffect() = default;
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/backends/builtin/flangereffect.cpp
similarity index 62%
rename from src/effects/builtin/flangereffect.cpp
rename to src/effects/backends/builtin/flangereffect.cpp
index 542bd58a1a7b..70d77374f05a 100644
--- a/src/effects/builtin/flangereffect.cpp
+++ b/src/effects/backends/builtin/flangereffect.cpp
@@ -1,10 +1,10 @@
-#include "effects/builtin/flangereffect.h"
+#include "effects/backends/builtin/flangereffect.h"
#include
#include "util/math.h"
-namespace{
+namespace {
// Gain correction was verified with replay gain and default parameters
constexpr CSAMPLE kGainCorrection = 1.41253754f; // 3 dB
@@ -28,63 +28,51 @@ EffectManifestPointer FlangerEffect::getManifest() {
pManifest->setShortName(QObject::tr("Flanger"));
pManifest->setAuthor("The Mixxx Team");
pManifest->setVersion("1.0");
- pManifest->setDescription(QObject::tr(
- "Mixes the input with a delayed, pitch modulated copy of itself to create comb filtering"));
- pManifest->setMetaknobDefault(1.0);
+ pManifest->setDescription(
+ QObject::tr("Mixes the input with a delayed, pitch modulated copy "
+ "of itself to create comb filtering"));
EffectManifestParameterPointer speed = pManifest->addParameter();
speed->setId("speed");
speed->setName(QObject::tr("Speed"));
speed->setShortName(QObject::tr("Speed"));
speed->setDescription(QObject::tr(
- "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->setSemanticHint(EffectManifestParameter::SemanticHint::UNKNOWN);
- speed->setMinimum(kMinLfoBeats);
- speed->setMaximum(kMaxLfoBeats);
- speed->setDefault(8);
+ "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->setValueScaler(EffectManifestParameter::ValueScaler::LogarithmicInverse);
+ speed->setRange(kMinLfoBeats, 8, kMaxLfoBeats);
EffectManifestParameterPointer width = pManifest->addParameter();
width->setId("width");
width->setName(QObject::tr("Width"));
width->setShortName(QObject::tr("Width"));
width->setDescription(QObject::tr(
- "Delay amplitude of the LFO (low frequency oscillator)"));
- width->setControlHint(EffectManifestParameter::ControlHint::KNOB_LOGARITHMIC);
- width->setSemanticHint(EffectManifestParameter::SemanticHint::UNKNOWN);
- width->setUnitsHint(EffectManifestParameter::UnitsHint::UNKNOWN);
- width->setDefault(kMaxLfoWidthMs / 2);
- width->setMinimum(0.0);
- width->setMaximum(kMaxLfoWidthMs);
+ "Delay amplitude of the LFO (low frequency oscillator)"));
+ width->setValueScaler(EffectManifestParameter::ValueScaler::Logarithmic);
+ width->setUnitsHint(EffectManifestParameter::UnitsHint::Unknown);
+ width->setRange(0.0, kMaxLfoWidthMs / 2, kMaxLfoWidthMs);
EffectManifestParameterPointer manual = pManifest->addParameter();
manual->setId("manual");
manual->setName(QObject::tr("Manual"));
manual->setShortName(QObject::tr("Manual"));
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->setSemanticHint(EffectManifestParameter::SemanticHint::UNKNOWN);
- manual->setUnitsHint(EffectManifestParameter::UnitsHint::UNKNOWN);
- manual->setDefault(kCenterDelayMs);
- manual->setMinimum(kMinDelayMs);
- manual->setMaximum(kMaxDelayMs);
+ "Delay offset of the LFO (low frequency oscillator).\n"
+ "With width at zero, this allows for manually sweeping over the entire delay range."));
+ manual->setValueScaler(EffectManifestParameter::ValueScaler::Logarithmic);
+ manual->setUnitsHint(EffectManifestParameter::UnitsHint::Unknown);
+ manual->setRange(kMinDelayMs, kCenterDelayMs, kMaxDelayMs);
EffectManifestParameterPointer regen = pManifest->addParameter();
regen->setId("regen");
regen->setName(QObject::tr("Regeneration"));
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->setSemanticHint(EffectManifestParameter::SemanticHint::UNKNOWN);
- regen->setUnitsHint(EffectManifestParameter::UnitsHint::UNKNOWN);
- regen->setDefault(0.25);
- regen->setMinimum(0.0);
- regen->setMaximum(1.0);
+ "How much of the delay output is feed back into the input"));
+ regen->setValueScaler(EffectManifestParameter::ValueScaler::Linear);
+ regen->setUnitsHint(EffectManifestParameter::UnitsHint::Unknown);
+ regen->setRange(0.0, 0.25, 1.0);
EffectManifestParameterPointer mix = pManifest->addParameter();
mix->setId("mix");
@@ -92,13 +80,10 @@ EffectManifestPointer FlangerEffect::getManifest() {
mix->setShortName(QObject::tr("Mix"));
mix->setDescription(QObject::tr(
"Intensity of the effect"));
- mix->setControlHint(EffectManifestParameter::ControlHint::KNOB_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->setValueScaler(EffectManifestParameter::ValueScaler::Linear);
+ mix->setUnitsHint(EffectManifestParameter::UnitsHint::Unknown);
+ mix->setDefaultLinkType(EffectManifestParameter::LinkType::Linked);
+ mix->setRange(0.0, 1.0, 1.0);
EffectManifestParameterPointer triplet = pManifest->addParameter();
triplet->setId("triplet");
@@ -106,37 +91,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->setSemanticHint(EffectManifestParameter::SemanticHint::UNKNOWN);
- triplet->setUnitsHint(EffectManifestParameter::UnitsHint::UNKNOWN);
- triplet->setDefault(0);
- triplet->setMinimum(0);
- triplet->setMaximum(1);
+ triplet->setValueScaler(EffectManifestParameter::ValueScaler::Toggle);
+ triplet->setUnitsHint(EffectManifestParameter::UnitsHint::Unknown);
+ 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;
if (groupFeatures.has_beat_length_sec) {
@@ -145,12 +127,12 @@ void FlangerEffect::processChannel(const ChannelHandle& handle,
if (m_pTripletParameter->toBool()) {
lfoPeriodParameter /= 3.0;
}
- lfoPeriodFrames = lfoPeriodParameter * groupFeatures.beat_length_sec
- * bufferParameters.sampleRate();
+ lfoPeriodFrames = lfoPeriodParameter * groupFeatures.beat_length_sec *
+ bufferParameters.sampleRate();
} else {
// lfoPeriodParameter is a number of seconds
- lfoPeriodFrames = std::max(lfoPeriodParameter, kMinLfoBeats)
- * bufferParameters.sampleRate();
+ lfoPeriodFrames = std::max(lfoPeriodParameter, kMinLfoBeats) *
+ bufferParameters.sampleRate();
}
// When the period is changed, the position of the sound shouldn't
@@ -161,7 +143,6 @@ void FlangerEffect::processChannel(const ChannelHandle& handle,
}
pState->previousPeriodFrames = lfoPeriodFrames;
-
// lfoPeriodSamples is used to calculate the delay for each channel
// independently in the loop below, so do not multiply lfoPeriodSamples by
// the number of channels.
@@ -212,10 +193,14 @@ void FlangerEffect::processChannel(const ChannelHandle& handle,
double delayMs = manual_ramped + width_ramped / 2 * sin(M_PI * 2.0f * periodFraction);
double delayFrames = delayMs * bufferParameters.sampleRate() / 1000;
- SINT framePrev = (pState->delayPos - static_cast(floor(delayFrames))
- + kBufferLenth) % kBufferLenth;
- SINT frameNext = (pState->delayPos - static_cast(ceil(delayFrames))
- + kBufferLenth) % kBufferLenth;
+ SINT framePrev =
+ (pState->delayPos - static_cast(floor(delayFrames)) +
+ kBufferLenth) %
+ kBufferLenth;
+ SINT frameNext =
+ (pState->delayPos - static_cast(ceil(delayFrames)) +
+ kBufferLenth) %
+ kBufferLenth;
CSAMPLE prevLeft = delayLeft[framePrev];
CSAMPLE nextLeft = delayLeft[frameNext];
@@ -228,7 +213,8 @@ void FlangerEffect::processChannel(const ChannelHandle& handle,
CSAMPLE delayedSampleRight = prevRight + frac * (nextRight - prevRight);
delayLeft[pState->delayPos] = tanh_approx(pInput[i] + regen_ramped * delayedSampleLeft);
- delayRight[pState->delayPos] = tanh_approx(pInput[i + 1] + regen_ramped * delayedSampleRight);
+ delayRight[pState->delayPos] =
+ tanh_approx(pInput[i + 1] + regen_ramped * delayedSampleRight);
pState->delayPos = (pState->delayPos + 1) % kBufferLenth;
diff --git a/src/effects/builtin/flangereffect.h b/src/effects/backends/builtin/flangereffect.h
similarity index 66%
rename from src/effects/builtin/flangereffect.h
rename to src/effects/backends/builtin/flangereffect.h
index a942f90bc68f..d0b988a5e00c 100644
--- a/src/effects/builtin/flangereffect.h
+++ b/src/effects/backends/builtin/flangereffect.h
@@ -2,14 +2,14 @@
#include
-#include "effects/effectprocessor.h"
+#include "effects/backends/effectprocessor.h"
#include "engine/effects/engineeffect.h"
#include "engine/effects/engineeffectparameter.h"
#include "util/class.h"
#include "util/defs.h"
+#include "util/rampingvalue.h"
#include "util/sample.h"
#include "util/types.h"
-#include "util/rampingvalue.h"
namespace {
constexpr double kMaxDelayMs = 13.0;
@@ -17,8 +17,8 @@ constexpr double kMinDelayMs = 0.22;
constexpr double kCenterDelayMs = (kMaxDelayMs - kMinDelayMs) / 2 + kMinDelayMs;
constexpr double kMaxLfoWidthMs = kMaxDelayMs - kMinDelayMs;
// using + 1.0 instead of ceil() for Mac OS
-constexpr SINT kBufferLenth = static_cast(kMaxDelayMs + 1.0) * 96; // for 96 kHz
-constexpr double kMinLfoBeats = 1/4.0;
+constexpr SINT kBufferLenth = static_cast(kMaxDelayMs + 1.0) * 96; // for 96 kHz
+constexpr double kMinLfoBeats = 1 / 4.0;
constexpr double kMaxLfoBeats = 32.0;
} // anonymous namespace
@@ -48,31 +48,34 @@ struct FlangerGroupState : public EffectState {
class FlangerEffect : public EffectProcessorImpl {
public:
- FlangerEffect(EngineEffect* pEffect);
+ FlangerEffect() = default;
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/backends/builtin/graphiceqeffect.cpp
similarity index 64%
rename from src/effects/builtin/graphiceqeffect.cpp
rename to src/effects/backends/builtin/graphiceqeffect.cpp
index dbeeb8d63cc9..94784c369eb0 100644
--- a/src/effects/builtin/graphiceqeffect.cpp
+++ b/src/effects/backends/builtin/graphiceqeffect.cpp
@@ -1,4 +1,5 @@
-#include "effects/builtin/graphiceqeffect.h"
+#include "effects/backends/builtin/graphiceqeffect.h"
+
#include "util/math.h"
#define Q 1.2247449
@@ -17,27 +18,23 @@ EffectManifestPointer GraphicEQEffect::getManifest() {
pManifest->setAuthor("The Mixxx Team");
pManifest->setVersion("1.0");
pManifest->setDescription(QObject::tr(
- "An 8-band graphic equalizer based on biquad filters"));
+ "An 8-band graphic equalizer based on biquad filters"));
pManifest->setEffectRampsFromDry(true);
pManifest->setIsMasterEQ(true);
// Display rounded center frequencies for each filter
- float centerFrequencies[8] = {45, 100, 220, 500, 1100, 2500,
- 5500, 12000};
+ float centerFrequencies[8] = {45, 100, 220, 500, 1100, 2500, 5500, 12000};
EffectManifestParameterPointer low = pManifest->addParameter();
low->setId(QString("low"));
low->setName(QString("%1 Hz").arg(centerFrequencies[0]));
low->setShortName(QString("%1 Hz").arg(centerFrequencies[0]));
low->setDescription(QObject::tr(
- "Gain for Low Filter"));
- low->setControlHint(EffectManifestParameter::ControlHint::KNOB_LINEAR);
- low->setSemanticHint(EffectManifestParameter::SemanticHint::UNKNOWN);
- low->setUnitsHint(EffectManifestParameter::UnitsHint::UNKNOWN);
+ "Gain for Low Filter"));
+ low->setValueScaler(EffectManifestParameter::ValueScaler::Linear);
+ 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++) {
@@ -52,34 +49,29 @@ EffectManifestPointer GraphicEQEffect::getManifest() {
mid->setName(paramName);
mid->setShortName(paramName);
mid->setDescription(QObject::tr(
- "Gain for Band Filter %1").arg(i + 1));
- mid->setControlHint(EffectManifestParameter::ControlHint::KNOB_LINEAR);
- mid->setSemanticHint(EffectManifestParameter::SemanticHint::UNKNOWN);
- mid->setUnitsHint(EffectManifestParameter::UnitsHint::UNKNOWN);
+ "Gain for Band Filter %1")
+ .arg(i + 1));
+ mid->setValueScaler(EffectManifestParameter::ValueScaler::Linear);
+ 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();
high->setId(QString("high"));
high->setName(QString("%1 kHz").arg(centerFrequencies[7] / 1000));
high->setDescription(QObject::tr(
- "Gain for High Filter"));
- high->setControlHint(EffectManifestParameter::ControlHint::KNOB_LINEAR);
- high->setSemanticHint(EffectManifestParameter::SemanticHint::UNKNOWN);
- high->setUnitsHint(EffectManifestParameter::UnitsHint::UNKNOWN);
- high->setDefault(0);
- high->setMinimum(-12);
- high->setMaximum(12);
+ "Gain for High Filter"));
+ high->setValueScaler(EffectManifestParameter::ValueScaler::Linear);
+ high->setUnitsHint(EffectManifestParameter::UnitsHint::Unknown);
+ high->setRange(-12, 0, 12);
return pManifest;
}
GraphicEQEffectGroupState::GraphicEQEffectGroupState(
const mixxx::EngineParameters& bufferParameters)
- : EffectState(bufferParameters) {
+ : EffectState(bufferParameters) {
m_oldLow = 0;
for (int i = 0; i < 6; i++) {
m_oldMid.append(1.0);
@@ -104,8 +96,8 @@ GraphicEQEffectGroupState::GraphicEQEffectGroupState(
m_high = new EngineFilterBiquad1HighShelving(44100, m_centerFrequencies[7], Q);
for (int i = 1; i < 7; i++) {
m_bands.append(new EngineFilterBiquad1Peaking(44100,
- m_centerFrequencies[i],
- Q));
+ m_centerFrequencies[i],
+ Q));
}
}
@@ -117,41 +109,38 @@ GraphicEQEffectGroupState::~GraphicEQEffectGroupState() {
delete m_low;
delete m_high;
- foreach(CSAMPLE* buf, m_pBufs) {
+ foreach (CSAMPLE* buf, m_pBufs) {
SampleUtil::free(buf);
}
}
void GraphicEQEffectGroupState::setFilters(int sampleRate) {
- m_low->setFrequencyCorners(sampleRate, m_centerFrequencies[0], Q,
- m_oldLow);
- m_high->setFrequencyCorners(sampleRate, m_centerFrequencies[7], Q,
- m_oldHigh);
+ m_low->setFrequencyCorners(sampleRate, m_centerFrequencies[0], Q, m_oldLow);
+ m_high->setFrequencyCorners(sampleRate, m_centerFrequencies[7], Q, m_oldHigh);
for (int i = 0; i < 6; i++) {
- m_bands[i]->setFrequencyCorners(sampleRate, m_centerFrequencies[i + 1],
- Q, m_oldMid[i]);
+ m_bands[i]->setFrequencyCorners(sampleRate, m_centerFrequencies[i + 1], Q, m_oldMid[i]);
}
}
-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
@@ -166,9 +155,10 @@ void GraphicEQEffect::processChannel(const ChannelHandle& handle,
float fHigh;
if (enableState == EffectEnableState::Disabling) {
- // Ramp to dry, when disabling, this will ramp from dry when enabling as well
+ // Ramp to dry, when disabling, this will ramp from dry when enabling as well
fLow = 1.0;
- fHigh = 1.0;;
+ fHigh = 1.0;
+ ;
for (int i = 0; i < 6; i++) {
fMid[i] = 1.0;
}
@@ -180,28 +170,32 @@ void GraphicEQEffect::processChannel(const ChannelHandle& handle,
}
}
-
if (fLow != pState->m_oldLow) {
pState->m_low->setFrequencyCorners(bufferParameters.sampleRate(),
- pState->m_centerFrequencies[0], Q,
- fLow);
+ pState->m_centerFrequencies[0],
+ Q,
+ fLow);
}
if (fHigh != pState->m_oldHigh) {
pState->m_high->setFrequencyCorners(bufferParameters.sampleRate(),
- pState->m_centerFrequencies[7], Q,
- fHigh);
+ pState->m_centerFrequencies[7],
+ Q,
+ fHigh);
}
for (int i = 0; i < 6; i++) {
if (fMid[i] != pState->m_oldMid[i]) {
pState->m_bands[i]->setFrequencyCorners(bufferParameters.sampleRate(),
- pState->m_centerFrequencies[i + 1],
- Q, fMid[i]);
+ pState->m_centerFrequencies[i + 1],
+ Q,
+ fMid[i]);
}
}
int bufIndex = 0;
if (fLow != 0) {
- pState->m_low->process(pInput, pState->m_pBufs[1 - bufIndex], bufferParameters.samplesPerBuffer());
+ pState->m_low->process(pInput,
+ pState->m_pBufs[1 - bufIndex],
+ bufferParameters.samplesPerBuffer());
bufIndex = 1 - bufIndex;
} else {
pState->m_low->pauseFilter();
@@ -211,7 +205,8 @@ void GraphicEQEffect::processChannel(const ChannelHandle& handle,
for (int i = 0; i < 6; i++) {
if (fMid[i] != 0) {
pState->m_bands[i]->process(pState->m_pBufs[bufIndex],
- pState->m_pBufs[1 - bufIndex], bufferParameters.samplesPerBuffer());
+ pState->m_pBufs[1 - bufIndex],
+ bufferParameters.samplesPerBuffer());
bufIndex = 1 - bufIndex;
} else {
pState->m_bands[i]->pauseFilter();
@@ -220,7 +215,8 @@ void GraphicEQEffect::processChannel(const ChannelHandle& handle,
if (fHigh != 0) {
pState->m_high->process(pState->m_pBufs[bufIndex],
- pOutput, bufferParameters.samplesPerBuffer());
+ pOutput,
+ bufferParameters.samplesPerBuffer());
} else {
SampleUtil::copy(pOutput, pState->m_pBufs[bufIndex], bufferParameters.samplesPerBuffer());
pState->m_high->pauseFilter();
diff --git a/src/effects/builtin/graphiceqeffect.h b/src/effects/backends/builtin/graphiceqeffect.h
similarity index 64%
rename from src/effects/builtin/graphiceqeffect.h
rename to src/effects/backends/builtin/graphiceqeffect.h
index b4a3c40a745f..5116ebba86f9 100644
--- a/src/effects/builtin/graphiceqeffect.h
+++ b/src/effects/backends/builtin/graphiceqeffect.h
@@ -3,8 +3,7 @@
#include
#include "control/controlproxy.h"
-#include "effects/effect.h"
-#include "effects/effectprocessor.h"
+#include "effects/backends/effectprocessor.h"
#include "engine/effects/engineeffect.h"
#include "engine/effects/engineeffectparameter.h"
#include "engine/filters/enginefilterbiquad1.h"
@@ -32,27 +31,32 @@ class GraphicEQEffectGroupState : public EffectState {
class GraphicEQEffect : public EffectProcessorImpl {
public:
- GraphicEQEffect(EngineEffect* pEffect);
+ GraphicEQEffect() = default;
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;
+
mixxx::audio::SampleRate m_oldSampleRate;
DISALLOW_COPY_AND_ASSIGN(GraphicEQEffect);
diff --git a/src/effects/builtin/linkwitzriley8eqeffect.cpp b/src/effects/backends/builtin/linkwitzriley8eqeffect.cpp
similarity index 70%
rename from src/effects/builtin/linkwitzriley8eqeffect.cpp
rename to src/effects/backends/builtin/linkwitzriley8eqeffect.cpp
index 62e271032dc4..9222d085d3b4 100644
--- a/src/effects/builtin/linkwitzriley8eqeffect.cpp
+++ b/src/effects/backends/builtin/linkwitzriley8eqeffect.cpp
@@ -1,6 +1,6 @@
-#include "effects/builtin/linkwitzriley8eqeffect.h"
+#include "effects/backends/builtin/linkwitzriley8eqeffect.h"
-#include "effects/builtin/equalizer_util.h"
+#include "effects/backends/builtin/equalizer_util.h"
#include "util/math.h"
static constexpr unsigned int kStartupSamplerate = 44100;
@@ -20,8 +20,11 @@ EffectManifestPointer LinkwitzRiley8EQEffect::getManifest() {
pManifest->setShortName(QObject::tr("LR8 ISO"));
pManifest->setAuthor("The Mixxx Team");
pManifest->setVersion("1.0");
- pManifest->setDescription(QObject::tr(
- "A Linkwitz-Riley 8th-order filter isolator (optimized crossover, constant phase shift, roll-off -48 dB/octave).") + " " + EqualizerUtil::adjustFrequencyShelvesTip());
+ pManifest->setDescription(
+ QObject::tr("A Linkwitz-Riley 8th-order filter isolator (optimized "
+ "crossover, constant phase shift, roll-off -48 "
+ "dB/octave).") +
+ " " + EqualizerUtil::adjustFrequencyShelvesTip());
pManifest->setIsMixingEQ(true);
EqualizerUtil::createCommonParameters(pManifest.data(), false);
@@ -37,7 +40,6 @@ LinkwitzRiley8EQEffectGroupState::LinkwitzRiley8EQEffectGroupState(
m_oldSampleRate(kStartupSamplerate),
m_loFreq(kStartupLoFreq),
m_hiFreq(kStartupHiFreq) {
-
m_pLowBuf = SampleUtil::alloc(MAX_BUFFER_LEN);
m_pMidBuf = SampleUtil::alloc(MAX_BUFFER_LEN);
m_pHighBuf = SampleUtil::alloc(MAX_BUFFER_LEN);
@@ -58,37 +60,40 @@ LinkwitzRiley8EQEffectGroupState::~LinkwitzRiley8EQEffectGroupState() {
SampleUtil::free(m_pHighBuf);
}
-void LinkwitzRiley8EQEffectGroupState::setFilters(int sampleRate, int lowFreq,
- int highFreq) {
+void LinkwitzRiley8EQEffectGroupState::setFilters(int sampleRate, int lowFreq, int highFreq) {
m_low1->setFrequencyCorners(sampleRate, lowFreq);
m_high1->setFrequencyCorners(sampleRate, lowFreq);
m_low2->setFrequencyCorners(sampleRate, highFreq);
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;
@@ -111,8 +116,13 @@ void LinkwitzRiley8EQEffect::processChannel(const ChannelHandle& handle,
pState->setFilters(bufferParameters.sampleRate(), pState->m_loFreq, pState->m_hiFreq);
}
- pState->m_high2->process(pInput, pState->m_pHighBuf, bufferParameters.samplesPerBuffer()); // HighPass first run
- pState->m_low2->process(pInput, pState->m_pLowBuf, bufferParameters.samplesPerBuffer()); // LowPass first run for low and bandpass
+ pState->m_high2->process(pInput,
+ pState->m_pHighBuf,
+ bufferParameters.samplesPerBuffer()); // HighPass first run
+ pState->m_low2->process(pInput,
+ pState->m_pLowBuf,
+ bufferParameters
+ .samplesPerBuffer()); // LowPass first run for low and bandpass
if (fMid != pState->old_mid || fHigh != pState->old_high) {
SampleUtil::applyRampingGain(pState->m_pHighBuf,
@@ -127,12 +137,18 @@ void LinkwitzRiley8EQEffect::processChannel(const ChannelHandle& handle,
} else {
SampleUtil::applyGain(pState->m_pHighBuf, fHigh, bufferParameters.samplesPerBuffer());
SampleUtil::addWithGain(pState->m_pHighBuf,
- pState->m_pLowBuf, fMid,
- bufferParameters.samplesPerBuffer());
+ pState->m_pLowBuf,
+ fMid,
+ bufferParameters.samplesPerBuffer());
}
- pState->m_high1->process(pState->m_pHighBuf, pState->m_pMidBuf, bufferParameters.samplesPerBuffer()); // HighPass + BandPass second run
- pState->m_low1->process(pState->m_pLowBuf, pState->m_pLowBuf, bufferParameters.samplesPerBuffer()); // LowPass second run
+ pState->m_high1->process(pState->m_pHighBuf,
+ pState->m_pMidBuf,
+ bufferParameters
+ .samplesPerBuffer()); // HighPass + BandPass second run
+ pState->m_low1->process(pState->m_pLowBuf,
+ pState->m_pLowBuf,
+ bufferParameters.samplesPerBuffer()); // LowPass second run
if (fLow != pState->old_low) {
SampleUtil::copy2WithRampingGain(pOutput,
@@ -145,8 +161,10 @@ void LinkwitzRiley8EQEffect::processChannel(const ChannelHandle& handle,
bufferParameters.samplesPerBuffer());
} else {
SampleUtil::copy2WithGain(pOutput,
- pState->m_pLowBuf, fLow,
- pState->m_pMidBuf, 1,
+ pState->m_pLowBuf,
+ fLow,
+ pState->m_pMidBuf,
+ 1,
bufferParameters.samplesPerBuffer());
}
diff --git a/src/effects/builtin/linkwitzriley8eqeffect.h b/src/effects/backends/builtin/linkwitzriley8eqeffect.h
similarity index 64%
rename from src/effects/builtin/linkwitzriley8eqeffect.h
rename to src/effects/backends/builtin/linkwitzriley8eqeffect.h
index 0bf85b3354ad..53cb383dcec6 100644
--- a/src/effects/builtin/linkwitzriley8eqeffect.h
+++ b/src/effects/backends/builtin/linkwitzriley8eqeffect.h
@@ -3,8 +3,7 @@
#include
#include "control/controlproxy.h"
-#include "effects/effect.h"
-#include "effects/effectprocessor.h"
+#include "effects/backends/effectprocessor.h"
#include "engine/effects/engineeffect.h"
#include "engine/effects/engineeffectparameter.h"
#include "engine/filters/enginefilterlinkwitzriley8.h"
@@ -40,32 +39,35 @@ 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/backends/builtin/loudnesscontoureffect.cpp
similarity index 75%
rename from src/effects/builtin/loudnesscontoureffect.cpp
rename to src/effects/backends/builtin/loudnesscontoureffect.cpp
index 1bd78f1f4b0c..3b9463ab9e00 100644
--- a/src/effects/builtin/loudnesscontoureffect.cpp
+++ b/src/effects/backends/builtin/loudnesscontoureffect.cpp
@@ -1,4 +1,5 @@
-#include "effects/builtin/loudnesscontoureffect.h"
+#include "effects/backends/builtin/loudnesscontoureffect.h"
+
#include "util/math.h"
namespace {
@@ -13,7 +14,6 @@ static constexpr double kHiShelveQ = 0.7;
} // anonymous namespace
-
// static
QString LoudnessContourEffect::getId() {
return "org.mixxx.effects.loudnesscontour";
@@ -28,37 +28,32 @@ EffectManifestPointer LoudnessContourEffect::getManifest() {
pManifest->setAuthor("The Mixxx Team");
pManifest->setVersion("1.0");
pManifest->setDescription(QObject::tr(
- "Amplifies low and high frequencies at low volumes to compensate for reduced sensitivity of the human ear."));
+ "Amplifies low and high frequencies at low volumes to compensate "
+ "for reduced sensitivity of the human ear."));
pManifest->setEffectRampsFromDry(true);
- pManifest->setMetaknobDefault(-kMaxLoGain / 2);
+ pManifest->setMetaknobDefault(1.0);
EffectManifestParameterPointer loudness = pManifest->addParameter();
loudness->setId("loudness");
loudness->setName(QObject::tr("Loudness"));
loudness->setShortName(QObject::tr("Loudness"));
loudness->setDescription(QObject::tr(
- "Set the gain of the applied loudness contour"));
- loudness->setControlHint(EffectManifestParameter::ControlHint::KNOB_LINEAR);
- loudness->setSemanticHint(EffectManifestParameter::SemanticHint::UNKNOWN);
- loudness->setUnitsHint(EffectManifestParameter::UnitsHint::UNKNOWN);
- loudness->setDefaultLinkType(EffectManifestParameter::LinkType::LINKED);
+ "Set the gain of the applied loudness contour"));
+ loudness->setValueScaler(EffectManifestParameter::ValueScaler::Linear);
+ 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");
useGain->setName(QObject::tr("Use Gain"));
useGain->setShortName(QObject::tr("Use Gain"));
useGain->setDescription(QObject::tr(
- "Follow Gain Knob"));
- useGain->setControlHint(EffectManifestParameter::ControlHint::TOGGLE_STEPPING);
- useGain->setSemanticHint(EffectManifestParameter::SemanticHint::UNKNOWN);
- useGain->setUnitsHint(EffectManifestParameter::UnitsHint::UNKNOWN);
- useGain->setDefault(0);
- useGain->setMinimum(0);
- useGain->setMaximum(1);
+ "Follow Gain Knob"));
+ useGain->setValueScaler(EffectManifestParameter::ValueScaler::Toggle);
+ useGain->setUnitsHint(EffectManifestParameter::UnitsHint::Unknown);
+ useGain->setRange(0, 0, 1);
return pManifest;
}
@@ -76,9 +71,9 @@ LoudnessContourEffectGroupState::LoudnessContourEffectGroupState(
// Initialize the filters with default parameters
m_low = std::make_unique(
- bufferParameters.sampleRate() , kLoPeakFreq , kHiShelveQ);
+ bufferParameters.sampleRate(), kLoPeakFreq, kHiShelveQ);
m_high = std::make_unique(
- bufferParameters.sampleRate() , kHiShelveFreq ,kHiShelveQ);
+ bufferParameters.sampleRate(), kHiShelveFreq, kHiShelveQ);
}
LoudnessContourEffectGroupState::~LoudnessContourEffectGroupState() {
@@ -90,34 +85,30 @@ void LoudnessContourEffectGroupState::setFilters(int sampleRate, double gain) {
sampleRate, kLoPeakFreq, kLoPleakQ, gain);
m_high->setFrequencyCorners(
sampleRate, kHiShelveFreq, kHiShelveQ, gain / kHiShelveGainDiv);
-
}
-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;
auto gain = static_cast(pState->m_oldGain);
if (enableState != EffectEnableState::Disabling) {
-
bool useGain = m_pUseGain->toBool() && groupFeatures.has_gain;
double loudness = m_pLoudness->value();
double gainKnob = groupFeatures.gain;
@@ -128,9 +119,8 @@ void LoudnessContourEffect::processChannel(
gainKnob != pState->m_oldGainKnob ||
loudness != pState->m_oldLoudness ||
bufferParameters.sampleRate() != pState->m_oldSampleRate) {
-
pState->m_oldUseGain = useGain;
- pState->m_oldGainKnob = gainKnob;
+ pState->m_oldGainKnob = gainKnob;
pState->m_oldLoudness = loudness;
pState->m_oldSampleRate = bufferParameters.sampleRate();
@@ -139,8 +129,7 @@ void LoudnessContourEffect::processChannel(
double gainKnobDb = ratio2db(gainKnob);
filterGainDb = loudness * gainKnobDb / kMaxLoGain;
gain = 1; // No need for adjust gain because master gain follows
- }
- else {
+ } else {
filterGainDb = -loudness;
// compensate filter boost to avoid clipping
gain = static_cast(db2ratio(-filterGainDb));
@@ -156,11 +145,13 @@ void LoudnessContourEffect::processChannel(
} else {
pState->m_low->process(pInput, pOutput, bufferParameters.samplesPerBuffer());
pState->m_high->process(pOutput, pState->m_pBuf, bufferParameters.samplesPerBuffer());
- SampleUtil::copyWithRampingGain(
- pOutput, pState->m_pBuf, pState->m_oldGain, gain,
+ SampleUtil::copyWithRampingGain(pOutput,
+ pState->m_pBuf,
+ pState->m_oldGain,
+ gain,
bufferParameters.samplesPerBuffer());
}
- pState->m_oldFilterGainDb = filterGainDb ;
+ pState->m_oldFilterGainDb = filterGainDb;
pState->m_oldGain = gain;
}
diff --git a/src/effects/builtin/loudnesscontoureffect.h b/src/effects/backends/builtin/loudnesscontoureffect.h
similarity index 68%
rename from src/effects/builtin/loudnesscontoureffect.h
rename to src/effects/backends/builtin/loudnesscontoureffect.h
index d2149cf2767a..e8f9dd72cc26 100644
--- a/src/effects/builtin/loudnesscontoureffect.h
+++ b/src/effects/backends/builtin/loudnesscontoureffect.h
@@ -1,16 +1,15 @@
#pragma once
#include "control/controlproxy.h"
-#include "effects/effect.h"
-#include "effects/effectprocessor.h"
+#include "effects/backends/effectprocessor.h"
#include "engine/effects/engineeffect.h"
#include "engine/effects/engineeffectparameter.h"
#include "engine/filters/enginefilterbiquad1.h"
#include "util/class.h"
#include "util/defs.h"
+#include "util/memory.h"
#include "util/sample.h"
#include "util/types.h"
-#include "util/memory.h"
class LoudnessContourEffectGroupState final : public EffectState {
public:
@@ -33,20 +32,24 @@ class LoudnessContourEffectGroupState final : public EffectState {
class LoudnessContourEffect
: public EffectProcessorImpl {
public:
- LoudnessContourEffect(EngineEffect* pEffect);
+ LoudnessContourEffect() = default;
~LoudnessContourEffect() override;
static QString getId();
static EffectManifestPointer getManifest();
- void setFilters(int sampleRate);
+ void loadEngineEffectParameters(
+ const QMap& parameters) override;
- void processChannel(const ChannelHandle& handle,
- LoudnessContourEffectGroupState* pState,
- const CSAMPLE* pInput, CSAMPLE *pOutput,
- const mixxx::EngineParameters& bufferParameters,
- const EffectEnableState enableState,
- const GroupFeatureState& groupFeatureState) override;
+ void processChannel(
+ LoudnessContourEffectGroupState* pState,
+ const CSAMPLE* pInput,
+ CSAMPLE* pOutput,
+ const mixxx::EngineParameters& bufferParameters,
+ const EffectEnableState enableState,
+ const GroupFeatureState& groupFeatureState) override;
+
+ void setFilters(int sampleRate);
private:
LoudnessContourEffect(const LoudnessContourEffect&) = delete;
@@ -56,6 +59,6 @@ class LoudnessContourEffect
return getId();
}
- EngineEffectParameter* m_pLoudness;
- EngineEffectParameter* m_pUseGain;
+ EngineEffectParameterPointer m_pLoudness;
+ EngineEffectParameterPointer m_pUseGain;
};
diff --git a/src/effects/builtin/lvmixeqbase.h b/src/effects/backends/builtin/lvmixeqbase.h
similarity index 91%
rename from src/effects/builtin/lvmixeqbase.h
rename to src/effects/backends/builtin/lvmixeqbase.h
index 02f74a03e1c6..f409755e2dac 100644
--- a/src/effects/builtin/lvmixeqbase.h
+++ b/src/effects/backends/builtin/lvmixeqbase.h
@@ -1,6 +1,6 @@
#pragma once
-#include "effects/effectprocessor.h"
+#include "effects/backends/effectprocessor.h"
#include "engine/filters/enginefilterdelay.h"
#include "util/defs.h"
#include "util/math.h"
@@ -122,9 +122,12 @@ class LVMixEQEffectGroupState : public EffectState {
fMid == m_oldMid &&
fHigh == m_oldHigh) {
SampleUtil::copy3WithGain(pOutput,
- m_pLowBuf, fLow,
- m_pBandBuf, fMid,
- m_pHighBuf, fHigh,
+ m_pLowBuf,
+ fLow,
+ m_pBandBuf,
+ fMid,
+ m_pHighBuf,
+ fHigh,
numSamples);
} else {
SINT copySamples = 0;
@@ -153,17 +156,26 @@ class LVMixEQEffectGroupState : public EffectState {
rampingSamples = numSamples - copySamples;
SampleUtil::copy3WithGain(pOutput,
- m_pLowBuf, m_oldLow,
- m_pBandBuf, m_oldMid,
- m_pHighBuf, m_oldHigh,
+ m_pLowBuf,
+ m_oldLow,
+ m_pBandBuf,
+ m_oldMid,
+ m_pHighBuf,
+ m_oldHigh,
copySamples);
}
if (rampingSamples) {
SampleUtil::copy3WithRampingGain(&pOutput[copySamples],
- &m_pLowBuf[copySamples], m_oldLow, fLow,
- &m_pBandBuf[copySamples], m_oldMid, fMid,
- &m_pHighBuf[copySamples], m_oldHigh, fHigh,
+ &m_pLowBuf[copySamples],
+ m_oldLow,
+ fLow,
+ &m_pBandBuf[copySamples],
+ m_oldMid,
+ fMid,
+ &m_pHighBuf[copySamples],
+ m_oldHigh,
+ fHigh,
rampingSamples);
m_oldLow = fLow;
@@ -194,9 +206,15 @@ class LVMixEQEffectGroupState : public EffectState {
}
SampleUtil::copy3WithRampingGain(pOutput,
- m_pLowBuf, m_oldLow, 0.0,
- m_pBandBuf, m_oldMid, 0.0,
- m_pHighBuf, m_oldHigh, 1.0,
+ m_pLowBuf,
+ m_oldLow,
+ 0.0,
+ m_pBandBuf,
+ m_oldMid,
+ 0.0,
+ m_pHighBuf,
+ m_oldHigh,
+ 1.0,
numSamples);
}
diff --git a/src/effects/builtin/metronomeclick.h b/src/effects/backends/builtin/metronomeclick.h
similarity index 100%
rename from src/effects/builtin/metronomeclick.h
rename to src/effects/backends/builtin/metronomeclick.h
diff --git a/src/effects/builtin/metronomeeffect.cpp b/src/effects/backends/builtin/metronomeeffect.cpp
similarity index 79%
rename from src/effects/builtin/metronomeeffect.cpp
rename to src/effects/backends/builtin/metronomeeffect.cpp
index 3423b472b6c5..b16652437ca4 100644
--- a/src/effects/builtin/metronomeeffect.cpp
+++ b/src/effects/backends/builtin/metronomeeffect.cpp
@@ -7,7 +7,6 @@
#include "util/math.h"
#include "util/sample.h"
-
// static
QString MetronomeEffect::getId() {
return "org.mixxx.effects.metronome";
@@ -29,45 +28,39 @@ 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->setSemanticHint(EffectManifestParameter::SemanticHint::UNKNOWN);
- period->setUnitsHint(EffectManifestParameter::UnitsHint::UNKNOWN);
- period->setMinimum(40);
- period->setDefault(120);
- period->setMaximum(208);
-
+ period->setValueScaler(EffectManifestParameter::ValueScaler::Logarithmic);
+ period->setUnitsHint(EffectManifestParameter::UnitsHint::Unknown);
+ period->setRange(40, 120, 208);
// Period unit
EffectManifestParameterPointer periodUnit = pManifest->addParameter();
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->setSemanticHint(EffectManifestParameter::SemanticHint::UNKNOWN);
- periodUnit->setUnitsHint(EffectManifestParameter::UnitsHint::UNKNOWN);
- periodUnit->setDefault(1);
- periodUnit->setMinimum(0);
- periodUnit->setMaximum(1);
+ periodUnit->setDescription(QObject::tr(
+ "Synchronizes the BPM with the track if it can be retrieved"));
+ periodUnit->setValueScaler(EffectManifestParameter::ValueScaler::Toggle);
+ periodUnit->setUnitsHint(EffectManifestParameter::UnitsHint::Unknown);
+ 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 CSAMPLE* pInput,
+ CSAMPLE* pOutput,
const mixxx::EngineParameters& bufferParameters,
const EffectEnableState enableState,
const GroupFeatureState& groupFeatures) {
- Q_UNUSED(handle);
Q_UNUSED(pInput);
MetronomeGroupState* gs = pGroupState;
@@ -114,8 +107,7 @@ void MetronomeEffect::processChannel(
const SINT copyFrames =
math_min(bufferParameters.framesPerBuffer(),
clickSize - gs->m_framesSinceClickStart);
- SampleUtil::addMonoToStereo(pOutput, &click[gs->m_framesSinceClickStart],
- copyFrames);
+ SampleUtil::addMonoToStereo(pOutput, &click[gs->m_framesSinceClickStart], copyFrames);
}
gs->m_framesSinceClickStart += bufferParameters.framesPerBuffer();
@@ -134,7 +126,6 @@ void MetronomeEffect::processChannel(
bufferParameters.framesPerBuffer() - gs->m_framesSinceClickStart;
const unsigned int copyFrames =
math_min(gs->m_framesSinceClickStart, clickSize);
- SampleUtil::addMonoToStereo(&pOutput[outputOffset * 2], click,
- copyFrames);
+ SampleUtil::addMonoToStereo(&pOutput[outputOffset * 2], click, copyFrames);
}
}
diff --git a/src/effects/builtin/metronomeeffect.h b/src/effects/backends/builtin/metronomeeffect.h
similarity index 51%
rename from src/effects/builtin/metronomeeffect.h
rename to src/effects/backends/builtin/metronomeeffect.h
index 6207f008d2e7..7fe0f29d285e 100644
--- a/src/effects/builtin/metronomeeffect.h
+++ b/src/effects/backends/builtin/metronomeeffect.h
@@ -2,7 +2,7 @@
#include
-#include "effects/effectprocessor.h"
+#include "effects/backends/effectprocessor.h"
#include "engine/effects/engineeffect.h"
#include "engine/effects/engineeffectparameter.h"
#include "engine/filters/enginefilterpansingle.h"
@@ -11,12 +11,11 @@
#include "util/sample.h"
#include "util/types.h"
-
class MetronomeGroupState final : public EffectState {
public:
MetronomeGroupState(const mixxx::EngineParameters& bufferParameters)
- : EffectState(bufferParameters),
- m_framesSinceClickStart(0) {
+ : EffectState(bufferParameters),
+ m_framesSinceClickStart(0) {
}
~MetronomeGroupState() {
}
@@ -26,22 +25,26 @@ class MetronomeGroupState final : public EffectState {
class MetronomeEffect : public EffectProcessorImpl {
public:
- MetronomeEffect(EngineEffect* pEffect);
+ MetronomeEffect() = default;
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/backends/builtin/moogladder4filtereffect.cpp
similarity index 74%
rename from src/effects/builtin/moogladder4filtereffect.cpp
rename to src/effects/backends/builtin/moogladder4filtereffect.cpp
index fd5691dd2136..018efe7fe109 100644
--- a/src/effects/builtin/moogladder4filtereffect.cpp
+++ b/src/effects/backends/builtin/moogladder4filtereffect.cpp
@@ -1,4 +1,5 @@
-#include "effects/builtin/moogladder4filtereffect.h"
+#include "effects/backends/builtin/moogladder4filtereffect.h"
+
#include "util/math.h"
static constexpr double kMinCorner = 0.0003; // 13 Hz @ 44100
@@ -17,47 +18,40 @@ EffectManifestPointer MoogLadder4FilterEffect::getManifest() {
pManifest->setShortName(QObject::tr("Moog Filter"));
pManifest->setAuthor("The Mixxx Team");
pManifest->setVersion("1.0");
- pManifest->setDescription(QObject::tr(
- "A 4-pole Moog ladder filter, based on Antti Houvilainen's non linear digital implementation"));
+ pManifest->setDescription(
+ QObject::tr("A 4-pole Moog ladder filter, based on Antti "
+ "Houvilainen's non linear digital implementation"));
pManifest->setEffectRampsFromDry(true);
+ pManifest->setMetaknobDefault(0.5);
EffectManifestParameterPointer lpf = pManifest->addParameter();
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->setSemanticHint(EffectManifestParameter::SemanticHint::UNKNOWN);
- lpf->setUnitsHint(EffectManifestParameter::UnitsHint::UNKNOWN);
- lpf->setDefaultLinkType(EffectManifestParameter::LinkType::LINKED_LEFT);
+ lpf->setValueScaler(EffectManifestParameter::ValueScaler::Logarithmic);
+ lpf->setUnitsHint(EffectManifestParameter::UnitsHint::Unknown);
+ lpf->setDefaultLinkType(EffectManifestParameter::LinkType::LinkedLeft);
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->setSemanticHint(EffectManifestParameter::SemanticHint::UNKNOWN);
- q->setUnitsHint(EffectManifestParameter::UnitsHint::SAMPLERATE);
- q->setMinimum(0.0);
- q->setMaximum(4.0);
- q->setDefault(1.0);
+ q->setValueScaler(EffectManifestParameter::ValueScaler::Logarithmic);
+ q->setUnitsHint(EffectManifestParameter::UnitsHint::SampleRate);
+ 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->setSemanticHint(EffectManifestParameter::SemanticHint::UNKNOWN);
- hpf->setUnitsHint(EffectManifestParameter::UnitsHint::UNKNOWN);
- hpf->setDefaultLinkType(EffectManifestParameter::LinkType::LINKED_RIGHT);
+ hpf->setValueScaler(EffectManifestParameter::ValueScaler::Logarithmic);
+ hpf->setUnitsHint(EffectManifestParameter::UnitsHint::Unknown);
+ hpf->setDefaultLinkType(EffectManifestParameter::LinkType::LinkedRight);
hpf->setNeutralPointOnScale(0.0);
- hpf->setDefault(kMinCorner);
- hpf->setMinimum(kMinCorner);
- hpf->setMaximum(kMaxCorner);
+ hpf->setRange(kMinCorner, kMinCorner, kMaxCorner);
return pManifest;
}
@@ -72,10 +66,12 @@ MoogLadder4FilterGroupState::MoogLadder4FilterGroupState(
m_pBuf = SampleUtil::alloc(bufferParameters.samplesPerBuffer());
m_pLowFilter = new EngineFilterMoogLadder4Low(
bufferParameters.sampleRate(),
- m_loFreq * bufferParameters.sampleRate(), m_resonance);
+ m_loFreq * bufferParameters.sampleRate(),
+ m_resonance);
m_pHighFilter = new EngineFilterMoogLadder4High(
bufferParameters.sampleRate(),
- m_hiFreq * bufferParameters.sampleRate(), m_resonance);
+ m_hiFreq * bufferParameters.sampleRate(),
+ m_resonance);
}
MoogLadder4FilterGroupState::~MoogLadder4FilterGroupState() {
@@ -84,10 +80,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() {
@@ -95,13 +92,12 @@ MoogLadder4FilterEffect::~MoogLadder4FilterEffect() {
}
void MoogLadder4FilterEffect::processChannel(
- const ChannelHandle& handle,
MoogLadder4FilterGroupState* pState,
- const CSAMPLE* pInput, CSAMPLE* pOutput,
+ 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();
@@ -146,7 +142,8 @@ void MoogLadder4FilterEffect::processChannel(
} else if (pState->m_hiFreq > kMinCorner) {
// hpf disabling
pState->m_pHighFilter->processAndPauseFilter(pInput,
- pHpfOutput, bufferParameters.samplesPerBuffer());
+ pHpfOutput,
+ bufferParameters.samplesPerBuffer());
} else {
// paused LP uses input directly
pLpfInput = pInput;
@@ -158,7 +155,8 @@ void MoogLadder4FilterEffect::processChannel(
} else if (pState->m_loFreq < kMaxCorner) {
// hpf disabling
pState->m_pLowFilter->processAndPauseFilter(pLpfInput,
- pOutput, bufferParameters.samplesPerBuffer());
+ pOutput,
+ bufferParameters.samplesPerBuffer());
} else if (pLpfInput == pInput) {
// Both disabled
if (pOutput != pInput) {
diff --git a/src/effects/builtin/moogladder4filtereffect.h b/src/effects/backends/builtin/moogladder4filtereffect.h
similarity index 62%
rename from src/effects/builtin/moogladder4filtereffect.h
rename to src/effects/backends/builtin/moogladder4filtereffect.h
index 8f269b4905a9..f819690b5fe6 100644
--- a/src/effects/builtin/moogladder4filtereffect.h
+++ b/src/effects/backends/builtin/moogladder4filtereffect.h
@@ -1,7 +1,5 @@
#pragma once
-
-#include "effects/effect.h"
-#include "effects/effectprocessor.h"
+#include "effects/backends/effectprocessor.h"
#include "engine/effects/engineeffect.h"
#include "engine/effects/engineeffectparameter.h"
#include "engine/filters/enginefiltermoogladder4.h"
@@ -28,28 +26,31 @@ class MoogLadder4FilterGroupState : public EffectState {
class MoogLadder4FilterEffect : public EffectProcessorImpl {
public:
- MoogLadder4FilterEffect(EngineEffect* pEffect);
+ MoogLadder4FilterEffect() = default;
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/backends/builtin/parametriceqeffect.cpp
similarity index 58%
rename from src/effects/builtin/parametriceqeffect.cpp
rename to src/effects/backends/builtin/parametriceqeffect.cpp
index 11927b588537..1e6efde36859 100644
--- a/src/effects/builtin/parametriceqeffect.cpp
+++ b/src/effects/backends/builtin/parametriceqeffect.cpp
@@ -1,4 +1,5 @@
-#include "effects/builtin/parametriceqeffect.h"
+#include "effects/backends/builtin/parametriceqeffect.h"
+
#include "util/math.h"
namespace {
@@ -21,8 +22,8 @@ EffectManifestPointer ParametricEQEffect::getManifest() {
pManifest->setAuthor("The Mixxx Team");
pManifest->setVersion("1.0");
pManifest->setDescription(QObject::tr(
- "An gentle 2-band parametric equalizer based on biquad filters.\n"
- "It is designed as a complement to the steep mixing equalizers."));
+ "An gentle 2-band parametric equalizer based on biquad filters.\n"
+ "It is designed as a complement to the steep mixing equalizers."));
pManifest->setEffectRampsFromDry(true);
pManifest->setIsMasterEQ(true);
@@ -31,95 +32,78 @@ EffectManifestPointer ParametricEQEffect::getManifest() {
gain1->setName(QObject::tr("Gain 1"));
gain1->setShortName(QObject::tr("Gain 1"));
gain1->setDescription(QObject::tr(
- "Gain for Filter 1"));
- gain1->setControlHint(EffectManifestParameter::ControlHint::KNOB_LINEAR);
- gain1->setSemanticHint(EffectManifestParameter::SemanticHint::UNKNOWN);
- gain1->setUnitsHint(EffectManifestParameter::UnitsHint::UNKNOWN);
+ "Gain for Filter 1"));
+ gain1->setValueScaler(EffectManifestParameter::ValueScaler::Linear);
+ 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");
q1->setName(QObject::tr("Q 1"));
q1->setShortName(QObject::tr("Q 1"));
q1->setDescription(QObject::tr(
- "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->setSemanticHint(EffectManifestParameter::SemanticHint::UNKNOWN);
- q1->setUnitsHint(EffectManifestParameter::UnitsHint::UNKNOWN);
+ "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->setValueScaler(EffectManifestParameter::ValueScaler::Linear);
+ 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");
center1->setName(QObject::tr("Center 1"));
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->setSemanticHint(EffectManifestParameter::SemanticHint::UNKNOWN);
- center1->setUnitsHint(EffectManifestParameter::UnitsHint::HERTZ);
+ "Center frequency for Filter 1, from 100 Hz to 14 kHz"));
+ center1->setValueScaler(EffectManifestParameter::ValueScaler::Logarithmic);
+ 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");
gain2->setName(QObject::tr("Gain 2"));
gain2->setShortName(QObject::tr("Gain 2"));
gain2->setDescription(QObject::tr(
- "Gain for Filter 2"));
- gain2->setControlHint(EffectManifestParameter::ControlHint::KNOB_LINEAR);
- gain2->setSemanticHint(EffectManifestParameter::SemanticHint::UNKNOWN);
- gain2->setUnitsHint(EffectManifestParameter::UnitsHint::UNKNOWN);
+ "Gain for Filter 2"));
+ gain2->setValueScaler(EffectManifestParameter::ValueScaler::Linear);
+ 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");
q2->setName(QObject::tr("Q 2"));
q2->setShortName(QObject::tr("Q 2"));
q2->setDescription(QObject::tr(
- "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->setSemanticHint(EffectManifestParameter::SemanticHint::UNKNOWN);
- q2->setUnitsHint(EffectManifestParameter::UnitsHint::UNKNOWN);
+ "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->setValueScaler(EffectManifestParameter::ValueScaler::Linear);
+ 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");
center2->setName(QObject::tr("Center 2"));
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->setSemanticHint(EffectManifestParameter::SemanticHint::UNKNOWN);
- center2->setUnitsHint(EffectManifestParameter::UnitsHint::HERTZ);
+ "Center frequency for Filter 2, from 100 Hz to 14 kHz"));
+ center2->setValueScaler(EffectManifestParameter::ValueScaler::Logarithmic);
+ 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) {
+ const mixxx::EngineParameters& 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 +126,32 @@ 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/backends/builtin/parametriceqeffect.h
similarity index 54%
rename from src/effects/builtin/parametriceqeffect.h
rename to src/effects/backends/builtin/parametriceqeffect.h
index b41a45118702..caf3ea42b992 100644
--- a/src/effects/builtin/parametriceqeffect.h
+++ b/src/effects/backends/builtin/parametriceqeffect.h
@@ -1,23 +1,23 @@
#pragma once
-#include
#include
+#include
+#include "audio/types.h"
#include "control/controlproxy.h"
-#include "effects/effect.h"
-#include "effects/effectprocessor.h"
+#include "effects/backends/effectprocessor.h"
#include "engine/effects/engineeffect.h"
#include "engine/effects/engineeffectparameter.h"
#include "engine/filters/enginefilterbiquad1.h"
#include "util/class.h"
#include "util/defs.h"
+#include "util/memory.h"
#include "util/sample.h"
#include "util/types.h"
-#include "util/memory.h"
// The ParametricEQEffect models the mid bands from a SSL Black EQ (242)
// with a gentle parameter range, as requested here:
-// https://www.mixxx.org/forums/viewtopic.php?f=3&t=9239&p=33312&hilit=SSL#p33312
+// https://mixxx.discourse.group/t/sending-output-via-a-software-equalizer/16718/10#p33312
// The main use case is to tweak the room or recording sound, which is hard to achieve
// with the sharp and wide curves of the mixing EQs.
@@ -27,38 +27,47 @@ class ParametricEQEffectGroupState final : public EffectState {
void setFilters(int sampleRate);
+ // These containers are only appended in the constructor which is called on
+ // the main thread, so there is no risk of allocation in the audio thread.
std::vector > m_bands;
QList m_oldGain;
QList m_oldCenter;
QList m_oldQ;
+ mixxx::audio::SampleRate m_oldSampleRate;
+
QList m_pBufs;
};
class ParametricEQEffect : public EffectProcessorImpl {
public:
- ParametricEQEffect(EngineEffect* pEffect);
+ ParametricEQEffect() = default;
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;
+ // These QLists are only appended on the main thread in loadEngineEffectParameters,
+ // so there is no risk of allocation in the audio thread.
+ QList m_pPotGain;
+ QList m_pPotQ;
+ QList m_pPotCenter;
mixxx::audio::SampleRate m_oldSampleRate;
diff --git a/src/effects/builtin/phasereffect.cpp b/src/effects/backends/builtin/phasereffect.cpp
similarity index 59%
rename from src/effects/builtin/phasereffect.cpp
rename to src/effects/backends/builtin/phasereffect.cpp
index defd40a6a263..f7cc39c58610 100644
--- a/src/effects/builtin/phasereffect.cpp
+++ b/src/effects/backends/builtin/phasereffect.cpp
@@ -1,4 +1,4 @@
-#include "effects/builtin/phasereffect.h"
+#include "effects/backends/builtin/phasereffect.h"
#include
@@ -21,8 +21,8 @@ EffectManifestPointer PhaserEffect::getManifest() {
pManifest->setAuthor("The Mixxx Team");
pManifest->setVersion("1.0");
pManifest->setDescription(QObject::tr(
- "Mixes the input signal with a copy passed through a series of "
- "all-pass filters to create comb filtering"));
+ "Mixes the input signal with a copy passed through a series of "
+ "all-pass filters to create comb filtering"));
pManifest->setEffectRampsFromDry(true);
EffectManifestParameterPointer period = pManifest->addParameter();
@@ -30,120 +30,100 @@ EffectManifestPointer PhaserEffect::getManifest() {
period->setName(QObject::tr("Period"));
period->setShortName(QObject::tr("Period"));
period->setDescription(QObject::tr(
- "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->setSemanticHint(EffectManifestParameter::SemanticHint::UNKNOWN);
- period->setUnitsHint(EffectManifestParameter::UnitsHint::BEATS);
- period->setMinimum(0.0);
- period->setMaximum(4.0);
- period->setDefault(1.0);
+ "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->setValueScaler(EffectManifestParameter::ValueScaler::Linear);
+ period->setUnitsHint(EffectManifestParameter::UnitsHint::Beats);
+ period->setRange(0.0, 1.0, 4.0);
EffectManifestParameterPointer fb = pManifest->addParameter();
fb->setId("feedback");
fb->setName(QObject::tr("Feedback"));
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->setSemanticHint(EffectManifestParameter::SemanticHint::UNKNOWN);
- fb->setUnitsHint(EffectManifestParameter::UnitsHint::UNKNOWN);
- fb->setMinimum(-1.0);
- fb->setMaximum(1.0);
- fb->setDefault(0.0);
+ "Controls how much of the output signal is looped"));
+ fb->setValueScaler(EffectManifestParameter::ValueScaler::Linear);
+ fb->setUnitsHint(EffectManifestParameter::UnitsHint::Unknown);
+ fb->setRange(-1.0, 0.0, 1.0);
EffectManifestParameterPointer range = pManifest->addParameter();
range->setId("range");
range->setName(QObject::tr("Range"));
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->setSemanticHint(EffectManifestParameter::SemanticHint::UNKNOWN);
- range->setUnitsHint(EffectManifestParameter::UnitsHint::UNKNOWN);
- range->setMinimum(0.05);
- range->setMaximum(1.0);
- range->setDefault(1.0);
+ "Controls the frequency range across which the notches sweep."));
+ range->setValueScaler(EffectManifestParameter::ValueScaler::Linear);
+ range->setUnitsHint(EffectManifestParameter::UnitsHint::Unknown);
+ range->setRange(0.05, 1.0, 1.0);
EffectManifestParameterPointer stages = pManifest->addParameter();
stages->setId("stages");
stages->setName(QObject::tr("Stages"));
stages->setShortName(QObject::tr("Stages"));
stages->setDescription(QObject::tr(
- "Number of stages")); // stages of what?
- stages->setControlHint(EffectManifestParameter::ControlHint::KNOB_LINEAR);
- stages->setSemanticHint(EffectManifestParameter::SemanticHint::UNKNOWN);
- stages->setUnitsHint(EffectManifestParameter::UnitsHint::UNKNOWN);
- stages->setMinimum(1.0);
- stages->setMaximum(6.0);
- stages->setDefault(3.5);
+ "Number of stages")); // stages of what?
+ stages->setValueScaler(EffectManifestParameter::ValueScaler::Linear);
+ stages->setUnitsHint(EffectManifestParameter::UnitsHint::Unknown);
+ stages->setRange(1.0, 3.5, 6.0);
EffectManifestParameterPointer depth = pManifest->addParameter();
depth->setId("depth");
depth->setName(QObject::tr("Depth"));
depth->setShortName(QObject::tr("Depth"));
depth->setDescription(QObject::tr(
- "Intensity of the effect"));
- depth->setControlHint(EffectManifestParameter::ControlHint::KNOB_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);
+ "Intensity of the effect"));
+ depth->setValueScaler(EffectManifestParameter::ValueScaler::Linear);
+ depth->setUnitsHint(EffectManifestParameter::UnitsHint::Unknown);
+ depth->setDefaultLinkType(EffectManifestParameter::LinkType::Linked);
+ depth->setRange(0.5, 0.5, 1.0);
EffectManifestParameterPointer triplet = pManifest->addParameter();
triplet->setId("triplet");
triplet->setName(QObject::tr("Triplets"));
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->setSemanticHint(EffectManifestParameter::SemanticHint::UNKNOWN);
- triplet->setUnitsHint(EffectManifestParameter::UnitsHint::UNKNOWN);
- triplet->setDefault(0);
- triplet->setMinimum(0);
- triplet->setMaximum(1);
+ "Divide rounded 1/2 beats of the Period parameter by 3."));
+ triplet->setValueScaler(EffectManifestParameter::ValueScaler::Toggle);
+ triplet->setUnitsHint(EffectManifestParameter::UnitsHint::Unknown);
+ triplet->setRange(0, 0, 1);
EffectManifestParameterPointer stereo = pManifest->addParameter();
stereo->setId("stereo");
stereo->setName(QObject::tr("Stereo"));
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->setSemanticHint(EffectManifestParameter::SemanticHint::UNKNOWN);
- stereo->setUnitsHint(EffectManifestParameter::UnitsHint::UNKNOWN);
- stereo->setMinimum(0);
- stereo->setMaximum(1);
- stereo->setDefault(0);
+ "Sets the LFOs (low frequency oscillators) for the left and right "
+ "channels out of phase with each others"));
+ stereo->setValueScaler(EffectManifestParameter::ValueScaler::Toggle);
+ stereo->setUnitsHint(EffectManifestParameter::UnitsHint::Unknown);
+ 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();
}
@@ -157,14 +137,15 @@ void PhaserEffect::processChannel(const ChannelHandle& handle,
double periodSamples;
if (groupFeatures.has_beat_length_sec) {
// periodParameter is a number of beats
- periodParameter = std::max(roundToFraction(periodParameter, 2.0), 1/4.0);
+ periodParameter = std::max(roundToFraction(periodParameter, 2.0), 1 / 4.0);
if (m_pTripletParameter->toBool()) {
periodParameter /= 3.0;
}
- periodSamples = periodParameter * groupFeatures.beat_length_sec * bufferParameters.sampleRate();
+ periodSamples = periodParameter * groupFeatures.beat_length_sec *
+ bufferParameters.sampleRate();
} else {
// periodParameter is a number of seconds
- periodSamples = std::max(periodParameter, 1/4.0) * bufferParameters.sampleRate();
+ periodSamples = std::max(periodParameter, 1 / 4.0) * bufferParameters.sampleRate();
}
// freqSkip is used to calculate the phase independently for each channel,
// so do not multiply periodSamples by the number of channels.
@@ -186,8 +167,7 @@ void PhaserEffect::processChannel(const ChannelHandle& handle,
CSAMPLE left = 0, right = 0;
CSAMPLE_GAIN oldDepth = pState->oldDepth;
- const CSAMPLE_GAIN depthDelta = (depth - oldDepth)
- / bufferParameters.framesPerBuffer();
+ const CSAMPLE_GAIN depthDelta = (depth - oldDepth) / bufferParameters.framesPerBuffer();
const CSAMPLE_GAIN depthStart = oldDepth + depthDelta;
const auto stereoCheck = static_cast(m_pStereoParameter->value());
diff --git a/src/effects/builtin/phasereffect.h b/src/effects/backends/builtin/phasereffect.h
similarity index 59%
rename from src/effects/builtin/phasereffect.h
rename to src/effects/backends/builtin/phasereffect.h
index bc71a0f7865b..fb36f64d051f 100644
--- a/src/effects/builtin/phasereffect.h
+++ b/src/effects/backends/builtin/phasereffect.h
@@ -1,6 +1,6 @@
#pragma once
-#include "effects/effectprocessor.h"
+#include "effects/backends/effectprocessor.h"
#include "engine/effects/engineeffect.h"
#include "engine/effects/engineeffectparameter.h"
#include "util/class.h"
@@ -34,42 +34,46 @@ class PhaserGroupState final : public EffectState {
CSAMPLE leftPhase;
CSAMPLE rightPhase;
CSAMPLE_GAIN oldDepth;
-
};
class PhaserEffect : public EffectProcessorImpl {
-
public:
- PhaserEffect(EngineEffect* pEffect);
+ PhaserEffect() = default;
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) override;
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,
- CSAMPLE mainCoef, int stages) {
+ inline CSAMPLE processSample(CSAMPLE input,
+ CSAMPLE* oldIn,
+ CSAMPLE* oldOut,
+ CSAMPLE mainCoef,
+ int stages) {
for (int j = 0; j < stages; j++) {
oldOut[j] = (mainCoef * input) + (mainCoef * oldOut[j]) - oldIn[j];
oldIn[j] = input;
diff --git a/src/effects/builtin/reverbeffect.cpp b/src/effects/backends/builtin/reverbeffect.cpp
similarity index 50%
rename from src/effects/builtin/reverbeffect.cpp
rename to src/effects/backends/builtin/reverbeffect.cpp
index 320b69349007..27f9292263e5 100644
--- a/src/effects/builtin/reverbeffect.cpp
+++ b/src/effects/backends/builtin/reverbeffect.cpp
@@ -1,4 +1,4 @@
-#include "effects/builtin/reverbeffect.h"
+#include "effects/backends/builtin/reverbeffect.h"
#include
@@ -20,84 +20,74 @@ EffectManifestPointer ReverbEffect::getManifest() {
pManifest->setAuthor("The Mixxx Team, CAPS Plugins");
pManifest->setVersion("1.0");
pManifest->setDescription(QObject::tr(
- "Emulates the sound of the signal bouncing off the walls of a room"));
+ "Emulates the sound of the signal bouncing off the walls of a room"));
EffectManifestParameterPointer decay = pManifest->addParameter();
decay->setId("decay");
decay->setName(QObject::tr("Decay"));
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->setSemanticHint(EffectManifestParameter::SemanticHint::UNKNOWN);
- decay->setUnitsHint(EffectManifestParameter::UnitsHint::UNKNOWN);
- decay->setMinimum(0);
- decay->setDefault(0.5);
- decay->setMaximum(1);
+ "Lower decay values cause reverberations to fade out more quickly."));
+ decay->setValueScaler(EffectManifestParameter::ValueScaler::Linear);
+ decay->setUnitsHint(EffectManifestParameter::UnitsHint::Unknown);
+ decay->setRange(0, 0.5, 1);
EffectManifestParameterPointer bandwidth = pManifest->addParameter();
bandwidth->setId("bandwidth");
bandwidth->setName(QObject::tr("Bandwidth"));
bandwidth->setShortName(QObject::tr("BW"));
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->setSemanticHint(EffectManifestParameter::SemanticHint::UNKNOWN);
- bandwidth->setUnitsHint(EffectManifestParameter::UnitsHint::UNKNOWN);
- bandwidth->setMinimum(0);
- bandwidth->setDefault(1);
- bandwidth->setMaximum(1);
+ "Bandwidth of the low pass filter at the input.\n"
+ "Higher values result in less attenuation of high frequencies."));
+ bandwidth->setValueScaler(EffectManifestParameter::ValueScaler::Linear);
+ bandwidth->setUnitsHint(EffectManifestParameter::UnitsHint::Unknown);
+ bandwidth->setRange(0, 1, 1);
EffectManifestParameterPointer damping = pManifest->addParameter();
damping->setId("damping");
damping->setName(QObject::tr("Damping"));
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->setSemanticHint(EffectManifestParameter::SemanticHint::UNKNOWN);
- damping->setUnitsHint(EffectManifestParameter::UnitsHint::UNKNOWN);
- damping->setMinimum(0);
- damping->setDefault(0);
- damping->setMaximum(1);
+ damping->setDescription(
+ QObject::tr("Higher damping values cause high frequencies to decay "
+ "more quickly than low frequencies."));
+ damping->setValueScaler(EffectManifestParameter::ValueScaler::Linear);
+ damping->setUnitsHint(EffectManifestParameter::UnitsHint::Unknown);
+ damping->setRange(0, 0, 1);
EffectManifestParameterPointer send = pManifest->addParameter();
send->setId("send_amount");
send->setName(QObject::tr("Send"));
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->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);
+ "How much of the signal to send in to the effect"));
+ send->setValueScaler(EffectManifestParameter::ValueScaler::Linear);
+ send->setUnitsHint(EffectManifestParameter::UnitsHint::Unknown);
+ send->setDefaultLinkType(EffectManifestParameter::LinkType::Linked);
+ send->setDefaultLinkInversion(EffectManifestParameter::LinkInversion::NotInverted);
+ 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 = static_cast(m_pDecayParameter->value());
@@ -108,15 +98,20 @@ void ReverbEffect::processChannel(const ChannelHandle& handle,
// Reinitialize the effect when turning it on to prevent replaying the old buffer
// from the last time the effect was enabled.
// Also, update the sample rate if it has changed.
- if (enableState == EffectEnableState::Enabling
- || pState->sampleRate != bufferParameters.sampleRate()) {
+ if (enableState == EffectEnableState::Enabling ||
+ pState->sampleRate != bufferParameters.sampleRate()) {
pState->reverb.init(bufferParameters.sampleRate());
pState->sampleRate = bufferParameters.sampleRate();
}
- pState->reverb.processBuffer(pInput, pOutput,
- bufferParameters.samplesPerBuffer(),
- bandwidth, decay, damping, sendCurrent, pState->sendPrevious);
+ pState->reverb.processBuffer(pInput,
+ pOutput,
+ bufferParameters.samplesPerBuffer(),
+ bandwidth,
+ decay,
+ damping,
+ sendCurrent,
+ pState->sendPrevious);
// The ramping of the send parameter handles ramping when enabling, so
// this effect must handle ramping to dry when disabling itself (instead
diff --git a/src/effects/builtin/reverbeffect.h b/src/effects/backends/builtin/reverbeffect.h
similarity index 55%
rename from src/effects/builtin/reverbeffect.h
rename to src/effects/backends/builtin/reverbeffect.h
index 5708c37dcae6..11b629e4b317 100644
--- a/src/effects/builtin/reverbeffect.h
+++ b/src/effects/backends/builtin/reverbeffect.h
@@ -3,11 +3,11 @@
#pragma once
-#include
-
#include
-#include "effects/effectprocessor.h"
+#include
+
+#include "effects/backends/effectprocessor.h"
#include "engine/effects/engineeffect.h"
#include "engine/effects/engineeffectparameter.h"
#include "util/class.h"
@@ -18,8 +18,8 @@
class ReverbGroupState : public EffectState {
public:
ReverbGroupState(const mixxx::EngineParameters& bufferParameters)
- : EffectState(bufferParameters),
- sendPrevious(0) {
+ : EffectState(bufferParameters),
+ sendPrevious(0) {
}
void engineParametersChanged(const mixxx::EngineParameters& bufferParameters) {
@@ -34,29 +34,32 @@ class ReverbGroupState : public EffectState {
class ReverbEffect : public EffectProcessorImpl {
public:
- ReverbEffect(EngineEffect* pEffect);
+ ReverbEffect() = default;
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) override;
+
+ 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/backends/builtin/threebandbiquadeqeffect.cpp
similarity index 89%
rename from src/effects/builtin/threebandbiquadeqeffect.cpp
rename to src/effects/backends/builtin/threebandbiquadeqeffect.cpp
index a2ceee064110..fac62611e42a 100644
--- a/src/effects/builtin/threebandbiquadeqeffect.cpp
+++ b/src/effects/backends/builtin/threebandbiquadeqeffect.cpp
@@ -1,6 +1,6 @@
-#include "effects/builtin/threebandbiquadeqeffect.h"
+#include "effects/backends/builtin/threebandbiquadeqeffect.h"
-#include "effects/builtin/equalizer_util.h"
+#include "effects/backends/builtin/equalizer_util.h"
#include "util/math.h"
namespace {
@@ -19,7 +19,6 @@ static constexpr double kQKillShelve = 0.4;
static constexpr double kBoostGain = 12;
static constexpr double kKillGain = -26;
-
double getCenterFrequency(double low, double high) {
double scaleLow = log10(low);
double scaleHigh = log10(high);
@@ -28,7 +27,7 @@ double getCenterFrequency(double low, double high) {
return pow(10, scaleCenter);
}
-double knobValueToBiquadGainDb (double value, bool kill) {
+double knobValueToBiquadGainDb(double value, bool kill) {
if (kill) {
return kKillGain;
}
@@ -44,7 +43,6 @@ double knobValueToBiquadGainDb (double value, bool kill) {
} // anonymous namespace
-
// static
QString ThreeBandBiquadEQEffect::getId() {
return "org.mixxx.effects.threebandbiquadeq";
@@ -58,9 +56,10 @@ EffectManifestPointer ThreeBandBiquadEQEffect::getManifest() {
pManifest->setShortName(QObject::tr("BQ EQ"));
pManifest->setAuthor("The Mixxx Team");
pManifest->setVersion("1.0");
- pManifest->setDescription(QObject::tr(
- "A 3-band Equalizer with two biquad bell filters, a shelving high pass and kill switches.") +
- " " + EqualizerUtil::adjustFrequencyShelvesTip());
+ pManifest->setDescription(
+ QObject::tr("A 3-band Equalizer with two biquad bell filters, a "
+ "shelving high pass and kill switches.") +
+ " " + EqualizerUtil::adjustFrequencyShelvesTip());
pManifest->setEffectRampsFromDry(true);
pManifest->setIsMixingEQ(true);
@@ -69,7 +68,7 @@ EffectManifestPointer ThreeBandBiquadEQEffect::getManifest() {
}
ThreeBandBiquadEQEffectGroupState::ThreeBandBiquadEQEffectGroupState(
- const mixxx::EngineParameters& bufferParameters)
+ const mixxx::EngineParameters& bufferParameters)
: EffectState(bufferParameters),
m_tempBuf(bufferParameters.samplesPerBuffer()),
m_oldLowBoost(0),
@@ -81,21 +80,20 @@ ThreeBandBiquadEQEffectGroupState::ThreeBandBiquadEQEffectGroupState(
m_loFreqCorner(0),
m_highFreqCorner(0),
m_oldSampleRate(bufferParameters.sampleRate()) {
-
// Initialize the filters with default parameters
m_lowBoost = std::make_unique(
- bufferParameters.sampleRate() , kStartupLoFreq, kQBoost);
+ bufferParameters.sampleRate(), kStartupLoFreq, kQBoost);
m_midBoost = std::make_unique(
- bufferParameters.sampleRate() , kStartupMidFreq, kQBoost);
+ bufferParameters.sampleRate(), kStartupMidFreq, kQBoost);
m_highBoost = std::make_unique(
- bufferParameters.sampleRate() , kStartupHiFreq, kQBoost);
+ bufferParameters.sampleRate(), kStartupHiFreq, kQBoost);
m_lowCut = std::make_unique(
- bufferParameters.sampleRate() , kStartupLoFreq, kQKill);
+ bufferParameters.sampleRate(), kStartupLoFreq, kQKill);
m_midCut = std::make_unique(
- bufferParameters.sampleRate() , kStartupMidFreq, kQKill);
+ bufferParameters.sampleRate(), kStartupMidFreq, kQKill);
m_highCut = std::make_unique(
- bufferParameters.sampleRate() , kStartupHiFreq / 2, kQKillShelve);
+ bufferParameters.sampleRate(), kStartupHiFreq / 2, kQKillShelve);
}
ThreeBandBiquadEQEffectGroupState::~ThreeBandBiquadEQEffectGroupState() {
@@ -103,12 +101,10 @@ ThreeBandBiquadEQEffectGroupState::~ThreeBandBiquadEQEffectGroupState() {
void ThreeBandBiquadEQEffectGroupState::setFilters(
int sampleRate, double lowFreqCorner, double highFreqCorner) {
-
double lowCenter = getCenterFrequency(kMinimumFrequency, lowFreqCorner);
double midCenter = getCenterFrequency(lowFreqCorner, highFreqCorner);
double highCenter = getCenterFrequency(highFreqCorner, kMaximumFrequency);
-
m_lowBoost->setFrequencyCorners(
sampleRate, lowCenter, kQBoost, m_oldLowBoost);
m_midBoost->setFrequencyCorners(
@@ -121,32 +117,33 @@ void ThreeBandBiquadEQEffectGroupState::setFilters(
sampleRate, midCenter, kQKill, m_oldMidCut);
m_highCut->setFrequencyCorners(
sampleRate, highCenter / 2, kQKillShelve, m_oldHighCut);
-
}
-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() ||
@@ -155,10 +152,11 @@ void ThreeBandBiquadEQEffect::processChannel(
pState->m_loFreqCorner = m_pLoFreqCorner->get();
pState->m_highFreqCorner = m_pHiFreqCorner->get();
pState->m_oldSampleRate = bufferParameters.sampleRate();
- pState->setFilters(bufferParameters.sampleRate(), pState->m_loFreqCorner, pState->m_highFreqCorner);
+ pState->setFilters(bufferParameters.sampleRate(),
+ pState->m_loFreqCorner,
+ pState->m_highFreqCorner);
}
-
// Ramp to dry, when disabling, this will ramp from dry when enabling as well
double bqGainLow = 0;
double bqGainMid = 0;
@@ -214,9 +212,7 @@ void ThreeBandBiquadEQEffect::processChannel(
inBuffer.append(pState->m_tempBuf.data());
outBuffer.append(pOutput);
- }
- else
- {
+ } else {
inBuffer.append(pInput);
outBuffer.append(pOutput);
@@ -298,7 +294,6 @@ void ThreeBandBiquadEQEffect::processChannel(
pState->m_midBoost->pauseFilter();
}
-
if (bqGainMid < 0.0 || pState->m_oldMidCut < 0.0) {
if (bqGainMid != pState->m_oldMidCut) {
double midCenter = getCenterFrequency(
diff --git a/src/effects/builtin/threebandbiquadeqeffect.h b/src/effects/backends/builtin/threebandbiquadeqeffect.h
similarity index 70%
rename from src/effects/builtin/threebandbiquadeqeffect.h
rename to src/effects/backends/builtin/threebandbiquadeqeffect.h
index 308a3131d2cd..55e3e5e38144 100644
--- a/src/effects/builtin/threebandbiquadeqeffect.h
+++ b/src/effects/backends/builtin/threebandbiquadeqeffect.h
@@ -1,17 +1,16 @@
#pragma once
#include "control/controlproxy.h"
-#include "effects/effect.h"
-#include "effects/effectprocessor.h"
+#include "effects/backends/effectprocessor.h"
#include "engine/effects/engineeffect.h"
#include "engine/effects/engineeffectparameter.h"
#include "engine/filters/enginefilterbiquad1.h"
#include "util/class.h"
#include "util/defs.h"
-#include "util/sample.h"
-#include "util/types.h"
#include "util/memory.h"
+#include "util/sample.h"
#include "util/samplebuffer.h"
+#include "util/types.h"
class ThreeBandBiquadEQEffectGroupState final : public EffectState {
public:
@@ -43,21 +42,24 @@ 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) override;
+ void setFilters(int sampleRate, double lowFreqCorner, double highFreqCorner);
private:
ThreeBandBiquadEQEffect(const ThreeBandBiquadEQEffect&) = delete;
@@ -67,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/backends/builtin/tremoloeffect.cpp
similarity index 55%
rename from src/effects/builtin/tremoloeffect.cpp
rename to src/effects/backends/builtin/tremoloeffect.cpp
index 7d116e0b25b6..6faf62245e68 100644
--- a/src/effects/builtin/tremoloeffect.cpp
+++ b/src/effects/backends/builtin/tremoloeffect.cpp
@@ -1,4 +1,4 @@
-#include "effects/builtin/tremoloeffect.h"
+#include "effects/backends/builtin/tremoloeffect.h"
namespace {
// Used to avoid gain discontinuities when changing parameters too fast
@@ -19,134 +19,112 @@ EffectManifestPointer TremoloEffect::getManifest() {
pManifest->setAuthor("The Mixxx Team");
pManifest->setVersion("1.0");
pManifest->setDescription(QObject::tr(
- "Cycles the volume up and down"));
- pManifest->setMetaknobDefault(1.0);
+ "Cycles the volume up and down"));
EffectManifestParameterPointer depth = pManifest->addParameter();
depth->setId("depth");
depth->setName(QObject::tr("Depth"));
depth->setShortName(QObject::tr("Depth"));
depth->setDescription(QObject::tr(
- "How much the effect changes the volume"));
- depth->setControlHint(EffectManifestParameter::ControlHint::KNOB_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);
+ "How much the effect changes the volume"));
+ depth->setValueScaler(EffectManifestParameter::ValueScaler::Linear);
+ depth->setUnitsHint(EffectManifestParameter::UnitsHint::Unknown);
+ depth->setDefaultLinkType(EffectManifestParameter::LinkType::Linked);
+ depth->setRange(0, 1, 1);
EffectManifestParameterPointer rate = pManifest->addParameter();
rate->setId("rate");
rate->setName(QObject::tr("Rate"));
rate->setShortName(QObject::tr("Rate"));
rate->setDescription(QObject::tr(
- "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->setSemanticHint(EffectManifestParameter::SemanticHint::UNKNOWN);
- rate->setUnitsHint(EffectManifestParameter::UnitsHint::BEATS);
- rate->setDefault(1);
- rate->setMinimum(1.0/4);
- rate->setMaximum(8);
+ "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->setValueScaler(
+ EffectManifestParameter::ValueScaler::Logarithmic);
+ rate->setUnitsHint(EffectManifestParameter::UnitsHint::Beats);
+ rate->setRange(1.0 / 4, 1, 8);
EffectManifestParameterPointer width = pManifest->addParameter();
width->setId("width");
width->setName(QObject::tr("Width"));
width->setShortName(QObject::tr("Width"));
width->setDescription(QObject::tr(
- "Width of the volume peak\n"
- "10% - 90% of the effect period"));
- width->setControlHint(EffectManifestParameter::ControlHint::KNOB_LINEAR);
- width->setSemanticHint(EffectManifestParameter::SemanticHint::UNKNOWN);
- width->setUnitsHint(EffectManifestParameter::UnitsHint::UNKNOWN);
- width->setMinimum(0.1);
- width->setDefault(0.5);
- width->setMaximum(0.9);
+ "Width of the volume peak\n"
+ "10% - 90% of the effect period"));
+ width->setValueScaler(EffectManifestParameter::ValueScaler::Linear);
+ width->setUnitsHint(EffectManifestParameter::UnitsHint::Unknown);
+ width->setRange(0.1, 0.5, 0.9);
EffectManifestParameterPointer waveform = pManifest->addParameter();
waveform->setId("waveform");
waveform->setName(QObject::tr("Waveform"));
waveform->setShortName(QObject::tr("Waveform"));
waveform->setDescription(QObject::tr(
- "Shape of the volume modulation wave\n"
- "Fully left: Square wave\n"
- "Fully right: Sine wave"));
- waveform->setControlHint(
- EffectManifestParameter::ControlHint::KNOB_LOGARITHMIC);
- waveform->setSemanticHint(EffectManifestParameter::SemanticHint::UNKNOWN);
- waveform->setUnitsHint(EffectManifestParameter::UnitsHint::UNKNOWN);
- waveform->setMinimum(0.005);
- waveform->setDefault(0.5);
- waveform->setMaximum(1);
+ "Shape of the volume modulation wave\n"
+ "Fully left: Square wave\n"
+ "Fully right: Sine wave"));
+ waveform->setValueScaler(
+ EffectManifestParameter::ValueScaler::Logarithmic);
+ waveform->setUnitsHint(EffectManifestParameter::UnitsHint::Unknown);
+ waveform->setRange(0.005, 0.5, 1);
EffectManifestParameterPointer phase = pManifest->addParameter();
phase->setId("phase");
phase->setName(QObject::tr("Phase"));
phase->setShortName(QObject::tr("Phase"));
phase->setDescription(QObject::tr(
- "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->setSemanticHint(EffectManifestParameter::SemanticHint::UNKNOWN);
- phase->setUnitsHint(EffectManifestParameter::UnitsHint::UNKNOWN);
- phase->setDefault(0);
- phase->setMinimum(0);
- phase->setMaximum(1);
+ "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->setValueScaler(
+ EffectManifestParameter::ValueScaler::Linear);
+ phase->setUnitsHint(EffectManifestParameter::UnitsHint::Unknown);
+ phase->setRange(0, 0, 1);
EffectManifestParameterPointer quantize = pManifest->addParameter();
quantize->setId("quantize");
quantize->setName(QObject::tr("Quantize"));
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->setSemanticHint(EffectManifestParameter::SemanticHint::UNKNOWN);
- quantize->setUnitsHint(EffectManifestParameter::UnitsHint::UNKNOWN);
- quantize->setDefault(1);
- quantize->setMinimum(0);
- quantize->setMaximum(1);
+ "Round the Rate parameter to the nearest whole division of a beat."));
+ quantize->setValueScaler(
+ EffectManifestParameter::ValueScaler::Toggle);
+ quantize->setUnitsHint(EffectManifestParameter::UnitsHint::Unknown);
+ quantize->setRange(0, 1, 1);
EffectManifestParameterPointer triplet = pManifest->addParameter();
triplet->setId("triplet");
triplet->setName(QObject::tr("Triplets"));
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->setSemanticHint(EffectManifestParameter::SemanticHint::UNKNOWN);
- triplet->setUnitsHint(EffectManifestParameter::UnitsHint::UNKNOWN);
- triplet->setDefault(0);
- triplet->setMinimum(0);
- triplet->setMaximum(1);
+ "When the Quantize parameter is enabled, divide the effect period by 3."));
+ triplet->setValueScaler(
+ EffectManifestParameter::ValueScaler::Toggle);
+ triplet->setUnitsHint(EffectManifestParameter::UnitsHint::Unknown);
+ 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();
@@ -156,14 +134,10 @@ void TremoloEffect::processChannel(const ChannelHandle& handle,
const GroupFeatureState& gf = groupFeatures;
- bool quantizeEnabling = !pState->quantizeEnabled
- && m_pQuantizeParameter->toBool();
- bool tripletDisabling = pState->tripletEnabled
- && !m_pTripletParameter->toBool();
+ bool quantizeEnabling = !pState->quantizeEnabled && m_pQuantizeParameter->toBool();
+ bool tripletDisabling = pState->tripletEnabled && !m_pTripletParameter->toBool();
- if (enableState == EffectEnableState::Enabling
- || quantizeEnabling
- || tripletDisabling) {
+ if (enableState == EffectEnableState::Enabling || quantizeEnabling || tripletDisabling) {
if (gf.has_beat_length_sec && gf.has_beat_fraction) {
currentFrame = static_cast(gf.beat_fraction *
gf.beat_length_sec * bufferParameters.sampleRate());
@@ -216,9 +190,10 @@ void TremoloEffect::processChannel(const ChannelHandle& handle,
// This function gives the gain to apply for position in [0 1]
// Plot the function to get a grasp :
// From a sine to a square wave depending on the smooth parameter
- double gainTarget = 1.0 - (depth / 2.0)
- + (atan(sin(2.0 * M_PI * position) / smooth) / (2 * atan(1 / smooth)))
- * depth;
+ double gainTarget = 1.0 - (depth / 2.0) +
+ (atan(sin(2.0 * M_PI * position) / smooth) /
+ (2 * atan(1 / smooth))) *
+ depth;
if (gainTarget > gain + kMaxGainIncrement) {
gain += kMaxGainIncrement;
diff --git a/src/effects/backends/builtin/tremoloeffect.h b/src/effects/backends/builtin/tremoloeffect.h
new file mode 100644
index 000000000000..fa185a4022a6
--- /dev/null
+++ b/src/effects/backends/builtin/tremoloeffect.h
@@ -0,0 +1,52 @@
+#pragma once
+#include "effects/backends/effectprocessor.h"
+#include "engine/effects/engineeffect.h"
+#include "engine/effects/engineeffectparameter.h"
+#include "util/class.h"
+#include "util/defs.h"
+#include "util/sample.h"
+#include "util/types.h"
+
+class TremoloState : public EffectState {
+ public:
+ TremoloState(const mixxx::EngineParameters& bufferParameters)
+ : EffectState(bufferParameters){};
+ double gain;
+ unsigned int currentFrame;
+ bool quantizeEnabled = false;
+ bool tripletEnabled = false;
+};
+
+class TremoloEffect : public EffectProcessorImpl {
+ public:
+ TremoloEffect() = default;
+
+ static QString getId();
+ static EffectManifestPointer getManifest();
+
+ 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();
+ }
+
+ 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/builtin/whitenoiseeffect.cpp b/src/effects/backends/builtin/whitenoiseeffect.cpp
similarity index 62%
rename from src/effects/builtin/whitenoiseeffect.cpp
rename to src/effects/backends/builtin/whitenoiseeffect.cpp
index 0a9409142b40..818f77c1bdff 100644
--- a/src/effects/builtin/whitenoiseeffect.cpp
+++ b/src/effects/backends/builtin/whitenoiseeffect.cpp
@@ -1,4 +1,4 @@
-#include "effects/builtin/whitenoiseeffect.h"
+#include "effects/backends/builtin/whitenoiseeffect.h"
#include "util/rampingvalue.h"
@@ -22,40 +22,33 @@ EffectManifestPointer WhiteNoiseEffect::getManifest() {
pManifest->setEffectRampsFromDry(true);
// This is dry/wet parameter
- EffectManifestParameterPointer intensity = pManifest->addParameter();
- intensity->setId(dryWetParameterId);
- intensity->setName(QObject::tr("Dry/Wet"));
- intensity->setDescription(QObject::tr("Crossfade the noise with the dry signal"));
- intensity->setControlHint(EffectManifestParameter::ControlHint::KNOB_LOGARITHMIC);
- intensity->setSemanticHint(EffectManifestParameter::SemanticHint::UNKNOWN);
- intensity->setUnitsHint(EffectManifestParameter::UnitsHint::UNKNOWN);
- intensity->setDefaultLinkType(EffectManifestParameter::LinkType::LINKED);
- intensity->setMinimum(0);
- intensity->setDefault(0);
- intensity->setMaximum(1);
+ EffectManifestParameterPointer drywet = pManifest->addParameter();
+ drywet->setId(dryWetParameterId);
+ drywet->setName(QObject::tr("Dry/Wet"));
+ drywet->setDescription(QObject::tr("Crossfade the noise with the dry signal"));
+ drywet->setValueScaler(EffectManifestParameter::ValueScaler::Logarithmic);
+ drywet->setUnitsHint(EffectManifestParameter::UnitsHint::Unknown);
+ drywet->setDefaultLinkType(EffectManifestParameter::LinkType::Linked);
+ drywet->setRange(0, 1, 1);
return pManifest;
}
-WhiteNoiseEffect::WhiteNoiseEffect(EngineEffect* pEffect)
- : m_pDryWetParameter(pEffect->getParameterById(dryWetParameterId)) {
-}
-
-WhiteNoiseEffect::~WhiteNoiseEffect() {
+void WhiteNoiseEffect::loadEngineEffectParameters(
+ const QMap& parameters) {
+ m_pDryWetParameter = parameters.value(dryWetParameterId);
}
void WhiteNoiseEffect::processChannel(
- const ChannelHandle& handle,
- WhiteNoiseGroupState* pGroupState,
+ WhiteNoiseGroupState* pState,
const CSAMPLE* pInput,
CSAMPLE* pOutput,
const mixxx::EngineParameters& bufferParameters,
const EffectEnableState enableState,
const GroupFeatureState& groupFeatures) {
- Q_UNUSED(handle);
Q_UNUSED(groupFeatures);
- WhiteNoiseGroupState& gs = *pGroupState;
+ WhiteNoiseGroupState& gs = *pState;
CSAMPLE drywet = static_cast(m_pDryWetParameter->value());
RampingValue drywet_ramping_value(
diff --git a/src/effects/builtin/whitenoiseeffect.h b/src/effects/backends/builtin/whitenoiseeffect.h
similarity index 76%
rename from src/effects/builtin/whitenoiseeffect.h
rename to src/effects/backends/builtin/whitenoiseeffect.h
index 437f7ffa42fe..53cb24431283 100644
--- a/src/effects/builtin/whitenoiseeffect.h
+++ b/src/effects/backends/builtin/whitenoiseeffect.h
@@ -2,7 +2,7 @@
#include
-#include "effects/effectprocessor.h"
+#include "effects/backends/effectprocessor.h"
#include "engine/effects/engineeffect.h"
#include "engine/effects/engineeffectparameter.h"
#include "engine/filters/enginefilterpansingle.h"
@@ -29,23 +29,24 @@ class WhiteNoiseGroupState final : public EffectState {
class WhiteNoiseEffect : public EffectProcessorImpl {
public:
- WhiteNoiseEffect(EngineEffect* pEffect);
- virtual ~WhiteNoiseEffect();
+ WhiteNoiseEffect() = default;
static QString getId();
static EffectManifestPointer getManifest();
- // See effectprocessor.h
- void processChannel(const ChannelHandle& handle,
+ void processChannel(
WhiteNoiseGroupState* pState,
const CSAMPLE* pInput,
CSAMPLE* pOutput,
const mixxx::EngineParameters& bufferParameters,
const EffectEnableState enableState,
- const GroupFeatureState& groupFeatures);
+ const GroupFeatureState& groupFeatures) override;
+
+ void loadEngineEffectParameters(
+ const QMap& parameters) override;
private:
- EngineEffectParameter* m_pDryWetParameter;
+ EngineEffectParameterPointer m_pDryWetParameter;
DISALLOW_COPY_AND_ASSIGN(WhiteNoiseEffect);
};
diff --git a/src/effects/backends/effectmanifest.cpp b/src/effects/backends/effectmanifest.cpp
new file mode 100644
index 000000000000..993a2205a87f
--- /dev/null
+++ b/src/effects/backends/effectmanifest.cpp
@@ -0,0 +1,29 @@
+#include "effects/backends/effectmanifest.h"
+
+QDebug operator<<(QDebug dbg, const EffectManifest& manifest) {
+ return dbg.maybeSpace() << QString("EffectManifest(%1)").arg(manifest.id());
+}
+
+bool EffectManifest::hasMetaKnobLinking() const {
+ for (const auto& pParameterManifest : m_parameters) {
+ if (pParameterManifest->defaultLinkType() !=
+ EffectManifestParameter::LinkType::None) {
+ return true;
+ }
+ }
+ return false;
+}
+
+bool EffectManifest::sortLexigraphically(
+ EffectManifestPointer pManifest1, EffectManifestPointer pManifest2) {
+ // Sort built-in effects first before external plugins
+ int backendNameComparision = static_cast(pManifest1->backendType()) -
+ static_cast(pManifest2->backendType());
+ if (backendNameComparision != 0) {
+ return backendNameComparision < 0;
+ }
+
+ int displayNameComparision = QString::localeAwareCompare(
+ pManifest1->displayName(), pManifest2->displayName());
+ return displayNameComparision < 0;
+}
diff --git a/src/effects/effectmanifest.h b/src/effects/backends/effectmanifest.h
similarity index 58%
rename from src/effects/effectmanifest.h
rename to src/effects/backends/effectmanifest.h
index a09a57351b33..d74f2b5c1b6f 100644
--- a/src/effects/effectmanifest.h
+++ b/src/effects/backends/effectmanifest.h
@@ -1,36 +1,47 @@
#pragma once
#include
+#include
#include
#include
-#include
-#include "effects/effectmanifestparameter.h"
+#include "effects/backends/effectmanifestparameter.h"
+#include "effects/backends/effectsbackend.h"
#include "effects/defs.h"
-// An EffectManifest is a full description of the metadata associated with an
-// effect (e.g. name, author, version, description, etc.) and the parameters of
-// the effect that are intended to be exposed to the rest of Mixxx for user or
-// script control.
-//
-// EffectManifest is composed purely of simple data types, and when an
-// 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 {
+/// An EffectManifest is a description of the metadata associated with an effect
+/// (ID, display name, author, description) and all the parameters of the effect.
+/// The pair of the ID string and EffectBackendType uniquely identifies an
+/// effect. EffectManifests are used by EffectBackends to create EffectProcessors
+/// which implement the DSP logic of the effect. The name string of effect
+/// parameters in the manifest is used to link EngineEffectParameters
+/// with member variables used in the DSP logic of the EffectProcessorImpl.
+///
+/// EffectManifest is composed purely of simple data types, and when an
+/// 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.
+class EffectManifest {
public:
EffectManifest()
- : m_backendType(EffectBackendType::Unknown),
- m_isMixingEQ(false),
- m_isMasterEQ(false),
- m_effectRampsFromDry(false),
- m_bAddDryToWet(false),
- m_metaknobDefault(0.5) {
+ : m_backendType(EffectBackendType::Unknown),
+ m_isMixingEQ(false),
+ m_isMasterEQ(false),
+ m_effectRampsFromDry(false),
+ m_bAddDryToWet(false),
+ m_metaknobDefault(0.0) {
}
+ /// Hack to store unique IDs in QComboBox models
+ const QString uniqueId() const {
+ return m_id + " " + EffectsBackend::backendTypeToString(m_backendType);
+ }
+
+ /// 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;
}
@@ -101,6 +112,8 @@ class EffectManifest final {
m_isMasterEQ = value;
}
+ bool hasMetaKnobLinking() const;
+
void setDescription(const QString& description) {
m_description = description;
}
@@ -112,6 +125,7 @@ class EffectManifest final {
EffectManifestParameterPointer addParameter() {
EffectManifestParameterPointer effectManifestParameterPointer(
new EffectManifestParameter());
+ effectManifestParameterPointer->setIndex(m_parameters.size());
m_parameters.append(effectManifestParameterPointer);
return effectManifestParameterPointer;
}
@@ -141,39 +155,20 @@ class EffectManifest final {
m_metaknobDefault = metaknobDefault;
}
- QString backendName() {
- switch (m_backendType) {
- case EffectBackendType::BuiltIn:
- return QString("Built-in");
- case EffectBackendType::LV2:
- return QString("LV2");
- default:
- return QString("Unknown");
- }
+ bool operator==(const EffectManifest& other) const {
+ return other.id() == m_id && other.backendType() == m_backendType;
}
- // Use this when showing the string in the GUI
- QString translatedBackendName() {
- switch (m_backendType) {
- case EffectBackendType::BuiltIn:
- //: Used for effects that are built into Mixxx
- return QObject::tr("Built-in");
- case EffectBackendType::LV2:
- return QString("LV2");
- default:
- return QString();
- }
- }
- static EffectBackendType backendTypeFromString(const QString& name) {
- if (name == "Built-in") {
- return EffectBackendType::BuiltIn;
- } else if (name == "LV2") {
- return EffectBackendType::LV2;
- } else {
- return EffectBackendType::Unknown;
+ bool operator<(const EffectManifest& other) const {
+ if (other.backendType() != m_backendType) {
+ return other.backendType() < m_backendType;
}
+ return other.id() < m_id;
}
+ static bool sortLexigraphically(
+ EffectManifestPointer pManifest1, EffectManifestPointer pManifest2);
+
private:
QString debugString() const {
return QString("EffectManifest(%1)").arg(m_id);
@@ -186,7 +181,7 @@ class EffectManifest final {
QString m_author;
QString m_version;
QString m_description;
- // This helps us at DlgPrefEQ's basic selection of Equalizers
+ /// This helps us at DlgPrefEQ's basic selection of Equalizers
bool m_isMixingEQ;
bool m_isMasterEQ;
QList m_parameters;
diff --git a/src/effects/effectmanifestparameter.cpp b/src/effects/backends/effectmanifestparameter.cpp
similarity index 75%
rename from src/effects/effectmanifestparameter.cpp
rename to src/effects/backends/effectmanifestparameter.cpp
index 0094635c1489..9e3ba418a579 100644
--- a/src/effects/effectmanifestparameter.cpp
+++ b/src/effects/backends/effectmanifestparameter.cpp
@@ -1,4 +1,4 @@
-#include "effects/effectmanifestparameter.h"
+#include "effects/backends/effectmanifestparameter.h"
QDebug operator<<(QDebug dbg, const EffectManifestParameter& parameter) {
return dbg.maybeSpace() << QString("EffectManifestParameter(%1)").arg(parameter.id());
diff --git a/src/effects/backends/effectmanifestparameter.h b/src/effects/backends/effectmanifestparameter.h
new file mode 100644
index 000000000000..a744058acfcb
--- /dev/null
+++ b/src/effects/backends/effectmanifestparameter.h
@@ -0,0 +1,282 @@
+#pragma once
+
+#include
+#include
+#include
+#include
+
+#include "effects/defs.h"
+#include "util/assert.h"
+
+class EffectManifestParameter;
+typedef QSharedPointer EffectManifestParameterPointer;
+
+class EffectManifestParameter {
+ public:
+ enum class ParameterType : int {
+ Knob,
+ Button,
+ NumTypes,
+ };
+
+ enum class ValueScaler : int {
+ Unknown = 0,
+ Linear,
+ LinearInverse,
+ Logarithmic,
+ LogarithmicInverse,
+ /// A step rotary, steps given by m_steps are arranged with equal
+ /// distance on scale
+ Integral,
+ /// For button and enum controls, not accessible from many controllers,
+ /// no linking to meta knob
+ Toggle,
+ };
+
+ enum class UnitsHint : int {
+ Unknown = 0,
+ Time,
+ Hertz,
+ /// Fraction of the Sample Rate
+ SampleRate,
+ /// Multiples of a Beat
+ Beats,
+ };
+
+ enum class LinkType : int {
+ /// Not controlled by the meta knob
+ None = 0,
+ /// Controlled by the meta knob as it is
+ Linked,
+ /// Controlled by the left side of the meta knob
+ LinkedLeft,
+ /// Controlled by the right side of the meta knob
+ LinkedRight,
+ /// Controlled by both sides of the meta knob
+ LinkedLeftRight,
+ NumLinkTypes,
+ };
+
+ static QString LinkTypeToString(LinkType type) {
+ switch (type) {
+ case LinkType::Linked:
+ return QLatin1String("LINKED");
+ case LinkType::LinkedLeft:
+ return QLatin1String("LINKED_LEFT");
+ case LinkType::LinkedRight:
+ return QLatin1String("LINKED_RIGHT");
+ case LinkType::LinkedLeftRight:
+ return QLatin1String("LINKED_LEFT_RIGHT");
+ default:
+ return QLatin1String("NONE");
+ }
+ }
+
+ static LinkType LinkTypeFromString(const QString& string) {
+ if (string == QLatin1String("LINKED")) {
+ return LinkType::Linked;
+ } else if (string == QLatin1String("LINKED_LEFT")) {
+ return LinkType::LinkedLeft;
+ } else if (string == QLatin1String("LINKED_RIGHT")) {
+ return LinkType::LinkedRight;
+ } else if (string == QLatin1String("LINKED_LEFT_RIGHT")) {
+ return LinkType::LinkedLeftRight;
+ } else {
+ return LinkType::None;
+ }
+ }
+
+ enum class LinkInversion : int {
+ NotInverted = 0,
+ Inverted = 1
+ };
+
+ EffectManifestParameter()
+ : m_valueScaler(ValueScaler::Unknown),
+ m_unitsHint(UnitsHint::Unknown),
+ m_defaultLinkType(LinkType::None),
+ m_defaultLinkInversion(LinkInversion::NotInverted),
+ m_neutralPointOnScale(0.0),
+ m_default(0),
+ m_minimum(0),
+ m_maximum(1.0) {
+ }
+
+ ~EffectManifestParameter() {
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ // Parameter Information
+ ////////////////////////////////////////////////////////////////////////////////
+
+ const QString& id() const {
+ return m_id;
+ }
+ void setId(const QString& id) {
+ m_id = id;
+ }
+
+ const QString& name() const {
+ return m_name;
+ }
+ void setName(const QString& name) {
+ m_name = name;
+ }
+
+ const QString& shortName() const {
+ return m_shortName;
+ }
+ void setShortName(const QString& shortName) {
+ m_shortName = shortName;
+ }
+
+ const QString& description() const {
+ return m_description;
+ }
+ void setDescription(const QString& description) {
+ m_description = description;
+ }
+
+ int index() const {
+ return m_iIndex;
+ }
+ void setIndex(int index) {
+ m_iIndex = index;
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ // Usage hints
+ ////////////////////////////////////////////////////////////////////////////////
+
+ const ParameterType& parameterType() const {
+ return m_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);
+ }
+ }
+
+ UnitsHint unitsHint() const {
+ return m_unitsHint;
+ }
+ void setUnitsHint(UnitsHint unitsHint) {
+ m_unitsHint = unitsHint;
+ }
+
+ LinkType defaultLinkType() const {
+ return m_defaultLinkType;
+ }
+ void setDefaultLinkType(const LinkType linkType) {
+ m_defaultLinkType = linkType;
+ }
+
+ LinkInversion defaultLinkInversion() const {
+ return m_defaultLinkInversion;
+ }
+ void setDefaultLinkInversion(const LinkInversion linkInversion) {
+ m_defaultLinkInversion = linkInversion;
+ }
+
+ /// Neutral Point On Scale is the parameter in the range 0 .. 1 on the knob that
+ /// is adopted as neutral when controlled by the meta knob.
+ /// This is allows to link the meta knob in a way that two effects are
+ /// cranked in simultaneous, or in case of a split filter like meta knob,
+ /// both effects are neutral at meta knob center.
+ /// 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.
+ double neutralPointOnScale() const {
+ return m_neutralPointOnScale;
+ }
+ void setNeutralPointOnScale(double neutralPoint) {
+ m_neutralPointOnScale = neutralPoint;
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ // Value Settings
+ ////////////////////////////////////////////////////////////////////////////////
+
+ const double& getDefault() const {
+ return m_default;
+ }
+
+ const double& getMinimum() const {
+ return m_minimum;
+ }
+
+ const double& getMaximum() const {
+ return m_maximum;
+ }
+
+ /// Minimum, default, and maximum are set together in one function so their
+ /// validity only needs to be checked once.
+ void setRange(const double& minimum, const double& defaultValue, const double& maximum) {
+ VERIFY_OR_DEBUG_ASSERT(minimum <= defaultValue && defaultValue <= maximum) {
+ qWarning() << "EffectManifestParameter" << m_name
+ << "tried to set invalid parameter range:"
+ << "minimum" << minimum
+ << "default" << defaultValue
+ << "maximum" << maximum;
+ return;
+ }
+ m_minimum = minimum;
+ m_default = defaultValue;
+ m_maximum = maximum;
+ }
+
+ void appendStep(const QPair& step) {
+ m_steps.append(step);
+ }
+ const QList >& getSteps() const {
+ return m_steps;
+ }
+
+ private:
+ void setParameterType(const ParameterType parameterType) {
+ m_parameterType = parameterType;
+ }
+
+ QString debugString() const {
+ return QString("EffectManifestParameter(%1)").arg(m_id);
+ }
+
+ QString m_id;
+ QString m_name;
+ QString m_shortName;
+ QString m_description;
+ int m_iIndex;
+
+ ParameterType m_parameterType;
+ ValueScaler m_valueScaler;
+ UnitsHint m_unitsHint;
+ LinkType m_defaultLinkType;
+ LinkInversion m_defaultLinkInversion;
+ double m_neutralPointOnScale;
+
+ double m_default;
+ double m_minimum;
+ double m_maximum;
+
+ /// Used to describe steps of
+ /// CONTROL_INTEGRAL and CONTROL_TOGGLE
+ /// effect parameters
+ /// Each pair has the following form:
+ /// name - value
+ QList > m_steps;
+};
+
+QDebug operator<<(QDebug dbg, const EffectManifestParameter& parameter);
+
+typedef EffectManifestParameter::ParameterType EffectParameterType;
+
+inline uint qHash(const EffectParameterType& parameterType) {
+ return static_cast(parameterType);
+}
diff --git a/src/effects/backends/effectprocessor.h b/src/effects/backends/effectprocessor.h
new file mode 100644
index 000000000000..f86323daa23d
--- /dev/null
+++ b/src/effects/backends/effectprocessor.h
@@ -0,0 +1,301 @@
+#pragma once
+
+#include
+#include
+#include
+#include
+
+#include "effects/defs.h"
+#include "engine/channelhandle.h"
+#include "engine/effects/groupfeaturestate.h"
+#include "engine/effects/message.h"
+#include "engine/engine.h"
+#include "util/types.h"
+
+/// Effects are implemented as two separate classes, an EffectState subclass and
+/// an EffectProcessorImpl subclass. Separating state from the DSP code allows
+/// memory allocation and deletion on the heap, which is slow, to be done on the
+/// main thread instead of potentially blocking the audio engine callback thread
+/// and causing audible glitches.
+///
+/// The base EffectState class does nothing on its own; each effect is responsible
+/// for subclassing it with whatever state it needs to maintain between cycles of
+/// the audio thread. The base EffectProcessorImpl class handles the management of
+/// EffectStates. EffectProcessorImpl subclasses only need to be concerned with
+/// implementing the signal processing logic and providing metadata for describing
+/// the effect and its parameters with an EffectManifest.
+///
+/// EffectProcessorImpl interfaces with the main thread through the EffectProcessor
+/// abstract base class. EngineEffect passes state changes between the
+/// ControlObjects in EffectSlot on the main thread and EffectProcessor in the audio
+/// thread via EffectsMessenger.
+///
+/// Each EffectState instance tracks the state for one combination of input signal
+/// and output signal. Input signals can be any EngineChannel, but output channels
+/// are hardcoded in EngineMaster as the postfader processing for the main mix
+/// and prefader processing for headphones. There can be many EffectStates for one
+/// EffectProcessorImpl, allowing a single EffectProcessorImpl to maintain
+/// independent state for each combination of input and output signal. This allows
+/// each EffectProcessor to handle an arbitrary number of input signals. Tracking
+/// state separately for the main mix and the headphone output allows effects to be
+/// processed postfader for the main mix and prefader for the headphone output in
+/// parallel so there is no need for a prefader/postfader toggle switch.
+///
+/// EffectStates allocated on the main thread are passed as pointers to the
+/// EffectProcessorImpl in the audio callback thread via the EffectsMessenger.
+/// EffectStates are allocated and deallocated when a routing switch for an
+/// EffectChain is toggled and when a new EngineEffect is loaded into an EffectSlot.
+/// This allows for scaling up to an arbitrary number of input signals
+/// without wasting a lot of memory. (EffectStates could be (de)allocated when toggling
+/// the enable switches for EffectSlots as well, but the memory savings would be
+/// relatively small compared to the additional code complexity.)
+class EffectState {
+ public:
+ EffectState(const mixxx::EngineParameters& bufferParameters) {
+ // Subclasses should call engineParametersChanged here.
+ Q_UNUSED(bufferParameters);
+ };
+ virtual ~EffectState(){};
+};
+
+/// EffectProcessor is an abstract base class for interfacing with an EffectSlot
+/// in the main thread without needing to specify a specific EffectState subclass
+/// for the template in EffectProcessorImpl.
+class EffectProcessor {
+ public:
+ virtual ~EffectProcessor() {
+ }
+
+ /// These methods are called from the main thread
+ virtual void initialize(
+ const QSet& activeInputChannels,
+ const QSet& registeredOutputChannels,
+ const mixxx::EngineParameters& bufferParameters) = 0;
+ virtual void loadEngineEffectParameters(
+ const QMap& parameters) = 0;
+ virtual EffectState* createState(const mixxx::EngineParameters& bufferParameters) = 0;
+ virtual void deleteStatesForInputChannel(const ChannelHandle* inputChannel) = 0;
+
+ // Called from the audio thread
+ virtual bool loadStatesForInputChannel(const ChannelHandle* inputChannel,
+ const EffectStatesMap* pStatesMap) = 0;
+
+ /// Called from the audio thread
+ /// This method takes a buffer of audio samples as pInput, processes the buffer
+ /// according to effect-specific logic, and outputs it to the buffer pOutput.
+ /// Both pInput and pOutput are represented as stereo interleaved samples for now,
+ /// but effects should not be written assuming this will remain true. The properties
+ /// of the buffer necessary for determining how to process it (frames per
+ /// buffer, number of channels, and sample rate) are available on the
+ /// mixxx::EngineParameters argument. The provided channel handles allow
+ /// EffectProcessorImpl::process to fetch the appropriate EffectState and
+ /// pass it on to EffectProcessorImpl::processChannel, allowing one
+ /// EffectProcessor instance to process multiple signals simultaneously.
+ virtual void process(const ChannelHandle& inputHandle,
+ const ChannelHandle& outputHandle,
+ const CSAMPLE* pInput,
+ CSAMPLE* pOutput,
+ const mixxx::EngineParameters& bufferParameters,
+ const EffectEnableState enableState,
+ const GroupFeatureState& groupFeatures) = 0;
+};
+
+/// EffectProcessorImpl manages a separate EffectState for every combination of
+/// input channel to output channel. This allows for processing effects in
+/// parallel for PFL and post-fader for the master output.
+/// EffectSpecificState must be a subclass of EffectState.
+template
+class EffectProcessorImpl : public EffectProcessor {
+ public:
+ EffectProcessorImpl() {
+ }
+ /// Subclasses should not implement their own destructor. All state should
+ /// be stored in the EffectState subclass, not the EffectProcessorImpl subclass.
+ ~EffectProcessorImpl() {
+ if (kEffectDebugOutput) {
+ qDebug() << "~EffectProcessorImpl" << this;
+ }
+ int inputChannelHandleNumber = 0;
+ for (ChannelHandleMap& outputsMap : m_channelStateMatrix) {
+ int outputChannelHandleNumber = 0;
+ for (EffectSpecificState* pState : outputsMap) {
+ VERIFY_OR_DEBUG_ASSERT(pState != nullptr) {
+ continue;
+ }
+ if (kEffectDebugOutput) {
+ qDebug() << "~EffectProcessorImpl deleting EffectState" << pState
+ << "for input ChannelHandle(" << inputChannelHandleNumber << ")"
+ << "and output ChannelHandle(" << outputChannelHandleNumber << ")";
+ }
+ delete pState;
+ outputChannelHandleNumber++;
+ }
+ outputsMap.clear();
+ inputChannelHandleNumber++;
+ }
+ m_channelStateMatrix.clear();
+ };
+
+ /// NOTE: Subclasses for Built-In effects must implement the following static methods for
+ /// BuiltInBackend to work:
+ /// static QString getId();
+ /// static EffectManifestPointer getManifest();
+
+ /// This is the only non-static method that subclasses need to implement.
+ virtual void processChannel(EffectSpecificState* channelState,
+ const CSAMPLE* pInput,
+ CSAMPLE* pOutput,
+ const mixxx::EngineParameters& bufferParameters,
+ const EffectEnableState enableState,
+ const GroupFeatureState& groupFeatures) = 0;
+
+ void process(const ChannelHandle& inputHandle,
+ const ChannelHandle& outputHandle,
+ const CSAMPLE* pInput,
+ CSAMPLE* pOutput,
+ const mixxx::EngineParameters& bufferParameters,
+ const EffectEnableState enableState,
+ const GroupFeatureState& groupFeatures) final {
+ EffectSpecificState* pState = m_channelStateMatrix[inputHandle][outputHandle];
+ VERIFY_OR_DEBUG_ASSERT(pState != nullptr) {
+ if (kEffectDebugOutput) {
+ qWarning() << "EffectProcessorImpl::process could not retrieve"
+ "EffectState for input"
+ << inputHandle
+ << "and output" << outputHandle
+ << "EffectState should have been preallocated in the"
+ "main thread.";
+ }
+ pState = createSpecificState(bufferParameters);
+ m_channelStateMatrix[inputHandle][outputHandle] = pState;
+ }
+ processChannel(pState, pInput, pOutput, bufferParameters, enableState, groupFeatures);
+ }
+
+ void initialize(const QSet& activeInputChannels,
+ 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 :
+ std::as_const(m_registeredOutputChannels)) {
+ outputChannelMap.insert(outputChannel.handle(),
+ createSpecificState(bufferParameters));
+ if (kEffectDebugOutput) {
+ qDebug() << this << "EffectProcessorImpl::initialize "
+ "registering output"
+ << outputChannel << outputChannelMap[outputChannel.handle()];
+ }
+ }
+ m_channelStateMatrix.insert(inputChannel.handle(), outputChannelMap);
+ }
+ };
+
+ EffectState* createState(const mixxx::EngineParameters& bufferParameters) final {
+ return createSpecificState(bufferParameters);
+ };
+
+ bool loadStatesForInputChannel(const ChannelHandle* inputChannel,
+ const EffectStatesMap* pStatesMap) final {
+ if (kEffectDebugOutput) {
+ qDebug() << "EffectProcessorImpl::loadStatesForInputChannel" << this
+ << "input" << *inputChannel;
+ }
+
+ // NOTE: ChannelHandleMap is like a map in that it associates an
+ // object with a ChannelHandle key, but it is 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 (EffectSpecificState* pState : effectSpecificStatesMap) {
+ VERIFY_OR_DEBUG_ASSERT(pState == nullptr) {
+ delete pState;
+ }
+ }
+
+ QSet receivedOutputChannels = m_registeredOutputChannels;
+ for (const ChannelHandleAndGroup& outputChannel :
+ std::as_const(m_registeredOutputChannels)) {
+ if (kEffectDebugOutput) {
+ qDebug() << "EffectProcessorImpl::loadStatesForInputChannel"
+ << this << "output" << outputChannel;
+ }
+
+ auto pState = dynamic_cast(
+ pStatesMap->at(outputChannel.handle()));
+ VERIFY_OR_DEBUG_ASSERT(pState != nullptr) {
+ 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;
+ };
+
+ /// Called from main thread for garbage collection after an input channel is disabled
+ void deleteStatesForInputChannel(const ChannelHandle* inputChannel) final {
+ if (kEffectDebugOutput) {
+ qDebug() << "EffectProcessorImpl::deleteStatesForInputChannel"
+ << this << *inputChannel;
+ }
+
+ // NOTE: ChannelHandleMap is like a map in that it associates an
+ // object with a ChannelHandle key, but it is 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 (EffectSpecificState* pState : stateMap) {
+ VERIFY_OR_DEBUG_ASSERT(pState != nullptr) {
+ continue;
+ }
+ if (kEffectDebugOutput) {
+ qDebug() << "EffectProcessorImpl::deleteStatesForInputChannel"
+ << this << "deleting state" << pState;
+ }
+ delete pState;
+ }
+ stateMap.clear();
+ };
+
+ 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;
+ }
+ return pState;
+ };
+
+ private:
+ QSet m_registeredOutputChannels;
+ ChannelHandleMap> m_channelStateMatrix;
+};
diff --git a/src/effects/backends/effectsbackend.cpp b/src/effects/backends/effectsbackend.cpp
new file mode 100644
index 000000000000..d56a8d2812c3
--- /dev/null
+++ b/src/effects/backends/effectsbackend.cpp
@@ -0,0 +1,39 @@
+#include "effects/backends/effectsbackend.h"
+
+namespace {
+const QString backendTypeNameLV2 = QStringLiteral("LV2");
+// QString::tr requires const char[] rather than QString
+constexpr char backendTypeNameBuiltIn[] = "Built-In";
+constexpr char backendTypeNameUnknown[] = "Unknown";
+} // anonymous namespace
+
+EffectBackendType EffectsBackend::backendTypeFromString(const QString& typeName) {
+ if (typeName == backendTypeNameLV2) {
+ return EffectBackendType::LV2;
+ } else {
+ return EffectBackendType::BuiltIn;
+ }
+}
+
+QString EffectsBackend::backendTypeToString(EffectBackendType backendType) {
+ switch (backendType) {
+ case EffectBackendType::BuiltIn:
+ return backendTypeNameBuiltIn;
+ case EffectBackendType::LV2:
+ return backendTypeNameLV2;
+ default:
+ return backendTypeNameUnknown;
+ }
+}
+
+QString EffectsBackend::translatedBackendName(EffectBackendType backendType) {
+ switch (backendType) {
+ case EffectBackendType::BuiltIn:
+ //: Used for effects that are built into Mixxx
+ return QObject::tr(backendTypeNameBuiltIn);
+ case EffectBackendType::LV2:
+ return backendTypeNameLV2;
+ default:
+ return QObject::tr(backendTypeNameUnknown);
+ }
+}
diff --git a/src/effects/backends/effectsbackend.h b/src/effects/backends/effectsbackend.h
new file mode 100644
index 000000000000..00b99285207d
--- /dev/null
+++ b/src/effects/backends/effectsbackend.h
@@ -0,0 +1,41 @@
+#pragma once
+
+#include
+#include
+#include
+#include
+
+#include "effects/defs.h"
+
+class EffectProcessor;
+
+/// EffectsBackend is an abstract base class that enumerates available effects
+/// which are identified by EffectManifests. EffectsBackends create an
+/// EffectProcessor when provided with an EffectManifest indicating which
+/// specific EffectProcessor type to create. EffectProcessors implement the DSP
+/// logic specific to each effect.
+///
+/// Currently the implemented EffectsBackend subclasses are for the effects
+/// built into Mixxx and LV2 plugins. Other plugin types such as VSTs could be
+/// added in the future by creating new subclasses of EffectsBackend,
+/// EffectManifest, EffectState, and EffectProcessorImpl.
+class EffectsBackend {
+ public:
+ virtual ~EffectsBackend(){};
+
+ virtual EffectBackendType getType() const = 0;
+
+ /// 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 const QList getManifests() const = 0;
+ virtual bool canInstantiateEffect(const QString& effectId) const = 0;
+
+ virtual std::unique_ptr createProcessor(
+ const EffectManifestPointer pManifest) const = 0;
+
+ static EffectBackendType backendTypeFromString(const QString& typeName);
+ static QString backendTypeToString(EffectBackendType backendType);
+ /// Use this when showing the string in the GUI
+ static QString translatedBackendName(EffectBackendType backendType);
+};
diff --git a/src/effects/backends/effectsbackendmanager.cpp b/src/effects/backends/effectsbackendmanager.cpp
new file mode 100644
index 000000000000..d8068bd44ed3
--- /dev/null
+++ b/src/effects/backends/effectsbackendmanager.cpp
@@ -0,0 +1,116 @@
+#include "effects/backends/effectsbackendmanager.h"
+
+#include "control/controlobject.h"
+#include "effects/backends/builtin/builtinbackend.h"
+#include "effects/backends/effectprocessor.h"
+#ifdef __LILV__
+#include "effects/backends/lv2/lv2backend.h"
+#endif
+#include "effects/presets/effectpreset.h"
+
+EffectsBackendManager::EffectsBackendManager() {
+ m_pNumEffectsAvailable = std::make_unique(
+ ConfigKey("[Master]", "num_effectsavailable"));
+ m_pNumEffectsAvailable->setReadOnly();
+
+ addBackend(EffectsBackendPointer(new BuiltInBackend()));
+#ifdef __LILV__
+ addBackend(EffectsBackendPointer(new LV2Backend()));
+#endif
+}
+
+void EffectsBackendManager::addBackend(EffectsBackendPointer pBackend) {
+ VERIFY_OR_DEBUG_ASSERT(pBackend) {
+ return;
+ }
+
+ m_effectsBackends.insert(pBackend->getType(), pBackend);
+
+ for (const QString& effectId : pBackend->getEffectIds()) {
+ m_manifests.append(pBackend->getManifest(effectId));
+ }
+
+ m_pNumEffectsAvailable->forceSet(m_manifests.size());
+
+ std::sort(m_manifests.begin(),
+ m_manifests.end(),
+ EffectManifest::sortLexigraphically);
+}
+
+const QList EffectsBackendManager::getManifestsForBackend(
+ EffectBackendType backendType) const {
+ auto pBackend = m_effectsBackends.value(backendType);
+ VERIFY_OR_DEBUG_ASSERT(pBackend) {
+ return QList();
+ }
+ auto list = pBackend->getManifests();
+ std::sort(list.begin(), list.end(), EffectManifest::sortLexigraphically);
+ return list;
+}
+
+EffectManifestPointer EffectsBackendManager::getManifestFromUniqueId(
+ const QString& uid) const {
+ if (kEffectDebugOutput) {
+ //qDebug() << "EffectsBackendManager::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(" ");
+ auto backendType = EffectBackendType::BuiltIn;
+ // Mixxx 2.0 - 2.3 did not store the backend type in mixxx.cfg,
+ // so this code will be executed once when upgrading to Mixxx 2.4.
+ // 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.
+ if (delimiterIndex == -1) {
+ return m_effectsBackends.value(EffectBackendType::BuiltIn)
+ ->getManifest(uid);
+ }
+ backendType = EffectsBackend::backendTypeFromString(uid.mid(delimiterIndex + 1));
+ return m_effectsBackends.value(backendType)
+ ->getManifest(uid.mid(-1, delimiterIndex + 1));
+}
+
+EffectManifestPointer EffectsBackendManager::getManifest(
+ const QString& id, EffectBackendType backendType) const {
+ return m_effectsBackends.value(backendType)->getManifest(id);
+}
+
+const QString EffectsBackendManager::getDisplayNameForEffectPreset(
+ EffectPresetPointer pPreset) const {
+ //: Displayed when no effect is loaded
+ QString displayName(kNoEffectString);
+ if (!pPreset || pPreset->isEmpty()) {
+ return displayName;
+ }
+
+ bool manifestFound = false;
+ for (const auto& pManifest : std::as_const(m_manifests)) {
+ if (pManifest->id() == pPreset->id() &&
+ pManifest->backendType() == pPreset->backendType()) {
+ displayName = pManifest->name();
+ manifestFound = true;
+ break;
+ }
+ }
+ VERIFY_OR_DEBUG_ASSERT(manifestFound) {
+ qWarning() << "Failed to find manifest for effect preset " << pPreset->id();
+ }
+ return displayName;
+}
+
+std::unique_ptr EffectsBackendManager::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);
+}
diff --git a/src/effects/backends/effectsbackendmanager.h b/src/effects/backends/effectsbackendmanager.h
new file mode 100644
index 000000000000..0d8618c886ff
--- /dev/null
+++ b/src/effects/backends/effectsbackendmanager.h
@@ -0,0 +1,33 @@
+#pragma once
+
+#include "effects/backends/effectsbackend.h"
+
+class ControlObject;
+
+/// EffectsBackendManager initializes EffectsBackends, maintains the list of
+/// available EffectManifests, and creates EffectProcessors from EffectManifests.
+class EffectsBackendManager {
+ public:
+ EffectsBackendManager();
+ ~EffectsBackendManager() = default;
+
+ const QList& getManifests() const {
+ return m_manifests;
+ };
+ const QList getManifestsForBackend(EffectBackendType backendType) const;
+ EffectManifestPointer getManifestFromUniqueId(const QString& uid) const;
+ EffectManifestPointer getManifest(const QString& id, EffectBackendType backendType) const;
+ const QString getDisplayNameForEffectPreset(EffectPresetPointer pPreset) const;
+
+ std::unique_ptr createProcessor(const EffectManifestPointer pManifest);
+
+ private:
+ void addBackend(EffectsBackendPointer pEffectsBackend);
+
+ std::unique_ptr m_pNumEffectsAvailable;
+
+ QHash m_effectsBackends;
+ QList m_manifests;
+};
+
+typedef QSharedPointer EffectsBackendManagerPointer;
diff --git a/src/effects/backends/lv2/lv2backend.cpp b/src/effects/backends/lv2/lv2backend.cpp
new file mode 100644
index 000000000000..80b51dc02e3c
--- /dev/null
+++ b/src/effects/backends/lv2/lv2backend.cpp
@@ -0,0 +1,98 @@
+#include "effects/backends/lv2/lv2backend.h"
+
+#include "effects/backends/lv2/lv2effectprocessor.h"
+#include "effects/backends/lv2/lv2manifest.h"
+
+LV2Backend::LV2Backend() {
+ m_pWorld = lilv_world_new();
+ initializeProperties();
+ lilv_world_load_all(m_pWorld);
+ enumeratePlugins();
+}
+
+LV2Backend::~LV2Backend() {
+ for (LilvNode* node : std::as_const(m_properties)) {
+ lilv_node_free(node);
+ }
+ lilv_world_free(m_pWorld);
+ m_registeredEffects.clear();
+}
+
+void LV2Backend::enumeratePlugins() {
+ const LilvPlugins* plugs = lilv_world_get_all_plugins(m_pWorld);
+ LILV_FOREACH(plugins, i, plugs) {
+ const LilvPlugin* plug = lilv_plugins_get(plugs, i);
+ if (lilv_plugin_is_replaced(plug)) {
+ continue;
+ }
+ auto lv2Manifest = LV2EffectManifestPointer::create(plug, m_properties);
+ lv2Manifest->setBackendType(getType());
+ m_registeredEffects.insert(lv2Manifest->id(), lv2Manifest);
+ }
+}
+
+void LV2Backend::initializeProperties() {
+ m_properties["audio_port"] = lilv_new_uri(m_pWorld, LV2_CORE__AudioPort);
+ m_properties["input_port"] = lilv_new_uri(m_pWorld, LV2_CORE__InputPort);
+ m_properties["output_port"] = lilv_new_uri(m_pWorld, LV2_CORE__OutputPort);
+ m_properties["control_port"] = lilv_new_uri(m_pWorld, LV2_CORE__ControlPort);
+ m_properties["button_port"] = lilv_new_uri(m_pWorld, LV2_CORE__toggled);
+ m_properties["integer_port"] = lilv_new_uri(m_pWorld, LV2_CORE__integer);
+ m_properties["enumeration_port"] = lilv_new_uri(m_pWorld, LV2_CORE__enumeration);
+}
+
+const QList LV2Backend::getEffectIds() const {
+ QList availableEffects;
+ for (const auto& lv2Manifest : std::as_const(m_registeredEffects)) {
+ if (lv2Manifest->isValid()) {
+ availableEffects.append(lv2Manifest->id());
+ }
+ }
+ return availableEffects;
+}
+
+const QSet LV2Backend::getDiscoveredPluginIds() const {
+ QSet pluginIds;
+ for (auto it = m_registeredEffects.constBegin();
+ it != m_registeredEffects.constEnd();
+ ++it) {
+ pluginIds.insert(it.key());
+ }
+ return pluginIds;
+}
+
+bool LV2Backend::canInstantiateEffect(const QString& effectId) const {
+ if (m_registeredEffects.contains(effectId) &&
+ m_registeredEffects[effectId]->isValid()) {
+ return true;
+ }
+ return false;
+}
+
+EffectManifestPointer LV2Backend::getManifest(const QString& effectId) const {
+ VERIFY_OR_DEBUG_ASSERT(m_registeredEffects.contains(effectId)) {
+ return EffectManifestPointer();
+ }
+ return m_registeredEffects.value(effectId);
+}
+
+const QList LV2Backend::getManifests() const {
+ QList list;
+ for (const auto& manifest : m_registeredEffects) {
+ list.append(manifest);
+ }
+ return list;
+}
+
+std::unique_ptr LV2Backend::createProcessor(
+ const EffectManifestPointer pManifest) const {
+ LV2EffectManifestPointer pLV2Manifest = m_registeredEffects.value(pManifest->id());
+ VERIFY_OR_DEBUG_ASSERT(pLV2Manifest) {
+ return nullptr;
+ }
+ return std::make_unique(pLV2Manifest);
+}
+
+LV2EffectManifestPointer LV2Backend::getLV2Manifest(const QString& effectId) const {
+ return m_registeredEffects[effectId];
+}
diff --git a/src/effects/lv2/lv2backend.h b/src/effects/backends/lv2/lv2backend.h
similarity index 53%
rename from src/effects/lv2/lv2backend.h
rename to src/effects/backends/lv2/lv2backend.h
index b22a22e52a64..4b008882fa51 100644
--- a/src/effects/lv2/lv2backend.h
+++ b/src/effects/backends/lv2/lv2backend.h
@@ -2,31 +2,36 @@
#include