Skip to content

S4 Mk3 screen support#13653

Merged
JoergAtGithub merged 7 commits intomixxxdj:mainfrom
acolombier:feat/s4-mk3-screen-support
Oct 22, 2025
Merged

S4 Mk3 screen support#13653
JoergAtGithub merged 7 commits intomixxxdj:mainfrom
acolombier:feat/s4-mk3-screen-support

Conversation

@acolombier
Copy link
Member

@acolombier acolombier commented Sep 15, 2024

This PR include support for the S4 Mk3 screen support. It is made to work without #12199 although there is a setting to enable communication between mapping. This way, I can maintain a single mapping definition, without needing to get an API commitment for communication between mapping.

It includes two themes:

  • Traktor Pro stock inspired theme
    image
  • Joe Easton's inspired theme
    image

Depends on:

Here is the list of improvement made on the core mapping

  • Beatjump tab
  • Stem tab
  • Support for beatloop roll inside a loop
  • Screen feedback (optional, require Ability for controller to share data at runtime #12199 - temporary merge available on feat/s4-mk3-screen-support-with-shared-data)
  • Add library page scroll
  • Ability to preview the active deck hotcue
  • Ability change the hotcue color

@acolombier acolombier force-pushed the feat/s4-mk3-screen-support branch from 1c270cf to cdcbd4e Compare October 16, 2024 23:55
@acolombier
Copy link
Member Author

@mixxxdj/developers what are you opinion about where this PR is aiming?

I'm now at a stage where the mapping is pretty stable and usable. I appreciate that this introduce a huge amount of source code. I'm afraid there is no alternative, and I think the current screen content is really impressive! (Happy to post a full demo video if you would like me to justify adding 74 QML files...)

I would like to get an agreement in principle before I start working on the documentation PR.

Note that every C++ change is the early version of the dependencies and once those are merged, this PR should include no core source changes.

@ywwg
Copy link
Member

ywwg commented Oct 17, 2024

I will try to take a look at this soon.

@JoergAtGithub
Copy link
Member

Sure, we want to have this feature in Mixxx. This is why we co-financed the S4 Mk3 for Owen.
And as long as the code is device specific, we do not have the high requirements to the code anyway. These only apply for generic code shared between different controllers.

@ywwg
Copy link
Member

ywwg commented Oct 17, 2024

These only apply for generic code shared between different controllers.

the biggest point of controversy was how the data from the engine is shared with the controller. That is a mechanism that will be used by every controller with a screen, and needs to be safe and efficient. If we are agreed on how that works, then the rest of the changes are good to go

@acolombier
Copy link
Member Author

The approach I went with is a controller settings to enable the API rejected in #12199, is this is a must have for the screen.

As suggested in the PR description, this will allow me to maintain a single code base, and also allow advanced users to build this feature while still using the mainstream mapping.
If you've been following the development of the S4 on Zulip, you've probably noticed that I have been maintaining multiple forks and it has now become unmaintainable so getting it in one code base is a hard requirement on my end.

Obviously, if we ever manage to get a stable API in Mixxx, we can eventually make the migration.

@ywwg
Copy link
Member

ywwg commented Oct 18, 2024

for sure, we want to get this in and don't want to have forks that need maintenance. I do like the approach of using a controller setting to enable / disable the new API. That limits the blast radius nicely. If/when another controller screen comes online, we can iterate on the design as needed.

@acolombier acolombier force-pushed the feat/s4-mk3-screen-support branch from cdcbd4e to d3b16c3 Compare October 27, 2024 19:31
@acolombier acolombier mentioned this pull request Nov 17, 2024
8 tasks
@acolombier acolombier force-pushed the feat/s4-mk3-screen-support branch 3 times, most recently from f5b7c13 to 85f2705 Compare November 25, 2024 23:47
@acolombier acolombier force-pushed the feat/s4-mk3-screen-support branch from 85f2705 to 60383a2 Compare December 3, 2024 13:49
@acolombier
Copy link
Member Author

Manual PR available in mixxxdj/manual#703

@acolombier acolombier marked this pull request as ready for review December 6, 2024 00:32
@acolombier acolombier requested a review from ywwg December 6, 2024 00:33
This was referenced Aug 18, 2025
@acolombier acolombier force-pushed the feat/s4-mk3-screen-support branch from 8b726bc to 1c75b6f Compare August 18, 2025 22:13
@acolombier acolombier force-pushed the feat/s4-mk3-screen-support branch from 1c75b6f to c2c7272 Compare August 18, 2025 22:14
@acolombier
Copy link
Member Author

acolombier commented Aug 18, 2025

This PR now solely bring the new QML mapping. I have also dropped the fix for the regression, so this should be ready for merge hopefully 🤞

(FYI, a branch with HID mapping + screen mapping + shared API is still available and up to date on my branch feat/s4-mk3-screen-support-with-shared-data)

@ywwg
Copy link
Member

ywwg commented Aug 19, 2025

thanks for shifting things around!

@acolombier
Copy link
Member Author

This should now be ready for merge, as #15216 has now been merged!

@acolombier
Copy link
Member Author

Friendly ping @ronso0 @ywwg - would be great to finally get something out for the 2.7 beta so we can gather some feedback already :)

