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