From 2d9d9ee4137f4d51dce65cc8c15d2ab73ddf9368 Mon Sep 17 00:00:00 2001 From: Antoine C Date: Tue, 30 Jul 2024 22:34:17 +0100 Subject: [PATCH 1/8] feat: add the ability to load a single stem track This allows players such as sampler or preview deck to load a selected stem, instead of the main mix, as those players can only read stereo tracks --- src/analyzer/constants.h | 1 - src/engine/cachingreader/cachingreader.cpp | 11 +- src/engine/cachingreader/cachingreader.h | 7 +- .../cachingreader/cachingreaderworker.cpp | 34 +- .../cachingreader/cachingreaderworker.h | 24 +- src/engine/channels/enginedeck.cpp | 12 +- src/engine/engine.h | 4 + src/engine/enginebuffer.cpp | 14 +- src/engine/enginebuffer.h | 7 +- src/library/analysis/analysisfeature.cpp | 6 +- src/library/autodj/autodjprocessor.h | 12 +- src/library/autodj/dlgautodj.h | 6 +- src/library/library.cpp | 18 +- src/library/library.h | 13 +- src/library/librarycontrol.cpp | 51 ++- src/library/librarycontrol.h | 17 +- src/library/libraryfeature.h | 7 +- src/library/recording/dlgrecording.h | 6 +- .../tabledelegates/previewbuttondelegate.cpp | 6 +- .../tabledelegates/previewbuttondelegate.h | 7 +- src/mixer/basetrackplayer.cpp | 47 ++- src/mixer/basetrackplayer.h | 15 +- src/mixer/playermanager.cpp | 19 +- src/mixer/playermanager.h | 6 +- src/mixer/samplerbank.cpp | 7 +- src/sources/audiosource.h | 39 ++- src/sources/soundsourcestem.cpp | 21 +- src/test/autodjprocessor_test.cpp | 294 +++++++++++++++--- src/test/cuecontrol_test.cpp | 6 +- src/test/hotcuecontrol_test.cpp | 6 +- src/test/playermanagertest.cpp | 36 ++- src/test/signalpathtest.h | 6 +- src/track/track.h | 20 +- .../allshader/waveformrendererstem.cpp | 15 +- .../renderers/waveformwidgetrenderer.cpp | 9 + .../renderers/waveformwidgetrenderer.h | 12 + src/waveform/waveform.h | 1 + src/widget/wlibrarytableview.h | 7 +- src/widget/wtrackmenu.cpp | 111 +++++-- src/widget/wtrackmenu.h | 22 +- src/widget/wtracktableview.cpp | 11 +- src/widget/wtracktableview.h | 6 +- src/widget/wwaveformviewer.cpp | 12 + src/widget/wwaveformviewer.h | 4 + 44 files changed, 825 insertions(+), 170 deletions(-) diff --git a/src/analyzer/constants.h b/src/analyzer/constants.h index 42d84db7217..5e670a37dc0 100644 --- a/src/analyzer/constants.h +++ b/src/analyzer/constants.h @@ -10,7 +10,6 @@ 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 kMaxSupportedStems = 4; constexpr SINT kAnalysisFramesPerChunk = 4096; constexpr SINT kAnalysisSamplesPerChunk = kAnalysisFramesPerChunk * kAnalysisMaxChannels; diff --git a/src/engine/cachingreader/cachingreader.cpp b/src/engine/cachingreader/cachingreader.cpp index d2b868fa353..8f4d780d18d 100644 --- a/src/engine/cachingreader/cachingreader.cpp +++ b/src/engine/cachingreader/cachingreader.cpp @@ -205,7 +205,11 @@ CachingReaderChunkForOwner* CachingReader::lookupChunkAndFreshen(SINT chunkIndex } // Invoked from the UI thread!! +#ifdef __STEM__ +void CachingReader::newTrack(TrackPointer pTrack, uint stemIdx) { +#else void CachingReader::newTrack(TrackPointer pTrack) { +#endif auto newState = pTrack ? STATE_TRACK_LOADING : STATE_TRACK_UNLOADING; auto oldState = m_state.fetchAndStoreAcquire(newState); @@ -220,7 +224,12 @@ void CachingReader::newTrack(TrackPointer pTrack) { kLogger.warning() << "Loading a new track while loading a track may lead to inconsistent states"; } - m_worker.newTrack(std::move(pTrack)); + m_worker.newTrack(std::move(pTrack) +#ifdef __STEM__ + , + stemIdx +#endif + ); } // Called from the engine thread diff --git a/src/engine/cachingreader/cachingreader.h b/src/engine/cachingreader/cachingreader.h index 384f12a8047..97854f4cf7e 100644 --- a/src/engine/cachingreader/cachingreader.h +++ b/src/engine/cachingreader/cachingreader.h @@ -116,7 +116,12 @@ class CachingReader : public QObject { // Request that the CachingReader load a new track. These requests are // processed in the work thread, so the reader must be woken up via wake() // for this to take effect. - void newTrack(TrackPointer pTrack); + void newTrack(TrackPointer pTrack +#ifdef __STEM__ + , + uint stemIdx = 0 +#endif + ); void setScheduler(EngineWorkerScheduler* pScheduler) { m_worker.setScheduler(pScheduler); diff --git a/src/engine/cachingreader/cachingreaderworker.cpp b/src/engine/cachingreader/cachingreaderworker.cpp index cb4d12488e4..41d2583a783 100644 --- a/src/engine/cachingreader/cachingreaderworker.cpp +++ b/src/engine/cachingreader/cachingreaderworker.cpp @@ -92,10 +92,21 @@ ReaderStatusUpdate CachingReaderWorker::processReadRequest( } // WARNING: Always called from a different thread (GUI) -void CachingReaderWorker::newTrack(TrackPointer pTrack) { +void CachingReaderWorker::newTrack(TrackPointer pTrack +#ifdef __STEM__ + , + uint stemIdx +#endif +) { { const auto locker = lockMutex(&m_newTrackMutex); +#ifdef __STEM__ + m_pNewTrack = NewTrackRequest{ + pTrack, + stemIdx}; +#else m_pNewTrack = pTrack; +#endif m_newTrackAvailable.storeRelease(1); } workReady(); @@ -113,16 +124,25 @@ void CachingReaderWorker::run() { // Request is initialized by reading from FIFO CachingReaderChunkReadRequest request; if (m_newTrackAvailable.loadAcquire()) { +#ifdef __STEM__ + NewTrackRequest pLoadTrack; +#else TrackPointer pLoadTrack; +#endif { // locking scope const auto locker = lockMutex(&m_newTrackMutex); pLoadTrack = m_pNewTrack; - m_pNewTrack.reset(); m_newTrackAvailable.storeRelease(0); } // implicitly unlocks the mutex +#ifdef __STEM__ + if (pLoadTrack.track) { + // in this case the engine is still running with the old track + loadTrack(pLoadTrack.track, pLoadTrack.stemIdx); +#else if (pLoadTrack) { // in this case the engine is still running with the old track loadTrack(pLoadTrack); +#endif } else { // here, the engine is already stopped unloadTrack(); @@ -168,7 +188,12 @@ void CachingReaderWorker::unloadTrack() { m_pReaderStatusFIFO->writeBlocking(&update, 1); } -void CachingReaderWorker::loadTrack(const TrackPointer& pTrack) { +void CachingReaderWorker::loadTrack(const TrackPointer& pTrack +#ifdef __STEM__ + , + uint stemIdx +#endif +) { // This emit is directly connected and returns synchronized // after the engine has been stopped. emit trackLoading(); @@ -190,6 +215,9 @@ void CachingReaderWorker::loadTrack(const TrackPointer& pTrack) { mixxx::AudioSource::OpenParams config; config.setChannelCount(m_maxSupportedChannel); +#ifdef __STEM__ + config.setStemIdx(stemIdx); +#endif m_pAudioSource = SoundSourceProxy(pTrack).openAudioSource(config); if (!m_pAudioSource) { kLogger.warning() diff --git a/src/engine/cachingreader/cachingreaderworker.h b/src/engine/cachingreader/cachingreaderworker.h index a99bbb150a6..12e044cb048 100644 --- a/src/engine/cachingreader/cachingreaderworker.h +++ b/src/engine/cachingreader/cachingreaderworker.h @@ -104,7 +104,12 @@ class CachingReaderWorker : public EngineWorker { ~CachingReaderWorker() override = default; // Request to load a new track. wake() must be called afterwards. - void newTrack(TrackPointer pTrack); + void newTrack(TrackPointer pTrack +#ifdef __STEM__ + , + uint stemIdx +#endif + ); // Run upkeep operations like loading tracks and reading from file. Run by a // thread pool via the EngineWorkerScheduler. @@ -122,6 +127,12 @@ class CachingReaderWorker : public EngineWorker { void trackLoadFailed(TrackPointer pTrack, const QString& reason); private: +#ifdef __STEM__ + struct NewTrackRequest { + TrackPointer track; + uint stemIdx; + }; +#endif const QString m_group; QString m_tag; @@ -134,7 +145,11 @@ class CachingReaderWorker : public EngineWorker { // lock to touch. QMutex m_newTrackMutex; QAtomicInt m_newTrackAvailable; +#ifdef __STEM__ + NewTrackRequest m_pNewTrack; +#else TrackPointer m_pNewTrack; +#endif void discardAllPendingRequests(); @@ -147,7 +162,12 @@ class CachingReaderWorker : public EngineWorker { void unloadTrack(); /// Internal method to load a track. Emits trackLoaded when finished. - void loadTrack(const TrackPointer& pTrack); + void loadTrack(const TrackPointer& pTrack +#ifdef __STEM__ + , + uint stemIdx +#endif + ); ReaderStatusUpdate processReadRequest( const CachingReaderChunkReadRequest& request); diff --git a/src/engine/channels/enginedeck.cpp b/src/engine/channels/enginedeck.cpp index 09f2474e4b5..2a6c95a6b6f 100644 --- a/src/engine/channels/enginedeck.cpp +++ b/src/engine/channels/enginedeck.cpp @@ -12,8 +12,6 @@ #ifdef __STEM__ namespace { -constexpr int kMaxSupportedStems = 4; - QString getGroupForStem(const QString& deckGroup, int stemIdx) { DEBUG_ASSERT(deckGroup.endsWith("]")); return QStringLiteral("%1Stem%2]") @@ -72,9 +70,9 @@ EngineDeck::EngineDeck( m_pStemCount = std::make_unique(ConfigKey(getGroup(), "stem_count")); m_pStemCount->setReadOnly(); - m_stemGain.reserve(kMaxSupportedStems); - m_stemMute.reserve(kMaxSupportedStems); - for (int stemIdx = 1; stemIdx <= kMaxSupportedStems; stemIdx++) { + m_stemGain.reserve(mixxx::kMaxSupportedStems); + m_stemMute.reserve(mixxx::kMaxSupportedStems); + for (int stemIdx = 1; stemIdx <= mixxx::kMaxSupportedStems; stemIdx++) { m_stemGain.emplace_back(std::make_unique( ConfigKey(getGroupForStem(getGroup(), stemIdx), QStringLiteral("volume")))); // The default value is ignored and override with the medium value by @@ -96,7 +94,7 @@ void EngineDeck::slotTrackLoaded(TrackPointer pNewTrack, } if (m_pConfig->getValue( ConfigKey("[Mixer Profile]", "stem_auto_reset"), true)) { - for (int stemIdx = 0; stemIdx < kMaxSupportedStems; stemIdx++) { + for (int stemIdx = 0; stemIdx < mixxx::kMaxSupportedStems; stemIdx++) { m_stemGain[stemIdx]->set(1.0); m_stemMute[stemIdx]->set(0.0); ; @@ -150,7 +148,7 @@ void EngineDeck::cloneStemState(const EngineDeck* deckToClone) { VERIFY_OR_DEBUG_ASSERT(deckToClone) { return; } - for (int stemIdx = 0; stemIdx < kMaxSupportedStems; stemIdx++) { + for (int stemIdx = 0; stemIdx < mixxx::kMaxSupportedStems; stemIdx++) { m_stemGain[stemIdx]->set(deckToClone->m_stemGain[stemIdx]->get()); m_stemMute[stemIdx]->set(deckToClone->m_stemMute[stemIdx]->get()); } diff --git a/src/engine/engine.h b/src/engine/engine.h index 4df4ab6c270..9de33d6143c 100644 --- a/src/engine/engine.h +++ b/src/engine/engine.h @@ -8,6 +8,10 @@ static constexpr audio::ChannelCount kEngineChannelOutputCount = audio::ChannelCount::stereo(); static constexpr audio::ChannelCount kMaxEngineChannelInputCount = audio::ChannelCount::stem(); +#ifdef __STEM__ +constexpr int kMaxSupportedStems = 4; +constexpr uint kNoStemSelectedIdx = 0; +#endif // Contains the information needed to process a buffer of audio class EngineParameters final { diff --git a/src/engine/enginebuffer.cpp b/src/engine/enginebuffer.cpp index 4bfc4a3cf3a..07f2cbf3ed3 100644 --- a/src/engine/enginebuffer.cpp +++ b/src/engine/enginebuffer.cpp @@ -1540,12 +1540,22 @@ void EngineBuffer::hintReader(const double dRate) { } // WARNING: This method runs in the GUI thread -void EngineBuffer::loadTrack(TrackPointer pTrack, bool play, EngineChannel* pChannelToCloneFrom) { +void EngineBuffer::loadTrack(TrackPointer pTrack, +#ifdef __STEM__ + uint stemIdx, +#endif + bool play, + EngineChannel* pChannelToCloneFrom) { if (pTrack) { // Signal to the reader to load the track. The reader will respond with // trackLoading and then either with trackLoaded or trackLoadFailed signals. m_bPlayAfterLoading = play; - m_pReader->newTrack(pTrack); + m_pReader->newTrack(pTrack +#ifdef __STEM__ + , + stemIdx +#endif + ); atomicStoreRelaxed(m_pChannelToCloneFrom, pChannelToCloneFrom); } else { // Loading a null track means "eject" diff --git a/src/engine/enginebuffer.h b/src/engine/enginebuffer.h index 202d64dd5a5..a996a5dc7ef 100644 --- a/src/engine/enginebuffer.h +++ b/src/engine/enginebuffer.h @@ -215,7 +215,12 @@ class EngineBuffer : public EngineObject { // Request that the EngineBuffer load a track. Since the process is // asynchronous, EngineBuffer will emit a trackLoaded signal when the load // has completed. - void loadTrack(TrackPointer pTrack, bool play, EngineChannel* pChannelToCloneFrom); + void loadTrack(TrackPointer pTrack, +#ifdef __STEM__ + uint stemIdx, +#endif + bool play, + EngineChannel* pChannelToCloneFrom); void setChannelIndex(int channelIndex) { m_channelIndex = channelIndex; diff --git a/src/library/analysis/analysisfeature.cpp b/src/library/analysis/analysisfeature.cpp index a713f57ddfc..1ecb67efeba 100644 --- a/src/library/analysis/analysisfeature.cpp +++ b/src/library/analysis/analysisfeature.cpp @@ -81,7 +81,11 @@ void AnalysisFeature::bindLibraryWidget(WLibrary* libraryWidget, &DlgAnalysis::loadTrackToPlayer, this, [=, this](TrackPointer track, const QString& group) { - emit loadTrackToPlayer(track, group, false); + emit loadTrackToPlayer(track, group, +#ifdef __STEM__ + mixxx::kNoStemSelectedIdx, +#endif + false); }); connect(m_pAnalysisView, &DlgAnalysis::analyzeTracks, diff --git a/src/library/autodj/autodjprocessor.h b/src/library/autodj/autodjprocessor.h index 600cf7bfb70..38d0de3b67e 100644 --- a/src/library/autodj/autodjprocessor.h +++ b/src/library/autodj/autodjprocessor.h @@ -201,7 +201,11 @@ class AutoDJProcessor : public QObject { AutoDJError toggleAutoDJ(bool enable); signals: - void loadTrackToPlayer(TrackPointer pTrack, const QString& group, bool play); + void loadTrackToPlayer(TrackPointer pTrack, const QString& group, +#ifdef __STEM__ + uint stemIdx, +#endif + bool play); void autoDJStateChanged(AutoDJProcessor::AutoDJState state); void autoDJError(AutoDJProcessor::AutoDJError error); void transitionTimeChanged(int time); @@ -229,7 +233,11 @@ class AutoDJProcessor : public QObject { protected: // The following virtual signal wrappers are used for testing virtual void emitLoadTrackToPlayer(TrackPointer pTrack, const QString& group, bool play) { - emit loadTrackToPlayer(pTrack, group, play); + emit loadTrackToPlayer(pTrack, group, +#ifdef __STEM__ + mixxx::kNoStemSelectedIdx, +#endif + play); } virtual void emitAutoDJStateChanged(AutoDJProcessor::AutoDJState state) { emit autoDJStateChanged(state); diff --git a/src/library/autodj/dlgautodj.h b/src/library/autodj/dlgautodj.h index 9ac38a1e722..47a585f599a 100644 --- a/src/library/autodj/dlgautodj.h +++ b/src/library/autodj/dlgautodj.h @@ -49,7 +49,11 @@ class DlgAutoDJ : public QWidget, public Ui::DlgAutoDJ, public LibraryView { signals: void addRandomTrackButton(bool buttonChecked); void loadTrack(TrackPointer tio); - void loadTrackToPlayer(TrackPointer tio, const QString& group, bool); + void loadTrackToPlayer(TrackPointer tio, const QString& group, +#ifdef __STEM__ + uint stemIdx, +#endif + bool); void trackSelected(TrackPointer pTrack); private: diff --git a/src/library/library.cpp b/src/library/library.cpp index 21f82be564e..71bff659c0a 100644 --- a/src/library/library.cpp +++ b/src/library/library.cpp @@ -552,13 +552,25 @@ void Library::slotLoadLocationToPlayer(const QString& location, const QString& g auto trackRef = TrackRef::fromFilePath(location); TrackPointer pTrack = m_pTrackCollectionManager->getOrAddTrack(trackRef); if (pTrack) { - emit loadTrackToPlayer(pTrack, group, play); + emit loadTrackToPlayer(pTrack, group, +#ifdef __STEM__ + mixxx::kNoStemSelectedIdx, +#endif + play); } } void Library::slotLoadTrackToPlayer( - TrackPointer pTrack, const QString& group, bool play) { - emit loadTrackToPlayer(pTrack, group, play); + TrackPointer pTrack, const QString& group, +#ifdef __STEM__ + uint stemIdx, +#endif + bool play) { + emit loadTrackToPlayer(pTrack, group, +#ifdef __STEM__ + stemIdx, +#endif + play); } void Library::slotRefreshLibraryModels() { diff --git a/src/library/library.h b/src/library/library.h index e0190084eeb..a4a1bd61eee 100644 --- a/src/library/library.h +++ b/src/library/library.h @@ -114,7 +114,11 @@ class Library: public QObject { void slotShowTrackModel(QAbstractItemModel* model); void slotSwitchToView(const QString& view); void slotLoadTrack(TrackPointer pTrack); - void slotLoadTrackToPlayer(TrackPointer pTrack, const QString& group, bool play); + void slotLoadTrackToPlayer(TrackPointer pTrack, const QString& group, +#ifdef __STEM__ + uint stemIdx, +#endif + bool play); void slotLoadLocationToPlayer(const QString& location, const QString& group, bool play); void slotRefreshLibraryModels(); void slotCreatePlaylist(); @@ -127,7 +131,12 @@ class Library: public QObject { void showTrackModel(QAbstractItemModel* model, bool restoreState = true); void switchToView(const QString& view); void loadTrack(TrackPointer pTrack); - void loadTrackToPlayer(TrackPointer pTrack, const QString& group, bool play = false); + void loadTrackToPlayer(TrackPointer pTrack, + const QString& group, +#ifdef __STEM__ + uint stemIdx, +#endif + bool play = false); void restoreSearch(const QString&); void search(const QString& text); void disableSearch(); diff --git a/src/library/librarycontrol.cpp b/src/library/librarycontrol.cpp index 3d5e9cac1fa..b834946c132 100644 --- a/src/library/librarycontrol.cpp +++ b/src/library/librarycontrol.cpp @@ -38,6 +38,33 @@ LoadToGroupController::LoadToGroupController(LibraryControl* pParent, const QStr this, &LoadToGroupController::slotLoadToGroupAndPlay); +#ifdef __STEM__ + for (int stemIdx = 1; stemIdx <= mixxx::kMaxSupportedStems; stemIdx++) { + m_loadSelectedTrackStemAndPlay.emplace_back( + std::make_unique(ConfigKey(group, + QStringLiteral("load_selected_track_stem_%1_and_play").arg(stemIdx)))); + connect(m_loadSelectedTrackStemAndPlay.back().get(), + &ControlObject::valueChanged, + this, + [this, stemIdx](double value) { + if (value > 0) { + emit loadToGroup(m_group, stemIdx, true); + } + }); + m_loadSelectedTrackStem.emplace_back( + std::make_unique(ConfigKey(group, + QStringLiteral("load_selected_track_stem_%1").arg(stemIdx)))); + connect(m_loadSelectedTrackStem.back().get(), + &ControlObject::valueChanged, + this, + [this, stemIdx](double value) { + if (value > 0) { + emit loadToGroup(m_group, stemIdx, false); + } + }); + } +#endif + connect(this, &LoadToGroupController::loadToGroup, pParent, @@ -48,13 +75,21 @@ LoadToGroupController::~LoadToGroupController() = default; void LoadToGroupController::slotLoadToGroup(double v) { if (v > 0) { - emit loadToGroup(m_group, false); + emit loadToGroup(m_group, +#ifdef __STEM__ + mixxx::kNoStemSelectedIdx, +#endif + false); } } void LoadToGroupController::slotLoadToGroupAndPlay(double v) { if (v > 0) { - emit loadToGroup(m_group, true); + emit loadToGroup(m_group, +#ifdef __STEM__ + mixxx::kNoStemSelectedIdx, +#endif + true); } } @@ -600,14 +635,22 @@ void LibraryControl::slotUpdateTrackMenuControl(bool visible) { m_pShowTrackMenu->setAndConfirm(visible ? 1.0 : 0.0); } -void LibraryControl::slotLoadSelectedTrackToGroup(const QString& group, bool play) { +void LibraryControl::slotLoadSelectedTrackToGroup(const QString& group, +#ifdef __STEM__ + uint stemIdx, +#endif + bool play) { if (!m_pLibraryWidget) { return; } WTrackTableView* pTrackTableView = m_pLibraryWidget->getCurrentTrackTableView(); if (pTrackTableView) { - pTrackTableView->loadSelectedTrackToGroup(group, play); + pTrackTableView->loadSelectedTrackToGroup(group, +#ifdef __STEM__ + stemIdx, +#endif + play); } } diff --git a/src/library/librarycontrol.h b/src/library/librarycontrol.h index 65e21013ea4..d0557269a8c 100644 --- a/src/library/librarycontrol.h +++ b/src/library/librarycontrol.h @@ -23,7 +23,11 @@ class LoadToGroupController : public QObject { virtual ~LoadToGroupController(); signals: - void loadToGroup(const QString& group, bool); + void loadToGroup(const QString& group, +#ifdef __STEM__ + uint stemIdx, +#endif + bool); public slots: void slotLoadToGroup(double v); @@ -33,6 +37,11 @@ class LoadToGroupController : public QObject { const QString m_group; std::unique_ptr m_pLoadControl; std::unique_ptr m_pLoadAndPlayControl; + +#ifdef __STEM__ + std::vector> m_loadSelectedTrackStemAndPlay; + std::vector> m_loadSelectedTrackStem; +#endif }; class LibraryControl : public QObject { @@ -54,7 +63,11 @@ class LibraryControl : public QObject { public slots: // Deprecated navigation slots - void slotLoadSelectedTrackToGroup(const QString& group, bool play); + void slotLoadSelectedTrackToGroup(const QString& group, +#ifdef __STEM__ + uint stemIdx, +#endif + bool play); void slotUpdateTrackMenuControl(bool visible); private slots: diff --git a/src/library/libraryfeature.h b/src/library/libraryfeature.h index 61972192dcd..2ceaffbe619 100644 --- a/src/library/libraryfeature.h +++ b/src/library/libraryfeature.h @@ -135,7 +135,12 @@ class LibraryFeature : public QObject { void showTrackModel(QAbstractItemModel* model, bool restoreState = true); void switchToView(const QString& view); void loadTrack(TrackPointer pTrack); - void loadTrackToPlayer(TrackPointer pTrack, const QString& group, bool play = false); + void loadTrackToPlayer(TrackPointer pTrack, + const QString& group, +#ifdef __STEM__ + uint stemIdx, +#endif + bool play = false); /// saves the scroll, selection and current state of the library model void saveModelState(); /// restores the scroll, selection and current state of the library model diff --git a/src/library/recording/dlgrecording.h b/src/library/recording/dlgrecording.h index 8d715056319..8cd3d741021 100644 --- a/src/library/recording/dlgrecording.h +++ b/src/library/recording/dlgrecording.h @@ -37,7 +37,11 @@ class DlgRecording : public QWidget, public Ui::DlgRecording, public virtual Lib signals: void loadTrack(TrackPointer tio); - void loadTrackToPlayer(TrackPointer tio, const QString& group, bool play); + void loadTrackToPlayer(TrackPointer tio, const QString& group, +#ifdef __STEM__ + uint stemIdx, +#endif + bool play); void restoreSearch(const QString& search); void restoreModelState(); diff --git a/src/library/tabledelegates/previewbuttondelegate.cpp b/src/library/tabledelegates/previewbuttondelegate.cpp index 87c897ec95f..1c8a2c1d910 100644 --- a/src/library/tabledelegates/previewbuttondelegate.cpp +++ b/src/library/tabledelegates/previewbuttondelegate.cpp @@ -220,7 +220,11 @@ void PreviewButtonDelegate::buttonClicked() { TrackPointer pTrack = pTrackModel->getTrack(m_currentEditedCellIndex); if (pTrack && pTrack != pOldTrack) { // Load to preview deck and start playing - emit loadTrackToPlayer(pTrack, kPreviewDeckGroup, true); + emit loadTrackToPlayer(pTrack, kPreviewDeckGroup, +#ifdef __STEM__ + mixxx::kNoStemSelectedIdx, +#endif + true); startedPlaying = true; } else if (pTrack == pOldTrack && !isPreviewDeckPlaying()) { // Since the Preview deck might be hidden, starting at the main cue diff --git a/src/library/tabledelegates/previewbuttondelegate.h b/src/library/tabledelegates/previewbuttondelegate.h index a42b206bc12..7f50caddb59 100644 --- a/src/library/tabledelegates/previewbuttondelegate.h +++ b/src/library/tabledelegates/previewbuttondelegate.h @@ -54,7 +54,12 @@ class PreviewButtonDelegate : public TableItemDelegate { const QModelIndex& index) const override; signals: - void loadTrackToPlayer(const TrackPointer& pTrack, const QString& group, bool play); + void loadTrackToPlayer(const TrackPointer& pTrack, + const QString& group, +#ifdef __STEM__ + uint stemIdx, +#endif + bool play); void buttonSetChecked(bool); public slots: diff --git a/src/mixer/basetrackplayer.cpp b/src/mixer/basetrackplayer.cpp index e6b9d87a744..55c0cfaf3a7 100644 --- a/src/mixer/basetrackplayer.cpp +++ b/src/mixer/basetrackplayer.cpp @@ -24,7 +24,6 @@ namespace { constexpr double kNoTrackColor = -1; constexpr double kShiftCuesOffsetMillis = 10; constexpr double kShiftCuesOffsetSmallMillis = 1; -constexpr int kMaxSupportedStems = 4; const QString kEffectGroupFormat = QStringLiteral("[EqualizerRack1_%1_Effect1]"); inline double trackColorToDouble(mixxx::RgbColor::optional_t color) { @@ -285,9 +284,9 @@ BaseTrackPlayerImpl::BaseTrackPlayerImpl( } #ifdef __STEM__ - m_pStemColors.reserve(kMaxSupportedStems); + m_pStemColors.reserve(mixxx::kMaxSupportedStems); QString group = getGroup(); - for (int stemIdx = 1; stemIdx <= kMaxSupportedStems; stemIdx++) { + for (int stemIdx = 1; stemIdx <= mixxx::kMaxSupportedStems; stemIdx++) { QString stemGroup = QStringLiteral("%1Stem%2]") .arg(group.left(group.size() - 1), QString::number(stemIdx)); @@ -416,7 +415,11 @@ void BaseTrackPlayerImpl::slotEjectTrack(double v) { if (elapsed < mixxx::Duration::fromMillis(kUnreplaceDelay)) { TrackPointer lastEjected = m_pPlayerManager->getSecondLastEjectedTrack(); if (lastEjected) { - slotLoadTrack(lastEjected, false); + slotLoadTrack(lastEjected, +#ifdef __STEM__ + mixxx::kNoStemSelectedIdx, +#endif + false); } return; } @@ -425,7 +428,11 @@ void BaseTrackPlayerImpl::slotEjectTrack(double v) { if (!m_pLoadedTrack) { TrackPointer lastEjected = m_pPlayerManager->getLastEjectedTrack(); if (lastEjected) { - slotLoadTrack(lastEjected, false); + slotLoadTrack(lastEjected, +#ifdef __STEM__ + mixxx::kNoStemSelectedIdx, +#endif + false); } return; } @@ -539,7 +546,11 @@ void BaseTrackPlayerImpl::disconnectLoadedTrack() { disconnect(m_pLoadedTrack.get(), nullptr, m_pKey.get(), nullptr); } -void BaseTrackPlayerImpl::slotLoadTrack(TrackPointer pNewTrack, bool bPlay) { +void BaseTrackPlayerImpl::slotLoadTrack(TrackPointer pNewTrack, +#ifdef __STEM__ + uint stemIdx, +#endif + bool bPlay) { //qDebug() << "BaseTrackPlayerImpl::slotLoadTrack" << getGroup() << pNewTrack.get(); // Before loading the track, ensure we have access. This uses lazy // evaluation to make sure track isn't NULL before we dereference it. @@ -562,7 +573,17 @@ void BaseTrackPlayerImpl::slotLoadTrack(TrackPointer pNewTrack, bool bPlay) { // Request a new track from EngineBuffer EngineBuffer* pEngineBuffer = m_pChannel->getEngineBuffer(); +#ifdef __STEM__ + pEngineBuffer->loadTrack(pNewTrack, + stemIdx, + bPlay, + m_pChannelToCloneFrom); + + // Select a specific stem if requested + emit selectedStem(stemIdx); +#else pEngineBuffer->loadTrack(pNewTrack, bPlay, m_pChannelToCloneFrom); +#endif } void BaseTrackPlayerImpl::slotLoadFailed(TrackPointer pTrack, const QString& reason) { @@ -694,7 +715,7 @@ void BaseTrackPlayerImpl::slotTrackLoaded(TrackPointer pNewTrack, #ifdef __STEM__ if (m_pStemColors.size()) { const auto& stemInfo = m_pLoadedTrack->getStemInfo(); - DEBUG_ASSERT(stemInfo.size() <= kMaxSupportedStems); + DEBUG_ASSERT(stemInfo.size() <= mixxx::kMaxSupportedStems); int stemIdx = 0; for (const auto& stemColorCo : m_pStemColors) { auto color = kNoTrackColor; @@ -773,7 +794,11 @@ void BaseTrackPlayerImpl::slotCloneChannel(EngineChannel* pChannel) { m_pChannelToCloneFrom = pChannel; bool play = ControlObject::toBool(ConfigKey(m_pChannelToCloneFrom->getGroup(), "play")); - slotLoadTrack(pTrack, play); + slotLoadTrack(pTrack, +#ifdef __STEM__ + mixxx::kNoStemSelectedIdx, +#endif + play); } void BaseTrackPlayerImpl::slotLoadTrackFromDeck(double d) { @@ -797,7 +822,11 @@ void BaseTrackPlayerImpl::loadTrackFromGroup(const QString& group) { return; } - slotLoadTrack(pTrack, false); + slotLoadTrack(pTrack, +#ifdef __STEM__ + mixxx::kNoStemSelectedIdx, +#endif + false); } bool BaseTrackPlayerImpl::isTrackMenuControlAvailable() { diff --git a/src/mixer/basetrackplayer.h b/src/mixer/basetrackplayer.h index 048455edfec..8c6b3812e3c 100644 --- a/src/mixer/basetrackplayer.h +++ b/src/mixer/basetrackplayer.h @@ -45,7 +45,11 @@ class BaseTrackPlayer : public BasePlayer { }; public slots: - virtual void slotLoadTrack(TrackPointer pTrack, bool bPlay = false) = 0; + virtual void slotLoadTrack(TrackPointer pTrack, +#ifdef __STEM__ + uint stemIdx, +#endif + bool bPlay = false) = 0; virtual void slotCloneFromGroup(const QString& group) = 0; virtual void slotCloneDeck() = 0; virtual void slotEjectTrack(double) = 0; @@ -56,6 +60,9 @@ class BaseTrackPlayer : public BasePlayer { void newTrackLoaded(TrackPointer pLoadedTrack); void trackUnloaded(TrackPointer pUnloadedTrack); void loadingTrack(TrackPointer pNewTrack, TrackPointer pOldTrack); +#ifdef __STEM__ + void selectedStem(uint stemIdx); +#endif void playerEmpty(); void noVinylControlInputConfigured(); void trackRatingChanged(int rating); @@ -93,7 +100,11 @@ class BaseTrackPlayerImpl : public BaseTrackPlayer { TrackPointer loadFakeTrack(bool bPlay, double filebpm); public slots: - void slotLoadTrack(TrackPointer track, bool bPlay) final; + void slotLoadTrack(TrackPointer track, +#ifdef __STEM__ + uint stemIdx, +#endif + bool bPlay) final; void slotEjectTrack(double) final; void slotCloneFromGroup(const QString& group) final; void slotCloneDeck() final; diff --git a/src/mixer/playermanager.cpp b/src/mixer/playermanager.cpp index a4f0f1ea15e..f5a4ad240d6 100644 --- a/src/mixer/playermanager.cpp +++ b/src/mixer/playermanager.cpp @@ -660,7 +660,12 @@ void PlayerManager::slotCloneDeck(const QString& source_group, const QString& ta pPlayer->slotCloneFromGroup(source_group); } -void PlayerManager::slotLoadTrackToPlayer(TrackPointer pTrack, const QString& group, bool play) { +void PlayerManager::slotLoadTrackToPlayer( + TrackPointer pTrack, const QString& group, +#ifdef __STEM__ + uint stemIdx, +#endif + bool play) { // Do not lock mutex in this method unless it is changed to access // PlayerManager state. BaseTrackPlayer* pPlayer = getPlayer(group); @@ -711,7 +716,11 @@ void PlayerManager::slotLoadTrackToPlayer(TrackPointer pTrack, const QString& gr if (clone) { pPlayer->slotCloneDeck(); } else { - pPlayer->slotLoadTrack(pTrack, play); + pPlayer->slotLoadTrack(pTrack, +#ifdef __STEM__ + stemIdx, +#endif + play); } m_lastLoadedPlayer = group; @@ -763,7 +772,11 @@ void PlayerManager::slotLoadTrackIntoNextAvailableDeck(TrackPointer pTrack) { return; } - pDeck->slotLoadTrack(pTrack, false); + pDeck->slotLoadTrack(pTrack, +#ifdef __STEM__ + mixxx::kNoStemSelectedIdx, +#endif + false); } void PlayerManager::slotLoadLocationIntoNextAvailableDeck(const QString& location, bool play) { diff --git a/src/mixer/playermanager.h b/src/mixer/playermanager.h index cbd74d31787..4641694ddd1 100644 --- a/src/mixer/playermanager.h +++ b/src/mixer/playermanager.h @@ -185,7 +185,11 @@ class PlayerManager : public QObject, public PlayerManagerInterface { public slots: // Slots for loading tracks into a Player, which is either a Sampler or a Deck - void slotLoadTrackToPlayer(TrackPointer pTrack, const QString& group, bool play); + void slotLoadTrackToPlayer(TrackPointer pTrack, const QString& group, +#ifdef __STEM__ + uint stemIdx, +#endif + bool play); void slotLoadLocationToPlayer(const QString& location, const QString& group, bool play); void slotLoadLocationToPlayerMaybePlay(const QString& location, const QString& group); diff --git a/src/mixer/samplerbank.cpp b/src/mixer/samplerbank.cpp index 4e03f6cdea7..2ceaf70704e 100644 --- a/src/mixer/samplerbank.cpp +++ b/src/mixer/samplerbank.cpp @@ -212,7 +212,12 @@ bool SamplerBank::loadSamplerBankFromPath(const QString& samplerBankPath) { } if (location.isEmpty()) { - m_pPlayerManager->slotLoadTrackToPlayer(TrackPointer(), group, false); + m_pPlayerManager->slotLoadTrackToPlayer( + TrackPointer(), group, +#ifdef __STEM__ + mixxx::kNoStemSelectedIdx, +#endif + false); } else { m_pPlayerManager->slotLoadLocationToPlayer(location, group, false); } diff --git a/src/sources/audiosource.h b/src/sources/audiosource.h index 8c007848d23..4284bff1b56 100644 --- a/src/sources/audiosource.h +++ b/src/sources/audiosource.h @@ -193,24 +193,56 @@ class AudioSource : public UrlResource, public virtual /*implements*/ IAudioSour // Parameters for opening audio sources class OpenParams { public: +#ifdef __STEM__ + OpenParams() + : m_signalInfo(), m_stemIdx(mixxx::kNoStemSelectedIdx) { + } +#else OpenParams() = default; +#endif OpenParams( audio::ChannelCount channelCount, - audio::SampleRate sampleRate) + audio::SampleRate sampleRate +#ifdef __STEM__ + , + uint stemIdx = mixxx::kNoStemSelectedIdx +#endif + ) : m_signalInfo( channelCount, - sampleRate) { + sampleRate) +#ifdef __STEM__ + , + m_stemIdx(stemIdx) +#endif + { } const audio::SignalInfo& getSignalInfo() const { return m_signalInfo; } +#ifdef __STEM__ + uint stemIdx() const { + return m_stemIdx; + } +#endif + void setChannelCount( audio::ChannelCount channelCount) { m_signalInfo.setChannelCount(channelCount); } +#ifdef __STEM__ + void setStemIdx( + uint stemIdx) { + VERIFY_OR_DEBUG_ASSERT(stemIdx <= mixxx::kMaxSupportedStems) { + return; + } + m_stemIdx = stemIdx; + } +#endif + void setSampleRate( audio::SampleRate sampleRate) { m_signalInfo.setSampleRate(sampleRate); @@ -218,6 +250,9 @@ class AudioSource : public UrlResource, public virtual /*implements*/ IAudioSour private: audio::SignalInfo m_signalInfo; +#ifdef __STEM__ + uint m_stemIdx; +#endif }; // Opens the AudioSource for reading audio data. diff --git a/src/sources/soundsourcestem.cpp b/src/sources/soundsourcestem.cpp index 76105135f2d..c4e6edef9d9 100644 --- a/src/sources/soundsourcestem.cpp +++ b/src/sources/soundsourcestem.cpp @@ -323,6 +323,12 @@ SoundSource::OpenResult SoundSourceSTEM::tryOpen( AVStream* firstAudioStream = nullptr; int stemCount = 0; + uint selectedStem = params.stemIdx(); + VERIFY_OR_DEBUG_ASSERT(selectedStem <= mixxx::kMaxSupportedStems) { + kLogger.warning().noquote() + << "Invalid selected stem Idx" << selectedStem; + return OpenResult::Failed; + } OpenParams stemParam = params; stemParam.setChannelCount(mixxx::audio::ChannelCount::stereo()); for (unsigned int streamIdx = 0; streamIdx < pavInputFormatContext->nb_streams; streamIdx++) { @@ -365,6 +371,10 @@ SoundSource::OpenResult SoundSourceSTEM::tryOpen( stemCount++; } + if (selectedStem && selectedStem != streamIdx) { + continue; + } + m_pStereoStreams.emplace_back(std::make_unique(getUrl(), streamIdx)); if (m_pStereoStreams.back()->open(OpenMode::Strict /*Unused*/, stemParam) != OpenResult::Succeeded) { @@ -380,7 +390,9 @@ SoundSource::OpenResult SoundSourceSTEM::tryOpen( return OpenResult::Failed; } - if (params.getSignalInfo().getChannelCount() == mixxx::audio::ChannelCount::stereo()) { + if (params.getSignalInfo().getChannelCount() == + mixxx::audio::ChannelCount::stereo() || + selectedStem) { // Requesting a stereo stream (used for samples and preview decks) m_requestedChannelCount = mixxx::audio::ChannelCount::stereo(); initChannelCountOnce(mixxx::audio::ChannelCount::stereo()); @@ -434,12 +446,17 @@ ReadableSampleFrames SoundSourceSTEM::readSampleFramesClamped( int stemCount = m_pStereoStreams.size(); CSAMPLE* pBuffer = globalSampleFrames.writableData(); - if (m_requestedChannelCount == mixxx::audio::ChannelCount::stereo()) { + if (m_requestedChannelCount == mixxx::audio::ChannelCount::stereo() && stemCount != 1) { SampleUtil::clear(pBuffer, globalSampleFrames.writableLength()); } else { DEBUG_ASSERT(stemSampleLength * stemCount == globalSampleFrames.writableLength()); } + if (stemCount == 1) { + m_pStereoStreams[0]->readSampleFrames(globalSampleFrames); + return read; + } + for (int streamIdx = 0; streamIdx < stemCount; streamIdx++) { WritableSampleFrames currentStemFrame = WritableSampleFrames( globalSampleFrames.frameIndexRange(), diff --git a/src/test/autodjprocessor_test.cpp b/src/test/autodjprocessor_test.cpp index 4cebd3b7b9b..254bb1ad9a7 100644 --- a/src/test/autodjprocessor_test.cpp +++ b/src/test/autodjprocessor_test.cpp @@ -94,7 +94,11 @@ class FakeDeck : public BaseTrackPlayer { // a success or failure signal. To simulate a load success, call // fakeTrackLoadedEvent. To simulate a failure, call // fakeTrackLoadFailedEvent. - void slotLoadTrack(TrackPointer pTrack, bool bPlay) override { + void slotLoadTrack(TrackPointer pTrack, +#ifdef __STEM__ + uint, +#endif + bool bPlay) override { loadedTrack = pTrack; samplerate.set(pTrack->getSampleRate()); play.set(bPlay); @@ -263,7 +267,11 @@ TEST_F(AutoDJProcessorTest, FullIntroOutro_LongerIntro) { // Pretend that track is 1 minute and 40 seconds long. pTrack->setDuration(100); // Load track and mark it playing. - deck1.slotLoadTrack(pTrack, true); + deck1.slotLoadTrack(pTrack, +#ifdef __STEM__ + mixxx::kNoStemSelectedIdx, +#endif + true); // Indicate the track loaded successfully. deck1.fakeTrackLoadedEvent(pTrack); @@ -280,7 +288,11 @@ TEST_F(AutoDJProcessorTest, FullIntroOutro_LongerIntro) { EXPECT_EQ(AutoDJProcessor::ADJ_IDLE, pProcessor->getState()); // Pretend the track load succeeds. - deck2.slotLoadTrack(pTrack, false); + deck2.slotLoadTrack(pTrack, +#ifdef __STEM__ + mixxx::kNoStemSelectedIdx, +#endif + false); // Set intro + outro cues. Outro is 10 seconds long; intro is 30 seconds. const double kSamplesPerSecond = kChannelCount * pTrack->getSampleRate(); @@ -337,7 +349,11 @@ TEST_F(AutoDJProcessorTest, FullIntroOutro_LongerOutro) { // Pretend that track is 1 minute and 40 seconds long. pTrack->setDuration(100); // Load track and mark it playing. - deck1.slotLoadTrack(pTrack, true); + deck1.slotLoadTrack(pTrack, +#ifdef __STEM__ + mixxx::kNoStemSelectedIdx, +#endif + true); // Indicate the track loaded successfully. deck1.fakeTrackLoadedEvent(pTrack); @@ -354,7 +370,11 @@ TEST_F(AutoDJProcessorTest, FullIntroOutro_LongerOutro) { EXPECT_EQ(AutoDJProcessor::ADJ_IDLE, pProcessor->getState()); // Pretend the track load succeeds. - deck2.slotLoadTrack(pTrack, false); + deck2.slotLoadTrack(pTrack, +#ifdef __STEM__ + mixxx::kNoStemSelectedIdx, +#endif + false); // Set intro + outro cues. Outro is 20 seconds long; intro is 10 seconds. const double kSamplesPerSecond = kChannelCount * pTrack->getSampleRate(); @@ -417,7 +437,11 @@ TEST_F(AutoDJProcessorTest, FadeAtOutroStart_LongerIntro) { // Pretend that track is 1 minute and 40 seconds long. pTrack->setDuration(100); // Load track and mark it playing. - deck1.slotLoadTrack(pTrack, true); + deck1.slotLoadTrack(pTrack, +#ifdef __STEM__ + mixxx::kNoStemSelectedIdx, +#endif + true); // Indicate the track loaded successfully. deck1.fakeTrackLoadedEvent(pTrack); @@ -434,7 +458,11 @@ TEST_F(AutoDJProcessorTest, FadeAtOutroStart_LongerIntro) { EXPECT_EQ(AutoDJProcessor::ADJ_IDLE, pProcessor->getState()); // Pretend the track load succeeds. - deck2.slotLoadTrack(pTrack, false); + deck2.slotLoadTrack(pTrack, +#ifdef __STEM__ + mixxx::kNoStemSelectedIdx, +#endif + false); // Set intro + outro cues. Outro is 10 seconds long; intro is 20 seconds. const double kSamplesPerSecond = kChannelCount * pTrack->getSampleRate(); @@ -493,7 +521,11 @@ TEST_F(AutoDJProcessorTest, FadeAtOutroStart_LongerOutro) { // Pretend that track is 1 minute and 40 seconds long. pTrack->setDuration(100); // Load track and mark it playing. - deck1.slotLoadTrack(pTrack, true); + deck1.slotLoadTrack(pTrack, +#ifdef __STEM__ + mixxx::kNoStemSelectedIdx, +#endif + true); // Indicate the track loaded successfully. deck1.fakeTrackLoadedEvent(pTrack); @@ -510,7 +542,11 @@ TEST_F(AutoDJProcessorTest, FadeAtOutroStart_LongerOutro) { EXPECT_EQ(AutoDJProcessor::ADJ_IDLE, pProcessor->getState()); // Pretend the track load succeeds. - deck2.slotLoadTrack(pTrack, false); + deck2.slotLoadTrack(pTrack, +#ifdef __STEM__ + mixxx::kNoStemSelectedIdx, +#endif + false); // Set intro + outro cues. Outro is 20 seconds long; intro is 10 seconds. const double kSamplesPerSecond = kChannelCount * pTrack->getSampleRate(); @@ -640,7 +676,11 @@ TEST_F(AutoDJProcessorTest, EnabledSuccess_DecksStopped) { // Load the track and mark it playing (as the loadTrackToPlayer signal would // have connected to this eventually). TrackPointer pTrack = trackCollectionManager()->getTrackById(testId); - deck1.slotLoadTrack(pTrack, true); + deck1.slotLoadTrack(pTrack, +#ifdef __STEM__ + mixxx::kNoStemSelectedIdx, +#endif + true); // Signal that the request to load pTrack succeeded. deck1.fakeTrackLoadedEvent(pTrack); @@ -686,7 +726,11 @@ TEST_F(AutoDJProcessorTest, EnabledSuccess_DecksStopped_TrackLoadFails) { // Load the track and mark it playing (as the loadTrackToPlayer signal would // have connected to this eventually). TrackPointer pTrack(newTestTrack(testId)); - deck1.slotLoadTrack(pTrack, true); + deck1.slotLoadTrack(pTrack, +#ifdef __STEM__ + mixxx::kNoStemSelectedIdx, +#endif + true); // Signal that the request to load pTrack failed. deck1.fakeTrackLoadFailedEvent(pTrack); @@ -704,7 +748,11 @@ TEST_F(AutoDJProcessorTest, EnabledSuccess_DecksStopped_TrackLoadFails) { EXPECT_DOUBLE_EQ(0.0, deck2.play.get()); // Now pretend that the follow-up load request succeeded. - deck1.slotLoadTrack(pTrack, true); + deck1.slotLoadTrack(pTrack, +#ifdef __STEM__ + mixxx::kNoStemSelectedIdx, +#endif + true); deck1.fakeTrackLoadedEvent(pTrack); // Expect that we will receive a load call for [Channel2] after we get the @@ -752,7 +800,11 @@ TEST_F(AutoDJProcessorTest, EnabledSuccess_DecksStopped_TrackLoadFailsRightDeck) // Load the track and mark it playing (as the loadTrackToPlayer signal would // have connected to this eventually). TrackPointer pTrack(newTestTrack(testId)); - deck1.slotLoadTrack(pTrack, true); + deck1.slotLoadTrack(pTrack, +#ifdef __STEM__ + mixxx::kNoStemSelectedIdx, +#endif + true); // Signal that the request to load pTrack to deck1 succeeded. deck1.fakeTrackLoadedEvent(pTrack); @@ -776,14 +828,22 @@ TEST_F(AutoDJProcessorTest, EnabledSuccess_DecksStopped_TrackLoadFailsRightDeck) EXPECT_CALL(*pProcessor, emitLoadTrackToPlayer(_, QString("[Channel2]"), false)); // Now pretend that the deck2 load request failed. - deck2.slotLoadTrack(pTrack, false); + deck2.slotLoadTrack(pTrack, +#ifdef __STEM__ + mixxx::kNoStemSelectedIdx, +#endif + false); deck2.fakeTrackLoadFailedEvent(pTrack); // Check that we are still in ADJ_IDLE mode. EXPECT_EQ(AutoDJProcessor::ADJ_IDLE, pProcessor->getState()); // Pretend the deck2 load request succeeded. - deck2.slotLoadTrack(pTrack, false); + deck2.slotLoadTrack(pTrack, +#ifdef __STEM__ + mixxx::kNoStemSelectedIdx, +#endif + false); deck2.fakeTrackLoadedEvent(pTrack); // Check that we are still in ADJ_IDLE mode and the left deck is playing. @@ -800,7 +860,11 @@ TEST_F(AutoDJProcessorTest, EnabledSuccess_PlayingDeck1) { // Pretend a track is playing on deck 1. TrackPointer pTrack = newTestTrack(); // Load track and mark it playing. - deck1.slotLoadTrack(pTrack, true); + deck1.slotLoadTrack(pTrack, +#ifdef __STEM__ + mixxx::kNoStemSelectedIdx, +#endif + true); // Indicate the track loaded successfully. deck1.fakeTrackLoadedEvent(pTrack); @@ -822,7 +886,11 @@ TEST_F(AutoDJProcessorTest, EnabledSuccess_PlayingDeck1) { EXPECT_DOUBLE_EQ(0.0, deck2.play.get()); // Pretend the track load succeeds. - deck2.slotLoadTrack(pTrack, false); + deck2.slotLoadTrack(pTrack, +#ifdef __STEM__ + mixxx::kNoStemSelectedIdx, +#endif + false); deck2.fakeTrackLoadedEvent(pTrack); // No change to the mode, crossfader or play states. @@ -839,7 +907,11 @@ TEST_F(AutoDJProcessorTest, EnabledSuccess_PlayingDeck1_TrackLoadFailed) { // Pretend a track is playing on deck 1. TrackPointer pTrack = newTestTrack(); // Load track and mark it playing. - deck1.slotLoadTrack(pTrack, true); + deck1.slotLoadTrack(pTrack, +#ifdef __STEM__ + mixxx::kNoStemSelectedIdx, +#endif + true); // Indicate the track loaded successfully. deck1.fakeTrackLoadedEvent(pTrack); @@ -868,7 +940,11 @@ TEST_F(AutoDJProcessorTest, EnabledSuccess_PlayingDeck1_TrackLoadFailed) { EXPECT_CALL(*pProcessor, emitLoadTrackToPlayer(_, QString("[Channel2]"), false)); // Pretend the track load fails. - deck2.slotLoadTrack(pTrack, false); + deck2.slotLoadTrack(pTrack, +#ifdef __STEM__ + mixxx::kNoStemSelectedIdx, +#endif + false); deck2.fakeTrackLoadFailedEvent(pTrack); // No change to the mode, crossfader, or play states. @@ -878,7 +954,11 @@ TEST_F(AutoDJProcessorTest, EnabledSuccess_PlayingDeck1_TrackLoadFailed) { EXPECT_DOUBLE_EQ(0.0, deck2.play.get()); // Pretend the track load succeeds. - deck2.slotLoadTrack(pTrack, false); + deck2.slotLoadTrack(pTrack, +#ifdef __STEM__ + mixxx::kNoStemSelectedIdx, +#endif + false); deck2.fakeTrackLoadedEvent(pTrack); // No change to the mode, crossfader, or play states. @@ -895,7 +975,11 @@ TEST_F(AutoDJProcessorTest, EnabledSuccess_PlayingDeck2) { // Pretend a track is playing on deck 2. TrackPointer pTrack = newTestTrack(); // Load track and mark it playing. - deck2.slotLoadTrack(pTrack, true); + deck2.slotLoadTrack(pTrack, +#ifdef __STEM__ + mixxx::kNoStemSelectedIdx, +#endif + true); // Indicate the track loaded successfully. deck2.fakeTrackLoadedEvent(pTrack); @@ -918,7 +1002,11 @@ TEST_F(AutoDJProcessorTest, EnabledSuccess_PlayingDeck2) { EXPECT_DOUBLE_EQ(1.0, deck2.play.get()); // Pretend the track load succeeds. - deck1.slotLoadTrack(pTrack, false); + deck1.slotLoadTrack(pTrack, +#ifdef __STEM__ + mixxx::kNoStemSelectedIdx, +#endif + false); deck1.fakeTrackLoadedEvent(pTrack); // No change to the mode, crossfader or play states. @@ -935,7 +1023,11 @@ TEST_F(AutoDJProcessorTest, EnabledSuccess_PlayingDeck2_TrackLoadFailed) { // Pretend a track is playing on deck 2. TrackPointer pTrack = newTestTrack(); // Load track and mark it playing. - deck2.slotLoadTrack(pTrack, true); + deck2.slotLoadTrack(pTrack, +#ifdef __STEM__ + mixxx::kNoStemSelectedIdx, +#endif + true); // Indicate the track loaded successfully. deck2.fakeTrackLoadedEvent(pTrack); @@ -964,7 +1056,11 @@ TEST_F(AutoDJProcessorTest, EnabledSuccess_PlayingDeck2_TrackLoadFailed) { EXPECT_CALL(*pProcessor, emitLoadTrackToPlayer(_, QString("[Channel1]"), false)); // Pretend the track load fails. - deck1.slotLoadTrack(pTrack, false); + deck1.slotLoadTrack(pTrack, +#ifdef __STEM__ + mixxx::kNoStemSelectedIdx, +#endif + false); deck1.fakeTrackLoadFailedEvent(pTrack); // No change to the mode, crossfader, or play states. @@ -974,7 +1070,11 @@ TEST_F(AutoDJProcessorTest, EnabledSuccess_PlayingDeck2_TrackLoadFailed) { EXPECT_DOUBLE_EQ(1.0, deck2.play.get()); // Pretend the track load succeeds. - deck1.slotLoadTrack(pTrack, false); + deck1.slotLoadTrack(pTrack, +#ifdef __STEM__ + mixxx::kNoStemSelectedIdx, +#endif + false); deck1.fakeTrackLoadedEvent(pTrack); // No change to the mode, crossfader, or play states. @@ -1009,7 +1109,11 @@ TEST_F(AutoDJProcessorTest, FadeToDeck1_LoadOnDeck2_TrackLoadSuccess) { // Pretend a track is playing on deck 2. TrackPointer pTrack = newTestTrack(); // Load track and mark it playing. - deck2.slotLoadTrack(pTrack, true); + deck2.slotLoadTrack(pTrack, +#ifdef __STEM__ + mixxx::kNoStemSelectedIdx, +#endif + true); // Indicate the track loaded successfully. deck2.fakeTrackLoadedEvent(pTrack); @@ -1034,7 +1138,11 @@ TEST_F(AutoDJProcessorTest, FadeToDeck1_LoadOnDeck2_TrackLoadSuccess) { EXPECT_DOUBLE_EQ(1.0, deck2.play.get()); // Pretend the track load succeeds. - deck1.slotLoadTrack(pTrack, false); + deck1.slotLoadTrack(pTrack, +#ifdef __STEM__ + mixxx::kNoStemSelectedIdx, +#endif + false); deck1.fakeTrackLoadedEvent(pTrack); // No change to the mode, crossfader or play states. @@ -1077,7 +1185,11 @@ TEST_F(AutoDJProcessorTest, FadeToDeck1_LoadOnDeck2_TrackLoadSuccess) { EXPECT_DOUBLE_EQ(0.0, deck2.play.get()); // Pretend the track load request succeeds. - deck2.slotLoadTrack(pTrack, false); + deck2.slotLoadTrack(pTrack, +#ifdef __STEM__ + mixxx::kNoStemSelectedIdx, +#endif + false); deck2.fakeTrackLoadedEvent(pTrack); // No change to the mode, crossfader, or play states. @@ -1096,7 +1208,11 @@ TEST_F(AutoDJProcessorTest, FadeToDeck1_LoadOnDeck2_TrackLoadFailed) { // Pretend a track is playing on deck 2. TrackPointer pTrack = newTestTrack(); // Load track and mark it playing. - deck2.slotLoadTrack(pTrack, true); + deck2.slotLoadTrack(pTrack, +#ifdef __STEM__ + mixxx::kNoStemSelectedIdx, +#endif + true); // Indicate the track loaded successfully. deck2.fakeTrackLoadedEvent(pTrack); @@ -1123,7 +1239,11 @@ TEST_F(AutoDJProcessorTest, FadeToDeck1_LoadOnDeck2_TrackLoadFailed) { EXPECT_DOUBLE_EQ(1.0, deck2.play.get()); // Pretend the track load succeeds. - deck1.slotLoadTrack(pTrack, false); + deck1.slotLoadTrack(pTrack, +#ifdef __STEM__ + mixxx::kNoStemSelectedIdx, +#endif + false); deck1.fakeTrackLoadedEvent(pTrack); // No change to the mode, crossfader or play states. @@ -1170,7 +1290,11 @@ TEST_F(AutoDJProcessorTest, FadeToDeck1_LoadOnDeck2_TrackLoadFailed) { EXPECT_CALL(*pProcessor, emitLoadTrackToPlayer(_, QString("[Channel2]"), false)); // Pretend the track load request fails. - deck2.slotLoadTrack(pTrack, false); + deck2.slotLoadTrack(pTrack, +#ifdef __STEM__ + mixxx::kNoStemSelectedIdx, +#endif + false); deck2.fakeTrackLoadFailedEvent(pTrack); // No change to the mode, crossfader, or play states. @@ -1180,7 +1304,11 @@ TEST_F(AutoDJProcessorTest, FadeToDeck1_LoadOnDeck2_TrackLoadFailed) { EXPECT_DOUBLE_EQ(0.0, deck2.play.get()); // Pretend the second track load request succeeds. - deck2.slotLoadTrack(pTrack, false); + deck2.slotLoadTrack(pTrack, +#ifdef __STEM__ + mixxx::kNoStemSelectedIdx, +#endif + false); deck2.fakeTrackLoadedEvent(pTrack); // No change to the mode, crossfader, or play states. @@ -1199,7 +1327,11 @@ TEST_F(AutoDJProcessorTest, FadeToDeck2_LoadOnDeck1_TrackLoadSuccess) { // Pretend a track is playing on deck 1. TrackPointer pTrack = newTestTrack(); // Load track and mark it playing. - deck1.slotLoadTrack(pTrack, true); + deck1.slotLoadTrack(pTrack, +#ifdef __STEM__ + mixxx::kNoStemSelectedIdx, +#endif + true); // Indicate the track loaded successfully. deck1.fakeTrackLoadedEvent(pTrack); @@ -1224,7 +1356,11 @@ TEST_F(AutoDJProcessorTest, FadeToDeck2_LoadOnDeck1_TrackLoadSuccess) { EXPECT_DOUBLE_EQ(0.0, deck2.play.get()); // Pretend the track load succeeds. - deck2.slotLoadTrack(pTrack, false); + deck2.slotLoadTrack(pTrack, +#ifdef __STEM__ + mixxx::kNoStemSelectedIdx, +#endif + false); deck2.fakeTrackLoadedEvent(pTrack); // No change to the mode, crossfader or play states. @@ -1267,7 +1403,11 @@ TEST_F(AutoDJProcessorTest, FadeToDeck2_LoadOnDeck1_TrackLoadSuccess) { EXPECT_DOUBLE_EQ(1.0, deck2.play.get()); // Pretend the track load request succeeds. - deck1.slotLoadTrack(pTrack, false); + deck1.slotLoadTrack(pTrack, +#ifdef __STEM__ + mixxx::kNoStemSelectedIdx, +#endif + false); deck1.fakeTrackLoadedEvent(pTrack); // No change to the mode, crossfader, or play states. @@ -1286,7 +1426,11 @@ TEST_F(AutoDJProcessorTest, FadeToDeck2_LoadOnDeck1_TrackLoadFailed) { // Pretend a track is playing on deck 1. TrackPointer pTrack = newTestTrack(); // Load track and mark it playing. - deck1.slotLoadTrack(pTrack, true); + deck1.slotLoadTrack(pTrack, +#ifdef __STEM__ + mixxx::kNoStemSelectedIdx, +#endif + true); // Indicate the track loaded successfully. deck1.fakeTrackLoadedEvent(pTrack); @@ -1313,7 +1457,11 @@ TEST_F(AutoDJProcessorTest, FadeToDeck2_LoadOnDeck1_TrackLoadFailed) { EXPECT_DOUBLE_EQ(0.0, deck2.play.get()); // Pretend the track load succeeds. - deck2.slotLoadTrack(pTrack, false); + deck2.slotLoadTrack(pTrack, +#ifdef __STEM__ + mixxx::kNoStemSelectedIdx, +#endif + false); deck2.fakeTrackLoadedEvent(pTrack); // No change to the mode, crossfader or play states. @@ -1360,7 +1508,11 @@ TEST_F(AutoDJProcessorTest, FadeToDeck2_LoadOnDeck1_TrackLoadFailed) { EXPECT_CALL(*pProcessor, emitLoadTrackToPlayer(_, QString("[Channel1]"), false)); // Pretend the track load request fails. - deck1.slotLoadTrack(pTrack, false); + deck1.slotLoadTrack(pTrack, +#ifdef __STEM__ + mixxx::kNoStemSelectedIdx, +#endif + false); deck1.fakeTrackLoadFailedEvent(pTrack); // No change to the mode, crossfader, or play states. @@ -1370,7 +1522,11 @@ TEST_F(AutoDJProcessorTest, FadeToDeck2_LoadOnDeck1_TrackLoadFailed) { EXPECT_DOUBLE_EQ(1.0, deck2.play.get()); // Pretend the track load request succeeds. - deck1.slotLoadTrack(pTrack, false); + deck1.slotLoadTrack(pTrack, +#ifdef __STEM__ + mixxx::kNoStemSelectedIdx, +#endif + false); deck1.fakeTrackLoadedEvent(pTrack); // No change to the mode, crossfader, or play states. @@ -1392,7 +1548,11 @@ TEST_F(AutoDJProcessorTest, FadeToDeck2_Long_Transition) { // Pretend a track is playing on deck 1. TrackPointer pTrack = newTestTrack(); // Load track and mark it playing. - deck1.slotLoadTrack(pTrack, true); + deck1.slotLoadTrack(pTrack, +#ifdef __STEM__ + mixxx::kNoStemSelectedIdx, +#endif + true); // Indicate the track loaded successfully. deck1.fakeTrackLoadedEvent(pTrack); @@ -1409,7 +1569,11 @@ TEST_F(AutoDJProcessorTest, FadeToDeck2_Long_Transition) { EXPECT_EQ(AutoDJProcessor::ADJ_IDLE, pProcessor->getState()); // Pretend the track load succeeds. - deck2.slotLoadTrack(pTrack, false); + deck2.slotLoadTrack(pTrack, +#ifdef __STEM__ + mixxx::kNoStemSelectedIdx, +#endif + false); deck2.fakeTrackLoadedEvent(pTrack); // Set a long transition time @@ -1481,7 +1645,11 @@ TEST_F(AutoDJProcessorTest, FadeToDeck2_Pause_Transition) { // Pretend that track is 2 minutes long. pTrack->setDuration(120); // Load track and mark it playing. - deck1.slotLoadTrack(pTrack, true); + deck1.slotLoadTrack(pTrack, +#ifdef __STEM__ + mixxx::kNoStemSelectedIdx, +#endif + true); // Indicate the track loaded successfully. deck1.fakeTrackLoadedEvent(pTrack); @@ -1497,7 +1665,11 @@ TEST_F(AutoDJProcessorTest, FadeToDeck2_Pause_Transition) { EXPECT_EQ(AutoDJProcessor::ADJ_IDLE, pProcessor->getState()); // Pretend the track load succeeds. - deck2.slotLoadTrack(pTrack, false); + deck2.slotLoadTrack(pTrack, +#ifdef __STEM__ + mixxx::kNoStemSelectedIdx, +#endif + false); deck2.fakeTrackLoadedEvent(pTrack); // The track should have been cued at 0.0. @@ -1511,7 +1683,11 @@ TEST_F(AutoDJProcessorTest, FadeToDeck2_Pause_Transition) { EXPECT_DOUBLE_EQ(0.0, deck2.playposition.get()); // Pretend the track load succeeds. - deck2.slotLoadTrack(pTrack, false); + deck2.slotLoadTrack(pTrack, +#ifdef __STEM__ + mixxx::kNoStemSelectedIdx, +#endif + false); deck2.fakeTrackLoadedEvent(pTrack); // The newly loaded track should have been seeked back by the trackSamples of transition. @@ -1561,7 +1737,11 @@ TEST_F(AutoDJProcessorTest, FadeToDeck2_SeekEnd) { // Pretend a track is playing on deck 1. TrackPointer pTrack = newTestTrack(); // Load track and mark it playing. - deck1.slotLoadTrack(pTrack, true); + deck1.slotLoadTrack(pTrack, +#ifdef __STEM__ + mixxx::kNoStemSelectedIdx, +#endif + true); // Indicate the track loaded successfully. deck1.fakeTrackLoadedEvent(pTrack); @@ -1578,7 +1758,11 @@ TEST_F(AutoDJProcessorTest, FadeToDeck2_SeekEnd) { EXPECT_EQ(AutoDJProcessor::ADJ_IDLE, pProcessor->getState()); // Pretend the track load succeeds. - deck2.slotLoadTrack(pTrack, false); + deck2.slotLoadTrack(pTrack, +#ifdef __STEM__ + mixxx::kNoStemSelectedIdx, +#endif + false); deck2.fakeTrackLoadedEvent(pTrack); // No change to the mode, crossfader or play states. @@ -1613,7 +1797,11 @@ TEST_F(AutoDJProcessorTest, FadeToDeck2_SeekBeforeTransition) { // Pretend a track is playing on deck 1. TrackPointer pTrack = newTestTrack(); // Load track and mark it playing. - deck1.slotLoadTrack(pTrack, true); + deck1.slotLoadTrack(pTrack, +#ifdef __STEM__ + mixxx::kNoStemSelectedIdx, +#endif + true); // Indicate the track loaded successfully. deck1.fakeTrackLoadedEvent(pTrack); @@ -1630,7 +1818,11 @@ TEST_F(AutoDJProcessorTest, FadeToDeck2_SeekBeforeTransition) { EXPECT_EQ(AutoDJProcessor::ADJ_IDLE, pProcessor->getState()); // Pretend the track load succeeds. - deck2.slotLoadTrack(pTrack, false); + deck2.slotLoadTrack(pTrack, +#ifdef __STEM__ + mixxx::kNoStemSelectedIdx, +#endif + false); deck2.fakeTrackLoadedEvent(pTrack); // No change to the mode, crossfader or play states. @@ -1689,7 +1881,11 @@ TEST_F(AutoDJProcessorTest, TrackZeroLength) { // have connected to this eventually). TrackPointer pTrack(newTestTrack(testId)); pTrack->setDuration(0); - deck1.slotLoadTrack(pTrack, true); + deck1.slotLoadTrack(pTrack, +#ifdef __STEM__ + mixxx::kNoStemSelectedIdx, +#endif + true); // Expect that the track is rejected an a new one is loaded // Signal that the request to load pTrack succeeded. diff --git a/src/test/cuecontrol_test.cpp b/src/test/cuecontrol_test.cpp index 5666a9bf284..399f983f1c2 100644 --- a/src/test/cuecontrol_test.cpp +++ b/src/test/cuecontrol_test.cpp @@ -48,7 +48,11 @@ class CueControlTest : public BaseSignalPathTest { } void unloadTrack() { - m_pMixerDeck1->slotLoadTrack(TrackPointer(), false); + m_pMixerDeck1->slotLoadTrack(TrackPointer(), +#ifdef __STEM__ + mixxx::kNoStemSelectedIdx, +#endif + false); } mixxx::audio::FramePos getCurrentFramePos() { diff --git a/src/test/hotcuecontrol_test.cpp b/src/test/hotcuecontrol_test.cpp index 73eca9f01fe..df13f131ddc 100644 --- a/src/test/hotcuecontrol_test.cpp +++ b/src/test/hotcuecontrol_test.cpp @@ -79,7 +79,11 @@ class HotcueControlTest : public BaseSignalPathTest { } void unloadTrack() { - m_pMixerDeck1->slotLoadTrack(TrackPointer(), false); + m_pMixerDeck1->slotLoadTrack(TrackPointer(), +#ifdef __STEM__ + mixxx::kNoStemSelectedIdx, +#endif + false); } mixxx::audio::FramePos currentFramePosition() { diff --git a/src/test/playermanagertest.cpp b/src/test/playermanagertest.cpp index a0f8ac2d36d..ba5fd028b4d 100644 --- a/src/test/playermanagertest.cpp +++ b/src/test/playermanagertest.cpp @@ -148,7 +148,11 @@ TEST_F(PlayerManagerTest, UnEjectTest) { ASSERT_NE(nullptr, pTrack1); TrackId testId1 = pTrack1->getId(); ASSERT_TRUE(testId1.isValid()); - deck1->slotLoadTrack(pTrack1, false); + deck1->slotLoadTrack(pTrack1, +#ifdef __STEM__ + mixxx::kNoStemSelectedIdx, +#endif + false); ASSERT_NE(nullptr, deck1->getLoadedTrack()); m_pEngine->process(1024); @@ -161,7 +165,11 @@ TEST_F(PlayerManagerTest, UnEjectTest) { // Load another track. TrackPointer pTrack2 = getOrAddTrackByLocation(getTestDir().filePath(kTrackLocationTest2)); ASSERT_NE(nullptr, pTrack2); - deck1->slotLoadTrack(pTrack2, false); + deck1->slotLoadTrack(pTrack2, +#ifdef __STEM__ + mixxx::kNoStemSelectedIdx, +#endif + false); // Ejecting in an empty deck loads the last-ejected track. auto deck2 = m_pPlayerManager->getDeck(2); @@ -182,7 +190,11 @@ TEST_F(PlayerManagerTest, UnEjectReplaceTrackTest) { ASSERT_NE(nullptr, pTrack1); TrackId testId1 = pTrack1->getId(); ASSERT_TRUE(testId1.isValid()); - deck1->slotLoadTrack(pTrack1, false); + deck1->slotLoadTrack(pTrack1, +#ifdef __STEM__ + mixxx::kNoStemSelectedIdx, +#endif + false); ASSERT_NE(nullptr, deck1->getLoadedTrack()); m_pEngine->process(1024); @@ -191,7 +203,11 @@ TEST_F(PlayerManagerTest, UnEjectReplaceTrackTest) { // Load another track, replacing the first, causing it to be unloaded. TrackPointer pTrack2 = getOrAddTrackByLocation(getTestDir().filePath(kTrackLocationTest2)); ASSERT_NE(nullptr, pTrack2); - deck1->slotLoadTrack(pTrack2, false); + deck1->slotLoadTrack(pTrack2, +#ifdef __STEM__ + mixxx::kNoStemSelectedIdx, +#endif + false); m_pEngine->process(1024); waitForTrackToBeLoaded(deck1); @@ -227,7 +243,11 @@ TEST_F(PlayerManagerTest, UnReplaceTest) { ASSERT_NE(nullptr, pTrack1); TrackId testId1 = pTrack1->getId(); ASSERT_TRUE(testId1.isValid()); - deck1->slotLoadTrack(pTrack1, false); + deck1->slotLoadTrack(pTrack1, +#ifdef __STEM__ + mixxx::kNoStemSelectedIdx, +#endif + false); m_pEngine->process(1024); waitForTrackToBeLoaded(deck1); ASSERT_NE(nullptr, deck1->getLoadedTrack()); @@ -235,7 +255,11 @@ TEST_F(PlayerManagerTest, UnReplaceTest) { // Load another track. TrackPointer pTrack2 = getOrAddTrackByLocation(getTestDir().filePath(kTrackLocationTest2)); ASSERT_NE(nullptr, pTrack2); - deck1->slotLoadTrack(pTrack2, false); + deck1->slotLoadTrack(pTrack2, +#ifdef __STEM__ + mixxx::kNoStemSelectedIdx, +#endif + false); m_pEngine->process(1024); waitForTrackToBeLoaded(deck1); ASSERT_NE(nullptr, deck1->getLoadedTrack()); diff --git a/src/test/signalpathtest.h b/src/test/signalpathtest.h index a1d4926bfdf..e7ee5830e01 100644 --- a/src/test/signalpathtest.h +++ b/src/test/signalpathtest.h @@ -169,7 +169,11 @@ class BaseSignalPathTest : public MixxxTest, SoundSourceProviderRegistration { if (pEngineDeck->getEngineBuffer()->isTrackLoaded()) { pEngineDeck->getEngineBuffer()->ejectTrack(); } - pDeck->slotLoadTrack(pTrack, false); + pDeck->slotLoadTrack(pTrack, +#ifdef __STEM__ + mixxx::kNoStemSelectedIdx, +#endif + false); // Wait for the track to load. ProcessBuffer(); diff --git a/src/track/track.h b/src/track/track.h index 471c2aae688..26f6dc57837 100644 --- a/src/track/track.h +++ b/src/track/track.h @@ -435,6 +435,16 @@ class Track : public QObject { void setAudioProperties( const mixxx::audio::StreamInfo& streamInfo); + // Information about the actual properties of the + // audio stream is only available after opening the + // source at least once. On this occasion the metadata + // stream info of the track need to be updated to reflect + // these values. + bool hasStreamInfoFromSource() const { + const auto locked = lockMutex(&m_qMutex); + return m_record.hasStreamInfoFromSource(); + } + signals: void artistChanged(const QString&); void titleChanged(const QString&); @@ -568,16 +578,6 @@ class Track : public QObject { ExportTrackMetadataResult exportMetadata( const mixxx::MetadataSource& metadataSource, const SyncTrackMetadataParams& syncParams); - - // Information about the actual properties of the - // audio stream is only available after opening the - // source at least once. On this occasion the metadata - // stream info of the track need to be updated to reflect - // these values. - bool hasStreamInfoFromSource() const { - const auto locked = lockMutex(&m_qMutex); - return m_record.hasStreamInfoFromSource(); - } void updateStreamInfoFromSource( mixxx::audio::StreamInfo&& streamInfo); diff --git a/src/waveform/renderers/allshader/waveformrendererstem.cpp b/src/waveform/renderers/allshader/waveformrendererstem.cpp index a1d03a63377..cb9cee96069 100644 --- a/src/waveform/renderers/allshader/waveformrendererstem.cpp +++ b/src/waveform/renderers/allshader/waveformrendererstem.cpp @@ -4,6 +4,7 @@ #include #include +#include "engine/engine.h" #include "track/track.h" #include "util/math.h" #include "waveform/renderers/allshader/matrixforwidgetgeometry.h" @@ -11,10 +12,6 @@ #include "waveform/renderers/waveformwidgetrenderer.h" #include "waveform/waveform.h" -namespace { -constexpr int kMaxSupportedStems = 4; -} // anonymous namespace - namespace allshader { WaveformRendererStem::WaveformRendererStem( @@ -33,7 +30,7 @@ void WaveformRendererStem::initializeGL() { m_shader.init(); m_textureShader.init(); auto group = m_pEQEnabled->getKey().group; - for (int stemIdx = 1; stemIdx <= kMaxSupportedStems; stemIdx++) { + for (int stemIdx = 1; stemIdx <= mixxx::kMaxSupportedStems; stemIdx++) { DEBUG_ASSERT(group.endsWith("]")); QString stemGroup = QStringLiteral("%1Stem%2]") .arg(group.left(group.size() - 1), @@ -79,6 +76,8 @@ void WaveformRendererStem::paintGL() { return; } + uint selectedStem = m_waveformRenderer->getSelectedStem(); + const float devicePixelRatio = m_waveformRenderer->getDevicePixelRatio(); const int length = static_cast(m_waveformRenderer->getLength() * devicePixelRatio); @@ -125,7 +124,7 @@ void WaveformRendererStem::paintGL() { const double maxSamplingRange = visualIncrementPerPixel / 2.0; for (int visualIdx = 0; visualIdx < length; ++visualIdx) { - for (int stemIdx = 0; stemIdx < 4; stemIdx++) { + for (int stemIdx = 0; stemIdx < mixxx::kMaxSupportedStems; stemIdx++) { // Stem is drawn twice with different opacity level, this allow to // see the maximum signal by transparency for (int layerIdx = 0; layerIdx < 2; layerIdx++) { @@ -160,7 +159,9 @@ void WaveformRendererStem::paintGL() { // Apply the gains if (layerIdx) { - max *= m_pStemMute[stemIdx]->toBool() + max *= m_pStemMute[stemIdx]->toBool() || + (selectedStem && + selectedStem != stemIdx + 1) ? 0.f : static_cast(m_pStemGain[stemIdx]->get()); } diff --git a/src/waveform/renderers/waveformwidgetrenderer.cpp b/src/waveform/renderers/waveformwidgetrenderer.cpp index ffefe5d6d45..1b28006a935 100644 --- a/src/waveform/renderers/waveformwidgetrenderer.cpp +++ b/src/waveform/renderers/waveformwidgetrenderer.cpp @@ -21,6 +21,9 @@ constexpr int kDefaultDimBrightThreshold = 127; WaveformWidgetRenderer::WaveformWidgetRenderer(const QString& group) : m_group(group), +#ifdef __STEM__ + m_selectedStem(0), +#endif m_orientation(Qt::Horizontal), m_dimBrightThreshold(kDefaultDimBrightThreshold), m_height(-1), @@ -416,6 +419,12 @@ void WaveformWidgetRenderer::setDisplayBeatGridAlpha(int alpha) { m_alphaBeatGrid = alpha; } +#ifdef __STEM__ +void WaveformWidgetRenderer::selectStem(uint stemIdx) { + m_selectedStem = stemIdx; +} +#endif + void WaveformWidgetRenderer::setTrack(TrackPointer track) { m_pTrack = track; //used to postpone first display until track sample is actually available diff --git a/src/waveform/renderers/waveformwidgetrenderer.h b/src/waveform/renderers/waveformwidgetrenderer.h index 47cd21b67a6..86a6bf860b3 100644 --- a/src/waveform/renderers/waveformwidgetrenderer.h +++ b/src/waveform/renderers/waveformwidgetrenderer.h @@ -46,6 +46,12 @@ class WaveformWidgetRenderer { return m_pTrack; } +#ifdef __STEM__ + uint getSelectedStem() const { + return m_selectedStem; + } +#endif + bool isSlipActive() const { return m_pos[::WaveformRendererAbstract::Play] != m_pos[::WaveformRendererAbstract::Slip]; } @@ -170,6 +176,9 @@ class WaveformWidgetRenderer { return renderer; } +#ifdef __STEM__ + void selectStem(uint stemIdx); +#endif void setTrack(TrackPointer track); void setMarkPositions(const QList& markPositions) { m_markPositions = markPositions; @@ -195,6 +204,9 @@ class WaveformWidgetRenderer { protected: const QString m_group; TrackPointer m_pTrack; +#ifdef __STEM__ + uint m_selectedStem; +#endif QList m_rendererStack; Qt::Orientation m_orientation; int m_dimBrightThreshold; diff --git a/src/waveform/waveform.h b/src/waveform/waveform.h index fc415e31db6..7ebf28f25f8 100644 --- a/src/waveform/waveform.h +++ b/src/waveform/waveform.h @@ -9,6 +9,7 @@ #include "analyzer/constants.h" #include "audio/signalinfo.h" +#include "engine/engine.h" #include "util/class.h" #include "util/compatibility/qmutex.h" diff --git a/src/widget/wlibrarytableview.h b/src/widget/wlibrarytableview.h index 6a63ecc2de5..c4ac76fc1d5 100644 --- a/src/widget/wlibrarytableview.h +++ b/src/widget/wlibrarytableview.h @@ -56,7 +56,12 @@ class WLibraryTableView : public QTableView, public virtual LibraryView { signals: void loadTrack(TrackPointer pTrack); - void loadTrackToPlayer(TrackPointer pTrack, const QString& group, bool play = false); + void loadTrackToPlayer(TrackPointer pTrack, + const QString& group, +#ifdef __STEM__ + uint stemIdx, +#endif + bool play = false); void trackSelected(TrackPointer pTrack); void onlyCachedCoverArt(bool); void scrollValueChanged(int); diff --git a/src/widget/wtrackmenu.cpp b/src/widget/wtrackmenu.cpp index f9df992a90b..77e7ef98634 100644 --- a/src/widget/wtrackmenu.cpp +++ b/src/widget/wtrackmenu.cpp @@ -293,13 +293,6 @@ void WTrackMenu::createActions() { connect(m_pAutoDJReplaceAct, &QAction::triggered, this, &WTrackMenu::slotAddToAutoDJReplace); } - if (featureIsEnabled(Feature::LoadTo)) { - m_pAddToPreviewDeck = new QAction(tr("Preview Deck"), m_pLoadToMenu); - // currently there is only one preview deck so just map it here. - QString previewDeckGroup = PlayerManager::groupForPreviewDeck(0); - connect(m_pAddToPreviewDeck, &QAction::triggered, this, [this, previewDeckGroup] { loadSelectionToGroup(previewDeckGroup); }); - } - if (featureIsEnabled(Feature::Remove)) { // Keyboard shortcuts are set here just to have them displayed in the menu. // Actual keypress is handled in WTrackTableView::keyPressEvent(). @@ -582,14 +575,6 @@ void WTrackMenu::setupActions() { } if (featureIsEnabled(Feature::LoadTo)) { - m_pLoadToMenu->addMenu(m_pDeckMenu); - - m_pLoadToMenu->addMenu(m_pSamplerMenu); - - if (m_pNumPreviewDecks.get() > 0.0) { - m_pLoadToMenu->addAction(m_pAddToPreviewDeck); - } - addMenu(m_pLoadToMenu); addSeparator(); } @@ -890,11 +875,59 @@ CoverInfo WTrackMenu::getCoverInfoOfLastTrack() const { } } +void WTrackMenu::generateTrackLoadMenu(const QString& group, + const QString& label, + TrackPointer pTrack, + QMenu* pParentMenu, + bool enabled) { +#ifdef __STEM__ + if (pTrack && !pTrack->hasStreamInfoFromSource()) { + // The stem metadata are loaded on stream info refresh, which occurs + // when the file gets loaded for the time in the session. If there is no + // stream info from source, when open the file, which lead to loading + // the stem manifest. + mixxx::AudioSource::OpenParams config; + config.setChannelCount(mixxx::kMaxEngineChannelInputCount); + SoundSourceProxy(pTrack).openAudioSource(config); + } + if (enabled && pTrack && pTrack->hasStem()) { + QMenu* pStemMenu = new QMenu(label, pParentMenu); + + QAction* pAction = new QAction(tr("Load as a stem deck"), this); + pStemMenu->addAction(pAction); + connect(pAction, &QAction::triggered, this, [this, group] { loadSelectionToGroup(group); }); + pStemMenu->addSeparator(); + + auto stemInfo = pTrack->getStemInfo(); + for (uint stemIdx = 0; stemIdx < mixxx::kMaxSupportedStems; stemIdx++) { + QAction* pAction = + new QAction(tr("Load the \"%1\" stem") + .arg(stemInfo.at(stemIdx).getLabel()), + this); + pStemMenu->addAction(pAction); + connect(pAction, &QAction::triggered, this, [this, group, stemIdx] { + loadSelectionToGroup(group, stemIdx + 1); + }); + } + pParentMenu->addMenu(pStemMenu); + } else { +#endif + QAction* pAction = new QAction(label, this); + pAction->setEnabled(enabled); + pParentMenu->addAction(pAction); + connect(pAction, &QAction::triggered, this, [this, group] { loadSelectionToGroup(group); }); +#ifdef __STEM__ + } +#endif +} + void WTrackMenu::updateMenus() { if (isEmpty()) { return; } + m_pLoadToMenu->clear(); + // Gray out some stuff if multiple songs were selected. const bool singleTrackSelected = getTrackCount() == 1; @@ -927,12 +960,15 @@ void WTrackMenu::updateMenus() { bool deckEnabled = (!deckPlaying || allowLoadTrackIntoPlayingDeck) && singleTrackSelected; - QAction* pAction = new QAction(tr("Deck %1").arg(i), this); - pAction->setEnabled(deckEnabled); - m_pDeckMenu->addAction(pAction); - connect(pAction, &QAction::triggered, this, [this, deckGroup] { loadSelectionToGroup(deckGroup); }); + auto pTrack = getFirstTrackPointer(); + generateTrackLoadMenu(deckGroup, + tr("Deck %1").arg(i), + getFirstTrackPointer(), + m_pDeckMenu, + deckEnabled); } } + m_pLoadToMenu->addMenu(m_pDeckMenu); int iNumSamplers = static_cast(m_pNumSamplers.get()); const int maxSamplersPerMenu = 16; @@ -940,6 +976,7 @@ void WTrackMenu::updateMenus() { m_pSamplerMenu->clear(); QMenu* pMenu = m_pSamplerMenu; int samplersInMenu = 0; + TrackPointer pTrack = getFirstTrackPointer(); for (int i = 1; i <= iNumSamplers; ++i) { if (samplersInMenu == maxSamplersPerMenu) { samplersInMenu = 0; @@ -954,17 +991,23 @@ void WTrackMenu::updateMenus() { bool samplerPlaying = ControlObject::get( ConfigKey(samplerGroup, "play")) > 0.0; bool samplerEnabled = !samplerPlaying && singleTrackSelected; - QAction* pAction = new QAction(samplerTrString(i), pMenu); - pAction->setEnabled(samplerEnabled); - pMenu->addAction(pAction); - connect(pAction, - &QAction::triggered, - this, - [this, samplerGroup] { - loadSelectionToGroup(samplerGroup); - }); + + generateTrackLoadMenu(samplerGroup, + samplerTrString(i), + pTrack, + pMenu, + samplerEnabled); } } + m_pLoadToMenu->addMenu(m_pSamplerMenu); + + if (m_pNumPreviewDecks.get() > 0.0) { + // currently there is only one preview deck so just map it here. + generateTrackLoadMenu(PlayerManager::groupForPreviewDeck(0), + tr("Preview Deck"), + getFirstTrackPointer(), + m_pLoadToMenu); + } } if (featureIsEnabled(Feature::Playlist)) { @@ -1821,7 +1864,11 @@ void WTrackMenu::slotColorPicked(const mixxx::RgbColor::optional_t& color) { hide(); } -void WTrackMenu::loadSelectionToGroup(const QString& group, bool play) { +void WTrackMenu::loadSelectionToGroup(const QString& group, +#ifdef __STEM__ + uint stemIdx, +#endif + bool play) { TrackPointer pTrack = getFirstTrackPointer(); if (!pTrack) { return; @@ -1841,7 +1888,11 @@ void WTrackMenu::loadSelectionToGroup(const QString& group, bool play) { // TODO: load track from this class without depending on // external slot to load track - emit loadTrackToPlayer(pTrack, group, play); + emit loadTrackToPlayer(pTrack, group, +#ifdef __STEM__ + stemIdx, +#endif + play); } namespace { diff --git a/src/widget/wtrackmenu.h b/src/widget/wtrackmenu.h index 23b0efda0b7..a19c4668e60 100644 --- a/src/widget/wtrackmenu.h +++ b/src/widget/wtrackmenu.h @@ -110,7 +110,12 @@ class WTrackMenu : public QMenu { const QString getDeckGroup() const; signals: - void loadTrackToPlayer(TrackPointer pTrack, const QString& group, bool play = false); + void loadTrackToPlayer(TrackPointer pTrack, + const QString& group, +#ifdef __STEM__ + uint stemIdx, +#endif + bool play = false); void trackMenuVisible(bool visible); void saveCurrentViewState(); void restoreCurrentViewStateOrIndex(); @@ -214,6 +219,12 @@ class WTrackMenu : public QMenu { void setupActions(); void updateMenus(); + void generateTrackLoadMenu(const QString& group, + const QString& label, + TrackPointer pTrack, + QMenu* pParentMenu, + bool enabled = true); + bool featureIsEnabled(Feature flag) const; void addSelectionToPlaylist(int iPlaylistId); @@ -225,7 +236,11 @@ class WTrackMenu : public QMenu { void clearBeats(); void lockBpm(bool lock); - void loadSelectionToGroup(const QString& group, bool play = false); + void loadSelectionToGroup(const QString& group, +#ifdef __STEM__ + uint stemIdx = mixxx::kNoStemSelectedIdx, +#endif + bool play = false); void clearTrackSelection(); std::pair getTrackBpmLockStates() const; @@ -279,9 +294,6 @@ class WTrackMenu : public QMenu { // Save Track Metadata Action: QAction* m_pExportMetadataAct{}; - // Load Track to PreviewDeck - QAction* m_pAddToPreviewDeck{}; - // Send to Auto-DJ Action QAction* m_pAutoDJBottomAct{}; QAction* m_pAutoDJTopAct{}; diff --git a/src/widget/wtracktableview.cpp b/src/widget/wtracktableview.cpp index b939dd2c83a..0b4f8a950fe 100644 --- a/src/widget/wtracktableview.cpp +++ b/src/widget/wtracktableview.cpp @@ -1247,7 +1247,11 @@ void WTrackTableView::activateSelectedTrack() { slotMouseDoubleClicked(indices.at(0)); } -void WTrackTableView::loadSelectedTrackToGroup(const QString& group, bool play) { +void WTrackTableView::loadSelectedTrackToGroup(const QString& group, +#ifdef __STEM__ + uint stemIdx, +#endif + bool play) { auto indices = getSelectedRows(); if (indices.isEmpty()) { return; @@ -1281,7 +1285,12 @@ void WTrackTableView::loadSelectedTrackToGroup(const QString& group, bool play) auto* trackModel = getTrackModel(); TrackPointer pTrack; if (trackModel && (pTrack = trackModel->getTrack(index))) { +#ifdef __STEM__ + DEBUG_ASSERT(!stemIdx || pTrack->hasStem()); + emit loadTrackToPlayer(pTrack, group, stemIdx, play); +#else emit loadTrackToPlayer(pTrack, group, play); +#endif } } diff --git a/src/widget/wtracktableview.h b/src/widget/wtracktableview.h index 7ec93a3ae67..19fc5306d21 100644 --- a/src/widget/wtracktableview.h +++ b/src/widget/wtracktableview.h @@ -38,7 +38,11 @@ class WTrackTableView : public WLibraryTableView { void keyPressEvent(QKeyEvent* event) override; void resizeEvent(QResizeEvent* event) override; void activateSelectedTrack(); - void loadSelectedTrackToGroup(const QString& group, bool play); + void loadSelectedTrackToGroup(const QString& group, +#ifdef __STEM__ + uint stemIdx, +#endif + bool play); void assignNextTrackColor() override; void assignPreviousTrackColor() override; TrackModel::SortColumnId getColumnIdFromCurrentIndex() override; diff --git a/src/widget/wwaveformviewer.cpp b/src/widget/wwaveformviewer.cpp index 22629abc884..e3ee08349fe 100644 --- a/src/widget/wwaveformviewer.cpp +++ b/src/widget/wwaveformviewer.cpp @@ -227,6 +227,18 @@ void WWaveformViewer::slotTrackLoaded(TrackPointer track) { } } +#ifdef __STEM__ +void WWaveformViewer::slotSelectStem(uint stemIdx) { + if (m_waveformWidget) { + m_waveformWidget->selectStem(stemIdx); + } +} +#endif + +void WWaveformViewer::slotTrackUnloaded(TrackPointer pOldTrack) { + slotLoadingTrack(pOldTrack, TrackPointer()); +} + void WWaveformViewer::slotLoadingTrack(TrackPointer pNewTrack, TrackPointer pOldTrack) { Q_UNUSED(pNewTrack); Q_UNUSED(pOldTrack); diff --git a/src/widget/wwaveformviewer.h b/src/widget/wwaveformviewer.h index eead266f540..ad6b8e406a9 100644 --- a/src/widget/wwaveformviewer.h +++ b/src/widget/wwaveformviewer.h @@ -43,7 +43,11 @@ class WWaveformViewer : public WWidget, public TrackDropTarget { public slots: void slotTrackLoaded(TrackPointer track); + void slotTrackUnloaded(TrackPointer pOldTrack); void slotLoadingTrack(TrackPointer pNewTrack, TrackPointer pOldTrack); +#ifdef __STEM__ + void slotSelectStem(uint stemIdx); +#endif protected: void showEvent(QShowEvent* event) override; From 0f433d46583026042875da62eee9e098c9f2a801 Mon Sep 17 00:00:00 2001 From: Antoine C Date: Thu, 22 Aug 2024 15:26:02 +0100 Subject: [PATCH 2/8] feat: allow multiple stem selection --- CMakeLists.txt | 1 + src/engine/cachingreader/cachingreader.cpp | 9 +- src/engine/cachingreader/cachingreader.h | 7 +- .../cachingreader/cachingreaderworker.cpp | 20 ++-- .../cachingreader/cachingreaderworker.h | 16 ++-- src/engine/engine.h | 7 +- src/engine/enginebuffer.cpp | 17 ++-- src/engine/enginebuffer.h | 10 +- src/library/analysis/analysisfeature.cpp | 2 +- src/library/autodj/autodjprocessor.h | 8 +- src/library/autodj/dlgautodj.h | 6 +- src/library/library.cpp | 25 +++-- src/library/library.h | 16 ++-- src/library/librarycontrol.cpp | 57 +++++------ src/library/librarycontrol.h | 18 ++-- src/library/libraryfeature.h | 10 +- src/library/recording/dlgrecording.h | 6 +- .../tabledelegates/previewbuttondelegate.cpp | 2 +- .../tabledelegates/previewbuttondelegate.h | 7 +- src/mixer/basetrackplayer.cpp | 21 ++-- src/mixer/basetrackplayer.h | 20 ++-- src/mixer/playermanager.cpp | 17 ++-- src/mixer/playermanager.h | 6 +- src/mixer/samplerbank.cpp | 2 +- src/skin/legacy/legacyskinparser.cpp | 11 +++ src/sources/audiosource.h | 43 +++++---- src/sources/soundsourcestem.cpp | 18 +++- src/test/autodjprocessor_test.cpp | 96 +++++++++---------- src/test/cuecontrol_test.cpp | 2 +- src/test/hotcuecontrol_test.cpp | 2 +- src/test/playermanagertest.cpp | 12 +-- src/test/signalpathtest.h | 2 +- .../allshader/waveformrendererstem.cpp | 6 +- .../renderers/waveformwidgetrenderer.cpp | 6 +- .../renderers/waveformwidgetrenderer.h | 8 +- src/waveform/waveform.h | 1 - src/widget/wlibrarytableview.h | 2 +- src/widget/wtrackmenu.cpp | 48 +++++----- src/widget/wtrackmenu.h | 19 ++-- src/widget/wtrackstemmenu.cpp | 90 +++++++++++++++++ src/widget/wtrackstemmenu.h | 38 ++++++++ src/widget/wtracktableview.cpp | 13 ++- src/widget/wtracktableview.h | 9 +- src/widget/wwaveformviewer.cpp | 4 +- src/widget/wwaveformviewer.h | 2 +- 45 files changed, 456 insertions(+), 286 deletions(-) create mode 100644 src/widget/wtrackstemmenu.cpp create mode 100644 src/widget/wtrackstemmenu.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 7d8494b260d..cd46b79fd76 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -3457,6 +3457,7 @@ if (STEM) src/sources/soundsourcestem.cpp src/track/steminfoimporter.cpp src/track/steminfo.cpp + src/widget/wtrackstemmenu.cpp ) if(QOPENGL) target_sources(mixxx-lib PRIVATE diff --git a/src/engine/cachingreader/cachingreader.cpp b/src/engine/cachingreader/cachingreader.cpp index 8f4d780d18d..eb8953611db 100644 --- a/src/engine/cachingreader/cachingreader.cpp +++ b/src/engine/cachingreader/cachingreader.cpp @@ -206,7 +206,7 @@ CachingReaderChunkForOwner* CachingReader::lookupChunkAndFreshen(SINT chunkIndex // Invoked from the UI thread!! #ifdef __STEM__ -void CachingReader::newTrack(TrackPointer pTrack, uint stemIdx) { +void CachingReader::newTrack(TrackPointer pTrack, uint stemMask) { #else void CachingReader::newTrack(TrackPointer pTrack) { #endif @@ -224,12 +224,11 @@ void CachingReader::newTrack(TrackPointer pTrack) { kLogger.warning() << "Loading a new track while loading a track may lead to inconsistent states"; } - m_worker.newTrack(std::move(pTrack) #ifdef __STEM__ - , - stemIdx + m_worker.newTrack(std::move(pTrack), stemMask); +#else + m_worker.newTrack(std::move(pTrack)); #endif - ); } // Called from the engine thread diff --git a/src/engine/cachingreader/cachingreader.h b/src/engine/cachingreader/cachingreader.h index 97854f4cf7e..05fc71e5c9a 100644 --- a/src/engine/cachingreader/cachingreader.h +++ b/src/engine/cachingreader/cachingreader.h @@ -116,12 +116,11 @@ class CachingReader : public QObject { // Request that the CachingReader load a new track. These requests are // processed in the work thread, so the reader must be woken up via wake() // for this to take effect. - void newTrack(TrackPointer pTrack #ifdef __STEM__ - , - uint stemIdx = 0 + void newTrack(TrackPointer pTrack, uint stemMask = 0); +#else + void newTrack(TrackPointer pTrack); #endif - ); void setScheduler(EngineWorkerScheduler* pScheduler) { m_worker.setScheduler(pScheduler); diff --git a/src/engine/cachingreader/cachingreaderworker.cpp b/src/engine/cachingreader/cachingreaderworker.cpp index 41d2583a783..bed83f053dd 100644 --- a/src/engine/cachingreader/cachingreaderworker.cpp +++ b/src/engine/cachingreader/cachingreaderworker.cpp @@ -92,18 +92,17 @@ ReaderStatusUpdate CachingReaderWorker::processReadRequest( } // WARNING: Always called from a different thread (GUI) -void CachingReaderWorker::newTrack(TrackPointer pTrack #ifdef __STEM__ - , - uint stemIdx +void CachingReaderWorker::newTrack(TrackPointer pTrack, uint stemMask) { +#else +void CachingReaderWorker::newTrack(TrackPointer pTrack) { #endif -) { { const auto locker = lockMutex(&m_newTrackMutex); #ifdef __STEM__ m_pNewTrack = NewTrackRequest{ pTrack, - stemIdx}; + stemMask}; #else m_pNewTrack = pTrack; #endif @@ -137,7 +136,7 @@ void CachingReaderWorker::run() { #ifdef __STEM__ if (pLoadTrack.track) { // in this case the engine is still running with the old track - loadTrack(pLoadTrack.track, pLoadTrack.stemIdx); + loadTrack(pLoadTrack.track, pLoadTrack.stemMask); #else if (pLoadTrack) { // in this case the engine is still running with the old track @@ -188,12 +187,11 @@ void CachingReaderWorker::unloadTrack() { m_pReaderStatusFIFO->writeBlocking(&update, 1); } -void CachingReaderWorker::loadTrack(const TrackPointer& pTrack #ifdef __STEM__ - , - uint stemIdx +void CachingReaderWorker::loadTrack(const TrackPointer& pTrack, uint stemMask) { +#else +void CachingReaderWorker::loadTrack(const TrackPointer& pTrack) { #endif -) { // This emit is directly connected and returns synchronized // after the engine has been stopped. emit trackLoading(); @@ -216,7 +214,7 @@ void CachingReaderWorker::loadTrack(const TrackPointer& pTrack mixxx::AudioSource::OpenParams config; config.setChannelCount(m_maxSupportedChannel); #ifdef __STEM__ - config.setStemIdx(stemIdx); + config.setStemMask(stemMask); #endif m_pAudioSource = SoundSourceProxy(pTrack).openAudioSource(config); if (!m_pAudioSource) { diff --git a/src/engine/cachingreader/cachingreaderworker.h b/src/engine/cachingreader/cachingreaderworker.h index 12e044cb048..d4c8320fe04 100644 --- a/src/engine/cachingreader/cachingreaderworker.h +++ b/src/engine/cachingreader/cachingreaderworker.h @@ -104,12 +104,11 @@ class CachingReaderWorker : public EngineWorker { ~CachingReaderWorker() override = default; // Request to load a new track. wake() must be called afterwards. - void newTrack(TrackPointer pTrack #ifdef __STEM__ - , - uint stemIdx + void newTrack(TrackPointer pTrack, uint stemMask); +#else + void newTrack(TrackPointer pTrack); #endif - ); // Run upkeep operations like loading tracks and reading from file. Run by a // thread pool via the EngineWorkerScheduler. @@ -130,7 +129,7 @@ class CachingReaderWorker : public EngineWorker { #ifdef __STEM__ struct NewTrackRequest { TrackPointer track; - uint stemIdx; + uint stemMask; }; #endif const QString m_group; @@ -162,12 +161,11 @@ class CachingReaderWorker : public EngineWorker { void unloadTrack(); /// Internal method to load a track. Emits trackLoaded when finished. - void loadTrack(const TrackPointer& pTrack #ifdef __STEM__ - , - uint stemIdx + void loadTrack(const TrackPointer& pTrack, uint stemMask); +#else + void loadTrack(const TrackPointer& pTrack); #endif - ); ReaderStatusUpdate processReadRequest( const CachingReaderChunkReadRequest& request); diff --git a/src/engine/engine.h b/src/engine/engine.h index 9de33d6143c..02bf959b4fa 100644 --- a/src/engine/engine.h +++ b/src/engine/engine.h @@ -8,9 +8,12 @@ static constexpr audio::ChannelCount kEngineChannelOutputCount = audio::ChannelCount::stereo(); static constexpr audio::ChannelCount kMaxEngineChannelInputCount = audio::ChannelCount::stem(); -#ifdef __STEM__ +// The following constant is always defined as it used for the waveform data +// struct, which must stay consistent, whether the STEM feature is enabled or +// not. constexpr int kMaxSupportedStems = 4; -constexpr uint kNoStemSelectedIdx = 0; +#ifdef __STEM__ +constexpr uint kNoStemSelected = 0; #endif // Contains the information needed to process a buffer of audio diff --git a/src/engine/enginebuffer.cpp b/src/engine/enginebuffer.cpp index 07f2cbf3ed3..7a8e68faa11 100644 --- a/src/engine/enginebuffer.cpp +++ b/src/engine/enginebuffer.cpp @@ -1540,22 +1540,25 @@ void EngineBuffer::hintReader(const double dRate) { } // WARNING: This method runs in the GUI thread -void EngineBuffer::loadTrack(TrackPointer pTrack, #ifdef __STEM__ - uint stemIdx, -#endif +void EngineBuffer::loadTrack(TrackPointer pTrack, + uint stemMask, bool play, EngineChannel* pChannelToCloneFrom) { +#else +void EngineBuffer::loadTrack(TrackPointer pTrack, + bool play, + EngineChannel* pChannelToCloneFrom) { +#endif if (pTrack) { // Signal to the reader to load the track. The reader will respond with // trackLoading and then either with trackLoaded or trackLoadFailed signals. m_bPlayAfterLoading = play; - m_pReader->newTrack(pTrack #ifdef __STEM__ - , - stemIdx + m_pReader->newTrack(pTrack, stemMask); +#else + m_pReader->newTrack(pTrack); #endif - ); atomicStoreRelaxed(m_pChannelToCloneFrom, pChannelToCloneFrom); } else { // Loading a null track means "eject" diff --git a/src/engine/enginebuffer.h b/src/engine/enginebuffer.h index a996a5dc7ef..78fe05fb758 100644 --- a/src/engine/enginebuffer.h +++ b/src/engine/enginebuffer.h @@ -215,12 +215,16 @@ class EngineBuffer : public EngineObject { // Request that the EngineBuffer load a track. Since the process is // asynchronous, EngineBuffer will emit a trackLoaded signal when the load // has completed. - void loadTrack(TrackPointer pTrack, #ifdef __STEM__ - uint stemIdx, -#endif + void loadTrack(TrackPointer pTrack, + uint stemMask, + bool play, + EngineChannel* pChannelToCloneFrom); +#else + void loadTrack(TrackPointer pTrack, bool play, EngineChannel* pChannelToCloneFrom); +#endif void setChannelIndex(int channelIndex) { m_channelIndex = channelIndex; diff --git a/src/library/analysis/analysisfeature.cpp b/src/library/analysis/analysisfeature.cpp index 1ecb67efeba..82b64ca3e49 100644 --- a/src/library/analysis/analysisfeature.cpp +++ b/src/library/analysis/analysisfeature.cpp @@ -83,7 +83,7 @@ void AnalysisFeature::bindLibraryWidget(WLibrary* libraryWidget, [=, this](TrackPointer track, const QString& group) { emit loadTrackToPlayer(track, group, #ifdef __STEM__ - mixxx::kNoStemSelectedIdx, + mixxx::kNoStemSelected, #endif false); }); diff --git a/src/library/autodj/autodjprocessor.h b/src/library/autodj/autodjprocessor.h index 38d0de3b67e..fd0f699559d 100644 --- a/src/library/autodj/autodjprocessor.h +++ b/src/library/autodj/autodjprocessor.h @@ -201,11 +201,11 @@ class AutoDJProcessor : public QObject { AutoDJError toggleAutoDJ(bool enable); signals: - void loadTrackToPlayer(TrackPointer pTrack, const QString& group, #ifdef __STEM__ - uint stemIdx, + void loadTrackToPlayer(TrackPointer pTrack, const QString& group, uint stemMask, bool play); +#else + void loadTrackToPlayer(TrackPointer pTrack, const QString& group, bool play); #endif - bool play); void autoDJStateChanged(AutoDJProcessor::AutoDJState state); void autoDJError(AutoDJProcessor::AutoDJError error); void transitionTimeChanged(int time); @@ -235,7 +235,7 @@ class AutoDJProcessor : public QObject { virtual void emitLoadTrackToPlayer(TrackPointer pTrack, const QString& group, bool play) { emit loadTrackToPlayer(pTrack, group, #ifdef __STEM__ - mixxx::kNoStemSelectedIdx, + mixxx::kNoStemSelected, #endif play); } diff --git a/src/library/autodj/dlgautodj.h b/src/library/autodj/dlgautodj.h index 47a585f599a..f4138ec86f5 100644 --- a/src/library/autodj/dlgautodj.h +++ b/src/library/autodj/dlgautodj.h @@ -49,11 +49,11 @@ class DlgAutoDJ : public QWidget, public Ui::DlgAutoDJ, public LibraryView { signals: void addRandomTrackButton(bool buttonChecked); void loadTrack(TrackPointer tio); - void loadTrackToPlayer(TrackPointer tio, const QString& group, #ifdef __STEM__ - uint stemIdx, + void loadTrackToPlayer(TrackPointer tio, const QString& group, uint stemMask, bool); +#else + void loadTrackToPlayer(TrackPointer tio, const QString& group, bool); #endif - bool); void trackSelected(TrackPointer pTrack); private: diff --git a/src/library/library.cpp b/src/library/library.cpp index 71bff659c0a..99fb2d429f3 100644 --- a/src/library/library.cpp +++ b/src/library/library.cpp @@ -552,26 +552,25 @@ void Library::slotLoadLocationToPlayer(const QString& location, const QString& g auto trackRef = TrackRef::fromFilePath(location); TrackPointer pTrack = m_pTrackCollectionManager->getOrAddTrack(trackRef); if (pTrack) { - emit loadTrackToPlayer(pTrack, group, #ifdef __STEM__ - mixxx::kNoStemSelectedIdx, + emit loadTrackToPlayer(pTrack, group, mixxx::kNoStemSelected, play); +#else + emit loadTrackToPlayer(pTrack, group, play); #endif - play); } } -void Library::slotLoadTrackToPlayer( - TrackPointer pTrack, const QString& group, -#ifdef __STEM__ - uint stemIdx, -#endif - bool play) { - emit loadTrackToPlayer(pTrack, group, #ifdef __STEM__ - stemIdx, -#endif - play); +void Library::slotLoadTrackToPlayer( + TrackPointer pTrack, const QString& group, uint stemMask, bool play) { + emit loadTrackToPlayer(pTrack, group, stemMask, play); +} +#else +void Library::slotLoadTrackToPlayer( + TrackPointer pTrack, const QString& group, bool play) { + emit loadTrackToPlayer(pTrack, group, play); } +#endif void Library::slotRefreshLibraryModels() { m_pMixxxLibraryFeature->refreshLibraryModels(); diff --git a/src/library/library.h b/src/library/library.h index a4a1bd61eee..75b2e4e014a 100644 --- a/src/library/library.h +++ b/src/library/library.h @@ -114,11 +114,11 @@ class Library: public QObject { void slotShowTrackModel(QAbstractItemModel* model); void slotSwitchToView(const QString& view); void slotLoadTrack(TrackPointer pTrack); - void slotLoadTrackToPlayer(TrackPointer pTrack, const QString& group, #ifdef __STEM__ - uint stemIdx, + void slotLoadTrackToPlayer(TrackPointer pTrack, const QString& group, uint stemMask, bool play); +#else + void slotLoadTrackToPlayer(TrackPointer pTrack, const QString& group, bool play); #endif - bool play); void slotLoadLocationToPlayer(const QString& location, const QString& group, bool play); void slotRefreshLibraryModels(); void slotCreatePlaylist(); @@ -131,12 +131,16 @@ class Library: public QObject { void showTrackModel(QAbstractItemModel* model, bool restoreState = true); void switchToView(const QString& view); void loadTrack(TrackPointer pTrack); +#ifdef __STEM__ void loadTrackToPlayer(TrackPointer pTrack, const QString& group, -#ifdef __STEM__ - uint stemIdx, -#endif + uint stemMask, bool play = false); +#else + void loadTrackToPlayer(TrackPointer pTrack, + const QString& group, + bool play = false); +#endif void restoreSearch(const QString&); void search(const QString& text); void disableSearch(); diff --git a/src/library/librarycontrol.cpp b/src/library/librarycontrol.cpp index b834946c132..0b4ba6da353 100644 --- a/src/library/librarycontrol.cpp +++ b/src/library/librarycontrol.cpp @@ -39,30 +39,16 @@ LoadToGroupController::LoadToGroupController(LibraryControl* pParent, const QStr &LoadToGroupController::slotLoadToGroupAndPlay); #ifdef __STEM__ - for (int stemIdx = 1; stemIdx <= mixxx::kMaxSupportedStems; stemIdx++) { - m_loadSelectedTrackStemAndPlay.emplace_back( - std::make_unique(ConfigKey(group, - QStringLiteral("load_selected_track_stem_%1_and_play").arg(stemIdx)))); - connect(m_loadSelectedTrackStemAndPlay.back().get(), - &ControlObject::valueChanged, - this, - [this, stemIdx](double value) { - if (value > 0) { - emit loadToGroup(m_group, stemIdx, true); - } - }); - m_loadSelectedTrackStem.emplace_back( - std::make_unique(ConfigKey(group, - QStringLiteral("load_selected_track_stem_%1").arg(stemIdx)))); - connect(m_loadSelectedTrackStem.back().get(), - &ControlObject::valueChanged, - this, - [this, stemIdx](double value) { - if (value > 0) { - emit loadToGroup(m_group, stemIdx, false); - } - }); - } + m_loadSelectedTrackStems = + std::make_unique(ConfigKey(group, "load_selected_track_stems")); + connect(m_loadSelectedTrackStems.get(), + &ControlObject::valueChanged, + this, + [this](double value) { + if (value >= 0 && value <= 2 << mixxx::kMaxSupportedStems) { + emit loadToGroup(m_group, static_cast(value), false); + } + }); #endif connect(this, @@ -77,7 +63,7 @@ void LoadToGroupController::slotLoadToGroup(double v) { if (v > 0) { emit loadToGroup(m_group, #ifdef __STEM__ - mixxx::kNoStemSelectedIdx, + mixxx::kNoStemSelected, #endif false); } @@ -85,11 +71,14 @@ void LoadToGroupController::slotLoadToGroup(double v) { void LoadToGroupController::slotLoadToGroupAndPlay(double v) { if (v > 0) { - emit loadToGroup(m_group, #ifdef __STEM__ - mixxx::kNoStemSelectedIdx, -#endif + emit loadToGroup(m_group, + mixxx::kNoStemSelected, true); +#else + emit loadToGroup(m_group, + true); +#endif } } @@ -635,22 +624,22 @@ void LibraryControl::slotUpdateTrackMenuControl(bool visible) { m_pShowTrackMenu->setAndConfirm(visible ? 1.0 : 0.0); } -void LibraryControl::slotLoadSelectedTrackToGroup(const QString& group, #ifdef __STEM__ - uint stemIdx, +void LibraryControl::slotLoadSelectedTrackToGroup(const QString& group, uint stemMask, bool play) { +#else +void LibraryControl::slotLoadSelectedTrackToGroup(const QString& group, bool play) { #endif - bool play) { if (!m_pLibraryWidget) { return; } WTrackTableView* pTrackTableView = m_pLibraryWidget->getCurrentTrackTableView(); if (pTrackTableView) { - pTrackTableView->loadSelectedTrackToGroup(group, #ifdef __STEM__ - stemIdx, + pTrackTableView->loadSelectedTrackToGroup(group, stemMask, play); +#else + pTrackTableView->loadSelectedTrackToGroup(group, play); #endif - play); } } diff --git a/src/library/librarycontrol.h b/src/library/librarycontrol.h index d0557269a8c..dbc3ea66c8b 100644 --- a/src/library/librarycontrol.h +++ b/src/library/librarycontrol.h @@ -23,11 +23,14 @@ class LoadToGroupController : public QObject { virtual ~LoadToGroupController(); signals: - void loadToGroup(const QString& group, #ifdef __STEM__ - uint stemIdx, -#endif + void loadToGroup(const QString& group, + uint stemMask, bool); +#else + void loadToGroup(const QString& group, + bool); +#endif public slots: void slotLoadToGroup(double v); @@ -39,8 +42,7 @@ class LoadToGroupController : public QObject { std::unique_ptr m_pLoadAndPlayControl; #ifdef __STEM__ - std::vector> m_loadSelectedTrackStemAndPlay; - std::vector> m_loadSelectedTrackStem; + std::unique_ptr m_loadSelectedTrackStems; #endif }; @@ -63,11 +65,11 @@ class LibraryControl : public QObject { public slots: // Deprecated navigation slots - void slotLoadSelectedTrackToGroup(const QString& group, #ifdef __STEM__ - uint stemIdx, + void slotLoadSelectedTrackToGroup(const QString& group, uint stemMask, bool play); +#else + void slotLoadSelectedTrackToGroup(const QString& group, bool play); #endif - bool play); void slotUpdateTrackMenuControl(bool visible); private slots: diff --git a/src/library/libraryfeature.h b/src/library/libraryfeature.h index 2ceaffbe619..9840d4424b2 100644 --- a/src/library/libraryfeature.h +++ b/src/library/libraryfeature.h @@ -135,12 +135,16 @@ class LibraryFeature : public QObject { void showTrackModel(QAbstractItemModel* model, bool restoreState = true); void switchToView(const QString& view); void loadTrack(TrackPointer pTrack); +#ifdef __STEM__ void loadTrackToPlayer(TrackPointer pTrack, const QString& group, -#ifdef __STEM__ - uint stemIdx, -#endif + uint stemMask, bool play = false); +#else + void loadTrackToPlayer(TrackPointer pTrack, + const QString& group, + bool play = false); +#endif /// saves the scroll, selection and current state of the library model void saveModelState(); /// restores the scroll, selection and current state of the library model diff --git a/src/library/recording/dlgrecording.h b/src/library/recording/dlgrecording.h index 8cd3d741021..3ea574632cb 100644 --- a/src/library/recording/dlgrecording.h +++ b/src/library/recording/dlgrecording.h @@ -37,11 +37,11 @@ class DlgRecording : public QWidget, public Ui::DlgRecording, public virtual Lib signals: void loadTrack(TrackPointer tio); - void loadTrackToPlayer(TrackPointer tio, const QString& group, #ifdef __STEM__ - uint stemIdx, + void loadTrackToPlayer(TrackPointer tio, const QString& group, uint stemMask, bool); +#else + void loadTrackToPlayer(TrackPointer tio, const QString& group, bool); #endif - bool play); void restoreSearch(const QString& search); void restoreModelState(); diff --git a/src/library/tabledelegates/previewbuttondelegate.cpp b/src/library/tabledelegates/previewbuttondelegate.cpp index 1c8a2c1d910..d4b695a3636 100644 --- a/src/library/tabledelegates/previewbuttondelegate.cpp +++ b/src/library/tabledelegates/previewbuttondelegate.cpp @@ -222,7 +222,7 @@ void PreviewButtonDelegate::buttonClicked() { // Load to preview deck and start playing emit loadTrackToPlayer(pTrack, kPreviewDeckGroup, #ifdef __STEM__ - mixxx::kNoStemSelectedIdx, + mixxx::kNoStemSelected, #endif true); startedPlaying = true; diff --git a/src/library/tabledelegates/previewbuttondelegate.h b/src/library/tabledelegates/previewbuttondelegate.h index 7f50caddb59..a7a9be95dbe 100644 --- a/src/library/tabledelegates/previewbuttondelegate.h +++ b/src/library/tabledelegates/previewbuttondelegate.h @@ -54,12 +54,11 @@ class PreviewButtonDelegate : public TableItemDelegate { const QModelIndex& index) const override; signals: - void loadTrackToPlayer(const TrackPointer& pTrack, - const QString& group, #ifdef __STEM__ - uint stemIdx, + void loadTrackToPlayer(const TrackPointer& pTrack, const QString& group, uint stemMask, bool); +#else + void loadTrackToPlayer(const TrackPointer& pTrack, const QString& group, bool); #endif - bool play); void buttonSetChecked(bool); public slots: diff --git a/src/mixer/basetrackplayer.cpp b/src/mixer/basetrackplayer.cpp index 55c0cfaf3a7..5e284a99d1f 100644 --- a/src/mixer/basetrackplayer.cpp +++ b/src/mixer/basetrackplayer.cpp @@ -417,7 +417,7 @@ void BaseTrackPlayerImpl::slotEjectTrack(double v) { if (lastEjected) { slotLoadTrack(lastEjected, #ifdef __STEM__ - mixxx::kNoStemSelectedIdx, + mixxx::kNoStemSelected, #endif false); } @@ -430,7 +430,7 @@ void BaseTrackPlayerImpl::slotEjectTrack(double v) { if (lastEjected) { slotLoadTrack(lastEjected, #ifdef __STEM__ - mixxx::kNoStemSelectedIdx, + mixxx::kNoStemSelected, #endif false); } @@ -546,11 +546,14 @@ void BaseTrackPlayerImpl::disconnectLoadedTrack() { disconnect(m_pLoadedTrack.get(), nullptr, m_pKey.get(), nullptr); } -void BaseTrackPlayerImpl::slotLoadTrack(TrackPointer pNewTrack, #ifdef __STEM__ - uint stemIdx, -#endif +void BaseTrackPlayerImpl::slotLoadTrack(TrackPointer pNewTrack, + uint stemMask, bool bPlay) { +#else +void BaseTrackPlayerImpl::slotLoadTrack(TrackPointer pNewTrack, + bool bPlay) { +#endif //qDebug() << "BaseTrackPlayerImpl::slotLoadTrack" << getGroup() << pNewTrack.get(); // Before loading the track, ensure we have access. This uses lazy // evaluation to make sure track isn't NULL before we dereference it. @@ -575,12 +578,12 @@ void BaseTrackPlayerImpl::slotLoadTrack(TrackPointer pNewTrack, EngineBuffer* pEngineBuffer = m_pChannel->getEngineBuffer(); #ifdef __STEM__ pEngineBuffer->loadTrack(pNewTrack, - stemIdx, + stemMask, bPlay, m_pChannelToCloneFrom); // Select a specific stem if requested - emit selectedStem(stemIdx); + emit selectedStems(stemMask); #else pEngineBuffer->loadTrack(pNewTrack, bPlay, m_pChannelToCloneFrom); #endif @@ -796,7 +799,7 @@ void BaseTrackPlayerImpl::slotCloneChannel(EngineChannel* pChannel) { bool play = ControlObject::toBool(ConfigKey(m_pChannelToCloneFrom->getGroup(), "play")); slotLoadTrack(pTrack, #ifdef __STEM__ - mixxx::kNoStemSelectedIdx, + mixxx::kNoStemSelected, #endif play); } @@ -824,7 +827,7 @@ void BaseTrackPlayerImpl::loadTrackFromGroup(const QString& group) { slotLoadTrack(pTrack, #ifdef __STEM__ - mixxx::kNoStemSelectedIdx, + mixxx::kNoStemSelected, #endif false); } diff --git a/src/mixer/basetrackplayer.h b/src/mixer/basetrackplayer.h index 8c6b3812e3c..87e096e4a35 100644 --- a/src/mixer/basetrackplayer.h +++ b/src/mixer/basetrackplayer.h @@ -45,11 +45,14 @@ class BaseTrackPlayer : public BasePlayer { }; public slots: - virtual void slotLoadTrack(TrackPointer pTrack, #ifdef __STEM__ - uint stemIdx, -#endif + virtual void slotLoadTrack(TrackPointer pTrack, + uint stemMask, bool bPlay = false) = 0; +#else + virtual void slotLoadTrack(TrackPointer pTrack, + bool bPlay = false) = 0; +#endif virtual void slotCloneFromGroup(const QString& group) = 0; virtual void slotCloneDeck() = 0; virtual void slotEjectTrack(double) = 0; @@ -61,7 +64,7 @@ class BaseTrackPlayer : public BasePlayer { void trackUnloaded(TrackPointer pUnloadedTrack); void loadingTrack(TrackPointer pNewTrack, TrackPointer pOldTrack); #ifdef __STEM__ - void selectedStem(uint stemIdx); + void selectedStems(uint stemMask); #endif void playerEmpty(); void noVinylControlInputConfigured(); @@ -100,11 +103,14 @@ class BaseTrackPlayerImpl : public BaseTrackPlayer { TrackPointer loadFakeTrack(bool bPlay, double filebpm); public slots: - void slotLoadTrack(TrackPointer track, #ifdef __STEM__ - uint stemIdx, -#endif + void slotLoadTrack(TrackPointer track, + uint stemMask, bool bPlay) final; +#else + void slotLoadTrack(TrackPointer track, + bool bPlay) final; +#endif void slotEjectTrack(double) final; void slotCloneFromGroup(const QString& group) final; void slotCloneDeck() final; diff --git a/src/mixer/playermanager.cpp b/src/mixer/playermanager.cpp index f5a4ad240d6..aa4cf90b28f 100644 --- a/src/mixer/playermanager.cpp +++ b/src/mixer/playermanager.cpp @@ -660,12 +660,13 @@ void PlayerManager::slotCloneDeck(const QString& source_group, const QString& ta pPlayer->slotCloneFromGroup(source_group); } -void PlayerManager::slotLoadTrackToPlayer( - TrackPointer pTrack, const QString& group, #ifdef __STEM__ - uint stemIdx, +void PlayerManager::slotLoadTrackToPlayer( + TrackPointer pTrack, const QString& group, uint stemMask, bool play) { +#else +void PlayerManager::slotLoadTrackToPlayer( + TrackPointer pTrack, const QString& group, bool play) { #endif - bool play) { // Do not lock mutex in this method unless it is changed to access // PlayerManager state. BaseTrackPlayer* pPlayer = getPlayer(group); @@ -716,11 +717,11 @@ void PlayerManager::slotLoadTrackToPlayer( if (clone) { pPlayer->slotCloneDeck(); } else { - pPlayer->slotLoadTrack(pTrack, #ifdef __STEM__ - stemIdx, + pPlayer->slotLoadTrack(pTrack, stemMask, play); +#else + pPlayer->slotLoadTrack(pTrack, play); #endif - play); } m_lastLoadedPlayer = group; @@ -774,7 +775,7 @@ void PlayerManager::slotLoadTrackIntoNextAvailableDeck(TrackPointer pTrack) { pDeck->slotLoadTrack(pTrack, #ifdef __STEM__ - mixxx::kNoStemSelectedIdx, + mixxx::kNoStemSelected, #endif false); } diff --git a/src/mixer/playermanager.h b/src/mixer/playermanager.h index 4641694ddd1..d7aca58440c 100644 --- a/src/mixer/playermanager.h +++ b/src/mixer/playermanager.h @@ -185,11 +185,11 @@ class PlayerManager : public QObject, public PlayerManagerInterface { public slots: // Slots for loading tracks into a Player, which is either a Sampler or a Deck - void slotLoadTrackToPlayer(TrackPointer pTrack, const QString& group, #ifdef __STEM__ - uint stemIdx, + void slotLoadTrackToPlayer(TrackPointer pTrack, const QString& group, uint stemMask, bool play); +#else + void slotLoadTrackToPlayer(TrackPointer pTrack, const QString& group, bool play); #endif - bool play); void slotLoadLocationToPlayer(const QString& location, const QString& group, bool play); void slotLoadLocationToPlayerMaybePlay(const QString& location, const QString& group); diff --git a/src/mixer/samplerbank.cpp b/src/mixer/samplerbank.cpp index 2ceaf70704e..dca2e1b4112 100644 --- a/src/mixer/samplerbank.cpp +++ b/src/mixer/samplerbank.cpp @@ -215,7 +215,7 @@ bool SamplerBank::loadSamplerBankFromPath(const QString& samplerBankPath) { m_pPlayerManager->slotLoadTrackToPlayer( TrackPointer(), group, #ifdef __STEM__ - mixxx::kNoStemSelectedIdx, + mixxx::kNoStemSelected, #endif false); } else { diff --git a/src/skin/legacy/legacyskinparser.cpp b/src/skin/legacy/legacyskinparser.cpp index 467b928c331..e0a01c50bda 100644 --- a/src/skin/legacy/legacyskinparser.cpp +++ b/src/skin/legacy/legacyskinparser.cpp @@ -1038,6 +1038,17 @@ QWidget* LegacySkinParser::parseVisual(const QDomElement& node) { &BaseTrackPlayer::loadingTrack, viewer, &WWaveformViewer::slotLoadingTrack); +#ifdef __STEM__ + QObject::connect(pPlayer, + &BaseTrackPlayer::selectedStems, + viewer, + &WWaveformViewer::slotSelectStem); +#endif + + QObject::connect(pPlayer, + &BaseTrackPlayer::trackUnloaded, + viewer, + &WWaveformViewer::slotTrackUnloaded); connect(viewer, &WWaveformViewer::trackDropped, diff --git a/src/sources/audiosource.h b/src/sources/audiosource.h index 4284bff1b56..9a77cb8beab 100644 --- a/src/sources/audiosource.h +++ b/src/sources/audiosource.h @@ -195,36 +195,37 @@ class AudioSource : public UrlResource, public virtual /*implements*/ IAudioSour public: #ifdef __STEM__ OpenParams() - : m_signalInfo(), m_stemIdx(mixxx::kNoStemSelectedIdx) { + : m_signalInfo(), m_stemMask(mixxx::kNoStemSelected) { + } + + OpenParams( + audio::ChannelCount channelCount, + audio::SampleRate sampleRate, + uint stemMask = mixxx::kNoStemSelected) + : m_signalInfo( + channelCount, + sampleRate), + m_stemMask(stemMask) { } #else OpenParams() = default; -#endif + OpenParams( audio::ChannelCount channelCount, - audio::SampleRate sampleRate -#ifdef __STEM__ - , - uint stemIdx = mixxx::kNoStemSelectedIdx -#endif - ) + audio::SampleRate sampleRate) : m_signalInfo( channelCount, - sampleRate) -#ifdef __STEM__ - , - m_stemIdx(stemIdx) -#endif - { + sampleRate) { } +#endif const audio::SignalInfo& getSignalInfo() const { return m_signalInfo; } #ifdef __STEM__ - uint stemIdx() const { - return m_stemIdx; + uint stemMask() const { + return m_stemMask; } #endif @@ -234,12 +235,12 @@ class AudioSource : public UrlResource, public virtual /*implements*/ IAudioSour } #ifdef __STEM__ - void setStemIdx( - uint stemIdx) { - VERIFY_OR_DEBUG_ASSERT(stemIdx <= mixxx::kMaxSupportedStems) { + void setStemMask( + uint stemMask) { + VERIFY_OR_DEBUG_ASSERT(stemMask <= 2 << mixxx::kMaxSupportedStems) { return; } - m_stemIdx = stemIdx; + m_stemMask = stemMask; } #endif @@ -251,7 +252,7 @@ class AudioSource : public UrlResource, public virtual /*implements*/ IAudioSour private: audio::SignalInfo m_signalInfo; #ifdef __STEM__ - uint m_stemIdx; + uint m_stemMask; #endif }; diff --git a/src/sources/soundsourcestem.cpp b/src/sources/soundsourcestem.cpp index c4e6edef9d9..5e6ec817398 100644 --- a/src/sources/soundsourcestem.cpp +++ b/src/sources/soundsourcestem.cpp @@ -323,10 +323,10 @@ SoundSource::OpenResult SoundSourceSTEM::tryOpen( AVStream* firstAudioStream = nullptr; int stemCount = 0; - uint selectedStem = params.stemIdx(); - VERIFY_OR_DEBUG_ASSERT(selectedStem <= mixxx::kMaxSupportedStems) { + uint selectedStemMask = params.stemMask(); + VERIFY_OR_DEBUG_ASSERT(selectedStemMask <= 2 << mixxx::kMaxSupportedStems) { kLogger.warning().noquote() - << "Invalid selected stem Idx" << selectedStem; + << "Invalid selected stem mask" << selectedStemMask; return OpenResult::Failed; } OpenParams stemParam = params; @@ -371,7 +371,8 @@ SoundSource::OpenResult SoundSourceSTEM::tryOpen( stemCount++; } - if (selectedStem && selectedStem != streamIdx) { + // StemIdx is equal to StreamIdx -1 (the main mix) + if (selectedStemMask && !(selectedStemMask & 1 << (streamIdx - 1))) { continue; } @@ -390,9 +391,16 @@ SoundSource::OpenResult SoundSourceSTEM::tryOpen( return OpenResult::Failed; } + VERIFY_OR_DEBUG_ASSERT(!m_pStereoStreams.empty()) { + kLogger.warning().noquote() + << "no stem track were selected"; + close(); + return OpenResult::Failed; + } + if (params.getSignalInfo().getChannelCount() == mixxx::audio::ChannelCount::stereo() || - selectedStem) { + selectedStemMask) { // Requesting a stereo stream (used for samples and preview decks) m_requestedChannelCount = mixxx::audio::ChannelCount::stereo(); initChannelCountOnce(mixxx::audio::ChannelCount::stereo()); diff --git a/src/test/autodjprocessor_test.cpp b/src/test/autodjprocessor_test.cpp index 254bb1ad9a7..048ab390214 100644 --- a/src/test/autodjprocessor_test.cpp +++ b/src/test/autodjprocessor_test.cpp @@ -269,7 +269,7 @@ TEST_F(AutoDJProcessorTest, FullIntroOutro_LongerIntro) { // Load track and mark it playing. deck1.slotLoadTrack(pTrack, #ifdef __STEM__ - mixxx::kNoStemSelectedIdx, + mixxx::kNoStemSelected, #endif true); // Indicate the track loaded successfully. @@ -290,7 +290,7 @@ TEST_F(AutoDJProcessorTest, FullIntroOutro_LongerIntro) { // Pretend the track load succeeds. deck2.slotLoadTrack(pTrack, #ifdef __STEM__ - mixxx::kNoStemSelectedIdx, + mixxx::kNoStemSelected, #endif false); @@ -351,7 +351,7 @@ TEST_F(AutoDJProcessorTest, FullIntroOutro_LongerOutro) { // Load track and mark it playing. deck1.slotLoadTrack(pTrack, #ifdef __STEM__ - mixxx::kNoStemSelectedIdx, + mixxx::kNoStemSelected, #endif true); // Indicate the track loaded successfully. @@ -372,7 +372,7 @@ TEST_F(AutoDJProcessorTest, FullIntroOutro_LongerOutro) { // Pretend the track load succeeds. deck2.slotLoadTrack(pTrack, #ifdef __STEM__ - mixxx::kNoStemSelectedIdx, + mixxx::kNoStemSelected, #endif false); @@ -439,7 +439,7 @@ TEST_F(AutoDJProcessorTest, FadeAtOutroStart_LongerIntro) { // Load track and mark it playing. deck1.slotLoadTrack(pTrack, #ifdef __STEM__ - mixxx::kNoStemSelectedIdx, + mixxx::kNoStemSelected, #endif true); // Indicate the track loaded successfully. @@ -460,7 +460,7 @@ TEST_F(AutoDJProcessorTest, FadeAtOutroStart_LongerIntro) { // Pretend the track load succeeds. deck2.slotLoadTrack(pTrack, #ifdef __STEM__ - mixxx::kNoStemSelectedIdx, + mixxx::kNoStemSelected, #endif false); @@ -523,7 +523,7 @@ TEST_F(AutoDJProcessorTest, FadeAtOutroStart_LongerOutro) { // Load track and mark it playing. deck1.slotLoadTrack(pTrack, #ifdef __STEM__ - mixxx::kNoStemSelectedIdx, + mixxx::kNoStemSelected, #endif true); // Indicate the track loaded successfully. @@ -544,7 +544,7 @@ TEST_F(AutoDJProcessorTest, FadeAtOutroStart_LongerOutro) { // Pretend the track load succeeds. deck2.slotLoadTrack(pTrack, #ifdef __STEM__ - mixxx::kNoStemSelectedIdx, + mixxx::kNoStemSelected, #endif false); @@ -678,7 +678,7 @@ TEST_F(AutoDJProcessorTest, EnabledSuccess_DecksStopped) { TrackPointer pTrack = trackCollectionManager()->getTrackById(testId); deck1.slotLoadTrack(pTrack, #ifdef __STEM__ - mixxx::kNoStemSelectedIdx, + mixxx::kNoStemSelected, #endif true); @@ -728,7 +728,7 @@ TEST_F(AutoDJProcessorTest, EnabledSuccess_DecksStopped_TrackLoadFails) { TrackPointer pTrack(newTestTrack(testId)); deck1.slotLoadTrack(pTrack, #ifdef __STEM__ - mixxx::kNoStemSelectedIdx, + mixxx::kNoStemSelected, #endif true); @@ -750,7 +750,7 @@ TEST_F(AutoDJProcessorTest, EnabledSuccess_DecksStopped_TrackLoadFails) { // Now pretend that the follow-up load request succeeded. deck1.slotLoadTrack(pTrack, #ifdef __STEM__ - mixxx::kNoStemSelectedIdx, + mixxx::kNoStemSelected, #endif true); deck1.fakeTrackLoadedEvent(pTrack); @@ -802,7 +802,7 @@ TEST_F(AutoDJProcessorTest, EnabledSuccess_DecksStopped_TrackLoadFailsRightDeck) TrackPointer pTrack(newTestTrack(testId)); deck1.slotLoadTrack(pTrack, #ifdef __STEM__ - mixxx::kNoStemSelectedIdx, + mixxx::kNoStemSelected, #endif true); @@ -830,7 +830,7 @@ TEST_F(AutoDJProcessorTest, EnabledSuccess_DecksStopped_TrackLoadFailsRightDeck) // Now pretend that the deck2 load request failed. deck2.slotLoadTrack(pTrack, #ifdef __STEM__ - mixxx::kNoStemSelectedIdx, + mixxx::kNoStemSelected, #endif false); deck2.fakeTrackLoadFailedEvent(pTrack); @@ -841,7 +841,7 @@ TEST_F(AutoDJProcessorTest, EnabledSuccess_DecksStopped_TrackLoadFailsRightDeck) // Pretend the deck2 load request succeeded. deck2.slotLoadTrack(pTrack, #ifdef __STEM__ - mixxx::kNoStemSelectedIdx, + mixxx::kNoStemSelected, #endif false); deck2.fakeTrackLoadedEvent(pTrack); @@ -862,7 +862,7 @@ TEST_F(AutoDJProcessorTest, EnabledSuccess_PlayingDeck1) { // Load track and mark it playing. deck1.slotLoadTrack(pTrack, #ifdef __STEM__ - mixxx::kNoStemSelectedIdx, + mixxx::kNoStemSelected, #endif true); // Indicate the track loaded successfully. @@ -888,7 +888,7 @@ TEST_F(AutoDJProcessorTest, EnabledSuccess_PlayingDeck1) { // Pretend the track load succeeds. deck2.slotLoadTrack(pTrack, #ifdef __STEM__ - mixxx::kNoStemSelectedIdx, + mixxx::kNoStemSelected, #endif false); deck2.fakeTrackLoadedEvent(pTrack); @@ -909,7 +909,7 @@ TEST_F(AutoDJProcessorTest, EnabledSuccess_PlayingDeck1_TrackLoadFailed) { // Load track and mark it playing. deck1.slotLoadTrack(pTrack, #ifdef __STEM__ - mixxx::kNoStemSelectedIdx, + mixxx::kNoStemSelected, #endif true); // Indicate the track loaded successfully. @@ -942,7 +942,7 @@ TEST_F(AutoDJProcessorTest, EnabledSuccess_PlayingDeck1_TrackLoadFailed) { // Pretend the track load fails. deck2.slotLoadTrack(pTrack, #ifdef __STEM__ - mixxx::kNoStemSelectedIdx, + mixxx::kNoStemSelected, #endif false); deck2.fakeTrackLoadFailedEvent(pTrack); @@ -956,7 +956,7 @@ TEST_F(AutoDJProcessorTest, EnabledSuccess_PlayingDeck1_TrackLoadFailed) { // Pretend the track load succeeds. deck2.slotLoadTrack(pTrack, #ifdef __STEM__ - mixxx::kNoStemSelectedIdx, + mixxx::kNoStemSelected, #endif false); deck2.fakeTrackLoadedEvent(pTrack); @@ -977,7 +977,7 @@ TEST_F(AutoDJProcessorTest, EnabledSuccess_PlayingDeck2) { // Load track and mark it playing. deck2.slotLoadTrack(pTrack, #ifdef __STEM__ - mixxx::kNoStemSelectedIdx, + mixxx::kNoStemSelected, #endif true); // Indicate the track loaded successfully. @@ -1004,7 +1004,7 @@ TEST_F(AutoDJProcessorTest, EnabledSuccess_PlayingDeck2) { // Pretend the track load succeeds. deck1.slotLoadTrack(pTrack, #ifdef __STEM__ - mixxx::kNoStemSelectedIdx, + mixxx::kNoStemSelected, #endif false); deck1.fakeTrackLoadedEvent(pTrack); @@ -1025,7 +1025,7 @@ TEST_F(AutoDJProcessorTest, EnabledSuccess_PlayingDeck2_TrackLoadFailed) { // Load track and mark it playing. deck2.slotLoadTrack(pTrack, #ifdef __STEM__ - mixxx::kNoStemSelectedIdx, + mixxx::kNoStemSelected, #endif true); // Indicate the track loaded successfully. @@ -1058,7 +1058,7 @@ TEST_F(AutoDJProcessorTest, EnabledSuccess_PlayingDeck2_TrackLoadFailed) { // Pretend the track load fails. deck1.slotLoadTrack(pTrack, #ifdef __STEM__ - mixxx::kNoStemSelectedIdx, + mixxx::kNoStemSelected, #endif false); deck1.fakeTrackLoadFailedEvent(pTrack); @@ -1072,7 +1072,7 @@ TEST_F(AutoDJProcessorTest, EnabledSuccess_PlayingDeck2_TrackLoadFailed) { // Pretend the track load succeeds. deck1.slotLoadTrack(pTrack, #ifdef __STEM__ - mixxx::kNoStemSelectedIdx, + mixxx::kNoStemSelected, #endif false); deck1.fakeTrackLoadedEvent(pTrack); @@ -1111,7 +1111,7 @@ TEST_F(AutoDJProcessorTest, FadeToDeck1_LoadOnDeck2_TrackLoadSuccess) { // Load track and mark it playing. deck2.slotLoadTrack(pTrack, #ifdef __STEM__ - mixxx::kNoStemSelectedIdx, + mixxx::kNoStemSelected, #endif true); // Indicate the track loaded successfully. @@ -1140,7 +1140,7 @@ TEST_F(AutoDJProcessorTest, FadeToDeck1_LoadOnDeck2_TrackLoadSuccess) { // Pretend the track load succeeds. deck1.slotLoadTrack(pTrack, #ifdef __STEM__ - mixxx::kNoStemSelectedIdx, + mixxx::kNoStemSelected, #endif false); deck1.fakeTrackLoadedEvent(pTrack); @@ -1187,7 +1187,7 @@ TEST_F(AutoDJProcessorTest, FadeToDeck1_LoadOnDeck2_TrackLoadSuccess) { // Pretend the track load request succeeds. deck2.slotLoadTrack(pTrack, #ifdef __STEM__ - mixxx::kNoStemSelectedIdx, + mixxx::kNoStemSelected, #endif false); deck2.fakeTrackLoadedEvent(pTrack); @@ -1210,7 +1210,7 @@ TEST_F(AutoDJProcessorTest, FadeToDeck1_LoadOnDeck2_TrackLoadFailed) { // Load track and mark it playing. deck2.slotLoadTrack(pTrack, #ifdef __STEM__ - mixxx::kNoStemSelectedIdx, + mixxx::kNoStemSelected, #endif true); // Indicate the track loaded successfully. @@ -1241,7 +1241,7 @@ TEST_F(AutoDJProcessorTest, FadeToDeck1_LoadOnDeck2_TrackLoadFailed) { // Pretend the track load succeeds. deck1.slotLoadTrack(pTrack, #ifdef __STEM__ - mixxx::kNoStemSelectedIdx, + mixxx::kNoStemSelected, #endif false); deck1.fakeTrackLoadedEvent(pTrack); @@ -1292,7 +1292,7 @@ TEST_F(AutoDJProcessorTest, FadeToDeck1_LoadOnDeck2_TrackLoadFailed) { // Pretend the track load request fails. deck2.slotLoadTrack(pTrack, #ifdef __STEM__ - mixxx::kNoStemSelectedIdx, + mixxx::kNoStemSelected, #endif false); deck2.fakeTrackLoadFailedEvent(pTrack); @@ -1306,7 +1306,7 @@ TEST_F(AutoDJProcessorTest, FadeToDeck1_LoadOnDeck2_TrackLoadFailed) { // Pretend the second track load request succeeds. deck2.slotLoadTrack(pTrack, #ifdef __STEM__ - mixxx::kNoStemSelectedIdx, + mixxx::kNoStemSelected, #endif false); deck2.fakeTrackLoadedEvent(pTrack); @@ -1329,7 +1329,7 @@ TEST_F(AutoDJProcessorTest, FadeToDeck2_LoadOnDeck1_TrackLoadSuccess) { // Load track and mark it playing. deck1.slotLoadTrack(pTrack, #ifdef __STEM__ - mixxx::kNoStemSelectedIdx, + mixxx::kNoStemSelected, #endif true); // Indicate the track loaded successfully. @@ -1358,7 +1358,7 @@ TEST_F(AutoDJProcessorTest, FadeToDeck2_LoadOnDeck1_TrackLoadSuccess) { // Pretend the track load succeeds. deck2.slotLoadTrack(pTrack, #ifdef __STEM__ - mixxx::kNoStemSelectedIdx, + mixxx::kNoStemSelected, #endif false); deck2.fakeTrackLoadedEvent(pTrack); @@ -1405,7 +1405,7 @@ TEST_F(AutoDJProcessorTest, FadeToDeck2_LoadOnDeck1_TrackLoadSuccess) { // Pretend the track load request succeeds. deck1.slotLoadTrack(pTrack, #ifdef __STEM__ - mixxx::kNoStemSelectedIdx, + mixxx::kNoStemSelected, #endif false); deck1.fakeTrackLoadedEvent(pTrack); @@ -1428,7 +1428,7 @@ TEST_F(AutoDJProcessorTest, FadeToDeck2_LoadOnDeck1_TrackLoadFailed) { // Load track and mark it playing. deck1.slotLoadTrack(pTrack, #ifdef __STEM__ - mixxx::kNoStemSelectedIdx, + mixxx::kNoStemSelected, #endif true); // Indicate the track loaded successfully. @@ -1459,7 +1459,7 @@ TEST_F(AutoDJProcessorTest, FadeToDeck2_LoadOnDeck1_TrackLoadFailed) { // Pretend the track load succeeds. deck2.slotLoadTrack(pTrack, #ifdef __STEM__ - mixxx::kNoStemSelectedIdx, + mixxx::kNoStemSelected, #endif false); deck2.fakeTrackLoadedEvent(pTrack); @@ -1510,7 +1510,7 @@ TEST_F(AutoDJProcessorTest, FadeToDeck2_LoadOnDeck1_TrackLoadFailed) { // Pretend the track load request fails. deck1.slotLoadTrack(pTrack, #ifdef __STEM__ - mixxx::kNoStemSelectedIdx, + mixxx::kNoStemSelected, #endif false); deck1.fakeTrackLoadFailedEvent(pTrack); @@ -1524,7 +1524,7 @@ TEST_F(AutoDJProcessorTest, FadeToDeck2_LoadOnDeck1_TrackLoadFailed) { // Pretend the track load request succeeds. deck1.slotLoadTrack(pTrack, #ifdef __STEM__ - mixxx::kNoStemSelectedIdx, + mixxx::kNoStemSelected, #endif false); deck1.fakeTrackLoadedEvent(pTrack); @@ -1550,7 +1550,7 @@ TEST_F(AutoDJProcessorTest, FadeToDeck2_Long_Transition) { // Load track and mark it playing. deck1.slotLoadTrack(pTrack, #ifdef __STEM__ - mixxx::kNoStemSelectedIdx, + mixxx::kNoStemSelected, #endif true); // Indicate the track loaded successfully. @@ -1571,7 +1571,7 @@ TEST_F(AutoDJProcessorTest, FadeToDeck2_Long_Transition) { // Pretend the track load succeeds. deck2.slotLoadTrack(pTrack, #ifdef __STEM__ - mixxx::kNoStemSelectedIdx, + mixxx::kNoStemSelected, #endif false); deck2.fakeTrackLoadedEvent(pTrack); @@ -1647,7 +1647,7 @@ TEST_F(AutoDJProcessorTest, FadeToDeck2_Pause_Transition) { // Load track and mark it playing. deck1.slotLoadTrack(pTrack, #ifdef __STEM__ - mixxx::kNoStemSelectedIdx, + mixxx::kNoStemSelected, #endif true); // Indicate the track loaded successfully. @@ -1667,7 +1667,7 @@ TEST_F(AutoDJProcessorTest, FadeToDeck2_Pause_Transition) { // Pretend the track load succeeds. deck2.slotLoadTrack(pTrack, #ifdef __STEM__ - mixxx::kNoStemSelectedIdx, + mixxx::kNoStemSelected, #endif false); deck2.fakeTrackLoadedEvent(pTrack); @@ -1685,7 +1685,7 @@ TEST_F(AutoDJProcessorTest, FadeToDeck2_Pause_Transition) { // Pretend the track load succeeds. deck2.slotLoadTrack(pTrack, #ifdef __STEM__ - mixxx::kNoStemSelectedIdx, + mixxx::kNoStemSelected, #endif false); deck2.fakeTrackLoadedEvent(pTrack); @@ -1739,7 +1739,7 @@ TEST_F(AutoDJProcessorTest, FadeToDeck2_SeekEnd) { // Load track and mark it playing. deck1.slotLoadTrack(pTrack, #ifdef __STEM__ - mixxx::kNoStemSelectedIdx, + mixxx::kNoStemSelected, #endif true); // Indicate the track loaded successfully. @@ -1760,7 +1760,7 @@ TEST_F(AutoDJProcessorTest, FadeToDeck2_SeekEnd) { // Pretend the track load succeeds. deck2.slotLoadTrack(pTrack, #ifdef __STEM__ - mixxx::kNoStemSelectedIdx, + mixxx::kNoStemSelected, #endif false); deck2.fakeTrackLoadedEvent(pTrack); @@ -1799,7 +1799,7 @@ TEST_F(AutoDJProcessorTest, FadeToDeck2_SeekBeforeTransition) { // Load track and mark it playing. deck1.slotLoadTrack(pTrack, #ifdef __STEM__ - mixxx::kNoStemSelectedIdx, + mixxx::kNoStemSelected, #endif true); // Indicate the track loaded successfully. @@ -1820,7 +1820,7 @@ TEST_F(AutoDJProcessorTest, FadeToDeck2_SeekBeforeTransition) { // Pretend the track load succeeds. deck2.slotLoadTrack(pTrack, #ifdef __STEM__ - mixxx::kNoStemSelectedIdx, + mixxx::kNoStemSelected, #endif false); deck2.fakeTrackLoadedEvent(pTrack); @@ -1883,7 +1883,7 @@ TEST_F(AutoDJProcessorTest, TrackZeroLength) { pTrack->setDuration(0); deck1.slotLoadTrack(pTrack, #ifdef __STEM__ - mixxx::kNoStemSelectedIdx, + mixxx::kNoStemSelected, #endif true); diff --git a/src/test/cuecontrol_test.cpp b/src/test/cuecontrol_test.cpp index 399f983f1c2..d4aa2aabb7a 100644 --- a/src/test/cuecontrol_test.cpp +++ b/src/test/cuecontrol_test.cpp @@ -50,7 +50,7 @@ class CueControlTest : public BaseSignalPathTest { void unloadTrack() { m_pMixerDeck1->slotLoadTrack(TrackPointer(), #ifdef __STEM__ - mixxx::kNoStemSelectedIdx, + mixxx::kNoStemSelected, #endif false); } diff --git a/src/test/hotcuecontrol_test.cpp b/src/test/hotcuecontrol_test.cpp index df13f131ddc..303a00ad036 100644 --- a/src/test/hotcuecontrol_test.cpp +++ b/src/test/hotcuecontrol_test.cpp @@ -81,7 +81,7 @@ class HotcueControlTest : public BaseSignalPathTest { void unloadTrack() { m_pMixerDeck1->slotLoadTrack(TrackPointer(), #ifdef __STEM__ - mixxx::kNoStemSelectedIdx, + mixxx::kNoStemSelected, #endif false); } diff --git a/src/test/playermanagertest.cpp b/src/test/playermanagertest.cpp index ba5fd028b4d..d820847bc50 100644 --- a/src/test/playermanagertest.cpp +++ b/src/test/playermanagertest.cpp @@ -150,7 +150,7 @@ TEST_F(PlayerManagerTest, UnEjectTest) { ASSERT_TRUE(testId1.isValid()); deck1->slotLoadTrack(pTrack1, #ifdef __STEM__ - mixxx::kNoStemSelectedIdx, + mixxx::kNoStemSelected, #endif false); ASSERT_NE(nullptr, deck1->getLoadedTrack()); @@ -167,7 +167,7 @@ TEST_F(PlayerManagerTest, UnEjectTest) { ASSERT_NE(nullptr, pTrack2); deck1->slotLoadTrack(pTrack2, #ifdef __STEM__ - mixxx::kNoStemSelectedIdx, + mixxx::kNoStemSelected, #endif false); @@ -192,7 +192,7 @@ TEST_F(PlayerManagerTest, UnEjectReplaceTrackTest) { ASSERT_TRUE(testId1.isValid()); deck1->slotLoadTrack(pTrack1, #ifdef __STEM__ - mixxx::kNoStemSelectedIdx, + mixxx::kNoStemSelected, #endif false); ASSERT_NE(nullptr, deck1->getLoadedTrack()); @@ -205,7 +205,7 @@ TEST_F(PlayerManagerTest, UnEjectReplaceTrackTest) { ASSERT_NE(nullptr, pTrack2); deck1->slotLoadTrack(pTrack2, #ifdef __STEM__ - mixxx::kNoStemSelectedIdx, + mixxx::kNoStemSelected, #endif false); m_pEngine->process(1024); @@ -245,7 +245,7 @@ TEST_F(PlayerManagerTest, UnReplaceTest) { ASSERT_TRUE(testId1.isValid()); deck1->slotLoadTrack(pTrack1, #ifdef __STEM__ - mixxx::kNoStemSelectedIdx, + mixxx::kNoStemSelected, #endif false); m_pEngine->process(1024); @@ -257,7 +257,7 @@ TEST_F(PlayerManagerTest, UnReplaceTest) { ASSERT_NE(nullptr, pTrack2); deck1->slotLoadTrack(pTrack2, #ifdef __STEM__ - mixxx::kNoStemSelectedIdx, + mixxx::kNoStemSelected, #endif false); m_pEngine->process(1024); diff --git a/src/test/signalpathtest.h b/src/test/signalpathtest.h index e7ee5830e01..341c4670fc8 100644 --- a/src/test/signalpathtest.h +++ b/src/test/signalpathtest.h @@ -171,7 +171,7 @@ class BaseSignalPathTest : public MixxxTest, SoundSourceProviderRegistration { } pDeck->slotLoadTrack(pTrack, #ifdef __STEM__ - mixxx::kNoStemSelectedIdx, + mixxx::kNoStemSelected, #endif false); diff --git a/src/waveform/renderers/allshader/waveformrendererstem.cpp b/src/waveform/renderers/allshader/waveformrendererstem.cpp index cb9cee96069..40ff8cc2547 100644 --- a/src/waveform/renderers/allshader/waveformrendererstem.cpp +++ b/src/waveform/renderers/allshader/waveformrendererstem.cpp @@ -76,7 +76,7 @@ void WaveformRendererStem::paintGL() { return; } - uint selectedStem = m_waveformRenderer->getSelectedStem(); + uint selectedStems = m_waveformRenderer->getSelectedStems(); const float devicePixelRatio = m_waveformRenderer->getDevicePixelRatio(); const int length = static_cast(m_waveformRenderer->getLength() * devicePixelRatio); @@ -160,8 +160,8 @@ void WaveformRendererStem::paintGL() { // Apply the gains if (layerIdx) { max *= m_pStemMute[stemIdx]->toBool() || - (selectedStem && - selectedStem != stemIdx + 1) + (selectedStems && + !(selectedStems & 1 << stemIdx)) ? 0.f : static_cast(m_pStemGain[stemIdx]->get()); } diff --git a/src/waveform/renderers/waveformwidgetrenderer.cpp b/src/waveform/renderers/waveformwidgetrenderer.cpp index 1b28006a935..f21dcf2a8eb 100644 --- a/src/waveform/renderers/waveformwidgetrenderer.cpp +++ b/src/waveform/renderers/waveformwidgetrenderer.cpp @@ -22,7 +22,7 @@ constexpr int kDefaultDimBrightThreshold = 127; WaveformWidgetRenderer::WaveformWidgetRenderer(const QString& group) : m_group(group), #ifdef __STEM__ - m_selectedStem(0), + m_selectedStems(mixxx::kNoStemSelected), #endif m_orientation(Qt::Horizontal), m_dimBrightThreshold(kDefaultDimBrightThreshold), @@ -420,8 +420,8 @@ void WaveformWidgetRenderer::setDisplayBeatGridAlpha(int alpha) { } #ifdef __STEM__ -void WaveformWidgetRenderer::selectStem(uint stemIdx) { - m_selectedStem = stemIdx; +void WaveformWidgetRenderer::selectStem(uint stemMask) { + m_selectedStems = stemMask; } #endif diff --git a/src/waveform/renderers/waveformwidgetrenderer.h b/src/waveform/renderers/waveformwidgetrenderer.h index 86a6bf860b3..2d4cb4cf3e8 100644 --- a/src/waveform/renderers/waveformwidgetrenderer.h +++ b/src/waveform/renderers/waveformwidgetrenderer.h @@ -47,8 +47,8 @@ class WaveformWidgetRenderer { } #ifdef __STEM__ - uint getSelectedStem() const { - return m_selectedStem; + uint getSelectedStems() const { + return m_selectedStems; } #endif @@ -177,7 +177,7 @@ class WaveformWidgetRenderer { } #ifdef __STEM__ - void selectStem(uint stemIdx); + void selectStem(uint stemMask); #endif void setTrack(TrackPointer track); void setMarkPositions(const QList& markPositions) { @@ -205,7 +205,7 @@ class WaveformWidgetRenderer { const QString m_group; TrackPointer m_pTrack; #ifdef __STEM__ - uint m_selectedStem; + uint m_selectedStems; #endif QList m_rendererStack; Qt::Orientation m_orientation; diff --git a/src/waveform/waveform.h b/src/waveform/waveform.h index 7ebf28f25f8..fc415e31db6 100644 --- a/src/waveform/waveform.h +++ b/src/waveform/waveform.h @@ -9,7 +9,6 @@ #include "analyzer/constants.h" #include "audio/signalinfo.h" -#include "engine/engine.h" #include "util/class.h" #include "util/compatibility/qmutex.h" diff --git a/src/widget/wlibrarytableview.h b/src/widget/wlibrarytableview.h index c4ac76fc1d5..78977d1e166 100644 --- a/src/widget/wlibrarytableview.h +++ b/src/widget/wlibrarytableview.h @@ -59,7 +59,7 @@ class WLibraryTableView : public QTableView, public virtual LibraryView { void loadTrackToPlayer(TrackPointer pTrack, const QString& group, #ifdef __STEM__ - uint stemIdx, + uint stemMask, #endif bool play = false); void trackSelected(TrackPointer pTrack); diff --git a/src/widget/wtrackmenu.cpp b/src/widget/wtrackmenu.cpp index 77e7ef98634..2b1d79d9390 100644 --- a/src/widget/wtrackmenu.cpp +++ b/src/widget/wtrackmenu.cpp @@ -50,6 +50,9 @@ // WStarRating is required for DlgTrackInfo #include "widget/wstarrating.h" #include "widget/wstarratingaction.h" +#ifdef __STEM__ +#include "widget/wtrackstemmenu.h" +#endif constexpr WTrackMenu::Features WTrackMenu::kDeckTrackMenuFeatures; @@ -891,24 +894,14 @@ void WTrackMenu::generateTrackLoadMenu(const QString& group, SoundSourceProxy(pTrack).openAudioSource(config); } if (enabled && pTrack && pTrack->hasStem()) { - QMenu* pStemMenu = new QMenu(label, pParentMenu); - - QAction* pAction = new QAction(tr("Load as a stem deck"), this); - pStemMenu->addAction(pAction); - connect(pAction, &QAction::triggered, this, [this, group] { loadSelectionToGroup(group); }); - pStemMenu->addSeparator(); - - auto stemInfo = pTrack->getStemInfo(); - for (uint stemIdx = 0; stemIdx < mixxx::kMaxSupportedStems; stemIdx++) { - QAction* pAction = - new QAction(tr("Load the \"%1\" stem") - .arg(stemInfo.at(stemIdx).getLabel()), - this); - pStemMenu->addAction(pAction); - connect(pAction, &QAction::triggered, this, [this, group, stemIdx] { - loadSelectionToGroup(group, stemIdx + 1); - }); - } + auto* pStemMenu = new WTrackStemMenu(label, pParentMenu, group, pTrack->getStemInfo()); + connect(pStemMenu, + &WTrackStemMenu::selectedStem, + this, + [this](const QString& group, uint stemMask) { + loadSelectionToGroup(group, stemMask); + close(); + }); pParentMenu->addMenu(pStemMenu); } else { #endif @@ -926,7 +919,9 @@ void WTrackMenu::updateMenus() { return; } - m_pLoadToMenu->clear(); + if (m_pLoadToMenu) { + m_pLoadToMenu->clear(); + } // Gray out some stuff if multiple songs were selected. const bool singleTrackSelected = getTrackCount() == 1; @@ -1864,11 +1859,14 @@ void WTrackMenu::slotColorPicked(const mixxx::RgbColor::optional_t& color) { hide(); } -void WTrackMenu::loadSelectionToGroup(const QString& group, #ifdef __STEM__ - uint stemIdx, -#endif +void WTrackMenu::loadSelectionToGroup(const QString& group, + uint stemMask, + bool play) { +#else +void WTrackMenu::loadSelectionToGroup(const QString& group, bool play) { +#endif TrackPointer pTrack = getFirstTrackPointer(); if (!pTrack) { return; @@ -1888,11 +1886,11 @@ void WTrackMenu::loadSelectionToGroup(const QString& group, // TODO: load track from this class without depending on // external slot to load track - emit loadTrackToPlayer(pTrack, group, #ifdef __STEM__ - stemIdx, + emit loadTrackToPlayer(pTrack, group, stemMask, play); +#else + emit loadTrackToPlayer(pTrack, group, play); #endif - play); } namespace { diff --git a/src/widget/wtrackmenu.h b/src/widget/wtrackmenu.h index a19c4668e60..ad48411c4b4 100644 --- a/src/widget/wtrackmenu.h +++ b/src/widget/wtrackmenu.h @@ -110,12 +110,16 @@ class WTrackMenu : public QMenu { const QString getDeckGroup() const; signals: +#ifdef __STEM__ void loadTrackToPlayer(TrackPointer pTrack, const QString& group, -#ifdef __STEM__ - uint stemIdx, -#endif + uint stemMask, bool play = false); +#else + void loadTrackToPlayer(TrackPointer pTrack, + const QString& group, + bool play = false); +#endif void trackMenuVisible(bool visible); void saveCurrentViewState(); void restoreCurrentViewStateOrIndex(); @@ -236,11 +240,14 @@ class WTrackMenu : public QMenu { void clearBeats(); void lockBpm(bool lock); - void loadSelectionToGroup(const QString& group, #ifdef __STEM__ - uint stemIdx = mixxx::kNoStemSelectedIdx, -#endif + void loadSelectionToGroup(const QString& group, + uint stemMask = mixxx::kNoStemSelected, bool play = false); +#else + void loadSelectionToGroup(const QString& group, + bool play = false); +#endif void clearTrackSelection(); std::pair getTrackBpmLockStates() const; diff --git a/src/widget/wtrackstemmenu.cpp b/src/widget/wtrackstemmenu.cpp new file mode 100644 index 00000000000..41dcce7ee4f --- /dev/null +++ b/src/widget/wtrackstemmenu.cpp @@ -0,0 +1,90 @@ +#include "widget/wtrackstemmenu.h" + +#include + +#include "engine/engine.h" +#include "moc_wtrackstemmenu.cpp" + +WTrackStemMenu::WTrackStemMenu(const QString& label, + QWidget* parent, + const QString& group, + const QList& stemInfo) + : QMenu(label, parent), + m_group(group), + m_selectMode(false), + m_stemInfo(stemInfo), + m_currentSelection(mixxx::kNoStemSelected) { + QAction* pAction = new QAction(tr("Load as a stem deck"), this); + addAction(pAction); + connect(pAction, &QAction::triggered, this, [this, group] { + emit selectedStem(group, mixxx::kNoStemSelected); + }); + addSeparator(); + + for (uint stemIdx = 0; stemIdx < mixxx::kMaxSupportedStems; stemIdx++) { + m_stemActions.emplace_back( + make_parented(tr("Load the \"%1\" stem") + .arg(m_stemInfo.at(stemIdx).getLabel()), + this)); + addAction(m_stemActions.back().get()); + connect(m_stemActions.back().get(), &QAction::triggered, this, [this, stemIdx] { + emit selectedStem(m_group, 1 << stemIdx); + }); + connect(m_stemActions.back().get(), &QAction::toggled, this, [this, stemIdx](bool checked) { + if (checked) { + m_currentSelection |= 1 << stemIdx; + } else { + m_currentSelection ^= 1 << stemIdx; + } + }); + } + m_selectAction = make_parented(this); + m_selectAction->setToolTip(tr("Load multiple stem into a stereo deck")); + m_selectAction->setDisabled(true); + addAction(m_selectAction.get()); + installEventFilter(this); +} + +bool WTrackStemMenu::eventFilter(QObject* pObj, QEvent* e) { + if (e->type() == QEvent::MouseButtonPress) { + QAction* pAction = activeAction(); + if (pAction && pAction->isCheckable() && m_selectMode) { + pAction->setChecked(!pAction->isChecked()); + updateActions(); + return true; + } + } + return QObject::eventFilter(pObj, e); +} +void WTrackStemMenu::updateActions() { + for (const auto& pAction : m_stemActions) { + pAction->setCheckable(m_selectMode); + } + m_selectAction->setText(m_selectMode + ? !m_currentSelection ? tr("Select stems to load") + : tr("Release \"CTRL\" to load the " + "current selection") + : tr("Use \"CTRL\" to select multiple stems")); +} + +void WTrackStemMenu::showEvent(QShowEvent* pQEvent) { + updateActions(); + QMenu::showEvent(pQEvent); +} + +void WTrackStemMenu::keyPressEvent(QKeyEvent* pQEvent) { + m_selectMode = pQEvent->modifiers() & Qt::ControlModifier; + updateActions(); + pQEvent->accept(); +} + +void WTrackStemMenu::keyReleaseEvent(QKeyEvent* pQEvent) { + bool selectMode = pQEvent->modifiers() & Qt::ControlModifier; + if (!selectMode && m_selectMode && m_currentSelection) { + emit selectedStem(m_group, m_currentSelection); + m_currentSelection = mixxx::kNoStemSelected; + } + m_selectMode = selectMode; + updateActions(); + pQEvent->accept(); +} diff --git a/src/widget/wtrackstemmenu.h b/src/widget/wtrackstemmenu.h new file mode 100644 index 00000000000..96357efbf97 --- /dev/null +++ b/src/widget/wtrackstemmenu.h @@ -0,0 +1,38 @@ +#pragma once + +#include +#include + +#include "track/steminfo.h" +#include "util/parented_ptr.h" + +class QAction; + +class WTrackStemMenu : public QMenu { + Q_OBJECT + public: + WTrackStemMenu(const QString& label, + QWidget* parent, + const QString& group, + const QList& stemInfo); + + signals: + void selectedStem(const QString& group, uint stemMask); + + protected: + virtual void showEvent(QShowEvent* pQEvent) override; + virtual void keyPressEvent(QKeyEvent* pQEvent) override; + virtual void keyReleaseEvent(QKeyEvent* pQEvent) override; + virtual bool eventFilter(QObject* pObj, QEvent* e) override; + + private: + void updateActions(); + + QString m_group; + bool m_selectMode; + QList m_stemInfo; + uint m_currentSelection; + + std::vector> m_stemActions; + parented_ptr m_selectAction; +}; diff --git a/src/widget/wtracktableview.cpp b/src/widget/wtracktableview.cpp index 0b4f8a950fe..b2f4113242d 100644 --- a/src/widget/wtracktableview.cpp +++ b/src/widget/wtracktableview.cpp @@ -1247,11 +1247,14 @@ void WTrackTableView::activateSelectedTrack() { slotMouseDoubleClicked(indices.at(0)); } -void WTrackTableView::loadSelectedTrackToGroup(const QString& group, #ifdef __STEM__ - uint stemIdx, -#endif +void WTrackTableView::loadSelectedTrackToGroup(const QString& group, + uint stemMask, bool play) { +#else +void WTrackTableView::loadSelectedTrackToGroup(const QString& group, + bool play) { +#endif auto indices = getSelectedRows(); if (indices.isEmpty()) { return; @@ -1286,8 +1289,8 @@ void WTrackTableView::loadSelectedTrackToGroup(const QString& group, TrackPointer pTrack; if (trackModel && (pTrack = trackModel->getTrack(index))) { #ifdef __STEM__ - DEBUG_ASSERT(!stemIdx || pTrack->hasStem()); - emit loadTrackToPlayer(pTrack, group, stemIdx, play); + DEBUG_ASSERT(!stemMask || pTrack->hasStem()); + emit loadTrackToPlayer(pTrack, group, stemMask, play); #else emit loadTrackToPlayer(pTrack, group, play); #endif diff --git a/src/widget/wtracktableview.h b/src/widget/wtracktableview.h index 19fc5306d21..e5c0b932ff7 100644 --- a/src/widget/wtracktableview.h +++ b/src/widget/wtracktableview.h @@ -38,11 +38,14 @@ class WTrackTableView : public WLibraryTableView { void keyPressEvent(QKeyEvent* event) override; void resizeEvent(QResizeEvent* event) override; void activateSelectedTrack(); - void loadSelectedTrackToGroup(const QString& group, #ifdef __STEM__ - uint stemIdx, -#endif + void loadSelectedTrackToGroup(const QString& group, + uint stemMask, bool play); +#else + void loadSelectedTrackToGroup(const QString& group, + bool play); +#endif void assignNextTrackColor() override; void assignPreviousTrackColor() override; TrackModel::SortColumnId getColumnIdFromCurrentIndex() override; diff --git a/src/widget/wwaveformviewer.cpp b/src/widget/wwaveformviewer.cpp index e3ee08349fe..c10e3e0f9b3 100644 --- a/src/widget/wwaveformviewer.cpp +++ b/src/widget/wwaveformviewer.cpp @@ -228,9 +228,9 @@ void WWaveformViewer::slotTrackLoaded(TrackPointer track) { } #ifdef __STEM__ -void WWaveformViewer::slotSelectStem(uint stemIdx) { +void WWaveformViewer::slotSelectStem(uint stemMask) { if (m_waveformWidget) { - m_waveformWidget->selectStem(stemIdx); + m_waveformWidget->selectStem(stemMask); } } #endif diff --git a/src/widget/wwaveformviewer.h b/src/widget/wwaveformviewer.h index ad6b8e406a9..5848e7c1bad 100644 --- a/src/widget/wwaveformviewer.h +++ b/src/widget/wwaveformviewer.h @@ -46,7 +46,7 @@ class WWaveformViewer : public WWidget, public TrackDropTarget { void slotTrackUnloaded(TrackPointer pOldTrack); void slotLoadingTrack(TrackPointer pNewTrack, TrackPointer pOldTrack); #ifdef __STEM__ - void slotSelectStem(uint stemIdx); + void slotSelectStem(uint stemMask); #endif protected: From ce869682ce90c94a444674568ade67a1f6b5cd23 Mon Sep 17 00:00:00 2001 From: Antoine C Date: Fri, 23 Aug 2024 20:47:32 +0100 Subject: [PATCH 3/8] Hide stem load for non-primary deck and add shortcut to load as pre-mixed track --- src/widget/wtrackmenu.cpp | 9 +++++++-- src/widget/wtrackmenu.h | 1 + src/widget/wtrackstemmenu.cpp | 13 +++++++++++-- src/widget/wtrackstemmenu.h | 1 + 4 files changed, 20 insertions(+), 4 deletions(-) diff --git a/src/widget/wtrackmenu.cpp b/src/widget/wtrackmenu.cpp index 2b1d79d9390..02a7b7faf1a 100644 --- a/src/widget/wtrackmenu.cpp +++ b/src/widget/wtrackmenu.cpp @@ -882,6 +882,7 @@ void WTrackMenu::generateTrackLoadMenu(const QString& group, const QString& label, TrackPointer pTrack, QMenu* pParentMenu, + bool primaryDeck, bool enabled) { #ifdef __STEM__ if (pTrack && !pTrack->hasStreamInfoFromSource()) { @@ -894,7 +895,8 @@ void WTrackMenu::generateTrackLoadMenu(const QString& group, SoundSourceProxy(pTrack).openAudioSource(config); } if (enabled && pTrack && pTrack->hasStem()) { - auto* pStemMenu = new WTrackStemMenu(label, pParentMenu, group, pTrack->getStemInfo()); + auto* pStemMenu = new WTrackStemMenu( + label, pParentMenu, primaryDeck, group, pTrack->getStemInfo()); connect(pStemMenu, &WTrackStemMenu::selectedStem, this, @@ -960,6 +962,7 @@ void WTrackMenu::updateMenus() { tr("Deck %1").arg(i), getFirstTrackPointer(), m_pDeckMenu, + true, deckEnabled); } } @@ -991,6 +994,7 @@ void WTrackMenu::updateMenus() { samplerTrString(i), pTrack, pMenu, + false, samplerEnabled); } } @@ -1001,7 +1005,8 @@ void WTrackMenu::updateMenus() { generateTrackLoadMenu(PlayerManager::groupForPreviewDeck(0), tr("Preview Deck"), getFirstTrackPointer(), - m_pLoadToMenu); + m_pLoadToMenu, + false); } } diff --git a/src/widget/wtrackmenu.h b/src/widget/wtrackmenu.h index ad48411c4b4..9a9e641e577 100644 --- a/src/widget/wtrackmenu.h +++ b/src/widget/wtrackmenu.h @@ -227,6 +227,7 @@ class WTrackMenu : public QMenu { const QString& label, TrackPointer pTrack, QMenu* pParentMenu, + bool primaryDeck, bool enabled = true); bool featureIsEnabled(Feature flag) const; diff --git a/src/widget/wtrackstemmenu.cpp b/src/widget/wtrackstemmenu.cpp index 41dcce7ee4f..02d6d90e4e9 100644 --- a/src/widget/wtrackstemmenu.cpp +++ b/src/widget/wtrackstemmenu.cpp @@ -7,6 +7,7 @@ WTrackStemMenu::WTrackStemMenu(const QString& label, QWidget* parent, + bool primaryDeck, const QString& group, const QList& stemInfo) : QMenu(label, parent), @@ -14,10 +15,18 @@ WTrackStemMenu::WTrackStemMenu(const QString& label, m_selectMode(false), m_stemInfo(stemInfo), m_currentSelection(mixxx::kNoStemSelected) { - QAction* pAction = new QAction(tr("Load as a stem deck"), this); + if (primaryDeck) { + QAction* pAction = new QAction(tr("Load for stem mixing"), this); + addAction(pAction); + connect(pAction, &QAction::triggered, this, [this, group] { + emit selectedStem(group, mixxx::kNoStemSelected); + }); + } + + QAction* pAction = new QAction(tr("Load pre-mixed stereo track"), this); addAction(pAction); connect(pAction, &QAction::triggered, this, [this, group] { - emit selectedStem(group, mixxx::kNoStemSelected); + emit selectedStem(group, 0xf); }); addSeparator(); diff --git a/src/widget/wtrackstemmenu.h b/src/widget/wtrackstemmenu.h index 96357efbf97..915f45f8339 100644 --- a/src/widget/wtrackstemmenu.h +++ b/src/widget/wtrackstemmenu.h @@ -13,6 +13,7 @@ class WTrackStemMenu : public QMenu { public: WTrackStemMenu(const QString& label, QWidget* parent, + bool primaryDeck, const QString& group, const QList& stemInfo); From 394ba4afb53ce42bb00ece2fa7b890acadfdb633 Mon Sep 17 00:00:00 2001 From: Antoine C Date: Fri, 23 Aug 2024 20:56:05 +0100 Subject: [PATCH 4/8] Use the default waveform if fully loaded as stereo --- src/sources/audiosource.h | 3 ++- .../renderers/allshader/waveformrendererfiltered.cpp | 5 +++-- src/waveform/renderers/allshader/waveformrendererhsv.cpp | 5 +++-- src/waveform/renderers/allshader/waveformrendererrgb.cpp | 5 +++-- src/waveform/renderers/allshader/waveformrendererstem.cpp | 8 ++++---- 5 files changed, 15 insertions(+), 11 deletions(-) diff --git a/src/sources/audiosource.h b/src/sources/audiosource.h index 9a77cb8beab..705a71be51c 100644 --- a/src/sources/audiosource.h +++ b/src/sources/audiosource.h @@ -195,7 +195,8 @@ class AudioSource : public UrlResource, public virtual /*implements*/ IAudioSour public: #ifdef __STEM__ OpenParams() - : m_signalInfo(), m_stemMask(mixxx::kNoStemSelected) { + : m_signalInfo(), + m_stemMask(mixxx::kNoStemSelected) { } OpenParams( diff --git a/src/waveform/renderers/allshader/waveformrendererfiltered.cpp b/src/waveform/renderers/allshader/waveformrendererfiltered.cpp index 0ddf164cc3e..ee9ee1b4041 100644 --- a/src/waveform/renderers/allshader/waveformrendererfiltered.cpp +++ b/src/waveform/renderers/allshader/waveformrendererfiltered.cpp @@ -45,8 +45,9 @@ void WaveformRendererFiltered::paintGL() { } #ifdef __STEM__ auto stemInfo = pTrack->getStemInfo(); - // If this track is a stem track, skip the rendering - if (!stemInfo.isEmpty() && waveform->hasStem()) { + uint selectedStems = m_waveformRenderer->getSelectedStems(); + // If this track is a stem track and is not fully loaded as a stereo track, skip the rendering + if (!stemInfo.isEmpty() && waveform->hasStem() && selectedStems != 0xf) { return; } #endif diff --git a/src/waveform/renderers/allshader/waveformrendererhsv.cpp b/src/waveform/renderers/allshader/waveformrendererhsv.cpp index b03a17a304e..c99183a14ea 100644 --- a/src/waveform/renderers/allshader/waveformrendererhsv.cpp +++ b/src/waveform/renderers/allshader/waveformrendererhsv.cpp @@ -45,8 +45,9 @@ void WaveformRendererHSV::paintGL() { } #ifdef __STEM__ auto stemInfo = pTrack->getStemInfo(); - // If this track is a stem track, skip the rendering - if (!stemInfo.isEmpty() && waveform->hasStem()) { + uint selectedStems = m_waveformRenderer->getSelectedStems(); + // If this track is a stem track and is not fully loaded as a stereo track, skip the rendering + if (!stemInfo.isEmpty() && waveform->hasStem() && selectedStems != 0xf) { return; } #endif diff --git a/src/waveform/renderers/allshader/waveformrendererrgb.cpp b/src/waveform/renderers/allshader/waveformrendererrgb.cpp index 828a8a71bbb..65e4fc85e7a 100644 --- a/src/waveform/renderers/allshader/waveformrendererrgb.cpp +++ b/src/waveform/renderers/allshader/waveformrendererrgb.cpp @@ -56,8 +56,9 @@ void WaveformRendererRGB::paintGL() { } #ifdef __STEM__ auto stemInfo = pTrack->getStemInfo(); - // If this track is a stem track, skip the rendering - if (!stemInfo.isEmpty() && waveform->hasStem()) { + uint selectedStems = m_waveformRenderer->getSelectedStems(); + // If this track is a stem track and is not fully loaded as a stereo track, skip the rendering + if (!stemInfo.isEmpty() && waveform->hasStem() && selectedStems != 0xf) { return; } #endif diff --git a/src/waveform/renderers/allshader/waveformrendererstem.cpp b/src/waveform/renderers/allshader/waveformrendererstem.cpp index 40ff8cc2547..394ffa50fd8 100644 --- a/src/waveform/renderers/allshader/waveformrendererstem.cpp +++ b/src/waveform/renderers/allshader/waveformrendererstem.cpp @@ -50,8 +50,10 @@ void WaveformRendererStem::paintGL() { } auto stemInfo = pTrack->getStemInfo(); - // If this track isn't a stem track, skip the rendering - if (stemInfo.isEmpty()) { + uint selectedStems = m_waveformRenderer->getSelectedStems(); + + // If this track isn't a stem track, or if it is fully loaded as stereo, skip the rendering + if (stemInfo.isEmpty() || selectedStems == 0xf) { return; } auto positionType = m_isSlipRenderer ? ::WaveformRendererAbstract::Slip @@ -76,8 +78,6 @@ void WaveformRendererStem::paintGL() { return; } - uint selectedStems = m_waveformRenderer->getSelectedStems(); - const float devicePixelRatio = m_waveformRenderer->getDevicePixelRatio(); const int length = static_cast(m_waveformRenderer->getLength() * devicePixelRatio); From e4f5ff376c59f6e7e4cce8a1dd9bf33909a66f80 Mon Sep 17 00:00:00 2001 From: Antoine C Date: Sat, 14 Sep 2024 12:35:51 +0100 Subject: [PATCH 5/8] Fix waveform not displaying when loading STEm as stereo --- src/widget/wwaveformviewer.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/widget/wwaveformviewer.cpp b/src/widget/wwaveformviewer.cpp index c10e3e0f9b3..54b2283c1de 100644 --- a/src/widget/wwaveformviewer.cpp +++ b/src/widget/wwaveformviewer.cpp @@ -231,6 +231,7 @@ void WWaveformViewer::slotTrackLoaded(TrackPointer track) { void WWaveformViewer::slotSelectStem(uint stemMask) { if (m_waveformWidget) { m_waveformWidget->selectStem(stemMask); + update(); } } #endif From 7b735f57f731dc70b01dd6702996ea642bc51301 Mon Sep 17 00:00:00 2001 From: Antoine C Date: Fri, 20 Sep 2024 09:25:09 +0100 Subject: [PATCH 6/8] Revert "Use the default waveform if fully loaded as stereo" --- .../renderers/allshader/waveformrendererfiltered.cpp | 5 ++--- src/waveform/renderers/allshader/waveformrendererhsv.cpp | 5 ++--- src/waveform/renderers/allshader/waveformrendererrgb.cpp | 5 ++--- src/waveform/renderers/allshader/waveformrendererstem.cpp | 8 ++++---- 4 files changed, 10 insertions(+), 13 deletions(-) diff --git a/src/waveform/renderers/allshader/waveformrendererfiltered.cpp b/src/waveform/renderers/allshader/waveformrendererfiltered.cpp index ee9ee1b4041..0ddf164cc3e 100644 --- a/src/waveform/renderers/allshader/waveformrendererfiltered.cpp +++ b/src/waveform/renderers/allshader/waveformrendererfiltered.cpp @@ -45,9 +45,8 @@ void WaveformRendererFiltered::paintGL() { } #ifdef __STEM__ auto stemInfo = pTrack->getStemInfo(); - uint selectedStems = m_waveformRenderer->getSelectedStems(); - // If this track is a stem track and is not fully loaded as a stereo track, skip the rendering - if (!stemInfo.isEmpty() && waveform->hasStem() && selectedStems != 0xf) { + // If this track is a stem track, skip the rendering + if (!stemInfo.isEmpty() && waveform->hasStem()) { return; } #endif diff --git a/src/waveform/renderers/allshader/waveformrendererhsv.cpp b/src/waveform/renderers/allshader/waveformrendererhsv.cpp index c99183a14ea..b03a17a304e 100644 --- a/src/waveform/renderers/allshader/waveformrendererhsv.cpp +++ b/src/waveform/renderers/allshader/waveformrendererhsv.cpp @@ -45,9 +45,8 @@ void WaveformRendererHSV::paintGL() { } #ifdef __STEM__ auto stemInfo = pTrack->getStemInfo(); - uint selectedStems = m_waveformRenderer->getSelectedStems(); - // If this track is a stem track and is not fully loaded as a stereo track, skip the rendering - if (!stemInfo.isEmpty() && waveform->hasStem() && selectedStems != 0xf) { + // If this track is a stem track, skip the rendering + if (!stemInfo.isEmpty() && waveform->hasStem()) { return; } #endif diff --git a/src/waveform/renderers/allshader/waveformrendererrgb.cpp b/src/waveform/renderers/allshader/waveformrendererrgb.cpp index 65e4fc85e7a..828a8a71bbb 100644 --- a/src/waveform/renderers/allshader/waveformrendererrgb.cpp +++ b/src/waveform/renderers/allshader/waveformrendererrgb.cpp @@ -56,9 +56,8 @@ void WaveformRendererRGB::paintGL() { } #ifdef __STEM__ auto stemInfo = pTrack->getStemInfo(); - uint selectedStems = m_waveformRenderer->getSelectedStems(); - // If this track is a stem track and is not fully loaded as a stereo track, skip the rendering - if (!stemInfo.isEmpty() && waveform->hasStem() && selectedStems != 0xf) { + // If this track is a stem track, skip the rendering + if (!stemInfo.isEmpty() && waveform->hasStem()) { return; } #endif diff --git a/src/waveform/renderers/allshader/waveformrendererstem.cpp b/src/waveform/renderers/allshader/waveformrendererstem.cpp index 232163fde42..5827904f513 100644 --- a/src/waveform/renderers/allshader/waveformrendererstem.cpp +++ b/src/waveform/renderers/allshader/waveformrendererstem.cpp @@ -50,10 +50,8 @@ void WaveformRendererStem::paintGL() { } auto stemInfo = pTrack->getStemInfo(); - uint selectedStems = m_waveformRenderer->getSelectedStems(); - - // If this track isn't a stem track, or if it is fully loaded as stereo, skip the rendering - if (stemInfo.isEmpty() || selectedStems == 0xf) { + // If this track isn't a stem track, skip the rendering + if (stemInfo.isEmpty()) { return; } auto positionType = m_isSlipRenderer ? ::WaveformRendererAbstract::Slip @@ -78,6 +76,8 @@ void WaveformRendererStem::paintGL() { return; } + uint selectedStems = m_waveformRenderer->getSelectedStems(); + const float devicePixelRatio = m_waveformRenderer->getDevicePixelRatio(); const int length = static_cast(m_waveformRenderer->getLength() * devicePixelRatio); From ecdbb1a8ba99bc02e3250f03efb2cc70e5f07a54 Mon Sep 17 00:00:00 2001 From: Antoine C Date: Fri, 20 Sep 2024 21:49:40 +0100 Subject: [PATCH 7/8] Use release event instead of press event to handle double clicks and drag move --- src/widget/wtrackstemmenu.cpp | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/src/widget/wtrackstemmenu.cpp b/src/widget/wtrackstemmenu.cpp index 02d6d90e4e9..ebb7de4e284 100644 --- a/src/widget/wtrackstemmenu.cpp +++ b/src/widget/wtrackstemmenu.cpp @@ -55,9 +55,18 @@ WTrackStemMenu::WTrackStemMenu(const QString& label, } bool WTrackStemMenu::eventFilter(QObject* pObj, QEvent* e) { - if (e->type() == QEvent::MouseButtonPress) { + QInputEvent* pInputEvent = dynamic_cast(e); + qDebug() << e << pInputEvent; + if (pInputEvent != nullptr && + (pInputEvent->modifiers() & Qt::ControlModifier) != m_selectMode) { + m_selectMode = pInputEvent->modifiers() & Qt::ControlModifier; + updateActions(); + } + + if (m_selectMode && (e->type() == QEvent::MouseButtonRelease)) { QAction* pAction = activeAction(); - if (pAction && pAction->isCheckable() && m_selectMode) { + qDebug() << e << pAction; + if (pAction && pAction->isCheckable()) { pAction->setChecked(!pAction->isChecked()); updateActions(); return true; From a54051a30ad9c09381e8659b54fca2d828f79f3b Mon Sep 17 00:00:00 2001 From: Antoine C Date: Sun, 29 Sep 2024 21:13:05 +0100 Subject: [PATCH 8/8] Add a QFlag and enum to represent stem track selection --- src/engine/cachingreader/cachingreader.cpp | 2 +- src/engine/cachingreader/cachingreader.h | 2 +- .../cachingreader/cachingreaderworker.cpp | 5 +- .../cachingreader/cachingreaderworker.h | 6 +- src/engine/channels/enginedeck.cpp | 6 +- src/engine/engine.h | 11 ++- src/engine/enginebuffer.cpp | 2 +- src/engine/enginebuffer.h | 2 +- src/library/analysis/analysisfeature.cpp | 2 +- src/library/autodj/autodjprocessor.h | 7 +- src/library/autodj/dlgautodj.h | 5 +- src/library/library.cpp | 8 +- src/library/library.h | 7 +- src/library/librarycontrol.cpp | 12 ++- src/library/librarycontrol.h | 9 +- src/library/libraryfeature.h | 5 +- src/library/recording/dlgrecording.h | 8 +- .../tabledelegates/previewbuttondelegate.cpp | 2 +- .../tabledelegates/previewbuttondelegate.h | 8 +- src/mixer/basetrackplayer.cpp | 10 +- src/mixer/basetrackplayer.h | 9 +- src/mixer/playermanager.cpp | 12 ++- src/mixer/playermanager.h | 5 +- src/mixer/samplerbank.cpp | 2 +- src/sources/audiosource.h | 10 +- src/test/autodjprocessor_test.cpp | 98 +++++++++---------- src/test/cuecontrol_test.cpp | 2 +- src/test/hotcuecontrol_test.cpp | 2 +- src/test/playermanagertest.cpp | 12 +-- src/test/signalpathtest.h | 2 +- .../renderers/waveformwidgetrenderer.cpp | 4 +- .../renderers/waveformwidgetrenderer.h | 2 +- src/widget/wlibrarytableview.h | 5 +- src/widget/wtrackmenu.cpp | 4 +- src/widget/wtrackmenu.h | 4 +- src/widget/wtrackstemmenu.cpp | 43 ++++---- src/widget/wtrackstemmenu.h | 5 +- src/widget/wtracktableview.cpp | 2 +- src/widget/wtracktableview.h | 5 +- src/widget/wwaveformviewer.cpp | 2 +- src/widget/wwaveformviewer.h | 2 +- 41 files changed, 212 insertions(+), 139 deletions(-) diff --git a/src/engine/cachingreader/cachingreader.cpp b/src/engine/cachingreader/cachingreader.cpp index eb8953611db..2859dd96aa0 100644 --- a/src/engine/cachingreader/cachingreader.cpp +++ b/src/engine/cachingreader/cachingreader.cpp @@ -206,7 +206,7 @@ CachingReaderChunkForOwner* CachingReader::lookupChunkAndFreshen(SINT chunkIndex // Invoked from the UI thread!! #ifdef __STEM__ -void CachingReader::newTrack(TrackPointer pTrack, uint stemMask) { +void CachingReader::newTrack(TrackPointer pTrack, mixxx::StemChannelSelection stemMask) { #else void CachingReader::newTrack(TrackPointer pTrack) { #endif diff --git a/src/engine/cachingreader/cachingreader.h b/src/engine/cachingreader/cachingreader.h index 05fc71e5c9a..fc77167b927 100644 --- a/src/engine/cachingreader/cachingreader.h +++ b/src/engine/cachingreader/cachingreader.h @@ -117,7 +117,7 @@ class CachingReader : public QObject { // processed in the work thread, so the reader must be woken up via wake() // for this to take effect. #ifdef __STEM__ - void newTrack(TrackPointer pTrack, uint stemMask = 0); + void newTrack(TrackPointer pTrack, mixxx::StemChannelSelection stemMask = {}); #else void newTrack(TrackPointer pTrack); #endif diff --git a/src/engine/cachingreader/cachingreaderworker.cpp b/src/engine/cachingreader/cachingreaderworker.cpp index bed83f053dd..2caaf7af059 100644 --- a/src/engine/cachingreader/cachingreaderworker.cpp +++ b/src/engine/cachingreader/cachingreaderworker.cpp @@ -93,7 +93,7 @@ ReaderStatusUpdate CachingReaderWorker::processReadRequest( // WARNING: Always called from a different thread (GUI) #ifdef __STEM__ -void CachingReaderWorker::newTrack(TrackPointer pTrack, uint stemMask) { +void CachingReaderWorker::newTrack(TrackPointer pTrack, mixxx::StemChannelSelection stemMask) { #else void CachingReaderWorker::newTrack(TrackPointer pTrack) { #endif @@ -188,7 +188,8 @@ void CachingReaderWorker::unloadTrack() { } #ifdef __STEM__ -void CachingReaderWorker::loadTrack(const TrackPointer& pTrack, uint stemMask) { +void CachingReaderWorker::loadTrack( + const TrackPointer& pTrack, mixxx::StemChannelSelection stemMask) { #else void CachingReaderWorker::loadTrack(const TrackPointer& pTrack) { #endif diff --git a/src/engine/cachingreader/cachingreaderworker.h b/src/engine/cachingreader/cachingreaderworker.h index d4c8320fe04..d7ecc2c04bb 100644 --- a/src/engine/cachingreader/cachingreaderworker.h +++ b/src/engine/cachingreader/cachingreaderworker.h @@ -105,7 +105,7 @@ class CachingReaderWorker : public EngineWorker { // Request to load a new track. wake() must be called afterwards. #ifdef __STEM__ - void newTrack(TrackPointer pTrack, uint stemMask); + void newTrack(TrackPointer pTrack, mixxx::StemChannelSelection stemMask); #else void newTrack(TrackPointer pTrack); #endif @@ -129,7 +129,7 @@ class CachingReaderWorker : public EngineWorker { #ifdef __STEM__ struct NewTrackRequest { TrackPointer track; - uint stemMask; + mixxx::StemChannelSelection stemMask; }; #endif const QString m_group; @@ -162,7 +162,7 @@ class CachingReaderWorker : public EngineWorker { /// Internal method to load a track. Emits trackLoaded when finished. #ifdef __STEM__ - void loadTrack(const TrackPointer& pTrack, uint stemMask); + void loadTrack(const TrackPointer& pTrack, mixxx::StemChannelSelection stemMask); #else void loadTrack(const TrackPointer& pTrack); #endif diff --git a/src/engine/channels/enginedeck.cpp b/src/engine/channels/enginedeck.cpp index 02ddf9a05b4..a9c5e18d1ee 100644 --- a/src/engine/channels/enginedeck.cpp +++ b/src/engine/channels/enginedeck.cpp @@ -74,16 +74,16 @@ EngineDeck::EngineDeck( m_stemGain.reserve(mixxx::kMaxSupportedStems); m_stemMute.reserve(mixxx::kMaxSupportedStems); - for (int stemIdx = 1; stemIdx <= mixxx::kMaxSupportedStems; stemIdx++) { + for (int stemIdx = 0; stemIdx < mixxx::kMaxSupportedStems; stemIdx++) { m_stemGain.emplace_back(std::make_unique( - ConfigKey(getGroupForStem(getGroup(), stemIdx), QStringLiteral("volume")))); + ConfigKey(getGroupForStem(getGroup(), stemIdx + 1), QStringLiteral("volume")))); // The default value is ignored and override with the medium value by // ControlPotmeter. This is likely a bug but fixing might have a // disruptive impact, so setting the default explicitly m_stemGain.back()->set(1.0); m_stemGain.back()->setDefaultValue(1.0); m_stemMute.emplace_back(std::make_unique( - ConfigKey(getGroupForStem(getGroup(), stemIdx), QStringLiteral("mute")))); + ConfigKey(getGroupForStem(getGroup(), stemIdx + 1), QStringLiteral("mute")))); } #endif } diff --git a/src/engine/engine.h b/src/engine/engine.h index 02bf959b4fa..c5912ba714d 100644 --- a/src/engine/engine.h +++ b/src/engine/engine.h @@ -13,7 +13,16 @@ static constexpr audio::ChannelCount kMaxEngineChannelInputCount = // not. constexpr int kMaxSupportedStems = 4; #ifdef __STEM__ -constexpr uint kNoStemSelected = 0; +enum class StemChannel { + First = 0x1, + Second = 0x2, + Third = 0x4, + Fourth = 0x8, + + None = 0, + All = First | Second | Third | Fourth +}; +Q_DECLARE_FLAGS(StemChannelSelection, StemChannel); #endif // Contains the information needed to process a buffer of audio diff --git a/src/engine/enginebuffer.cpp b/src/engine/enginebuffer.cpp index 0eabc94d8ab..3ba98042378 100644 --- a/src/engine/enginebuffer.cpp +++ b/src/engine/enginebuffer.cpp @@ -1542,7 +1542,7 @@ void EngineBuffer::hintReader(const double dRate) { // WARNING: This method runs in the GUI thread #ifdef __STEM__ void EngineBuffer::loadTrack(TrackPointer pTrack, - uint stemMask, + mixxx::StemChannelSelection stemMask, bool play, EngineChannel* pChannelToCloneFrom) { #else diff --git a/src/engine/enginebuffer.h b/src/engine/enginebuffer.h index 78fe05fb758..06841d6ddad 100644 --- a/src/engine/enginebuffer.h +++ b/src/engine/enginebuffer.h @@ -217,7 +217,7 @@ class EngineBuffer : public EngineObject { // has completed. #ifdef __STEM__ void loadTrack(TrackPointer pTrack, - uint stemMask, + mixxx::StemChannelSelection stemMask, bool play, EngineChannel* pChannelToCloneFrom); #else diff --git a/src/library/analysis/analysisfeature.cpp b/src/library/analysis/analysisfeature.cpp index 82b64ca3e49..3789b4a1295 100644 --- a/src/library/analysis/analysisfeature.cpp +++ b/src/library/analysis/analysisfeature.cpp @@ -83,7 +83,7 @@ void AnalysisFeature::bindLibraryWidget(WLibrary* libraryWidget, [=, this](TrackPointer track, const QString& group) { emit loadTrackToPlayer(track, group, #ifdef __STEM__ - mixxx::kNoStemSelected, + mixxx::StemChannelSelection(), #endif false); }); diff --git a/src/library/autodj/autodjprocessor.h b/src/library/autodj/autodjprocessor.h index df8cb786acc..0e5fb21dc34 100644 --- a/src/library/autodj/autodjprocessor.h +++ b/src/library/autodj/autodjprocessor.h @@ -202,7 +202,10 @@ class AutoDJProcessor : public QObject { signals: #ifdef __STEM__ - void loadTrackToPlayer(TrackPointer pTrack, const QString& group, uint stemMask, bool play); + void loadTrackToPlayer(TrackPointer pTrack, + const QString& group, + mixxx::StemChannelSelection stemMask, + bool play); #else void loadTrackToPlayer(TrackPointer pTrack, const QString& group, bool play); #endif @@ -236,7 +239,7 @@ class AutoDJProcessor : public QObject { virtual void emitLoadTrackToPlayer(TrackPointer pTrack, const QString& group, bool play) { emit loadTrackToPlayer(pTrack, group, #ifdef __STEM__ - mixxx::kNoStemSelected, + mixxx::StemChannelSelection(), #endif play); } diff --git a/src/library/autodj/dlgautodj.h b/src/library/autodj/dlgautodj.h index f4138ec86f5..1e6d396f8b5 100644 --- a/src/library/autodj/dlgautodj.h +++ b/src/library/autodj/dlgautodj.h @@ -50,7 +50,10 @@ class DlgAutoDJ : public QWidget, public Ui::DlgAutoDJ, public LibraryView { void addRandomTrackButton(bool buttonChecked); void loadTrack(TrackPointer tio); #ifdef __STEM__ - void loadTrackToPlayer(TrackPointer tio, const QString& group, uint stemMask, bool); + void loadTrackToPlayer(TrackPointer tio, + const QString& group, + mixxx::StemChannelSelection stemMask, + bool); #else void loadTrackToPlayer(TrackPointer tio, const QString& group, bool); #endif diff --git a/src/library/library.cpp b/src/library/library.cpp index 99fb2d429f3..91a5acf8f5a 100644 --- a/src/library/library.cpp +++ b/src/library/library.cpp @@ -553,7 +553,7 @@ void Library::slotLoadLocationToPlayer(const QString& location, const QString& g TrackPointer pTrack = m_pTrackCollectionManager->getOrAddTrack(trackRef); if (pTrack) { #ifdef __STEM__ - emit loadTrackToPlayer(pTrack, group, mixxx::kNoStemSelected, play); + emit loadTrackToPlayer(pTrack, group, mixxx::StemChannelSelection(), play); #else emit loadTrackToPlayer(pTrack, group, play); #endif @@ -561,8 +561,10 @@ void Library::slotLoadLocationToPlayer(const QString& location, const QString& g } #ifdef __STEM__ -void Library::slotLoadTrackToPlayer( - TrackPointer pTrack, const QString& group, uint stemMask, bool play) { +void Library::slotLoadTrackToPlayer(TrackPointer pTrack, + const QString& group, + mixxx::StemChannelSelection stemMask, + bool play) { emit loadTrackToPlayer(pTrack, group, stemMask, play); } #else diff --git a/src/library/library.h b/src/library/library.h index 75b2e4e014a..d872b3c5d06 100644 --- a/src/library/library.h +++ b/src/library/library.h @@ -115,7 +115,10 @@ class Library: public QObject { void slotSwitchToView(const QString& view); void slotLoadTrack(TrackPointer pTrack); #ifdef __STEM__ - void slotLoadTrackToPlayer(TrackPointer pTrack, const QString& group, uint stemMask, bool play); + void slotLoadTrackToPlayer(TrackPointer pTrack, + const QString& group, + mixxx::StemChannelSelection stemMask, + bool play); #else void slotLoadTrackToPlayer(TrackPointer pTrack, const QString& group, bool play); #endif @@ -134,7 +137,7 @@ class Library: public QObject { #ifdef __STEM__ void loadTrackToPlayer(TrackPointer pTrack, const QString& group, - uint stemMask, + mixxx::StemChannelSelection stemMask, bool play = false); #else void loadTrackToPlayer(TrackPointer pTrack, diff --git a/src/library/librarycontrol.cpp b/src/library/librarycontrol.cpp index 74874e3e040..a16c742a691 100644 --- a/src/library/librarycontrol.cpp +++ b/src/library/librarycontrol.cpp @@ -46,7 +46,10 @@ LoadToGroupController::LoadToGroupController(LibraryControl* pParent, const QStr this, [this](double value) { if (value >= 0 && value <= 2 << mixxx::kMaxSupportedStems) { - emit loadToGroup(m_group, static_cast(value), false); + emit loadToGroup(m_group, + mixxx::StemChannelSelection::fromInt( + static_cast(value)), + false); } }); #endif @@ -63,7 +66,7 @@ void LoadToGroupController::slotLoadToGroup(double v) { if (v > 0) { emit loadToGroup(m_group, #ifdef __STEM__ - mixxx::kNoStemSelected, + mixxx::StemChannelSelection(), #endif false); } @@ -73,7 +76,7 @@ void LoadToGroupController::slotLoadToGroupAndPlay(double v) { if (v > 0) { #ifdef __STEM__ emit loadToGroup(m_group, - mixxx::kNoStemSelected, + mixxx::StemChannelSelection(), true); #else emit loadToGroup(m_group, @@ -625,7 +628,8 @@ void LibraryControl::slotUpdateTrackMenuControl(bool visible) { } #ifdef __STEM__ -void LibraryControl::slotLoadSelectedTrackToGroup(const QString& group, uint stemMask, bool play) { +void LibraryControl::slotLoadSelectedTrackToGroup( + const QString& group, mixxx::StemChannelSelection stemMask, bool play) { #else void LibraryControl::slotLoadSelectedTrackToGroup(const QString& group, bool play) { #endif diff --git a/src/library/librarycontrol.h b/src/library/librarycontrol.h index dbc3ea66c8b..584d2df1a7a 100644 --- a/src/library/librarycontrol.h +++ b/src/library/librarycontrol.h @@ -5,6 +5,9 @@ #include "control/controlproxy.h" #include "library/library_decl.h" +#ifdef __STEM__ +#include "engine/engine.h" +#endif class ControlEncoder; class ControlObject; @@ -25,7 +28,7 @@ class LoadToGroupController : public QObject { signals: #ifdef __STEM__ void loadToGroup(const QString& group, - uint stemMask, + mixxx::StemChannelSelection stemMask, bool); #else void loadToGroup(const QString& group, @@ -66,7 +69,9 @@ class LibraryControl : public QObject { public slots: // Deprecated navigation slots #ifdef __STEM__ - void slotLoadSelectedTrackToGroup(const QString& group, uint stemMask, bool play); + void slotLoadSelectedTrackToGroup(const QString& group, + mixxx::StemChannelSelection stemMask, + bool play); #else void slotLoadSelectedTrackToGroup(const QString& group, bool play); #endif diff --git a/src/library/libraryfeature.h b/src/library/libraryfeature.h index 9840d4424b2..9a91e748ddd 100644 --- a/src/library/libraryfeature.h +++ b/src/library/libraryfeature.h @@ -12,6 +12,9 @@ #include "library/dao/trackdao.h" #include "library/treeitemmodel.h" #include "track/track_decl.h" +#ifdef __STEM__ +#include "engine/engine.h" +#endif class KeyboardEventFilter; class Library; @@ -138,7 +141,7 @@ class LibraryFeature : public QObject { #ifdef __STEM__ void loadTrackToPlayer(TrackPointer pTrack, const QString& group, - uint stemMask, + mixxx::StemChannelSelection stemMask, bool play = false); #else void loadTrackToPlayer(TrackPointer pTrack, diff --git a/src/library/recording/dlgrecording.h b/src/library/recording/dlgrecording.h index 3ea574632cb..a4832ce0392 100644 --- a/src/library/recording/dlgrecording.h +++ b/src/library/recording/dlgrecording.h @@ -6,6 +6,9 @@ #include "library/recording/ui_dlgrecording.h" #include "preferences/usersettings.h" #include "track/track_decl.h" +#ifdef __STEM__ +#include "engine/engine.h" +#endif class WLibrary; class WTrackTableView; @@ -38,7 +41,10 @@ class DlgRecording : public QWidget, public Ui::DlgRecording, public virtual Lib signals: void loadTrack(TrackPointer tio); #ifdef __STEM__ - void loadTrackToPlayer(TrackPointer tio, const QString& group, uint stemMask, bool); + void loadTrackToPlayer(TrackPointer tio, + const QString& group, + mixxx::StemChannelSelection stemMask, + bool); #else void loadTrackToPlayer(TrackPointer tio, const QString& group, bool); #endif diff --git a/src/library/tabledelegates/previewbuttondelegate.cpp b/src/library/tabledelegates/previewbuttondelegate.cpp index d4b695a3636..32c0b4856eb 100644 --- a/src/library/tabledelegates/previewbuttondelegate.cpp +++ b/src/library/tabledelegates/previewbuttondelegate.cpp @@ -222,7 +222,7 @@ void PreviewButtonDelegate::buttonClicked() { // Load to preview deck and start playing emit loadTrackToPlayer(pTrack, kPreviewDeckGroup, #ifdef __STEM__ - mixxx::kNoStemSelected, + mixxx::StemChannelSelection(), #endif true); startedPlaying = true; diff --git a/src/library/tabledelegates/previewbuttondelegate.h b/src/library/tabledelegates/previewbuttondelegate.h index a7a9be95dbe..261b576d1b3 100644 --- a/src/library/tabledelegates/previewbuttondelegate.h +++ b/src/library/tabledelegates/previewbuttondelegate.h @@ -6,6 +6,9 @@ #include "library/tabledelegates/tableitemdelegate.h" #include "track/track_decl.h" #include "util/parented_ptr.h" +#ifdef __STEM__ +#include "engine/engine.h" +#endif class ControlProxy; class WLibraryTableView; @@ -55,7 +58,10 @@ class PreviewButtonDelegate : public TableItemDelegate { signals: #ifdef __STEM__ - void loadTrackToPlayer(const TrackPointer& pTrack, const QString& group, uint stemMask, bool); + void loadTrackToPlayer(const TrackPointer& pTrack, + const QString& group, + mixxx::StemChannelSelection stemMask, + bool); #else void loadTrackToPlayer(const TrackPointer& pTrack, const QString& group, bool); #endif diff --git a/src/mixer/basetrackplayer.cpp b/src/mixer/basetrackplayer.cpp index 5d789cd4b6d..1891fec2c43 100644 --- a/src/mixer/basetrackplayer.cpp +++ b/src/mixer/basetrackplayer.cpp @@ -419,7 +419,7 @@ void BaseTrackPlayerImpl::slotEjectTrack(double v) { if (lastEjected) { slotLoadTrack(lastEjected, #ifdef __STEM__ - mixxx::kNoStemSelected, + mixxx::StemChannelSelection(), #endif false); } @@ -432,7 +432,7 @@ void BaseTrackPlayerImpl::slotEjectTrack(double v) { if (lastEjected) { slotLoadTrack(lastEjected, #ifdef __STEM__ - mixxx::kNoStemSelected, + mixxx::StemChannelSelection(), #endif false); } @@ -550,7 +550,7 @@ void BaseTrackPlayerImpl::disconnectLoadedTrack() { #ifdef __STEM__ void BaseTrackPlayerImpl::slotLoadTrack(TrackPointer pNewTrack, - uint stemMask, + mixxx::StemChannelSelection stemMask, bool bPlay) { #else void BaseTrackPlayerImpl::slotLoadTrack(TrackPointer pNewTrack, @@ -801,7 +801,7 @@ void BaseTrackPlayerImpl::slotCloneChannel(EngineChannel* pChannel) { bool play = ControlObject::toBool(ConfigKey(m_pChannelToCloneFrom->getGroup(), "play")); slotLoadTrack(pTrack, #ifdef __STEM__ - mixxx::kNoStemSelected, + mixxx::StemChannelSelection(), #endif play); } @@ -829,7 +829,7 @@ void BaseTrackPlayerImpl::loadTrackFromGroup(const QString& group) { slotLoadTrack(pTrack, #ifdef __STEM__ - mixxx::kNoStemSelected, + mixxx::StemChannelSelection(), #endif false); } diff --git a/src/mixer/basetrackplayer.h b/src/mixer/basetrackplayer.h index 28bcd88b17e..e3c596a85e2 100644 --- a/src/mixer/basetrackplayer.h +++ b/src/mixer/basetrackplayer.h @@ -3,6 +3,9 @@ #include #include +#ifdef __STEM__ +#include "engine/engine.h" +#endif #include "engine/channels/enginechannel.h" #include "mixer/baseplayer.h" #include "preferences/colorpalettesettings.h" @@ -48,7 +51,7 @@ class BaseTrackPlayer : public BasePlayer { public slots: #ifdef __STEM__ virtual void slotLoadTrack(TrackPointer pTrack, - uint stemMask, + mixxx::StemChannelSelection stemMask, bool bPlay = false) = 0; #else virtual void slotLoadTrack(TrackPointer pTrack, @@ -65,7 +68,7 @@ class BaseTrackPlayer : public BasePlayer { void trackUnloaded(TrackPointer pUnloadedTrack); void loadingTrack(TrackPointer pNewTrack, TrackPointer pOldTrack); #ifdef __STEM__ - void selectedStems(uint stemMask); + void selectedStems(mixxx::StemChannelSelection stemMask); #endif void playerEmpty(); void noVinylControlInputConfigured(); @@ -106,7 +109,7 @@ class BaseTrackPlayerImpl : public BaseTrackPlayer { public slots: #ifdef __STEM__ void slotLoadTrack(TrackPointer track, - uint stemMask, + mixxx::StemChannelSelection stemMask, bool bPlay) final; #else void slotLoadTrack(TrackPointer track, diff --git a/src/mixer/playermanager.cpp b/src/mixer/playermanager.cpp index 2a38360aacf..965d153a883 100644 --- a/src/mixer/playermanager.cpp +++ b/src/mixer/playermanager.cpp @@ -671,8 +671,10 @@ void PlayerManager::slotCloneDeck(const QString& source_group, const QString& ta } #ifdef __STEM__ -void PlayerManager::slotLoadTrackToPlayer( - TrackPointer pTrack, const QString& group, uint stemMask, bool play) { +void PlayerManager::slotLoadTrackToPlayer(TrackPointer pTrack, + const QString& group, + mixxx::StemChannelSelection stemMask, + bool play) { #else void PlayerManager::slotLoadTrackToPlayer( TrackPointer pTrack, const QString& group, bool play) { @@ -785,7 +787,7 @@ void PlayerManager::slotLoadTrackIntoNextAvailableDeck(TrackPointer pTrack) { pDeck->slotLoadTrack(pTrack, #ifdef __STEM__ - mixxx::kNoStemSelected, + mixxx::StemChannelSelection(), #endif false); } @@ -810,7 +812,11 @@ void PlayerManager::slotLoadTrackIntoNextAvailableSampler(TrackPointer pTrack) { } locker.unlock(); +#ifdef __STEM__ + pSampler->slotLoadTrack(pTrack, mixxx::StemChannelSelection(), false); +#else pSampler->slotLoadTrack(pTrack, false); +#endif } void PlayerManager::slotAnalyzeTrack(TrackPointer track) { diff --git a/src/mixer/playermanager.h b/src/mixer/playermanager.h index b5298ae2493..22a98c74831 100644 --- a/src/mixer/playermanager.h +++ b/src/mixer/playermanager.h @@ -195,7 +195,10 @@ class PlayerManager : public QObject, public PlayerManagerInterface { public slots: // Slots for loading tracks into a Player, which is either a Sampler or a Deck #ifdef __STEM__ - void slotLoadTrackToPlayer(TrackPointer pTrack, const QString& group, uint stemMask, bool play); + void slotLoadTrackToPlayer(TrackPointer pTrack, + const QString& group, + mixxx::StemChannelSelection stemMask, + bool play); #else void slotLoadTrackToPlayer(TrackPointer pTrack, const QString& group, bool play); #endif diff --git a/src/mixer/samplerbank.cpp b/src/mixer/samplerbank.cpp index dca2e1b4112..82624221f90 100644 --- a/src/mixer/samplerbank.cpp +++ b/src/mixer/samplerbank.cpp @@ -215,7 +215,7 @@ bool SamplerBank::loadSamplerBankFromPath(const QString& samplerBankPath) { m_pPlayerManager->slotLoadTrackToPlayer( TrackPointer(), group, #ifdef __STEM__ - mixxx::kNoStemSelected, + mixxx::StemChannelSelection(), #endif false); } else { diff --git a/src/sources/audiosource.h b/src/sources/audiosource.h index 705a71be51c..4f72b1f9959 100644 --- a/src/sources/audiosource.h +++ b/src/sources/audiosource.h @@ -196,13 +196,13 @@ class AudioSource : public UrlResource, public virtual /*implements*/ IAudioSour #ifdef __STEM__ OpenParams() : m_signalInfo(), - m_stemMask(mixxx::kNoStemSelected) { + m_stemMask(mixxx::StemChannelSelection()) { } OpenParams( audio::ChannelCount channelCount, audio::SampleRate sampleRate, - uint stemMask = mixxx::kNoStemSelected) + mixxx::StemChannelSelection stemMask = mixxx::StemChannelSelection()) : m_signalInfo( channelCount, sampleRate), @@ -225,7 +225,7 @@ class AudioSource : public UrlResource, public virtual /*implements*/ IAudioSour } #ifdef __STEM__ - uint stemMask() const { + mixxx::StemChannelSelection stemMask() const { return m_stemMask; } #endif @@ -237,7 +237,7 @@ class AudioSource : public UrlResource, public virtual /*implements*/ IAudioSour #ifdef __STEM__ void setStemMask( - uint stemMask) { + mixxx::StemChannelSelection stemMask) { VERIFY_OR_DEBUG_ASSERT(stemMask <= 2 << mixxx::kMaxSupportedStems) { return; } @@ -253,7 +253,7 @@ class AudioSource : public UrlResource, public virtual /*implements*/ IAudioSour private: audio::SignalInfo m_signalInfo; #ifdef __STEM__ - uint m_stemMask; + mixxx::StemChannelSelection m_stemMask; #endif }; diff --git a/src/test/autodjprocessor_test.cpp b/src/test/autodjprocessor_test.cpp index 53b59e17a66..88f7c9c28b5 100644 --- a/src/test/autodjprocessor_test.cpp +++ b/src/test/autodjprocessor_test.cpp @@ -96,7 +96,7 @@ class FakeDeck : public BaseTrackPlayer { // fakeTrackLoadFailedEvent. void slotLoadTrack(TrackPointer pTrack, #ifdef __STEM__ - uint, + mixxx::StemChannelSelection, #endif bool bPlay) override { loadedTrack = pTrack; @@ -269,7 +269,7 @@ TEST_F(AutoDJProcessorTest, FullIntroOutro_LongerIntro) { // Load track and mark it playing. deck1.slotLoadTrack(pTrack, #ifdef __STEM__ - mixxx::kNoStemSelected, + mixxx::StemChannelSelection(), #endif true); // Indicate the track loaded successfully. @@ -290,7 +290,7 @@ TEST_F(AutoDJProcessorTest, FullIntroOutro_LongerIntro) { // Pretend the track load succeeds. deck2.slotLoadTrack(pTrack, #ifdef __STEM__ - mixxx::kNoStemSelected, + mixxx::StemChannelSelection(), #endif false); @@ -351,7 +351,7 @@ TEST_F(AutoDJProcessorTest, FullIntroOutro_LongerOutro) { // Load track and mark it playing. deck1.slotLoadTrack(pTrack, #ifdef __STEM__ - mixxx::kNoStemSelected, + mixxx::StemChannelSelection(), #endif true); // Indicate the track loaded successfully. @@ -372,7 +372,7 @@ TEST_F(AutoDJProcessorTest, FullIntroOutro_LongerOutro) { // Pretend the track load succeeds. deck2.slotLoadTrack(pTrack, #ifdef __STEM__ - mixxx::kNoStemSelected, + mixxx::StemChannelSelection(), #endif false); @@ -439,7 +439,7 @@ TEST_F(AutoDJProcessorTest, FadeAtOutroStart_LongerIntro) { // Load track and mark it playing. deck1.slotLoadTrack(pTrack, #ifdef __STEM__ - mixxx::kNoStemSelected, + mixxx::StemChannelSelection(), #endif true); // Indicate the track loaded successfully. @@ -460,7 +460,7 @@ TEST_F(AutoDJProcessorTest, FadeAtOutroStart_LongerIntro) { // Pretend the track load succeeds. deck2.slotLoadTrack(pTrack, #ifdef __STEM__ - mixxx::kNoStemSelected, + mixxx::StemChannelSelection(), #endif false); @@ -523,7 +523,7 @@ TEST_F(AutoDJProcessorTest, FadeAtOutroStart_LongerOutro) { // Load track and mark it playing. deck1.slotLoadTrack(pTrack, #ifdef __STEM__ - mixxx::kNoStemSelected, + mixxx::StemChannelSelection(), #endif true); // Indicate the track loaded successfully. @@ -544,7 +544,7 @@ TEST_F(AutoDJProcessorTest, FadeAtOutroStart_LongerOutro) { // Pretend the track load succeeds. deck2.slotLoadTrack(pTrack, #ifdef __STEM__ - mixxx::kNoStemSelected, + mixxx::StemChannelSelection(), #endif false); @@ -678,7 +678,7 @@ TEST_F(AutoDJProcessorTest, EnabledSuccess_DecksStopped) { TrackPointer pTrack = trackCollectionManager()->getTrackById(testId); deck1.slotLoadTrack(pTrack, #ifdef __STEM__ - mixxx::kNoStemSelected, + mixxx::StemChannelSelection(), #endif true); @@ -728,7 +728,7 @@ TEST_F(AutoDJProcessorTest, EnabledSuccess_DecksStopped_TrackLoadFails) { TrackPointer pTrack(newTestTrack(testId)); deck1.slotLoadTrack(pTrack, #ifdef __STEM__ - mixxx::kNoStemSelected, + mixxx::StemChannelSelection(), #endif true); @@ -750,7 +750,7 @@ TEST_F(AutoDJProcessorTest, EnabledSuccess_DecksStopped_TrackLoadFails) { // Now pretend that the follow-up load request succeeded. deck1.slotLoadTrack(pTrack, #ifdef __STEM__ - mixxx::kNoStemSelected, + mixxx::StemChannelSelection(), #endif true); deck1.fakeTrackLoadedEvent(pTrack); @@ -802,7 +802,7 @@ TEST_F(AutoDJProcessorTest, EnabledSuccess_DecksStopped_TrackLoadFailsRightDeck) TrackPointer pTrack(newTestTrack(testId)); deck1.slotLoadTrack(pTrack, #ifdef __STEM__ - mixxx::kNoStemSelected, + mixxx::StemChannelSelection(), #endif true); @@ -830,7 +830,7 @@ TEST_F(AutoDJProcessorTest, EnabledSuccess_DecksStopped_TrackLoadFailsRightDeck) // Now pretend that the deck2 load request failed. deck2.slotLoadTrack(pTrack, #ifdef __STEM__ - mixxx::kNoStemSelected, + mixxx::StemChannelSelection(), #endif false); deck2.fakeTrackLoadFailedEvent(pTrack); @@ -841,7 +841,7 @@ TEST_F(AutoDJProcessorTest, EnabledSuccess_DecksStopped_TrackLoadFailsRightDeck) // Pretend the deck2 load request succeeded. deck2.slotLoadTrack(pTrack, #ifdef __STEM__ - mixxx::kNoStemSelected, + mixxx::StemChannelSelection(), #endif false); deck2.fakeTrackLoadedEvent(pTrack); @@ -862,7 +862,7 @@ TEST_F(AutoDJProcessorTest, EnabledSuccess_PlayingDeck1) { // Load track and mark it playing. deck1.slotLoadTrack(pTrack, #ifdef __STEM__ - mixxx::kNoStemSelected, + mixxx::StemChannelSelection(), #endif true); // Indicate the track loaded successfully. @@ -888,7 +888,7 @@ TEST_F(AutoDJProcessorTest, EnabledSuccess_PlayingDeck1) { // Pretend the track load succeeds. deck2.slotLoadTrack(pTrack, #ifdef __STEM__ - mixxx::kNoStemSelected, + mixxx::StemChannelSelection(), #endif false); deck2.fakeTrackLoadedEvent(pTrack); @@ -909,7 +909,7 @@ TEST_F(AutoDJProcessorTest, EnabledSuccess_PlayingDeck1_TrackLoadFailed) { // Load track and mark it playing. deck1.slotLoadTrack(pTrack, #ifdef __STEM__ - mixxx::kNoStemSelected, + mixxx::StemChannelSelection(), #endif true); // Indicate the track loaded successfully. @@ -942,7 +942,7 @@ TEST_F(AutoDJProcessorTest, EnabledSuccess_PlayingDeck1_TrackLoadFailed) { // Pretend the track load fails. deck2.slotLoadTrack(pTrack, #ifdef __STEM__ - mixxx::kNoStemSelected, + mixxx::StemChannelSelection(), #endif false); deck2.fakeTrackLoadFailedEvent(pTrack); @@ -956,7 +956,7 @@ TEST_F(AutoDJProcessorTest, EnabledSuccess_PlayingDeck1_TrackLoadFailed) { // Pretend the track load succeeds. deck2.slotLoadTrack(pTrack, #ifdef __STEM__ - mixxx::kNoStemSelected, + mixxx::StemChannelSelection(), #endif false); deck2.fakeTrackLoadedEvent(pTrack); @@ -977,7 +977,7 @@ TEST_F(AutoDJProcessorTest, EnabledSuccess_PlayingDeck2) { // Load track and mark it playing. deck2.slotLoadTrack(pTrack, #ifdef __STEM__ - mixxx::kNoStemSelected, + mixxx::StemChannelSelection(), #endif true); // Indicate the track loaded successfully. @@ -1004,7 +1004,7 @@ TEST_F(AutoDJProcessorTest, EnabledSuccess_PlayingDeck2) { // Pretend the track load succeeds. deck1.slotLoadTrack(pTrack, #ifdef __STEM__ - mixxx::kNoStemSelected, + mixxx::StemChannelSelection(), #endif false); deck1.fakeTrackLoadedEvent(pTrack); @@ -1025,7 +1025,7 @@ TEST_F(AutoDJProcessorTest, EnabledSuccess_PlayingDeck2_TrackLoadFailed) { // Load track and mark it playing. deck2.slotLoadTrack(pTrack, #ifdef __STEM__ - mixxx::kNoStemSelected, + mixxx::StemChannelSelection(), #endif true); // Indicate the track loaded successfully. @@ -1058,7 +1058,7 @@ TEST_F(AutoDJProcessorTest, EnabledSuccess_PlayingDeck2_TrackLoadFailed) { // Pretend the track load fails. deck1.slotLoadTrack(pTrack, #ifdef __STEM__ - mixxx::kNoStemSelected, + mixxx::StemChannelSelection(), #endif false); deck1.fakeTrackLoadFailedEvent(pTrack); @@ -1072,7 +1072,7 @@ TEST_F(AutoDJProcessorTest, EnabledSuccess_PlayingDeck2_TrackLoadFailed) { // Pretend the track load succeeds. deck1.slotLoadTrack(pTrack, #ifdef __STEM__ - mixxx::kNoStemSelected, + mixxx::StemChannelSelection(), #endif false); deck1.fakeTrackLoadedEvent(pTrack); @@ -1111,7 +1111,7 @@ TEST_F(AutoDJProcessorTest, FadeToDeck1_LoadOnDeck2_TrackLoadSuccess) { // Load track and mark it playing. deck2.slotLoadTrack(pTrack, #ifdef __STEM__ - mixxx::kNoStemSelected, + mixxx::StemChannelSelection(), #endif true); // Indicate the track loaded successfully. @@ -1140,7 +1140,7 @@ TEST_F(AutoDJProcessorTest, FadeToDeck1_LoadOnDeck2_TrackLoadSuccess) { // Pretend the track load succeeds. deck1.slotLoadTrack(pTrack, #ifdef __STEM__ - mixxx::kNoStemSelected, + mixxx::StemChannelSelection(), #endif false); deck1.fakeTrackLoadedEvent(pTrack); @@ -1187,7 +1187,7 @@ TEST_F(AutoDJProcessorTest, FadeToDeck1_LoadOnDeck2_TrackLoadSuccess) { // Pretend the track load request succeeds. deck2.slotLoadTrack(pTrack, #ifdef __STEM__ - mixxx::kNoStemSelected, + mixxx::StemChannelSelection(), #endif false); deck2.fakeTrackLoadedEvent(pTrack); @@ -1210,7 +1210,7 @@ TEST_F(AutoDJProcessorTest, FadeToDeck1_LoadOnDeck2_TrackLoadFailed) { // Load track and mark it playing. deck2.slotLoadTrack(pTrack, #ifdef __STEM__ - mixxx::kNoStemSelected, + mixxx::StemChannelSelection(), #endif true); // Indicate the track loaded successfully. @@ -1241,7 +1241,7 @@ TEST_F(AutoDJProcessorTest, FadeToDeck1_LoadOnDeck2_TrackLoadFailed) { // Pretend the track load succeeds. deck1.slotLoadTrack(pTrack, #ifdef __STEM__ - mixxx::kNoStemSelected, + mixxx::StemChannelSelection(), #endif false); deck1.fakeTrackLoadedEvent(pTrack); @@ -1292,7 +1292,7 @@ TEST_F(AutoDJProcessorTest, FadeToDeck1_LoadOnDeck2_TrackLoadFailed) { // Pretend the track load request fails. deck2.slotLoadTrack(pTrack, #ifdef __STEM__ - mixxx::kNoStemSelected, + mixxx::StemChannelSelection(), #endif false); deck2.fakeTrackLoadFailedEvent(pTrack); @@ -1306,7 +1306,7 @@ TEST_F(AutoDJProcessorTest, FadeToDeck1_LoadOnDeck2_TrackLoadFailed) { // Pretend the second track load request succeeds. deck2.slotLoadTrack(pTrack, #ifdef __STEM__ - mixxx::kNoStemSelected, + mixxx::StemChannelSelection(), #endif false); deck2.fakeTrackLoadedEvent(pTrack); @@ -1329,7 +1329,7 @@ TEST_F(AutoDJProcessorTest, FadeToDeck2_LoadOnDeck1_TrackLoadSuccess) { // Load track and mark it playing. deck1.slotLoadTrack(pTrack, #ifdef __STEM__ - mixxx::kNoStemSelected, + mixxx::StemChannelSelection(), #endif true); // Indicate the track loaded successfully. @@ -1358,7 +1358,7 @@ TEST_F(AutoDJProcessorTest, FadeToDeck2_LoadOnDeck1_TrackLoadSuccess) { // Pretend the track load succeeds. deck2.slotLoadTrack(pTrack, #ifdef __STEM__ - mixxx::kNoStemSelected, + mixxx::StemChannelSelection(), #endif false); deck2.fakeTrackLoadedEvent(pTrack); @@ -1405,7 +1405,7 @@ TEST_F(AutoDJProcessorTest, FadeToDeck2_LoadOnDeck1_TrackLoadSuccess) { // Pretend the track load request succeeds. deck1.slotLoadTrack(pTrack, #ifdef __STEM__ - mixxx::kNoStemSelected, + mixxx::StemChannelSelection(), #endif false); deck1.fakeTrackLoadedEvent(pTrack); @@ -1428,7 +1428,7 @@ TEST_F(AutoDJProcessorTest, FadeToDeck2_LoadOnDeck1_TrackLoadFailed) { // Load track and mark it playing. deck1.slotLoadTrack(pTrack, #ifdef __STEM__ - mixxx::kNoStemSelected, + mixxx::StemChannelSelection(), #endif true); // Indicate the track loaded successfully. @@ -1459,7 +1459,7 @@ TEST_F(AutoDJProcessorTest, FadeToDeck2_LoadOnDeck1_TrackLoadFailed) { // Pretend the track load succeeds. deck2.slotLoadTrack(pTrack, #ifdef __STEM__ - mixxx::kNoStemSelected, + mixxx::StemChannelSelection(), #endif false); deck2.fakeTrackLoadedEvent(pTrack); @@ -1510,7 +1510,7 @@ TEST_F(AutoDJProcessorTest, FadeToDeck2_LoadOnDeck1_TrackLoadFailed) { // Pretend the track load request fails. deck1.slotLoadTrack(pTrack, #ifdef __STEM__ - mixxx::kNoStemSelected, + mixxx::StemChannelSelection(), #endif false); deck1.fakeTrackLoadFailedEvent(pTrack); @@ -1524,7 +1524,7 @@ TEST_F(AutoDJProcessorTest, FadeToDeck2_LoadOnDeck1_TrackLoadFailed) { // Pretend the track load request succeeds. deck1.slotLoadTrack(pTrack, #ifdef __STEM__ - mixxx::kNoStemSelected, + mixxx::StemChannelSelection(), #endif false); deck1.fakeTrackLoadedEvent(pTrack); @@ -1550,7 +1550,7 @@ TEST_F(AutoDJProcessorTest, FadeToDeck2_Long_Transition) { // Load track and mark it playing. deck1.slotLoadTrack(pTrack, #ifdef __STEM__ - mixxx::kNoStemSelected, + mixxx::StemChannelSelection(), #endif true); // Indicate the track loaded successfully. @@ -1571,7 +1571,7 @@ TEST_F(AutoDJProcessorTest, FadeToDeck2_Long_Transition) { // Pretend the track load succeeds. deck2.slotLoadTrack(pTrack, #ifdef __STEM__ - mixxx::kNoStemSelected, + mixxx::StemChannelSelection(), #endif false); deck2.fakeTrackLoadedEvent(pTrack); @@ -1647,7 +1647,7 @@ TEST_F(AutoDJProcessorTest, FadeToDeck2_Pause_Transition) { // Load track and mark it playing. deck1.slotLoadTrack(pTrack, #ifdef __STEM__ - mixxx::kNoStemSelected, + mixxx::StemChannelSelection(), #endif true); // Indicate the track loaded successfully. @@ -1667,7 +1667,7 @@ TEST_F(AutoDJProcessorTest, FadeToDeck2_Pause_Transition) { // Pretend the track load succeeds. deck2.slotLoadTrack(pTrack, #ifdef __STEM__ - mixxx::kNoStemSelected, + mixxx::StemChannelSelection(), #endif false); deck2.fakeTrackLoadedEvent(pTrack); @@ -1685,7 +1685,7 @@ TEST_F(AutoDJProcessorTest, FadeToDeck2_Pause_Transition) { // Pretend the track load succeeds. deck2.slotLoadTrack(pTrack, #ifdef __STEM__ - mixxx::kNoStemSelected, + mixxx::StemChannelSelection(), #endif false); deck2.fakeTrackLoadedEvent(pTrack); @@ -1739,7 +1739,7 @@ TEST_F(AutoDJProcessorTest, FadeToDeck2_SeekEnd) { // Load track and mark it playing. deck1.slotLoadTrack(pTrack, #ifdef __STEM__ - mixxx::kNoStemSelected, + mixxx::StemChannelSelection(), #endif true); // Indicate the track loaded successfully. @@ -1760,7 +1760,7 @@ TEST_F(AutoDJProcessorTest, FadeToDeck2_SeekEnd) { // Pretend the track load succeeds. deck2.slotLoadTrack(pTrack, #ifdef __STEM__ - mixxx::kNoStemSelected, + mixxx::StemChannelSelection(), #endif false); deck2.fakeTrackLoadedEvent(pTrack); @@ -1799,7 +1799,7 @@ TEST_F(AutoDJProcessorTest, FadeToDeck2_SeekBeforeTransition) { // Load track and mark it playing. deck1.slotLoadTrack(pTrack, #ifdef __STEM__ - mixxx::kNoStemSelected, + mixxx::StemChannelSelection(), #endif true); // Indicate the track loaded successfully. @@ -1820,7 +1820,7 @@ TEST_F(AutoDJProcessorTest, FadeToDeck2_SeekBeforeTransition) { // Pretend the track load succeeds. deck2.slotLoadTrack(pTrack, #ifdef __STEM__ - mixxx::kNoStemSelected, + mixxx::StemChannelSelection(), #endif false); deck2.fakeTrackLoadedEvent(pTrack); @@ -1883,7 +1883,7 @@ TEST_F(AutoDJProcessorTest, TrackZeroLength) { pTrack->setDuration(0); deck1.slotLoadTrack(pTrack, #ifdef __STEM__ - mixxx::kNoStemSelected, + mixxx::StemChannelSelection(), #endif true); diff --git a/src/test/cuecontrol_test.cpp b/src/test/cuecontrol_test.cpp index d4aa2aabb7a..ad131aa216a 100644 --- a/src/test/cuecontrol_test.cpp +++ b/src/test/cuecontrol_test.cpp @@ -50,7 +50,7 @@ class CueControlTest : public BaseSignalPathTest { void unloadTrack() { m_pMixerDeck1->slotLoadTrack(TrackPointer(), #ifdef __STEM__ - mixxx::kNoStemSelected, + mixxx::StemChannelSelection(), #endif false); } diff --git a/src/test/hotcuecontrol_test.cpp b/src/test/hotcuecontrol_test.cpp index 303a00ad036..556028e6a24 100644 --- a/src/test/hotcuecontrol_test.cpp +++ b/src/test/hotcuecontrol_test.cpp @@ -81,7 +81,7 @@ class HotcueControlTest : public BaseSignalPathTest { void unloadTrack() { m_pMixerDeck1->slotLoadTrack(TrackPointer(), #ifdef __STEM__ - mixxx::kNoStemSelected, + mixxx::StemChannelSelection(), #endif false); } diff --git a/src/test/playermanagertest.cpp b/src/test/playermanagertest.cpp index 27a9aa9c351..d1642b5a4f4 100644 --- a/src/test/playermanagertest.cpp +++ b/src/test/playermanagertest.cpp @@ -151,7 +151,7 @@ TEST_F(PlayerManagerTest, UnEjectTest) { ASSERT_TRUE(testId1.isValid()); deck1->slotLoadTrack(pTrack1, #ifdef __STEM__ - mixxx::kNoStemSelected, + mixxx::StemChannelSelection(), #endif false); ASSERT_NE(nullptr, deck1->getLoadedTrack()); @@ -168,7 +168,7 @@ TEST_F(PlayerManagerTest, UnEjectTest) { ASSERT_NE(nullptr, pTrack2); deck1->slotLoadTrack(pTrack2, #ifdef __STEM__ - mixxx::kNoStemSelected, + mixxx::StemChannelSelection(), #endif false); @@ -193,7 +193,7 @@ TEST_F(PlayerManagerTest, UnEjectReplaceTrackTest) { ASSERT_TRUE(testId1.isValid()); deck1->slotLoadTrack(pTrack1, #ifdef __STEM__ - mixxx::kNoStemSelected, + mixxx::StemChannelSelection(), #endif false); ASSERT_NE(nullptr, deck1->getLoadedTrack()); @@ -206,7 +206,7 @@ TEST_F(PlayerManagerTest, UnEjectReplaceTrackTest) { ASSERT_NE(nullptr, pTrack2); deck1->slotLoadTrack(pTrack2, #ifdef __STEM__ - mixxx::kNoStemSelected, + mixxx::StemChannelSelection(), #endif false); m_pEngine->process(1024); @@ -246,7 +246,7 @@ TEST_F(PlayerManagerTest, UnReplaceTest) { ASSERT_TRUE(testId1.isValid()); deck1->slotLoadTrack(pTrack1, #ifdef __STEM__ - mixxx::kNoStemSelected, + mixxx::StemChannelSelection(), #endif false); m_pEngine->process(1024); @@ -258,7 +258,7 @@ TEST_F(PlayerManagerTest, UnReplaceTest) { ASSERT_NE(nullptr, pTrack2); deck1->slotLoadTrack(pTrack2, #ifdef __STEM__ - mixxx::kNoStemSelected, + mixxx::StemChannelSelection(), #endif false); m_pEngine->process(1024); diff --git a/src/test/signalpathtest.h b/src/test/signalpathtest.h index 902bbbbdb6c..619e80e21f8 100644 --- a/src/test/signalpathtest.h +++ b/src/test/signalpathtest.h @@ -171,7 +171,7 @@ class BaseSignalPathTest : public MixxxTest, SoundSourceProviderRegistration { } pDeck->slotLoadTrack(pTrack, #ifdef __STEM__ - mixxx::kNoStemSelected, + mixxx::StemChannelSelection(), #endif false); diff --git a/src/waveform/renderers/waveformwidgetrenderer.cpp b/src/waveform/renderers/waveformwidgetrenderer.cpp index f21dcf2a8eb..91e7717649f 100644 --- a/src/waveform/renderers/waveformwidgetrenderer.cpp +++ b/src/waveform/renderers/waveformwidgetrenderer.cpp @@ -22,7 +22,7 @@ constexpr int kDefaultDimBrightThreshold = 127; WaveformWidgetRenderer::WaveformWidgetRenderer(const QString& group) : m_group(group), #ifdef __STEM__ - m_selectedStems(mixxx::kNoStemSelected), + m_selectedStems(mixxx::StemChannelSelection()), #endif m_orientation(Qt::Horizontal), m_dimBrightThreshold(kDefaultDimBrightThreshold), @@ -420,7 +420,7 @@ void WaveformWidgetRenderer::setDisplayBeatGridAlpha(int alpha) { } #ifdef __STEM__ -void WaveformWidgetRenderer::selectStem(uint stemMask) { +void WaveformWidgetRenderer::selectStem(mixxx::StemChannelSelection stemMask) { m_selectedStems = stemMask; } #endif diff --git a/src/waveform/renderers/waveformwidgetrenderer.h b/src/waveform/renderers/waveformwidgetrenderer.h index 2d4cb4cf3e8..71ad9de5829 100644 --- a/src/waveform/renderers/waveformwidgetrenderer.h +++ b/src/waveform/renderers/waveformwidgetrenderer.h @@ -177,7 +177,7 @@ class WaveformWidgetRenderer { } #ifdef __STEM__ - void selectStem(uint stemMask); + void selectStem(mixxx::StemChannelSelection stemMask); #endif void setTrack(TrackPointer track); void setMarkPositions(const QList& markPositions) { diff --git a/src/widget/wlibrarytableview.h b/src/widget/wlibrarytableview.h index 78977d1e166..ad060872f2f 100644 --- a/src/widget/wlibrarytableview.h +++ b/src/widget/wlibrarytableview.h @@ -8,6 +8,9 @@ #include "library/libraryview.h" #include "preferences/usersettings.h" #include "track/track_decl.h" +#ifdef __STEM__ +#include "engine/engine.h" +#endif class QFont; @@ -59,7 +62,7 @@ class WLibraryTableView : public QTableView, public virtual LibraryView { void loadTrackToPlayer(TrackPointer pTrack, const QString& group, #ifdef __STEM__ - uint stemMask, + mixxx::StemChannelSelection stemMask, #endif bool play = false); void trackSelected(TrackPointer pTrack); diff --git a/src/widget/wtrackmenu.cpp b/src/widget/wtrackmenu.cpp index f633cdce217..e9a1cf332b2 100644 --- a/src/widget/wtrackmenu.cpp +++ b/src/widget/wtrackmenu.cpp @@ -900,7 +900,7 @@ void WTrackMenu::generateTrackLoadMenu(const QString& group, connect(pStemMenu, &WTrackStemMenu::selectedStem, this, - [this](const QString& group, uint stemMask) { + [this](const QString& group, mixxx::StemChannelSelection stemMask) { loadSelectionToGroup(group, stemMask); close(); }); @@ -1866,7 +1866,7 @@ void WTrackMenu::slotColorPicked(const mixxx::RgbColor::optional_t& color) { #ifdef __STEM__ void WTrackMenu::loadSelectionToGroup(const QString& group, - uint stemMask, + mixxx::StemChannelSelection stemMask, bool play) { #else void WTrackMenu::loadSelectionToGroup(const QString& group, diff --git a/src/widget/wtrackmenu.h b/src/widget/wtrackmenu.h index 9a9e641e577..44bed61f7cc 100644 --- a/src/widget/wtrackmenu.h +++ b/src/widget/wtrackmenu.h @@ -113,7 +113,7 @@ class WTrackMenu : public QMenu { #ifdef __STEM__ void loadTrackToPlayer(TrackPointer pTrack, const QString& group, - uint stemMask, + mixxx::StemChannelSelection stemMask, bool play = false); #else void loadTrackToPlayer(TrackPointer pTrack, @@ -243,7 +243,7 @@ class WTrackMenu : public QMenu { #ifdef __STEM__ void loadSelectionToGroup(const QString& group, - uint stemMask = mixxx::kNoStemSelected, + mixxx::StemChannelSelection stemMask = mixxx::StemChannelSelection(), bool play = false); #else void loadSelectionToGroup(const QString& group, diff --git a/src/widget/wtrackstemmenu.cpp b/src/widget/wtrackstemmenu.cpp index ebb7de4e284..65d77b0d713 100644 --- a/src/widget/wtrackstemmenu.cpp +++ b/src/widget/wtrackstemmenu.cpp @@ -2,9 +2,18 @@ #include -#include "engine/engine.h" #include "moc_wtrackstemmenu.cpp" +namespace { +const QList stemTracks = { + + mixxx::StemChannel::First, + mixxx::StemChannel::Second, + mixxx::StemChannel::Third, + mixxx::StemChannel::Fourth, +}; +} + WTrackStemMenu::WTrackStemMenu(const QString& label, QWidget* parent, bool primaryDeck, @@ -14,38 +23,40 @@ WTrackStemMenu::WTrackStemMenu(const QString& label, m_group(group), m_selectMode(false), m_stemInfo(stemInfo), - m_currentSelection(mixxx::kNoStemSelected) { + m_currentSelection() { if (primaryDeck) { QAction* pAction = new QAction(tr("Load for stem mixing"), this); addAction(pAction); connect(pAction, &QAction::triggered, this, [this, group] { - emit selectedStem(group, mixxx::kNoStemSelected); + emit selectedStem(group, {mixxx::StemChannelSelection()}); }); } QAction* pAction = new QAction(tr("Load pre-mixed stereo track"), this); addAction(pAction); connect(pAction, &QAction::triggered, this, [this, group] { - emit selectedStem(group, 0xf); + emit selectedStem(group, mixxx::StemChannel::All); }); addSeparator(); - for (uint stemIdx = 0; stemIdx < mixxx::kMaxSupportedStems; stemIdx++) { + DEBUG_ASSERT(stemTracks.count() == mixxx::kMaxSupportedStems); + int stemIdx = 0; + for (const auto& stemTrack : stemTracks) { m_stemActions.emplace_back( make_parented(tr("Load the \"%1\" stem") .arg(m_stemInfo.at(stemIdx).getLabel()), this)); addAction(m_stemActions.back().get()); - connect(m_stemActions.back().get(), &QAction::triggered, this, [this, stemIdx] { - emit selectedStem(m_group, 1 << stemIdx); - }); - connect(m_stemActions.back().get(), &QAction::toggled, this, [this, stemIdx](bool checked) { - if (checked) { - m_currentSelection |= 1 << stemIdx; - } else { - m_currentSelection ^= 1 << stemIdx; - } + connect(m_stemActions.back().get(), &QAction::triggered, this, [this, stemTrack] { + emit selectedStem(m_group, stemTrack); }); + connect(m_stemActions.back().get(), + &QAction::toggled, + this, + [this, stemTrack](bool checked) { + m_currentSelection.setFlag(stemTrack, checked); + }); + stemIdx++; } m_selectAction = make_parented(this); m_selectAction->setToolTip(tr("Load multiple stem into a stereo deck")); @@ -56,7 +67,6 @@ WTrackStemMenu::WTrackStemMenu(const QString& label, bool WTrackStemMenu::eventFilter(QObject* pObj, QEvent* e) { QInputEvent* pInputEvent = dynamic_cast(e); - qDebug() << e << pInputEvent; if (pInputEvent != nullptr && (pInputEvent->modifiers() & Qt::ControlModifier) != m_selectMode) { m_selectMode = pInputEvent->modifiers() & Qt::ControlModifier; @@ -65,7 +75,6 @@ bool WTrackStemMenu::eventFilter(QObject* pObj, QEvent* e) { if (m_selectMode && (e->type() == QEvent::MouseButtonRelease)) { QAction* pAction = activeAction(); - qDebug() << e << pAction; if (pAction && pAction->isCheckable()) { pAction->setChecked(!pAction->isChecked()); updateActions(); @@ -100,7 +109,7 @@ void WTrackStemMenu::keyReleaseEvent(QKeyEvent* pQEvent) { bool selectMode = pQEvent->modifiers() & Qt::ControlModifier; if (!selectMode && m_selectMode && m_currentSelection) { emit selectedStem(m_group, m_currentSelection); - m_currentSelection = mixxx::kNoStemSelected; + m_currentSelection = mixxx::StemChannelSelection(); } m_selectMode = selectMode; updateActions(); diff --git a/src/widget/wtrackstemmenu.h b/src/widget/wtrackstemmenu.h index 915f45f8339..0b965febf26 100644 --- a/src/widget/wtrackstemmenu.h +++ b/src/widget/wtrackstemmenu.h @@ -3,6 +3,7 @@ #include #include +#include "engine/engine.h" #include "track/steminfo.h" #include "util/parented_ptr.h" @@ -18,7 +19,7 @@ class WTrackStemMenu : public QMenu { const QList& stemInfo); signals: - void selectedStem(const QString& group, uint stemMask); + void selectedStem(const QString& group, mixxx::StemChannelSelection stemMask); protected: virtual void showEvent(QShowEvent* pQEvent) override; @@ -32,7 +33,7 @@ class WTrackStemMenu : public QMenu { QString m_group; bool m_selectMode; QList m_stemInfo; - uint m_currentSelection; + mixxx::StemChannelSelection m_currentSelection; std::vector> m_stemActions; parented_ptr m_selectAction; diff --git a/src/widget/wtracktableview.cpp b/src/widget/wtracktableview.cpp index cb8daf5b1b0..0f2c11e7739 100644 --- a/src/widget/wtracktableview.cpp +++ b/src/widget/wtracktableview.cpp @@ -1267,7 +1267,7 @@ void WTrackTableView::activateSelectedTrack() { #ifdef __STEM__ void WTrackTableView::loadSelectedTrackToGroup(const QString& group, - uint stemMask, + mixxx::StemChannelSelection stemMask, bool play) { #else void WTrackTableView::loadSelectedTrackToGroup(const QString& group, diff --git a/src/widget/wtracktableview.h b/src/widget/wtracktableview.h index e5c0b932ff7..dc47f12d237 100644 --- a/src/widget/wtracktableview.h +++ b/src/widget/wtracktableview.h @@ -11,6 +11,9 @@ #include "util/duration.h" #include "util/parented_ptr.h" #include "widget/wlibrarytableview.h" +#ifdef __STEM__ +#include "engine/engine.h" +#endif class ControlProxy; class DlgTagFetcher; @@ -40,7 +43,7 @@ class WTrackTableView : public WLibraryTableView { void activateSelectedTrack(); #ifdef __STEM__ void loadSelectedTrackToGroup(const QString& group, - uint stemMask, + mixxx::StemChannelSelection stemMask, bool play); #else void loadSelectedTrackToGroup(const QString& group, diff --git a/src/widget/wwaveformviewer.cpp b/src/widget/wwaveformviewer.cpp index 54b2283c1de..f9e41713aca 100644 --- a/src/widget/wwaveformviewer.cpp +++ b/src/widget/wwaveformviewer.cpp @@ -228,7 +228,7 @@ void WWaveformViewer::slotTrackLoaded(TrackPointer track) { } #ifdef __STEM__ -void WWaveformViewer::slotSelectStem(uint stemMask) { +void WWaveformViewer::slotSelectStem(mixxx::StemChannelSelection stemMask) { if (m_waveformWidget) { m_waveformWidget->selectStem(stemMask); update(); diff --git a/src/widget/wwaveformviewer.h b/src/widget/wwaveformviewer.h index 5848e7c1bad..854bbe87ee6 100644 --- a/src/widget/wwaveformviewer.h +++ b/src/widget/wwaveformviewer.h @@ -46,7 +46,7 @@ class WWaveformViewer : public WWidget, public TrackDropTarget { void slotTrackUnloaded(TrackPointer pOldTrack); void slotLoadingTrack(TrackPointer pNewTrack, TrackPointer pOldTrack); #ifdef __STEM__ - void slotSelectStem(uint stemMask); + void slotSelectStem(mixxx::StemChannelSelection stemMask); #endif protected: