Mercurial > hg > vamp-tempogram
comparison Tempogram.cpp @ 13:7680cc4c0073
* Tidying - made length of array variables type size_t and for loops unsigned int, where index > 0.
* Window length parameter is now a dropdown box.
author | Carl Bussey <c.bussey@se10.qmul.ac.uk> |
---|---|
date | Wed, 13 Aug 2014 14:18:00 +0100 |
parents | 09fb76606b2b |
children |
comparison
equal
deleted
inserted
replaced
12:d58409ecd720 | 13:7680cc4c0073 |
---|---|
14 | 14 |
15 Tempogram::Tempogram(float inputSampleRate) : | 15 Tempogram::Tempogram(float inputSampleRate) : |
16 Plugin(inputSampleRate), | 16 Plugin(inputSampleRate), |
17 m_blockSize(0), | 17 m_blockSize(0), |
18 m_stepSize(0), | 18 m_stepSize(0), |
19 compressionConstant(1000), //parameter | 19 m_compressionConstant(1000), //parameter |
20 minDB(0), | 20 m_minDB(0), |
21 windowLength(128), //parameter | 21 m_log2WindowLength(10), |
22 fftLength(4096), //parameter | 22 m_windowLength(pow((float)2,(float)m_log2WindowLength)), //parameter |
23 thopSize(64), //parameter | 23 m_fftLength(4096), //parameter |
24 minBPM(30), | 24 m_hopSize(64), //parameter |
25 maxBPM(480), | 25 m_minBPM(30), |
26 minBin(0), //set in initialise() | 26 m_maxBPM(480), |
27 maxBin(0), //set in initialise() | 27 m_minBin(0), //set in initialise() |
28 numberOfBlocks(0) //incremented in process() | 28 m_maxBin(0), //set in initialise() |
29 m_numberOfBlocks(0) //incremented in process() | |
29 | 30 |
30 // Also be sure to set your plugin parameters (presumably stored | 31 // Also be sure to set your plugin parameters (presumably stored |
31 // in member variables) to their default values here -- the host | 32 // in member variables) to their default values here -- the host |
32 // will not do that for you | 33 // will not do that for you |
33 { | 34 { |
140 d.maxValue = 10000; | 141 d.maxValue = 10000; |
141 d.defaultValue = 1000; | 142 d.defaultValue = 1000; |
142 d.isQuantized = false; | 143 d.isQuantized = false; |
143 list.push_back(d); | 144 list.push_back(d); |
144 | 145 |
145 d.identifier = "TN"; | 146 d.identifier = "log2TN"; |
146 d.name = "Tempogram Window Length"; | 147 d.name = "Tempogram Window Length"; |
147 d.description = "FFT window length when analysing the novelty curve and extracting the tempogram time-frequency function."; | 148 d.description = "FFT window length when analysing the novelty curve and extracting the tempogram time-frequency function."; |
148 d.unit = ""; | 149 d.unit = ""; |
149 d.minValue = 1024; | 150 d.minValue = 7; |
150 d.maxValue = 4096; | 151 d.maxValue = 12; |
151 d.defaultValue = 128; | 152 d.defaultValue = 10; |
152 d.isQuantized = true; | 153 d.isQuantized = true; |
153 d.quantizeStep = 128; | 154 d.quantizeStep = 1; |
155 for (int i = d.minValue; i <= d.maxValue; i++){ | |
156 d.valueNames.push_back(floatToString(pow((float)2,(float)i))); | |
157 } | |
154 list.push_back(d); | 158 list.push_back(d); |
155 | 159 |
156 d.identifier = "minBPM"; | 160 d.identifier = "minBPM"; |
157 d.name = "Minimum BPM"; | 161 d.name = "Minimum BPM"; |
158 d.description = "The minimum BPM of the tempogram output bins."; | 162 d.description = "The minimum BPM of the tempogram output bins."; |
180 | 184 |
181 float | 185 float |
182 Tempogram::getParameter(string identifier) const | 186 Tempogram::getParameter(string identifier) const |
183 { | 187 { |
184 if (identifier == "C") { | 188 if (identifier == "C") { |
185 return compressionConstant; // return the ACTUAL current value of your parameter here! | 189 return m_compressionConstant; // return the ACTUAL current value of your parameter here! |
186 } | 190 } |
187 if (identifier == "TN"){ | 191 if (identifier == "log2TN"){ |
188 return windowLength; | 192 return m_log2WindowLength; |
189 } | 193 } |
190 if (identifier == "minBPM") { | 194 if (identifier == "minBPM") { |
191 return minBPM; | 195 return m_minBPM; |
192 } | 196 } |
193 if (identifier == "maxBPM"){ | 197 if (identifier == "maxBPM"){ |
194 return maxBPM; | 198 return m_maxBPM; |
195 } | 199 } |
196 | 200 |
197 return 0; | 201 return 0; |
198 } | 202 } |
199 | 203 |
200 void | 204 void |
201 Tempogram::setParameter(string identifier, float value) | 205 Tempogram::setParameter(string identifier, float value) |
202 { | 206 { |
203 | 207 |
204 if (identifier == "C") { | 208 if (identifier == "C") { |
205 compressionConstant = value; // set the actual value of your parameter | 209 m_compressionConstant = value; // set the actual value of your parameter |
206 } | 210 } |
207 if (identifier == "TN") { | 211 if (identifier == "log2TN") { |
208 windowLength = value; | 212 m_windowLength = pow(2,value); |
213 m_log2WindowLength = value; | |
209 } | 214 } |
210 if (identifier == "minBPM") { | 215 if (identifier == "minBPM") { |
211 minBPM = value; | 216 m_minBPM = value; |
212 } | 217 } |
213 if (identifier == "maxBPM"){ | 218 if (identifier == "maxBPM"){ |
214 maxBPM = value; | 219 m_maxBPM = value; |
215 } | 220 } |
216 | 221 |
217 } | 222 } |
218 | 223 |
219 void Tempogram::updateBPMParameters(){ | 224 void Tempogram::updateBPMParameters(){ |
265 d.identifier = "tempogram"; | 270 d.identifier = "tempogram"; |
266 d.name = "Tempogram"; | 271 d.name = "Tempogram"; |
267 d.description = "Tempogram"; | 272 d.description = "Tempogram"; |
268 d.unit = "BPM"; | 273 d.unit = "BPM"; |
269 d.hasFixedBinCount = true; | 274 d.hasFixedBinCount = true; |
270 d.binCount = maxBin - minBin + 1; | 275 d.binCount = m_maxBin - m_minBin + 1; |
271 d.hasKnownExtents = false; | 276 d.hasKnownExtents = false; |
272 d.isQuantized = false; | 277 d.isQuantized = false; |
273 d.sampleType = OutputDescriptor::FixedSampleRate; | 278 d.sampleType = OutputDescriptor::FixedSampleRate; |
274 d_sampleRate = tempogramInputSampleRate/thopSize; | 279 d_sampleRate = tempogramInputSampleRate/m_hopSize; |
275 d.sampleRate = d_sampleRate > 0.0 && !isnan(d_sampleRate) ? d_sampleRate : 0.0; | 280 d.sampleRate = d_sampleRate > 0.0 && !isnan(d_sampleRate) ? d_sampleRate : 0.0; |
276 for(int i = minBin; i <= maxBin; i++){ | 281 for(int i = m_minBin; i <= (int)m_maxBin; i++){ |
277 float w = ((float)i/fftLength)*(tempogramInputSampleRate); | 282 float w = ((float)i/m_fftLength)*(tempogramInputSampleRate); |
278 d.binNames.push_back(floatToString(w*60)); | 283 d.binNames.push_back(floatToString(w*60)); |
279 } | 284 } |
280 d.hasDuration = false; | 285 d.hasDuration = false; |
281 list.push_back(d); | 286 list.push_back(d); |
282 | 287 |
304 channels > getMaxChannelCount()) return false; | 309 channels > getMaxChannelCount()) return false; |
305 | 310 |
306 // Real initialisation work goes here! | 311 // Real initialisation work goes here! |
307 m_blockSize = blockSize; | 312 m_blockSize = blockSize; |
308 m_stepSize = stepSize; | 313 m_stepSize = stepSize; |
309 minDB = pow(10,(float)-74/20); | 314 m_minDB = pow(10,(float)-74/20); |
310 | 315 |
311 if (minBPM > maxBPM){ | 316 if (m_minBPM > m_maxBPM){ |
312 minBPM = 30; | 317 m_minBPM = 30; |
313 maxBPM = 480; | 318 m_maxBPM = 480; |
314 } | 319 } |
315 float tempogramInputSampleRate = (float)m_inputSampleRate/m_stepSize; | 320 float tempogramInputSampleRate = (float)m_inputSampleRate/m_stepSize; |
316 minBin = (unsigned int)(max(floor(((minBPM/60)/tempogramInputSampleRate)*fftLength), (float)0.0)); | 321 m_minBin = (unsigned int)(max(floor(((m_minBPM/60)/tempogramInputSampleRate)*m_fftLength), (float)0.0)); |
317 maxBin = (unsigned int)(min(ceil(((maxBPM/60)/tempogramInputSampleRate)*fftLength), (float)fftLength/2)); | 322 m_maxBin = (unsigned int)(min(ceil(((m_maxBPM/60)/tempogramInputSampleRate)*m_fftLength), (float)m_fftLength/2)); |
318 | 323 |
319 specData = vector< vector<float> >(m_blockSize/2 + 1); | 324 m_spectrogram = vector< vector<float> >(m_blockSize/2 + 1); |
320 | 325 |
321 return true; | 326 return true; |
322 } | 327 } |
323 | 328 |
324 void Tempogram::cleanup(){ | 329 void Tempogram::cleanup(){ |
328 void | 333 void |
329 Tempogram::reset() | 334 Tempogram::reset() |
330 { | 335 { |
331 // Clear buffers, reset stored values, etc | 336 // Clear buffers, reset stored values, etc |
332 ncTimestamps.clear(); | 337 ncTimestamps.clear(); |
333 specData.clear(); | 338 m_spectrogram.clear(); |
334 specData = vector< vector<float> >(m_blockSize/2 + 1); | 339 m_spectrogram = vector< vector<float> >(m_blockSize/2 + 1); |
335 } | 340 } |
336 | 341 |
337 Tempogram::FeatureSet | 342 Tempogram::FeatureSet |
338 Tempogram::process(const float *const *inputBuffers, Vamp::RealTime timestamp) | 343 Tempogram::process(const float *const *inputBuffers, Vamp::RealTime timestamp) |
339 { | 344 { |
343 Feature feature; | 348 Feature feature; |
344 | 349 |
345 const float *in = inputBuffers[0]; | 350 const float *in = inputBuffers[0]; |
346 | 351 |
347 //calculate magnitude of FrequencyDomain input | 352 //calculate magnitude of FrequencyDomain input |
348 for (int i = 0; i < n; i++){ | 353 for (unsigned int i = 0; i < n; i++){ |
349 float magnitude = sqrt(in[2*i] * in[2*i] + in[2*i + 1] * in[2*i + 1]); | 354 float magnitude = sqrt(in[2*i] * in[2*i] + in[2*i + 1] * in[2*i + 1]); |
350 magnitude = magnitude > minDB ? magnitude : minDB; | 355 magnitude = magnitude > m_minDB ? magnitude : m_minDB; |
351 specData[i].push_back(magnitude); | 356 m_spectrogram[i].push_back(magnitude); |
352 } | 357 } |
353 | 358 |
354 numberOfBlocks++; | 359 m_numberOfBlocks++; |
355 ncTimestamps.push_back(timestamp); //save timestamp | 360 ncTimestamps.push_back(timestamp); //save timestamp |
356 | 361 |
357 return featureSet; | 362 return featureSet; |
358 } | 363 } |
359 | 364 |
360 Tempogram::FeatureSet | 365 Tempogram::FeatureSet |
361 Tempogram::getRemainingFeatures() | 366 Tempogram::getRemainingFeatures() |
362 { | 367 { |
363 | 368 |
364 float * hannWindowtN = new float[windowLength]; | 369 float * hannWindowtN = new float[m_windowLength]; |
365 for (int i = 0; i < windowLength; i++){ | 370 for (unsigned int i = 0; i < m_windowLength; i++){ |
366 hannWindowtN[i] = 0.0; | 371 hannWindowtN[i] = 0.0; |
367 } | 372 } |
368 | 373 |
369 FeatureSet featureSet; | 374 FeatureSet featureSet; |
370 | 375 |
371 //initialise noveltycurve processor | 376 //initialise m_noveltyCurve processor |
372 NoveltyCurve nc(m_inputSampleRate, m_blockSize, numberOfBlocks, compressionConstant); | 377 NoveltyCurve nc(m_inputSampleRate, m_blockSize, m_numberOfBlocks, m_compressionConstant); |
373 noveltyCurve = nc.spectrogramToNoveltyCurve(specData); //calculate novelty curve from magnitude data | 378 m_noveltyCurve = nc.spectrogramToNoveltyCurve(m_spectrogram); //calculate novelty curve from magnitude data |
374 | 379 |
375 //push novelty curve data to featureset 1 and set timestamps | 380 //push novelty curve data to featureset 1 and set timestamps |
376 for (int i = 0; i < numberOfBlocks; i++){ | 381 for (unsigned int i = 0; i < m_numberOfBlocks; i++){ |
377 Feature feature; | 382 Feature feature; |
378 feature.values.push_back(noveltyCurve[i]); | 383 feature.values.push_back(m_noveltyCurve[i]); |
379 feature.hasTimestamp = true; | 384 feature.hasTimestamp = true; |
380 feature.timestamp = ncTimestamps[i]; | 385 feature.timestamp = ncTimestamps[i]; |
381 featureSet[1].push_back(feature); | 386 featureSet[1].push_back(feature); |
382 } | 387 } |
383 | 388 |
384 //window function for spectrogram | 389 //window function for spectrogram |
385 WindowFunction::hanning(hannWindowtN,windowLength); | 390 WindowFunction::hanning(hannWindowtN,m_windowLength); |
386 | 391 |
387 //initialise spectrogram processor | 392 //initialise spectrogram processor |
388 SpectrogramProcessor spectrogramProcessor(numberOfBlocks, windowLength, fftLength, thopSize); | 393 SpectrogramProcessor spectrogramProcessor(m_numberOfBlocks, m_windowLength, m_fftLength, m_hopSize); |
389 //compute spectrogram from novelty curve data (i.e., tempogram) | 394 //compute spectrogram from novelty curve data (i.e., tempogram) |
390 vector< vector<float> > tempogram = spectrogramProcessor.process(&noveltyCurve[0], hannWindowtN); | 395 Spectrogram tempogram = spectrogramProcessor.process(&m_noveltyCurve[0], hannWindowtN); |
391 | 396 |
392 int timePointer = thopSize-windowLength/2; | 397 int timePointer = m_hopSize-m_windowLength/2; |
393 int tempogramLength = tempogram[0].size(); | 398 int tempogramLength = tempogram[0].size(); |
394 | 399 |
395 //push tempogram data to featureset 0 and set timestamps. | 400 //push tempogram data to featureset 0 and set timestamps. |
396 for (int block = 0; block < tempogramLength; block++){ | 401 for (int block = 0; block < tempogramLength; block++){ |
397 Feature feature; | 402 Feature feature; |
398 | 403 |
399 int timeMS = floor(1000*(m_stepSize*timePointer)/m_inputSampleRate + 0.5); | 404 int timeMS = floor(1000*(m_stepSize*timePointer)/m_inputSampleRate + 0.5); |
400 | 405 |
401 assert(tempogram.size() == (fftLength/2 + 1)); | 406 assert(tempogram.size() == (m_fftLength/2 + 1)); |
402 for(int k = minBin; k < maxBin; k++){ | 407 for(int k = m_minBin; k < (int)m_maxBin; k++){ |
403 feature.values.push_back(tempogram[k][block]); | 408 feature.values.push_back(tempogram[k][block]); |
409 //cout << tempogram[k][block] << endl; | |
404 } | 410 } |
405 feature.hasTimestamp = true; | 411 feature.hasTimestamp = true; |
406 feature.timestamp = RealTime::fromMilliseconds(timeMS); | 412 feature.timestamp = RealTime::fromMilliseconds(timeMS); |
407 featureSet[0].push_back(feature); | 413 featureSet[0].push_back(feature); |
408 | 414 |
409 timePointer += thopSize; | 415 timePointer += m_hopSize; |
410 } | 416 } |
411 | 417 |
412 //float func = [](){ cout << "Hello"; }; | 418 //float func = [](){ cout << "Hello"; }; |
413 | 419 |
414 delete []hannWindowtN; | 420 delete []hannWindowtN; |
415 hannWindowtN = NULL; | 421 hannWindowtN = 0; |
416 | 422 |
417 return featureSet; | 423 return featureSet; |
418 } | 424 } |