Mercurial > hg > qm-vamp-plugins
comparison plugins/AdaptiveSpectrogram.cpp @ 156:93355d263f8e
Add decimation factor to adaptive spectrogram
author | Chris Cannam <c.cannam@qmul.ac.uk> |
---|---|
date | Thu, 30 Jan 2014 10:04:06 +0000 |
parents | dcf5800f0f00 |
children | 3402a7a249a1 |
comparison
equal
deleted
inserted
replaced
155:46cee2d97bfc | 156:93355d263f8e |
---|---|
20 #include <cfloat> | 20 #include <cfloat> |
21 | 21 |
22 #include <iostream> | 22 #include <iostream> |
23 | 23 |
24 #include <dsp/transforms/FFT.h> | 24 #include <dsp/transforms/FFT.h> |
25 #include <dsp/rateconversion/Decimator.h> | |
25 | 26 |
26 using std::string; | 27 using std::string; |
27 using std::vector; | 28 using std::vector; |
28 using std::cerr; | 29 using std::cerr; |
29 using std::endl; | 30 using std::endl; |
36 Plugin(inputSampleRate), | 37 Plugin(inputSampleRate), |
37 m_w(8), | 38 m_w(8), |
38 m_n(2), | 39 m_n(2), |
39 m_coarse(false), | 40 m_coarse(false), |
40 m_threaded(true), | 41 m_threaded(true), |
41 m_threadsInUse(false) | 42 m_threadsInUse(false), |
43 m_decFactor(1), | |
44 m_buflen(0), | |
45 m_buffer(0), | |
46 m_decimator(0) | |
42 { | 47 { |
43 } | 48 } |
44 | 49 |
45 AdaptiveSpectrogram::~AdaptiveSpectrogram() | 50 AdaptiveSpectrogram::~AdaptiveSpectrogram() |
46 { | 51 { |
52 for (FFTMap::iterator i = m_fftThreads.begin(); | 57 for (FFTMap::iterator i = m_fftThreads.begin(); |
53 i != m_fftThreads.end(); ++i) { | 58 i != m_fftThreads.end(); ++i) { |
54 delete i->second; | 59 delete i->second; |
55 } | 60 } |
56 m_fftThreads.clear(); | 61 m_fftThreads.clear(); |
62 | |
63 delete[] m_buffer; | |
64 delete m_decimator; | |
57 } | 65 } |
58 | 66 |
59 string | 67 string |
60 AdaptiveSpectrogram::getIdentifier() const | 68 AdaptiveSpectrogram::getIdentifier() const |
61 { | 69 { |
81 } | 89 } |
82 | 90 |
83 int | 91 int |
84 AdaptiveSpectrogram::getPluginVersion() const | 92 AdaptiveSpectrogram::getPluginVersion() const |
85 { | 93 { |
86 return 1; | 94 return 2; |
87 } | 95 } |
88 | 96 |
89 string | 97 string |
90 AdaptiveSpectrogram::getCopyright() const | 98 AdaptiveSpectrogram::getCopyright() const |
91 { | 99 { |
93 } | 101 } |
94 | 102 |
95 size_t | 103 size_t |
96 AdaptiveSpectrogram::getPreferredStepSize() const | 104 AdaptiveSpectrogram::getPreferredStepSize() const |
97 { | 105 { |
98 return ((2 << m_w) << m_n) / 2; | 106 return getPreferredBlockSize(); |
99 } | 107 } |
100 | 108 |
101 size_t | 109 size_t |
102 AdaptiveSpectrogram::getPreferredBlockSize() const | 110 AdaptiveSpectrogram::getPreferredBlockSize() const |
103 { | 111 { |
104 return (2 << m_w) << m_n; | 112 // the /2 at the end is for 50% overlap (we handle framing ourselves) |
113 return ((2 << m_w) << m_n) * m_decFactor / 2; | |
105 } | 114 } |
106 | 115 |
107 bool | 116 bool |
108 AdaptiveSpectrogram::initialise(size_t channels, size_t stepSize, size_t blockSize) | 117 AdaptiveSpectrogram::initialise(size_t channels, size_t stepSize, size_t blockSize) |
109 { | 118 { |
110 if (channels < getMinChannelCount() || | 119 if (channels < getMinChannelCount() || |
111 channels > getMaxChannelCount()) return false; | 120 channels > getMaxChannelCount()) return false; |
112 | 121 |
122 if (blockSize != getPreferredBlockSize()) { | |
123 std::cerr << "AdaptiveSpectrogram::initialise: Block size " << blockSize << " does not match required block size of " << getPreferredBlockSize() << std::endl; | |
124 return false; | |
125 } | |
126 if (stepSize != getPreferredStepSize()) { | |
127 std::cerr << "AdaptiveSpectrogram::initialise: Step size " << stepSize << " does not match required step size of " << getPreferredStepSize() << std::endl; | |
128 return false; | |
129 } | |
130 | |
131 if (m_decFactor > 1) { | |
132 m_decimator = new Decimator(blockSize, m_decFactor); | |
133 } | |
134 | |
135 m_buflen = (blockSize * 2) / m_decFactor; // *2 for 50% overlap | |
136 m_buffer = new float[m_buflen]; | |
137 | |
138 reset(); | |
139 | |
113 return true; | 140 return true; |
114 } | 141 } |
115 | 142 |
116 void | 143 void |
117 AdaptiveSpectrogram::reset() | 144 AdaptiveSpectrogram::reset() |
118 { | 145 { |
119 | 146 if (m_decimator) m_decimator->resetFilter(); |
147 for (int i = 0; i < m_buflen; ++i) m_buffer[i] = 0.f; | |
120 } | 148 } |
121 | 149 |
122 AdaptiveSpectrogram::ParameterList | 150 AdaptiveSpectrogram::ParameterList |
123 AdaptiveSpectrogram::getParameterDescriptors() const | 151 AdaptiveSpectrogram::getParameterDescriptors() const |
124 { | 152 { |
161 desc2.valueNames.push_back("4096"); | 189 desc2.valueNames.push_back("4096"); |
162 desc2.valueNames.push_back("8192"); | 190 desc2.valueNames.push_back("8192"); |
163 desc2.valueNames.push_back("16384"); | 191 desc2.valueNames.push_back("16384"); |
164 list.push_back(desc2); | 192 list.push_back(desc2); |
165 | 193 |
194 desc2.identifier = "dec"; | |
195 desc2.name = "Decimation factor"; | |
196 desc2.description = "Factor to down-sample by, increasing speed but lowering maximum frequency"; | |
197 desc2.unit = ""; | |
198 desc2.minValue = 0; | |
199 desc2.maxValue = 3; | |
200 desc2.defaultValue = 0; | |
201 desc2.isQuantized = true; | |
202 desc2.quantizeStep = 1; | |
203 desc2.valueNames.clear(); | |
204 desc2.valueNames.push_back("No decimation"); | |
205 desc2.valueNames.push_back("2"); | |
206 desc2.valueNames.push_back("4"); | |
207 desc2.valueNames.push_back("8"); | |
208 list.push_back(desc2); | |
209 | |
166 ParameterDescriptor desc3; | 210 ParameterDescriptor desc3; |
167 desc3.identifier = "coarse"; | 211 desc3.identifier = "coarse"; |
168 desc3.name = "Omit alternate resolutions"; | 212 desc3.name = "Omit alternate resolutions"; |
169 desc3.description = "Generate a coarser spectrogram faster by excluding every alternate resolution (first and last resolution are always retained)"; | 213 desc3.description = "Generate a coarser spectrogram faster by excluding every alternate resolution (first and last resolution are always retained)"; |
170 desc3.unit = ""; | 214 desc3.unit = ""; |
194 { | 238 { |
195 if (id == "n") return m_n+1; | 239 if (id == "n") return m_n+1; |
196 else if (id == "w") return m_w+1; | 240 else if (id == "w") return m_w+1; |
197 else if (id == "threaded") return (m_threaded ? 1 : 0); | 241 else if (id == "threaded") return (m_threaded ? 1 : 0); |
198 else if (id == "coarse") return (m_coarse ? 1 : 0); | 242 else if (id == "coarse") return (m_coarse ? 1 : 0); |
243 else if (id == "dec") { | |
244 int f = m_decFactor; | |
245 int p = 0; | |
246 while (f > 1) { | |
247 f >>= 1; | |
248 p += 1; | |
249 } | |
250 return p; | |
251 } | |
199 return 0.f; | 252 return 0.f; |
200 } | 253 } |
201 | 254 |
202 void | 255 void |
203 AdaptiveSpectrogram::setParameter(std::string id, float value) | 256 AdaptiveSpectrogram::setParameter(std::string id, float value) |
210 if (w >= 1 && w <= 14) m_w = w-1; | 263 if (w >= 1 && w <= 14) m_w = w-1; |
211 } else if (id == "threaded") { | 264 } else if (id == "threaded") { |
212 m_threaded = (value > 0.5); | 265 m_threaded = (value > 0.5); |
213 } else if (id == "coarse") { | 266 } else if (id == "coarse") { |
214 m_coarse = (value > 0.5); | 267 m_coarse = (value > 0.5); |
268 } else if (id == "dec") { | |
269 int p = lrintf(value); | |
270 if (p >= 0 && p <= 3) m_decFactor = 1 << p; | |
215 } | 271 } |
216 } | 272 } |
217 | 273 |
218 AdaptiveSpectrogram::OutputList | 274 AdaptiveSpectrogram::OutputList |
219 AdaptiveSpectrogram::getOutputDescriptors() const | 275 AdaptiveSpectrogram::getOutputDescriptors() const |
224 d.identifier = "output"; | 280 d.identifier = "output"; |
225 d.name = "Output"; | 281 d.name = "Output"; |
226 d.description = "The output of the plugin"; | 282 d.description = "The output of the plugin"; |
227 d.unit = ""; | 283 d.unit = ""; |
228 d.hasFixedBinCount = true; | 284 d.hasFixedBinCount = true; |
229 d.binCount = getPreferredBlockSize() / 2; | 285 d.binCount = getPreferredBlockSize() / (m_decFactor * 2); |
230 d.hasKnownExtents = false; | 286 d.hasKnownExtents = false; |
231 d.isQuantized = false; | 287 d.isQuantized = false; |
232 d.sampleType = OutputDescriptor::FixedSampleRate; | 288 d.sampleType = OutputDescriptor::FixedSampleRate; |
233 d.sampleRate = m_inputSampleRate / ((2 << m_w) / 2); | 289 d.sampleRate = m_inputSampleRate / (m_decFactor * ((2 << m_w) / 2)); |
234 d.hasDuration = false; | 290 d.hasDuration = false; |
235 char name[20]; | 291 char name[20]; |
236 for (int i = 0; i < d.binCount; ++i) { | 292 for (int i = 0; i < d.binCount; ++i) { |
237 float freq = (m_inputSampleRate / (d.binCount * 2)) * (i + 1); // no DC bin | 293 float freq = (m_inputSampleRate / (m_decFactor * (d.binCount * 2)) * (i + 1)); // no DC bin |
238 sprintf(name, "%d Hz", int(freq)); | 294 sprintf(name, "%d Hz", int(freq)); |
239 d.binNames.push_back(name); | 295 d.binNames.push_back(name); |
240 } | 296 } |
241 list.push_back(d); | 297 list.push_back(d); |
242 | 298 |
251 } | 307 } |
252 | 308 |
253 AdaptiveSpectrogram::FeatureSet | 309 AdaptiveSpectrogram::FeatureSet |
254 AdaptiveSpectrogram::process(const float *const *inputBuffers, RealTime ts) | 310 AdaptiveSpectrogram::process(const float *const *inputBuffers, RealTime ts) |
255 { | 311 { |
312 // framing: shift and write the new data to right half | |
313 for (int i = 0; i < m_buflen/2; ++i) { | |
314 m_buffer[i] = m_buffer[m_buflen/2 + i]; | |
315 } | |
316 | |
317 if (m_decFactor == 1) { | |
318 for (int i = 0; i < m_buflen/2; ++i) { | |
319 m_buffer[m_buflen/2 + i] = inputBuffers[0][i]; | |
320 } | |
321 } else { | |
322 m_decimator->process(inputBuffers[0], m_buffer + m_buflen/2); | |
323 } | |
324 | |
256 FeatureSet fs; | 325 FeatureSet fs; |
257 | 326 |
258 int minwid = (2 << m_w), maxwid = ((2 << m_w) << m_n); | 327 int minwid = (2 << m_w), maxwid = ((2 << m_w) << m_n); |
259 | 328 |
260 #ifdef DEBUG_VERBOSE | 329 #ifdef DEBUG_VERBOSE |
277 | 346 |
278 if (m_fftThreads.find(w) == m_fftThreads.end()) { | 347 if (m_fftThreads.find(w) == m_fftThreads.end()) { |
279 m_fftThreads[w] = new FFTThread(w); | 348 m_fftThreads[w] = new FFTThread(w); |
280 } | 349 } |
281 if (m_threaded) { | 350 if (m_threaded) { |
282 m_fftThreads[w]->startCalculation | 351 m_fftThreads[w]->startCalculation(m_buffer, s, index, maxwid); |
283 (inputBuffers[0], s, index, maxwid); | |
284 } else { | 352 } else { |
285 m_fftThreads[w]->setParameters | 353 m_fftThreads[w]->setParameters(m_buffer, s, index, maxwid); |
286 (inputBuffers[0], s, index, maxwid); | |
287 m_fftThreads[w]->performTask(); | 354 m_fftThreads[w]->performTask(); |
288 } | 355 } |
289 w *= 2; | 356 w *= 2; |
290 ++index; | 357 ++index; |
291 } | 358 } |