Mercurial > hg > vamp-tempogram
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 |