annotate CalciumSignalAnalyser.cpp @ 4:f19dfc9cbd91 tip

Win32 build added
author mathieub <mathieu.barthet@eecs.qmul.ac.uk>
date Wed, 22 Jun 2011 20:41:48 +0100
parents e26a8489c148
children
rev   line source
mathieu@0 1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
mathieu@0 2
mathieu@0 3 /*
mathieu@0 4 Calcium Signal Analyser Vamp Plugin
mathieu@0 5
mathieu@2 6 Transient detection and characterisation for calcium signals.
mathieu@0 7
mathieu@2 8 Centre for Digital Music, Queen Mary University of London.
mathieu@2 9 This file copyright 2010-2011 Mathieu Barthet and QMUL.
mathieu@0 10
mathieu@2 11 Based on the QM Vamp note onset detector plugin by Christian
mathieu@2 12 Landone, Chris Duxbury, and Juan Pablo Bello.
mathieu@0 13
mathieu@2 14 This program is free software; you can redistribute it and/or
mathieu@2 15 modify it under the terms of the GNU General Public License as
mathieu@2 16 published by the Free Software Foundation; either version 2 of the
mathieu@2 17 License, or (at your option) any later version. See the file
mathieu@2 18 COPYING included with this distribution for more information.
mathieu@2 19
mathieu@2 20 Version: 2
mathieu@2 21 */
mathieu@0 22
mathieu@0 23 #include "CalciumSignalAnalyser.h"
mathieu@0 24
mathieu@0 25 #include <dsp/onsets/PeakPicking.h>
mathieu@0 26 #include <dsp/tempotracking/TempoTrack.h>
mathieu@0 27
mathieu@0 28 using std::string;
mathieu@0 29 using std::vector;
mathieu@0 30 using std::cerr;
mathieu@0 31 using std::endl;
mathieu@0 32
mathieu@0 33 #define MAX_PEAKFREQ 10; //maximum peak frequency in Hz
mathieu@0 34
mathieu@0 35 //#define VERBOSE //remove comment to have output messages for data display or debugging information
mathieu@0 36
mathieu@0 37 CalciumSignalAnalyser::CalciumSignalAnalyser(float inputSampleRate) :
mathieu@0 38 Vamp::Plugin(inputSampleRate),
mathieu@0 39 m_inputSampleRate(inputSampleRate),
mathieu@0 40 m_blockSize(0),
mathieu@0 41 m_stepSize(0),
mathieu@0 42 data(0),
mathieu@0 43 time(0),
mathieu@0 44 m_sensitivity(50),
mathieu@0 45 m_delta(0.2),
mathieu@2 46 m_mfwindur(10),
mathieu@0 47 processcounter(0)
mathieu@0 48 {
mathieu@0 49 #ifdef VERBOSE
mathieu@0 50 cout << "Sample rate: " << inputSampleRate << endl;
mathieu@0 51 #endif
mathieu@0 52 }
mathieu@0 53
mathieu@0 54 CalciumSignalAnalyser::~CalciumSignalAnalyser()
mathieu@0 55 {
mathieu@0 56 #ifdef VERBOSE
mathieu@0 57 cout << "Destructor" << endl;
mathieu@0 58 #endif
mathieu@0 59
mathieu@0 60 if (!data.empty()){
mathieu@0 61 #ifdef VERBOSE
mathieu@0 62 cout << "Data vector reset" << endl;
mathieu@0 63 #endif
mathieu@0 64 data.clear(); //clears the vector's elements
mathieu@0 65 }
mathieu@0 66
mathieu@0 67 if (!time.empty()){
mathieu@0 68 #ifdef VERBOSE
mathieu@0 69 cout << "Time vector reset" << endl;
mathieu@0 70 #endif
mathieu@0 71 time.clear(); //clears the vector's elements
mathieu@0 72 }
mathieu@0 73 }
mathieu@0 74
mathieu@0 75 string
mathieu@0 76 CalciumSignalAnalyser::getIdentifier() const
mathieu@0 77 {
mathieu@0 78 return "peakdetection";
mathieu@0 79 }
mathieu@0 80
mathieu@0 81 string
mathieu@0 82 CalciumSignalAnalyser::getName() const
mathieu@0 83 {
mathieu@0 84 return "Calcium Signal Analyser";
mathieu@0 85 }
mathieu@0 86
mathieu@0 87 string
mathieu@0 88 CalciumSignalAnalyser::getDescription() const
mathieu@0 89 {
mathieu@0 90 return "Automatic detection and characterisation of the signal's transients";
mathieu@0 91 }
mathieu@0 92
mathieu@0 93 string
mathieu@0 94 CalciumSignalAnalyser::getMaker() const
mathieu@0 95 {
mathieu@0 96 return "Mathieu Barthet";
mathieu@0 97 }
mathieu@0 98
mathieu@0 99 int
mathieu@0 100 CalciumSignalAnalyser::getPluginVersion() const
mathieu@0 101 {
mathieu@2 102 return 2;
mathieu@0 103 }
mathieu@0 104
mathieu@0 105 string
mathieu@0 106 CalciumSignalAnalyser::getCopyright() const
mathieu@0 107 {
mathieu@0 108 return "Plugin by Mathieu Barthet. Based on the note onset detector plugin by Christian Landone, Chris Duxbury and Juan Pablo Bello. Copyright (c) 2010 QMUL - All Rights Reserved";
mathieu@0 109 }
mathieu@0 110
mathieu@0 111 CalciumSignalAnalyser::ParameterList
mathieu@0 112 CalciumSignalAnalyser::getParameterDescriptors() const
mathieu@0 113 {
mathieu@0 114 ParameterList list;
mathieu@0 115 ParameterDescriptor desc;
mathieu@0 116
mathieu@0 117 desc.identifier = "sensitivity";
mathieu@0 118 desc.name = "Peak-picking sensitivity";
mathieu@0 119 desc.description = "Sensitivity of the peak detection (criterion based on quadratic interpolation)";
mathieu@0 120 desc.minValue = 0;
mathieu@0 121 desc.maxValue = 100;
mathieu@0 122 desc.defaultValue = 50;
mathieu@0 123 desc.isQuantized = true;
mathieu@0 124 desc.quantizeStep = 1;
mathieu@0 125 desc.unit = "%";
mathieu@0 126 list.push_back(desc);
mathieu@0 127
mathieu@0 128 desc.identifier = "deltathreshold";
mathieu@0 129 desc.name = "Peak-picking offset threshold (delta)";
mathieu@0 130 desc.description = "Offset threshold aiming at improving the peak detection by discarding the noise";
mathieu@0 131 desc.minValue = 0;
mathieu@0 132 desc.maxValue = 1;
mathieu@0 133 desc.defaultValue = 0.2;
mathieu@0 134 desc.isQuantized = true;
mathieu@0 135 desc.quantizeStep = 0.05;
mathieu@0 136 desc.unit = "";
mathieu@0 137 list.push_back(desc);
mathieu@0 138
mathieu@2 139 desc.identifier = "mfwindowduration";
mathieu@2 140 desc.name = "Duration of the median filtering window";
mathieu@2 141 desc.description = "Sets the duration of the median filtering window";
mathieu@2 142 desc.minValue = 2;
mathieu@2 143 desc.maxValue = 100;
mathieu@2 144 desc.defaultValue = 10;
mathieu@2 145 desc.isQuantized = true;
mathieu@2 146 desc.quantizeStep = 0.1;
mathieu@2 147 desc.unit = "s";
mathieu@2 148 list.push_back(desc);
mathieu@2 149
mathieu@0 150 return list;
mathieu@0 151 }
mathieu@0 152
mathieu@0 153 float
mathieu@0 154 CalciumSignalAnalyser::getParameter(std::string name) const
mathieu@0 155 {
mathieu@0 156 if (name == "sensitivity"){
mathieu@0 157 return m_sensitivity;
mathieu@0 158 }
mathieu@0 159 else if (name == "deltathreshold") {
mathieu@0 160 return m_delta;
mathieu@2 161 }
mathieu@2 162 else if (name == "mfwindowduration") {
mathieu@2 163 return m_mfwindur;
mathieu@0 164 }
mathieu@0 165
mathieu@0 166 return 0.0;
mathieu@0 167 }
mathieu@0 168
mathieu@0 169 void
mathieu@0 170 CalciumSignalAnalyser::setParameter(std::string name, float value)
mathieu@0 171 {
mathieu@0 172 if (name == "sensitivity") {
mathieu@0 173 if (m_sensitivity == value) return;
mathieu@0 174 m_sensitivity = value;
mathieu@0 175
mathieu@0 176 }
mathieu@0 177 else if (name == "deltathreshold") {
mathieu@0 178 if (m_delta == value) return;
mathieu@0 179 m_delta = value;
mathieu@0 180 }
mathieu@2 181 else if (name == "mfwindowduration") {
mathieu@2 182 if (m_mfwindur == value) return;
mathieu@2 183 m_mfwindur = value;
mathieu@2 184 }
mathieu@0 185 }
mathieu@0 186
mathieu@0 187
mathieu@0 188 CalciumSignalAnalyser::ProgramList
mathieu@0 189 CalciumSignalAnalyser::getPrograms() const
mathieu@0 190 {
mathieu@0 191 ProgramList programs;
mathieu@0 192
mathieu@0 193 return programs;
mathieu@0 194 }
mathieu@0 195
mathieu@0 196 std::string
mathieu@0 197 CalciumSignalAnalyser::getCurrentProgram() const
mathieu@0 198 {
mathieu@0 199 return "";
mathieu@0 200 }
mathieu@0 201
mathieu@0 202 void
mathieu@0 203 CalciumSignalAnalyser::selectProgram(std::string program)
mathieu@0 204 {
mathieu@0 205 }
mathieu@0 206
mathieu@0 207 bool
mathieu@0 208 CalciumSignalAnalyser::initialise(size_t channels, size_t stepSize, size_t blockSize)
mathieu@0 209 {
mathieu@0 210
mathieu@0 211 #ifdef VERBOSE
mathieu@0 212 cout << "Initialise" << endl;
mathieu@0 213 #endif
mathieu@0 214
mathieu@0 215 m_blockSize = 1;
mathieu@0 216 m_stepSize = 1;
mathieu@0 217
mathieu@0 218 #ifdef VERBOSE
mathieu@0 219 cout << m_blockSize << " " << m_stepSize << endl;
mathieu@0 220 #endif
mathieu@0 221
mathieu@0 222 if (channels < getMinChannelCount() ||
mathieu@0 223 channels > getMaxChannelCount()) {
mathieu@0 224 std::cerr << "CalciumSignalAnalyser::initialise: Unsupported channel count: "
mathieu@0 225 << channels << std::endl;
mathieu@0 226 return false;
mathieu@0 227 }
mathieu@0 228
mathieu@0 229 if (stepSize != getPreferredStepSize()) {
mathieu@0 230
mathieu@0 231 std::cerr << "ERROR: CalciumSignalAnalyser::initialise: the step size has to be 1." << std::endl;
mathieu@0 232 return false;
mathieu@0 233 }
mathieu@0 234
mathieu@0 235 if (blockSize != getPreferredBlockSize()) {
mathieu@0 236
mathieu@0 237 std::cerr << "ERROR: CalciumSignalAnalyser::initialise: the block size has to be 1." << std::endl;
mathieu@0 238 return false;
mathieu@0 239 }
mathieu@0 240
mathieu@0 241 return true;
mathieu@0 242 }
mathieu@0 243
mathieu@0 244 void
mathieu@0 245 CalciumSignalAnalyser::reset()
mathieu@0 246 {
mathieu@0 247 #ifdef VERBOSE
mathieu@0 248 cout << "Reset" << endl;
mathieu@0 249 #endif
mathieu@0 250
mathieu@0 251 if (!data.empty()){
mathieu@0 252 #ifdef VERBOSE
mathieu@0 253 cout << "Data vector reset" << endl;
mathieu@0 254 #endif
mathieu@0 255 data.clear(); //clears the vector's elements
mathieu@0 256 }
mathieu@0 257
mathieu@0 258 if (!time.empty()){
mathieu@0 259 #ifdef VERBOSE
mathieu@0 260 cout << "Time vector reset" << endl;
mathieu@0 261 #endif
mathieu@0 262 time.clear(); //clears the vector's elements
mathieu@0 263 }
mathieu@0 264 }
mathieu@0 265
mathieu@0 266 size_t
mathieu@0 267 CalciumSignalAnalyser::getPreferredStepSize() const
mathieu@0 268 {
mathieu@0 269 return getPreferredBlockSize();
mathieu@0 270 }
mathieu@0 271
mathieu@0 272 size_t
mathieu@0 273 CalciumSignalAnalyser::getPreferredBlockSize() const
mathieu@0 274 {
mathieu@0 275 return 1;
mathieu@0 276 }
mathieu@0 277
mathieu@0 278 size_t
mathieu@0 279 CalciumSignalAnalyser::getMinChannelCount() const
mathieu@0 280 {
mathieu@0 281 return 1;
mathieu@0 282 }
mathieu@0 283
mathieu@0 284 size_t
mathieu@0 285 CalciumSignalAnalyser::getMaxChannelCount() const
mathieu@0 286 {
mathieu@0 287 return 1;
mathieu@0 288 }
mathieu@0 289
mathieu@0 290
mathieu@0 291 CalciumSignalAnalyser::OutputList
mathieu@0 292 CalciumSignalAnalyser::getOutputDescriptors() const
mathieu@0 293 {
mathieu@0 294 #ifdef VERBOSE
mathieu@0 295 cout << "get output desc" << endl;
mathieu@0 296 #endif
mathieu@0 297
mathieu@0 298 OutputList list;
mathieu@0 299
mathieu@0 300 OutputDescriptor pt;
mathieu@0 301 pt.identifier = "peaktimes";
mathieu@0 302 pt.name = "Peaks times";
mathieu@0 303 pt.description = "Time positions of the peaks (in seconds)";
mathieu@0 304 pt.unit = "";
mathieu@0 305 pt.hasFixedBinCount = true;
mathieu@0 306 pt.binCount = 0; //0 for time only feature
mathieu@0 307 pt.sampleType = OutputDescriptor::VariableSampleRate;
mathieu@0 308 pt.hasDuration = false;
mathieu@0 309 pt.hasKnownExtents = false;
mathieu@0 310 pt.isQuantized = false;
mathieu@0 311 pt.sampleRate = 0; //no sensible resolution, the time of the feature are given in the timestamp of the feature
mathieu@0 312 list.push_back(pt);
mathieu@0 313
mathieu@0 314 OutputDescriptor po;
mathieu@0 315 po.identifier = "peakonsets";
mathieu@0 316 po.name = "Peaks onsets";
mathieu@0 317 po.description = "Time positions of the peak onsets (in seconds)";
mathieu@0 318 po.unit = "";
mathieu@0 319 po.hasFixedBinCount = true;
mathieu@0 320 po.binCount = 0; //0 for time only feature
mathieu@0 321 po.sampleType = OutputDescriptor::VariableSampleRate;
mathieu@0 322 po.hasDuration = false;
mathieu@0 323 po.hasKnownExtents = false;
mathieu@0 324 po.isQuantized = false;
mathieu@0 325 po.sampleRate = 0; //no sensible resolution, the time of the feature are given in the timestamp of the feature
mathieu@0 326 list.push_back(po);
mathieu@0 327
mathieu@0 328 OutputDescriptor sdf;
mathieu@0 329 sdf.identifier = "smoothed_df";
mathieu@0 330 sdf.name = "Smoothed Detection Function";
mathieu@0 331 sdf.description = "Smoothed probability function used for peak-picking";
mathieu@0 332 sdf.unit = "";
mathieu@0 333 sdf.hasFixedBinCount = true;
mathieu@0 334 sdf.binCount = 1;
mathieu@0 335 sdf.hasKnownExtents = false;
mathieu@0 336 sdf.isQuantized = false;
mathieu@0 337 sdf.sampleType = OutputDescriptor::FixedSampleRate;
mathieu@0 338 sdf.sampleRate = m_inputSampleRate; //the smoothed detection function has the same sample rate as the input signal
mathieu@0 339 list.push_back(sdf);
mathieu@0 340
mathieu@0 341 OutputDescriptor pf;
mathieu@0 342 pf.identifier = "peak_frequency";
mathieu@0 343 pf.name = "Peak frequency";
mathieu@0 344 pf.description = "Frequency of the peaks (in Hz)";
mathieu@0 345 //pf.unit = "Hz"; //if unit is Hz then the feature is treated as a pitch which is not relevant in this case
mathieu@0 346 pf.unit = "";
mathieu@0 347 pf.hasFixedBinCount = true;
mathieu@0 348 pf.binCount = 1; //1 corresponds to time and value
mathieu@0 349 pf.sampleType = OutputDescriptor::VariableSampleRate;
mathieu@0 350 pf.sampleRate = 0; //no sensible resolution, the time of the feature is given in the timestamp of the feature
mathieu@0 351 pf.hasKnownExtents = true;
mathieu@0 352 pf.minValue = 0;
mathieu@0 353 pf.maxValue = MAX_PEAKFREQ;
mathieu@0 354 pf.isQuantized = false;
mathieu@0 355 pf.hasDuration = true; //duration of the signal
mathieu@0 356 list.push_back(pf);
mathieu@0 357
mathieu@0 358 OutputDescriptor mipi;
mathieu@0 359 mipi.identifier = "mean_interpeakinterval";
mathieu@0 360 mipi.name = "Mean Inter Peak Interval";
mathieu@0 361 mipi.description = "Mean of the time intervals between peaks (in seconds)";
mathieu@0 362 mipi.unit = "s";
mathieu@0 363 mipi.hasFixedBinCount = true;
mathieu@0 364 mipi.binCount = 1; //1 corresponds to time and value
mathieu@0 365 mipi.sampleType = OutputDescriptor::VariableSampleRate;
mathieu@0 366 mipi.sampleRate = 0; //no sensible resolution, the time of the feature is given in the timestamp of the feature
mathieu@0 367 mipi.hasKnownExtents = false;
mathieu@0 368 mipi.isQuantized = false;
mathieu@0 369 mipi.hasDuration = true; //duration of the signal
mathieu@0 370 list.push_back(mipi);
mathieu@0 371
mathieu@0 372 return list;
mathieu@0 373 }
mathieu@0 374
mathieu@0 375 CalciumSignalAnalyser::FeatureSet
mathieu@0 376 CalciumSignalAnalyser::process(const float *const *inputBuffers,
mathieu@0 377 Vamp::RealTime timestamp)
mathieu@0 378 {
mathieu@0 379 FeatureSet fs;
mathieu@0 380
mathieu@0 381 if (m_blockSize == 0 || m_stepSize == 0) {
mathieu@0 382 cerr << "ERROR: CalciumSignalAnalyser::process: "
mathieu@0 383 << "CalciumSignalAnalyser has not been initialised."
mathieu@0 384 << endl;
mathieu@0 385 return fs;
mathieu@0 386 }
mathieu@0 387
mathieu@0 388 data.push_back(inputBuffers[0][0]); //assumes that only one sample is read at a time
mathieu@0 389 time.push_back(timestamp);
mathieu@0 390
mathieu@0 391 processcounter ++;
mathieu@0 392
mathieu@0 393 fs = FeatureSet(); //empty feature set
mathieu@0 394
mathieu@0 395 return fs;
mathieu@0 396 }
mathieu@0 397
mathieu@0 398 CalciumSignalAnalyser::FeatureSet
mathieu@0 399 CalciumSignalAnalyser::getRemainingFeatures()
mathieu@0 400 {
mathieu@0 401 FeatureSet returnFeatures;
mathieu@0 402 returnFeatures = FeatureSet();
mathieu@0 403
mathieu@0 404 #ifdef VERBOSE
mathieu@0 405 cout << "Get remaining features" << endl << endl;
mathieu@0 406 #endif
mathieu@0 407
mathieu@0 408 /***************************************
mathieu@0 409 Peak times
mathieu@0 410 ****************************************/
mathieu@0 411
mathieu@0 412 double aCoeffs[] = { 1.0000, -0.5949, 0.2348 };
mathieu@0 413 double bCoeffs[] = { 0.1600, 0.3200, 0.1600 };
mathieu@0 414
mathieu@0 415 //The signal is directly treated as a detection function for the peak picking stage
mathieu@0 416
mathieu@0 417 PPickParams ppParams;
mathieu@0 418 ppParams.length = data.size(); //length of the signal
mathieu@0 419
mathieu@0 420 #ifdef VERBOSE
mathieu@0 421 cout << "Length: " << ppParams.length << endl;
mathieu@0 422 #endif
mathieu@0 423
mathieu@0 424 // tau and cutoff appear to be unused in PeakPicking, but I've
mathieu@0 425 // inserted some moderately plausible values rather than leave
mathieu@0 426 // them unset. The QuadThresh values come from trial and error.
mathieu@0 427 // The rest of these are copied from ttParams in the BeatTracker
mathieu@0 428 // code: I don't claim to know whether they're good or not --cc
mathieu@0 429
mathieu@0 430 ppParams.tau = m_stepSize / m_inputSampleRate; //not used for peak picking
mathieu@0 431
mathieu@0 432 ppParams.alpha = 9;
mathieu@0 433 ppParams.cutoff = m_inputSampleRate/4; //not used for peak picking
mathieu@0 434 ppParams.LPOrd = 2;
mathieu@0 435 ppParams.LPACoeffs = aCoeffs;
mathieu@0 436 ppParams.LPBCoeffs = bCoeffs;
mathieu@0 437
mathieu@2 438 int NWin;
mathieu@2 439 float samples = m_inputSampleRate*m_mfwindur;
mathieu@2 440 if (samples < 4){
mathieu@2 441 NWin = 4; //minimal possible length of the window in samples
mathieu@2 442 #ifdef VERBOSE
mathieu@2 443 cout << "WARNING: CalciumSignalAnalyser::getRemainingFeatures:"
mathieu@2 444 << "The duration of the median filtering window is too small considering the"
mathieu@2 445 << "sample frequency of the signal. Duration of "<< NWin/m_inputSampleRate
mathieu@2 446 << " s used instead."
mathieu@2 447 << endl;
mathieu@2 448 #endif
mathieu@2 449 }else{
mathieu@2 450 NWin = floor(m_inputSampleRate*m_mfwindur);
mathieu@2 451 if (NWin%2 != 0) NWin--;
mathieu@2 452 }
mathieu@2 453
mathieu@2 454 ppParams.WinT.post = NWin/2;
mathieu@2 455 ppParams.WinT.pre = NWin/2 - 1;
mathieu@0 456
mathieu@0 457 ppParams.QuadThresh.a = (100 - m_sensitivity) / 1000.0;
mathieu@0 458 ppParams.QuadThresh.b = 0;
mathieu@0 459 ppParams.QuadThresh.c = (100 - m_sensitivity) / 1500.0;
mathieu@0 460 ppParams.delta = m_delta; //delta threshold used as an offset when computing the smoothed detection function
mathieu@0 461
mathieu@0 462 PeakPicking peakPicker(ppParams);
mathieu@0 463
mathieu@0 464 double *ppSrc = new double[ppParams.length];
mathieu@0 465 if (ppSrc==NULL) {
mathieu@0 466 cerr << "ERROR: CalciumSignalAnalyser::getRemainingFeatures:"
mathieu@0 467 << "Unable to allocate memory (ppSrc)."
mathieu@0 468 << endl;
mathieu@0 469 return returnFeatures;
mathieu@0 470 }
mathieu@0 471
mathieu@0 472 for (unsigned int i = 0; i < ppParams.length; ++i) {
mathieu@0 473
mathieu@0 474 ppSrc[i] = (double) data[i];
mathieu@0 475 }
mathieu@0 476
mathieu@0 477 vector<int> peaks;
mathieu@0 478 vector<int> peak_frame;
mathieu@0 479 vector<int> onsets_frame;
mathieu@0 480
mathieu@0 481 peakPicker.process(ppSrc, ppParams.length, peaks);
mathieu@0 482
mathieu@0 483 for (size_t i = 0; i < peaks.size(); ++i) {
mathieu@0 484
mathieu@0 485 //peak times
mathieu@0 486 size_t index = peaks[i];
mathieu@0 487 size_t peakframe = peaks[i] * m_stepSize;
mathieu@0 488 peak_frame.push_back(peakframe);
mathieu@0 489
mathieu@0 490 Feature featurepeaks;
mathieu@0 491 featurepeaks.hasTimestamp = true;
mathieu@0 492 featurepeaks.timestamp = Vamp::RealTime::frame2RealTime(peakframe, lrintf(m_inputSampleRate));
mathieu@0 493
mathieu@0 494 returnFeatures[0].push_back(featurepeaks); // peak times are output 0
mathieu@0 495
mathieu@0 496 //algorithm to detect the peak onsets
mathieu@0 497
mathieu@0 498 double prevDiff = 0.0;
mathieu@0 499 while (index > 1) {
mathieu@0 500 double diff = ppSrc[index] - ppSrc[index-1];
mathieu@0 501 if (diff < prevDiff * 0.9) break;
mathieu@0 502 prevDiff = diff;
mathieu@0 503 --index;
mathieu@0 504 }
mathieu@0 505
mathieu@0 506 size_t onsetframe = index * m_stepSize;
mathieu@0 507 onsets_frame.push_back(onsetframe);
mathieu@0 508
mathieu@0 509 Feature featureonsets;
mathieu@0 510 featureonsets.hasTimestamp = true;
mathieu@0 511 featureonsets.timestamp = Vamp::RealTime::frame2RealTime(onsetframe, lrintf(m_inputSampleRate));
mathieu@0 512
mathieu@0 513 #ifdef VERBOSE
mathieu@0 514 cout << featureonsets.timestamp << endl;
mathieu@0 515 #endif
mathieu@0 516 returnFeatures[1].push_back(featureonsets); // peak onsets are output 1
mathieu@0 517 }
mathieu@0 518
mathieu@0 519 for (unsigned int i = 0; i < ppParams.length; ++i) {
mathieu@0 520
mathieu@0 521 Feature feature;
mathieu@0 522 feature.hasTimestamp = true;
mathieu@0 523 size_t frame = i * m_stepSize;
mathieu@0 524
mathieu@0 525 feature.timestamp = Vamp::RealTime::frame2RealTime(frame, lrintf(m_inputSampleRate));
mathieu@0 526
mathieu@0 527 feature.values.push_back(ppSrc[i]);
mathieu@0 528
mathieu@0 529 returnFeatures[2].push_back(feature); // smoothed df is output 2
mathieu@0 530 }
mathieu@0 531
mathieu@0 532 /***************************************
mathieu@0 533 Peak frequency
mathieu@0 534 ****************************************/
mathieu@0 535
mathieu@0 536 double peakfreq, duration;
mathieu@0 537 int npeaks; //total number of peaks
mathieu@0 538
mathieu@0 539 //last element of the time vector is the duration of the signal - converts the RealTime to a float
mathieu@0 540 duration = time.back()/Vamp::RealTime(1,0); //division by 1 s to obtain a double
mathieu@0 541
mathieu@0 542 npeaks = peaks.size();
mathieu@0 543 peakfreq = npeaks/duration;
mathieu@0 544
mathieu@0 545 #ifdef VERBOSE
mathieu@0 546 cout << npeaks << endl;
mathieu@0 547 cout << duration << endl;
mathieu@0 548 cout << peakfreq << endl;
mathieu@0 549 #endif
mathieu@0 550
mathieu@0 551 Feature pf;
mathieu@0 552 pf.hasTimestamp = true;
mathieu@0 553 pf.timestamp = time[0];
mathieu@0 554 pf.hasDuration = true;
mathieu@0 555 pf.duration = time.back()-time[0];
mathieu@0 556
mathieu@0 557 #ifdef VERBOSE
mathieu@0 558 cout << "processcounter" << processcounter << endl;
mathieu@0 559
mathieu@0 560 cout << "time.back " << time.back().toText() << endl;
mathieu@0 561 cout << "time.size " << time.size() << endl;
mathieu@0 562 cout << "data.size " << data.size() << endl;
mathieu@0 563 cout << "time[0, 1 ...] " << time[0].toText() << " " << time[1].toText() << " " << time[2].toText() << " " << time[time.size()].toText() << endl;
mathieu@0 564
mathieu@0 565 cout << "time[999] " << time[999].toText() << endl;
mathieu@0 566 cout << "data[999] " << data[999] << endl;
mathieu@0 567 cout << "time[1000] " << time[1000].toText() << endl;
mathieu@0 568 cout << "data[1000] " << data[1000]<< endl;
mathieu@0 569 #endif
mathieu@0 570
mathieu@0 571 pf.values.push_back(peakfreq);
mathieu@0 572
mathieu@0 573 char pflabel[256];
mathieu@0 574 sprintf(pflabel,"%f Hz",peakfreq);
mathieu@0 575 pf.label = pflabel;
mathieu@0 576
mathieu@0 577 #ifdef VERBOSE
mathieu@0 578 cout << "label: " << pflabel << endl;
mathieu@0 579 #endif
mathieu@0 580
mathieu@0 581 returnFeatures[3].push_back(pf); //peak frequency is output 3
mathieu@0 582
mathieu@0 583 /***************************************
mathieu@0 584 Mean Inter Peak Interval
mathieu@0 585 ****************************************/
mathieu@0 586
mathieu@0 587 double o1,o2;
mathieu@0 588
mathieu@0 589 double sumipi_s = 0;
mathieu@0 590 double meanipi_s;
mathieu@0 591
mathieu@0 592 for (int j = 0; j < npeaks-1; ++j) {
mathieu@0 593 o2 = Vamp::RealTime::frame2RealTime(peak_frame[j+1], lrintf(m_inputSampleRate))/Vamp::RealTime(1,0);
mathieu@0 594 o1 = Vamp::RealTime::frame2RealTime(peak_frame[j], lrintf(m_inputSampleRate))/Vamp::RealTime(1,0);
mathieu@0 595 #ifdef VERBOSE
mathieu@0 596 cout << "o1: " << o1 << endl;
mathieu@0 597 cout << "o2: " << o2 << endl;
mathieu@0 598 #endif
mathieu@0 599 sumipi_s = sumipi_s + o2 - o1;
mathieu@0 600 }
mathieu@0 601
mathieu@0 602 meanipi_s = sumipi_s/(npeaks-1);
mathieu@0 603
mathieu@0 604 #ifdef VERBOSE
mathieu@0 605 cout << "Sum IPI: " << sumipi_s << endl;
mathieu@0 606 cout << "Mean IPI: " << meanipi_s << endl;
mathieu@0 607 #endif
mathieu@0 608
mathieu@0 609 Feature mipi;
mathieu@0 610 mipi.hasTimestamp = true;
mathieu@0 611 mipi.timestamp = time[0];
mathieu@0 612 mipi.hasDuration = true;
mathieu@0 613 mipi.duration = time.back()-time[0];
mathieu@0 614
mathieu@0 615 mipi.values.push_back(meanipi_s); //mean inter peak interval in secs
mathieu@0 616
mathieu@0 617 returnFeatures[4].push_back(mipi); //mean inter peak interval is output 4
mathieu@0 618
mathieu@0 619 //clear data
mathieu@0 620
mathieu@0 621 delete [] ppSrc;
mathieu@0 622
mathieu@0 623 if (!data.empty()){
mathieu@0 624 #ifdef VERBOSE
mathieu@0 625 cout << "Data vector reset" << endl;
mathieu@0 626 #endif
mathieu@0 627 data.clear(); //clears the vector's elements
mathieu@0 628 }
mathieu@0 629
mathieu@0 630 if (!time.empty()){
mathieu@0 631 #ifdef VERBOSE
mathieu@0 632 cout << "Time vector reset" << endl;
mathieu@0 633 #endif
mathieu@0 634 time.clear(); //clears the vector's elements
mathieu@0 635 }
mathieu@0 636
mathieu@0 637 #ifdef VERBOSE
mathieu@0 638 cout << "End of get remaining features" << endl << endl;
mathieu@0 639 #endif
mathieu@0 640 return returnFeatures;
mathieu@0 641 }
mathieu@0 642