Krotos Modules 3
Loading...
Searching...
No Matches
SuperFluxOnsetDetection.cpp
Go to the documentation of this file.
1namespace krotos
2{
3 SuperFluxOnsetDetection::SuperFluxOnsetDetection(std::vector<std::vector<float>>& logSpectrum, float sampleRate,
4 int hopSize)
5 {
6 m_sampleRate = sampleRate;
7 m_hopSize = hopSize;
8 m_inputLogSpectrum = logSpectrum;
9 setParametersMS(30e-3f, 30e-3f, 100e-3f, 70e-3f, 30e-3f);
10 }
11
12 void SuperFluxOnsetDetection::setParametersMS(float preMax, float postMax, float preAvg, float postAvg,
13 float combWidth)
14 {
15 jassert(m_sampleRate > 0 && m_hopSize > 0);
16
17 // Convert to number of samples from milisec
18 m_preMaxFrames = std::lround(preMax * m_sampleRate / static_cast<float>(m_hopSize));
19 m_postMaxFrames = std::lround(postMax * m_sampleRate / static_cast<float>(m_hopSize));
20 m_preAvgFrames = std::lround(preAvg * m_sampleRate / static_cast<float>(m_hopSize));
21 m_postAvgFrames = std::lround(postAvg * m_sampleRate / static_cast<float>(m_hopSize));
22 m_combWidthFrames = std::lround(combWidth * m_sampleRate / static_cast<float>(m_hopSize));
23 }
24
25 void SuperFluxOnsetDetection::setDeltaPercentage(float deltaPrcnt) { m_deltaPrcnt = deltaPrcnt; }
26
27 std::vector<float> SuperFluxOnsetDetection::trajectoryTracking(std::vector<std::vector<float>> logSpectrum)
28 {
29 // Apply maximum Filter of length 3
30 m_numBands = static_cast<int>(logSpectrum.size());
31 m_numFrames = static_cast<int>(logSpectrum[0].size());
32
33 // Widen the spectro in freq dimension by reflecting beginning and end
34 // beginning
35 logSpectrum.insert(std::begin(logSpectrum), logSpectrum.at(1));
36 // end
37 logSpectrum.insert(std::end(logSpectrum), std::end(logSpectrum)[-2]);
38
39 // Maximum Filtered Spectrogram
40 std::vector<float> maxLogSpectrum(m_numBands * m_numFrames);
41
42 for (int j = 0; j < m_numFrames; j++)
43 {
44 for (int i = 0; i < m_numBands; i++)
45 {
46 std::vector<float> subVec = {logSpectrum[i][j], logSpectrum[i + 1][j], logSpectrum[i + 2][j]};
47 // Apply max filter
48 float max = *std::max_element(std::begin(subVec), std::end(subVec));
49 maxLogSpectrum[i * m_numFrames + j] = max;
50 }
51 }
52
53 return maxLogSpectrum;
54 }
55
57 const std::vector<std::vector<float>>& logSpectrum, const std::vector<float>& maxLogSpectum)
58 {
59 float diffFlat = 0.0f;
60 // Detection function Vector
61 std::vector<float> detectionFunctionFlat(m_numFrames);
62 // Calculate difference for each band per frame
63 for (int j = mi; j < m_numFrames; j++)
64 {
65 for (int i = 0; i < m_numBands; i++)
66 {
67 diffFlat += halfWaveRect(logSpectrum[i][j] - maxLogSpectum[i * m_numFrames + (j - mi)]);
68 }
69
70 detectionFunctionFlat[j] = diffFlat;
71 diffFlat = 0.0f;
72 }
73
74 return detectionFunctionFlat;
75 }
76
77 std::vector<int> SuperFluxOnsetDetection::peakPicking(std::vector<float> detectionFunction)
78 {
79 size_t detectionSize = detectionFunction.size();
80
81 // Moving maximum vector calculation
82 auto movingMaxVec = movingMax(detectionFunction);
83
84 // Moving average vector calculation
85 auto movingMeanVec = movingMean(detectionFunction);
86
87 // if this hits something went wrong, probably weird parameters!!!
88 jassert(movingMaxVec.size() == detectionSize && movingMeanVec.size() == detectionSize);
89
90 // Set delta
91 float maxDetect = *std::max_element(std::begin(detectionFunction), std::end(detectionFunction));
92 float minDetect = *std::min_element(std::begin(detectionFunction), std::end(detectionFunction));
93 float delta = m_deltaPrcnt * ((maxDetect - minDetect) / 2.0f);
94
95 // Find positions of max > mean + delta
96 std::vector<int> allOnsets;
97 for (int i = 0; i < detectionSize; i++)
98 {
99 // peak picking condition
100 if (movingMaxVec[i] >= movingMeanVec[i] + delta)
101 {
102 allOnsets.push_back(i);
103 }
104 }
105
106 // Caclulate differences in positions between all onset frames
107 std::vector<int> onsetPositions;
108 // adjacent_difference(allOnsets.std::begin(), allOnsets.std::end(),
109 // differences.std::begin());
110
111 for (int i = 1; i < allOnsets.size(); i++)
112 {
113 // Keep only positions that are distanced more than combWidth
114 if (allOnsets[i] - allOnsets[i - 1] > m_combWidthFrames)
115 {
116 onsetPositions.push_back(allOnsets[i] * m_hopSize);
117 }
118 }
119
120 // Add 1st onsetFrame
121 onsetPositions.insert(std::begin(onsetPositions), allOnsets[1] * m_hopSize);
122 // Add 1st sample
123 onsetPositions.insert(std::begin(onsetPositions), 0);
124
125 return onsetPositions;
126 }
127
128 std::vector<float> SuperFluxOnsetDetection::movingMax(std::vector<float> detectionFunction)
129 {
130 size_t length = detectionFunction.size();
131 // Extend the detection function by reflecting beginning and end
132
133 // extract beginning subVector
134 std::vector<float>::const_iterator first = std::begin(detectionFunction) + 1;
135 std::vector<float>::const_iterator last = first + m_preMaxFrames;
136 std::vector<float> subVecStart(first, last);
137 // reverse it
138 std::reverse(std::begin(subVecStart), std::end(subVecStart));
139 // concatenate at beginning
140 detectionFunction.insert(std::begin(detectionFunction), std::begin(subVecStart), std::end(subVecStart));
141
142 // extract end subVector
143 first = std::end(detectionFunction) - 1 - m_postMaxFrames;
144 last = std::end(detectionFunction) - 1;
145 std::vector<float> subVecEnd(first, last);
146 // reverse it
147 std::reverse(std::begin(subVecEnd), std::end(subVecEnd));
148 // concatenate at end
149 detectionFunction.insert(std::end(detectionFunction), std::begin(subVecEnd), std::end(subVecEnd));
150
151 std::vector<float> movMax(length);
152
153 // Iterate through the detect function,calculate the moving max
154 for (int i = m_preMaxFrames; i < detectionFunction.size() - m_postMaxFrames; i++)
155 {
156 // extract subVector
157 std::vector<float>::const_iterator start = std::begin(detectionFunction) + i - m_preMaxFrames;
158 std::vector<float>::const_iterator finish = start + m_postMaxFrames;
159 std::vector<float> subVec(start, finish);
160 // maximum
161 movMax.at(i - m_preMaxFrames) = *std::max_element(std::begin(subVec), std::end(subVec));
162 }
163
164 return movMax;
165 }
166
167 std::vector<float> SuperFluxOnsetDetection::movingMean(std::vector<float> detectionFunction)
168 {
169 size_t length = detectionFunction.size();
170
171 // Extend the detection function by reflecting beginning and end
172 // extract beginning subVector
173 std::vector<float>::const_iterator first = std::begin(detectionFunction) + 1;
174 std::vector<float>::const_iterator last = first + m_preAvgFrames;
175 std::vector<float> subVecStart(first, last);
176 // reverse it
177 std::reverse(std::begin(subVecStart), std::begin(subVecStart));
178 // concatenate at beginning
179 detectionFunction.insert(std::begin(detectionFunction), std::begin(subVecStart), std::end(subVecStart));
180
181 // extract end subVector
182 first = std::end(detectionFunction) - 1 - m_postAvgFrames;
183 last = std::end(detectionFunction) - 1;
184 std::vector<float> subVecEnd(first, last);
185 // reverse it
186 std::reverse(std::begin(subVecEnd), std::end(subVecEnd));
187 // concatenate at end
188 detectionFunction.insert(std::end(detectionFunction), std::begin(subVecEnd), std::end(subVecEnd));
189
190 std::vector<float> movMean(length);
191 float count = static_cast<float>(m_preAvgFrames + m_postAvgFrames + 1);
192 // Iterate through the detect function,calculate the moving max
193 for (int i = m_preAvgFrames; i < detectionFunction.size() - m_postAvgFrames; i++)
194 {
195 // extract subVector
196 std::vector<float>::const_iterator start = std::begin(detectionFunction) + i - m_preAvgFrames;
197 std::vector<float>::const_iterator finish = start + m_postAvgFrames;
198 std::vector<float> subVec(start, finish);
199 // mean
200 movMean.at(i - m_preAvgFrames) = std::accumulate(std::begin(subVec), std::end(subVec), 0.0f) / count;
201 }
202
203 return movMean;
204 }
205
207 {
208 auto maxLogSpectrum = trajectoryTracking(m_inputLogSpectrum);
209 auto detectionFunction = calculateDetectionFunction(m_inputLogSpectrum, maxLogSpectrum);
210 std::vector<int> onsetPositions = peakPicking(detectionFunction);
211
212 return onsetPositions;
213 }
214
215} // namespace krotos
std::vector< float > calculateDetectionFunction(const std::vector< std::vector< float > > &logSpectrum, const std::vector< float > &maxLogSpectum)
Definition SuperFluxOnsetDetection.cpp:56
void setParametersMS(float preMax, float postMax, float preAvg, float postAvg, float combWidth)
Definition SuperFluxOnsetDetection.cpp:12
std::vector< float > movingMean(std::vector< float > detectionFunction)
Definition SuperFluxOnsetDetection.cpp:167
int m_numBands
Definition SuperFluxOnsetDetection.h:97
float m_sampleRate
Definition SuperFluxOnsetDetection.h:99
int m_combWidthFrames
Definition SuperFluxOnsetDetection.h:93
std::vector< int > findOnsetsInSamples()
Definition SuperFluxOnsetDetection.cpp:206
int m_numFrames
Definition SuperFluxOnsetDetection.h:98
float halfWaveRect(float x)
Definition SuperFluxOnsetDetection.h:75
int m_preMaxFrames
Definition SuperFluxOnsetDetection.h:89
const int mi
Definition SuperFluxOnsetDetection.h:96
int m_preAvgFrames
Definition SuperFluxOnsetDetection.h:91
std::vector< std::vector< float > > m_inputLogSpectrum
Definition SuperFluxOnsetDetection.h:83
SuperFluxOnsetDetection(std::vector< std::vector< float > > &logSpectrum, float sampleRate, int hopSize)
Definition SuperFluxOnsetDetection.cpp:3
void setDeltaPercentage(float deltaPrcnt)
Definition SuperFluxOnsetDetection.cpp:25
int m_postMaxFrames
Definition SuperFluxOnsetDetection.h:90
std::vector< int > peakPicking(std::vector< float > detectionFunction)
Definition SuperFluxOnsetDetection.cpp:77
std::vector< float > movingMax(std::vector< float > detectionFunction)
Definition SuperFluxOnsetDetection.cpp:128
int m_postAvgFrames
Definition SuperFluxOnsetDetection.h:92
std::vector< float > trajectoryTracking(std::vector< std::vector< float > > logSpectrum)
Definition SuperFluxOnsetDetection.cpp:27
float m_deltaPrcnt
Definition SuperFluxOnsetDetection.h:87
int m_hopSize
Definition SuperFluxOnsetDetection.h:100
Definition AirAbsorptionFilter.cpp:2