@ywwg
Copy link
Member

ywwg commented Oct 15, 2025

I tried to change the Screens setting from Classic to Advanced while I was playing a track, and Mixxx UI locked up (sound still playing) with this spammed in the console:

critical [CtrlScreen_leftdeck] DEBUG ASSERT: "!m_pTexture->textureSize().isNull()" in function rendergraph_sg::Texture::Texture(rendergraph_sg::Context*, const QImage&) at /home/owen/src/github/mixxx/src/rendergraph/scenegraph/texture.cpp:13

@ywwg
Copy link
Member

ywwg commented Oct 15, 2025

and backtrace:

#0  syscall () at ../sysdeps/unix/sysv/linux/x86_64/syscall.S:38
#1  0x00007ccde447d28a in QSemaphore::acquire(int) () at /lib/x86_64-linux-gnu/libQt6Core.so.6
#2  0x00007ccde43840b7 in ??? () at /lib/x86_64-linux-gnu/libQt6Core.so.6
#3  0x000059f1291e1989 in DlgPrefController::applyMapping (_t3=<optimized out>, _t2=std::shared_ptr<LegacyControllerMapping> (use count 3, weak count 0) = {...}, _t1=<optimized out>, this=0x59f16dad03d0)
    at /home/owen/src/github/mixxx/cbuild/mixxx-lib_autogen/include/moc_dlgprefcontroller.cpp:375
