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 }