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 |