Mercurial > hg > svcore
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 |