Skip to content

Commit

Permalink
Merge pull request #13086 from acolombier/feat/add-stem-controls
Browse files Browse the repository at this point in the history
Add stem controls
  • Loading branch information
JoergAtGithub authored Jul 30, 2024
2 parents 7a3c515 + 0a4ba6d commit 9b31059
Show file tree
Hide file tree
Showing 36 changed files with 4,210 additions and 101 deletions.
12 changes: 12 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3450,13 +3450,25 @@ if (STEM)
target_sources(mixxx-test PUBLIC
src/test/stemtest.cpp
src/test/steminfotest.cpp
src/test/stemcontrolobjecttest.cpp
)
list(APPEND MIXXX_LIB_PRECOMPILED_HEADER src/track/steminfo.h)
target_sources(mixxx-lib PRIVATE
src/sources/soundsourcestem.cpp
src/track/steminfoimporter.cpp
src/track/steminfo.cpp
)
if(QOPENGL)
target_sources(mixxx-lib PRIVATE
src/waveform/renderers/allshader/waveformrendererstem.cpp
)
endif()
if(QML)
target_compile_definitions(mixxx-qml-lib PUBLIC __STEM__)
target_sources(mixxx-qml-lib PRIVATE
src/qml/qmlstemsmodel.cpp
)
endif()
endif()

# Test Suite
Expand Down
111 changes: 85 additions & 26 deletions res/qml/EqColumn.qml
Original file line number Diff line number Diff line change
@@ -1,44 +1,103 @@
import "." as Skin
import QtQuick 2.12
import QtQuick.Shapes 1.12
import QtQuick.Layouts
import Mixxx 1.0 as Mixxx
import "Theme"

