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