diff options
author | Uwe Klotz <uklotz@mixxx.org> | 2019-06-05 23:39:52 +0200 |
---|---|---|
committer | Uwe Klotz <uklotz@mixxx.org> | 2019-06-07 16:03:45 +0200 |
commit | 5f924ec12a2e1efda27f33751039f1cf0462fdc7 (patch) | |
tree | 4b0fabc88024245583f3cca0d20dd592fe429d75 | |
parent | b5fc790a542462288765b73497e211aefca05f43 (diff) |
Fix API design of Analyzer and adjust all implementations
-rw-r--r-- | src/analyzer/analyzer.h | 57 | ||||
-rw-r--r-- | src/analyzer/analyzerbeats.cpp | 41 | ||||
-rw-r--r-- | src/analyzer/analyzerbeats.h | 8 | ||||
-rw-r--r-- | src/analyzer/analyzerebur128.cpp | 33 | ||||
-rw-r--r-- | src/analyzer/analyzerebur128.h | 9 | ||||
-rw-r--r-- | src/analyzer/analyzergain.cpp | 41 | ||||
-rw-r--r-- | src/analyzer/analyzergain.h | 5 | ||||
-rw-r--r-- | src/analyzer/analyzerkey.cpp | 31 | ||||
-rw-r--r-- | src/analyzer/analyzerkey.h | 6 | ||||
-rw-r--r-- | src/analyzer/analyzersilence.cpp | 7 | ||||
-rw-r--r-- | src/analyzer/analyzersilence.h | 4 | ||||
-rw-r--r-- | src/analyzer/analyzerthread.cpp | 60 | ||||
-rw-r--r-- | src/analyzer/analyzerthread.h | 14 | ||||
-rw-r--r-- | src/analyzer/analyzerwaveform.cpp | 64 | ||||
-rw-r--r-- | src/analyzer/analyzerwaveform.h | 4 |
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); |