annotate plugin/transform/FeatureExtractionModelTransformer.cpp @ 339:ba30f4a3e3be

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