summaryrefslogtreecommitdiffstats
path: root/src/library
diff options
context:
space:
mode:
authorUwe Klotz <uklotz@mixxx.org>2018-04-18 16:39:07 +0200
committerUwe Klotz <uklotz@mixxx.org>2018-10-30 23:26:56 +0100
commitc236956884e3c7b9a47536f98eb7eb5a126a26e4 (patch)
tree85ea9323501bb2f5176c35679e2307e50eeed49c /src/library
parentdb7fe92a9a5c63e0d9b6f0fe6f1ad379f2b0b46a (diff)
Fix and enable multi-threaded analysis
Diffstat (limited to 'src/library')
-rw-r--r--src/library/analysisfeature.cpp153
-rw-r--r--src/library/analysisfeature.h25
-rw-r--r--src/library/dlganalysis.cpp71
-rw-r--r--src/library/dlganalysis.h15
-rw-r--r--src/library/library.cpp12
-rw-r--r--src/library/library.h9
6 files changed, 139 insertions, 146 deletions
diff --git a/src/library/analysisfeature.cpp b/src/library/analysisfeature.cpp
index a56279a2ef..bf51122c73 100644
--- a/src/library/analysisfeature.cpp
+++ b/src/library/analysisfeature.cpp
@@ -13,23 +13,36 @@
#include "library/dlganalysis.h"
#include "widget/wlibrary.h"
#include "controllers/keyboard/keyboardeventfilter.h"
-#include "analyzer/analyzerqueue.h"
#include "sources/soundsourceproxy.h"
#include "util/dnd.h"
#include "util/debug.h"
const QString AnalysisFeature::m_sAnalysisViewName = QString("Analysis");
-AnalysisFeature::AnalysisFeature(Library* parent,
- UserSettingsPointer pConfig,
- TrackCollection* pTrackCollection) :
- LibraryFeature(parent),
+namespace {
+
+// Utilize all available cores for batch analysis of tracks
+const int kNumberOfAnalyzerThreads = math_max(1, QThread::idealThreadCount());
+
+inline
+AnalyzerMode getAnalyzerMode(
+ const UserSettingsPointer& pConfig) {
+ if (pConfig->getValue<bool>(ConfigKey("[Library]", "EnableWaveformGenerationWithAnalysis"), true)) {
+ return AnalyzerMode::WithBeats;
+ } else {
+ return AnalyzerMode::WithBeatsWithoutWaveform;
+ }
+}
+
+} // anonymous namespace
+
+AnalysisFeature::AnalysisFeature(
+ Library* parent,
+ UserSettingsPointer pConfig)
+ : LibraryFeature(parent),
+ m_library(parent),
m_pConfig(pConfig),
- m_pLibrary(parent),
- m_pDbConnectionPool(parent->dbConnectionPool()),
- m_pTrackCollection(pTrackCollection),
- m_pAnalyzerQueue(nullptr),
- m_iOldBpmEnabled(0),
+ m_pTrackAnalysisScheduler(TrackAnalysisScheduler::nullPointer()),
m_analysisTitleName(tr("Analyze")),
m_pAnalysisView(nullptr) {
setTitleDefault();
@@ -38,20 +51,18 @@ AnalysisFeature::AnalysisFeature(Library* parent,
AnalysisFeature::~AnalysisFeature() {
// TODO(XXX) delete these
//delete m_pLibraryTableModel;
- cleanupAnalyzer();
}
-
void AnalysisFeature::setTitleDefault() {
m_Title = m_analysisTitleName;
emit(featureIsLoading(this, false));
}
-void AnalysisFeature::setTitleProgress(int trackNum, int totalNum) {
+void AnalysisFeature::setTitleProgress(int currentTrackNumber, int totalTracksCount) {
m_Title = QString("%1 (%2 / %3)")
.arg(m_analysisTitleName)
- .arg(QString::number(trackNum))
- .arg(QString::number(totalNum));
+ .arg(QString::number(currentTrackNumber))
+ .arg(QString::number(totalTracksCount));
emit(featureIsLoading(this, false));
}
@@ -67,8 +78,7 @@ void AnalysisFeature::bindWidget(WLibrary* libraryWidget,
KeyboardEventFilter* keyboard) {
m_pAnalysisView = new DlgAnalysis(libraryWidget,
m_pConfig,
- m_pLibrary,
- m_pTrackCollection);
+ m_library);
connect(m_pAnalysisView, SIGNAL(loadTrack(TrackPointer)),
this, SIGNAL(loadTrack(TrackPointer)));
connect(m_pAnalysisView, SIGNAL(loadTrackToPlayer(TrackPointer, QString)),
@@ -82,15 +92,12 @@ void AnalysisFeature::bindWidget(WLibrary* libraryWidget,
this, SIGNAL(trackSelected(TrackPointer)));
connect(this, SIGNAL(analysisActive(bool)),
- m_pAnalysisView, SLOT(analysisActive(bool)));
- connect(this, SIGNAL(trackAnalysisStarted(int)),
- m_pAnalysisView, SLOT(trackAnalysisStarted(int)));
+ m_pAnalysisView, SLOT(slotAnalysisActive(bool)));
m_pAnalysisView->installEventFilter(keyboard);
// Let the DlgAnalysis know whether or not analysis is active.
- bool bAnalysisActive = m_pAnalyzerQueue != NULL;
- emit(analysisActive(bAnalysisActive));
+ emit(analysisActive(static_cast<bool>(m_pTrackAnalysisScheduler)));
libraryWidget->registerView(m_sAnalysisViewName, m_pAnalysisView);
}
@@ -114,88 +121,80 @@ void AnalysisFeature::activate() {
emit(enableCoverArtDisplay(true));
}
-namespace {
- inline
- AnalyzerQueue::Mode getAnalyzerQueueMode(
- const UserSettingsPointer& pConfig) {
- if (pConfig->getValue<bool>(ConfigKey("[Library]", "EnableWaveformGenerationWithAnalysis"), true)) {
- return AnalyzerQueue::Mode::Default;
- } else {
- return AnalyzerQueue::Mode::WithoutWaveform;
- }
- }
-} // anonymous namespace
-
void AnalysisFeature::analyzeTracks(QList<TrackId> trackIds) {
- if (m_pAnalyzerQueue == NULL) {
- // Save the old BPM detection prefs setting (on or off)
- m_iOldBpmEnabled = m_pConfig->getValueString(ConfigKey("[BPM]","BPMDetectionEnabled")).toInt();
- // Force BPM detection to be on.
- m_pConfig->set(ConfigKey("[BPM]","BPMDetectionEnabled"), ConfigValue(1));
- // Note: this sucks... we should refactor the prefs/analyzer to fix this hacky bit ^^^^.
-
- m_pAnalyzerQueue = new AnalyzerQueue(
- m_pDbConnectionPool,
+ if (!m_pTrackAnalysisScheduler) {
+ m_pTrackAnalysisScheduler = TrackAnalysisScheduler::createInstance(
+ m_library,
+ kNumberOfAnalyzerThreads,
m_pConfig,
- getAnalyzerQueueMode(m_pConfig));
+ getAnalyzerMode(m_pConfig));
- connect(m_pAnalyzerQueue, SIGNAL(trackProgress(int)),
- m_pAnalysisView, SLOT(trackAnalysisProgress(int)));
- connect(m_pAnalyzerQueue, SIGNAL(trackFinished(int)),
- this, SLOT(slotProgressUpdate(int)));
- connect(m_pAnalyzerQueue, SIGNAL(trackFinished(int)),
- m_pAnalysisView, SLOT(trackAnalysisFinished(int)));
+ connect(m_pTrackAnalysisScheduler.get(), SIGNAL(progress(AnalyzerProgress, int, int)),
+ m_pAnalysisView, SLOT(onTrackAnalysisSchedulerProgress(AnalyzerProgress, int, int)));
+ connect(m_pTrackAnalysisScheduler.get(), SIGNAL(progress(AnalyzerProgress, int, int)),
+ this, SLOT(onTrackAnalysisSchedulerProgress(AnalyzerProgress, int, int)));
+ connect(m_pTrackAnalysisScheduler.get(), SIGNAL(finished()),
+ this, SLOT(stopAnalysis()));
- connect(m_pAnalyzerQueue, SIGNAL(queueEmpty()),
- this, SLOT(cleanupAnalyzer()));
emit(analysisActive(true));
}
for (const auto& trackId: trackIds) {
- TrackPointer pTrack = m_pTrackCollection->getTrackDAO().getTrack(trackId);
- if (pTrack) {
- //qDebug() << this << "Queueing track for analysis" << pTrack->getLocation();
- m_pAnalyzerQueue->queueAnalyseTrack(pTrack);
+ if (trackId.isValid()) {
+ m_pTrackAnalysisScheduler->scheduleTrackById(trackId);
}
}
- if (trackIds.size() > 0) {
- setTitleProgress(0, trackIds.size());
+ m_pTrackAnalysisScheduler->resume();
+}
+
+void AnalysisFeature::onTrackAnalysisSchedulerProgress(
+ AnalyzerProgress /*currentTrackProgress*/,
+ int currentTrackNumber,
+ int totalTracksCount) {
+ // Ignore any delayed progress updates after the analysis
+ // has already been stopped.
+ if (m_pTrackAnalysisScheduler) {
+ if (totalTracksCount > 0) {
+ setTitleProgress(currentTrackNumber, totalTracksCount);
+ } else {
+ setTitleDefault();
+ }
}
- emit(trackAnalysisStarted(trackIds.size()));
}
-void AnalysisFeature::slotProgressUpdate(int num_left) {
- int num_tracks = m_pAnalysisView->getNumTracks();
- if (num_left > 0) {
- int currentTrack = num_tracks - num_left + 1;
- setTitleProgress(currentTrack, num_tracks);
+void AnalysisFeature::suspendAnalysis() {
+ //qDebug() << this << "suspendAnalysis";
+ if (m_pTrackAnalysisScheduler) {
+ m_pTrackAnalysisScheduler->suspend();
}
}
-void AnalysisFeature::stopAnalysis() {
- //qDebug() << this << "stopAnalysis()";
- if (m_pAnalyzerQueue != NULL) {
- m_pAnalyzerQueue->stop();
+void AnalysisFeature::resumeAnalysis() {
+ //qDebug() << this << "resumeAnalysis";
+ if (m_pTrackAnalysisScheduler) {
+ m_pTrackAnalysisScheduler->resume();
}
}
-void AnalysisFeature::cleanupAnalyzer() {
+void AnalysisFeature::stopAnalysis() {
+ //qDebug() << this << "stopAnalysis()";
+ if (m_pTrackAnalysisScheduler) {
+ // Free resources by abandoning the queue after the batch analysis
+ // has completed. Batch analysis are not started very frequently
+ // during a session and should be avoided while performing live.
+ // If the user decides to start a new batch analysis the setup costs
+ // for creating the queue with its worker threads are acceptable.
+ m_pTrackAnalysisScheduler.reset();
+ }
setTitleDefault();
emit(analysisActive(false));
- if (m_pAnalyzerQueue != NULL) {
- m_pAnalyzerQueue->stop();
- m_pAnalyzerQueue->deleteLater();
- m_pAnalyzerQueue = NULL;
- // Restore old BPM detection setting for preferences...
- m_pConfig->set(ConfigKey("[BPM]","BPMDetectionEnabled"), ConfigValue(m_iOldBpmEnabled));
- }
}
bool AnalysisFeature::dropAccept(QList<QUrl> urls, QObject* pSource) {
Q_UNUSED(pSource);
QList<QFileInfo> files = DragAndDropHelper::supportedTracksFromUrls(urls, false, true);
// Adds track, does not insert duplicates, handles unremoving logic.
- QList<TrackId> trackIds = m_pTrackCollection->getTrackDAO().addMultipleTracks(files, true);
+ QList<TrackId> trackIds = m_library->trackCollection().getTrackDAO().addMultipleTracks(files, true);
analyzeTracks(trackIds);
return trackIds.size() > 0;
}
diff --git a/src/library/analysisfeature.h b/src/library/analysisfeature.h
index 74d6480b8c..4af45da37e 100644
--- a/src/library/analysisfeature.h
+++ b/src/library/analysisfeature.h
@@ -15,19 +15,17 @@
#include "library/libraryfeature.h"
#include "library/dlganalysis.h"
#include "library/treeitemmodel.h"
+#include "analyzer/trackanalysisscheduler.h"
#include "preferences/usersettings.h"
-#include "util/db/dbconnectionpool.h"
class Library;
class TrackCollection;
-class AnalyzerQueue;
class AnalysisFeature : public LibraryFeature {
Q_OBJECT
public:
AnalysisFeature(Library* parent,
- UserSettingsPointer pConfig,
- TrackCollection* pTrackCollection);
+ UserSettingsPointer pConfig);
virtual ~AnalysisFeature();
QVariant title();
@@ -43,16 +41,17 @@ class AnalysisFeature : public LibraryFeature {
signals:
void analysisActive(bool bActive);
- void trackAnalysisStarted(int size);
public slots:
void activate();
void analyzeTracks(QList<TrackId> trackIds);
+ void suspendAnalysis();
+ void resumeAnalysis();
+
private slots:
- void slotProgressUpdate(int num_left);
+ void onTrackAnalysisSchedulerProgress(AnalyzerProgress currentTrackProgress, int currentTrackNumber, int totalTracksCount);
void stopAnalysis();
- void cleanupAnalyzer();
private:
// Sets the title of this feature to the default name, given by
@@ -62,15 +61,13 @@ class AnalysisFeature : public LibraryFeature {
// Sets the title of this feature to the default name followed by (x / y)
// where x is the current track being analyzed and y is the total number of
// tracks in the job
- void setTitleProgress(int trackNum, int totalNum);
+ void setTitleProgress(int currentTrackNumber, int totalTracksCount);
+
+ Library* m_library;
UserSettingsPointer m_pConfig;
- Library* m_pLibrary;
- mixxx::DbConnectionPoolPtr m_pDbConnectionPool;
- TrackCollection* m_pTrackCollection;
- AnalyzerQueue* m_pAnalyzerQueue;
- // Used to temporarily enable BPM detection in the prefs before we analyse
- int m_iOldBpmEnabled;
+ TrackAnalysisScheduler::Pointer m_pTrackAnalysisScheduler;
+
// The title returned by title()
QVariant m_Title;
TreeItemModel m_childModel;
diff --git a/src/library/dlganalysis.cpp b/src/library/dlganalysis.cpp
index 8279c0c286..7f85e59c84 100644
--- a/src/library/dlganalysis.cpp
+++ b/src/library/dlganalysis.cpp
@@ -3,27 +3,25 @@
#include "widget/wwidget.h"
#include "widget/wskincolor.h"
#include "widget/wanalysislibrarytableview.h"
+#include "analyzer/analyzerprogress.h"
#include "library/dao/trackschema.h"
#include "library/trackcollection.h"
#include "library/dlganalysis.h"
#include "library/library.h"
#include "util/assert.h"
-DlgAnalysis::DlgAnalysis(QWidget* pParent,
+DlgAnalysis::DlgAnalysis(QWidget* parent,
UserSettingsPointer pConfig,
- Library* pLibrary,
- TrackCollection* pTrackCollection)
- : QWidget(pParent),
+ Library* pLibrary)
+ : QWidget(parent),
m_pConfig(pConfig),
- m_pTrackCollection(pTrackCollection),
- m_bAnalysisActive(false),
- m_tracksInQueue(0),
- m_currentTrack(0) {
+ m_pTrackCollection(&pLibrary->trackCollection()),
+ m_bAnalysisActive(false) {
setupUi(this);
m_songsButtonGroup.addButton(radioButtonRecentlyAdded);
m_songsButtonGroup.addButton(radioButtonAllSongs);
- m_pAnalysisLibraryTableView = new WAnalysisLibraryTableView(this, pConfig, pTrackCollection);
+ m_pAnalysisLibraryTableView = new WAnalysisLibraryTableView(this, pConfig, m_pTrackCollection);
connect(m_pAnalysisLibraryTableView, SIGNAL(loadTrack(TrackPointer)),
this, SIGNAL(loadTrack(TrackPointer)));
connect(m_pAnalysisLibraryTableView, SIGNAL(loadTrackToPlayer(TrackPointer, QString)),
@@ -40,7 +38,7 @@ DlgAnalysis::DlgAnalysis(QWidget* pParent,
box->insertWidget(1, m_pAnalysisLibraryTableView);
}
- m_pAnalysisLibraryTableModel = new AnalysisLibraryTableModel(this, pTrackCollection);
+ m_pAnalysisLibraryTableModel = new AnalysisLibraryTableModel(this, m_pTrackCollection);
m_pAnalysisLibraryTableView->loadTrackModel(m_pAnalysisLibraryTableModel);
connect(radioButtonRecentlyAdded, SIGNAL(clicked()),
@@ -52,8 +50,6 @@ DlgAnalysis::DlgAnalysis(QWidget* pParent,
// started up. Accounts for 0.2% of skin creation time. Get rid of this!
radioButtonRecentlyAdded->click();
- labelProgress->setText("");
- pushButtonAnalyze->setEnabled(false);
connect(pushButtonAnalyze, SIGNAL(clicked()),
this, SLOT(analyze()));
@@ -71,9 +67,8 @@ DlgAnalysis::DlgAnalysis(QWidget* pParent,
m_pAnalysisLibraryTableView, SLOT(setTrackTableRowHeight(int)));
connect(pLibrary, SIGNAL(setSelectedClick(bool)),
m_pAnalysisLibraryTableView, SLOT(setSelectedClick(bool)));
-}
-DlgAnalysis::~DlgAnalysis() {
+ slotAnalysisActive(m_bAnalysisActive);
}
void DlgAnalysis::onShow() {
@@ -143,13 +138,12 @@ void DlgAnalysis::analyze() {
trackIds.append(trackId);
}
}
- m_currentTrack = 1;
emit(analyzeTracks(trackIds));
}
}
-void DlgAnalysis::analysisActive(bool bActive) {
- qDebug() << this << "analysisActive" << bActive;
+void DlgAnalysis::slotAnalysisActive(bool bActive) {
+ //qDebug() << this << "slotAnalysisActive" << bActive;
m_bAnalysisActive = bActive;
if (bActive) {
pushButtonAnalyze->setEnabled(true);
@@ -162,33 +156,28 @@ void DlgAnalysis::analysisActive(bool bActive) {
}
}
-// slot
-void DlgAnalysis::trackAnalysisFinished(int size) {
- qDebug() << "Analysis finished" << size << "tracks left";
- if (size > 0) {
- m_currentTrack = m_tracksInQueue - size + 1;
- }
-}
-
-// slot
-void DlgAnalysis::trackAnalysisProgress(int progress) {
- if (m_bAnalysisActive) {
- QString text = tr("Analyzing %1/%2 %3%").arg(
- QString::number(m_currentTrack),
- QString::number(m_tracksInQueue),
- QString::number(progress));
- labelProgress->setText(text);
+void DlgAnalysis::onTrackAnalysisSchedulerProgress(
+ AnalyzerProgress analyzerProgress, int finishedCount, int totalCount) {
+ //qDebug() << this << "onTrackAnalysisSchedulerProgress" << analyzerProgress << finishedCount << totalCount;
+ if (labelProgress->isEnabled()) {
+ QString progressText;
+ if (analyzerProgress >= kAnalyzerProgressNone) {
+ QString progressPercent = QString::number(
+ analyzerProgressPercent(analyzerProgress));
+ progressText = tr("Analyzing %1% %2/%3").arg(
+ progressPercent,
+ QString::number(finishedCount),
+ QString::number(totalCount));
+ } else {
+ // Omit to display any percentage
+ progressText = tr("Analyzing %1/%2").arg(
+ QString::number(finishedCount),
+ QString::number(totalCount));
+ }
+ labelProgress->setText(progressText);
}
}
-int DlgAnalysis::getNumTracks() {
- return m_tracksInQueue;
-}
-
-void DlgAnalysis::trackAnalysisStarted(int size) {
- m_tracksInQueue = size;
-}
-
void DlgAnalysis::showRecentSongs() {
m_pAnalysisLibraryTableModel->showRecentSongs();
}
diff --git a/src/library/dlganalysis.h b/src/library/dlganalysis.h
index f1adea8140..d0241368a3 100644
--- a/src/library/dlganalysis.h
+++ b/src/library/dlganalysis.h
@@ -9,6 +9,7 @@
#include "library/libraryview.h"
#include "library/trackcollection.h"
#include "library/ui_dlganalysis.h"
+#include "analyzer/analyzerprogress.h"
class AnalysisLibraryTableModel;
class WAnalysisLibraryTableView;
@@ -19,9 +20,8 @@ class DlgAnalysis : public QWidget, public Ui::DlgAnalysis, public virtual Libra
public:
DlgAnalysis(QWidget *parent,
UserSettingsPointer pConfig,
- Library* pLibrary,
- TrackCollection* pTrackCollection);
- ~DlgAnalysis() override;
+ Library* pLibrary);
+ ~DlgAnalysis() override = default;
void onSearch(const QString& text) override;
void onShow() override;
@@ -35,20 +35,17 @@ class DlgAnalysis : public QWidget, public Ui::DlgAnalysis, public virtual Libra
inline const QString currentSearch() {
return m_pAnalysisLibraryTableModel->currentSearch();
}
- int getNumTracks();
public slots:
void tableSelectionChanged(const QItemSelection& selected,
const QItemSelection& deselected);
void selectAll();
void analyze();
- void trackAnalysisFinished(int size);
- void trackAnalysisProgress(int progress);
- void trackAnalysisStarted(int size);
+ void slotAnalysisActive(bool bActive);
+ void onTrackAnalysisSchedulerProgress(AnalyzerProgress analyzerProgress, int finishedCount, int totalCount);
void showRecentSongs();
void showAllSongs();
void installEventFilter(QObject* pFilter);
- void analysisActive(bool bActive);
signals:
void loadTrack(TrackPointer pTrack);
@@ -65,8 +62,6 @@ class DlgAnalysis : public QWidget, public Ui::DlgAnalysis, public virtual Libra
QButtonGroup m_songsButtonGroup;
WAnalysisLibraryTableView* m_pAnalysisLibraryTableView;
AnalysisLibraryTableModel* m_pAnalysisLibraryTableModel;
- int m_tracksInQueue;
- int m_currentTrack;
};
#endif //DLGTRIAGE_H
diff --git a/src/library/library.cpp b/src/library/library.cpp
index c47f813b3c..0892d5aed1 100644
--- a/src/library/library.cpp
+++ b/src/library/library.cpp
@@ -63,7 +63,7 @@ Library::Library(
QObject* parent,
UserSettingsPointer pConfig,
mixxx::DbConnectionPoolPtr pDbConnectionPool,
- PlayerManagerInterface* pPlayerManager,
+ PlayerManager* pPlayerManager,
RecordingManager* pRecordingManager)
: m_pConfig(pConfig),
m_pDbConnectionPool(pDbConnectionPool),
@@ -124,12 +124,20 @@ Library::Library(
addFeature(browseFeature);
addFeature(new RecordingFeature(this, pConfig, m_pTrackCollection, pRecordingManager));
addFeature(new SetlogFeature(this, pConfig, m_pTrackCollection));
- m_pAnalysisFeature = new AnalysisFeature(this, pConfig, m_pTrackCollection);
+
+ m_pAnalysisFeature = new AnalysisFeature(this, pConfig);
connect(m_pPlaylistFeature, SIGNAL(analyzeTracks(QList<TrackId>)),
m_pAnalysisFeature, SLOT(analyzeTracks(QList<TrackId>)));
connect(m_pCrateFeature, SIGNAL(analyzeTracks(QList<TrackId>)),
m_pAnalysisFeature, SLOT(analyzeTracks(QList<TrackId>)));
addFeature(m_pAnalysisFeature);
+ // Suspend a batch analysis while an ad-hoc analysis of
+ // loaded tracks is in progress and resume it afterwards.
+ connect(pPlayerManager, SIGNAL(trackAnalyzerProgress(TrackId, AnalyzerProgress)),
+ m_pAnalysisFeature, SLOT(suspendAnalysis()));
+ connect(pPlayerManager, SIGNAL(trackAnalyzerIdle()),
+ m_pAnalysisFeature, SLOT(resumeAnalysis()));
+
//iTunes and Rhythmbox should be last until we no longer have an obnoxious
//messagebox popup when you select them. (This forces you to reach for your
//mouse or keyboard if you're using MIDI control and you scroll through them...)
diff --git a/src/library/library.h b/src/library/library.h
index e8e2a01d61..09e1e7e9da 100644
--- a/src/library/library.h
+++ b/src/library/library.h
@@ -34,7 +34,7 @@ class PlaylistFeature;
class CrateFeature;
class LibraryControl;
class KeyboardEventFilter;
-class PlayerManagerInterface;
+class PlayerManager;
class Library: public QObject,
public virtual /*implements*/ GlobalTrackCacheSaver {
@@ -48,7 +48,7 @@ class Library: public QObject,
Library(QObject* parent,
UserSettingsPointer pConfig,
mixxx::DbConnectionPoolPtr pDbConnectionPool,
- PlayerManagerInterface* pPlayerManager,
+ PlayerManager* pPlayerManager,
RecordingManager* pRecordingManager);
~Library() override;
@@ -56,6 +56,11 @@ class Library: public QObject,
return m_pDbConnectionPool;
}
+ TrackCollection& trackCollection() {
+ DEBUG_ASSERT(m_pTrackCollection);
+ return *m_pTrackCollection;
+ }
+
void bindWidget(WLibrary* libraryWidget,
KeyboardEventFilter* pKeyboard);
void bindSidebarWidget(WLibrarySidebar* sidebarWidget);