annotate transform/FeatureExtractionPluginTransform.cpp @ 182:21a76c9ed5c3

* Merge transform directory from sv-match-alignment branch (the previous comment included notes for this stuff, but I missed it in the actual merge) * Fix crash when a transform fails to create an output model and the thread that created the transform then deletes its input model thinking it's no longer needed, even though the transform run thread is still using it -- fix is to wait() on the transform before returning the null output model
author Chris Cannam
date Fri, 28 Sep 2007 16:15:06 +0000
parents dab257bd9d2d
children ebd906049fb6
rev   line source
Chris@0 1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
Chris@0 2
Chris@0 3 /*
Chris@0 4 Sonic Visualiser
Chris@0 5 An audio file viewer and annotation editor.
Chris@0 6 Centre for Digital Music, Queen Mary, University of London.
Chris@77 7 This file copyright 2006 Chris Cannam and QMUL.
Chris@0 8
Chris@0 9 This program is free software; you can redistribute it and/or
Chris@0 10 modify it under the terms of the GNU General Public License as
Chris@0 11 published by the Free Software Foundation; either version 2 of the
Chris@0 12 License, or (at your option) any later version. See the file
Chris@0 13 COPYING included with this distribution for more information.
Chris@0 14 */
Chris@0 15
Chris@0 16 #include "FeatureExtractionPluginTransform.h"
Chris@0 17
Chris@0 18 #include "plugin/FeatureExtractionPluginFactory.h"
Chris@0 19 #include "plugin/PluginXml.h"
Chris@0 20 #include "vamp-sdk/Plugin.h"
Chris@0 21
Chris@1 22 #include "data/model/Model.h"
Chris@0 23 #include "base/Window.h"
Chris@1 24 #include "data/model/SparseOneDimensionalModel.h"
Chris@1 25 #include "data/model/SparseTimeValueModel.h"
Chris@3 26 #include "data/model/EditableDenseThreeDimensionalModel.h"
Chris@1 27 #include "data/model/DenseTimeValueModel.h"
Chris@1 28 #include "data/model/NoteModel.h"
Chris@3 29 #include "data/model/FFTModel.h"
Chris@55 30 #include "data/model/WaveFileModel.h"
Chris@0 31
Chris@71 32 #include <QMessageBox>
Chris@71 33
Chris@0 34 #include <iostream>
Chris@0 35
Chris@0 36 FeatureExtractionPluginTransform::FeatureExtractionPluginTransform(Model *inputModel,
Chris@0 37 QString pluginId,
Chris@27 38 const ExecutionContext &context,
Chris@0 39 QString configurationXml,
Chris@27 40 QString outputName) :
Chris@27 41 PluginTransform(inputModel, context),
Chris@0 42 m_plugin(0),
Chris@0 43 m_descriptor(0),
Chris@0 44 m_outputFeatureNo(0)
Chris@0 45 {
Chris@0 46 // std::cerr << "FeatureExtractionPluginTransform::FeatureExtractionPluginTransform: plugin " << pluginId.toStdString() << ", outputName " << outputName.toStdString() << std::endl;
Chris@0 47
Chris@0 48 FeatureExtractionPluginFactory *factory =
Chris@0 49 FeatureExtractionPluginFactory::instanceFor(pluginId);
Chris@0 50
Chris@0 51 if (!factory) {
Chris@0 52 std::cerr << "FeatureExtractionPluginTransform: No factory available for plugin id \""
Chris@0 53 << pluginId.toStdString() << "\"" << std::endl;
Chris@0 54 return;
Chris@0 55 }
Chris@0 56
Chris@0 57 m_plugin = factory->instantiatePlugin(pluginId, m_input->getSampleRate());
Chris@0 58
Chris@0 59 if (!m_plugin) {
Chris@0 60 std::cerr << "FeatureExtractionPluginTransform: Failed to instantiate plugin \""
Chris@0 61 << pluginId.toStdString() << "\"" << std::endl;
Chris@0 62 return;
Chris@0 63 }
Chris@0 64
Chris@0 65 if (configurationXml != "") {
Chris@0 66 PluginXml(m_plugin).setParametersFromXml(configurationXml);
Chris@0 67 }
Chris@0 68
Chris@0 69 DenseTimeValueModel *input = getInput();
Chris@0 70 if (!input) return;
Chris@0 71
Chris@0 72 size_t channelCount = input->getChannelCount();
Chris@0 73 if (m_plugin->getMaxChannelCount() < channelCount) {
Chris@0 74 channelCount = 1;
Chris@0 75 }
Chris@0 76 if (m_plugin->getMinChannelCount() > channelCount) {
Chris@0 77 std::cerr << "FeatureExtractionPluginTransform:: "
Chris@0 78 << "Can't provide enough channels to plugin (plugin min "
Chris@0 79 << m_plugin->getMinChannelCount() << ", max "
Chris@0 80 << m_plugin->getMaxChannelCount() << ", input model has "
Chris@0 81 << input->getChannelCount() << ")" << std::endl;
Chris@0 82 return;
Chris@0 83 }
Chris@0 84
Chris@27 85 std::cerr << "Initialising feature extraction plugin with channels = "
Chris@27 86 << channelCount << ", step = " << m_context.stepSize
Chris@27 87 << ", block = " << m_context.blockSize << std::endl;
Chris@27 88
Chris@27 89 if (!m_plugin->initialise(channelCount,
Chris@27 90 m_context.stepSize,
Chris@27 91 m_context.blockSize)) {
Chris@0 92 std::cerr << "FeatureExtractionPluginTransform: Plugin "
Chris@107 93 << m_plugin->getIdentifier() << " failed to initialise!" << std::endl;
Chris@0 94 return;
Chris@0 95 }
Chris@0 96
Chris@0 97 Vamp::Plugin::OutputList outputs = m_plugin->getOutputDescriptors();
Chris@0 98
Chris@0 99 if (outputs.empty()) {
Chris@0 100 std::cerr << "FeatureExtractionPluginTransform: Plugin \""
Chris@0 101 << pluginId.toStdString() << "\" has no outputs" << std::endl;
Chris@0 102 return;
Chris@0 103 }
Chris@0 104
Chris@0 105 for (size_t i = 0; i < outputs.size(); ++i) {
Chris@107 106 if (outputName == "" || outputs[i].identifier == outputName.toStdString()) {
Chris@0 107 m_outputFeatureNo = i;
Chris@0 108 m_descriptor = new Vamp::Plugin::OutputDescriptor
Chris@0 109 (outputs[i]);
Chris@0 110 break;
Chris@0 111 }
Chris@0 112 }
Chris@0 113
Chris@0 114 if (!m_descriptor) {
Chris@0 115 std::cerr << "FeatureExtractionPluginTransform: Plugin \""
Chris@0 116 << pluginId.toStdString() << "\" has no output named \""
Chris@0 117 << outputName.toStdString() << "\"" << std::endl;
Chris@0 118 return;
Chris@0 119 }
Chris@0 120
Chris@0 121 // std::cerr << "FeatureExtractionPluginTransform: output sample type "
Chris@0 122 // << m_descriptor->sampleType << std::endl;
Chris@0 123
Chris@0 124 int binCount = 1;
Chris@0 125 float minValue = 0.0, maxValue = 0.0;
Chris@134 126 bool haveExtents = false;
Chris@0 127
Chris@0 128 if (m_descriptor->hasFixedBinCount) {
Chris@0 129 binCount = m_descriptor->binCount;
Chris@0 130 }
Chris@0 131
Chris@0 132 // std::cerr << "FeatureExtractionPluginTransform: output bin count "
Chris@0 133 // << binCount << std::endl;
Chris@0 134
Chris@0 135 if (binCount > 0 && m_descriptor->hasKnownExtents) {
Chris@0 136 minValue = m_descriptor->minValue;
Chris@0 137 maxValue = m_descriptor->maxValue;
Chris@134 138 haveExtents = true;
Chris@0 139 }
Chris@0 140
Chris@0 141 size_t modelRate = m_input->getSampleRate();
Chris@0 142 size_t modelResolution = 1;
Chris@0 143
Chris@0 144 switch (m_descriptor->sampleType) {
Chris@0 145
Chris@0 146 case Vamp::Plugin::OutputDescriptor::VariableSampleRate:
Chris@0 147 if (m_descriptor->sampleRate != 0.0) {
Chris@0 148 modelResolution = size_t(modelRate / m_descriptor->sampleRate + 0.001);
Chris@0 149 }
Chris@0 150 break;
Chris@0 151
Chris@0 152 case Vamp::Plugin::OutputDescriptor::OneSamplePerStep:
Chris@27 153 modelResolution = m_context.stepSize;
Chris@0 154 break;
Chris@0 155
Chris@0 156 case Vamp::Plugin::OutputDescriptor::FixedSampleRate:
Chris@0 157 modelRate = size_t(m_descriptor->sampleRate + 0.001);
Chris@0 158 break;
Chris@0 159 }
Chris@0 160
Chris@0 161 if (binCount == 0) {
Chris@0 162
Chris@0 163 m_output = new SparseOneDimensionalModel(modelRate, modelResolution,
Chris@0 164 false);
Chris@0 165
Chris@0 166 } else if (binCount == 1) {
Chris@0 167
Chris@134 168 SparseTimeValueModel *model;
Chris@134 169 if (haveExtents) {
Chris@134 170 model = new SparseTimeValueModel
Chris@134 171 (modelRate, modelResolution, minValue, maxValue, false);
Chris@134 172 } else {
Chris@134 173 model = new SparseTimeValueModel
Chris@134 174 (modelRate, modelResolution, false);
Chris@134 175 }
Chris@0 176 model->setScaleUnits(outputs[m_outputFeatureNo].unit.c_str());
Chris@0 177
Chris@0 178 m_output = model;
Chris@0 179
Chris@0 180 } else if (m_descriptor->sampleType ==
Chris@0 181 Vamp::Plugin::OutputDescriptor::VariableSampleRate) {
Chris@0 182
Chris@0 183 // We don't have a sparse 3D model, so interpret this as a
Chris@0 184 // note model. There's nothing to define which values to use
Chris@0 185 // as which parameters of the note -- for the moment let's
Chris@0 186 // treat the first as pitch, second as duration in frames,
Chris@0 187 // third (if present) as velocity. (Our note model doesn't
Chris@0 188 // yet store velocity.)
Chris@0 189 //!!! todo: ask the user!
Chris@0 190
Chris@134 191 NoteModel *model;
Chris@134 192 if (haveExtents) {
Chris@134 193 model = new NoteModel
Chris@134 194 (modelRate, modelResolution, minValue, maxValue, false);
Chris@134 195 } else {
Chris@134 196 model = new NoteModel
Chris@134 197 (modelRate, modelResolution, false);
Chris@134 198 }
Chris@0 199 model->setScaleUnits(outputs[m_outputFeatureNo].unit.c_str());
Chris@0 200
Chris@0 201 m_output = model;
Chris@0 202
Chris@0 203 } else {
Chris@134 204
Chris@134 205 EditableDenseThreeDimensionalModel *model =
Chris@134 206 new EditableDenseThreeDimensionalModel
Chris@3 207 (modelRate, modelResolution, binCount, false);
Chris@0 208
Chris@0 209 if (!m_descriptor->binNames.empty()) {
Chris@0 210 std::vector<QString> names;
Chris@0 211 for (size_t i = 0; i < m_descriptor->binNames.size(); ++i) {
Chris@0 212 names.push_back(m_descriptor->binNames[i].c_str());
Chris@0 213 }
Chris@134 214 model->setBinNames(names);
Chris@0 215 }
Chris@134 216
Chris@134 217 m_output = model;
Chris@0 218 }
Chris@0 219 }
Chris@0 220
Chris@0 221 FeatureExtractionPluginTransform::~FeatureExtractionPluginTransform()
Chris@0 222 {
Chris@182 223 std::cerr << "FeatureExtractionPluginTransform::~FeatureExtractionPluginTransform()" << std::endl;
Chris@0 224 delete m_plugin;
Chris@0 225 delete m_descriptor;
Chris@0 226 }
Chris@0 227
Chris@0 228 DenseTimeValueModel *
Chris@0 229 FeatureExtractionPluginTransform::getInput()
Chris@0 230 {
Chris@0 231 DenseTimeValueModel *dtvm =
Chris@0 232 dynamic_cast<DenseTimeValueModel *>(getInputModel());
Chris@0 233 if (!dtvm) {
Chris@0 234 std::cerr << "FeatureExtractionPluginTransform::getInput: WARNING: Input model is not conformable to DenseTimeValueModel" << std::endl;
Chris@0 235 }
Chris@0 236 return dtvm;
Chris@0 237 }
Chris@0 238
Chris@0 239 void
Chris@0 240 FeatureExtractionPluginTransform::run()
Chris@0 241 {
Chris@0 242 DenseTimeValueModel *input = getInput();
Chris@0 243 if (!input) return;
Chris@0 244
Chris@182 245 if (!m_output) return;
Chris@182 246
Chris@55 247 while (!input->isReady()) {
Chris@148 248 /*
Chris@148 249 if (dynamic_cast<WaveFileModel *>(input)) {
Chris@148 250 std::cerr << "FeatureExtractionPluginTransform::run: Model is not ready, but it's not a WaveFileModel (it's a " << typeid(input).name() << "), so that's OK" << std::endl;
Chris@148 251 sleep(2);
Chris@148 252 break; // no need to wait
Chris@148 253 }
Chris@148 254 */
Chris@55 255 std::cerr << "FeatureExtractionPluginTransform::run: Waiting for input model to be ready..." << std::endl;
Chris@55 256 sleep(1);
Chris@55 257 }
Chris@55 258
Chris@0 259 size_t sampleRate = m_input->getSampleRate();
Chris@0 260
Chris@0 261 size_t channelCount = input->getChannelCount();
Chris@0 262 if (m_plugin->getMaxChannelCount() < channelCount) {
Chris@0 263 channelCount = 1;
Chris@0 264 }
Chris@0 265
Chris@0 266 float **buffers = new float*[channelCount];
Chris@0 267 for (size_t ch = 0; ch < channelCount; ++ch) {
Chris@79 268 buffers[ch] = new float[m_context.blockSize + 2];
Chris@0 269 }
Chris@0 270
Chris@0 271 bool frequencyDomain = (m_plugin->getInputDomain() ==
Chris@0 272 Vamp::Plugin::FrequencyDomain);
Chris@3 273 std::vector<FFTModel *> fftModels;
Chris@0 274
Chris@0 275 if (frequencyDomain) {
Chris@0 276 for (size_t ch = 0; ch < channelCount; ++ch) {
Chris@61 277 FFTModel *model = new FFTModel
Chris@0 278 (getInput(),
Chris@27 279 channelCount == 1 ? m_context.channel : ch,
Chris@27 280 m_context.windowType,
Chris@27 281 m_context.blockSize,
Chris@27 282 m_context.stepSize,
Chris@27 283 m_context.blockSize,
Chris@61 284 false);
Chris@71 285 if (!model->isOK()) {
Chris@71 286 QMessageBox::critical
Chris@71 287 (0, tr("FFT cache failed"),
Chris@71 288 tr("Failed to create the FFT model for this transform.\n"
Chris@71 289 "There may be insufficient memory or disc space to continue."));
Chris@71 290 delete model;
Chris@71 291 setCompletion(100);
Chris@71 292 return;
Chris@71 293 }
Chris@61 294 model->resume();
Chris@61 295 fftModels.push_back(model);
Chris@0 296 }
Chris@0 297 }
Chris@0 298
Chris@0 299 long startFrame = m_input->getStartFrame();
Chris@0 300 long endFrame = m_input->getEndFrame();
Chris@182 301
Chris@182 302 long contextStart = m_context.startFrame;
Chris@182 303 long contextDuration = m_context.duration;
Chris@182 304
Chris@182 305 if (contextStart == 0 || contextStart < startFrame) {
Chris@182 306 contextStart = startFrame;
Chris@182 307 }
Chris@182 308
Chris@182 309 if (contextDuration == 0) {
Chris@182 310 contextDuration = endFrame - contextStart;
Chris@182 311 }
Chris@182 312 if (contextStart + contextDuration > endFrame) {
Chris@182 313 contextDuration = endFrame - contextStart;
Chris@182 314 }
Chris@182 315
Chris@182 316 long blockFrame = contextStart;
Chris@0 317
Chris@0 318 long prevCompletion = 0;
Chris@0 319
Chris@182 320 setCompletion(0);
Chris@182 321
Chris@118 322 while (!m_abandoned) {
Chris@0 323
Chris@0 324 if (frequencyDomain) {
Chris@182 325 if (blockFrame - int(m_context.blockSize)/2 >
Chris@182 326 contextStart + contextDuration) break;
Chris@0 327 } else {
Chris@182 328 if (blockFrame >=
Chris@182 329 contextStart + contextDuration) break;
Chris@0 330 }
Chris@0 331
Chris@149 332 // std::cerr << "FeatureExtractionPluginTransform::run: blockFrame "
Chris@176 333 // << blockFrame << ", endFrame " << endFrame << ", blockSize "
Chris@176 334 // << m_context.blockSize << std::endl;
Chris@0 335
Chris@0 336 long completion =
Chris@182 337 (((blockFrame - contextStart) / m_context.stepSize) * 99) /
Chris@182 338 (contextDuration / m_context.stepSize);
Chris@0 339
Chris@0 340 // channelCount is either m_input->channelCount or 1
Chris@0 341
Chris@0 342 for (size_t ch = 0; ch < channelCount; ++ch) {
Chris@0 343 if (frequencyDomain) {
Chris@27 344 int column = (blockFrame - startFrame) / m_context.stepSize;
Chris@79 345 for (size_t i = 0; i <= m_context.blockSize/2; ++i) {
Chris@3 346 fftModels[ch]->getValuesAt
Chris@0 347 (column, i, buffers[ch][i*2], buffers[ch][i*2+1]);
Chris@0 348 }
Chris@0 349 } else {
Chris@0 350 getFrames(ch, channelCount,
Chris@27 351 blockFrame, m_context.blockSize, buffers[ch]);
Chris@0 352 }
Chris@0 353 }
Chris@0 354
Chris@0 355 Vamp::Plugin::FeatureSet features = m_plugin->process
Chris@0 356 (buffers, Vamp::RealTime::frame2RealTime(blockFrame, sampleRate));
Chris@0 357
Chris@0 358 for (size_t fi = 0; fi < features[m_outputFeatureNo].size(); ++fi) {
Chris@0 359 Vamp::Plugin::Feature feature =
Chris@0 360 features[m_outputFeatureNo][fi];
Chris@0 361 addFeature(blockFrame, feature);
Chris@0 362 }
Chris@0 363
Chris@182 364 if (blockFrame == contextStart || completion > prevCompletion) {
Chris@0 365 setCompletion(completion);
Chris@0 366 prevCompletion = completion;
Chris@0 367 }
Chris@0 368
Chris@27 369 blockFrame += m_context.stepSize;
Chris@0 370 }
Chris@0 371
Chris@118 372 if (m_abandoned) return;
Chris@118 373
Chris@0 374 Vamp::Plugin::FeatureSet features = m_plugin->getRemainingFeatures();
Chris@0 375
Chris@0 376 for (size_t fi = 0; fi < features[m_outputFeatureNo].size(); ++fi) {
Chris@0 377 Vamp::Plugin::Feature feature =
Chris@0 378 features[m_outputFeatureNo][fi];
Chris@0 379 addFeature(blockFrame, feature);
Chris@0 380 }
Chris@0 381
Chris@0 382 if (frequencyDomain) {
Chris@0 383 for (size_t ch = 0; ch < channelCount; ++ch) {
Chris@3 384 delete fftModels[ch];
Chris@0 385 }
Chris@0 386 }
Chris@0 387
Chris@0 388 setCompletion(100);
Chris@0 389 }
Chris@0 390
Chris@0 391 void
Chris@0 392 FeatureExtractionPluginTransform::getFrames(int channel, int channelCount,
Chris@0 393 long startFrame, long size,
Chris@0 394 float *buffer)
Chris@0 395 {
Chris@0 396 long offset = 0;
Chris@0 397
Chris@0 398 if (startFrame < 0) {
Chris@0 399 for (int i = 0; i < size && startFrame + i < 0; ++i) {
Chris@0 400 buffer[i] = 0.0f;
Chris@0 401 }
Chris@0 402 offset = -startFrame;
Chris@0 403 size -= offset;
Chris@0 404 if (size <= 0) return;
Chris@0 405 startFrame = 0;
Chris@0 406 }
Chris@0 407
Chris@0 408 long got = getInput()->getValues
Chris@27 409 ((channelCount == 1 ? m_context.channel : channel),
Chris@0 410 startFrame, startFrame + size, buffer + offset);
Chris@0 411
Chris@0 412 while (got < size) {
Chris@0 413 buffer[offset + got] = 0.0;
Chris@0 414 ++got;
Chris@0 415 }
Chris@0 416
Chris@27 417 if (m_context.channel == -1 && channelCount == 1 &&
Chris@0 418 getInput()->getChannelCount() > 1) {
Chris@0 419 // use mean instead of sum, as plugin input
Chris@0 420 int cc = getInput()->getChannelCount();
Chris@0 421 for (long i = 0; i < size; ++i) {
Chris@0 422 buffer[i] /= cc;
Chris@0 423 }
Chris@0 424 }
Chris@0 425 }
Chris@0 426
Chris@0 427 void
Chris@0 428 FeatureExtractionPluginTransform::addFeature(size_t blockFrame,
Chris@0 429 const Vamp::Plugin::Feature &feature)
Chris@0 430 {
Chris@0 431 size_t inputRate = m_input->getSampleRate();
Chris@0 432
Chris@0 433 // std::cerr << "FeatureExtractionPluginTransform::addFeature("
Chris@0 434 // << blockFrame << ")" << std::endl;
Chris@0 435
Chris@0 436 int binCount = 1;
Chris@0 437 if (m_descriptor->hasFixedBinCount) {
Chris@0 438 binCount = m_descriptor->binCount;
Chris@0 439 }
Chris@0 440
Chris@0 441 size_t frame = blockFrame;
Chris@0 442
Chris@0 443 if (m_descriptor->sampleType ==
Chris@0 444 Vamp::Plugin::OutputDescriptor::VariableSampleRate) {
Chris@0 445
Chris@0 446 if (!feature.hasTimestamp) {
Chris@0 447 std::cerr
Chris@0 448 << "WARNING: FeatureExtractionPluginTransform::addFeature: "
Chris@0 449 << "Feature has variable sample rate but no timestamp!"
Chris@0 450 << std::endl;
Chris@0 451 return;
Chris@0 452 } else {
Chris@0 453 frame = Vamp::RealTime::realTime2Frame(feature.timestamp, inputRate);
Chris@0 454 }
Chris@0 455
Chris@0 456 } else if (m_descriptor->sampleType ==
Chris@0 457 Vamp::Plugin::OutputDescriptor::FixedSampleRate) {
Chris@0 458
Chris@0 459 if (feature.hasTimestamp) {
Chris@0 460 //!!! warning: sampleRate may be non-integral
Chris@0 461 frame = Vamp::RealTime::realTime2Frame(feature.timestamp,
Chris@137 462 lrintf(m_descriptor->sampleRate));
Chris@0 463 } else {
Chris@50 464 frame = m_output->getEndFrame();
Chris@0 465 }
Chris@0 466 }
Chris@0 467
Chris@0 468 if (binCount == 0) {
Chris@0 469
Chris@0 470 SparseOneDimensionalModel *model = getOutput<SparseOneDimensionalModel>();
Chris@0 471 if (!model) return;
Chris@0 472 model->addPoint(SparseOneDimensionalModel::Point(frame, feature.label.c_str()));
Chris@0 473
Chris@0 474 } else if (binCount == 1) {
Chris@0 475
Chris@0 476 float value = 0.0;
Chris@0 477 if (feature.values.size() > 0) value = feature.values[0];
Chris@0 478
Chris@0 479 SparseTimeValueModel *model = getOutput<SparseTimeValueModel>();
Chris@0 480 if (!model) return;
Chris@0 481 model->addPoint(SparseTimeValueModel::Point(frame, value, feature.label.c_str()));
Chris@179 482 // std::cerr << "SparseTimeValueModel::addPoint(" << frame << ", " << value << "), " << feature.label.c_str() << std::endl;
Chris@0 483
Chris@0 484 } else if (m_descriptor->sampleType ==
Chris@0 485 Vamp::Plugin::OutputDescriptor::VariableSampleRate) {
Chris@0 486
Chris@0 487 float pitch = 0.0;
Chris@0 488 if (feature.values.size() > 0) pitch = feature.values[0];
Chris@0 489
Chris@0 490 float duration = 1;
Chris@0 491 if (feature.values.size() > 1) duration = feature.values[1];
Chris@0 492
Chris@0 493 float velocity = 100;
Chris@0 494 if (feature.values.size() > 2) velocity = feature.values[2];
Chris@0 495
Chris@0 496 NoteModel *model = getOutput<NoteModel>();
Chris@0 497 if (!model) return;
Chris@0 498
Chris@137 499 model->addPoint(NoteModel::Point(frame, pitch,
Chris@137 500 lrintf(duration),
Chris@137 501 feature.label.c_str()));
Chris@0 502
Chris@0 503 } else {
Chris@0 504
Chris@51 505 DenseThreeDimensionalModel::Column values = feature.values;
Chris@0 506
Chris@3 507 EditableDenseThreeDimensionalModel *model =
Chris@3 508 getOutput<EditableDenseThreeDimensionalModel>();
Chris@0 509 if (!model) return;
Chris@0 510
Chris@51 511 model->setColumn(frame / model->getResolution(), values);
Chris@0 512 }
Chris@0 513 }
Chris@0 514
Chris@0 515 void
Chris@0 516 FeatureExtractionPluginTransform::setCompletion(int completion)
Chris@0 517 {
Chris@0 518 int binCount = 1;
Chris@0 519 if (m_descriptor->hasFixedBinCount) {
Chris@0 520 binCount = m_descriptor->binCount;
Chris@0 521 }
Chris@0 522
Chris@182 523 std::cerr << "FeatureExtractionPluginTransform::setCompletion("
Chris@182 524 << completion << ")" << std::endl;
Chris@33 525
Chris@0 526 if (binCount == 0) {
Chris@0 527
Chris@0 528 SparseOneDimensionalModel *model = getOutput<SparseOneDimensionalModel>();
Chris@0 529 if (!model) return;
Chris@0 530 model->setCompletion(completion);
Chris@0 531
Chris@0 532 } else if (binCount == 1) {
Chris@0 533
Chris@0 534 SparseTimeValueModel *model = getOutput<SparseTimeValueModel>();
Chris@0 535 if (!model) return;
Chris@0 536 model->setCompletion(completion);
Chris@0 537
Chris@0 538 } else if (m_descriptor->sampleType ==
Chris@0 539 Vamp::Plugin::OutputDescriptor::VariableSampleRate) {
Chris@0 540
Chris@0 541 NoteModel *model = getOutput<NoteModel>();
Chris@0 542 if (!model) return;
Chris@0 543 model->setCompletion(completion);
Chris@0 544
Chris@0 545 } else {
Chris@0 546
Chris@3 547 EditableDenseThreeDimensionalModel *model =
Chris@3 548 getOutput<EditableDenseThreeDimensionalModel>();
Chris@0 549 if (!model) return;
Chris@0 550 model->setCompletion(completion);
Chris@0 551 }
Chris@0 552 }
Chris@0 553