#4  DlgPrefController::slotApply (this=0x59f16dad03d0) at /home/owen/src/github/mixxx/src/controllers/dlgprefcontroller.cpp:704
#5  0x000059f1291f066b in DlgPrefControllers::slotApply (this=<optimized out>) at /home/owen/src/github/mixxx/src/controllers/dlgprefcontrollers.cpp:129
#6  0x00007ccde4383d9b in ??? () at /lib/x86_64-linux-gnu/libQt6Core.so.6
#7  0x00007ccde4383d9b in ??? () at /lib/x86_64-linux-gnu/libQt6Core.so.6
#8  0x00007ccde994d3b1 in QDialogButtonBox::clicked(QAbstractButton*) () at /lib/x86_64-linux-gnu/libQt6Widgets.so.6
#9  0x00007ccde99563e6 in ??? () at /lib/x86_64-linux-gnu/libQt6Widgets.so.6
#10 0x00007ccde438413f in ??? () at /lib/x86_64-linux-gnu/libQt6Core.so.6
#11 0x00007ccde9896cb4 in QAbstractButton::clicked(bool) () at /lib/x86_64-linux-gnu/libQt6Widgets.so.6
#12 0x00007ccde988e9cf in ??? () at /lib/x86_64-linux-gnu/libQt6Widgets.so.6
#13 0x00007ccde988eda2 in ??? () at /lib/x86_64-linux-gnu/libQt6Widgets.so.6
#14 0x00007ccde989c013 in QAbstractButton::mouseReleaseEvent(QMouseEvent*) () at /lib/x86_64-linux-gnu/libQt6Widgets.so.6
#15 0x00007ccde97d484f in QWidget::event(QEvent*) () at /lib/x86_64-linux-gnu/libQt6Widgets.so.6
#16 0x00007ccde978b3b0 in QApplicationPrivate::notify_helper(QObject*, QEvent*) () at /lib/x86_64-linux-gnu/libQt6Widgets.so.6
#17 0x00007ccde97842c7 in QApplication::notify(QObject*, QEvent*) () at /lib/x86_64-linux-gnu/libQt6Widgets.so.6
#18 0x000059f1298b5f43 in MixxxApplication::notify (this=0x7ffc46d407d0, pTarget=0x59f16842a1b0, pEvent=0x7ffc46d3fd90) at /home/owen/src/github/mixxx/src/mixxxapplication.cpp:217
#19 0x00007ccde4338448 in QCoreApplication::notifyInternal2(QObject*, QEvent*) () at /lib/x86_64-linux-gnu/libQt6Core.so.6
#20 0x00007ccde9780d7e in QApplicationPrivate::sendMouseEvent(QWidget*, QMouseEvent*, QWidget*, QWidget*, QWidget**, QPointer<QWidget>&, bool, bool) () at /lib/x86_64-linux-gnu/libQt6Widgets.so.6
#21 0x00007ccde97e2ad7 in ??? () at /lib/x86_64-linux-gnu/libQt6Widgets.so.6
#22 0x00007ccde97e3e75 in ??? () at /lib/x86_64-linux-gnu/libQt6Widgets.so.6
#23 0x00007ccde978b3b0 in QApplicationPrivate::notify_helper(QObject*, QEvent*) () at /lib/x86_64-linux-gnu/libQt6Widgets.so.6
#24 0x000059f1298b5f43 in MixxxApplication::notify (this=0x7ffc46d407d0, pTarget=0x59f16afc7bb0, pEvent=0x7ffc46d40290) at /home/owen/src/github/mixxx/src/mixxxapplication.cpp:217
#25 0x00007ccde4338448 in QCoreApplication::notifyInternal2(QObject*, QEvent*) () at /lib/x86_64-linux-gnu/libQt6Core.so.6
#26 0x00007ccde4996de7 in QGuiApplicationPrivate::processMouseEvent(QWindowSystemInterfacePrivate::MouseEvent*) () at /lib/x86_64-linux-gnu/libQt6Gui.so.6
#27 0x00007ccde49e15cc in QWindowSystemInterface::sendWindowSystemEvents(QFlags<QEventLoop::ProcessEventsFlag>) () at /lib/x86_64-linux-gnu/libQt6Gui.so.6
#28 0x00007ccde4d152b4 in ??? () at /lib/x86_64-linux-gnu/libQt6Gui.so.6
#29 0x00007ccde35145c5 in ??? () at /lib/x86_64-linux-gnu/libglib-2.0.so.0
#30 0x00007ccde3573737 in ??? () at /lib/x86_64-linux-gnu/libglib-2.0.so.0
#31 0x00007ccde3513a63 in g_main_context_iteration () at /lib/x86_64-linux-gnu/libglib-2.0.so.0
#32 0x00007ccde45315ef in QEventDispatcherGlib::processEvents(QFlags<QEventLoop::ProcessEventsFlag>) () at /lib/x86_64-linux-gnu/libQt6Core.so.6
#33 0x00007ccde43429a3 in QEventLoop::exec(QFlags<QEventLoop::ProcessEventsFlag>) () at /lib/x86_64-linux-gnu/libQt6Core.so.6
#34 0x00007ccde433b35e in QCoreApplication::exec() () at /lib/x86_64-linux-gnu/libQt6Core.so.6
#35 0x000059f1290b6420 in (anonymous namespace)::runMixxx (args=<optimized out>, pApp=0x7ffc46d407d0) at /home/owen/src/github/mixxx/src/main.cpp:115
#36 main (argc=<optimized out>, argv=<optimized out>) at /home/owen/src/github/mixxx/src/main.cpp:293

