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 }