Mercurial > hg > svcore
comparison transform/FeatureExtractionModelTransformer.cpp @ 849:418cd2064769 tonioni_multi_transform
More on multi-transform stuff
| author | Chris Cannam |
|---|---|
| date | Mon, 02 Dec 2013 11:17:24 +0000 |
| parents | 2d53205f70cd |
| children | dba8a02b0413 |
comparison
equal
deleted
inserted
replaced
| 848:539740f231fa | 849:418cd2064769 |
|---|---|
| 37 | 37 |
| 38 #include <iostream> | 38 #include <iostream> |
| 39 | 39 |
| 40 FeatureExtractionModelTransformer::FeatureExtractionModelTransformer(Input in, | 40 FeatureExtractionModelTransformer::FeatureExtractionModelTransformer(Input in, |
| 41 const Transform &transform, | 41 const Transform &transform, |
| 42 const PreferredOutputModel outputmodel) : | 42 const PreferredOutputModel outputmodel) : |
| 43 ModelTransformer(in, transform), | 43 ModelTransformer(in, transform), |
| 44 m_plugin(0), | 44 m_plugin(0), |
| 45 m_descriptor(0), | |
| 46 m_outputNo(0), | |
| 47 m_fixedRateFeatureNo(-1), // we increment before use | |
| 48 m_preferredOutputModel(outputmodel) | 45 m_preferredOutputModel(outputmodel) |
| 49 { | 46 { |
| 50 // SVDEBUG << "FeatureExtractionModelTransformer::FeatureExtractionModelTransformer: plugin " << pluginId << ", outputName " << m_transform.getOutput() << endl; | 47 // SVDEBUG << "FeatureExtractionModelTransformer::FeatureExtractionModelTransformer: plugin " << pluginId << ", outputName " << m_transform.getOutput() << endl; |
| 51 | 48 |
| 52 QString pluginId = transform.getPluginIdentifier(); | 49 initialise(); |
| 50 } | |
| 51 | |
| 52 FeatureExtractionModelTransformer::FeatureExtractionModelTransformer(Input in, | |
| 53 const Transforms &transforms, | |
| 54 const PreferredOutputModel outputmodel) : | |
| 55 ModelTransformer(in, transforms), | |
| 56 m_plugin(0), | |
| 57 m_preferredOutputModel(outputmodel) | |
| 58 { | |
| 59 // SVDEBUG << "FeatureExtractionModelTransformer::FeatureExtractionModelTransformer: plugin " << pluginId << ", outputName " << m_transform.getOutput() << endl; | |
| 60 | |
| 61 initialise(); | |
| 62 } | |
| 63 | |
| 64 static bool | |
| 65 areTransformsSimilar(const Transform &t1, const Transform &t2) | |
| 66 { | |
| 67 Transform t2o(t2); | |
| 68 t2o.setOutput(t1.getOutput()); | |
| 69 return t1 == t2o; | |
| 70 } | |
| 71 | |
| 72 bool | |
| 73 FeatureExtractionModelTransformer::initialise() | |
| 74 { | |
| 75 // All transforms must use the same plugin, parameters, and | |
| 76 // inputs: they can differ only in choice of plugin output. So we | |
| 77 // initialise based purely on the first transform in the list (but | |
| 78 // first check that they are actually similar as promised) | |
| 79 | |
| 80 for (int j = 1; j < (int)m_transforms.size(); ++j) { | |
| 81 if (!areTransformsSimilar(m_transforms[0], m_transforms[j])) { | |
| 82 m_message = tr("Transforms supplied to a single FeatureExtractionModelTransformer instance must be similar in every respect except plugin output"); | |
| 83 return false; | |
| 84 } | |
| 85 } | |
| 86 | |
| 87 Transform primaryTransform = m_transforms[0]; | |
| 88 | |
| 89 QString pluginId = primaryTransform.getPluginIdentifier(); | |
| 53 | 90 |
| 54 FeatureExtractionPluginFactory *factory = | 91 FeatureExtractionPluginFactory *factory = |
| 55 FeatureExtractionPluginFactory::instanceFor(pluginId); | 92 FeatureExtractionPluginFactory::instanceFor(pluginId); |
| 56 | 93 |
| 57 if (!factory) { | 94 if (!factory) { |
| 58 m_message = tr("No factory available for feature extraction plugin id \"%1\" (unknown plugin type, or internal error?)").arg(pluginId); | 95 m_message = tr("No factory available for feature extraction plugin id \"%1\" (unknown plugin type, or internal error?)").arg(pluginId); |
| 59 return; | 96 return false; |
| 60 } | 97 } |
| 61 | 98 |
| 62 DenseTimeValueModel *input = getConformingInput(); | 99 DenseTimeValueModel *input = getConformingInput(); |
| 63 if (!input) { | 100 if (!input) { |
| 64 m_message = tr("Input model for feature extraction plugin \"%1\" is of wrong type (internal error?)").arg(pluginId); | 101 m_message = tr("Input model for feature extraction plugin \"%1\" is of wrong type (internal error?)").arg(pluginId); |
| 65 return; | 102 return false; |
| 66 } | 103 } |
| 67 | 104 |
| 68 m_plugin = factory->instantiatePlugin(pluginId, input->getSampleRate()); | 105 m_plugin = factory->instantiatePlugin(pluginId, input->getSampleRate()); |
| 69 if (!m_plugin) { | 106 if (!m_plugin) { |
| 70 m_message = tr("Failed to instantiate plugin \"%1\"").arg(pluginId); | 107 m_message = tr("Failed to instantiate plugin \"%1\"").arg(pluginId); |
| 71 return; | 108 return false; |
| 72 } | 109 } |
| 73 | 110 |
| 74 TransformFactory::getInstance()->makeContextConsistentWithPlugin | 111 TransformFactory::getInstance()->makeContextConsistentWithPlugin |
| 75 (m_transform, m_plugin); | 112 (primaryTransform, m_plugin); |
| 76 | 113 |
| 77 TransformFactory::getInstance()->setPluginParameters | 114 TransformFactory::getInstance()->setPluginParameters |
| 78 (m_transform, m_plugin); | 115 (primaryTransform, m_plugin); |
| 79 | 116 |
| 80 size_t channelCount = input->getChannelCount(); | 117 size_t channelCount = input->getChannelCount(); |
| 81 if (m_plugin->getMaxChannelCount() < channelCount) { | 118 if (m_plugin->getMaxChannelCount() < channelCount) { |
| 82 channelCount = 1; | 119 channelCount = 1; |
| 83 } | 120 } |
| 85 m_message = tr("Cannot provide enough channels to feature extraction plugin \"%1\" (plugin min is %2, max %3; input model has %4)") | 122 m_message = tr("Cannot provide enough channels to feature extraction plugin \"%1\" (plugin min is %2, max %3; input model has %4)") |
| 86 .arg(pluginId) | 123 .arg(pluginId) |
| 87 .arg(m_plugin->getMinChannelCount()) | 124 .arg(m_plugin->getMinChannelCount()) |
| 88 .arg(m_plugin->getMaxChannelCount()) | 125 .arg(m_plugin->getMaxChannelCount()) |
| 89 .arg(input->getChannelCount()); | 126 .arg(input->getChannelCount()); |
| 90 return; | 127 return false; |
| 91 } | 128 } |
| 92 | 129 |
| 93 SVDEBUG << "Initialising feature extraction plugin with channels = " | 130 SVDEBUG << "Initialising feature extraction plugin with channels = " |
| 94 << channelCount << ", step = " << m_transform.getStepSize() | 131 << channelCount << ", step = " << primaryTransform.getStepSize() |
| 95 << ", block = " << m_transform.getBlockSize() << endl; | 132 << ", block = " << primaryTransform.getBlockSize() << endl; |
| 96 | 133 |
| 97 if (!m_plugin->initialise(channelCount, | 134 if (!m_plugin->initialise(channelCount, |
| 98 m_transform.getStepSize(), | 135 primaryTransform.getStepSize(), |
| 99 m_transform.getBlockSize())) { | 136 primaryTransform.getBlockSize())) { |
| 100 | 137 |
| 101 size_t pstep = m_transform.getStepSize(); | 138 size_t pstep = primaryTransform.getStepSize(); |
| 102 size_t pblock = m_transform.getBlockSize(); | 139 size_t pblock = primaryTransform.getBlockSize(); |
| 103 | 140 |
| 104 m_transform.setStepSize(0); | 141 primaryTransform.setStepSize(0); |
| 105 m_transform.setBlockSize(0); | 142 primaryTransform.setBlockSize(0); |
| 106 TransformFactory::getInstance()->makeContextConsistentWithPlugin | 143 TransformFactory::getInstance()->makeContextConsistentWithPlugin |
| 107 (m_transform, m_plugin); | 144 (primaryTransform, m_plugin); |
| 108 | 145 |
| 109 if (m_transform.getStepSize() != pstep || | 146 if (primaryTransform.getStepSize() != pstep || |
| 110 m_transform.getBlockSize() != pblock) { | 147 primaryTransform.getBlockSize() != pblock) { |
| 111 | 148 |
| 112 if (!m_plugin->initialise(channelCount, | 149 if (!m_plugin->initialise(channelCount, |
| 113 m_transform.getStepSize(), | 150 primaryTransform.getStepSize(), |
| 114 m_transform.getBlockSize())) { | 151 primaryTransform.getBlockSize())) { |
| 115 | 152 |
| 116 m_message = tr("Failed to initialise feature extraction plugin \"%1\"").arg(pluginId); | 153 m_message = tr("Failed to initialise feature extraction plugin \"%1\"").arg(pluginId); |
| 117 return; | 154 return false; |
| 118 | 155 |
| 119 } else { | 156 } else { |
| 120 | 157 |
| 121 m_message = tr("Feature extraction plugin \"%1\" rejected the given step and block sizes (%2 and %3); using plugin defaults (%4 and %5) instead") | 158 m_message = tr("Feature extraction plugin \"%1\" rejected the given step and block sizes (%2 and %3); using plugin defaults (%4 and %5) instead") |
| 122 .arg(pluginId) | 159 .arg(pluginId) |
| 123 .arg(pstep) | 160 .arg(pstep) |
| 124 .arg(pblock) | 161 .arg(pblock) |
| 125 .arg(m_transform.getStepSize()) | 162 .arg(primaryTransform.getStepSize()) |
| 126 .arg(m_transform.getBlockSize()); | 163 .arg(primaryTransform.getBlockSize()); |
| 127 } | 164 } |
| 128 | 165 |
| 129 } else { | 166 } else { |
| 130 | 167 |
| 131 m_message = tr("Failed to initialise feature extraction plugin \"%1\"").arg(pluginId); | 168 m_message = tr("Failed to initialise feature extraction plugin \"%1\"").arg(pluginId); |
| 132 return; | 169 return false; |
| 133 } | 170 } |
| 134 } | 171 } |
| 135 | 172 |
| 136 if (m_transform.getPluginVersion() != "") { | 173 if (primaryTransform.getPluginVersion() != "") { |
| 137 QString pv = QString("%1").arg(m_plugin->getPluginVersion()); | 174 QString pv = QString("%1").arg(m_plugin->getPluginVersion()); |
| 138 if (pv != m_transform.getPluginVersion()) { | 175 if (pv != primaryTransform.getPluginVersion()) { |
| 139 QString vm = tr("Transform was configured for version %1 of plugin \"%2\", but the plugin being used is version %3") | 176 QString vm = tr("Transform was configured for version %1 of plugin \"%2\", but the plugin being used is version %3") |
| 140 .arg(m_transform.getPluginVersion()) | 177 .arg(primaryTransform.getPluginVersion()) |
| 141 .arg(pluginId) | 178 .arg(pluginId) |
| 142 .arg(pv); | 179 .arg(pv); |
| 143 if (m_message != "") { | 180 if (m_message != "") { |
| 144 m_message = QString("%1; %2").arg(vm).arg(m_message); | 181 m_message = QString("%1; %2").arg(vm).arg(m_message); |
| 145 } else { | 182 } else { |
| 150 | 187 |
| 151 Vamp::Plugin::OutputList outputs = m_plugin->getOutputDescriptors(); | 188 Vamp::Plugin::OutputList outputs = m_plugin->getOutputDescriptors(); |
| 152 | 189 |
| 153 if (outputs.empty()) { | 190 if (outputs.empty()) { |
| 154 m_message = tr("Plugin \"%1\" has no outputs").arg(pluginId); | 191 m_message = tr("Plugin \"%1\" has no outputs").arg(pluginId); |
| 155 return; | 192 return false; |
| 156 } | 193 } |
| 157 | 194 |
| 158 for (size_t i = 0; i < outputs.size(); ++i) { | 195 for (int j = 0; j < (int)m_transforms.size(); ++j) { |
| 196 | |
| 197 for (int i = 0; i < (int)outputs.size(); ++i) { | |
| 159 // SVDEBUG << "comparing output " << i << " name \"" << outputs[i].identifier << "\" with expected \"" << m_transform.getOutput() << "\"" << endl; | 198 // SVDEBUG << "comparing output " << i << " name \"" << outputs[i].identifier << "\" with expected \"" << m_transform.getOutput() << "\"" << endl; |
| 160 if (m_transform.getOutput() == "" || | 199 if (m_transforms[j].getOutput() == "" || |
| 161 outputs[i].identifier == m_transform.getOutput().toStdString()) { | 200 outputs[i].identifier == m_transforms[j].getOutput().toStdString()) { |
| 162 m_outputNo = i; | 201 m_outputNos.push_back(i); |
| 163 m_descriptor = new Vamp::Plugin::OutputDescriptor(outputs[i]); | 202 m_descriptors.push_back(new Vamp::Plugin::OutputDescriptor(outputs[i])); |
| 164 break; | 203 m_fixedRateFeatureNos.push_back(-1); // we increment before use |
| 165 } | 204 break; |
| 166 } | 205 } |
| 167 | 206 } |
| 168 if (!m_descriptor) { | 207 |
| 169 m_message = tr("Plugin \"%1\" has no output named \"%2\"") | 208 if (m_descriptors.size() <= j) { |
| 170 .arg(pluginId) | 209 m_message = tr("Plugin \"%1\" has no output named \"%2\"") |
| 171 .arg(m_transform.getOutput()); | 210 .arg(pluginId) |
| 172 return; | 211 .arg(m_transforms[j].getOutput()); |
| 173 } | 212 return false; |
| 174 | 213 } |
| 175 createOutputModel(); | 214 } |
| 215 | |
| 216 for (int j = 0; j < (int)m_transforms.size(); ++j) { | |
| 217 createOutputModel(j); | |
| 218 } | |
| 219 | |
| 220 return true; | |
| 176 } | 221 } |
| 177 | 222 |
| 178 void | 223 void |
| 179 FeatureExtractionModelTransformer::createOutputModel() | 224 FeatureExtractionModelTransformer::createOutputModel(int n) |
| 180 { | 225 { |
| 181 DenseTimeValueModel *input = getConformingInput(); | 226 DenseTimeValueModel *input = getConformingInput(); |
| 182 | 227 |
| 183 // cerr << "FeatureExtractionModelTransformer::createOutputModel: sample type " << m_descriptor->sampleType << ", rate " << m_descriptor->sampleRate << endl; | 228 // cerr << "FeatureExtractionModelTransformer::createOutputModel: sample type " << m_descriptor->sampleType << ", rate " << m_descriptor->sampleRate << endl; |
| 184 | 229 |
| 185 PluginRDFDescription description(m_transform.getPluginIdentifier()); | 230 PluginRDFDescription description(m_transforms[n].getPluginIdentifier()); |
| 186 QString outputId = m_transform.getOutput(); | 231 QString outputId = m_transforms[n].getOutput(); |
| 187 | 232 |
| 188 int binCount = 1; | 233 int binCount = 1; |
| 189 float minValue = 0.0, maxValue = 0.0; | 234 float minValue = 0.0, maxValue = 0.0; |
| 190 bool haveExtents = false; | 235 bool haveExtents = false; |
| 191 | 236 |
| 192 if (m_descriptor->hasFixedBinCount) { | 237 if (m_descriptors[n]->hasFixedBinCount) { |
| 193 binCount = m_descriptor->binCount; | 238 binCount = m_descriptors[n]->binCount; |
| 194 } | 239 } |
| 195 | 240 |
| 196 // cerr << "FeatureExtractionModelTransformer: output bin count " | 241 // cerr << "FeatureExtractionModelTransformer: output bin count " |
| 197 // << binCount << endl; | 242 // << binCount << endl; |
| 198 | 243 |
| 199 if (binCount > 0 && m_descriptor->hasKnownExtents) { | 244 if (binCount > 0 && m_descriptors[n]->hasKnownExtents) { |
| 200 minValue = m_descriptor->minValue; | 245 minValue = m_descriptors[n]->minValue; |
| 201 maxValue = m_descriptor->maxValue; | 246 maxValue = m_descriptors[n]->maxValue; |
| 202 haveExtents = true; | 247 haveExtents = true; |
| 203 } | 248 } |
| 204 | 249 |
| 205 size_t modelRate = input->getSampleRate(); | 250 size_t modelRate = input->getSampleRate(); |
| 206 size_t modelResolution = 1; | 251 size_t modelResolution = 1; |
| 207 | 252 |
| 208 if (m_descriptor->sampleType != | 253 if (m_descriptors[n]->sampleType != |
| 209 Vamp::Plugin::OutputDescriptor::OneSamplePerStep) { | 254 Vamp::Plugin::OutputDescriptor::OneSamplePerStep) { |
| 210 if (m_descriptor->sampleRate > input->getSampleRate()) { | 255 if (m_descriptors[n]->sampleRate > input->getSampleRate()) { |
| 211 cerr << "WARNING: plugin reports output sample rate as " | 256 cerr << "WARNING: plugin reports output sample rate as " |
| 212 << m_descriptor->sampleRate << " (can't display features with finer resolution than the input rate of " << input->getSampleRate() << ")" << endl; | 257 << m_descriptors[n]->sampleRate << " (can't display features with finer resolution than the input rate of " << input->getSampleRate() << ")" << endl; |
| 213 } | 258 } |
| 214 } | 259 } |
| 215 | 260 |
| 216 switch (m_descriptor->sampleType) { | 261 switch (m_descriptors[n]->sampleType) { |
| 217 | 262 |
| 218 case Vamp::Plugin::OutputDescriptor::VariableSampleRate: | 263 case Vamp::Plugin::OutputDescriptor::VariableSampleRate: |
| 219 if (m_descriptor->sampleRate != 0.0) { | 264 if (m_descriptors[n]->sampleRate != 0.0) { |
| 220 modelResolution = size_t(modelRate / m_descriptor->sampleRate + 0.001); | 265 modelResolution = size_t(modelRate / m_descriptors[n]->sampleRate + 0.001); |
| 221 } | 266 } |
| 222 break; | 267 break; |
| 223 | 268 |
| 224 case Vamp::Plugin::OutputDescriptor::OneSamplePerStep: | 269 case Vamp::Plugin::OutputDescriptor::OneSamplePerStep: |
| 225 modelResolution = m_transform.getStepSize(); | 270 modelResolution = m_transforms[n].getStepSize(); |
| 226 break; | 271 break; |
| 227 | 272 |
| 228 case Vamp::Plugin::OutputDescriptor::FixedSampleRate: | 273 case Vamp::Plugin::OutputDescriptor::FixedSampleRate: |
| 229 //!!! SV doesn't actually support display of models that have | 274 //!!! SV doesn't actually support display of models that have |
| 230 //!!! different underlying rates together -- so we always set | 275 //!!! different underlying rates together -- so we always set |
| 231 //!!! the model rate to be the input model's rate, and adjust | 276 //!!! the model rate to be the input model's rate, and adjust |
| 232 //!!! the resolution appropriately. We can't properly display | 277 //!!! the resolution appropriately. We can't properly display |
| 233 //!!! data with a higher resolution than the base model at all | 278 //!!! data with a higher resolution than the base model at all |
| 234 // modelRate = size_t(m_descriptor->sampleRate + 0.001); | 279 // modelRate = size_t(m_descriptors[n]->sampleRate + 0.001); |
| 235 if (m_descriptor->sampleRate > input->getSampleRate()) { | 280 if (m_descriptors[n]->sampleRate > input->getSampleRate()) { |
| 236 modelResolution = 1; | 281 modelResolution = 1; |
| 237 } else { | 282 } else { |
| 238 modelResolution = size_t(input->getSampleRate() / | 283 modelResolution = size_t(input->getSampleRate() / |
| 239 m_descriptor->sampleRate); | 284 m_descriptors[n]->sampleRate); |
| 240 } | 285 } |
| 241 break; | 286 break; |
| 242 } | 287 } |
| 243 | 288 |
| 244 bool preDurationPlugin = (m_plugin->getVampApiVersion() < 2); | 289 bool preDurationPlugin = (m_plugin->getVampApiVersion() < 2); |
| 245 | 290 |
| 291 Model *out = 0; | |
| 292 | |
| 246 if (binCount == 0 && | 293 if (binCount == 0 && |
| 247 (preDurationPlugin || !m_descriptor->hasDuration)) { | 294 (preDurationPlugin || !m_descriptors[n]->hasDuration)) { |
| 248 | 295 |
| 249 // Anything with no value and no duration is an instant | 296 // Anything with no value and no duration is an instant |
| 250 | 297 |
| 251 m_output = new SparseOneDimensionalModel(modelRate, modelResolution, | 298 out = new SparseOneDimensionalModel(modelRate, modelResolution, false); |
| 252 false); | |
| 253 | |
| 254 QString outputEventTypeURI = description.getOutputEventTypeURI(outputId); | 299 QString outputEventTypeURI = description.getOutputEventTypeURI(outputId); |
| 255 m_output->setRDFTypeURI(outputEventTypeURI); | 300 out->setRDFTypeURI(outputEventTypeURI); |
| 256 | 301 |
| 257 } else if ((preDurationPlugin && binCount > 1 && | 302 } else if ((preDurationPlugin && binCount > 1 && |
| 258 (m_descriptor->sampleType == | 303 (m_descriptors[n]->sampleType == |
| 259 Vamp::Plugin::OutputDescriptor::VariableSampleRate)) || | 304 Vamp::Plugin::OutputDescriptor::VariableSampleRate)) || |
| 260 (!preDurationPlugin && m_descriptor->hasDuration)) { | 305 (!preDurationPlugin && m_descriptors[n]->hasDuration)) { |
| 261 | 306 |
| 262 // For plugins using the old v1 API without explicit duration, | 307 // For plugins using the old v1 API without explicit duration, |
| 263 // we treat anything that has multiple bins (i.e. that has the | 308 // we treat anything that has multiple bins (i.e. that has the |
| 264 // potential to have value and duration) and a variable sample | 309 // potential to have value and duration) and a variable sample |
| 265 // rate as a note model, taking its values as pitch, duration | 310 // rate as a note model, taking its values as pitch, duration |
| 286 // duration) | 331 // duration) |
| 287 if (binCount > 1) isNoteModel = true; | 332 if (binCount > 1) isNoteModel = true; |
| 288 | 333 |
| 289 // Regions do not have units of Hz or MIDI things (a sweeping | 334 // Regions do not have units of Hz or MIDI things (a sweeping |
| 290 // assumption!) | 335 // assumption!) |
| 291 if (m_descriptor->unit == "Hz" || | 336 if (m_descriptors[n]->unit == "Hz" || |
| 292 m_descriptor->unit.find("MIDI") != std::string::npos || | 337 m_descriptors[n]->unit.find("MIDI") != std::string::npos || |
| 293 m_descriptor->unit.find("midi") != std::string::npos) { | 338 m_descriptors[n]->unit.find("midi") != std::string::npos) { |
| 294 isNoteModel = true; | 339 isNoteModel = true; |
| 295 } | 340 } |
| 296 | 341 |
| 297 // If we had a "sparse 3D model", we would have the additional | 342 // If we had a "sparse 3D model", we would have the additional |
| 298 // problem of determining whether to use that here (if bin | 343 // problem of determining whether to use that here (if bin |
| 304 if (haveExtents) { | 349 if (haveExtents) { |
| 305 model = new NoteModel (modelRate, modelResolution, minValue, maxValue, false); | 350 model = new NoteModel (modelRate, modelResolution, minValue, maxValue, false); |
| 306 } else { | 351 } else { |
| 307 model = new NoteModel (modelRate, modelResolution, false); | 352 model = new NoteModel (modelRate, modelResolution, false); |
| 308 } | 353 } |
| 309 model->setScaleUnits(m_descriptor->unit.c_str()); | 354 model->setScaleUnits(m_descriptors[n]->unit.c_str()); |
| 310 m_output = model; | 355 out = model; |
| 311 | 356 |
| 312 // GF: FlexiNoteModel is selected if the m_preferredOutputModel is set | 357 // GF: FlexiNoteModel is selected if the m_preferredOutputModel is set |
| 313 } else if (isNoteModel && m_preferredOutputModel == FlexiNoteOutputModel) { | 358 } else if (isNoteModel && m_preferredOutputModel == FlexiNoteOutputModel) { |
| 314 | 359 |
| 315 FlexiNoteModel *model; | 360 FlexiNoteModel *model; |
| 316 if (haveExtents) { | 361 if (haveExtents) { |
| 317 model = new FlexiNoteModel (modelRate, modelResolution, minValue, maxValue, false); | 362 model = new FlexiNoteModel (modelRate, modelResolution, minValue, maxValue, false); |
| 318 } else { | 363 } else { |
| 319 model = new FlexiNoteModel (modelRate, modelResolution, false); | 364 model = new FlexiNoteModel (modelRate, modelResolution, false); |
| 320 } | 365 } |
| 321 model->setScaleUnits(m_descriptor->unit.c_str()); | 366 model->setScaleUnits(m_descriptors[n]->unit.c_str()); |
| 322 m_output = model; | 367 out = model; |
| 323 | 368 |
| 324 } else { | 369 } else { |
| 325 | 370 |
| 326 RegionModel *model; | 371 RegionModel *model; |
| 327 if (haveExtents) { | 372 if (haveExtents) { |
| 329 (modelRate, modelResolution, minValue, maxValue, false); | 374 (modelRate, modelResolution, minValue, maxValue, false); |
| 330 } else { | 375 } else { |
| 331 model = new RegionModel | 376 model = new RegionModel |
| 332 (modelRate, modelResolution, false); | 377 (modelRate, modelResolution, false); |
| 333 } | 378 } |
| 334 model->setScaleUnits(m_descriptor->unit.c_str()); | 379 model->setScaleUnits(m_descriptors[n]->unit.c_str()); |
| 335 m_output = model; | 380 out = model; |
| 336 } | 381 } |
| 337 | 382 |
| 338 QString outputEventTypeURI = description.getOutputEventTypeURI(outputId); | 383 QString outputEventTypeURI = description.getOutputEventTypeURI(outputId); |
| 339 m_output->setRDFTypeURI(outputEventTypeURI); | 384 out->setRDFTypeURI(outputEventTypeURI); |
| 340 | 385 |
| 341 } else if (binCount == 1 || | 386 } else if (binCount == 1 || |
| 342 (m_descriptor->sampleType == | 387 (m_descriptors[n]->sampleType == |
| 343 Vamp::Plugin::OutputDescriptor::VariableSampleRate)) { | 388 Vamp::Plugin::OutputDescriptor::VariableSampleRate)) { |
| 344 | 389 |
| 345 // Anything that is not a 1D, note, or interval model and that | 390 // Anything that is not a 1D, note, or interval model and that |
| 346 // has only one value per result must be a sparse time value | 391 // has only one value per result must be a sparse time value |
| 347 // model. | 392 // model. |
| 359 model = new SparseTimeValueModel | 404 model = new SparseTimeValueModel |
| 360 (modelRate, modelResolution, false); | 405 (modelRate, modelResolution, false); |
| 361 } | 406 } |
| 362 | 407 |
| 363 Vamp::Plugin::OutputList outputs = m_plugin->getOutputDescriptors(); | 408 Vamp::Plugin::OutputList outputs = m_plugin->getOutputDescriptors(); |
| 364 model->setScaleUnits(outputs[m_outputNo].unit.c_str()); | 409 model->setScaleUnits(outputs[m_outputNos[n]].unit.c_str()); |
| 365 | 410 |
| 366 m_output = model; | 411 out = model; |
| 367 | 412 |
| 368 QString outputEventTypeURI = description.getOutputEventTypeURI(outputId); | 413 QString outputEventTypeURI = description.getOutputEventTypeURI(outputId); |
| 369 m_output->setRDFTypeURI(outputEventTypeURI); | 414 out->setRDFTypeURI(outputEventTypeURI); |
| 370 | 415 |
| 371 } else { | 416 } else { |
| 372 | 417 |
| 373 // Anything that is not a 1D, note, or interval model and that | 418 // Anything that is not a 1D, note, or interval model and that |
| 374 // has a fixed sample rate and more than one value per result | 419 // has a fixed sample rate and more than one value per result |
| 378 new EditableDenseThreeDimensionalModel | 423 new EditableDenseThreeDimensionalModel |
| 379 (modelRate, modelResolution, binCount, | 424 (modelRate, modelResolution, binCount, |
| 380 EditableDenseThreeDimensionalModel::BasicMultirateCompression, | 425 EditableDenseThreeDimensionalModel::BasicMultirateCompression, |
| 381 false); | 426 false); |
| 382 | 427 |
| 383 if (!m_descriptor->binNames.empty()) { | 428 if (!m_descriptors[n]->binNames.empty()) { |
| 384 std::vector<QString> names; | 429 std::vector<QString> names; |
| 385 for (size_t i = 0; i < m_descriptor->binNames.size(); ++i) { | 430 for (size_t i = 0; i < m_descriptors[n]->binNames.size(); ++i) { |
| 386 names.push_back(m_descriptor->binNames[i].c_str()); | 431 names.push_back(m_descriptors[n]->binNames[i].c_str()); |
| 387 } | 432 } |
| 388 model->setBinNames(names); | 433 model->setBinNames(names); |
| 389 } | 434 } |
| 390 | 435 |
| 391 m_output = model; | 436 out = model; |
| 392 | 437 |
| 393 QString outputSignalTypeURI = description.getOutputSignalTypeURI(outputId); | 438 QString outputSignalTypeURI = description.getOutputSignalTypeURI(outputId); |
| 394 m_output->setRDFTypeURI(outputSignalTypeURI); | 439 out->setRDFTypeURI(outputSignalTypeURI); |
| 395 } | 440 } |
| 396 | 441 |
| 397 if (m_output) m_output->setSourceModel(input); | 442 if (out) { |
| 443 out->setSourceModel(input); | |
| 444 m_outputs.push_back(out); | |
| 445 } | |
| 398 } | 446 } |
| 399 | 447 |
| 400 FeatureExtractionModelTransformer::~FeatureExtractionModelTransformer() | 448 FeatureExtractionModelTransformer::~FeatureExtractionModelTransformer() |
| 401 { | 449 { |
| 402 // SVDEBUG << "FeatureExtractionModelTransformer::~FeatureExtractionModelTransformer()" << endl; | 450 // SVDEBUG << "FeatureExtractionModelTransformer::~FeatureExtractionModelTransformer()" << endl; |
| 403 delete m_plugin; | 451 delete m_plugin; |
| 404 delete m_descriptor; | 452 delete m_descriptors[n]; |
| 405 } | 453 } |
| 406 | 454 |
| 407 DenseTimeValueModel * | 455 DenseTimeValueModel * |
| 408 FeatureExtractionModelTransformer::getConformingInput() | 456 FeatureExtractionModelTransformer::getConformingInput() |
| 409 { | 457 { |
| 421 FeatureExtractionModelTransformer::run() | 469 FeatureExtractionModelTransformer::run() |
| 422 { | 470 { |
| 423 DenseTimeValueModel *input = getConformingInput(); | 471 DenseTimeValueModel *input = getConformingInput(); |
| 424 if (!input) return; | 472 if (!input) return; |
| 425 | 473 |
| 426 if (!m_output) return; | 474 if (m_outputs.empty()) return; |
| 427 | 475 |
| 428 while (!input->isReady() && !m_abandoned) { | 476 while (!input->isReady() && !m_abandoned) { |
| 429 SVDEBUG << "FeatureExtractionModelTransformer::run: Waiting for input model to be ready..." << endl; | 477 SVDEBUG << "FeatureExtractionModelTransformer::run: Waiting for input model to be ready..." << endl; |
| 430 usleep(500000); | 478 usleep(500000); |
| 431 } | 479 } |
| 438 channelCount = 1; | 486 channelCount = 1; |
| 439 } | 487 } |
| 440 | 488 |
| 441 float **buffers = new float*[channelCount]; | 489 float **buffers = new float*[channelCount]; |
| 442 for (size_t ch = 0; ch < channelCount; ++ch) { | 490 for (size_t ch = 0; ch < channelCount; ++ch) { |
| 443 buffers[ch] = new float[m_transform.getBlockSize() + 2]; | 491 buffers[ch] = new float[m_transforms[n].getBlockSize() + 2]; |
| 444 } | 492 } |
| 445 | 493 |
| 446 size_t stepSize = m_transform.getStepSize(); | 494 size_t stepSize = m_transforms[n].getStepSize(); |
| 447 size_t blockSize = m_transform.getBlockSize(); | 495 size_t blockSize = m_transforms[n].getBlockSize(); |
| 448 | 496 |
| 449 bool frequencyDomain = (m_plugin->getInputDomain() == | 497 bool frequencyDomain = (m_plugin->getInputDomain() == |
| 450 Vamp::Plugin::FrequencyDomain); | 498 Vamp::Plugin::FrequencyDomain); |
| 451 std::vector<FFTModel *> fftModels; | 499 std::vector<FFTModel *> fftModels; |
| 452 | 500 |
| 453 if (frequencyDomain) { | 501 if (frequencyDomain) { |
| 454 for (size_t ch = 0; ch < channelCount; ++ch) { | 502 for (size_t ch = 0; ch < channelCount; ++ch) { |
| 455 FFTModel *model = new FFTModel | 503 FFTModel *model = new FFTModel |
| 456 (getConformingInput(), | 504 (getConformingInput(), |
| 457 channelCount == 1 ? m_input.getChannel() : ch, | 505 channelCount == 1 ? m_input.getChannel() : ch, |
| 458 m_transform.getWindowType(), | 506 m_transforms[n].getWindowType(), |
| 459 blockSize, | 507 blockSize, |
| 460 stepSize, | 508 stepSize, |
| 461 blockSize, | 509 blockSize, |
| 462 false, | 510 false, |
| 463 StorageAdviser::PrecisionCritical); | 511 StorageAdviser::PrecisionCritical); |
| 473 } | 521 } |
| 474 | 522 |
| 475 long startFrame = m_input.getModel()->getStartFrame(); | 523 long startFrame = m_input.getModel()->getStartFrame(); |
| 476 long endFrame = m_input.getModel()->getEndFrame(); | 524 long endFrame = m_input.getModel()->getEndFrame(); |
| 477 | 525 |
| 478 RealTime contextStartRT = m_transform.getStartTime(); | 526 RealTime contextStartRT = m_transforms[n].getStartTime(); |
| 479 RealTime contextDurationRT = m_transform.getDuration(); | 527 RealTime contextDurationRT = m_transforms[n].getDuration(); |
| 480 | 528 |
| 481 long contextStart = | 529 long contextStart = |
| 482 RealTime::realTime2Frame(contextStartRT, sampleRate); | 530 RealTime::realTime2Frame(contextStartRT, sampleRate); |
| 483 | 531 |
| 484 long contextDuration = | 532 long contextDuration = |
| 554 Vamp::Plugin::FeatureSet features = m_plugin->process | 602 Vamp::Plugin::FeatureSet features = m_plugin->process |
| 555 (buffers, Vamp::RealTime::frame2RealTime(blockFrame, sampleRate)); | 603 (buffers, Vamp::RealTime::frame2RealTime(blockFrame, sampleRate)); |
| 556 | 604 |
| 557 if (m_abandoned) break; | 605 if (m_abandoned) break; |
| 558 | 606 |
| 559 for (size_t fi = 0; fi < features[m_outputNo].size(); ++fi) { | 607 for (size_t fi = 0; fi < features[m_outputNos[n]].size(); ++fi) { |
| 560 Vamp::Plugin::Feature feature = features[m_outputNo][fi]; | 608 Vamp::Plugin::Feature feature = features[m_outputNos[n]][fi]; |
| 561 addFeature(blockFrame, feature); | 609 addFeature(blockFrame, feature); |
| 562 } | 610 } |
| 563 | 611 |
| 564 if (blockFrame == contextStart || completion > prevCompletion) { | 612 if (blockFrame == contextStart || completion > prevCompletion) { |
| 565 setCompletion(completion); | 613 setCompletion(completion); |
| 570 } | 618 } |
| 571 | 619 |
| 572 if (!m_abandoned) { | 620 if (!m_abandoned) { |
| 573 Vamp::Plugin::FeatureSet features = m_plugin->getRemainingFeatures(); | 621 Vamp::Plugin::FeatureSet features = m_plugin->getRemainingFeatures(); |
| 574 | 622 |
| 575 for (size_t fi = 0; fi < features[m_outputNo].size(); ++fi) { | 623 for (size_t fi = 0; fi < features[m_outputNos[n]].size(); ++fi) { |
| 576 Vamp::Plugin::Feature feature = features[m_outputNo][fi]; | 624 Vamp::Plugin::Feature feature = features[m_outputNos[n]][fi]; |
| 577 addFeature(blockFrame, feature); | 625 addFeature(blockFrame, feature); |
| 578 } | 626 } |
| 579 } | 627 } |
| 580 | 628 |
| 581 setCompletion(100); | 629 setCompletion(100); |
| 660 // << ", timestamp = " << feature.timestamp << ", hasDuration = " | 708 // << ", timestamp = " << feature.timestamp << ", hasDuration = " |
| 661 // << feature.hasDuration << ", duration = " << feature.duration | 709 // << feature.hasDuration << ", duration = " << feature.duration |
| 662 // << endl; | 710 // << endl; |
| 663 | 711 |
| 664 int binCount = 1; | 712 int binCount = 1; |
| 665 if (m_descriptor->hasFixedBinCount) { | 713 if (m_descriptors[n]->hasFixedBinCount) { |
| 666 binCount = m_descriptor->binCount; | 714 binCount = m_descriptors[n]->binCount; |
| 667 } | 715 } |
| 668 | 716 |
| 669 size_t frame = blockFrame; | 717 size_t frame = blockFrame; |
| 670 | 718 |
| 671 if (m_descriptor->sampleType == | 719 if (m_descriptors[n]->sampleType == |
| 672 Vamp::Plugin::OutputDescriptor::VariableSampleRate) { | 720 Vamp::Plugin::OutputDescriptor::VariableSampleRate) { |
| 673 | 721 |
| 674 if (!feature.hasTimestamp) { | 722 if (!feature.hasTimestamp) { |
| 675 cerr | 723 cerr |
| 676 << "WARNING: FeatureExtractionModelTransformer::addFeature: " | 724 << "WARNING: FeatureExtractionModelTransformer::addFeature: " |
| 679 return; | 727 return; |
| 680 } else { | 728 } else { |
| 681 frame = Vamp::RealTime::realTime2Frame(feature.timestamp, inputRate); | 729 frame = Vamp::RealTime::realTime2Frame(feature.timestamp, inputRate); |
| 682 } | 730 } |
| 683 | 731 |
| 684 } else if (m_descriptor->sampleType == | 732 } else if (m_descriptors[n]->sampleType == |
| 685 Vamp::Plugin::OutputDescriptor::FixedSampleRate) { | 733 Vamp::Plugin::OutputDescriptor::FixedSampleRate) { |
| 686 | 734 |
| 687 if (!feature.hasTimestamp) { | 735 if (!feature.hasTimestamp) { |
| 688 ++m_fixedRateFeatureNo; | 736 ++m_fixedRateFeatureNos[n]; |
| 689 } else { | 737 } else { |
| 690 RealTime ts(feature.timestamp.sec, feature.timestamp.nsec); | 738 RealTime ts(feature.timestamp.sec, feature.timestamp.nsec); |
| 691 m_fixedRateFeatureNo = | 739 m_fixedRateFeatureNos[n] = |
| 692 lrint(ts.toDouble() * m_descriptor->sampleRate); | 740 lrint(ts.toDouble() * m_descriptors[n]->sampleRate); |
| 693 } | 741 } |
| 694 | 742 |
| 695 frame = lrintf((m_fixedRateFeatureNo / m_descriptor->sampleRate) | 743 frame = lrintf((m_fixedRateFeatureNos[n] / m_descriptors[n]->sampleRate) |
| 696 * inputRate); | 744 * inputRate); |
| 697 } | 745 } |
| 698 | 746 |
| 699 // Rather than repeat the complicated tests from the constructor | 747 // Rather than repeat the complicated tests from the constructor |
| 700 // to determine what sort of model we must be adding the features | 748 // to determine what sort of model we must be adding the features |
| 701 // to, we instead test what sort of model the constructor decided | 749 // to, we instead test what sort of model the constructor decided |
| 702 // to create. | 750 // to create. |
| 703 | 751 |
| 704 if (isOutput<SparseOneDimensionalModel>()) { | 752 //!!! currently hardcoding model 0 |
| 753 | |
| 754 if (isOutput<SparseOneDimensionalModel>(n)) { | |
| 705 | 755 |
| 706 SparseOneDimensionalModel *model = | 756 SparseOneDimensionalModel *model = |
| 707 getConformingOutput<SparseOneDimensionalModel>(); | 757 getConformingOutput<SparseOneDimensionalModel>(n); |
| 708 if (!model) return; | 758 if (!model) return; |
| 709 | 759 |
| 710 model->addPoint(SparseOneDimensionalModel::Point | 760 model->addPoint(SparseOneDimensionalModel::Point |
| 711 (frame, feature.label.c_str())); | 761 (frame, feature.label.c_str())); |
| 712 | 762 |
| 713 } else if (isOutput<SparseTimeValueModel>()) { | 763 } else if (isOutput<SparseTimeValueModel>(n)) { |
| 714 | 764 |
| 715 SparseTimeValueModel *model = | 765 SparseTimeValueModel *model = |
| 716 getConformingOutput<SparseTimeValueModel>(); | 766 getConformingOutput<SparseTimeValueModel>(n); |
| 717 if (!model) return; | 767 if (!model) return; |
| 718 | 768 |
| 719 for (int i = 0; i < feature.values.size(); ++i) { | 769 for (int i = 0; i < feature.values.size(); ++i) { |
| 720 | 770 |
| 721 float value = feature.values[i]; | 771 float value = feature.values[i]; |
| 726 } | 776 } |
| 727 | 777 |
| 728 model->addPoint(SparseTimeValueModel::Point(frame, value, label)); | 778 model->addPoint(SparseTimeValueModel::Point(frame, value, label)); |
| 729 } | 779 } |
| 730 | 780 |
| 731 } else if (isOutput<FlexiNoteModel>() || isOutput<NoteModel>() || isOutput<RegionModel>()) { //GF: Added Note Model | 781 } else if (isOutput<FlexiNoteModel>(n) || isOutput<NoteModel>(n) || isOutput<RegionModel>(n)) { //GF: Added Note Model |
| 732 | 782 |
| 733 int index = 0; | 783 int index = 0; |
| 734 | 784 |
| 735 float value = 0.0; | 785 float value = 0.0; |
| 736 if (feature.values.size() > index) { | 786 if (feature.values.size() > index) { |
| 744 if (feature.values.size() > index) { | 794 if (feature.values.size() > index) { |
| 745 duration = feature.values[index++]; | 795 duration = feature.values[index++]; |
| 746 } | 796 } |
| 747 } | 797 } |
| 748 | 798 |
| 749 if (isOutput<FlexiNoteModel>()) { // GF: added for flexi note model | 799 if (isOutput<FlexiNoteModel>(n)) { // GF: added for flexi note model |
| 750 | 800 |
| 751 float velocity = 100; | 801 float velocity = 100; |
| 752 if (feature.values.size() > index) { | 802 if (feature.values.size() > index) { |
| 753 velocity = feature.values[index++]; | 803 velocity = feature.values[index++]; |
| 754 } | 804 } |
| 755 if (velocity < 0) velocity = 127; | 805 if (velocity < 0) velocity = 127; |
| 756 if (velocity > 127) velocity = 127; | 806 if (velocity > 127) velocity = 127; |
| 757 | 807 |
| 758 FlexiNoteModel *model = getConformingOutput<FlexiNoteModel>(); | 808 FlexiNoteModel *model = getConformingOutput<FlexiNoteModel>(n); |
| 759 if (!model) return; | 809 if (!model) return; |
| 760 model->addPoint(FlexiNoteModel::Point(frame, value, // value is pitch | 810 model->addPoint(FlexiNoteModel::Point(frame, value, // value is pitch |
| 761 lrintf(duration), | 811 lrintf(duration), |
| 762 velocity / 127.f, | 812 velocity / 127.f, |
| 763 feature.label.c_str())); | 813 feature.label.c_str())); |
| 764 // GF: end -- added for flexi note model | 814 // GF: end -- added for flexi note model |
| 765 } else if (isOutput<NoteModel>()) { | 815 } else if (isOutput<NoteModel>(n)) { |
| 766 | 816 |
| 767 float velocity = 100; | 817 float velocity = 100; |
| 768 if (feature.values.size() > index) { | 818 if (feature.values.size() > index) { |
| 769 velocity = feature.values[index++]; | 819 velocity = feature.values[index++]; |
| 770 } | 820 } |
| 771 if (velocity < 0) velocity = 127; | 821 if (velocity < 0) velocity = 127; |
| 772 if (velocity > 127) velocity = 127; | 822 if (velocity > 127) velocity = 127; |
| 773 | 823 |
| 774 NoteModel *model = getConformingOutput<NoteModel>(); | 824 NoteModel *model = getConformingOutput<NoteModel>(n); |
| 775 if (!model) return; | 825 if (!model) return; |
| 776 model->addPoint(NoteModel::Point(frame, value, // value is pitch | 826 model->addPoint(NoteModel::Point(frame, value, // value is pitch |
| 777 lrintf(duration), | 827 lrintf(duration), |
| 778 velocity / 127.f, | 828 velocity / 127.f, |
| 779 feature.label.c_str())); | 829 feature.label.c_str())); |
| 780 } else { | 830 } else { |
| 781 | 831 |
| 782 RegionModel *model = getConformingOutput<RegionModel>(); | 832 RegionModel *model = getConformingOutput<RegionModel>(n); |
| 783 if (!model) return; | 833 if (!model) return; |
| 784 | 834 |
| 785 if (feature.hasDuration && !feature.values.empty()) { | 835 if (feature.hasDuration && !feature.values.empty()) { |
| 786 | 836 |
| 787 for (int i = 0; i < feature.values.size(); ++i) { | 837 for (int i = 0; i < feature.values.size(); ++i) { |
| 803 lrintf(duration), | 853 lrintf(duration), |
| 804 feature.label.c_str())); | 854 feature.label.c_str())); |
| 805 } | 855 } |
| 806 } | 856 } |
| 807 | 857 |
| 808 } else if (isOutput<EditableDenseThreeDimensionalModel>()) { | 858 } else if (isOutput<EditableDenseThreeDimensionalModel>(n)) { |
| 809 | 859 |
| 810 DenseThreeDimensionalModel::Column values = | 860 DenseThreeDimensionalModel::Column values = |
| 811 DenseThreeDimensionalModel::Column::fromStdVector(feature.values); | 861 DenseThreeDimensionalModel::Column::fromStdVector(feature.values); |
| 812 | 862 |
| 813 EditableDenseThreeDimensionalModel *model = | 863 EditableDenseThreeDimensionalModel *model = |
| 814 getConformingOutput<EditableDenseThreeDimensionalModel>(); | 864 getConformingOutput<EditableDenseThreeDimensionalModel>(n); |
| 815 if (!model) return; | 865 if (!model) return; |
| 816 | 866 |
| 817 model->setColumn(frame / model->getResolution(), values); | 867 model->setColumn(frame / model->getResolution(), values); |
| 818 | 868 |
| 819 } else { | 869 } else { |
| 823 | 873 |
| 824 void | 874 void |
| 825 FeatureExtractionModelTransformer::setCompletion(int completion) | 875 FeatureExtractionModelTransformer::setCompletion(int completion) |
| 826 { | 876 { |
| 827 int binCount = 1; | 877 int binCount = 1; |
| 828 if (m_descriptor->hasFixedBinCount) { | 878 if (m_descriptors[n]->hasFixedBinCount) { |
| 829 binCount = m_descriptor->binCount; | 879 binCount = m_descriptors[n]->binCount; |
| 830 } | 880 } |
| 831 | 881 |
| 832 // SVDEBUG << "FeatureExtractionModelTransformer::setCompletion(" | 882 // SVDEBUG << "FeatureExtractionModelTransformer::setCompletion(" |
| 833 // << completion << ")" << endl; | 883 // << completion << ")" << endl; |
| 834 | 884 |
| 835 if (isOutput<SparseOneDimensionalModel>()) { | 885 if (isOutput<SparseOneDimensionalModel>(n)) { |
| 836 | 886 |
| 837 SparseOneDimensionalModel *model = | 887 SparseOneDimensionalModel *model = |
| 838 getConformingOutput<SparseOneDimensionalModel>(); | 888 getConformingOutput<SparseOneDimensionalModel>(n); |
| 839 if (!model) return; | 889 if (!model) return; |
| 840 model->setCompletion(completion, true); | 890 model->setCompletion(completion, true); |
| 841 | 891 |
| 842 } else if (isOutput<SparseTimeValueModel>()) { | 892 } else if (isOutput<SparseTimeValueModel>(n)) { |
| 843 | 893 |
| 844 SparseTimeValueModel *model = | 894 SparseTimeValueModel *model = |
| 845 getConformingOutput<SparseTimeValueModel>(); | 895 getConformingOutput<SparseTimeValueModel>(n); |
| 846 if (!model) return; | 896 if (!model) return; |
| 847 model->setCompletion(completion, true); | 897 model->setCompletion(completion, true); |
| 848 | 898 |
| 849 } else if (isOutput<NoteModel>()) { | 899 } else if (isOutput<NoteModel>(n)) { |
| 850 | 900 |
| 851 NoteModel *model = getConformingOutput<NoteModel>(); | 901 NoteModel *model = getConformingOutput<NoteModel>(n); |
| 852 if (!model) return; | 902 if (!model) return; |
| 853 model->setCompletion(completion, true); | 903 model->setCompletion(completion, true); |
| 854 | 904 |
| 855 } else if (isOutput<FlexiNoteModel>()) { | 905 } else if (isOutput<FlexiNoteModel>(n)) { |
| 856 | 906 |
| 857 FlexiNoteModel *model = getConformingOutput<FlexiNoteModel>(); | 907 FlexiNoteModel *model = getConformingOutput<FlexiNoteModel>(n); |
| 858 if (!model) return; | 908 if (!model) return; |
| 859 model->setCompletion(completion, true); | 909 model->setCompletion(completion, true); |
| 860 | 910 |
| 861 } else if (isOutput<RegionModel>()) { | 911 } else if (isOutput<RegionModel>(n)) { |
| 862 | 912 |
| 863 RegionModel *model = getConformingOutput<RegionModel>(); | 913 RegionModel *model = getConformingOutput<RegionModel>(n); |
| 864 if (!model) return; | 914 if (!model) return; |
| 865 model->setCompletion(completion, true); | 915 model->setCompletion(completion, true); |
| 866 | 916 |
| 867 } else if (isOutput<EditableDenseThreeDimensionalModel>()) { | 917 } else if (isOutput<EditableDenseThreeDimensionalModel>(n)) { |
| 868 | 918 |
| 869 EditableDenseThreeDimensionalModel *model = | 919 EditableDenseThreeDimensionalModel *model = |
| 870 getConformingOutput<EditableDenseThreeDimensionalModel>(); | 920 getConformingOutput<EditableDenseThreeDimensionalModel>(n); |
| 871 if (!model) return; | 921 if (!model) return; |
| 872 model->setCompletion(completion, true); //!!!m_context.updates); | 922 model->setCompletion(completion, true); //!!!m_context.updates); |
| 873 } | 923 } |
| 874 } | 924 } |
| 875 | 925 |
