diff --git a/src/waveform/renderers/glslwaveformrenderersignal.cpp b/src/waveform/renderers/glslwaveformrenderersignal.cpp index 88cadbde7d7f..0409882afccb 100644 --- a/src/waveform/renderers/glslwaveformrenderersignal.cpp +++ b/src/waveform/renderers/glslwaveformrenderersignal.cpp @@ -219,14 +219,29 @@ void GLSLWaveformRendererSignal::onSetup(const QDomNode& node) { } void GLSLWaveformRendererSignal::onSetTrack() { - m_loadedWaveform = 0; - loadTexture(); + slotWaveformUpdated(); + + TrackPointer pTrack = m_waveformRenderer->getTrackInfo(); + if (!pTrack) { + return; + } + + // When the track's waveform has been changed (or cleared), it is necessary + // to update (or delete) the texture containing the waveform which was + // uploaded to GPU. Otherwise, previous waveform will be shown. + connect(pTrack.get(), SIGNAL(waveformUpdated()), + this, SLOT(slotWaveformUpdated())); } void GLSLWaveformRendererSignal::onResize() { createFrameBuffers(); } +void GLSLWaveformRendererSignal::slotWaveformUpdated() { + m_loadedWaveform = 0; + loadTexture(); +} + void GLSLWaveformRendererSignal::draw(QPainter* painter, QPaintEvent* /*event*/) { if (!m_frameBuffersValid || !m_shadersValid) { return; diff --git a/src/waveform/renderers/glslwaveformrenderersignal.h b/src/waveform/renderers/glslwaveformrenderersignal.h index 11b366995b45..2923b3e9522e 100644 --- a/src/waveform/renderers/glslwaveformrenderersignal.h +++ b/src/waveform/renderers/glslwaveformrenderersignal.h @@ -7,7 +7,8 @@ #include "waveformrenderersignalbase.h" -class GLSLWaveformRendererSignal : public WaveformRendererSignalBase { +class GLSLWaveformRendererSignal : public QObject, public WaveformRendererSignalBase { + Q_OBJECT public: explicit GLSLWaveformRendererSignal( WaveformWidgetRenderer* waveformWidgetRenderer, bool rgbShader); @@ -24,6 +25,9 @@ class GLSLWaveformRendererSignal : public WaveformRendererSignalBase { bool loadShaders(); bool loadTexture(); + public slots: + void slotWaveformUpdated(); + private: void createGeometry(); void createFrameBuffers(); diff --git a/src/widget/woverview.cpp b/src/widget/woverview.cpp index 1bf3e2673e33..aa8528c824e9 100644 --- a/src/widget/woverview.cpp +++ b/src/widget/woverview.cpp @@ -35,7 +35,6 @@ WOverview::WOverview(const char *pGroup, UserSettingsPointer pConfig, QWidget* parent) : WWidget(parent), - m_pWaveformSourceImage(nullptr), m_actualCompletion(0), m_pixmapDone(false), m_waveformPeak(-1.0), @@ -61,12 +60,6 @@ WOverview::WOverview(const char *pGroup, UserSettingsPointer pConfig, QWidget* p setAcceptDrops(true); } -WOverview::~WOverview() { - if (m_pWaveformSourceImage) { - delete m_pWaveformSourceImage; - } -} - void WOverview::setup(const QDomNode& node, const SkinContext& context) { m_signalColors.setup(node, context); @@ -169,12 +162,23 @@ void WOverview::slotWaveformSummaryUpdated() { return; } m_pWaveform = pTrack->getWaveformSummary(); - // If the waveform is already complete, just draw it. - if (m_pWaveform && m_pWaveform->getCompletion() == m_pWaveform->getDataSize()) { - m_actualCompletion = 0; - if (drawNextPixmapPart()) { - update(); + if (m_pWaveform) { + // If the waveform is already complete, just draw it. + if (m_pWaveform->getCompletion() == m_pWaveform->getDataSize()) { + m_actualCompletion = 0; + if (drawNextPixmapPart()) { + update(); + } } + } else { + // Null waveform pointer means waveform was cleared. + m_waveformSourceImage = QImage(); + m_dAnalyzerProgress = 1.0; + m_actualCompletion = 0; + m_waveformPeak = -1.0; + m_pixmapDone = false; + + update(); } } @@ -211,11 +215,7 @@ void WOverview::slotLoadingTrack(TrackPointer pNewTrack, TrackPointer pOldTrack) this, SLOT(slotAnalyzerProgress(int))); } - if (m_pWaveformSourceImage) { - delete m_pWaveformSourceImage; - m_pWaveformSourceImage = nullptr; - } - + m_waveformSourceImage = QImage(); m_dAnalyzerProgress = 1.0; m_actualCompletion = 0; m_waveformPeak = -1.0; @@ -314,7 +314,7 @@ void WOverview::paintEvent(QPaintEvent * /*unused*/) { // Draw waveform pixmap WaveformWidgetFactory* widgetFactory = WaveformWidgetFactory::instance(); - if (m_pWaveformSourceImage) { + if (!m_waveformSourceImage.isNull()) { int diffGain; bool normalize = widgetFactory->isOverviewNormalized(); if (normalize && m_pixmapDone && m_waveformPeak > 1) { @@ -325,9 +325,9 @@ void WOverview::paintEvent(QPaintEvent * /*unused*/) { } if (m_diffGain != diffGain || m_waveformImageScaled.isNull()) { - QRect sourceRect(0, diffGain, m_pWaveformSourceImage->width(), - m_pWaveformSourceImage->height() - 2 * diffGain); - QImage croppedImage = m_pWaveformSourceImage->copy(sourceRect); + QRect sourceRect(0, diffGain, m_waveformSourceImage.width(), + m_waveformSourceImage.height() - 2 * diffGain); + QImage croppedImage = m_waveformSourceImage.copy(sourceRect); if (m_orientation == Qt::Vertical) { // Rotate pixmap croppedImage = croppedImage.transformed(QTransform(0, 1, 1, 0, 0, 0)); diff --git a/src/widget/woverview.h b/src/widget/woverview.h index db3c8ae46efc..55aaffc56756 100644 --- a/src/widget/woverview.h +++ b/src/widget/woverview.h @@ -34,7 +34,6 @@ class WOverview : public WWidget { Q_OBJECT public: WOverview(const char* pGroup, UserSettingsPointer pConfig, QWidget* parent=nullptr); - ~WOverview() override; void setup(const QDomNode& node, const SkinContext& context); @@ -67,7 +66,7 @@ class WOverview : public WWidget { return m_pWaveform; } - QImage* m_pWaveformSourceImage; + QImage m_waveformSourceImage; QImage m_waveformImageScaled; WaveformSignalColors m_signalColors; diff --git a/src/widget/woverviewhsv.cpp b/src/widget/woverviewhsv.cpp index 10198a965d27..e125737f3c40 100644 --- a/src/widget/woverviewhsv.cpp +++ b/src/widget/woverviewhsv.cpp @@ -29,13 +29,13 @@ bool WOverviewHSV::drawNextPixmapPart() { return false; } - if (!m_pWaveformSourceImage) { + if (m_waveformSourceImage.isNull()) { // Waveform pixmap twice the height of the viewport to be scalable // by total_gain // We keep full range waveform data to scale it on paint - m_pWaveformSourceImage = new QImage(dataSize / 2, 2 * 255, + m_waveformSourceImage = QImage(dataSize / 2, 2 * 255, QImage::Format_ARGB32_Premultiplied); - m_pWaveformSourceImage->fill(QColor(0,0,0,0).value()); + m_waveformSourceImage.fill(QColor(0, 0, 0, 0).value()); } // Always multiple of 2 @@ -57,8 +57,8 @@ bool WOverviewHSV::drawNextPixmapPart() { // << "completionIncrement:" << completionIncrement; - QPainter painter(m_pWaveformSourceImage); - painter.translate(0.0,static_cast(m_pWaveformSourceImage->height())/2.0); + QPainter painter(&m_waveformSourceImage); + painter.translate(0.0, static_cast(m_waveformSourceImage.height()) / 2.0); // Get HSV of low color. NOTE(rryan): On ARM, qreal is float so it's // important we use qreal here and not double or float or else we will get diff --git a/src/widget/woverviewlmh.cpp b/src/widget/woverviewlmh.cpp index 2f93d5f8eae2..bf838f2e33fc 100644 --- a/src/widget/woverviewlmh.cpp +++ b/src/widget/woverviewlmh.cpp @@ -31,13 +31,13 @@ bool WOverviewLMH::drawNextPixmapPart() { return false; } - if (!m_pWaveformSourceImage) { + if (m_waveformSourceImage.isNull()) { // Waveform pixmap twice the height of the viewport to be scalable // by total_gain // We keep full range waveform data to scale it on paint - m_pWaveformSourceImage = new QImage(dataSize / 2, 2 * 255, + m_waveformSourceImage = QImage(dataSize / 2, 2 * 255, QImage::Format_ARGB32_Premultiplied); - m_pWaveformSourceImage->fill(QColor(0,0,0,0).value()); + m_waveformSourceImage.fill(QColor(0, 0, 0, 0).value()); } // Always multiple of 2 @@ -59,8 +59,8 @@ bool WOverviewLMH::drawNextPixmapPart() { // << "completionIncrement:" << completionIncrement; - QPainter painter(m_pWaveformSourceImage); - painter.translate(0.0,static_cast(m_pWaveformSourceImage->height())/2.0); + QPainter painter(&m_waveformSourceImage); + painter.translate(0.0, static_cast(m_waveformSourceImage.height()) / 2.0); QColor lowColor = m_signalColors.getLowColor(); QPen lowColorPen(QBrush(lowColor), 1); diff --git a/src/widget/woverviewrgb.cpp b/src/widget/woverviewrgb.cpp index d7696b320d98..6a4c348efc7a 100644 --- a/src/widget/woverviewrgb.cpp +++ b/src/widget/woverviewrgb.cpp @@ -28,13 +28,13 @@ bool WOverviewRGB::drawNextPixmapPart() { return false; } - if (!m_pWaveformSourceImage) { + if (m_waveformSourceImage.isNull()) { // Waveform pixmap twice the height of the viewport to be scalable // by total_gain // We keep full range waveform data to scale it on paint - m_pWaveformSourceImage = new QImage(dataSize / 2, 2 * 255, + m_waveformSourceImage = QImage(dataSize / 2, 2 * 255, QImage::Format_ARGB32_Premultiplied); - m_pWaveformSourceImage->fill(QColor(0,0,0,0).value()); + m_waveformSourceImage.fill(QColor(0, 0, 0, 0).value()); } // Always multiple of 2 @@ -55,8 +55,8 @@ bool WOverviewRGB::drawNextPixmapPart() { // << "waveformCompletion:" << waveformCompletion // << "completionIncrement:" << completionIncrement; - QPainter painter(m_pWaveformSourceImage); - painter.translate(0.0,static_cast(m_pWaveformSourceImage->height())/2.0); + QPainter painter(&m_waveformSourceImage); + painter.translate(0.0, static_cast(m_waveformSourceImage.height()) / 2.0); QColor color; diff --git a/src/widget/wtracktableview.cpp b/src/widget/wtracktableview.cpp index d8774b78053b..cd509886f1b2 100644 --- a/src/widget/wtracktableview.cpp +++ b/src/widget/wtracktableview.cpp @@ -127,6 +127,7 @@ WTrackTableView::~WTrackTableView() { delete m_pPropertiesAct; delete m_pMenu; delete m_pPlaylistMenu; + delete m_pCoverMenu; delete m_pCrateMenu; delete m_pBpmLockAction; delete m_pBpmUnlockAction; @@ -137,6 +138,8 @@ WTrackTableView::~WTrackTableView() { delete m_pBpmFourThirdsAction; delete m_pBpmThreeHalvesAction; delete m_pBPMMenu; + delete m_pClearBeatsAction; + delete m_pClearWaveformAction; delete m_pReplayGainResetAction; delete m_pPurgeAct; delete m_pFileBrowserAct; @@ -455,6 +458,10 @@ void WTrackTableView::createActions() { connect(m_pClearBeatsAction, SIGNAL(triggered()), this, SLOT(slotClearBeats())); + m_pClearWaveformAction = new QAction(tr("Clear Waveform"), this); + connect(m_pClearWaveformAction, SIGNAL(triggered()), + this, SLOT(slotClearWaveform())); + m_pReplayGainResetAction = new QAction(tr("Reset ReplayGain"), this); connect(m_pReplayGainResetAction, SIGNAL(triggered()), this, SLOT(slotReplayGainReset())); @@ -929,6 +936,8 @@ void WTrackTableView::contextMenuEvent(QContextMenuEvent* event) { m_pBPMMenu->addAction(m_pClearBeatsAction); } + m_pMenu->addAction(m_pClearWaveformAction); + m_pMenu->addAction(m_pReplayGainResetAction); m_pMenu->addSeparator(); @@ -1606,6 +1615,25 @@ void WTrackTableView::slotClearBeats() { } } +void WTrackTableView::slotClearWaveform() { + TrackModel* trackModel = getTrackModel(); + if (trackModel == nullptr) { + return; + } + + AnalysisDao& analysisDao = m_pTrackCollection->getAnalysisDAO(); + QModelIndexList indices = selectionModel()->selectedRows(); + for (const QModelIndex& index : indices) { + TrackPointer pTrack = trackModel->getTrack(index); + if (!pTrack) { + continue; + } + analysisDao.deleteAnalysesForTrack(pTrack->getId()); + pTrack->setWaveform(WaveformPointer()); + pTrack->setWaveformSummary(WaveformPointer()); + } +} + void WTrackTableView::slotReplayGainReset() { QModelIndexList indices = selectionModel()->selectedRows(); TrackModel* trackModel = getTrackModel(); diff --git a/src/widget/wtracktableview.h b/src/widget/wtracktableview.h index f2306280970e..183ce6adbb27 100644 --- a/src/widget/wtracktableview.h +++ b/src/widget/wtracktableview.h @@ -70,6 +70,7 @@ class WTrackTableView : public WLibraryTableView { void slotUnlockBpm(); void slotScaleBpm(int); void slotClearBeats(); + void slotClearWaveform(); void slotReplayGainReset(); // Signalled 20 times per second (every 50ms) by GuiTick. void slotGuiTick50ms(double); @@ -162,6 +163,9 @@ class WTrackTableView : public WLibraryTableView { // Clear track beats QAction* m_pClearBeatsAction; + // Clear track waveform + QAction* m_pClearWaveformAction; + // Replay Gain feature QAction *m_pReplayGainResetAction;