annotate VampTestPlugin.cpp @ 20:cfff2b6ff0fd

Add timestamp output and frequency-domain version
author Chris Cannam
date Wed, 14 Jan 2015 10:55:32 +0000
parents 534b001d8e8f
children 8984ab4a0213
rev   line source
Chris@0 1
Chris@0 2
Chris@0 3 #include "VampTestPlugin.h"
Chris@0 4
Chris@19 5 #include <iostream>
Chris@3 6 #include <sstream>
Chris@18 7 #include <cmath>
Chris@3 8
Chris@19 9 using namespace std;
Chris@3 10
Chris@3 11 using Vamp::RealTime;
Chris@0 12
Chris@20 13 VampTestPlugin::VampTestPlugin(float inputSampleRate, bool freq) :
Chris@3 14 Plugin(inputSampleRate),
Chris@20 15 m_frequencyDomain(freq),
Chris@17 16 m_produceOutput(true),
Chris@3 17 m_n(0),
Chris@18 18 m_channels(1),
Chris@3 19 m_stepSize(0),
Chris@3 20 m_blockSize(0)
Chris@0 21 {
Chris@3 22 for (int i = 0; i < 10; ++i) {
Chris@3 23 m_instants.push_back(RealTime::fromSeconds(1.5 * i));
Chris@3 24 }
Chris@0 25 }
Chris@0 26
Chris@0 27 VampTestPlugin::~VampTestPlugin()
Chris@0 28 {
Chris@0 29 }
Chris@0 30
Chris@0 31 string
Chris@0 32 VampTestPlugin::getIdentifier() const
Chris@0 33 {
Chris@20 34 if (m_frequencyDomain) {
Chris@20 35 return "vamp-test-plugin-freq";
Chris@20 36 } else {
Chris@20 37 return "vamp-test-plugin";
Chris@20 38 }
Chris@0 39 }
Chris@0 40
Chris@0 41 string
Chris@0 42 VampTestPlugin::getName() const
Chris@0 43 {
Chris@20 44 if (m_frequencyDomain) {
Chris@20 45 return "Vamp Test Plugin (Frequency-Domain Input)";
Chris@20 46 } else {
Chris@20 47 return "Vamp Test Plugin";
Chris@20 48 }
Chris@0 49 }
Chris@0 50
Chris@0 51 string
Chris@0 52 VampTestPlugin::getDescription() const
Chris@0 53 {
Chris@0 54 return "Test plugin for hosts handling various output types";
Chris@0 55 }
Chris@0 56
Chris@0 57 string
Chris@0 58 VampTestPlugin::getMaker() const
Chris@0 59 {
Chris@0 60 return "Chris Cannam";
Chris@0 61 }
Chris@0 62
Chris@0 63 int
Chris@0 64 VampTestPlugin::getPluginVersion() const
Chris@0 65 {
Chris@20 66 return 3;
Chris@0 67 }
Chris@0 68
Chris@0 69 string
Chris@0 70 VampTestPlugin::getCopyright() const
Chris@0 71 {
Chris@0 72 return "BSD";
Chris@0 73 }
Chris@0 74
Chris@0 75 VampTestPlugin::InputDomain
Chris@0 76 VampTestPlugin::getInputDomain() const
Chris@0 77 {
Chris@20 78 return m_frequencyDomain ? FrequencyDomain : TimeDomain;
Chris@0 79 }
Chris@0 80
Chris@0 81 size_t
Chris@0 82 VampTestPlugin::getPreferredBlockSize() const
Chris@0 83 {
Chris@0 84 return 0;
Chris@0 85 }
Chris@0 86
Chris@0 87 size_t
Chris@0 88 VampTestPlugin::getPreferredStepSize() const
Chris@0 89 {
Chris@0 90 return 0;
Chris@0 91 }
Chris@0 92
Chris@0 93 size_t
Chris@0 94 VampTestPlugin::getMinChannelCount() const
Chris@0 95 {
Chris@0 96 return 1;
Chris@0 97 }
Chris@0 98
Chris@0 99 size_t
Chris@0 100 VampTestPlugin::getMaxChannelCount() const
Chris@0 101 {
Chris@18 102 return 10;
Chris@0 103 }
Chris@0 104
Chris@0 105 VampTestPlugin::ParameterList
Chris@0 106 VampTestPlugin::getParameterDescriptors() const
Chris@0 107 {
Chris@0 108 ParameterList list;
Chris@17 109
Chris@17 110 // Provide one parameter, and make it so that we can easily tell
Chris@17 111 // whether it has been changed
Chris@17 112 ParameterDescriptor d;
Chris@17 113 d.identifier = "produce_output";
Chris@17 114 d.name = "Produce some output";
Chris@17 115 d.description = "Whether to produce any output. If this parameter is switched off, the plugin will produce no output. This is intended for basic testing of whether a host's parameter setting logic is functioning.";
Chris@17 116 d.unit = "";
Chris@17 117 d.minValue = 0;
Chris@17 118 d.maxValue = 1;
Chris@17 119 d.defaultValue = 1;
Chris@17 120 d.isQuantized = true;
Chris@17 121 d.quantizeStep = 1;
Chris@17 122 list.push_back(d);
Chris@17 123
Chris@0 124 return list;
Chris@0 125 }
Chris@0 126
Chris@0 127 float
Chris@0 128 VampTestPlugin::getParameter(string identifier) const
Chris@0 129 {
Chris@17 130 if (identifier == "produce_output") {
Chris@17 131 return m_produceOutput ? 1.f : 0.f;
Chris@17 132 }
Chris@0 133 return 0;
Chris@0 134 }
Chris@0 135
Chris@0 136 void
Chris@0 137 VampTestPlugin::setParameter(string identifier, float value)
Chris@0 138 {
Chris@17 139 if (identifier == "produce_output") {
Chris@17 140 m_produceOutput = (value > 0.5);
Chris@17 141 }
Chris@0 142 }
Chris@0 143
Chris@0 144 VampTestPlugin::ProgramList
Chris@0 145 VampTestPlugin::getPrograms() const
Chris@0 146 {
Chris@0 147 ProgramList list;
Chris@0 148 return list;
Chris@0 149 }
Chris@0 150
Chris@0 151 string
Chris@0 152 VampTestPlugin::getCurrentProgram() const
Chris@0 153 {
Chris@0 154 return ""; // no programs
Chris@0 155 }
Chris@0 156
Chris@0 157 void
Chris@0 158 VampTestPlugin::selectProgram(string name)
Chris@0 159 {
Chris@0 160 }
Chris@0 161
Chris@0 162 VampTestPlugin::OutputList
Chris@0 163 VampTestPlugin::getOutputDescriptors() const
Chris@0 164 {
Chris@0 165 OutputList list;
Chris@0 166
Chris@7 167 int n = 0;
Chris@7 168
Chris@0 169 OutputDescriptor d;
Chris@1 170
Chris@1 171 d.identifier = "instants";
Chris@1 172 d.name = "Instants";
Chris@2 173 d.description = "Single time points without values";
Chris@1 174 d.unit = "";
Chris@1 175 d.hasFixedBinCount = true;
Chris@1 176 d.binCount = 0;
Chris@1 177 d.hasKnownExtents = false;
Chris@1 178 d.isQuantized = false;
Chris@1 179 d.sampleType = OutputDescriptor::VariableSampleRate;
Chris@1 180 d.hasDuration = false;
Chris@7 181 m_outputNumbers[d.identifier] = n++;
Chris@1 182 list.push_back(d);
Chris@1 183
Chris@1 184 d.identifier = "curve-oss";
Chris@1 185 d.name = "Curve: OneSamplePerStep";
Chris@2 186 d.description = "A time series with one value per process block";
Chris@0 187 d.unit = "";
Chris@0 188 d.hasFixedBinCount = true;
Chris@0 189 d.binCount = 1;
Chris@0 190 d.hasKnownExtents = false;
Chris@0 191 d.isQuantized = false;
Chris@0 192 d.sampleType = OutputDescriptor::OneSamplePerStep;
Chris@0 193 d.hasDuration = false;
Chris@7 194 m_outputNumbers[d.identifier] = n++;
Chris@0 195 list.push_back(d);
Chris@0 196
Chris@1 197 d.identifier = "curve-fsr";
Chris@1 198 d.name = "Curve: FixedSampleRate";
Chris@2 199 d.description = "A time series with equally-spaced values (independent of process step size)";
Chris@1 200 d.unit = "";
Chris@1 201 d.hasFixedBinCount = true;
Chris@1 202 d.binCount = 1;
Chris@1 203 d.hasKnownExtents = false;
Chris@1 204 d.isQuantized = false;
Chris@1 205 d.sampleType = OutputDescriptor::FixedSampleRate;
Chris@8 206 d.sampleRate = 2.5;
Chris@1 207 d.hasDuration = false;
Chris@7 208 m_outputNumbers[d.identifier] = n++;
Chris@1 209 list.push_back(d);
Chris@1 210
Chris@7 211 d.identifier = "curve-fsr-timed";
Chris@7 212 d.name = "Curve: FixedSampleRate/Timed";
Chris@7 213 d.description = "A time series with a fixed sample rate (independent of process step size) but with timestamps on features";
Chris@7 214 d.unit = "";
Chris@7 215 d.hasFixedBinCount = true;
Chris@7 216 d.binCount = 1;
Chris@7 217 d.hasKnownExtents = false;
Chris@7 218 d.isQuantized = false;
Chris@7 219 d.sampleType = OutputDescriptor::FixedSampleRate;
Chris@8 220 d.sampleRate = 2.5;
Chris@7 221 d.hasDuration = false;
Chris@7 222 m_outputNumbers[d.identifier] = n++;
Chris@7 223 list.push_back(d);
Chris@7 224
Chris@1 225 d.identifier = "curve-vsr";
Chris@1 226 d.name = "Curve: VariableSampleRate";
Chris@2 227 d.description = "A variably-spaced series of values";
Chris@1 228 d.unit = "";
Chris@1 229 d.hasFixedBinCount = true;
Chris@1 230 d.binCount = 1;
Chris@1 231 d.hasKnownExtents = false;
Chris@1 232 d.isQuantized = false;
Chris@1 233 d.sampleType = OutputDescriptor::VariableSampleRate;
Chris@2 234 d.sampleRate = 0;
Chris@1 235 d.hasDuration = false;
Chris@7 236 m_outputNumbers[d.identifier] = n++;
Chris@1 237 list.push_back(d);
Chris@1 238
Chris@2 239 d.identifier = "grid-oss";
Chris@2 240 d.name = "Grid: OneSamplePerStep";
Chris@2 241 d.description = "A fixed-height grid of values with one column per process block";
Chris@2 242 d.unit = "";
Chris@2 243 d.hasFixedBinCount = true;
Chris@4 244 d.binCount = 10;
Chris@2 245 d.hasKnownExtents = false;
Chris@2 246 d.isQuantized = false;
Chris@4 247 d.sampleType = OutputDescriptor::OneSamplePerStep;
Chris@2 248 d.sampleRate = 0;
Chris@2 249 d.hasDuration = false;
Chris@7 250 m_outputNumbers[d.identifier] = n++;
Chris@2 251 list.push_back(d);
Chris@2 252
Chris@2 253 d.identifier = "grid-fsr";
Chris@2 254 d.name = "Grid: FixedSampleRate";
Chris@2 255 d.description = "A fixed-height grid of values with equally-spaced columns (independent of process step size)";
Chris@2 256 d.unit = "";
Chris@2 257 d.hasFixedBinCount = true;
Chris@4 258 d.binCount = 10;
Chris@2 259 d.hasKnownExtents = false;
Chris@2 260 d.isQuantized = false;
Chris@4 261 d.sampleType = OutputDescriptor::FixedSampleRate;
Chris@8 262 d.sampleRate = 2.5;
Chris@2 263 d.hasDuration = false;
Chris@7 264 m_outputNumbers[d.identifier] = n++;
Chris@2 265 list.push_back(d);
Chris@2 266
Chris@5 267 d.identifier = "notes-regions";
Chris@5 268 d.name = "Notes or Regions";
Chris@5 269 d.description = "Variably-spaced features with one value and duration";
Chris@5 270 d.unit = "";
Chris@5 271 d.hasFixedBinCount = true;
Chris@5 272 d.binCount = 1;
Chris@5 273 d.hasKnownExtents = false;
Chris@5 274 d.isQuantized = false;
Chris@5 275 d.sampleType = OutputDescriptor::VariableSampleRate;
Chris@5 276 d.sampleRate = 0;
Chris@5 277 d.hasDuration = true;
Chris@7 278 m_outputNumbers[d.identifier] = n++;
Chris@5 279 list.push_back(d);
Chris@2 280
Chris@19 281 d.identifier = "input-summary";
Chris@19 282 d.name = "Data derived from inputs";
Chris@19 283 d.description = "One-sample-per-step features with n values, where n is the number of input channels. Each feature contains, for each input channel, the first sample value on that channel plus the total number of non-zero samples on that channel";
Chris@18 284 d.unit = "";
Chris@18 285 d.hasFixedBinCount = true;
Chris@18 286 d.binCount = m_channels;
Chris@18 287 d.hasKnownExtents = false;
Chris@18 288 d.isQuantized = false;
Chris@18 289 d.sampleType = OutputDescriptor::OneSamplePerStep;
Chris@18 290 d.hasDuration = false;
Chris@18 291 m_outputNumbers[d.identifier] = n++;
Chris@18 292 list.push_back(d);
Chris@18 293
Chris@20 294 d.identifier = "input-timestamp";
Chris@20 295 d.name = "Input timestamp";
Chris@20 296 d.description = "One-sample-per-step features with one value, containing the time in seconds converted from the timestamp of the corresponding process input block.";
Chris@20 297 d.unit = "s";
Chris@20 298 d.hasFixedBinCount = true;
Chris@20 299 d.binCount = 1;
Chris@20 300 d.hasKnownExtents = false;
Chris@20 301 d.isQuantized = false;
Chris@20 302 d.sampleType = OutputDescriptor::OneSamplePerStep;
Chris@20 303 d.hasDuration = false;
Chris@20 304 m_outputNumbers[d.identifier] = n++;
Chris@20 305 list.push_back(d);
Chris@20 306
Chris@0 307 return list;
Chris@0 308 }
Chris@0 309
Chris@0 310 bool
Chris@0 311 VampTestPlugin::initialise(size_t channels, size_t stepSize, size_t blockSize)
Chris@0 312 {
Chris@0 313 if (channels < getMinChannelCount() ||
Chris@0 314 channels > getMaxChannelCount()) return false;
Chris@0 315
Chris@18 316 m_channels = channels;
Chris@3 317 m_stepSize = stepSize;
Chris@3 318 m_blockSize = blockSize;
Chris@0 319
Chris@0 320 return true;
Chris@0 321 }
Chris@0 322
Chris@0 323 void
Chris@0 324 VampTestPlugin::reset()
Chris@0 325 {
Chris@3 326 m_n = 0;
Chris@3 327 }
Chris@3 328
Chris@3 329 static Vamp::Plugin::Feature
Chris@3 330 instant(RealTime r, int i, int n)
Chris@3 331 {
Chris@19 332 stringstream s;
Chris@3 333 Vamp::Plugin::Feature f;
Chris@3 334 f.hasTimestamp = true;
Chris@3 335 f.timestamp = r;
Chris@3 336 f.hasDuration = false;
Chris@3 337 s << i+1 << " of " << n << " at " << r.toText();
Chris@3 338 f.label = s.str();
Chris@3 339 return f;
Chris@3 340 }
Chris@3 341
Chris@3 342 static Vamp::Plugin::Feature
Chris@3 343 untimedCurveValue(RealTime r, int i, int n)
Chris@3 344 {
Chris@19 345 stringstream s;
Chris@3 346 Vamp::Plugin::Feature f;
Chris@3 347 f.hasTimestamp = false;
Chris@3 348 f.hasDuration = false;
Chris@3 349 float v = float(i) / float(n);
Chris@3 350 f.values.push_back(v);
Chris@3 351 s << i+1 << " of " << n << ": " << v << " at " << r.toText();
Chris@3 352 f.label = s.str();
Chris@3 353 return f;
Chris@0 354 }
Chris@0 355
Chris@4 356 static Vamp::Plugin::Feature
Chris@4 357 timedCurveValue(RealTime r, int i, int n)
Chris@4 358 {
Chris@19 359 stringstream s;
Chris@4 360 Vamp::Plugin::Feature f;
Chris@4 361 f.hasTimestamp = true;
Chris@4 362 f.timestamp = r;
Chris@4 363 f.hasDuration = false;
Chris@4 364 float v = float(i) / float(n);
Chris@4 365 f.values.push_back(v);
Chris@4 366 s << i+1 << " of " << n << ": " << v << " at " << r.toText();
Chris@4 367 f.label = s.str();
Chris@4 368 return f;
Chris@4 369 }
Chris@4 370
Chris@4 371 static Vamp::Plugin::Feature
Chris@7 372 snappedCurveValue(RealTime r, RealTime sn, int i, int n)
Chris@7 373 {
Chris@19 374 stringstream s;
Chris@7 375 Vamp::Plugin::Feature f;
Chris@7 376 f.hasTimestamp = true;
Chris@7 377 f.timestamp = r;
Chris@7 378 f.hasDuration = false;
Chris@7 379 float v = float(i) / float(n);
Chris@7 380 f.values.push_back(v);
Chris@7 381 s << i+1 << " of " << n << ": " << v << " at " << r.toText() << " snap to " << sn.toText();
Chris@7 382 f.label = s.str();
Chris@7 383 return f;
Chris@7 384 }
Chris@7 385
Chris@7 386 static Vamp::Plugin::Feature
Chris@4 387 gridColumn(RealTime r, int i, int n)
Chris@4 388 {
Chris@19 389 stringstream s;
Chris@4 390 Vamp::Plugin::Feature f;
Chris@4 391 f.hasTimestamp = false;
Chris@4 392 f.hasDuration = false;
Chris@4 393 for (int j = 0; j < 10; ++j) {
Chris@4 394 float v = float(j + i + 2) / float(n + 10);
Chris@4 395 f.values.push_back(v);
Chris@4 396 }
Chris@4 397 s << i+1 << " of " << n << " at " << r.toText();
Chris@4 398 f.label = s.str();
Chris@4 399 return f;
Chris@4 400 }
Chris@4 401
Chris@5 402 static Vamp::Plugin::Feature
Chris@5 403 noteOrRegion(RealTime r, RealTime d, int i, int n)
Chris@5 404 {
Chris@19 405 stringstream s;
Chris@5 406 Vamp::Plugin::Feature f;
Chris@5 407 f.hasTimestamp = true;
Chris@5 408 f.timestamp = r;
Chris@5 409 f.hasDuration = true;
Chris@5 410 f.duration = d;
Chris@5 411 float v = float(i) / float(n);
Chris@5 412 f.values.push_back(v);
Chris@5 413 s << i+1 << " of " << n << ": " << v << " at " << r.toText() << " dur. " << d.toText();
Chris@5 414 f.label = s.str();
Chris@5 415 return f;
Chris@5 416 }
Chris@5 417
Chris@7 418 static
Chris@7 419 float snap(float x, float r)
Chris@7 420 {
Chris@7 421 int n = int(x / r + 0.5);
Chris@7 422 return n * r;
Chris@7 423 }
Chris@7 424
Chris@5 425 Vamp::Plugin::FeatureSet
Chris@5 426 VampTestPlugin::featuresFrom(RealTime timestamp, bool final)
Chris@0 427 {
Chris@3 428 FeatureSet fs;
Chris@3 429
Chris@3 430 RealTime endTime = timestamp + RealTime::frame2RealTime
Chris@3 431 (m_stepSize, m_inputSampleRate);
Chris@3 432
Chris@3 433 for (int i = 0; i < (int)m_instants.size(); ++i) {
Chris@5 434
Chris@5 435 if (m_instants[i] >= timestamp && (final || m_instants[i] < endTime)) {
Chris@7 436 fs[m_outputNumbers["instants"]]
Chris@7 437 .push_back(instant(m_instants[i], i, m_instants.size()));
Chris@3 438 }
Chris@4 439
Chris@4 440 RealTime variCurveTime = m_instants[i] / 2;
Chris@5 441 if (variCurveTime >= timestamp && (final || variCurveTime < endTime)) {
Chris@7 442 fs[m_outputNumbers["curve-vsr"]]
Chris@7 443 .push_back(timedCurveValue(variCurveTime, i, m_instants.size()));
Chris@4 444 }
Chris@5 445
Chris@5 446 RealTime noteTime = (m_instants[i] + m_instants[i]) / 3;
Chris@5 447 RealTime noteDuration = RealTime::fromSeconds((i % 2 == 0) ? 1.75 : 0.5);
Chris@5 448
Chris@5 449 if (noteTime >= timestamp && (final || noteTime < endTime)) {
Chris@7 450 fs[m_outputNumbers["notes-regions"]]
Chris@7 451 .push_back(noteOrRegion(noteTime, noteDuration, i, m_instants.size()));
Chris@5 452 }
Chris@3 453 }
Chris@3 454
Chris@5 455 if (!final) {
Chris@3 456
Chris@5 457 if (m_n < 20) {
Chris@7 458 fs[m_outputNumbers["curve-oss"]]
Chris@7 459 .push_back(untimedCurveValue(timestamp, m_n, 20));
Chris@5 460 }
Chris@3 461
Chris@5 462 if (m_n < 5) {
Chris@7 463 fs[m_outputNumbers["curve-fsr"]]
Chris@8 464 .push_back(untimedCurveValue(RealTime::fromSeconds(m_n / 2.5), m_n, 10));
Chris@6 465
Chris@7 466 float s = (m_n / 4) * 2;
Chris@7 467 if ((m_n % 4) > 0) {
Chris@7 468 s += float((m_n % 4) - 1) / 6.0;
Chris@7 469 }
Chris@7 470 fs[m_outputNumbers["curve-fsr-timed"]]
Chris@7 471 .push_back(snappedCurveValue(RealTime::fromSeconds(s),
Chris@8 472 RealTime::fromSeconds(snap(s, 0.4)),
Chris@7 473 m_n, 10));
Chris@5 474 }
Chris@5 475
Chris@5 476 if (m_n < 20) {
Chris@7 477 fs[m_outputNumbers["grid-oss"]]
Chris@7 478 .push_back(gridColumn(timestamp, m_n, 20));
Chris@5 479 }
Chris@5 480
Chris@5 481 } else {
Chris@5 482
Chris@5 483 for (int i = (m_n > 5 ? 5 : m_n); i < 10; ++i) {
Chris@7 484 fs[m_outputNumbers["curve-fsr"]]
Chris@8 485 .push_back(untimedCurveValue(RealTime::fromSeconds(i / 2.5), i, 10));
Chris@7 486
Chris@7 487 float s = (i / 4) * 2;
Chris@7 488 if ((i % 4) > 0) {
Chris@7 489 s += float((i % 4) - 1) / 6.0;
Chris@7 490 }
Chris@7 491 fs[m_outputNumbers["curve-fsr-timed"]]
Chris@7 492 .push_back(snappedCurveValue(RealTime::fromSeconds(s),
Chris@8 493 RealTime::fromSeconds(snap(s, 0.4)),
Chris@7 494 i, 10));
Chris@5 495 }
Chris@5 496
Chris@8 497 for (int i = 0; i < 10; ++i) {
Chris@7 498 fs[m_outputNumbers["grid-fsr"]]
Chris@9 499 .push_back(gridColumn(RealTime::fromSeconds(i / 2.5), i, 10));
Chris@5 500 }
Chris@4 501 }
Chris@4 502
Chris@3 503 m_lastTime = endTime;
Chris@3 504 m_n = m_n + 1;
Chris@3 505 return fs;
Chris@5 506 }
Chris@5 507
Chris@5 508 VampTestPlugin::FeatureSet
Chris@5 509 VampTestPlugin::process(const float *const *inputBuffers, RealTime timestamp)
Chris@5 510 {
Chris@17 511 if (!m_produceOutput) return FeatureSet();
Chris@5 512 FeatureSet fs = featuresFrom(timestamp, false);
Chris@18 513
Chris@18 514 Feature f;
Chris@18 515 for (int c = 0; c < m_channels; ++c) {
Chris@19 516 // first value plus number of non-zero values
Chris@19 517 float sum = inputBuffers[c][0];
Chris@18 518 for (int i = 0; i < m_blockSize; ++i) {
Chris@19 519 if (inputBuffers[c][i] != 0.f) sum += 1;
Chris@18 520 }
Chris@19 521 f.values.push_back(sum);
Chris@18 522 }
Chris@19 523 fs[m_outputNumbers["input-summary"]].push_back(f);
Chris@20 524
Chris@20 525 f.values.clear();
Chris@20 526 f.values.push_back(float(timestamp / RealTime(1, 0)));
Chris@20 527 fs[m_outputNumbers["input-timestamp"]].push_back(f);
Chris@18 528
Chris@5 529 return fs;
Chris@0 530 }
Chris@0 531
Chris@0 532 VampTestPlugin::FeatureSet
Chris@0 533 VampTestPlugin::getRemainingFeatures()
Chris@0 534 {
Chris@17 535 if (!m_produceOutput) return FeatureSet();
Chris@5 536 FeatureSet fs = featuresFrom(m_lastTime, true);
Chris@3 537 return fs;
Chris@0 538 }
Chris@0 539