Skip to content
11 changes: 10 additions & 1 deletion src/analyzer/analyzerwaveform.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -104,12 +104,21 @@ bool AnalyzerWaveform::initialize(TrackPointer tio, int sampleRate, int totalSam
}

bool AnalyzerWaveform::loadStored(TrackPointer tio) const {
TrackId trackId = tio->getId();

if (tio->isClearWaveformRequested()) {
bool success = m_pAnalysisDao->deleteAnalysesForTrack(trackId);
qDebug() << (success ? "Successfully deleted" : "Failed to delete")
<< "waveform analysis for trackId" << trackId;
tio->setClearWaveformRequested(false);
return false;
}

ConstWaveformPointer pTrackWaveform = tio->getWaveform();
ConstWaveformPointer pTrackWaveformSummary = tio->getWaveformSummary();
ConstWaveformPointer pLoadedTrackWaveform;
ConstWaveformPointer pLoadedTrackWaveformSummary;

TrackId trackId = tio->getId();
bool missingWaveform = pTrackWaveform.isNull();
bool missingWavesummary = pTrackWaveformSummary.isNull();

Expand Down
14 changes: 12 additions & 2 deletions src/library/dao/analysisdao.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -323,14 +323,24 @@ void AnalysisDao::saveTrackAnalyses(TrackInfoObject* pTrack) {
ConstWaveformPointer pWaveform = pTrack->getWaveform();
ConstWaveformPointer pWaveSummary = pTrack->getWaveformSummary();

TrackId trackId(pTrack->getId());

// Delete waveform analysis if track was requested to have its waveform cleared.
if (pTrack->isClearWaveformRequested()) {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

The code in both AnalyzerWaveform and AnalysisDao for clearing the waveform if requested looks very similar. I would recommend to encapsulate the code from AnalysisDao in a function:

bool AnalysisDao::clearWaveformIfRequested(TrackInfoObject* pTrack)

Then from AnalyzerWaveform::loadStored() you could simply invoke pAnalysisDao->clearWaveformIfRequested(tio) before obtaining the waveform pointers from the TIO.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Yes, you are right, but I'm planning to implement automatic clear of waveforms, beats and keys of track being loaded if Mixxx detects that audio of the track has changed, so I need a name that will cover both (automatic and manual) clearing. Do you mind if I do this then?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Sure :) Thanks for your work, Nino! It's a pleasure to review your commits,
well done.

On 01/11/2016 11:06 PM, Nino MP wrote:

In src/library/dao/analysisdao.cpp
#841 (comment):

@@ -323,14 +323,26 @@ void AnalysisDao::saveTrackAnalyses(TrackInfoObject* pTrack) {
ConstWaveformPointer pWaveform = pTrack->getWaveform();
ConstWaveformPointer pWaveSummary = pTrack->getWaveformSummary();

  • TrackId trackId(pTrack->getId());
  • // Delete waveform analysis if track was requested to have its waveform cleared.
  • if (pTrack->isClearWaveformRequested()) {

Yes, you are right, but I'm planning to implement automatic clear of
waveforms, beats and keys of track being loaded if Mixxx detects that
audio of the track has changed, so I need a name that will cover both
(automatic and manual) clearing. Do you mind if I do this then?


Reply to this email directly or view it on GitHub
https://github.com/mixxxdj/mixxx/pull/841/files#r49386413.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Thank you! 😄 I'm glad you like it.

bool success = deleteAnalysesForTrack(trackId);
qDebug() << (success ? "Successfully deleted" : "Failed to delete")
<< "waveform analysis for trackId" << trackId;
// Clear flag
pTrack->setClearWaveformRequested(false);
return;
}

// Don't try to save invalid or non-dirty waveforms.
if (!pWaveform || pWaveform->getDataSize() == 0 || !pWaveform->isDirty() ||
!pWaveSummary || pWaveSummary->getDataSize() == 0 || !pWaveSummary->isDirty()) {
return;
}

TrackId trackId(pTrack->getId());

AnalysisDao::AnalysisInfo analysis;
analysis.trackId = trackId;
if (pWaveform->getId() != -1) {
Expand Down
37 changes: 31 additions & 6 deletions src/trackinfoobject.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ TrackInfoObject::TrackInfoObject(
m_dateAdded(QDateTime::currentDateTime()),
m_bHeaderParsed(false),
m_bBpmLocked(false),
m_bClearWaveformRequested(false),
m_analyzerProgress(-1) {
}

Expand Down Expand Up @@ -653,21 +654,45 @@ QString TrackInfoObject::getURL() const {
}

ConstWaveformPointer TrackInfoObject::getWaveform() {
return m_waveform;
return m_pWaveform;
}

void TrackInfoObject::setWaveform(ConstWaveformPointer pWaveform) {
m_waveform = pWaveform;
emit(waveformUpdated());
QMutexLocker lock(&m_qMutex);
if (m_pWaveform != pWaveform) {
m_pWaveform = pWaveform;
markDirtyAndUnlock(&lock);
emit(waveformUpdated());
}
}

ConstWaveformPointer TrackInfoObject::getWaveformSummary() const {
return m_waveformSummary;
return m_pWaveformSummary;
}

void TrackInfoObject::setWaveformSummary(ConstWaveformPointer pWaveform) {
m_waveformSummary = pWaveform;
emit(waveformSummaryUpdated());
QMutexLocker lock(&m_qMutex);
if (m_pWaveformSummary != pWaveform) {
m_pWaveformSummary = pWaveform;
markDirtyAndUnlock(&lock);
emit(waveformSummaryUpdated());
}
}

bool TrackInfoObject::isClearWaveformRequested() const {
QMutexLocker lock(&m_qMutex);
return m_bClearWaveformRequested;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Here a lock is required, even if it is only a primitive boolean value!

}

void TrackInfoObject::setClearWaveformRequested(bool requested) {
QMutexLocker lock(&m_qMutex);
m_bClearWaveformRequested = requested;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Same here, locking is required

}

void TrackInfoObject::clearWaveform() {
setClearWaveformRequested(true);
setWaveform(WaveformPointer());
setWaveformSummary(WaveformPointer());
}

void TrackInfoObject::setAnalyzerProgress(int progress) {
Expand Down
12 changes: 9 additions & 3 deletions src/trackinfoobject.h
Original file line number Diff line number Diff line change
Expand Up @@ -222,6 +222,10 @@ class TrackInfoObject : public QObject {
ConstWaveformPointer getWaveformSummary() const;
void setWaveformSummary(ConstWaveformPointer pWaveform);

bool isClearWaveformRequested() const;
void setClearWaveformRequested(bool);
void clearWaveform();

void setAnalyzerProgress(int progress);
int getAnalyzerProgress() const;

Expand Down Expand Up @@ -378,9 +382,11 @@ class TrackInfoObject : public QObject {
// Storage for the track's beats
BeatsPointer m_pBeats;

//Visual waveform data
ConstWaveformPointer m_waveform;
ConstWaveformPointer m_waveformSummary;
// Visual waveform data
ConstWaveformPointer m_pWaveform;
ConstWaveformPointer m_pWaveformSummary;

bool m_bClearWaveformRequested;

QAtomicInt m_analyzerProgress; // in 0.1%

Expand Down
21 changes: 21 additions & 0 deletions src/widget/wtracktableview.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -449,6 +449,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 Replay Gain"), this);
connect(m_pReplayGainResetAction, SIGNAL(triggered()),
this, SLOT(slotReplayGainReset()));
Expand Down Expand Up @@ -873,6 +877,8 @@ void WTrackTableView::contextMenuEvent(QContextMenuEvent* event) {
m_pBPMMenu->addAction(m_pClearBeatsAction);
}

m_pMenu->addAction(m_pClearWaveformAction);

m_pMenu->addAction(m_pReplayGainResetAction);

m_pMenu->addSeparator();
Expand Down Expand Up @@ -1586,6 +1592,21 @@ void WTrackTableView::slotClearBeats() {
}
}

void WTrackTableView::slotClearWaveform() {
TrackModel* trackModel = getTrackModel();
if (trackModel == nullptr) {
return;
}

QModelIndexList selectedIndices = selectionModel()->selectedRows();
foreach (QModelIndex index, selectedIndices) {
TrackPointer pTrack = trackModel->getTrack(index);
if (pTrack) {
pTrack->clearWaveform();
}
}
}

void WTrackTableView::slotReplayGainReset() {
QModelIndexList indices = selectionModel()->selectedRows();
TrackModel* trackModel = getTrackModel();
Expand Down
4 changes: 4 additions & 0 deletions src/widget/wtracktableview.h
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,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);
Expand Down Expand Up @@ -150,6 +151,9 @@ class WTrackTableView : public WLibraryTableView {
// Clear track beats
QAction* m_pClearBeatsAction;

// Clear track waveform
QAction* m_pClearWaveformAction;

// Replay Gain feature
QAction *m_pReplayGainResetAction;

Expand Down