@ywwg
Copy link
Member

ywwg commented Oct 15, 2025

another thread:

Thread 6 (Thread 0x7ccc745ca6c0 (LWP 35243) "ControllerScree"):
#0  syscall () at ../sysdeps/unix/sysv/linux/x86_64/syscall.S:38
#1  0x00007ccde447d28a in QSemaphore::acquire(int) () at /lib/x86_64-linux-gnu/libQt6Core.so.6
#2  0x00007ccde4346551 in QMetaObject::invokeMethodImpl(QObject*, QtPrivate::QSlotObjectBase*, Qt::ConnectionType, void*) () at /lib/x86_64-linux-gnu/libQt6Core.so.6
#3  0x000059f129daad72 in QMetaObject::invokeMethod<ControllerRenderingEngine::setup(std::shared_ptr<QQmlEngine>)::<lambda()> > (type=Qt::BlockingQueuedConnection, ret=0x0, function=..., context=0x7ffc46d407d0) at /usr/include/x86_64-linux-gnu/qt6/QtCore/qobjectdefs.h:319
#4  ControllerRenderingEngine::setup (this=0x7ccd0c668620, qmlEngine=std::shared_ptr<QQmlEngine> (use count 4, weak count 0) = {...}) at /home/owen/src/github/mixxx/src/controllers/rendering/controllerrenderingengine.cpp:208
#5  0x000059f129dab079 in operator() (__closure=<optimized out>) at /home/owen/src/github/mixxx/src/controllers/rendering/controllerrenderingengine.cpp:160
#6  QtPrivate::FunctorCall<QtPrivate::IndexesList<>, QtPrivate::List<>, void, ControllerRenderingEngine::requestEngineSetup(std::shared_ptr<QQmlEngine>)::<lambda()> >::call (arg=<optimized out>, f=<optimized out>) at /usr/include/x86_64-linux-gnu/qt6/QtCore/qobjectdefs_impl.h:127
#7  QtPrivate::Functor<ControllerRenderingEngine::requestEngineSetup(std::shared_ptr<QQmlEngine>)::<lambda()>, 0>::call<QtPrivate::List<>, void> (arg=<optimized out>, f=<optimized out>) at /usr/include/x86_64-linux-gnu/qt6/QtCore/qobjectdefs_impl.h:241
#8  QtPrivate::QFunctorSlotObject<ControllerRenderingEngine::requestEngineSetup(std::shared_ptr<QQmlEngine>)::<lambda()>, 0, QtPrivate::List<>, void>::impl(int, QtPrivate::QSlotObjectBase *, QObject *, void **, bool *) (which=<optimized out>, this_=<optimized out>, r=<optimized out>, a=<optimized out>, ret=<optimized out>) at /usr/include/x86_64-linux-gnu/qt6/QtCore/qobjectdefs_impl.h:408
#9  0x00007ccde4376683 in QObject::event(QEvent*) () at /lib/x86_64-linux-gnu/libQt6Core.so.6
#10 0x00007ccde978b3b0 in QApplicationPrivate::notify_helper(QObject*, QEvent*) () at /lib/x86_64-linux-gnu/libQt6Widgets.so.6
#11 0x000059f1298b5f43 in MixxxApplication::notify (this=0x7ffc46d407d0, pTarget=0x7ccd0c668620, pEvent=0x7ccd0c505b60) at /home/owen/src/github/mixxx/src/mixxxapplication.cpp:217
#12 0x00007ccde4338448 in QCoreApplication::notifyInternal2(QObject*, QEvent*) () at /lib/x86_64-linux-gnu/libQt6Core.so.6
#13 0x00007ccde4338635 in QCoreApplicationPrivate::sendPostedEvents(QObject*, int, QThreadData*) () at /lib/x86_64-linux-gnu/libQt6Core.so.6
#14 0x00007ccde4533a8f in ??? () at /lib/x86_64-linux-gnu/libQt6Core.so.6
#15 0x00007ccde35145c5 in ??? () at /lib/x86_64-linux-gnu/libglib-2.0.so.0
#16 0x00007ccde3573737 in ??? () at /lib/x86_64-linux-gnu/libglib-2.0.so.0
#17 0x00007ccde3513a63 in g_main_context_iteration () at /lib/x86_64-linux-gnu/libglib-2.0.so.0
#18 0x00007ccde45315ef in QEventDispatcherGlib::processEvents(QFlags<QEventLoop::ProcessEventsFlag>) () at /lib/x86_64-linux-gnu/libQt6Core.so.6
#19 0x00007ccde43429a3 in QEventLoop::exec(QFlags<QEventLoop::ProcessEventsFlag>) () at /lib/x86_64-linux-gnu/libQt6Core.so.6
#20 0x00007ccde4410683 in QThread::exec() () at /lib/x86_64-linux-gnu/libQt6Core.so.6
#21 0x00007ccde447c48d in ??? () at /lib/x86_64-linux-gnu/libQt6Core.so.6
#22 0x00007ccde3a9caa4 in start_thread (arg=<optimized out>) at ./nptl/pthread_create.c:447
#23 0x00007ccde3b29c6c in clone3 () at ../sysdeps/unix/sysv/linux/x86_64/clone3.S:78

