Skip to content

Commit

Permalink
feat: add scrolling waveform in QML using scenegraph
Browse files Browse the repository at this point in the history
  • Loading branch information
acolombier committed Dec 1, 2024
1 parent 72f0a0b commit a59fe88
Show file tree
Hide file tree
Showing 32 changed files with 1,693 additions and 49 deletions.
35 changes: 34 additions & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -1502,6 +1502,7 @@ else()
)
endif()
if(QOPENGL)
target_compile_definitions(mixxx-lib PRIVATE __RENDERGRAPH_IS_OPENGL)
target_sources(mixxx-lib PRIVATE
src/shaders/endoftrackshader.cpp
src/shaders/slipmodeshader.cpp
Expand Down Expand Up @@ -1770,7 +1771,7 @@ if(QT6)
# below that takes care of the correct object order in the resulting binary
# According to https://doc.qt.io/qt-6/qt-finalize-target.html it is importand for
# builds with Qt < 3.21
qt_add_executable(mixxx WIN32 src/main.cpp MANUAL_FINALIZATION)
qt_add_executable(mixxx WIN32 MACOSX_BUNDLE src/main.cpp MANUAL_FINALIZATION)
else()
find_package(Qt5 COMPONENTS Core) # For Qt Core cmake functions
# This is the first package form the environment, if this fails give hints how to install the environment
Expand Down Expand Up @@ -2766,9 +2767,11 @@ if(QML)
res/qml/Mixxx/Controls/WaveformOverviewHotcueMarker.qml
res/qml/Mixxx/Controls/WaveformOverviewMarker.qml
res/qml/Mixxx/Controls/WaveformOverview.qml
res/qml/Mixxx/Controls/WaveformDisplay.qml
)
target_link_libraries(mixxx-qml-lib PRIVATE mixxx-qml-mixxxcontrolsplugin)

