comparison transform/FeatureExtractionModelTransformer.cpp @ 1766:85b9b466a59f

Merge from branch by-id
author Chris Cannam
date Wed, 17 Jul 2019 14:24:51 +0100
parents d1e2062cbdec
children 9a8327e7b2dc
comparison
equal deleted inserted replaced
1730:649ac57c5a2d 1766:85b9b466a59f
81 // All transforms must use the same plugin, parameters, and 81 // All transforms must use the same plugin, parameters, and
82 // inputs: they can differ only in choice of plugin output. So we 82 // inputs: they can differ only in choice of plugin output. So we
83 // initialise based purely on the first transform in the list (but 83 // initialise based purely on the first transform in the list (but
84 // first check that they are actually similar as promised) 84 // first check that they are actually similar as promised)
85 85
86 for (int j = 1; j < (int)m_transforms.size(); ++j) { 86 for (int j = 1; in_range_for(m_transforms, j); ++j) {
87 if (!areTransformsSimilar(m_transforms[0], m_transforms[j])) { 87 if (!areTransformsSimilar(m_transforms[0], m_transforms[j])) {
88 m_message = tr("Transforms supplied to a single FeatureExtractionModelTransformer instance must be similar in every respect except plugin output"); 88 m_message = tr("Transforms supplied to a single FeatureExtractionModelTransformer instance must be similar in every respect except plugin output");
89 SVCERR << m_message << endl; 89 SVCERR << m_message << endl;
90 return false; 90 return false;
91 } 91 }
102 m_message = tr("No factory available for feature extraction plugin id \"%1\" (unknown plugin type, or internal error?)").arg(pluginId); 102 m_message = tr("No factory available for feature extraction plugin id \"%1\" (unknown plugin type, or internal error?)").arg(pluginId);
103 SVCERR << m_message << endl; 103 SVCERR << m_message << endl;
104 return false; 104 return false;
105 } 105 }
106 106
107 DenseTimeValueModel *input = getConformingInput(); 107 auto input = ModelById::getAs<DenseTimeValueModel>(getInputModel());
108 if (!input) { 108 if (!input) {
109 m_message = tr("Input model for feature extraction plugin \"%1\" is of wrong type (internal error?)").arg(pluginId); 109 m_message = tr("Input model for feature extraction plugin \"%1\" is of wrong type (internal error?)").arg(pluginId);
110 SVCERR << m_message << endl; 110 SVCERR << m_message << endl;
111 return false; 111 return false;
112 } 112 }
156 if (step != preferredStep || block != preferredBlock) { 156 if (step != preferredStep || block != preferredBlock) {
157 157
158 SVDEBUG << "Initialisation failed, trying again with preferred step = " 158 SVDEBUG << "Initialisation failed, trying again with preferred step = "
159 << preferredStep << ", block = " << preferredBlock << endl; 159 << preferredStep << ", block = " << preferredBlock << endl;
160 160
161 if (!m_plugin->initialise(channelCount, preferredStep, preferredBlock)) { 161 if (!m_plugin->initialise(channelCount,
162 preferredStep,
163 preferredBlock)) {
162 164
163 SVDEBUG << "Initialisation failed again" << endl; 165 SVDEBUG << "Initialisation failed again" << endl;
164 166
165 m_message = tr("Failed to initialise feature extraction plugin \"%1\"").arg(pluginId); 167 m_message = tr("Failed to initialise feature extraction plugin \"%1\"").arg(pluginId);
166 SVCERR << m_message << endl; 168 SVCERR << m_message << endl;
219 m_message = tr("Plugin \"%1\" has no outputs").arg(pluginId); 221 m_message = tr("Plugin \"%1\" has no outputs").arg(pluginId);
220 SVCERR << m_message << endl; 222 SVCERR << m_message << endl;
221 return false; 223 return false;
222 } 224 }
223 225
224 for (int j = 0; j < (int)m_transforms.size(); ++j) { 226 for (int j = 0; in_range_for(m_transforms, j); ++j) {
225 227
226 for (int i = 0; i < (int)outputs.size(); ++i) { 228 for (int i = 0; in_range_for(outputs, i); ++i) {
227 // SVDEBUG << "comparing output " << i << " name \"" << outputs[i].identifier << "\" with expected \"" << m_transform.getOutput() << "\"" << endl; 229
228 if (m_transforms[j].getOutput() == "" || 230 if (m_transforms[j].getOutput() == "" ||
229 outputs[i].identifier == m_transforms[j].getOutput().toStdString()) { 231 outputs[i].identifier ==
232 m_transforms[j].getOutput().toStdString()) {
233
230 m_outputNos.push_back(i); 234 m_outputNos.push_back(i);
231 m_descriptors.push_back(new Vamp::Plugin::OutputDescriptor(outputs[i])); 235 m_descriptors.push_back(outputs[i]);
232 m_fixedRateFeatureNos.push_back(-1); // we increment before use 236 m_fixedRateFeatureNos.push_back(-1); // we increment before use
233 break; 237 break;
234 } 238 }
235 } 239 }
236 240
237 if ((int)m_descriptors.size() <= j) { 241 if (!in_range_for(m_descriptors, j)) {
238 m_message = tr("Plugin \"%1\" has no output named \"%2\"") 242 m_message = tr("Plugin \"%1\" has no output named \"%2\"")
239 .arg(pluginId) 243 .arg(pluginId)
240 .arg(m_transforms[j].getOutput()); 244 .arg(m_transforms[j].getOutput());
241 SVCERR << m_message << endl; 245 SVCERR << m_message << endl;
242 return false; 246 return false;
243 } 247 }
244 } 248 }
245 249
246 for (int j = 0; j < (int)m_transforms.size(); ++j) { 250 for (int j = 0; in_range_for(m_transforms, j); ++j) {
247 createOutputModels(j); 251 createOutputModels(j);
248 } 252 }
249 253
250 m_outputMutex.lock(); 254 m_outputMutex.lock();
251 m_haveOutputs = true; 255 m_haveOutputs = true;
269 // accidentally done so, so just in case: 273 // accidentally done so, so just in case:
270 SVCERR << "FeatureExtractionModelTransformer: caught exception while deleting plugin: " << e.what() << endl; 274 SVCERR << "FeatureExtractionModelTransformer: caught exception while deleting plugin: " << e.what() << endl;
271 m_message = e.what(); 275 m_message = e.what();
272 } 276 }
273 m_plugin = nullptr; 277 m_plugin = nullptr;
274 278
275 for (int j = 0; j < (int)m_descriptors.size(); ++j) { 279 m_descriptors.clear();
276 delete m_descriptors[j];
277 }
278 } 280 }
279 281
280 void 282 void
281 FeatureExtractionModelTransformer::createOutputModels(int n) 283 FeatureExtractionModelTransformer::createOutputModels(int n)
282 { 284 {
283 DenseTimeValueModel *input = getConformingInput(); 285 auto input = ModelById::getAs<DenseTimeValueModel>(getInputModel());
286 if (!input) return;
284 287
285 PluginRDFDescription description(m_transforms[n].getPluginIdentifier()); 288 PluginRDFDescription description(m_transforms[n].getPluginIdentifier());
286 QString outputId = m_transforms[n].getOutput(); 289 QString outputId = m_transforms[n].getOutput();
287 290
288 int binCount = 1; 291 int binCount = 1;
289 float minValue = 0.0, maxValue = 0.0; 292 float minValue = 0.0, maxValue = 0.0;
290 bool haveExtents = false; 293 bool haveExtents = false;
291 bool haveBinCount = m_descriptors[n]->hasFixedBinCount; 294 bool haveBinCount = m_descriptors[n].hasFixedBinCount;
292 295
293 if (haveBinCount) { 296 if (haveBinCount) {
294 binCount = (int)m_descriptors[n]->binCount; 297 binCount = (int)m_descriptors[n].binCount;
295 } 298 }
296 299
297 m_needAdditionalModels[n] = false; 300 m_needAdditionalModels[n] = false;
298 301
299 // cerr << "FeatureExtractionModelTransformer: output bin count " 302 if (binCount > 0 && m_descriptors[n].hasKnownExtents) {
300 // << binCount << endl; 303 minValue = m_descriptors[n].minValue;
301 304 maxValue = m_descriptors[n].maxValue;
302 if (binCount > 0 && m_descriptors[n]->hasKnownExtents) {
303 minValue = m_descriptors[n]->minValue;
304 maxValue = m_descriptors[n]->maxValue;
305 haveExtents = true; 305 haveExtents = true;
306 } 306 }
307 307
308 sv_samplerate_t modelRate = input->getSampleRate(); 308 sv_samplerate_t modelRate = input->getSampleRate();
309 sv_samplerate_t outputRate = modelRate; 309 sv_samplerate_t outputRate = modelRate;
310 int modelResolution = 1; 310 int modelResolution = 1;
311 311
312 if (m_descriptors[n]->sampleType != 312 if (m_descriptors[n].sampleType !=
313 Vamp::Plugin::OutputDescriptor::OneSamplePerStep) { 313 Vamp::Plugin::OutputDescriptor::OneSamplePerStep) {
314 314
315 outputRate = m_descriptors[n]->sampleRate; 315 outputRate = m_descriptors[n].sampleRate;
316 316
317 //!!! SV doesn't actually support display of models that have 317 //!!! SV doesn't actually support display of models that have
318 //!!! different underlying rates together -- so we always set 318 //!!! different underlying rates together -- so we always set
319 //!!! the model rate to be the input model's rate, and adjust 319 //!!! the model rate to be the input model's rate, and adjust
320 //!!! the resolution appropriately. We can't properly display 320 //!!! the resolution appropriately. We can't properly display
326 << modelRate << ")" << endl; 326 << modelRate << ")" << endl;
327 outputRate = modelRate; 327 outputRate = modelRate;
328 } 328 }
329 } 329 }
330 330
331 switch (m_descriptors[n]->sampleType) { 331 switch (m_descriptors[n].sampleType) {
332 332
333 case Vamp::Plugin::OutputDescriptor::VariableSampleRate: 333 case Vamp::Plugin::OutputDescriptor::VariableSampleRate:
334 if (outputRate != 0.0) { 334 if (outputRate != 0.0) {
335 modelResolution = int(round(modelRate / outputRate)); 335 modelResolution = int(round(modelRate / outputRate));
336 } 336 }
340 modelResolution = m_transforms[n].getStepSize(); 340 modelResolution = m_transforms[n].getStepSize();
341 break; 341 break;
342 342
343 case Vamp::Plugin::OutputDescriptor::FixedSampleRate: 343 case Vamp::Plugin::OutputDescriptor::FixedSampleRate:
344 if (outputRate <= 0.0) { 344 if (outputRate <= 0.0) {
345 SVDEBUG << "WARNING: Fixed sample-rate plugin reports invalid sample rate " << m_descriptors[n]->sampleRate << "; defaulting to input rate of " << input->getSampleRate() << endl; 345 SVDEBUG << "WARNING: Fixed sample-rate plugin reports invalid sample rate " << m_descriptors[n].sampleRate << "; defaulting to input rate of " << input->getSampleRate() << endl;
346 modelResolution = 1; 346 modelResolution = 1;
347 } else { 347 } else {
348 modelResolution = int(round(modelRate / outputRate)); 348 modelResolution = int(round(modelRate / outputRate));
349 // cerr << "modelRate = " << modelRate << ", descriptor rate = " << outputRate << ", modelResolution = " << modelResolution << endl; 349 // cerr << "modelRate = " << modelRate << ", descriptor rate = " << outputRate << ", modelResolution = " << modelResolution << endl;
350 } 350 }
351 break; 351 break;
352 } 352 }
353 353
354 bool preDurationPlugin = (m_plugin->getVampApiVersion() < 2); 354 bool preDurationPlugin = (m_plugin->getVampApiVersion() < 2);
355 355
356 Model *out = nullptr; 356 std::shared_ptr<Model> out;
357 357
358 if (binCount == 0 && 358 if (binCount == 0 &&
359 (preDurationPlugin || !m_descriptors[n]->hasDuration)) { 359 (preDurationPlugin || !m_descriptors[n].hasDuration)) {
360 360
361 // Anything with no value and no duration is an instant 361 // Anything with no value and no duration is an instant
362 362
363 out = new SparseOneDimensionalModel(modelRate, modelResolution, false); 363 out = std::make_shared<SparseOneDimensionalModel>
364 (modelRate, modelResolution, false);
365
364 QString outputEventTypeURI = description.getOutputEventTypeURI(outputId); 366 QString outputEventTypeURI = description.getOutputEventTypeURI(outputId);
365 out->setRDFTypeURI(outputEventTypeURI); 367 out->setRDFTypeURI(outputEventTypeURI);
366 368
367 } else if ((preDurationPlugin && binCount > 1 && 369 } else if ((preDurationPlugin && binCount > 1 &&
368 (m_descriptors[n]->sampleType == 370 (m_descriptors[n].sampleType ==
369 Vamp::Plugin::OutputDescriptor::VariableSampleRate)) || 371 Vamp::Plugin::OutputDescriptor::VariableSampleRate)) ||
370 (!preDurationPlugin && m_descriptors[n]->hasDuration)) { 372 (!preDurationPlugin && m_descriptors[n].hasDuration)) {
371 373
372 // For plugins using the old v1 API without explicit duration, 374 // For plugins using the old v1 API without explicit duration,
373 // we treat anything that has multiple bins (i.e. that has the 375 // we treat anything that has multiple bins (i.e. that has the
374 // potential to have value and duration) and a variable sample 376 // potential to have value and duration) and a variable sample
375 // rate as a note model, taking its values as pitch, duration 377 // rate as a note model, taking its values as pitch, duration
396 // duration) 398 // duration)
397 if (binCount > 1) isNoteModel = true; 399 if (binCount > 1) isNoteModel = true;
398 400
399 // Regions do not have units of Hz or MIDI things (a sweeping 401 // Regions do not have units of Hz or MIDI things (a sweeping
400 // assumption!) 402 // assumption!)
401 if (m_descriptors[n]->unit == "Hz" || 403 if (m_descriptors[n].unit == "Hz" ||
402 m_descriptors[n]->unit.find("MIDI") != std::string::npos || 404 m_descriptors[n].unit.find("MIDI") != std::string::npos ||
403 m_descriptors[n]->unit.find("midi") != std::string::npos) { 405 m_descriptors[n].unit.find("midi") != std::string::npos) {
404 isNoteModel = true; 406 isNoteModel = true;
405 } 407 }
406 408
407 // If we had a "sparse 3D model", we would have the additional 409 // If we had a "sparse 3D model", we would have the additional
408 // problem of determining whether to use that here (if bin 410 // problem of determining whether to use that here (if bin
418 (modelRate, modelResolution, minValue, maxValue, false); 420 (modelRate, modelResolution, minValue, maxValue, false);
419 } else { 421 } else {
420 model = new NoteModel 422 model = new NoteModel
421 (modelRate, modelResolution, false); 423 (modelRate, modelResolution, false);
422 } 424 }
423 model->setScaleUnits(m_descriptors[n]->unit.c_str()); 425 model->setScaleUnits(m_descriptors[n].unit.c_str());
424 out = model; 426 out.reset(model);
425 427
426 } else { 428 } else {
427 429
428 RegionModel *model; 430 RegionModel *model;
429 if (haveExtents) { 431 if (haveExtents) {
431 (modelRate, modelResolution, minValue, maxValue, false); 433 (modelRate, modelResolution, minValue, maxValue, false);
432 } else { 434 } else {
433 model = new RegionModel 435 model = new RegionModel
434 (modelRate, modelResolution, false); 436 (modelRate, modelResolution, false);
435 } 437 }
436 model->setScaleUnits(m_descriptors[n]->unit.c_str()); 438 model->setScaleUnits(m_descriptors[n].unit.c_str());
437 out = model; 439 out.reset(model);
438 } 440 }
439 441
440 QString outputEventTypeURI = description.getOutputEventTypeURI(outputId); 442 QString outputEventTypeURI = description.getOutputEventTypeURI(outputId);
441 out->setRDFTypeURI(outputEventTypeURI); 443 out->setRDFTypeURI(outputEventTypeURI);
442 444
443 } else if (binCount == 1 || 445 } else if (binCount == 1 ||
444 (m_descriptors[n]->sampleType == 446 (m_descriptors[n].sampleType ==
445 Vamp::Plugin::OutputDescriptor::VariableSampleRate)) { 447 Vamp::Plugin::OutputDescriptor::VariableSampleRate)) {
446 448
447 // Anything that is not a 1D, note, or interval model and that 449 // Anything that is not a 1D, note, or interval model and that
448 // has only one value per result must be a sparse time value 450 // has only one value per result must be a sparse time value
449 // model. 451 // model.
480 } 482 }
481 483
482 Vamp::Plugin::OutputList outputs = m_plugin->getOutputDescriptors(); 484 Vamp::Plugin::OutputList outputs = m_plugin->getOutputDescriptors();
483 model->setScaleUnits(outputs[m_outputNos[n]].unit.c_str()); 485 model->setScaleUnits(outputs[m_outputNos[n]].unit.c_str());
484 486
485 out = model; 487 out.reset(model);
486 488
487 QString outputEventTypeURI = description.getOutputEventTypeURI(outputId); 489 QString outputEventTypeURI = description.getOutputEventTypeURI(outputId);
488 out->setRDFTypeURI(outputEventTypeURI); 490 out->setRDFTypeURI(outputEventTypeURI);
489 491
490 } else { 492 } else {
497 new EditableDenseThreeDimensionalModel 499 new EditableDenseThreeDimensionalModel
498 (modelRate, modelResolution, binCount, 500 (modelRate, modelResolution, binCount,
499 EditableDenseThreeDimensionalModel::BasicMultirateCompression, 501 EditableDenseThreeDimensionalModel::BasicMultirateCompression,
500 false); 502 false);
501 503
502 if (!m_descriptors[n]->binNames.empty()) { 504 if (!m_descriptors[n].binNames.empty()) {
503 std::vector<QString> names; 505 std::vector<QString> names;
504 for (int i = 0; i < (int)m_descriptors[n]->binNames.size(); ++i) { 506 for (int i = 0; i < (int)m_descriptors[n].binNames.size(); ++i) {
505 names.push_back(m_descriptors[n]->binNames[i].c_str()); 507 names.push_back(m_descriptors[n].binNames[i].c_str());
506 } 508 }
507 model->setBinNames(names); 509 model->setBinNames(names);
508 } 510 }
509 511
510 out = model; 512 out.reset(model);
511 513
512 QString outputSignalTypeURI = description.getOutputSignalTypeURI(outputId); 514 QString outputSignalTypeURI = description.getOutputSignalTypeURI(outputId);
513 out->setRDFTypeURI(outputSignalTypeURI); 515 out->setRDFTypeURI(outputSignalTypeURI);
514 } 516 }
515 517
516 if (out) { 518 if (out) {
517 out->setSourceModel(input); 519 out->setSourceModel(getInputModel());
518 m_outputs.push_back(out); 520 m_outputs.push_back(ModelById::add(out));
519 } 521 }
520 } 522 }
521 523
522 void 524 void
523 FeatureExtractionModelTransformer::awaitOutputModels() 525 FeatureExtractionModelTransformer::awaitOutputModels()
538 540
539 FeatureExtractionModelTransformer::Models 541 FeatureExtractionModelTransformer::Models
540 FeatureExtractionModelTransformer::getAdditionalOutputModels() 542 FeatureExtractionModelTransformer::getAdditionalOutputModels()
541 { 543 {
542 Models mm; 544 Models mm;
543 for (AdditionalModelMap::iterator i = m_additionalModels.begin(); 545 for (auto mp : m_additionalModels) {
544 i != m_additionalModels.end(); ++i) { 546 for (auto m: mp.second) {
545 for (std::map<int, SparseTimeValueModel *>::iterator j = 547 mm.push_back(m.second);
546 i->second.begin();
547 j != i->second.end(); ++j) {
548 SparseTimeValueModel *m = j->second;
549 if (m) mm.push_back(m);
550 } 548 }
551 } 549 }
552 return mm; 550 return mm;
553 } 551 }
554 552
555 bool 553 bool
556 FeatureExtractionModelTransformer::willHaveAdditionalOutputModels() 554 FeatureExtractionModelTransformer::willHaveAdditionalOutputModels()
557 { 555 {
558 for (std::map<int, bool>::const_iterator i = 556 for (auto p : m_needAdditionalModels) {
559 m_needAdditionalModels.begin(); 557 if (p.second) return true;
560 i != m_needAdditionalModels.end(); ++i) {
561 if (i->second) return true;
562 } 558 }
563 return false; 559 return false;
564 } 560 }
565 561
566 SparseTimeValueModel * 562 ModelId
567 FeatureExtractionModelTransformer::getAdditionalModel(int n, int binNo) 563 FeatureExtractionModelTransformer::getAdditionalModel(int n, int binNo)
568 { 564 {
569 // std::cerr << "getAdditionalModel(" << n << ", " << binNo << ")" << std::endl;
570
571 if (binNo == 0) { 565 if (binNo == 0) {
572 std::cerr << "Internal error: binNo == 0 in getAdditionalModel (should be using primary model)" << std::endl; 566 SVCERR << "Internal error: binNo == 0 in getAdditionalModel (should be using primary model, not calling getAdditionalModel)" << endl;
573 return nullptr; 567 return {};
574 } 568 }
575 569
576 if (!m_needAdditionalModels[n]) return nullptr; 570 if (!in_range_for(m_outputs, n)) {
577 if (!isOutput<SparseTimeValueModel>(n)) return nullptr; 571 SVCERR << "getAdditionalModel: Output " << n << " out of range" << endl;
578 if (m_additionalModels[n][binNo]) return m_additionalModels[n][binNo]; 572 return {};
579 573 }
580 std::cerr << "getAdditionalModel(" << n << ", " << binNo << "): creating" << std::endl; 574
581 575 if (!in_range_for(m_needAdditionalModels, n) ||
582 SparseTimeValueModel *baseModel = getConformingOutput<SparseTimeValueModel>(n); 576 !m_needAdditionalModels[n]) {
583 if (!baseModel) return nullptr; 577 return {};
584 578 }
585 std::cerr << "getAdditionalModel(" << n << ", " << binNo << "): (from " << baseModel << ")" << std::endl; 579
580 if (!m_additionalModels[n][binNo].isNone()) {
581 return m_additionalModels[n][binNo];
582 }
583
584 SVDEBUG << "getAdditionalModel(" << n << ", " << binNo
585 << "): creating" << endl;
586
587 auto baseModel = ModelById::getAs<SparseTimeValueModel>(m_outputs[n]);
588 if (!baseModel) {
589 SVCERR << "getAdditionalModel: Output model not conformable, or has vanished" << endl;
590 return {};
591 }
592
593 SVDEBUG << "getAdditionalModel(" << n << ", " << binNo
594 << "): (from " << baseModel << ")" << endl;
586 595
587 SparseTimeValueModel *additional = 596 SparseTimeValueModel *additional =
588 new SparseTimeValueModel(baseModel->getSampleRate(), 597 new SparseTimeValueModel(baseModel->getSampleRate(),
589 baseModel->getResolution(), 598 baseModel->getResolution(),
590 baseModel->getValueMinimum(), 599 baseModel->getValueMinimum(),
592 false); 601 false);
593 602
594 additional->setScaleUnits(baseModel->getScaleUnits()); 603 additional->setScaleUnits(baseModel->getScaleUnits());
595 additional->setRDFTypeURI(baseModel->getRDFTypeURI()); 604 additional->setRDFTypeURI(baseModel->getRDFTypeURI());
596 605
597 m_additionalModels[n][binNo] = additional; 606 ModelId additionalId = ModelById::add
598 return additional; 607 (std::shared_ptr<SparseTimeValueModel>(additional));
599 } 608 m_additionalModels[n][binNo] = additionalId;
600 609 return additionalId;
601 DenseTimeValueModel *
602 FeatureExtractionModelTransformer::getConformingInput()
603 {
604 // SVDEBUG << "FeatureExtractionModelTransformer::getConformingInput: input model is " << getInputModel() << endl;
605
606 DenseTimeValueModel *dtvm =
607 dynamic_cast<DenseTimeValueModel *>(getInputModel());
608 if (!dtvm) {
609 SVDEBUG << "FeatureExtractionModelTransformer::getConformingInput: WARNING: Input model is not conformable to DenseTimeValueModel" << endl;
610 }
611 return dtvm;
612 } 610 }
613 611
614 void 612 void
615 FeatureExtractionModelTransformer::run() 613 FeatureExtractionModelTransformer::run()
616 { 614 {
622 } catch (const std::exception &e) { 620 } catch (const std::exception &e) {
623 abandon(); 621 abandon();
624 m_message = e.what(); 622 m_message = e.what();
625 return; 623 return;
626 } 624 }
627
628 DenseTimeValueModel *input = getConformingInput();
629 if (!input) {
630 abandon();
631 return;
632 }
633 625
634 if (m_outputs.empty()) { 626 if (m_outputs.empty()) {
635 abandon(); 627 abandon();
636 return; 628 return;
637 } 629 }
638 630
639 Transform primaryTransform = m_transforms[0]; 631 Transform primaryTransform = m_transforms[0];
640 632
641 while (!input->isReady() && !m_abandoned) { 633 bool ready = false;
642 SVDEBUG << "FeatureExtractionModelTransformer::run: Waiting for input model to be ready..." << endl; 634 while (!ready && !m_abandoned) {
643 usleep(500000); 635 { // scope so as to release input shared_ptr before sleeping
644 } 636 auto input = ModelById::getAs<DenseTimeValueModel>(getInputModel());
645 SVDEBUG << "FeatureExtractionModelTransformer::run: Waited, ready = " 637 if (!input) {
646 << input->isReady() << ", m_abandoned = " << m_abandoned << endl; 638 abandon();
639 return;
640 }
641 ready = input->isReady();
642 }
643 if (!ready) {
644 SVDEBUG << "FeatureExtractionModelTransformer::run: Waiting for input model to be ready..." << endl;
645 usleep(500000);
646 }
647 }
647 if (m_abandoned) return; 648 if (m_abandoned) return;
648 649
649 sv_samplerate_t sampleRate = input->getSampleRate(); 650 ModelId inputId = getInputModel();
650 651
651 int channelCount = input->getChannelCount(); 652 sv_samplerate_t sampleRate;
652 if ((int)m_plugin->getMaxChannelCount() < channelCount) { 653 int channelCount;
653 channelCount = 1; 654 sv_frame_t startFrame;
655 sv_frame_t endFrame;
656
657 { // scope so as not to have this borrowed pointer retained around
658 // the edges of the process loop
659 auto input = ModelById::getAs<DenseTimeValueModel>(inputId);
660 if (!input) {
661 abandon();
662 return;
663 }
664
665 sampleRate = input->getSampleRate();
666
667 channelCount = input->getChannelCount();
668 if ((int)m_plugin->getMaxChannelCount() < channelCount) {
669 channelCount = 1;
670 }
671
672 startFrame = input->getStartFrame();
673 endFrame = input->getEndFrame();
654 } 674 }
655 675
656 float **buffers = new float*[channelCount]; 676 float **buffers = new float*[channelCount];
657 for (int ch = 0; ch < channelCount; ++ch) { 677 for (int ch = 0; ch < channelCount; ++ch) {
658 buffers[ch] = new float[primaryTransform.getBlockSize() + 2]; 678 buffers[ch] = new float[primaryTransform.getBlockSize() + 2];
667 std::vector<FFTModel *> fftModels; 687 std::vector<FFTModel *> fftModels;
668 688
669 if (frequencyDomain) { 689 if (frequencyDomain) {
670 for (int ch = 0; ch < channelCount; ++ch) { 690 for (int ch = 0; ch < channelCount; ++ch) {
671 FFTModel *model = new FFTModel 691 FFTModel *model = new FFTModel
672 (getConformingInput(), 692 (inputId,
673 channelCount == 1 ? m_input.getChannel() : ch, 693 channelCount == 1 ? m_input.getChannel() : ch,
674 primaryTransform.getWindowType(), 694 primaryTransform.getWindowType(),
675 blockSize, 695 blockSize,
676 stepSize, 696 stepSize,
677 blockSize); 697 blockSize);
678 if (!model->isOK() || model->getError() != "") { 698 if (!model->isOK() || model->getError() != "") {
679 QString err = model->getError(); 699 QString err = model->getError();
680 delete model; 700 delete model;
681 for (int j = 0; j < (int)m_outputNos.size(); ++j) { 701 for (int j = 0; in_range_for(m_outputNos, j); ++j) {
682 setCompletion(j, 100); 702 setCompletion(j, 100);
683 } 703 }
684 //!!! need a better way to handle this -- previously we were using a QMessageBox but that isn't an appropriate thing to do here either 704 //!!! need a better way to handle this -- previously we were using a QMessageBox but that isn't an appropriate thing to do here either
685 throw AllocationFailed("Failed to create the FFT model for this feature extraction model transformer: error is: " + err); 705 throw AllocationFailed("Failed to create the FFT model for this feature extraction model transformer: error is: " + err);
686 } 706 }
687 fftModels.push_back(model); 707 fftModels.push_back(model);
688 cerr << "created model for channel " << ch << endl; 708 }
689 } 709 }
690 }
691
692 sv_frame_t startFrame = m_input.getModel()->getStartFrame();
693 sv_frame_t endFrame = m_input.getModel()->getEndFrame();
694 710
695 RealTime contextStartRT = primaryTransform.getStartTime(); 711 RealTime contextStartRT = primaryTransform.getStartTime();
696 RealTime contextDurationRT = primaryTransform.getDuration(); 712 RealTime contextDurationRT = primaryTransform.getDuration();
697 713
698 sv_frame_t contextStart = 714 sv_frame_t contextStart =
714 730
715 sv_frame_t blockFrame = contextStart; 731 sv_frame_t blockFrame = contextStart;
716 732
717 long prevCompletion = 0; 733 long prevCompletion = 0;
718 734
719 for (int j = 0; j < (int)m_outputNos.size(); ++j) { 735 for (int j = 0; in_range_for(m_outputNos, j); ++j) {
720 setCompletion(j, 0); 736 setCompletion(j, 0);
721 } 737 }
722 738
723 float *reals = nullptr; 739 float *reals = nullptr;
724 float *imaginaries = nullptr; 740 float *imaginaries = nullptr;
732 try { 748 try {
733 while (!m_abandoned) { 749 while (!m_abandoned) {
734 750
735 if (frequencyDomain) { 751 if (frequencyDomain) {
736 if (blockFrame - int(blockSize)/2 > 752 if (blockFrame - int(blockSize)/2 >
737 contextStart + contextDuration) break; 753 contextStart + contextDuration) {
754 break;
755 }
738 } else { 756 } else {
739 if (blockFrame >= 757 if (blockFrame >=
740 contextStart + contextDuration) break; 758 contextStart + contextDuration) {
759 break;
760 }
741 } 761 }
742 762
743 #ifdef DEBUG_FEATURE_EXTRACTION_TRANSFORMER_RUN 763 #ifdef DEBUG_FEATURE_EXTRACTION_TRANSFORMER_RUN
744 SVDEBUG << "FeatureExtractionModelTransformer::run: blockFrame " 764 SVDEBUG << "FeatureExtractionModelTransformer::run: blockFrame "
745 << blockFrame << ", endFrame " << endFrame << ", blockSize " 765 << blockFrame << ", endFrame " << endFrame << ", blockSize "
748 768
749 int completion = int 769 int completion = int
750 ((((blockFrame - contextStart) / stepSize) * 99) / 770 ((((blockFrame - contextStart) / stepSize) * 99) /
751 (contextDuration / stepSize + 1)); 771 (contextDuration / stepSize + 1));
752 772
753 // channelCount is either m_input.getModel()->channelCount or 1 773 bool haveAllModels = true;
774 if (!ModelById::get(inputId)) {
775 #ifdef DEBUG_FEATURE_EXTRACTION_TRANSFORMER_RUN
776 SVDEBUG << "FeatureExtractionModelTransformer::run: Input model " << inputId << " no longer exists" << endl;
777 #endif
778 haveAllModels = false;
779 } else {
780 #ifdef DEBUG_FEATURE_EXTRACTION_TRANSFORMER_RUN
781 SVDEBUG << "Input model " << inputId << " still exists" << endl;
782 #endif
783 }
784 for (auto mid: m_outputs) {
785 if (!ModelById::get(mid)) {
786 #ifdef DEBUG_FEATURE_EXTRACTION_TRANSFORMER_RUN
787 SVDEBUG << "FeatureExtractionModelTransformer::run: Output model " << mid << " no longer exists" << endl;
788 #endif
789 haveAllModels = false;
790 } else {
791 #ifdef DEBUG_FEATURE_EXTRACTION_TRANSFORMER_RUN
792 SVDEBUG << "Output model " << mid << " still exists" << endl;
793 #endif
794 }
795 }
796 if (!haveAllModels) {
797 abandon();
798 break;
799 }
800
801 #ifdef DEBUG_FEATURE_EXTRACTION_TRANSFORMER_RUN
802 SVDEBUG << "FeatureExtractionModelTransformer::run: All models still exist" << endl;
803 #endif
804
805 // channelCount is either input->channelCount or 1
754 806
755 if (frequencyDomain) { 807 if (frequencyDomain) {
756 for (int ch = 0; ch < channelCount; ++ch) { 808 for (int ch = 0; ch < channelCount; ++ch) {
757 int column = int((blockFrame - startFrame) / stepSize); 809 int column = int((blockFrame - startFrame) / stepSize);
758 if (fftModels[ch]->getValuesAt(column, reals, imaginaries)) { 810 if (fftModels[ch]->getValuesAt(column, reals, imaginaries)) {
779 getFrames(channelCount, blockFrame, blockSize, buffers); 831 getFrames(channelCount, blockFrame, blockSize, buffers);
780 } 832 }
781 833
782 if (m_abandoned) break; 834 if (m_abandoned) break;
783 835
784 Vamp::Plugin::FeatureSet features = m_plugin->process 836 auto features = m_plugin->process
785 (buffers, 837 (buffers,
786 RealTime::frame2RealTime(blockFrame, sampleRate) 838 RealTime::frame2RealTime(blockFrame, sampleRate)
787 .toVampRealTime()); 839 .toVampRealTime());
788 840
789 if (m_abandoned) break; 841 if (m_abandoned) break;
790 842
791 for (int j = 0; j < (int)m_outputNos.size(); ++j) { 843 for (int j = 0; in_range_for(m_outputNos, j); ++j) {
792 for (int fi = 0; fi < (int)features[m_outputNos[j]].size(); ++fi) { 844 for (int fi = 0; in_range_for(features[m_outputNos[j]], fi); ++fi) {
793 Vamp::Plugin::Feature feature = features[m_outputNos[j]][fi]; 845 auto feature = features[m_outputNos[j]][fi];
794 addFeature(j, blockFrame, feature); 846 addFeature(j, blockFrame, feature);
795 } 847 }
796 } 848 }
797 849
798 if (blockFrame == contextStart || completion > prevCompletion) { 850 if (blockFrame == contextStart || completion > prevCompletion) {
799 for (int j = 0; j < (int)m_outputNos.size(); ++j) { 851 for (int j = 0; in_range_for(m_outputNos, j); ++j) {
800 setCompletion(j, completion); 852 setCompletion(j, completion);
801 } 853 }
802 prevCompletion = completion; 854 prevCompletion = completion;
803 } 855 }
804 856
805 blockFrame += stepSize; 857 blockFrame += stepSize;
806 858
807 } 859 }
808 860
809 if (!m_abandoned) { 861 if (!m_abandoned) {
810 Vamp::Plugin::FeatureSet features = m_plugin->getRemainingFeatures(); 862 auto features = m_plugin->getRemainingFeatures();
811 863
812 for (int j = 0; j < (int)m_outputNos.size(); ++j) { 864 for (int j = 0; in_range_for(m_outputNos, j); ++j) {
813 for (int fi = 0; fi < (int)features[m_outputNos[j]].size(); ++fi) { 865 for (int fi = 0; in_range_for(features[m_outputNos[j]], fi); ++fi) {
814 Vamp::Plugin::Feature feature = features[m_outputNos[j]][fi]; 866 auto feature = features[m_outputNos[j]][fi];
815 addFeature(j, blockFrame, feature); 867 addFeature(j, blockFrame, feature);
868 if (m_abandoned) {
869 break;
870 }
816 } 871 }
817 } 872 }
818 } 873 }
819 } catch (const std::exception &e) { 874 } catch (const std::exception &e) {
820 SVCERR << "FeatureExtractionModelTransformer::run: Exception caught: " 875 SVCERR << "FeatureExtractionModelTransformer::run: Exception caught: "
861 size -= offset; 916 size -= offset;
862 if (size <= 0) return; 917 if (size <= 0) return;
863 startFrame = 0; 918 startFrame = 0;
864 } 919 }
865 920
866 DenseTimeValueModel *input = getConformingInput(); 921 auto input = ModelById::getAs<DenseTimeValueModel>(getInputModel());
867 if (!input) return; 922 if (!input) {
923 return;
924 }
868 925
869 sv_frame_t got = 0; 926 sv_frame_t got = 0;
870 927
871 if (channelCount == 1) { 928 if (channelCount == 1) {
872 929
905 void 962 void
906 FeatureExtractionModelTransformer::addFeature(int n, 963 FeatureExtractionModelTransformer::addFeature(int n,
907 sv_frame_t blockFrame, 964 sv_frame_t blockFrame,
908 const Vamp::Plugin::Feature &feature) 965 const Vamp::Plugin::Feature &feature)
909 { 966 {
910 sv_samplerate_t inputRate = m_input.getModel()->getSampleRate(); 967 auto input = ModelById::get(getInputModel());
968 if (!input) return;
969
970 sv_samplerate_t inputRate = input->getSampleRate();
911 971
912 // cerr << "FeatureExtractionModelTransformer::addFeature: blockFrame = " 972 // cerr << "FeatureExtractionModelTransformer::addFeature: blockFrame = "
913 // << blockFrame << ", hasTimestamp = " << feature.hasTimestamp 973 // << blockFrame << ", hasTimestamp = " << feature.hasTimestamp
914 // << ", timestamp = " << feature.timestamp << ", hasDuration = " 974 // << ", timestamp = " << feature.timestamp << ", hasDuration = "
915 // << feature.hasDuration << ", duration = " << feature.duration 975 // << feature.hasDuration << ", duration = " << feature.duration
916 // << endl; 976 // << endl;
917 977
918 sv_frame_t frame = blockFrame; 978 sv_frame_t frame = blockFrame;
919 979
920 if (m_descriptors[n]->sampleType == 980 if (m_descriptors[n].sampleType ==
921 Vamp::Plugin::OutputDescriptor::VariableSampleRate) { 981 Vamp::Plugin::OutputDescriptor::VariableSampleRate) {
922 982
923 if (!feature.hasTimestamp) { 983 if (!feature.hasTimestamp) {
924 SVDEBUG 984 SVDEBUG
925 << "WARNING: FeatureExtractionModelTransformer::addFeature: " 985 << "WARNING: FeatureExtractionModelTransformer::addFeature: "
931 } 991 }
932 992
933 // cerr << "variable sample rate: timestamp = " << feature.timestamp 993 // cerr << "variable sample rate: timestamp = " << feature.timestamp
934 // << " at input rate " << inputRate << " -> " << frame << endl; 994 // << " at input rate " << inputRate << " -> " << frame << endl;
935 995
936 } else if (m_descriptors[n]->sampleType == 996 } else if (m_descriptors[n].sampleType ==
937 Vamp::Plugin::OutputDescriptor::FixedSampleRate) { 997 Vamp::Plugin::OutputDescriptor::FixedSampleRate) {
938 998
939 sv_samplerate_t rate = m_descriptors[n]->sampleRate; 999 sv_samplerate_t rate = m_descriptors[n].sampleRate;
940 if (rate <= 0.0) { 1000 if (rate <= 0.0) {
941 rate = inputRate; 1001 rate = inputRate;
942 } 1002 }
943 1003
944 if (!feature.hasTimestamp) { 1004 if (!feature.hasTimestamp) {
947 RealTime ts(feature.timestamp.sec, feature.timestamp.nsec); 1007 RealTime ts(feature.timestamp.sec, feature.timestamp.nsec);
948 m_fixedRateFeatureNos[n] = (int)lrint(ts.toDouble() * rate); 1008 m_fixedRateFeatureNos[n] = (int)lrint(ts.toDouble() * rate);
949 } 1009 }
950 1010
951 // cerr << "m_fixedRateFeatureNo = " << m_fixedRateFeatureNos[n] 1011 // cerr << "m_fixedRateFeatureNo = " << m_fixedRateFeatureNos[n]
952 // << ", m_descriptor->sampleRate = " << m_descriptors[n]->sampleRate 1012 // << ", m_descriptor->sampleRate = " << m_descriptors[n].sampleRate
953 // << ", inputRate = " << inputRate 1013 // << ", inputRate = " << inputRate
954 // << " giving frame = "; 1014 // << " giving frame = ";
955 frame = lrint((double(m_fixedRateFeatureNos[n]) / rate) * inputRate); 1015 frame = lrint((double(m_fixedRateFeatureNos[n]) / rate) * inputRate);
956 // cerr << frame << endl; 1016 // cerr << frame << endl;
957 } 1017 }
969 // Rather than repeat the complicated tests from the constructor 1029 // Rather than repeat the complicated tests from the constructor
970 // to determine what sort of model we must be adding the features 1030 // to determine what sort of model we must be adding the features
971 // to, we instead test what sort of model the constructor decided 1031 // to, we instead test what sort of model the constructor decided
972 // to create. 1032 // to create.
973 1033
974 if (isOutput<SparseOneDimensionalModel>(n)) { 1034 ModelId outputId = m_outputs[n];
975 1035
976 SparseOneDimensionalModel *model = 1036 if (isOutputType<SparseOneDimensionalModel>(n)) {
977 getConformingOutput<SparseOneDimensionalModel>(n); 1037
1038 auto model = ModelById::getAs<SparseOneDimensionalModel>(outputId);
978 if (!model) return; 1039 if (!model) return;
979
980 model->add(Event(frame, feature.label.c_str())); 1040 model->add(Event(frame, feature.label.c_str()));
981 1041
982 } else if (isOutput<SparseTimeValueModel>(n)) { 1042 } else if (isOutputType<SparseTimeValueModel>(n)) {
983 1043
984 SparseTimeValueModel *model = 1044 auto model = ModelById::getAs<SparseTimeValueModel>(outputId);
985 getConformingOutput<SparseTimeValueModel>(n);
986 if (!model) return; 1045 if (!model) return;
987 1046
988 for (int i = 0; i < (int)feature.values.size(); ++i) { 1047 for (int i = 0; in_range_for(feature.values, i); ++i) {
989 1048
990 float value = feature.values[i]; 1049 float value = feature.values[i];
991 1050
992 QString label = feature.label.c_str(); 1051 QString label = feature.label.c_str();
993 if (feature.values.size() > 1) { 1052 if (feature.values.size() > 1) {
994 label = QString("[%1] %2").arg(i+1).arg(label); 1053 label = QString("[%1] %2").arg(i+1).arg(label);
995 } 1054 }
996 1055
997 SparseTimeValueModel *targetModel = model; 1056 auto targetModel = model;
998 1057
999 if (m_needAdditionalModels[n] && i > 0) { 1058 if (m_needAdditionalModels[n] && i > 0) {
1000 targetModel = getAdditionalModel(n, i); 1059 targetModel = ModelById::getAs<SparseTimeValueModel>
1060 (getAdditionalModel(n, i));
1001 if (!targetModel) targetModel = model; 1061 if (!targetModel) targetModel = model;
1002 // std::cerr << "adding point to model " << targetModel
1003 // << " for output " << n << " bin " << i << std::endl;
1004 } 1062 }
1005 1063
1006 targetModel->add(Event(frame, value, label)); 1064 targetModel->add(Event(frame, value, label));
1007 } 1065 }
1008 1066
1009 } else if (isOutput<NoteModel>(n) || isOutput<RegionModel>(n)) { 1067 } else if (isOutputType<NoteModel>(n) || isOutputType<RegionModel>(n)) {
1010 1068
1011 int index = 0; 1069 int index = 0;
1012 1070
1013 float value = 0.0; 1071 float value = 0.0;
1014 if ((int)feature.values.size() > index) { 1072 if ((int)feature.values.size() > index) {
1015 value = feature.values[index++]; 1073 value = feature.values[index++];
1022 if (in_range_for(feature.values, index)) { 1080 if (in_range_for(feature.values, index)) {
1023 duration = lrintf(feature.values[index++]); 1081 duration = lrintf(feature.values[index++]);
1024 } 1082 }
1025 } 1083 }
1026 1084
1027 if (isOutput<NoteModel>(n)) { 1085 auto noteModel = ModelById::getAs<NoteModel>(outputId);
1086 if (noteModel) {
1028 1087
1029 float velocity = 100; 1088 float velocity = 100;
1030 if ((int)feature.values.size() > index) { 1089 if ((int)feature.values.size() > index) {
1031 velocity = feature.values[index++]; 1090 velocity = feature.values[index++];
1032 } 1091 }
1033 if (velocity < 0) velocity = 127; 1092 if (velocity < 0) velocity = 127;
1034 if (velocity > 127) velocity = 127; 1093 if (velocity > 127) velocity = 127;
1035 1094
1036 NoteModel *model = getConformingOutput<NoteModel>(n); 1095 noteModel->add(Event(frame, value, // value is pitch
1037 if (!model) return; 1096 duration,
1038 model->add(Event(frame, value, // value is pitch 1097 velocity / 127.f,
1039 duration, 1098 feature.label.c_str()));
1040 velocity / 127.f, 1099 }
1041 feature.label.c_str())); 1100
1042 } else { 1101 auto regionModel = ModelById::getAs<RegionModel>(outputId);
1043 1102 if (regionModel) {
1044 RegionModel *model = getConformingOutput<RegionModel>(n); 1103
1045 if (!model) return;
1046
1047 if (feature.hasDuration && !feature.values.empty()) { 1104 if (feature.hasDuration && !feature.values.empty()) {
1048 1105
1049 for (int i = 0; i < (int)feature.values.size(); ++i) { 1106 for (int i = 0; in_range_for(feature.values, i); ++i) {
1050 1107
1051 float value = feature.values[i]; 1108 float value = feature.values[i];
1052 1109
1053 QString label = feature.label.c_str(); 1110 QString label = feature.label.c_str();
1054 if (feature.values.size() > 1) { 1111 if (feature.values.size() > 1) {
1055 label = QString("[%1] %2").arg(i+1).arg(label); 1112 label = QString("[%1] %2").arg(i+1).arg(label);
1056 } 1113 }
1057 1114
1058 model->add(Event(frame, 1115 regionModel->add(Event(frame,
1059 value, 1116 value,
1060 duration, 1117 duration,
1061 label)); 1118 label));
1062 } 1119 }
1063 } else { 1120 } else {
1064 1121
1065 model->add(Event(frame, 1122 regionModel->add(Event(frame,
1066 value, 1123 value,
1067 duration, 1124 duration,
1068 feature.label.c_str())); 1125 feature.label.c_str()));
1069 } 1126 }
1070 } 1127 }
1071 1128
1072 } else if (isOutput<EditableDenseThreeDimensionalModel>(n)) { 1129 } else if (isOutputType<EditableDenseThreeDimensionalModel>(n)) {
1130
1131 auto model = ModelById::getAs
1132 <EditableDenseThreeDimensionalModel>(outputId);
1133 if (!model) return;
1073 1134
1074 DenseThreeDimensionalModel::Column values = feature.values; 1135 DenseThreeDimensionalModel::Column values = feature.values;
1075 1136
1076 EditableDenseThreeDimensionalModel *model =
1077 getConformingOutput<EditableDenseThreeDimensionalModel>(n);
1078 if (!model) return;
1079
1080 // cerr << "(note: model resolution = " << model->getResolution() << ")"
1081 // << endl;
1082
1083 if (!feature.hasTimestamp && m_fixedRateFeatureNos[n] >= 0) { 1137 if (!feature.hasTimestamp && m_fixedRateFeatureNos[n] >= 0) {
1084 model->setColumn(m_fixedRateFeatureNos[n], values); 1138 model->setColumn(m_fixedRateFeatureNos[n], values);
1085 } else { 1139 } else {
1086 model->setColumn(int(frame / model->getResolution()), values); 1140 model->setColumn(int(frame / model->getResolution()), values);
1087 } 1141 }
1088
1089 } else { 1142 } else {
1090 SVDEBUG << "FeatureExtractionModelTransformer::addFeature: Unknown output model type!" << endl; 1143
1144 SVDEBUG << "FeatureExtractionModelTransformer::addFeature: Unknown output model type - possibly a deleted model" << endl;
1145 abandon();
1091 } 1146 }
1092 } 1147 }
1093 1148
1094 void 1149 void
1095 FeatureExtractionModelTransformer::setCompletion(int n, int completion) 1150 FeatureExtractionModelTransformer::setCompletion(int n, int completion)
1097 #ifdef DEBUG_FEATURE_EXTRACTION_TRANSFORMER_RUN 1152 #ifdef DEBUG_FEATURE_EXTRACTION_TRANSFORMER_RUN
1098 SVDEBUG << "FeatureExtractionModelTransformer::setCompletion(" 1153 SVDEBUG << "FeatureExtractionModelTransformer::setCompletion("
1099 << completion << ")" << endl; 1154 << completion << ")" << endl;
1100 #endif 1155 #endif
1101 1156
1102 if (isOutput<SparseOneDimensionalModel>(n)) { 1157 (void)
1103 1158 (setOutputCompletion<SparseOneDimensionalModel>(n, completion) ||
1104 SparseOneDimensionalModel *model = 1159 setOutputCompletion<SparseTimeValueModel>(n, completion) ||
1105 getConformingOutput<SparseOneDimensionalModel>(n); 1160 setOutputCompletion<NoteModel>(n, completion) ||
1106 if (!model) return; 1161 setOutputCompletion<RegionModel>(n, completion) ||
1107 if (model->isAbandoning()) abandon(); 1162 setOutputCompletion<EditableDenseThreeDimensionalModel>(n, completion));
1108 model->setCompletion(completion, true); 1163 }
1109 1164
1110 } else if (isOutput<SparseTimeValueModel>(n)) {
1111
1112 SparseTimeValueModel *model =
1113 getConformingOutput<SparseTimeValueModel>(n);
1114 if (!model) return;
1115 if (model->isAbandoning()) abandon();
1116 model->setCompletion(completion, true);
1117
1118 } else if (isOutput<NoteModel>(n)) {
1119
1120 NoteModel *model = getConformingOutput<NoteModel>(n);
1121 if (!model) return;
1122 if (model->isAbandoning()) abandon();
1123 model->setCompletion(completion, true);
1124
1125 } else if (isOutput<RegionModel>(n)) {
1126
1127 RegionModel *model = getConformingOutput<RegionModel>(n);
1128 if (!model) return;
1129 if (model->isAbandoning()) abandon();
1130 model->setCompletion(completion, true);
1131
1132 } else if (isOutput<EditableDenseThreeDimensionalModel>(n)) {
1133
1134 EditableDenseThreeDimensionalModel *model =
1135 getConformingOutput<EditableDenseThreeDimensionalModel>(n);
1136 if (!model) return;
1137 if (model->isAbandoning()) abandon();
1138 model->setCompletion(completion, true); //!!!m_context.updates);
1139 }
1140 }
1141