@acolombier
Copy link
Member Author

acolombier commented Oct 15, 2025

Yes, this is an instance of #14606 - If you apply the patch in there, it should allow you to test correctly!

If you want, I have a branch forking this current one with the fix applied + runtime data

[...] this spammed in the console:

critical [CtrlScreen_leftdeck] DEBUG ASSERT: "!m_pTexture->textureSize().isNull()" in function rendergraph_sg::Texture::Texture(rendergraph_sg::Context*, const QImage&) at /home/owen/src/github/mixxx/src/rendergraph/scenegraph/texture.cpp:13

Sounds strange, I'll try and reproduce it. Just had tracks loaded on each deck playing, right? Or do I need anything to reproduce it?

@ywwg
Copy link
Member

ywwg commented Oct 16, 2025

ok I'll take a look. I will be traveling after today for a week, so I will not be able to do any more testing. But in general, this worked great!

@acolombier
Copy link
Member Author

Do you reckon we could merge it? Worth to point out that this is going to main, so still alpha!

Copy link
Member

@ywwg ywwg left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree this is working really well so far and we can iterate on individual problems as they come up 🚀

@ywwg
Copy link
Member

ywwg commented Oct 20, 2025

I am so excited to show off the Mixxx logo on the S4 screens 😎


// Cast to float
float max = static_cast<float>(u8max);
float max = static_cast<float>(u8max) * allGain;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is this changed in a controller specific PR?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, this PR contains some minor tweaks and fix as well, but they are all contained into atomic commits.

@JoergAtGithub
Copy link
Member

Let's merge this! As one core dev has tested this successful and most of the code only affect this one controller.

@JoergAtGithub JoergAtGithub merged commit eff6c83 into mixxxdj:main Oct 22, 2025
28 of 29 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

controller backend controller mappings developer experience Issues, bugs and PRs related to the development process, development environment & developer docs needs review qml waveform

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants