summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorUwe Klotz <uklotz@mixxx.org>2019-06-05 23:39:52 +0200
committerUwe Klotz <uklotz@mixxx.org>2019-06-07 16:03:45 +0200
commit5f924ec12a2e1efda27f33751039f1cf0462fdc7 (patch)
tree4b0fabc88024245583f3cca0d20dd592fe429d75
parentb5fc790a542462288765b73497e211aefca05f43 (diff)
Fix API design of Analyzer and adjust all implementations
-rw-r--r--src/analyzer/analyzer.h57
-rw-r--r--src/analyzer/analyzerbeats.cpp41
-rw-r--r--src/analyzer/analyzerbeats.h8
-rw-r--r--src/analyzer/analyzerebur128.cpp33
-rw-r--r--src/analyzer/analyzerebur128.h9
-rw-r--r--src/analyzer/analyzergain.cpp41
-rw-r--r--src/analyzer/analyzergain.h5
-rw-r--r--src/analyzer/analyzerkey.cpp31
-rw-r--r--src/analyzer/analyzerkey.h6
-rw-r--r--src/analyzer/analyzersilence.cpp7
-rw-r--r--src/analyzer/analyzersilence.h4
-rw-r--r--src/analyzer/analyzerthread.cpp60
-rw-r--r--src/analyzer/analyzerthread.h14
-rw-r--r--src/analyzer/analyzerwaveform.cpp64
-rw-r--r--src/analyzer/analyzerwaveform.h4
15 files changed, 184 insertions, 200 deletions
diff --git a/src/analyzer/analyzer.h b/src/analyzer/analyzer.h
index 2cb7f67dc3..6e6a4bbef2 100644
--- a/src/analyzer/analyzer.h
+++ b/src/analyzer/analyzer.h
@@ -27,15 +27,58 @@ class Analyzer {
// returned true!
/////////////////////////////////////////////////////////////////////////
- // Analyze the next chunk of audio samples.
- virtual void process(const CSAMPLE* pIn, const int iLen) = 0;
+ // Analyze the next chunk of audio samples and return true if successful.
+ // If processing fails the analysis can be aborted early by returning
+ // false. After aborting the analysis only cleanup() will be invoked,
+ // but not finalize()!
+ virtual bool process(const CSAMPLE* pIn, const int iLen) = 0;
// Update the track object with the analysis results after
- // processing finished, i.e. all available audio samples have
- // been processed.
+ // processing finished successfully, i.e. all available audio
+ // samples have been processed.
virtual void finalize(TrackPointer tio) = 0;
- // Discard any temporary results or free allocated memory after
- // finalization.
- virtual void cleanup(TrackPointer tio) = 0;
+ // Discard any temporary results or free allocated memory.
+ virtual void cleanup() = 0;
+};
+
+typedef std::unique_ptr<Analyzer> AnalyzerPtr;
+
+class AnalyzerState {
+ public:
+ explicit AnalyzerState(AnalyzerPtr analyzer)
+ : m_analyzer(std::move(analyzer)),
+ m_processing(false) {
+ DEBUG_ASSERT(m_analyzer);
+ }
+ AnalyzerState(const AnalyzerState&) = delete;
+ AnalyzerState(AnalyzerState&&) = default;
+
+ bool initialize(TrackPointer tio, int sampleRate, int totalSamples) {
+ DEBUG_ASSERT(!m_processing);
+ m_processing = m_analyzer->initialize(tio, sampleRate, totalSamples);
+ return m_processing;
+ }
+
+ void process(const CSAMPLE* pIn, const int iLen) {
+ if (m_processing) {
+ m_processing = m_analyzer->process(pIn, iLen);
+ }
+ }
+
+ void finalize(TrackPointer tio) {
+ if (m_processing) {
+ m_analyzer->finalize(tio);
+ m_processing = false;
+ }
+ }
+
+ void cleanup() {
+ m_analyzer->cleanup();
+ m_processing = false;
+ }
+
+ private:
+ AnalyzerPtr m_analyzer;
+ bool m_processing;
};
diff --git a/src/analyzer/analyzerbeats.cpp b/src/analyzer/analyzerbeats.cpp
index 6b6bec828a..8929356294 100644
--- a/src/analyzer/analyzerbeats.cpp
+++ b/src/analyzer/analyzerbeats.cpp
@@ -1,13 +1,13 @@
#include "analyzer/analyzerbeats.h"
-#include <QtDebug>
-#include <QVector>
#include <QHash>
#include <QString>
+#include <QVector>
+#include <QtDebug>
#include "analyzer/constants.h"
-#include "analyzer/plugins/analyzersoundtouchbeats.h"
#include "analyzer/plugins/analyzerqueenmarybeats.h"
+#include "analyzer/plugins/analyzersoundtouchbeats.h"
#include "track/beatfactory.h"
#include "track/beatmap.h"
#include "track/beatutils.h"
@@ -166,37 +166,30 @@ bool AnalyzerBeats::shouldAnalyze(TrackPointer tio) const {
return true;
}
-void AnalyzerBeats::process(const CSAMPLE *pIn, const int iLen) {
- if (!m_pPlugin) {
- return;
+bool AnalyzerBeats::process(const CSAMPLE *pIn, const int iLen) {
+ VERIFY_OR_DEBUG_ASSERT(m_pPlugin) {
+ return false;
}
m_iCurrentSample += iLen;
if (m_iCurrentSample > m_iMaxSamplesToProcess) {
- return;
+ return true; // silently ignore all remaining samples
}
- bool success = m_pPlugin->process(pIn, iLen);
- if (!success) {
- m_pPlugin.reset();
- }
+ return m_pPlugin->process(pIn, iLen);
}
-void AnalyzerBeats::cleanup(TrackPointer tio) {
- Q_UNUSED(tio);
+void AnalyzerBeats::cleanup() {
m_pPlugin.reset();
}
void AnalyzerBeats::finalize(TrackPointer tio) {
- if (!m_pPlugin) {
+ VERIFY_OR_DEBUG_ASSERT(m_pPlugin) {
return;
}
- bool success = m_pPlugin->finalize();
- qDebug() << "Beat Calculation" << (success ? "complete" : "failed");
-
- if (!success) {
- m_pPlugin.reset();
+ if (!m_pPlugin->finalize()) {
+ qWarning() << "Beat/BPM analysis failed";
return;
}
@@ -204,12 +197,9 @@ void AnalyzerBeats::finalize(TrackPointer tio) {
if (m_pPlugin->supportsBeatTracking()) {
QVector<double> beats = m_pPlugin->getBeats();
QHash<QString, QString> extraVersionInfo = getExtraVersionInfo(
- m_pluginId, m_bPreferencesFastAnalysis);
+ m_pluginId, m_bPreferencesFastAnalysis);
pBeats = BeatFactory::makePreferredBeats(
- *tio, beats, extraVersionInfo,
- m_bPreferencesFixedTempo, m_bPreferencesOffsetCorrection,
- m_iSampleRate, m_iTotalSamples,
- m_iMinBpm, m_iMaxBpm);
+ *tio, beats, extraVersionInfo, m_bPreferencesFixedTempo, m_bPreferencesOffsetCorrection, m_iSampleRate, m_iTotalSamples, m_iMinBpm, m_iMaxBpm);
qDebug() << "AnalyzerBeats plugin detected" << beats.size()
<< "beats. Average BPM:" << (pBeats ? pBeats->getBpm() : 0.0);
} else {
@@ -217,7 +207,6 @@ void AnalyzerBeats::finalize(TrackPointer tio) {
qDebug() << "AnalyzerBeats plugin detected constant BPM: " << bpm;
pBeats = BeatFactory::makeBeatGrid(*tio, bpm, 0.0f);
}
- m_pPlugin.reset();
BeatsPointer pCurrentBeats = tio->getBeats();
@@ -258,7 +247,7 @@ void AnalyzerBeats::finalize(TrackPointer tio) {
// static
QHash<QString, QString> AnalyzerBeats::getExtraVersionInfo(
- QString pluginId, bool bPreferencesFastAnalysis) {
+ QString pluginId, bool bPreferencesFastAnalysis) {
QHash<QString, QString> extraVersionInfo;
extraVersionInfo["vamp_plugin_id"] = pluginId;
if (bPreferencesFastAnalysis) {
diff --git a/src/analyzer/analyzerbeats.h b/src/analyzer/analyzerbeats.h
index 0470c416e7..6e09034799 100644
--- a/src/analyzer/analyzerbeats.h
+++ b/src/analyzer/analyzerbeats.h
@@ -17,7 +17,7 @@
#include "preferences/usersettings.h"
#include "util/memory.h"
-class AnalyzerBeats: public Analyzer {
+class AnalyzerBeats : public Analyzer {
public:
explicit AnalyzerBeats(
UserSettingsPointer pConfig,
@@ -27,14 +27,14 @@ class AnalyzerBeats: public Analyzer {
static QList<mixxx::AnalyzerPluginInfo> availablePlugins();
bool initialize(TrackPointer tio, int sampleRate, int totalSamples) override;
- void process(const CSAMPLE *pIn, const int iLen) override;
- void cleanup(TrackPointer tio) override;
+ bool process(const CSAMPLE *pIn, const int iLen) override;
void finalize(TrackPointer tio) override;
+ void cleanup() override;
private:
bool shouldAnalyze(TrackPointer tio) const;
static QHash<QString, QString> getExtraVersionInfo(
- QString pluginId, bool bPreferencesFastAnalysis);
+ QString pluginId, bool bPreferencesFastAnalysis);
BeatDetectionSettings m_bpmSettings;
std::unique_ptr<mixxx::AnalyzerBeatsPlugin> m_pPlugin;
diff --git a/src/analyzer/analyzerebur128.cpp b/src/analyzer/analyzerebur128.cpp
index 9e20712e41..df06208fbf 100644
--- a/src/analyzer/analyzerebur128.cpp
+++ b/src/analyzer/analyzerebur128.cpp
@@ -27,55 +27,48 @@ bool AnalyzerEbur128::initialize(TrackPointer tio,
qDebug() << "Skipping AnalyzerEbur128";
return false;
}
- if (!isInitialized()) {
- m_pState = ebur128_init(2u,
- static_cast<unsigned long>(sampleRate),
- EBUR128_MODE_I);
- }
- return isInitialized();
+ DEBUG_ASSERT(m_pState == nullptr);
+ m_pState = ebur128_init(2u,
+ static_cast<unsigned long>(sampleRate),
+ EBUR128_MODE_I);
+ return m_pState != nullptr;
}
void AnalyzerEbur128::cleanup() {
- if (isInitialized()) {
+ if (m_pState) {
ebur128_destroy(&m_pState);
// ebur128_destroy clears the pointer but let's not rely on that.
m_pState = nullptr;
}
- DEBUG_ASSERT(!isInitialized());
-}
-
-void AnalyzerEbur128::cleanup(TrackPointer tio) {
- Q_UNUSED(tio);
- cleanup();
}
-void AnalyzerEbur128::process(const CSAMPLE *pIn, const int iLen) {
- if (!isInitialized()) {
- return;
+bool AnalyzerEbur128::process(const CSAMPLE *pIn, const int iLen) {
+ VERIFY_OR_DEBUG_ASSERT(m_pState) {
+ return false;
}
ScopedTimer t("AnalyzerEbur128::process()");
size_t frames = iLen / 2;
int e = ebur128_add_frames_float(m_pState, pIn, frames);
VERIFY_OR_DEBUG_ASSERT(e == EBUR128_SUCCESS) {
qWarning() << "AnalyzerEbur128::process() failed with" << e;
- return;
+ return false;
}
+ return true;
}
void AnalyzerEbur128::finalize(TrackPointer tio) {
- if (!isInitialized()) {
+ VERIFY_OR_DEBUG_ASSERT(m_pState) {
return;
}
double averageLufs;
int e = ebur128_loudness_global(m_pState, &averageLufs);
- cleanup(tio);
VERIFY_OR_DEBUG_ASSERT(e == EBUR128_SUCCESS) {
qWarning() << "AnalyzerEbur128::finalize() failed with" << e;
return;
}
if (averageLufs == -HUGE_VAL || averageLufs == 0.0) {
qWarning() << "AnalyzerEbur128::finalize() averageLufs invalid:"
- << averageLufs;
+ << averageLufs;
return;
}
diff --git a/src/analyzer/analyzerebur128.h b/src/analyzer/analyzerebur128.h
index bc52b8267d..088e1b5b5d 100644
--- a/src/analyzer/analyzerebur128.h
+++ b/src/analyzer/analyzerebur128.h
@@ -16,16 +16,11 @@ class AnalyzerEbur128 : public Analyzer {
}
bool initialize(TrackPointer tio, int sampleRate, int totalSamples) override;
- void process(const CSAMPLE* pIn, const int iLen) override;
- void cleanup(TrackPointer tio) override;
+ bool process(const CSAMPLE* pIn, const int iLen) override;
void finalize(TrackPointer tio) override;
+ void cleanup() override;
private:
- void cleanup();
- bool isInitialized() const {
- return m_pState != nullptr;
- }
-
ReplayGainSettings m_rgSettings;
ebur128_state* m_pState;
};
diff --git a/src/analyzer/analyzergain.cpp b/src/analyzer/analyzergain.cpp
index 5d99ea2956..5b8f362ee3 100644
--- a/src/analyzer/analyzergain.cpp
+++ b/src/analyzer/analyzergain.cpp
@@ -1,5 +1,5 @@
-#include <QtDebug>
#include <replaygain.h>
+#include <QtDebug>
#include "analyzer/analyzergain.h"
#include "track/track.h"
@@ -8,17 +8,16 @@
#include "util/timer.h"
AnalyzerGain::AnalyzerGain(UserSettingsPointer pConfig)
- : m_initalized(false),
- m_rgSettings(pConfig),
- m_pLeftTempBuffer(NULL),
- m_pRightTempBuffer(NULL),
- m_iBufferSize(0) {
+ : m_rgSettings(pConfig),
+ m_pLeftTempBuffer(NULL),
+ m_pRightTempBuffer(NULL),
+ m_iBufferSize(0) {
m_pReplayGain = new ReplayGain();
}
AnalyzerGain::~AnalyzerGain() {
- delete [] m_pLeftTempBuffer;
- delete [] m_pRightTempBuffer;
+ delete[] m_pLeftTempBuffer;
+ delete[] m_pRightTempBuffer;
delete m_pReplayGain;
}
@@ -28,32 +27,26 @@ bool AnalyzerGain::initialize(TrackPointer tio, int sampleRate, int totalSamples
return false;
}
- m_initalized = m_pReplayGain->initialise((long)sampleRate, 2);
- return true;
+ return m_pReplayGain->initialise((long)sampleRate, 2);
}
-void AnalyzerGain::cleanup(TrackPointer tio) {
- m_initalized = false;
- Q_UNUSED(tio);
+void AnalyzerGain::cleanup() {
}
-void AnalyzerGain::process(const CSAMPLE *pIn, const int iLen) {
- if (!m_initalized) {
- return;
- }
+bool AnalyzerGain::process(const CSAMPLE *pIn, const int iLen) {
ScopedTimer t("AnalyzerGain::process()");
int halfLength = static_cast<int>(iLen / 2);
if (halfLength > m_iBufferSize) {
- delete [] m_pLeftTempBuffer;
- delete [] m_pRightTempBuffer;
+ delete[] m_pLeftTempBuffer;
+ delete[] m_pRightTempBuffer;
m_pLeftTempBuffer = new CSAMPLE[halfLength];
m_pRightTempBuffer = new CSAMPLE[halfLength];
}
SampleUtil::deinterleaveBuffer(m_pLeftTempBuffer, m_pRightTempBuffer, pIn, halfLength);
SampleUtil::applyGain(m_pLeftTempBuffer, 32767, halfLength);
SampleUtil::applyGain(m_pRightTempBuffer, 32767, halfLength);
- m_initalized = m_pReplayGain->process(m_pLeftTempBuffer, m_pRightTempBuffer, halfLength);
+ return m_pReplayGain->process(m_pLeftTempBuffer, m_pRightTempBuffer, halfLength);
}
void AnalyzerGain::finalize(TrackPointer tio) {
@@ -62,19 +55,15 @@ void AnalyzerGain::finalize(TrackPointer tio) {
// One may think to digg into replay_gain code and modify it so that
// it directly sends results as relative peaks.
// In that way there is no need to spend resources in calculating log10 or pow.
- if(!m_initalized)
- return;
float fReplayGainOutput = m_pReplayGain->end();
if (fReplayGainOutput == GAIN_NOT_ENOUGH_SAMPLES) {
- qDebug() << "ReplayGain 1.0 analysis failed";
- m_initalized = false;
+ qWarning() << "ReplayGain 1.0 analysis failed";
return;
}
mixxx::ReplayGain replayGain(tio->getReplayGain());
replayGain.setRatio(db2ratio(fReplayGainOutput));
tio->setReplayGain(replayGain);
- qDebug() << "ReplayGain 1.0 result is" << fReplayGainOutput << "dB for" << tio->getLocation();
- m_initalized = false;
+ qDebug() << "ReplayGain 1.0 result is" << fReplayGainOutput << "dB for" << tio->getFileInfo();
}
diff --git a/src/analyzer/analyzergain.h b/src/analyzer/analyzergain.h
index 58f5b8e34a..1b574526f8 100644
--- a/src/analyzer/analyzergain.h
+++ b/src/analyzer/analyzergain.h
@@ -23,12 +23,11 @@ class AnalyzerGain : public Analyzer {
}
bool initialize(TrackPointer tio, int sampleRate, int totalSamples) override;
- void process(const CSAMPLE* pIn, const int iLen) override;
- void cleanup(TrackPointer tio) override;
+ bool process(const CSAMPLE* pIn, const int iLen) override;
void finalize(TrackPointer tio) override;
+ void cleanup() override;
private:
- bool m_initalized;
ReplayGainSettings m_rgSettings;
CSAMPLE* m_pLeftTempBuffer;
CSAMPLE* m_pRightTempBuffer;
diff --git a/src/analyzer/analyzerkey.cpp b/src/analyzer/analyzerkey.cpp
index e4486cf915..50ae516c46 100644
--- a/src/analyzer/analyzerkey.cpp
+++ b/src/analyzer/analyzerkey.cpp
@@ -1,7 +1,7 @@
#include "analyzer/analyzerkey.h"
-#include <QtDebug>
#include <QVector>
+#include <QtDebug>
#include "analyzer/constants.h"
#include "analyzer/plugins/analyzerqueenmarykey.h"
@@ -91,7 +91,7 @@ bool AnalyzerKey::shouldAnalyze(TrackPointer tio) const {
QString subVersion = keys.getSubVersion();
QHash<QString, QString> extraVersionInfo = getExtraVersionInfo(
- pluginID, bPreferencesFastAnalysisEnabled);
+ pluginID, bPreferencesFastAnalysisEnabled);
QString newVersion = KeyFactory::getPreferredVersion();
QString newSubVersion = KeyFactory::getPreferredSubVersion(extraVersionInfo);
@@ -111,43 +111,34 @@ bool AnalyzerKey::shouldAnalyze(TrackPointer tio) const {
return true;
}
-void AnalyzerKey::process(const CSAMPLE *pIn, const int iLen) {
- if (!m_pPlugin) {
- return;
+bool AnalyzerKey::process(const CSAMPLE *pIn, const int iLen) {
+ VERIFY_OR_DEBUG_ASSERT(m_pPlugin) {
+ return false;
}
m_iCurrentSample += iLen;
if (m_iCurrentSample > m_iMaxSamplesToProcess) {
- return;
+ return true; // silently ignore remaining samples
}
- bool success = m_pPlugin->process(pIn, iLen);
- if (!success) {
- m_pPlugin.reset();
- }
+ return m_pPlugin->process(pIn, iLen);
}
-void AnalyzerKey::cleanup(TrackPointer tio) {
- Q_UNUSED(tio);
+void AnalyzerKey::cleanup() {
m_pPlugin.reset();
}
void AnalyzerKey::finalize(TrackPointer tio) {
- if (!m_pPlugin) {
+ VERIFY_OR_DEBUG_ASSERT(m_pPlugin) {
return;
}
- bool success = m_pPlugin->finalize();
- qDebug() << "Key Detection" << (success ? "complete" : "failed");
-
- if (!success) {
- m_pPlugin.reset();
+ if (!m_pPlugin->finalize()) {
+ qWarning() << "Key detection failed";
return;
}
KeyChangeList key_changes = m_pPlugin->getKeyChanges();
- m_pPlugin.reset();
-
QHash<QString, QString> extraVersionInfo = getExtraVersionInfo(
m_pluginId, m_bPreferencesFastAnalysisEnabled);
Keys track_keys = KeyFactory::makePreferredKeys(
diff --git a/src/analyzer/analyzerkey.h b/src/analyzer/analyzerkey.h
index 23a20f53e7..4bebe463dc 100644
--- a/src/analyzer/analyzerkey.h
+++ b/src/analyzer/analyzerkey.h
@@ -20,13 +20,13 @@ class AnalyzerKey : public Analyzer {
static QList<mixxx::AnalyzerPluginInfo> availablePlugins();
bool initialize(TrackPointer tio, int sampleRate, int totalSamples) override;
- void process(const CSAMPLE *pIn, const int iLen) override;
+ bool process(const CSAMPLE *pIn, const int iLen) override;
void finalize(TrackPointer tio) override;
- void cleanup(TrackPointer tio) override;
+ void cleanup() override;
private:
static QHash<QString, QString> getExtraVersionInfo(
- QString pluginId, bool bPreferencesFastAnalysis);
+ QString pluginId, bool bPreferencesFastAnalysis);
bool shouldAnalyze(TrackPointer tio) const;
diff --git a/src/analyzer/analyzersilence.cpp b/src/analyzer/analyzersilence.cpp
index a402ef0108..f9d37942a9 100644
--- a/src/analyzer/analyzersilence.cpp
+++ b/src/analyzer/analyzersilence.cpp
@@ -72,7 +72,7 @@ bool AnalyzerSilence::initialize(TrackPointer tio, int sampleRate, int totalSamp
return true;
}
-void AnalyzerSilence::process(const CSAMPLE* pIn, const int iLen) {
+bool AnalyzerSilence::process(const CSAMPLE* pIn, const int iLen) {
for (int i = 0; i < iLen; i += mixxx::kAnalysisChannels) {
// Compute max of channels in this sample frame
CSAMPLE fMax = CSAMPLE_ZERO;
@@ -93,12 +93,11 @@ void AnalyzerSilence::process(const CSAMPLE* pIn, const int iLen) {
m_bPrevSilence = bSilence;
}
-
m_iFramesProcessed += iLen / mixxx::kAnalysisChannels;
+ return true;
}
-void AnalyzerSilence::cleanup(TrackPointer tio) {
- Q_UNUSED(tio);
+void AnalyzerSilence::cleanup() {
}
void AnalyzerSilence::finalize(TrackPointer tio) {
diff --git a/src/analyzer/analyzersilence.h b/src/analyzer/analyzersilence.h
index ddd874b10f..f4de1a683d 100644
--- a/src/analyzer/analyzersilence.h
+++ b/src/analyzer/analyzersilence.h
@@ -12,9 +12,9 @@ class AnalyzerSilence : public Analyzer {
~AnalyzerSilence() override = default;
bool initialize(TrackPointer tio, int sampleRate, int totalSamples) override;
- void process(const CSAMPLE* pIn, const int iLen) override;
+ bool process(const CSAMPLE* pIn, const int iLen) override;
void finalize(TrackPointer tio) override;
- void cleanup(TrackPointer tio) override;
+ void cleanup() override;
private:
UserSettingsPointer m_pConfig;
diff --git a/src/analyzer/analyzerthread.cpp b/src/analyzer/analyzerthread.cpp
index 6b7f2f46c5..ed78fda127 100644
--- a/src/analyzer/analyzerthread.cpp
+++ b/src/analyzer/analyzerthread.cpp
@@ -3,26 +3,25 @@
#include <mutex>
#include "analyzer/analyzerbeats.h"
-#include "analyzer/constants.h"
-#include "analyzer/analyzerkey.h"
-#include "analyzer/analyzergain.h"
#include "analyzer/analyzerebur128.h"
-#include "analyzer/analyzerwaveform.h"
+#include "analyzer/analyzergain.h"
+#include "analyzer/analyzerkey.h"
#include "analyzer/analyzersilence.h"
+#include "analyzer/analyzerwaveform.h"
+#include "analyzer/constants.h"
#include "library/dao/analysisdao.h"
#include "engine/engine.h"
-#include "sources/soundsourceproxy.h"
#include "sources/audiosourcestereoproxy.h"
+#include "sources/soundsourceproxy.h"
-#include "util/db/dbconnectionpooler.h"
#include "util/db/dbconnectionpooled.h"
+#include "util/db/dbconnectionpooler.h"
#include "util/logger.h"
#include "util/timer.h"
-
namespace {
mixxx::Logger kLogger("AnalyzerThread");
@@ -34,8 +33,6 @@ mixxx::Logger kLogger("AnalyzerThread");
/// TODO(XXX): Use the vsync timer for the purpose of sending updates
// to the UI thread with a limited rate??
-
-
// Maximum frequency of progress updates while busy. A value of 60 ms
// results in ~17 progress updates per second which is sufficient for
// continuous feedback.
@@ -59,7 +56,7 @@ void registerMetaTypesOnce() {
} // anonymous namespace
AnalyzerThread::NullPointer::NullPointer()
- : Pointer(nullptr, [](AnalyzerThread*){}) {
+ : Pointer(nullptr, [](AnalyzerThread*) {}) {
}
//static
@@ -69,10 +66,10 @@ AnalyzerThread::Pointer AnalyzerThread::createInstance(
UserSettingsPointer pConfig,
AnalyzerModeFlags modeFlags) {
return Pointer(new AnalyzerThread(
- id,
- dbConnectionPool,
- pConfig,
- modeFlags),
+ id,
+ dbConnectionPool,
+ pConfig,
+ modeFlags),
deleteAnalyzerThread);
}
@@ -106,20 +103,20 @@ void AnalyzerThread::doRun() {
return;
}
QSqlDatabase dbConnection = mixxx::DbConnectionPooled(m_dbConnectionPool);
- m_analyzers.push_back(std::make_unique<AnalyzerWaveform>(m_pConfig, dbConnection));
+ m_analyzers.push_back(AnalyzerState(std::make_unique<AnalyzerWaveform>(m_pConfig, dbConnection)));
}
if (AnalyzerGain::isEnabled(ReplayGainSettings(m_pConfig))) {
- m_analyzers.push_back(std::make_unique<AnalyzerGain>(m_pConfig));
+ m_analyzers.push_back(AnalyzerState(std::make_unique<AnalyzerGain>(m_pConfig)));
}
if (AnalyzerEbur128::isEnabled(ReplayGainSettings(m_pConfig))) {
- m_analyzers.push_back(std::make_unique<AnalyzerEbur128>(m_pConfig));
+ m_analyzers.push_back(AnalyzerState(std::make_unique<AnalyzerEbur128>(m_pConfig)));
}
// BPM detection might be disabled in the config, but can be overridden
// and enabled by explicitly setting the mode flag.
const bool enforceBpmDetection = (m_modeFlags & AnalyzerModeFlags::WithBeats) != 0;
- m_analyzers.push_back(std::make_unique<AnalyzerBeats>(m_pConfig, enforceBpmDetection));
- m_analyzers.push_back(std::make_unique<AnalyzerKey>(m_pConfig));
- m_analyzers.push_back(std::make_unique<AnalyzerSilence>(m_pConfig));
+ m_analyzers.push_back(AnalyzerState(std::make_unique<AnalyzerBeats>(m_pConfig, enforceBpmDetection)));
+ m_analyzers.push_back(AnalyzerState(std::make_unique<AnalyzerKey>(m_pConfig)));
+ m_analyzers.push_back(AnalyzerState(std::make_unique<AnalyzerSilence>(m_pConfig)));
DEBUG_ASSERT(!m_analyzers.empty());
kLogger.debug() << "Activated" << m_analyzers.size() << "analyzers";
@@ -144,12 +141,12 @@ void AnalyzerThread::doRun() {
}
bool processTrack = false;
- for (auto const& analyzer: m_analyzers) {
+ for (auto&& analyzer : m_analyzers) {
// Make sure not to short-circuit initialize(...)
- if (analyzer->initialize(
- m_currentTrack,
- audioSource->sampleRate(),
- audioSource->frameLength() * mixxx::kAnalysisChannels)) {
+ if (analyzer.initialize(
+ m_currentTrack,
+ audioSource->sampleRate(),
+ audioSource->frameLength() * mixxx::kAnalysisChannels)) {
processTrack = true;
}
}
@@ -167,13 +164,14 @@ void AnalyzerThread::doRun() {
// suddenly.
emitBusyProgress(kAnalyzerProgressFinalizing);
// This takes around 3 sec on a Atom Netbook
- for (auto const& analyzer: m_analyzers) {
- analyzer->finalize(m_currentTrack);
+ for (auto&& analyzer : m_analyzers) {
+ analyzer.finalize(m_currentTrack);
+ analyzer.cleanup();
}
emitDoneProgress(kAnalyzerProgressDone);
} else {
- for (auto const& analyzer: m_analyzers) {
- analyzer->cleanup(m_currentTrack);
+ for (auto&& analyzer : m_analyzers) {
+ analyzer.cleanup();
}
emitDoneProgress(kAnalyzerProgressUnknown);
}
@@ -261,8 +259,8 @@ AnalyzerThread::AnalysisResult AnalyzerThread::analyzeAudioSource(
// 2nd: step: Analyze chunk of decoded audio data
if (readableSampleFrames.frameLength() == mixxx::kAnalysisFramesPerBlock) {
// Complete chunk of audio samples has been read for analysis
- for (auto const& analyzer: m_analyzers) {
- analyzer->process(
+ for (auto&& analyzer : m_analyzers) {
+ analyzer.process(
readableSampleFrames.readableData(),
readableSampleFrames.readableLength());
}
diff --git a/src/analyzer/analyzerthread.h b/src/analyzer/analyzerthread.h
index 4cc24e5d82..3e3a5753bf 100644
--- a/src/analyzer/analyzerthread.h
+++ b/src/analyzer/analyzerthread.h
@@ -4,17 +4,16 @@
#include "util/workerthread.h"
-#include "analyzer/analyzerprogress.h"
#include "analyzer/analyzer.h"
+#include "analyzer/analyzerprogress.h"
#include "preferences/usersettings.h"
#include "sources/audiosource.h"
#include "track/track.h"
#include "util/db/dbconnectionpool.h"
-#include "util/performancetimer.h"
-#include "util/samplebuffer.h"
#include "util/memory.h"
#include "util/mpscfifo.h"
-
+#include "util/performancetimer.h"
+#include "util/samplebuffer.h"
enum AnalyzerModeFlags {
None = 0x00,
@@ -46,9 +45,9 @@ class AnalyzerThread : public WorkerThread {
Q_OBJECT
public:
- typedef std::unique_ptr<AnalyzerThread, void(*)(AnalyzerThread*)> Pointer;
+ typedef std::unique_ptr<AnalyzerThread, void (*)(AnalyzerThread*)> Pointer;
// Subclass that provides a default constructor and nothing else
- class NullPointer: public Pointer {
+ class NullPointer : public Pointer {
public:
NullPointer();
};
@@ -114,8 +113,7 @@ class AnalyzerThread : public WorkerThread {
// Thread local: Only used in the constructor/destructor and within
// run() by the worker thread.
- typedef std::unique_ptr<Analyzer> AnalyzerPtr;
- std::vector<AnalyzerPtr> m_analyzers;
+ std::vector<AnalyzerState> m_analyzers;
mixxx::SampleBuffer m_sampleBuffer;
diff --git a/src/analyzer/analyzerwaveform.cpp b/src/analyzer/analyzerwaveform.cpp
index ed2506e143..1e9294239e 100644
--- a/src/analyzer/analyzerwaveform.cpp
+++ b/src/analyzer/analyzerwaveform.cpp
@@ -1,18 +1,18 @@
#include "analyzer/analyzerwaveform.h"
#include "engine/engineobject.h"
-#include "engine/filters/enginefilterbutterworth8.h"
#include "engine/filters/enginefilterbessel4.h"
+#include "engine/filters/enginefilterbutterworth8.h"
#include "library/trackcollection.h"
#include "track/track.h"
-#include "waveform/waveformfactory.h"
#include "util/logger.h"
+#include "waveform/waveformfactory.h"
namespace {
mixxx::Logger kLogger("AnalyzerWaveform");
-} // anonymous
+} // namespace
AnalyzerWaveform::AnalyzerWaveform(
UserSettingsPointer pConfig,
@@ -167,9 +167,13 @@ void AnalyzerWaveform::destroyFilters() {
}
}
-void AnalyzerWaveform::process(const CSAMPLE* buffer, const int bufferLength) {
- if (!m_waveform || !m_waveformSummary)
- return;
+bool AnalyzerWaveform::process(const CSAMPLE* buffer, const int bufferLength) {
+ VERIFY_OR_DEBUG_ASSERT(m_waveform) {
+ return false;
+ }
+ VERIFY_OR_DEBUG_ASSERT(m_waveformSummary) {
+ return false;
+ }
//this should only append once if bufferLength is constant
if (bufferLength > (int)m_buffers[0].size()) {
@@ -216,22 +220,22 @@ void AnalyzerWaveform::process(const CSAMPLE* buffer, const int bufferLength) {
m_stride.m_position++;
if (fmod(m_stride.m_position, m_stride.m_length) < 1) {
- if (m_currentStride + ChannelCount > m_waveform->getDataSize()) {
- qWarning() << "AnalyzerWaveform::process - currentStride >= waveform size";
- return;
+ VERIFY_OR_DEBUG_ASSERT(m_currentStride + ChannelCount <= m_waveform->getDataSize()) {
+ qWarning() << "AnalyzerWaveform::process - currentStride > waveform size";
+ return false;
}
m_stride.store(m_waveformData + m_currentStride);
- m_currentStride += 2;
+ m_currentStride += ChannelCount;
m_waveform->setCompletion(m_currentStride);
}
if (fmod(m_stride.m_position, m_stride.m_averageLength) < 1) {
- if (m_currentSummaryStride + ChannelCount > m_waveformSummary->getDataSize()) {
- qWarning() << "AnalyzerWaveform::process - current summary stride >= waveform summary size";
- return;
+ VERIFY_OR_DEBUG_ASSERT(m_currentSummaryStride + ChannelCount <= m_waveformSummary->getDataSize()) {
+ qWarning() << "AnalyzerWaveform::process - current summary stride > waveform summary size";
+ return false;
}
m_stride.averageStore(m_waveformSummaryData + m_currentSummaryStride);
- m_currentSummaryStride += 2;
+ m_currentSummaryStride += ChannelCount;
m_waveformSummary->setCompletion(m_currentSummaryStride);
#ifdef TEST_HEAT_MAP
@@ -249,22 +253,14 @@ void AnalyzerWaveform::process(const CSAMPLE* buffer, const int bufferLength) {
//kLogger.debug() << "process - m_waveform->getCompletion()" << m_waveform->getCompletion() << "off" << m_waveform->getDataSize();
//kLogger.debug() << "process - m_waveformSummary->getCompletion()" << m_waveformSummary->getCompletion() << "off" << m_waveformSummary->getDataSize();
+ return true;
}
-void AnalyzerWaveform::cleanup(TrackPointer tio) {
- Q_UNUSED(tio);
-
- tio->setWaveform(ConstWaveformPointer());
- // Since clear() could delete the waveform, clear our pointer to the
- // waveform's vector data first.
- m_waveformData = nullptr;
+void AnalyzerWaveform::cleanup() {
m_waveform.clear();
-
- tio->setWaveformSummary(ConstWaveformPointer());
- // Since clear() could delete the waveform, clear our pointer to the
- // waveform's vector data first.
- m_waveformSummaryData = nullptr;
+ m_waveformData = nullptr;
m_waveformSummary.clear();
+ m_waveformSummaryData = nullptr;
}
void AnalyzerWaveform::finalize(TrackPointer tio) {
@@ -274,11 +270,8 @@ void AnalyzerWaveform::finalize(TrackPointer tio) {
m_waveform->setCompletion(m_waveform->getDataSize());
m_waveform->setVersion(WaveformFactory::currentWaveformVersion());
m_waveform->setDescription(WaveformFactory::currentWaveformDescription());
- // Since clear() could delete the waveform, clear our pointer to the
- // waveform's vector data first.
- m_waveformData = nullptr;
- m_waveform.clear();
}
+ tio->setWaveform(m_waveform);