1 #pragma once 2 3 #include "util/assert.h" 4 #include "util/types.h" 5 6 /* 7 * An Analyzer is an object which wants to process an entire song to 8 * calculate some kind of metadata about it. This could be bpm, the 9 * summary, key or something else crazy. This is to help consolidate the 10 * many different threads currently processing the whole track in Mixxx on load. 11 * -- Adam 12 */ 13 14 #include "track/track_decl.h" 15 16 class Analyzer { 17 public: 18 virtual ~Analyzer() = default; 19 20 // This method is supposed to: 21 // 1. Check if the track needs to be analyzed, otherwise return false. 22 // 2. Perform the initialization and return true on success. 23 // 3. If the initialization failed log the internal error and return false. 24 virtual bool initialize(TrackPointer tio, int sampleRate, int totalSamples) = 0; 25 26 ///////////////////////////////////////////////////////////////////////// 27 // All following methods will only be invoked after initialize() 28 // returned true! 29 ///////////////////////////////////////////////////////////////////////// 30 31 // Analyze the next chunk of audio samples and return true if successful. 32 // If processing fails the analysis can be aborted early by returning 33 // false. After aborting the analysis only cleanup() will be invoked, 34 // but not finalize()! 35 virtual bool processSamples(const CSAMPLE* pIn, const int iLen) = 0; 36 37 // Update the track object with the analysis results after 38 // processing finished successfully, i.e. all available audio 39 // samples have been processed. 40 virtual void storeResults(TrackPointer tio) = 0; 41 42 // Discard any temporary results or free allocated memory. 43 // This function will be invoked after the results have been 44 // stored or if processing aborted preliminary. 45 virtual void cleanup() = 0; 46 }; 47 48 typedef std::unique_ptr<Analyzer> AnalyzerPtr; 49 50 class AnalyzerWithState final { 51 public: AnalyzerWithState(AnalyzerPtr analyzer)52 explicit AnalyzerWithState(AnalyzerPtr analyzer) 53 : m_analyzer(std::move(analyzer)), 54 m_active(false) { 55 DEBUG_ASSERT(m_analyzer); 56 } 57 AnalyzerWithState(const AnalyzerWithState&) = delete; 58 AnalyzerWithState(AnalyzerWithState&&) = default; ~AnalyzerWithState()59 ~AnalyzerWithState() { 60 VERIFY_OR_DEBUG_ASSERT(!m_active) { 61 m_analyzer->cleanup(); 62 } 63 } 64 isActive()65 bool isActive() const { 66 return m_active; 67 } 68 initialize(TrackPointer tio,int sampleRate,int totalSamples)69 bool initialize(TrackPointer tio, int sampleRate, int totalSamples) { 70 DEBUG_ASSERT(!m_active); 71 return m_active = m_analyzer->initialize(tio, sampleRate, totalSamples); 72 } 73 processSamples(const CSAMPLE * pIn,const int iLen)74 void processSamples(const CSAMPLE* pIn, const int iLen) { 75 if (m_active) { 76 m_active = m_analyzer->processSamples(pIn, iLen); 77 if (!m_active) { 78 // Ensure that cleanup() is invoked after processing 79 // failed and the analyzer became inactive! 80 m_analyzer->cleanup(); 81 } 82 } 83 } 84 finish(TrackPointer tio)85 void finish(TrackPointer tio) { 86 if (m_active) { 87 m_analyzer->storeResults(tio); 88 m_analyzer->cleanup(); 89 m_active = false; 90 } 91 } 92 cancel()93 void cancel() { 94 if (m_active) { 95 m_analyzer->cleanup(); 96 m_active = false; 97 } 98 } 99 100 private: 101 AnalyzerPtr m_analyzer; 102 bool m_active; 103 }; 104