target_compile_definitions(mixxx-qml-lib PRIVATE __RENDERGRAPH_IS_SCENEGRAPH)
target_sources(mixxx-qml-lib PRIVATE
src/qml/asyncimageprovider.cpp
src/qml/qmlapplication.cpp
Expand All @@ -2788,6 +2791,22 @@ if(QML)
src/qml/qmlvisibleeffectsmodel.cpp
src/qml/qmlchainpresetmodel.cpp
src/qml/qmlwaveformoverview.cpp
src/qml/qmlwaveformdisplay.cpp
src/qml/qmlwaveformrenderer.cpp
src/waveform/renderers/allshader/digitsrenderer.cpp
src/waveform/renderers/allshader/waveformrenderbeat.cpp
src/waveform/renderers/allshader/waveformrenderer.cpp
src/waveform/renderers/allshader/waveformrendererendoftrack.cpp
src/waveform/renderers/allshader/waveformrendererpreroll.cpp
src/waveform/renderers/allshader/waveformrendererrgb.cpp
src/waveform/renderers/allshader/waveformrenderersignalbase.cpp
src/waveform/renderers/allshader/waveformrendermark.cpp
src/waveform/renderers/allshader/waveformrendermarkrange.cpp
# FIXME depends on rendergraph/openglnode.h
# src/waveform/renderers/allshader/waveformrendererslipmode.cpp
# src/waveform/renderers/allshader/waveformrendererfiltered.cpp
# src/waveform/renderers/allshader/waveformrendererhsv.cpp
# src/waveform/renderers/allshader/waveformrenderersimple.cpp
# The following sources need to be in this target to get QML_ELEMENT properly interpreted
src/control/controlmodel.cpp
src/control/controlsortfiltermodel.cpp
Expand Down Expand Up @@ -3480,6 +3499,7 @@ if (STEM)
if(QML)
target_compile_definitions(mixxx-qml-lib PUBLIC __STEM__)
target_sources(mixxx-qml-lib PRIVATE
src/waveform/renderers/allshader/waveformrendererstem.cpp
src/qml/qmlstemsmodel.cpp
)
endif()
Expand Down Expand Up @@ -3812,8 +3832,21 @@ endif()
# rendergraph
add_subdirectory(src/rendergraph/opengl)
add_subdirectory(res/shaders/rendergraph)
target_compile_definitions(rendergraph_gl PUBLIC
$<$<CONFIG:Debug>:MIXXX_DEBUG_ASSERTIONS_ENABLED>
)
target_link_libraries(mixxx-lib PUBLIC rendergraph_gl)
target_compile_definitions(mixxx-lib PRIVATE rendergraph=rendergraph_gl)
target_compile_definitions(mixxx-lib PRIVATE allshader=allshader_gl)
if(QML)
add_subdirectory(src/rendergraph/scenegraph)
target_compile_definitions(rendergraph_sg PUBLIC
$<$<CONFIG:Debug>:MIXXX_DEBUG_ASSERTIONS_ENABLED>
)
target_link_libraries(mixxx-qml-lib PRIVATE rendergraph_sg)
target_compile_definitions(mixxx-qml-lib PRIVATE rendergraph=rendergraph_sg)
target_compile_definitions(mixxx-qml-lib PRIVATE allshader=allshader_sg)
endif()

# WavPack audio file support
find_package(wavpack)
Expand Down
238 changes: 238 additions & 0 deletions res/qml/WaveformDisplay.qml
Original file line number Diff line number Diff line change
@@ -0,0 +1,238 @@
import "." as Skin
import Mixxx 1.0 as Mixxx
import Mixxx.Controls 1.0 as MixxxControls
import QtQuick 2.12
import "Theme"

Item {
id: root

required property string group

enum MouseStatus {
Normal,
Bending,
Scratching
}

MixxxControls.WaveformDisplay {
anchors.fill: parent
group: root.group
zoom: zoomControl.value
backgroundColor: "#5e000000"

Mixxx.WaveformRendererEndOfTrack {
color: '#ff8872'
}

Mixxx.WaveformRendererPreroll {
color: '#ff8872'
}

Mixxx.WaveformRendererMarkRange {
// <!-- Loop -->
Mixxx.WaveformMarkRange {
startControl: "loop_start_position"
endControl: "loop_end_position"
enabledControl: "loop_enabled"
color: '#00b400'
opacity: 0.7
disabledColor: '#FFFFFF'
disabledOpacity: 0.6
}
// <!-- Intro -->
Mixxx.WaveformMarkRange {
startControl: "intro_start_position"
endControl: "intro_end_position"
color: '#2c5c9a'
opacity: 0.6
durationTextColor: '#ffffff'
durationTextLocation: 'after'
}
// <!-- Outro -->
Mixxx.WaveformMarkRange {
startControl: "outro_start_position"
endControl: "outro_end_position"
color: '#2c5c9a'
opacity: 0.6
durationTextColor: '#ffffff'
durationTextLocation: 'before'
}
}

Mixxx.WaveformRendererRGB {
axesColor: '#a1a1a1a1'
lowColor: '#ff2154d7'
midColor: '#cfb26606'
highColor: '#e5029c5c'
}

Mixxx.WaveformRendererStem { }

Mixxx.WaveformRendererBeat {
color: '#a1a1a1a1'
}

Mixxx.WaveformRendererMark {
playMarkerColor: 'cyan'
playMarkerBackground: 'orange'
defaultMark: Mixxx.WaveformMark {
align: "bottom|right"
color: "#00d9ff"
textColor: "#1a1a1a"
text: " %1 "
}

untilMark.showTime: true
untilMark.showBeats: true
untilMark.align: Mixxx.WaveformUntilMark.AlignBottom
untilMark.textSize: 11

Mixxx.WaveformMark {
control: "cue_point"
text: 'CUE'
align: 'top|right'
color: 'red'
textColor: '#1a1a1a'
}
Mixxx.WaveformMark {
control: "loop_start_position"
text: ''
align: 'top|left'
color: 'green'
textColor: '#FFFFFF'
}
Mixxx.WaveformMark {
control: "loop_end_position"
align: 'bottom|right'
color: 'green'
textColor: '#FFFFFF'
}
Mixxx.WaveformMark {
control: "intro_start_position"
align: 'top|right'
color: 'blue'
textColor: '#FFFFFF'
}
Mixxx.WaveformMark {
control: "intro_end_position"
text: ''
align: 'top|left'
color: 'blue'
textColor: '#FFFFFF'
}
Mixxx.WaveformMark {
control: "outro_start_position"
text: ''
align: 'top|right'
color: 'blue'
textColor: '#FFFFFF'
}
Mixxx.WaveformMark {
control: "outro_end_position"
align: 'top|left'
color: 'blue'
textColor: '#FFFFFF'
}
}
}

Mixxx.ControlProxy {
id: scratchPositionEnableControl

group: root.group
key: "scratch_position_enable"
}

Mixxx.ControlProxy {
id: scratchPositionControl

group: root.group
key: "scratch_position"
}

Mixxx.ControlProxy {
id: wheelControl

group: root.group
key: "wheel"
}

Mixxx.ControlProxy {
id: rateRatioControl

group: root.group
key: "rate_ratio"
}

Mixxx.ControlProxy {
id: zoomControl

group: root.group
key: "waveform_zoom"
}
readonly property real effectiveZoomFactor: (1 / rateRatioControl.value) * (100 / zoomControl.value)

MouseArea {
property int mouseStatus: WaveformDisplay.MouseStatus.Normal
property point mouseAnchor: Qt.point(0, 0)

anchors.fill: parent
acceptedButtons: Qt.LeftButton | Qt.RightButton
onPressed: {
mouseAnchor = Qt.point(mouse.x, mouse.y);
if (mouse.button == Qt.LeftButton) {
if (mouseStatus == WaveformDisplay.MouseStatus.Bending)
wheelControl.parameter = 0.5;

mouseStatus = WaveformDisplay.MouseStatus.Scratching;
scratchPositionEnableControl.value = 1;
// TODO: Calculate position properly
scratchPositionControl.value = -mouse.x * zoomControl.value * 50;
} else {
if (mouseStatus == WaveformDisplay.MouseStatus.Scratching)
scratchPositionEnableControl.value = 0;

wheelControl.parameter = 0.5;
mouseStatus = WaveformDisplay.MouseStatus.Bending;
}
}
onPositionChanged: {
switch (mouseStatus) {
case WaveformDisplay.MouseStatus.Bending: {
const diff = mouse.x - mouseAnchor.x;
// Start at the middle of [0.0, 1.0], and emit values based on how far
// the mouse has traveled horizontally. Note, for legacy (MIDI) reasons,
// this is tuned to 127.
const v = 0.5 + (diff / root.width);
// clamp to [0.0, 1.0]
wheelControl.parameter = Math.max(Math.min(v, 1), 0);
break;
};
case WaveformDisplay.MouseStatus.Scratching:
// TODO: Calculate position properly
scratchPositionControl.value = -mouse.x * zoomControl.value * 50;
break;
}
}
onReleased: {
switch (mouseStatus) {
case WaveformDisplay.MouseStatus.Bending:
wheelControl.parameter = 0.5;
break;
case WaveformDisplay.MouseStatus.Scratching:
scratchPositionEnableControl.value = 0;
break;
}
mouseStatus = WaveformDisplay.MouseStatus.Normal;
}

onWheel: {
if (wheel.angleDelta.y < 0 && zoomControl.value > 1) {
zoomControl.value -= 1;
} else if (wheel.angleDelta.y > 0 && zoomControl.value < 10.0) {
zoomControl.value += 1;
}
}
}
}
8 changes: 4 additions & 4 deletions res/qml/main.qml
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ ApplicationWindow {
}
}

