comparison transform/FeatureExtractionModelTransformer.cpp @ 874:862fe7b20df7 tony_integration

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