annotate VampTestPlugin.cpp @ 19:534b001d8e8f

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