WaveformRow {
Skin.WaveformDisplay {
id: deck3waveform

group: "[Channel3]"
Expand All @@ -111,7 +111,7 @@ ApplicationWindow {
}
}

WaveformRow {
Skin.WaveformDisplay {
id: deck1waveform

group: "[Channel1]"
Expand All @@ -124,7 +124,7 @@ ApplicationWindow {
}
}

WaveformRow {
Skin.WaveformDisplay {
id: deck2waveform

group: "[Channel2]"
Expand All @@ -137,7 +137,7 @@ ApplicationWindow {
}
}

WaveformRow {
Skin.WaveformDisplay {
id: deck4waveform

group: "[Channel4]"
Expand Down
12 changes: 12 additions & 0 deletions res/shaders/rendergraph/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,18 @@ qt6_add_shaders(rendergraph_sg "shaders-qsb"
${shaders}
)

if(TARGET mixxx)
qt6_add_shaders(mixxx "shaders-qsb"
BATCHABLE
PRECOMPILE
OPTIMIZED
PREFIX
/shaders/rendergraph
FILES
${shaders}
)
endif()

if(USE_QSHADER_FOR_GL)
message(STATUS "Adding qsb shaders to rendergraph_gl")
qt6_add_shaders(rendergraph_gl "shaders-qsb"
Expand Down
Loading

0 comments on commit a59fe88

Please sign in to comment.