Column {
id: root

required property string group
property var player: Mixxx.PlayerManager.getPlayer(root.group)

spacing: 4
Mixxx.ControlProxy {
id: stemCountControl

Skin.EqKnob {
statusKey: "button_parameter3"
knob.group: "[EqualizerRack1_" + root.group + "_Effect1]"
knob.key: "parameter3"
knob.color: Theme.eqHighColor
group: root.group
key: "stem_count"
}

Skin.EqKnob {
statusKey: "button_parameter2"
knob.group: "[EqualizerRack1_" + root.group + "_Effect1]"
knob.key: "parameter2"
knob.color: Theme.eqMidColor
}
Row {
Column {
id: stem
spacing: 4
visible: opacity != 0
Repeater {
model: root.player.stemsModel

Skin.EqKnob {
knob.group: "[EqualizerRack1_" + root.group + "_Effect1]"
knob.key: "parameter1"
statusKey: "button_parameter1"
knob.color: Theme.eqLowColor
}
Skin.StemKnob {
id: stem
group: root.group
property alias color: stem.stemColor
}
}
}
Column {
id: eq
spacing: 4
width: 10
visible: opacity != 0
Skin.EqKnob {
statusKey: "button_parameter3"
knob.group: "[EqualizerRack1_" + root.group + "_Effect1]"
knob.key: "parameter3"
knob.color: Theme.eqHighColor
}

Skin.EqKnob {
statusKey: "button_parameter2"
knob.group: "[EqualizerRack1_" + root.group + "_Effect1]"
knob.key: "parameter2"
knob.color: Theme.eqMidColor
}

Skin.EqKnob {
knob.group: "[EqualizerRack1_" + root.group + "_Effect1]"
knob.key: "parameter1"
statusKey: "button_parameter1"
knob.color: Theme.eqLowColor
}

Skin.EqKnob {
knob.group: "[QuickEffectRack1_" + root.group + "]"
knob.key: "super1"
statusGroup: "[QuickEffectRack1_" + root.group + "_Effect1]"
statusKey: "enabled"
knob.arcStyle: ShapePath.DashLine
knob.arcStylePattern: [2, 2]
knob.color: Theme.eqFxColor
}
}
states: [
State {
name: "eq"
when: stemCountControl.value == 0
PropertyChanges { target: stem; opacity: 0; width: 0}
},
State {
name: "stem"
when: stemCountControl.value != 0
PropertyChanges { target: eq; opacity: 0; width: 0 }
}
]

Skin.EqKnob {
knob.group: "[QuickEffectRack1_" + root.group + "]"
knob.key: "super1"
statusGroup: "[QuickEffectRack1_" + root.group + "_Effect1]"
statusKey: "enabled"
knob.arcStyle: ShapePath.DashLine
knob.arcStylePattern: [2, 2]
knob.color: Theme.eqFxColor
transitions: [
Transition {
from: "eq"
to: "stem"
ParallelAnimation {
PropertyAnimation { targets: [eq, stem]; properties: "opacity,width"; duration: 1000}
}
},
Transition {
from: "stem"
to: "eq"
ParallelAnimation {
PropertyAnimation { targets: [eq, stem]; properties: "opacity,width"; duration: 1000}
}
}
]
}

Skin.OrientationToggleButton {
Expand Down
1 change: 1 addition & 0 deletions res/qml/Mixer.qml
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import "." as Skin
import Mixxx 1.0 as Mixxx
import QtQuick 2.12

Item {
Expand Down
67 changes: 67 additions & 0 deletions res/qml/StemKnob.qml
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
import "." as Skin
import Mixxx 1.0 as Mixxx
import QtQuick 2.12
import "Theme"

Rectangle {
id: root

property alias knob: knob

required property string group
required property string label
required property color stemColor
required property int index

width: 56
height: 56
radius: 5
color: stemColor

Skin.ControlKnob {
id: knob
group: root.group
key: `stem_${root.index + 1}_volume`
color: Theme.gainKnobColor
anchors.topMargin: 5
anchors.top: root.top
anchors.horizontalCenter: root.horizontalCenter

arcStart: 0

width: 36
height: 36
}

Text {
anchors.bottom: root.bottom
anchors.horizontalCenter: root.horizontalCenter
text: label
}

Mixxx.ControlProxy {
id: statusControl

group: root.group
key: `stem_${root.index + 1}_mute`
}

Rectangle {
id: statusButton

anchors.left: root.left
anchors.top: root.top
anchors.leftMargin: 4
anchors.topMargin: 4
width: 8
height: width
radius: width / 2
border.width: 1
border.color: Theme.buttonNormalColor
color: statusControl.value ? knob.color : "transparent"

TapHandler {
onTapped: statusControl.value = !statusControl.value
}
}
}
16 changes: 16 additions & 0 deletions src/analyzer/analyzerwaveform.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,9 @@ bool AnalyzerWaveform::shouldAnalyze(TrackPointer tio) const {
ConstWaveformPointer pTrackWaveformSummary = tio->getWaveformSummary();
ConstWaveformPointer pLoadedTrackWaveform;
ConstWaveformPointer pLoadedTrackWaveformSummary;
#ifdef __STEM__
bool isStemTrack = !tio->getStemInfo().isEmpty();
#endif

TrackId trackId = tio->getId();
bool missingWaveform = pTrackWaveform.isNull();
Expand Down Expand Up @@ -142,6 +145,19 @@ bool AnalyzerWaveform::shouldAnalyze(TrackPointer tio) const {
}
}

#ifdef __STEM__
// If the waveform was generated without stem information but the track has
// some, or the waveform contains stem information but the track doesn't
// have any, we need to regenerate the waveform.
if (!missingWaveform &&
((!pTrackWaveform.isNull() &&
pTrackWaveform->hasStem() != isStemTrack) ||
(!pLoadedTrackWaveform.isNull() &&
pLoadedTrackWaveform->hasStem() != isStemTrack))) {
missingWaveform = true;
}
#endif

// If we don't need to calculate the waveform/wavesummary, skip.
if (!missingWaveform && !missingWavesummary) {
kLogger.debug() << "loadStored - Stored waveform loaded";
Expand Down
2 changes: 1 addition & 1 deletion src/analyzer/analyzerwaveform.h
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@ struct WaveformStride {

float m_overallData[ChannelCount];
float m_filteredData[ChannelCount][FilterCount];
float m_stemData[ChannelCount][mixxx::kMaxSupportedStem];
float m_stemData[ChannelCount][mixxx::kMaxSupportedStems];

float m_averageOverallData[ChannelCount];
float m_averageFilteredData[ChannelCount][FilterCount];
Expand Down
2 changes: 1 addition & 1 deletion src/analyzer/constants.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ namespace mixxx {
// fixed number of channels like the engine does, usually 2 = stereo.
constexpr audio::ChannelCount kAnalysisChannels = mixxx::kEngineChannelOutputCount;
constexpr audio::ChannelCount kAnalysisMaxChannels = mixxx::kMaxEngineChannelInputCount;
constexpr int kMaxSupportedStem = 4;
constexpr int kMaxSupportedStems = 4;
constexpr SINT kAnalysisFramesPerChunk = 4096;
constexpr SINT kAnalysisSamplesPerChunk =
kAnalysisFramesPerChunk * kAnalysisMaxChannels;
Expand Down
Loading

0 comments on commit 9b31059

Please sign in to comment.