Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

WIP: Overviews in library #13644

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -988,6 +988,7 @@ add_library(mixxx-lib STATIC EXCLUDE_FROM_ALL
src/library/tabledelegates/keydelegate.cpp
src/library/tabledelegates/locationdelegate.cpp
src/library/tabledelegates/multilineeditdelegate.cpp
src/library/tabledelegates/overviewdelegate.cpp
src/library/tabledelegates/previewbuttondelegate.cpp
src/library/tabledelegates/stardelegate.cpp
src/library/tabledelegates/stareditor.cpp
Expand Down Expand Up @@ -1209,6 +1210,9 @@ add_library(mixxx-lib STATIC EXCLUDE_FROM_ALL
src/util/workerthreadscheduler.cpp
src/util/xml.cpp
src/waveform/guitick.cpp
src/waveform/overviews/overviewcache.cpp
src/waveform/overviews/overviewrenderthread.cpp
src/waveform/overviews/overviewtype.cpp
src/waveform/renderers/glwaveformrenderbackground.cpp
src/waveform/renderers/glvsynctestrenderer.cpp
src/waveform/renderers/waveformmark.cpp
Expand Down
9 changes: 9 additions & 0 deletions res/skins/LateNight/library.xml
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,15 @@
<Library>
<ShowButtonText>false</ShowButtonText>
<TrackTableBackgroundColorOpacity>0.175</TrackTableBackgroundColorOpacity>
<!-- Waveform signal colors used for Overviews in library -->
<SignalColor>#fedcba</SignalColor>
<!-- Default colors are used for high/mid/low: blue/green/red -->
<SignalHighColor></SignalHighColor>
<SignalMidColor></SignalMidColor>
<SignalLowColor></SignalLowColor>
<SignalRGBHighColor></SignalRGBHighColor>
<SignalRGBMidColor></SignalRGBMidColor>
<SignalRGBLowColor></SignalRGBLowColor>
</Library>

</Children>
Expand Down
2 changes: 2 additions & 0 deletions src/coreservices.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@
#include "util/translations.h"
#include "util/versionstore.h"
#include "vinylcontrol/vinylcontrolmanager.h"
#include "waveform/overviews/overviewcache.h"

#ifdef __APPLE__
#include "util/sandbox.h"
Expand Down Expand Up @@ -358,6 +359,7 @@ void CoreServices::initialize(QApplication* pApp) {
emit initializationProgressUpdate(50, tr("library"));
CoverArtCache::createInstance();
Clipboard::createInstance();
OverviewCache::createInstance(pConfig, m_pDbConnectionPool, m_pPlayerManager);

m_pTrackCollectionManager = std::make_shared<TrackCollectionManager>(
this,
Expand Down
46 changes: 46 additions & 0 deletions src/library/basetracktablemodel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
#include "library/tabledelegates/keydelegate.h"
#include "library/tabledelegates/locationdelegate.h"
#include "library/tabledelegates/multilineeditdelegate.h"
#include "library/tabledelegates/overviewdelegate.h"
#include "library/tabledelegates/previewbuttondelegate.h"
#include "library/tabledelegates/stardelegate.h"
#include "library/trackcollection.h"
Expand Down Expand Up @@ -69,6 +70,7 @@ const QStringList kDefaultTableColumns = {
LIBRARYTABLE_TITLE,
LIBRARYTABLE_TRACKNUMBER,
LIBRARYTABLE_YEAR,
LIBRARYTABLE_WAVESUMMARYHEX,
};

inline QSqlDatabase cloneDatabase(
Expand Down Expand Up @@ -254,6 +256,9 @@ void BaseTrackTableModel::initHeaderProperties() {
ColumnCache::COLUMN_TRACKLOCATIONSTABLE_LOCATION,
tr("Location"),
defaultColumnWidth() * 6);
setHeaderProperties(ColumnCache::COLUMN_LIBRARYTABLE_WAVESUMMARYHEX,
tr("Overview"),
defaultColumnWidth());
setHeaderProperties(
ColumnCache::COLUMN_LIBRARYTABLE_PREVIEW,
tr("Preview"),
Expand Down Expand Up @@ -526,6 +531,23 @@ QAbstractItemDelegate* BaseTrackTableModel::delegateForColumn(
return pCoverArtDelegate;
} else if (index == fieldIndex(ColumnCache::COLUMN_LIBRARYTABLE_KEY)) {
return new KeyDelegate(pTableView);
} else if (index == fieldIndex(ColumnCache::COLUMN_LIBRARYTABLE_WAVESUMMARYHEX)) {
auto* pOverviewDelegate = new OverviewDelegate(pTableView);
// WLibraryTableView -> OverviewDelegate
connect(pTableView,
&WLibraryTableView::onlyCachedCoverArt,
pOverviewDelegate,
&OverviewDelegate::slotInhibitLazyLoading);
// OverviewDelegate -> BaseTrackTableModel
connect(pOverviewDelegate,
&OverviewDelegate::rowsChanged,
this,
&BaseTrackTableModel::slotRefreshOverviewRows);
connect(pOverviewDelegate,
&OverviewDelegate::overviewChanged,
this,
&BaseTrackTableModel::slotRefreshOverview);
return pOverviewDelegate;
}
return nullptr;
}
Expand Down Expand Up @@ -1201,6 +1223,30 @@ void BaseTrackTableModel::slotRefreshCoverRows(
emitDataChangedForMultipleRowsInColumn(rows, column);
}

void BaseTrackTableModel::slotRefreshOverviewRows(const QList<int>& rows) {
if (rows.isEmpty()) {
return;
}
const int column = fieldIndex(LIBRARYTABLE_WAVESUMMARYHEX);
VERIFY_OR_DEBUG_ASSERT(column >= 0) {
return;
}
emitDataChangedForMultipleRowsInColumn(rows, column);
}

void BaseTrackTableModel::slotRefreshOverview(const TrackId trackId) {
const int column = fieldIndex(LIBRARYTABLE_WAVESUMMARYHEX);
VERIFY_OR_DEBUG_ASSERT(column >= 0) {
return;
}

const auto rows = getTrackRows(trackId);
for (int row : rows) {
QModelIndex idx = index(row, column);
emit dataChanged(idx, idx);
}
}

void BaseTrackTableModel::slotRefreshAllRows() {
select();
}
Expand Down
4 changes: 4 additions & 0 deletions src/library/basetracktablemodel.h
Original file line number Diff line number Diff line change
Expand Up @@ -249,6 +249,10 @@ class BaseTrackTableModel : public QAbstractTableModel, public TrackModel {
void slotRefreshCoverRows(
const QList<int>& rows);

void slotRefreshOverviewRows(const QList<int>& rows);

void slotRefreshOverview(const TrackId trackId);

void slotRefreshAllRows();

void slotCoverFound(
Expand Down
5 changes: 4 additions & 1 deletion src/library/coverartcache.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
#include "track/track.h"
#include "util/logger.h"
#include "util/thread_affinity.h"
#include "util/timer.h"

namespace {

Expand Down Expand Up @@ -188,6 +189,8 @@ CoverArtCache::FutureResult CoverArtCache::loadCover(
TrackPointer pTrack,
CoverInfo coverInfo,
int desiredWidth) {
ScopedTimer t(QStringLiteral("CoverArtCache::loadCover"));

if (kLogger.traceEnabled()) {
kLogger.trace()
<< "loadCover"
Expand Down Expand Up @@ -245,7 +248,7 @@ void CoverArtCache::coverLoaded() {
}

if (kLogger.traceEnabled()) {
kLogger.trace() << "coverLoaded" << res.coverArt;
kLogger.info() << "coverLoaded" << res.coverArt;
}

QString cacheKey = pixmapCacheKey(
Expand Down
1 change: 1 addition & 0 deletions src/library/dao/trackschema.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ const QString LIBRARYTABLE_COVERART_COLOR = QStringLiteral("coverart_color");
const QString LIBRARYTABLE_COVERART_DIGEST = QStringLiteral("coverart_digest");
const QString LIBRARYTABLE_COVERART_HASH = QStringLiteral("coverart_hash");
const QString LIBRARYTABLE_CRATE = QStringLiteral("crate");
const QString LIBRARYTABLE_OVERVIEW = QStringLiteral("overview");

const QString TRACKLOCATIONSTABLE_ID = QStringLiteral("id");
const QString TRACKLOCATIONSTABLE_LOCATION = QStringLiteral("location");
Expand Down
2 changes: 1 addition & 1 deletion src/library/librarytablemodel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ bool LibraryTableModel::isColumnInternal(int column) {
return column == fieldIndex(ColumnCache::COLUMN_LIBRARYTABLE_ID) ||
column == fieldIndex(ColumnCache::COLUMN_LIBRARYTABLE_URL) ||
column == fieldIndex(ColumnCache::COLUMN_LIBRARYTABLE_CUEPOINT) ||
column == fieldIndex(ColumnCache::COLUMN_LIBRARYTABLE_WAVESUMMARYHEX) ||
// column == fieldIndex(ColumnCache::COLUMN_LIBRARYTABLE_WAVESUMMARYHEX) ||
column == fieldIndex(ColumnCache::COLUMN_LIBRARYTABLE_SAMPLERATE) ||
column == fieldIndex(ColumnCache::COLUMN_LIBRARYTABLE_MIXXXDELETED) ||
column == fieldIndex(ColumnCache::COLUMN_LIBRARYTABLE_HEADERPARSED) ||
Expand Down
4 changes: 2 additions & 2 deletions src/library/mixxxlibraryfeature.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@
#include "widget/wlibrarysidebar.h"
#endif


MixxxLibraryFeature::MixxxLibraryFeature(Library* pLibrary,
UserSettingsPointer pConfig)
: LibraryFeature(pLibrary, pConfig, QStringLiteral("tracks")),
Expand Down Expand Up @@ -70,7 +69,8 @@ MixxxLibraryFeature::MixxxLibraryFeature(Library* pLibrary,
LIBRARYTABLE_COVERART_LOCATION,
LIBRARYTABLE_COVERART_COLOR,
LIBRARYTABLE_COVERART_DIGEST,
LIBRARYTABLE_COVERART_HASH};
LIBRARYTABLE_COVERART_HASH,
LIBRARYTABLE_WAVESUMMARYHEX};
QStringList searchColumns = {
LIBRARYTABLE_ARTIST,
LIBRARYTABLE_ALBUM,
Expand Down
3 changes: 3 additions & 0 deletions src/library/tabledelegates/coverartdelegate.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
#include "track/track.h"
#include "util/logger.h"
#include "util/make_const_iterator.h"
#include "util/timer.h"

namespace {

Expand Down Expand Up @@ -108,6 +109,8 @@ void CoverArtDelegate::paintItem(
QPainter* painter,
const QStyleOptionViewItem& option,
const QModelIndex& index) const {
ScopedTimer t(QStringLiteral("CoverArtDelegate::paintItem"));

paintItemBackground(painter, option, index);

CoverInfo coverInfo = m_pTrackModel->getCoverInfo(index);
Expand Down
142 changes: 142 additions & 0 deletions src/library/tabledelegates/overviewdelegate.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
#include "library/tabledelegates/overviewdelegate.h"

#include "library/dao/trackdao.h"
#include "library/trackmodel.h"
#include "moc_overviewdelegate.cpp"
#include "util/logger.h"
#include "util/make_const_iterator.h"
#include "util/timer.h"
#include "waveform/overviews/overviewcache.h"
#include "widget/wlibrary.h"

namespace {

const mixxx::Logger kLogger("OverviewDelegate");

inline TrackModel* asTrackModel(
QTableView* pTableView) {
auto* pTrackModel =
dynamic_cast<TrackModel*>(pTableView->model());
DEBUG_ASSERT(pTrackModel);
return pTrackModel;
}

inline WLibrary* findLibraryWidgetParent(QWidget* pWidget) {
while (pWidget) {
WLibrary* pLibrary = qobject_cast<WLibrary*>(pWidget);
if (pLibrary) {
return pLibrary;
}

pWidget = pWidget->parentWidget();
}

return nullptr;
}

} // anonymous namespace

OverviewDelegate::OverviewDelegate(QTableView* parent)
: TableItemDelegate(parent),
m_pTrackModel(asTrackModel(parent)),
m_pCache(OverviewCache::instance()),
m_inhibitLazyLoading(false) {
WLibrary* pLibrary = findLibraryWidgetParent(parent);
if (pLibrary) {
m_signalColors = pLibrary->getOverviewSignalColors();
}

if (m_pCache) {
connect(m_pCache,
&OverviewCache::overviewReady,
this,
&OverviewDelegate::slotOverviewReady);

connect(m_pCache,
&OverviewCache::overviewChanged,
this,
&OverviewDelegate::slotOverviewChanged);
} else {
kLogger.warning() << "Caching of overviews is not available";
}
}

void OverviewDelegate::emitRowsChanged(QList<int>&& rows) {
if (rows.isEmpty()) {
return;
}
// Sort in ascending order...
std::sort(rows.begin(), rows.end());
// ...and then deduplicate...
constErase(
&rows,
make_const_iterator(
rows, std::unique(rows.begin(), rows.end())),
rows.constEnd());
// ...before emitting the signal.
DEBUG_ASSERT(!rows.isEmpty());
emit rowsChanged(std::move(rows));
}

void OverviewDelegate::slotInhibitLazyLoading(bool inhibitLazyLoading) {
m_inhibitLazyLoading = inhibitLazyLoading;
if (m_inhibitLazyLoading || m_cacheMissRows.isEmpty()) {
return;
}
// If we can request non-cache covers now, request updates
// for all rows that were cache misses since the last time.
// Reset the member variable before mutating the aggregated
// rows list (-> implicit sharing) and emitting a signal that
// in turn may trigger new signals for CoverArtDelegate!
QList<int> staleRows = std::move(m_cacheMissRows);
DEBUG_ASSERT(m_cacheMissRows.isEmpty());
emitRowsChanged(std::move(staleRows));
}

void OverviewDelegate::slotOverviewReady(const QObject* pRequester, TrackId trackId) {
kLogger.info() << "slotOverviewReady()" << this << pRequester << trackId;

if (pRequester == this) {
emit overviewChanged(trackId);
}
}

void OverviewDelegate::slotOverviewChanged(TrackId trackId) {
kLogger.info() << "slotOverviewChanged()" << trackId;

emit overviewChanged(trackId);
}

void OverviewDelegate::paintItem(QPainter* painter,
const QStyleOptionViewItem& option,
const QModelIndex& index) const {
ScopedTimer t(QStringLiteral("OverviewDelegate::paintItem"));

paintItemBackground(painter, option, index);

TrackId trackId(m_pTrackModel->getTrackId(index));

const double scaleFactor = qobject_cast<QWidget*>(parent())->devicePixelRatioF();

// QPixmap pixmap = , option.rect.size() * scaleFactor
QImage image = m_pCache->getCachedOverviewImage(trackId, m_signalColors);
if (image.isNull()) {
// Cache miss
if (m_inhibitLazyLoading) {
// We are requesting cache-only covers and got a cache
// miss. Record this row so that when we switch to requesting
// non-cache we can request an update.
m_cacheMissRows.append(index.row());
} else {
m_pCache->requestOverview(trackId,
m_signalColors,
this,
option.rect.size() * scaleFactor);
}
} else {
// Cache hit
// pixmap.setDevicePixelRatio(scaleFactor);
// painter->drawPixmap(option.rect, pixmap);
painter->drawImage(option.rect, image);
}
}
Loading
Loading