comparison Tempogram.cpp @ 7:21147df9cb2d

* Error when deleting Spectrogram object in Tempogram::getRemainingFeatures(). * Moved Spectrogram computation into own class.
author Carl Bussey <c.bussey@se10.qmul.ac.uk>
date Thu, 07 Aug 2014 16:21:21 +0100
parents 597f033fa7a2
children 4e429b9f2b4d
comparison
equal deleted inserted replaced
6:14a143a2c4c9 7:21147df9cb2d
3 // libraries. Replace MyPlugin and myPlugin throughout with the name 3 // libraries. Replace MyPlugin and myPlugin throughout with the name
4 // of your first plugin class, and fill in the gaps as appropriate. 4 // of your first plugin class, and fill in the gaps as appropriate.
5 5
6 6
7 #include "Tempogram.h" 7 #include "Tempogram.h"
8 #include "FIRFilter.h"
9 #include "WindowFunction.h"
10 #include "NoveltyCurve.h"
11 #include <vamp-sdk/FFT.h>
12 #include <cmath>
13 #include <fstream>
14 #include <assert.h>
15 8
16 using Vamp::FFT; 9 using Vamp::FFT;
10 using Vamp::RealTime;
17 using namespace std; 11 using namespace std;
18 12
19 Tempogram::Tempogram(float inputSampleRate) : 13 Tempogram::Tempogram(float inputSampleRate) :
20 Plugin(inputSampleRate), 14 Plugin(inputSampleRate),
21 m_blockSize(0), 15 m_blockSize(0),
22 m_stepSize(0), 16 m_stepSize(0),
23 compressionConstant(1000), //make param 17 compressionConstant(1000), //make param
24 specMax(0), 18 specMax(0),
25 previousY(NULL),
26 currentY(NULL),
27 spectrogram(NULL),
28 minDB(0), 19 minDB(0),
29 tN(256), //make param 20 tN(128), //make param
30 thopSize(128), //make param 21 thopSize(64), //make param
31 fftInput(NULL), 22 fftInput(NULL),
32 fftOutputReal(NULL), 23 fftOutputReal(NULL),
33 fftOutputImag(NULL), 24 fftOutputImag(NULL),
34 numberOfBlocks(0) 25 numberOfBlocks(0)
35 26
40 } 31 }
41 32
42 Tempogram::~Tempogram() 33 Tempogram::~Tempogram()
43 { 34 {
44 //delete stuff 35 //delete stuff
36 cleanup();
45 } 37 }
46 38
47 string 39 string
48 Tempogram::getIdentifier() const 40 Tempogram::getIdentifier() const
49 { 41 {
152 tN.name = "Tempogram FFT length"; 144 tN.name = "Tempogram FFT length";
153 tN.description = "Tempogram FFT length."; 145 tN.description = "Tempogram FFT length.";
154 tN.unit = ""; 146 tN.unit = "";
155 tN.minValue = 128; 147 tN.minValue = 128;
156 tN.maxValue = 4096; 148 tN.maxValue = 4096;
157 tN.defaultValue = 1024; 149 tN.defaultValue = 128;
158 tN.isQuantized = true; 150 tN.isQuantized = true;
159 tN.quantizeStep = 128; 151 tN.quantizeStep = 128;
160 list.push_back(tN); 152 list.push_back(tN);
161 153
162 return list; 154 return list;
215 207
216 // See OutputDescriptor documentation for the possibilities here. 208 // See OutputDescriptor documentation for the possibilities here.
217 // Every plugin must have at least one output. 209 // Every plugin must have at least one output.
218 210
219 OutputDescriptor d; 211 OutputDescriptor d;
212 float d_sampleRate;
213
220 d.identifier = "tempogram"; 214 d.identifier = "tempogram";
221 d.name = "Cyclic Tempogram"; 215 d.name = "Tempogram";
222 d.description = "Cyclic Tempogram"; 216 d.description = "Tempogram";
223 d.unit = ""; 217 d.unit = "";
224 d.hasFixedBinCount = true; 218 d.hasFixedBinCount = true;
225 d.binCount = tN; 219 d.binCount = tN/2 + 1;
226 d.hasKnownExtents = false; 220 d.hasKnownExtents = false;
227 d.isQuantized = false; 221 d.isQuantized = false;
228 d.sampleType = OutputDescriptor::FixedSampleRate; 222 d.sampleType = OutputDescriptor::FixedSampleRate;
229 float d_sampleRate = m_inputSampleRate/(m_stepSize * thopSize); 223 d_sampleRate = m_inputSampleRate/(m_stepSize * thopSize);
230 d.sampleRate = d_sampleRate > 0.0 && !isnan(d_sampleRate) ? d_sampleRate : 0.0; 224 d.sampleRate = d_sampleRate > 0.0 && !isnan(d_sampleRate) ? d_sampleRate : 0.0;
231 d.hasDuration = false; 225 d.hasDuration = false;
232 list.push_back(d); 226 list.push_back(d);
233 227
234 d.identifier = "nc"; 228 d.identifier = "nc";
235 d.name = "Novelty Curve"; 229 d.name = "Novelty Curve";
236 d.description = "Novelty Curve"; 230 d.description = "Novelty Curve";
237 d.unit = ""; 231 d.unit = "";
238 d.hasFixedBinCount = true; 232 d.hasFixedBinCount = true;
243 d_sampleRate = m_inputSampleRate/m_stepSize; 237 d_sampleRate = m_inputSampleRate/m_stepSize;
244 d.sampleRate = d_sampleRate > 0 && !isnan(d_sampleRate) ? d_sampleRate : 0.0; 238 d.sampleRate = d_sampleRate > 0 && !isnan(d_sampleRate) ? d_sampleRate : 0.0;
245 d.hasDuration = false; 239 d.hasDuration = false;
246 list.push_back(d); 240 list.push_back(d);
247 241
248 d.identifier = "spect";
249 d.name = "spect";
250 d.description = "spect";
251 d.unit = "";
252 d.hasFixedBinCount = true;
253 d.binCount = m_blockSize/2;
254 d.hasKnownExtents = false;
255 d.isQuantized = false;
256 d.sampleType = OutputDescriptor::OneSamplePerStep;
257 d.hasDuration = false;
258 list.push_back(d);
259
260 return list; 242 return list;
261 } 243 }
262 244
263 bool 245 bool
264 Tempogram::initialise(size_t channels, size_t stepSize, size_t blockSize) 246 Tempogram::initialise(size_t channels, size_t stepSize, size_t blockSize)
267 channels > getMaxChannelCount()) return false; 249 channels > getMaxChannelCount()) return false;
268 250
269 // Real initialisation work goes here! 251 // Real initialisation work goes here!
270 m_blockSize = blockSize; 252 m_blockSize = blockSize;
271 m_stepSize = stepSize; 253 m_stepSize = stepSize;
272 currentY = new float[m_blockSize]; 254 minDB = pow(10,(float)-74/20);
273 previousY = new float[m_blockSize];
274 minDB = pow((float)10,(float)-74/20);
275 255
276 specData = vector< vector<float> >(m_blockSize/2 + 1); 256 specData = vector< vector<float> >(m_blockSize/2 + 1);
277 spectrogram = new float * [m_blockSize/2 + 1];
278 257
279 return true; 258 return true;
280 } 259 }
281 260
261 void Tempogram::cleanup(){
262
263 }
264
282 void 265 void
283 Tempogram::reset() 266 Tempogram::reset()
284 { 267 {
285 // Clear buffers, reset stored values, etc 268 // Clear buffers, reset stored values, etc
269 cleanupForGRF();
270 ncTimestamps.clear();
271 specData.clear();
286 } 272 }
287 273
288 Tempogram::FeatureSet 274 Tempogram::FeatureSet
289 Tempogram::process(const float *const *inputBuffers, Vamp::RealTime timestamp) 275 Tempogram::process(const float *const *inputBuffers, Vamp::RealTime timestamp)
290 { 276 {
298 284
299 for (int i = 0; i < n; i++){ 285 for (int i = 0; i < n; i++){
300 float magnitude = sqrt(in[2*i] * in[2*i] + in[2*i + 1] * in[2*i + 1]); 286 float magnitude = sqrt(in[2*i] * in[2*i] + in[2*i + 1] * in[2*i + 1]);
301 magnitude = magnitude > minDB ? magnitude : minDB; 287 magnitude = magnitude > minDB ? magnitude : minDB;
302 specData[i].push_back(magnitude); 288 specData[i].push_back(magnitude);
303 feature.values.push_back(magnitude);
304 } 289 }
305 290
306 numberOfBlocks++; 291 numberOfBlocks++;
307 ncTimestamps.push_back(timestamp); 292 ncTimestamps.push_back(timestamp);
308 featureSet[2].push_back(feature); 293
309
310 return featureSet; 294 return featureSet;
311 } 295 }
312 296
313 void 297 void
314 Tempogram::initialiseForGRF(){ 298 Tempogram::initialiseForGRF(){
315 hannWindowtN = new float[tN]; 299 hannWindowtN = new float[tN];
316 fftInput = new double[tN]; 300 fftInput = new double[tN];
317 fftOutputReal = new double[tN]; 301 fftOutputReal = new double[tN];
318 fftOutputImag = new double[tN]; 302 fftOutputImag = new double[tN];
319 303
320 for (int i = 0; i < (m_blockSize/2 + 1); i ++){ 304 for (int i = 0; i < tN; i ++){
321 spectrogram[i] = &specData[i][0]; 305 hannWindowtN[i] = 0.0;
306 fftInput[i] = 0.0;
307 fftOutputReal[i] = 0.0;
308 fftOutputImag[i] = 0.0;
322 } 309 }
323 } 310 }
324 311
325 void 312 void
326 Tempogram::cleanupForGRF(){ 313 Tempogram::cleanupForGRF(){
327 delete []hannWindowtN; 314 delete []hannWindowtN;
328 hannWindowtN = NULL; 315 hannWindowtN = NULL;
329 delete []fftInput; 316 fftInput = fftOutputReal = fftOutputImag = NULL;
330 fftInput = NULL;
331 delete []fftOutputReal;
332 fftOutputReal = NULL;
333 delete []fftOutputImag;
334 fftOutputImag = NULL;
335 } 317 }
336 318
337 Tempogram::FeatureSet 319 Tempogram::FeatureSet
338 Tempogram::getRemainingFeatures() 320 Tempogram::getRemainingFeatures()
339 { 321 {
340 //Make sure this is called at the beginning of the function 322 //Make sure this is called at the beginning of the function
341 initialiseForGRF(); 323 initialiseForGRF();
342 FeatureSet featureSet; 324 FeatureSet featureSet;
343 325
344 NoveltyCurve nc(m_inputSampleRate, m_blockSize, numberOfBlocks, compressionConstant); 326 NoveltyCurve nc(m_inputSampleRate, m_blockSize, numberOfBlocks, compressionConstant);
345 noveltyCurve = nc.spectrogramToNoveltyCurve(spectrogram); 327 noveltyCurve = nc.spectrogramToNoveltyCurve(specData);
346 328
347 for (int i = 0; i < numberOfBlocks; i++){ 329 for (int i = 0; i < numberOfBlocks; i++){
348 Feature featureNC; 330 Feature feature;
349 cout << "nc:" << noveltyCurve[i] << endl; 331 feature.values.push_back(noveltyCurve[i]);
350 featureNC.values.push_back(noveltyCurve[i]); 332 feature.hasTimestamp = true;
351 featureNC.hasTimestamp = true; 333 feature.timestamp = ncTimestamps[i];
352 featureNC.timestamp = ncTimestamps[i]; 334 featureSet[1].push_back(feature);
353 featureSet[1].push_back(featureNC);
354 } 335 }
355 336
356 WindowFunction::hanning(hannWindowtN, tN); 337 WindowFunction::hanning(hannWindowtN, tN);
357 338 Spectrogram * spectrogramProcessor = new Spectrogram(numberOfBlocks, tN, thopSize);
358 int timestampInc = floor((((float)ncTimestamps[1].nsec - ncTimestamps[0].nsec)/1e9)*(thopSize) + 0.5); 339 vector< vector<float> > tempogram = spectrogramProcessor->audioToMagnitudeSpectrogram(&noveltyCurve[0], hannWindowtN);
359 int i = 0; 340
360 int index; 341 cout << "About to delete..." << endl;
361 int frameBeginOffset = thopSize; 342 delete spectrogramProcessor;
362 343 cout << "Deleted!" << endl;
363 while(i < numberOfBlocks){ 344 spectrogramProcessor = NULL;
345
346 int timePointer = thopSize-tN/2;
347 int tempogramLength = tempogram[0].size();
348
349 for (int block = 0; block < tempogramLength; block++){
364 Feature feature; 350 Feature feature;
365 351
366 for (int n = frameBeginOffset; n < tN; n++){ 352 int timeMS = floor(1000*(m_stepSize*timePointer)/m_inputSampleRate + 0.5);
367 index = i + n - thopSize; 353
368 assert (index >= 0); 354 cout << timeMS << endl;
369 355
370 if(index < numberOfBlocks){ 356 for(int k = 0; k < tN/2 + 1; k++){
371 fftInput[n] = noveltyCurve[i + n] * hannWindowtN[n]; 357 feature.values.push_back(tempogram[k][block]);
372 }
373 else if(index >= numberOfBlocks){
374 fftInput[n] = 0.0; //pad the end with zeros
375 }
376 } 358 }
359 feature.hasTimestamp = true;
360 feature.timestamp = RealTime::fromMilliseconds(timeMS);
361 featureSet[0].push_back(feature);
377 362
378 if (i+thopSize > numberOfBlocks){ 363 timePointer += thopSize;
379 feature.timestamp = Vamp::RealTime::fromSeconds(ncTimestamps[i].sec + timestampInc);
380 }
381 else{
382 feature.timestamp = ncTimestamps[i + thopSize];
383 }
384
385 FFT::forward(tN, fftInput, NULL, fftOutputReal, fftOutputImag);
386
387 //@todo: sample at logarithmic spacing? Leave for host?
388 for(int k = 0; k < tN; k++){
389 float fftOutputPower = (fftOutputReal[k]*fftOutputReal[k] + fftOutputImag[k]*fftOutputImag[k]); //Magnitude or power?
390
391 feature.values.push_back(fftOutputPower);
392 }
393
394 i += thopSize;
395 frameBeginOffset = 0;
396
397 feature.hasTimestamp = true;
398 featureSet[0].push_back(feature);
399 } 364 }
400 365
401 //Make sure this is called at the end of the function 366 //Make sure this is called at the end of the function
402 cleanupForGRF(); 367 cleanupForGRF();
403 368