Mercurial > hg > sonic-annotator
comparison runner/FeatureExtractionManager.cpp @ 288:fd4a6183482f kapoor_1202
Merge from branch piper-nopiper. The next release will be based on this.
author | Chris Cannam |
---|---|
date | Fri, 02 Dec 2016 10:04:44 +0000 |
parents | 5ba121f3889e |
children | 0e866ef12d87 |
comparison
equal
deleted
inserted
replaced
259:9e7d180be225 | 288:fd4a6183482f |
---|---|
21 #include <vamp-hostsdk/PluginInputDomainAdapter.h> | 21 #include <vamp-hostsdk/PluginInputDomainAdapter.h> |
22 #include <vamp-hostsdk/PluginSummarisingAdapter.h> | 22 #include <vamp-hostsdk/PluginSummarisingAdapter.h> |
23 #include <vamp-hostsdk/PluginWrapper.h> | 23 #include <vamp-hostsdk/PluginWrapper.h> |
24 #include <vamp-hostsdk/PluginLoader.h> | 24 #include <vamp-hostsdk/PluginLoader.h> |
25 | 25 |
26 #include "base/Debug.h" | |
26 #include "base/Exceptions.h" | 27 #include "base/Exceptions.h" |
27 | 28 |
28 #include <iostream> | 29 #include <iostream> |
29 | 30 |
30 using namespace std; | 31 using namespace std; |
49 | 50 |
50 #include <QTextStream> | 51 #include <QTextStream> |
51 #include <QFile> | 52 #include <QFile> |
52 #include <QFileInfo> | 53 #include <QFileInfo> |
53 | 54 |
54 FeatureExtractionManager::FeatureExtractionManager() : | 55 FeatureExtractionManager::FeatureExtractionManager(bool verbose) : |
56 m_verbose(verbose), | |
55 m_summariesOnly(false), | 57 m_summariesOnly(false), |
56 // We can read using an arbitrary fixed block size -- | 58 // We can read using an arbitrary fixed block size -- |
57 // PluginBufferingAdapter handles this for us. But while this | 59 // PluginBufferingAdapter handles this for us. But while this |
58 // doesn't affect the step and block size actually passed to the | 60 // doesn't affect the step and block size actually passed to the |
59 // plugin, it does affect the overall time range of the audio | 61 // plugin, it does affect the overall time range of the audio |
71 { | 73 { |
72 } | 74 } |
73 | 75 |
74 FeatureExtractionManager::~FeatureExtractionManager() | 76 FeatureExtractionManager::~FeatureExtractionManager() |
75 { | 77 { |
78 SVDEBUG << "FeatureExtractionManager::~FeatureExtractionManager: cleaning up" | |
79 << endl; | |
80 | |
76 for (PluginMap::iterator pi = m_plugins.begin(); | 81 for (PluginMap::iterator pi = m_plugins.begin(); |
77 pi != m_plugins.end(); ++pi) { | 82 pi != m_plugins.end(); ++pi) { |
78 delete pi->first; | 83 delete pi->first; |
79 } | 84 } |
80 foreach (AudioFileReader *r, m_readyReaders) { | 85 foreach (AudioFileReader *r, m_readyReaders) { |
81 delete r; | 86 delete r; |
82 } | 87 } |
88 | |
89 SVDEBUG << "FeatureExtractionManager::~FeatureExtractionManager: done" << endl; | |
83 } | 90 } |
84 | 91 |
85 void FeatureExtractionManager::setChannels(int channels) | 92 void FeatureExtractionManager::setChannels(int channels) |
86 { | 93 { |
87 m_channels = channels; | 94 m_channels = channels; |
117 const PluginSummarisingAdapter::SegmentBoundaries &boundaries) | 124 const PluginSummarisingAdapter::SegmentBoundaries &boundaries) |
118 { | 125 { |
119 for (SummaryNameSet::const_iterator i = names.begin(); | 126 for (SummaryNameSet::const_iterator i = names.begin(); |
120 i != names.end(); ++i) { | 127 i != names.end(); ++i) { |
121 if (getSummaryType(*i) == PluginSummarisingAdapter::UnknownSummaryType) { | 128 if (getSummaryType(*i) == PluginSummarisingAdapter::UnknownSummaryType) { |
122 cerr << "ERROR: Unknown summary type \"" << *i << "\"" << endl; | 129 SVCERR << "ERROR: Unknown summary type \"" << *i << "\"" << endl; |
123 return false; | 130 return false; |
124 } | 131 } |
125 } | 132 } |
126 m_summaries = names; | 133 m_summaries = names; |
127 m_boundaries = boundaries; | 134 m_boundaries = boundaries; |
154 return PluginInputDomainAdapter::BlackmanHarrisWindow; | 161 return PluginInputDomainAdapter::BlackmanHarrisWindow; |
155 case GaussianWindow: | 162 case GaussianWindow: |
156 case ParzenWindow: | 163 case ParzenWindow: |
157 // Not supported in Vamp SDK, fall through | 164 // Not supported in Vamp SDK, fall through |
158 default: | 165 default: |
159 cerr << "ERROR: Unknown or unsupported window type \"" << t << "\", using Hann (\"" << HanningWindow << "\")" << endl; | 166 SVCERR << "ERROR: Unknown or unsupported window type \"" << t << "\", using Hann (\"" << HanningWindow << "\")" << endl; |
160 return PluginInputDomainAdapter::HanningWindow; | 167 return PluginInputDomainAdapter::HanningWindow; |
161 } | 168 } |
162 } | 169 } |
163 | 170 |
164 bool FeatureExtractionManager::addFeatureExtractor | 171 bool FeatureExtractionManager::addFeatureExtractor |
166 { | 173 { |
167 //!!! exceptions rather than return values? | 174 //!!! exceptions rather than return values? |
168 | 175 |
169 if (transform.getSampleRate() == 0) { | 176 if (transform.getSampleRate() == 0) { |
170 if (m_sampleRate == 0) { | 177 if (m_sampleRate == 0) { |
171 cerr << "NOTE: Transform does not specify a sample rate, using default rate of " << m_defaultSampleRate << endl; | 178 SVCERR << "NOTE: Transform does not specify a sample rate, using default rate of " << m_defaultSampleRate << endl; |
172 transform.setSampleRate(m_defaultSampleRate); | 179 transform.setSampleRate(m_defaultSampleRate); |
173 m_sampleRate = m_defaultSampleRate; | 180 m_sampleRate = m_defaultSampleRate; |
174 } else { | 181 } else { |
175 cerr << "NOTE: Transform does not specify a sample rate, using previous transform's rate of " << m_sampleRate << endl; | 182 SVCERR << "NOTE: Transform does not specify a sample rate, using previous transform's rate of " << m_sampleRate << endl; |
176 transform.setSampleRate(m_sampleRate); | 183 transform.setSampleRate(m_sampleRate); |
177 } | 184 } |
178 } | 185 } |
179 | 186 |
180 if (m_sampleRate == 0) { | 187 if (m_sampleRate == 0) { |
181 m_sampleRate = transform.getSampleRate(); | 188 m_sampleRate = transform.getSampleRate(); |
182 } | 189 } |
183 | 190 |
184 if (transform.getSampleRate() != m_sampleRate) { | 191 if (transform.getSampleRate() != m_sampleRate) { |
185 cerr << "WARNING: Transform sample rate " << transform.getSampleRate() << " does not match previously specified transform rate of " << m_sampleRate << " -- only a single rate is supported for each run" << endl; | 192 SVCERR << "WARNING: Transform sample rate " << transform.getSampleRate() << " does not match previously specified transform rate of " << m_sampleRate << " -- only a single rate is supported for each run" << endl; |
186 cerr << "WARNING: Using previous rate of " << m_sampleRate << " for this transform as well" << endl; | 193 SVCERR << "WARNING: Using previous rate of " << m_sampleRate << " for this transform as well" << endl; |
187 transform.setSampleRate(m_sampleRate); | 194 transform.setSampleRate(m_sampleRate); |
188 } | 195 } |
189 | 196 |
190 Plugin *plugin = 0; | 197 Plugin *plugin = 0; |
191 | 198 |
206 i != m_transformPluginMap.end(); ++i) { | 213 i != m_transformPluginMap.end(); ++i) { |
207 Transform test = i->first; | 214 Transform test = i->first; |
208 test.setOutput(transform.getOutput()); | 215 test.setOutput(transform.getOutput()); |
209 test.setSummaryType(transform.getSummaryType()); | 216 test.setSummaryType(transform.getSummaryType()); |
210 if (transform == test) { | 217 if (transform == test) { |
211 cerr << "NOTE: Already have transform identical to this one (for \"" | 218 SVCERR << "NOTE: Already have transform identical to this one (for \"" |
212 << transform.getIdentifier().toStdString() | 219 << transform.getIdentifier().toStdString() |
213 << "\") in every detail except output identifier and/or " | 220 << "\") in every detail except output identifier and/or " |
214 << "summary type; sharing its plugin instance" << endl; | 221 << "summary type; sharing its plugin instance" << endl; |
215 plugin = i->second; | 222 plugin = i->second; |
216 if (transform.getSummaryType() != Transform::NoSummary && | 223 if (transform.getSummaryType() != Transform::NoSummary && |
229 PluginBase *pb = tf->instantiatePluginFor(transform); | 236 PluginBase *pb = tf->instantiatePluginFor(transform); |
230 plugin = tf->downcastVampPlugin(pb); | 237 plugin = tf->downcastVampPlugin(pb); |
231 if (!plugin) { | 238 if (!plugin) { |
232 //!!! todo: handle non-Vamp plugins too, or make the main --list | 239 //!!! todo: handle non-Vamp plugins too, or make the main --list |
233 // option print out only Vamp transforms | 240 // option print out only Vamp transforms |
234 cerr << "ERROR: Failed to load plugin for transform \"" | 241 SVCERR << "ERROR: Failed to load plugin for transform \"" |
235 << transform.getIdentifier().toStdString() << "\"" << endl; | 242 << transform.getIdentifier().toStdString() << "\"" << endl; |
236 if (pb) { | 243 if (pb) { |
237 cerr << "NOTE: (A plugin was loaded, but apparently not a Vamp plugin)" << endl; | 244 SVCERR << "NOTE: (A plugin was loaded, but apparently not a Vamp plugin)" << endl; |
238 } | 245 } |
239 delete pb; | 246 delete pb; |
240 return false; | 247 return false; |
241 } | 248 } |
242 | 249 |
292 adapter->setSummarySegmentBoundaries(m_boundaries); | 299 adapter->setSummarySegmentBoundaries(m_boundaries); |
293 plugin = adapter; | 300 plugin = adapter; |
294 } | 301 } |
295 | 302 |
296 if (!plugin->initialise(m_channels, m_blockSize, m_blockSize)) { | 303 if (!plugin->initialise(m_channels, m_blockSize, m_blockSize)) { |
297 cerr << "ERROR: Plugin initialise (channels = " << m_channels << ", stepSize = " << m_blockSize << ", blockSize = " << m_blockSize << ") failed." << endl; | 304 SVCERR << "ERROR: Plugin initialise (channels = " << m_channels << ", stepSize = " << m_blockSize << ", blockSize = " << m_blockSize << ") failed." << endl; |
298 delete plugin; | 305 delete plugin; |
299 return false; | 306 return false; |
300 } | 307 } |
301 | 308 |
302 // cerr << "Initialised plugin" << endl; | 309 SVDEBUG << "Initialised plugin" << endl; |
303 | 310 |
304 size_t actualStepSize = 0; | 311 size_t actualStepSize = 0; |
305 size_t actualBlockSize = 0; | 312 size_t actualBlockSize = 0; |
306 pba->getActualStepAndBlockSizes(actualStepSize, actualBlockSize); | 313 pba->getActualStepAndBlockSizes(actualStepSize, actualBlockSize); |
307 transform.setStepSize(actualStepSize); | 314 transform.setStepSize(actualStepSize); |
308 transform.setBlockSize(actualBlockSize); | 315 transform.setBlockSize(actualBlockSize); |
309 | 316 |
310 Plugin::OutputList outputs = plugin->getOutputDescriptors(); | 317 Plugin::OutputList outputs = plugin->getOutputDescriptors(); |
311 for (int i = 0; i < (int)outputs.size(); ++i) { | 318 for (int i = 0; i < (int)outputs.size(); ++i) { |
312 | 319 |
313 // cerr << "Newly initialised plugin output " << i << " has bin count " << outputs[i].binCount << endl; | 320 SVDEBUG << "Newly initialised plugin output " << i << " has bin count " << outputs[i].binCount << endl; |
314 | 321 |
315 m_pluginOutputs[plugin][outputs[i].identifier] = outputs[i]; | 322 m_pluginOutputs[plugin][outputs[i].identifier] = outputs[i]; |
316 m_pluginOutputIndices[outputs[i].identifier] = i; | 323 m_pluginOutputIndices[outputs[i].identifier] = i; |
317 } | 324 } |
318 | 325 |
319 cerr << "NOTE: Loaded and initialised plugin for transform \"" | 326 SVCERR << "NOTE: Loaded and initialised plugin for transform \"" |
320 << transform.getIdentifier().toStdString() | 327 << transform.getIdentifier().toStdString() |
321 << "\" with plugin step size " << actualStepSize | 328 << "\" with plugin step size " << actualStepSize |
322 << " and block size " << actualBlockSize | 329 << " and block size " << actualBlockSize |
323 << " (adapter step and block size " << m_blockSize << ")" | 330 << " (adapter step and block size " << m_blockSize << ")" |
324 << endl; | 331 << endl; |
325 | 332 |
326 // cerr << "NOTE: That transform is: " << transform.toXmlString() << endl; | 333 SVDEBUG << "NOTE: That transform is: " << transform.toXmlString() << endl; |
327 | 334 |
328 if (pida) { | 335 if (pida) { |
329 cerr << "NOTE: PluginInputDomainAdapter timestamp adjustment is " | 336 SVCERR << "NOTE: PluginInputDomainAdapter timestamp adjustment is " |
330 | |
331 << pida->getTimestampAdjustment() << endl; | 337 << pida->getTimestampAdjustment() << endl; |
332 } | 338 } |
333 | 339 |
334 } else { | 340 } else { |
335 | 341 |
356 } | 362 } |
357 | 363 |
358 if (transform.getPluginVersion() != "") { | 364 if (transform.getPluginVersion() != "") { |
359 if (QString("%1").arg(plugin->getPluginVersion()) | 365 if (QString("%1").arg(plugin->getPluginVersion()) |
360 != transform.getPluginVersion()) { | 366 != transform.getPluginVersion()) { |
361 cerr << "ERROR: Transform specifies version " | 367 SVCERR << "ERROR: Transform specifies version " |
362 << transform.getPluginVersion() | 368 << transform.getPluginVersion() |
363 << " of plugin \"" << plugin->getIdentifier() | 369 << " of plugin \"" << plugin->getIdentifier() |
364 << "\", but installed plugin is version " | 370 << "\", but installed plugin is version " |
365 << plugin->getPluginVersion() | 371 << plugin->getPluginVersion() |
366 << endl; | 372 << endl; |
373 (plugin->getOutputDescriptors()[0].identifier.c_str()); | 379 (plugin->getOutputDescriptors()[0].identifier.c_str()); |
374 } else { | 380 } else { |
375 if (m_pluginOutputs[plugin].find | 381 if (m_pluginOutputs[plugin].find |
376 (transform.getOutput().toLocal8Bit().data()) == | 382 (transform.getOutput().toLocal8Bit().data()) == |
377 m_pluginOutputs[plugin].end()) { | 383 m_pluginOutputs[plugin].end()) { |
378 cerr << "ERROR: Transform requests nonexistent plugin output \"" | 384 SVCERR << "ERROR: Transform requests nonexistent plugin output \"" |
379 << transform.getOutput() | 385 << transform.getOutput() |
380 << "\"" << endl; | 386 << "\"" << endl; |
381 return false; | 387 return false; |
382 } | 388 } |
383 } | 389 } |
384 | 390 |
385 m_transformPluginMap[transform] = plugin; | 391 m_transformPluginMap[transform] = plugin; |
386 | 392 |
387 // cerr << "NOTE: Assigned plugin " << plugin << " for transform: " << transform.toXmlString() << endl; | 393 SVDEBUG << "NOTE: Assigned plugin " << plugin << " for transform: " << transform.toXmlString() << endl; |
388 | 394 |
389 if (!(originalTransform == transform)) { | 395 if (!(originalTransform == transform)) { |
390 m_transformPluginMap[originalTransform] = plugin; | 396 m_transformPluginMap[originalTransform] = plugin; |
391 // cerr << "NOTE: Also assigned plugin " << plugin << " for original transform: " << originalTransform.toXmlString() << endl; | 397 SVDEBUG << "NOTE: Also assigned plugin " << plugin << " for original transform: " << originalTransform.toXmlString() << endl; |
392 } | 398 } |
393 | 399 |
394 } else { | 400 } else { |
395 | 401 |
396 plugin = m_transformPluginMap[transform]; | 402 plugin = m_transformPluginMap[transform]; |
410 { | 416 { |
411 TransformFactory *tf = TransformFactory::getInstance(); | 417 TransformFactory *tf = TransformFactory::getInstance(); |
412 | 418 |
413 if (m_sampleRate == 0) { | 419 if (m_sampleRate == 0) { |
414 if (m_defaultSampleRate == 0) { | 420 if (m_defaultSampleRate == 0) { |
415 cerr << "ERROR: Default transform requested, but no default sample rate available" << endl; | 421 SVCERR << "ERROR: Default transform requested, but no default sample rate available" << endl; |
416 return false; | 422 return false; |
417 } else { | 423 } else { |
418 cerr << "NOTE: Using default sample rate of " << m_defaultSampleRate << " for default transform" << endl; | 424 SVCERR << "NOTE: Using default sample rate of " << m_defaultSampleRate << " for default transform" << endl; |
419 m_sampleRate = m_defaultSampleRate; | 425 m_sampleRate = m_defaultSampleRate; |
420 } | 426 } |
421 } | 427 } |
422 | 428 |
423 Transform transform = tf->getDefaultTransformFor(transformId, m_sampleRate); | 429 Transform transform = tf->getDefaultTransformFor(transformId, m_sampleRate); |
424 | 430 |
425 bool result = addFeatureExtractor(transform, writers); | 431 bool result = addFeatureExtractor(transform, writers); |
426 if (!result) { | 432 if (!result) { |
427 if (transform.getType() == Transform::UnknownType) { | 433 if (transform.getType() == Transform::UnknownType) { |
428 cerr << "(Maybe mixed up filename with transform, or --transform with --default?)" << endl; | 434 SVCERR << "(Maybe mixed up filename with transform, or --transform with --default?)" << endl; |
429 } | 435 } |
430 } | 436 } |
431 return result; | 437 return result; |
432 } | 438 } |
433 | 439 |
452 // We don't actually need to open this here yet, we just hoist | 458 // We don't actually need to open this here yet, we just hoist |
453 // it to the top for error reporting purposes | 459 // it to the top for error reporting purposes |
454 QFile file(transformFile); | 460 QFile file(transformFile); |
455 if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { | 461 if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { |
456 // Error case 1. File does not exist or cannot be opened | 462 // Error case 1. File does not exist or cannot be opened |
457 cerr << "ERROR: Failed to open transform file \"" << transformFile | 463 SVCERR << "ERROR: Failed to open transform file \"" << transformFile |
458 << "\" for reading" << endl; | 464 << "\" for reading" << endl; |
459 return false; | 465 return false; |
460 } | 466 } |
461 } | 467 } |
462 | 468 |
482 | 488 |
483 RDFTransformFactory factory | 489 RDFTransformFactory factory |
484 (QUrl::fromLocalFile(QFileInfo(transformFile).absoluteFilePath()) | 490 (QUrl::fromLocalFile(QFileInfo(transformFile).absoluteFilePath()) |
485 .toString()); | 491 .toString()); |
486 ProgressPrinter printer("Parsing transforms RDF file"); | 492 ProgressPrinter printer("Parsing transforms RDF file"); |
487 std::vector<Transform> transforms = factory.getTransforms(&printer); | 493 std::vector<Transform> transforms = factory.getTransforms |
494 (m_verbose ? &printer : 0); | |
488 | 495 |
489 if (factory.isOK()) { | 496 if (factory.isOK()) { |
490 if (transforms.empty()) { | 497 if (transforms.empty()) { |
491 cerr << "ERROR: Transform file \"" << transformFile | 498 SVCERR << "ERROR: Transform file \"" << transformFile |
492 << "\" is valid RDF but defines no transforms" << endl; | 499 << "\" is valid RDF but defines no transforms" << endl; |
493 return false; | 500 return false; |
494 } else { | 501 } else { |
495 bool success = true; | 502 bool success = true; |
496 for (int i = 0; i < (int)transforms.size(); ++i) { | 503 for (int i = 0; i < (int)transforms.size(); ++i) { |
500 } | 507 } |
501 return success; | 508 return success; |
502 } | 509 } |
503 } else { // !factory.isOK() | 510 } else { // !factory.isOK() |
504 if (factory.isRDF()) { | 511 if (factory.isRDF()) { |
505 cerr << "ERROR: Invalid transform RDF file \"" << transformFile | 512 SVCERR << "ERROR: Invalid transform RDF file \"" << transformFile |
506 << "\": " << factory.getErrorString() << endl; | 513 << "\": " << factory.getErrorString() << endl; |
507 return false; | 514 return false; |
508 } | 515 } |
509 | 516 |
510 // the not-RDF case: fall through without reporting an | 517 // the not-RDF case: fall through without reporting an |
516 | 523 |
517 if (tryXml) { | 524 if (tryXml) { |
518 | 525 |
519 QFile file(transformFile); | 526 QFile file(transformFile); |
520 if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { | 527 if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { |
521 cerr << "ERROR: Failed to open transform file \"" | 528 SVCERR << "ERROR: Failed to open transform file \"" |
522 << transformFile.toStdString() << "\" for reading" << endl; | 529 << transformFile.toStdString() << "\" for reading" << endl; |
523 return false; | 530 return false; |
524 } | 531 } |
525 | 532 |
526 QTextStream *qts = new QTextStream(&file); | 533 QTextStream *qts = new QTextStream(&file); |
532 xmlError = transform.getErrorString(); | 539 xmlError = transform.getErrorString(); |
533 | 540 |
534 if (xmlError == "") { | 541 if (xmlError == "") { |
535 | 542 |
536 if (transform.getIdentifier() == "") { | 543 if (transform.getIdentifier() == "") { |
537 cerr << "ERROR: Transform file \"" << transformFile | 544 SVCERR << "ERROR: Transform file \"" << transformFile |
538 << "\" is valid XML but defines no transform" << endl; | 545 << "\" is valid XML but defines no transform" << endl; |
539 return false; | 546 return false; |
540 } | 547 } |
541 | 548 |
542 return addFeatureExtractor(transform, writers); | 549 return addFeatureExtractor(transform, writers); |
543 } | 550 } |
544 } | 551 } |
545 | 552 |
546 cerr << "ERROR: Transform file \"" << transformFile | 553 SVCERR << "ERROR: Transform file \"" << transformFile |
547 << "\" could not be parsed" << endl; | 554 << "\" could not be parsed" << endl; |
548 if (rdfError != "") { | 555 if (rdfError != "") { |
549 cerr << "ERROR: RDF parser reported: " << rdfError << endl; | 556 SVCERR << "ERROR: RDF parser reported: " << rdfError << endl; |
550 } | 557 } |
551 if (xmlError != "") { | 558 if (xmlError != "") { |
552 cerr << "ERROR: XML parser reported: " << xmlError << endl; | 559 SVCERR << "ERROR: XML parser reported: " << xmlError << endl; |
553 } | 560 } |
554 | 561 |
555 return false; | 562 return false; |
556 } | 563 } |
557 | 564 |
558 void FeatureExtractionManager::addSource(QString audioSource, bool willMultiplex) | 565 void FeatureExtractionManager::addSource(QString audioSource, bool willMultiplex) |
559 { | 566 { |
560 std::cerr << "Have audio source: \"" << audioSource.toStdString() << "\"" << std::endl; | 567 SVCERR << "Have audio source: \"" << audioSource.toStdString() << "\"" << endl; |
561 | 568 |
562 // We don't actually do anything with it here, unless it's the | 569 // We don't actually do anything with it here, unless it's the |
563 // first audio source and we need it to establish default channel | 570 // first audio source and we need it to establish default channel |
564 // count and sample rate | 571 // count and sample rate |
565 | 572 |
566 if (m_channels == 0 || m_defaultSampleRate == 0) { | 573 if (m_channels == 0 || m_defaultSampleRate == 0) { |
567 | 574 |
568 ProgressPrinter retrievalProgress("Retrieving first input file to determine default rate and channel count..."); | 575 ProgressPrinter retrievalProgress("Retrieving first input file to determine default rate and channel count..."); |
569 | 576 |
570 FileSource source(audioSource, &retrievalProgress); | 577 FileSource source(audioSource, m_verbose ? &retrievalProgress : 0); |
571 if (!source.isAvailable()) { | 578 if (!source.isAvailable()) { |
572 cerr << "ERROR: File or URL \"" << audioSource.toStdString() | 579 SVCERR << "ERROR: File or URL \"" << audioSource.toStdString() |
573 << "\" could not be located"; | 580 << "\" could not be located"; |
574 if (source.getErrorString() != "") { | 581 if (source.getErrorString() != "") { |
575 cerr << ": " << source.getErrorString(); | 582 SVCERR << ": " << source.getErrorString(); |
576 } | 583 } |
577 cerr << endl; | 584 SVCERR << endl; |
578 throw FileNotFound(audioSource); | 585 throw FileNotFound(audioSource); |
579 } | 586 } |
580 | 587 |
581 source.waitForData(); | 588 source.waitForData(); |
582 | 589 |
583 // Open to determine validity, channel count, sample rate only | 590 // Open to determine validity, channel count, sample rate only |
584 // (then close, and open again later with actual desired rate &c) | 591 // (then close, and open again later with actual desired rate &c) |
585 | 592 |
593 AudioFileReaderFactory::Parameters params; | |
594 params.normalisation = (m_normalise ? | |
595 AudioFileReaderFactory::Normalisation::Peak : | |
596 AudioFileReaderFactory::Normalisation::None); | |
597 | |
586 AudioFileReader *reader = | 598 AudioFileReader *reader = |
587 AudioFileReaderFactory::createReader(source, 0, | 599 AudioFileReaderFactory::createReader |
588 m_normalise, | 600 (source, params, m_verbose ? &retrievalProgress : 0); |
589 &retrievalProgress); | |
590 | 601 |
591 if (!reader) { | 602 if (!reader) { |
592 throw FailedToOpenFile(audioSource); | 603 throw FailedToOpenFile(audioSource); |
593 } | 604 } |
594 | 605 |
595 retrievalProgress.done(); | 606 if (m_verbose) retrievalProgress.done(); |
596 | 607 |
597 cerr << "File or URL \"" << audioSource.toStdString() << "\" opened successfully" << endl; | 608 SVCERR << "File or URL \"" << audioSource.toStdString() << "\" opened successfully" << endl; |
598 | 609 |
599 if (!willMultiplex) { | 610 if (!willMultiplex) { |
600 if (m_channels == 0) { | 611 if (m_channels == 0) { |
601 m_channels = reader->getChannelCount(); | 612 m_channels = reader->getChannelCount(); |
602 cerr << "Taking default channel count of " | 613 SVCERR << "Taking default channel count of " |
603 << reader->getChannelCount() << " from audio file" << endl; | 614 << reader->getChannelCount() << " from audio file" << endl; |
604 } | 615 } |
605 } | 616 } |
606 | 617 |
607 if (m_defaultSampleRate == 0) { | 618 if (m_defaultSampleRate == 0) { |
608 m_defaultSampleRate = reader->getNativeRate(); | 619 m_defaultSampleRate = reader->getNativeRate(); |
609 cerr << "Taking default sample rate of " | 620 SVCERR << "Taking default sample rate of " |
610 << reader->getNativeRate() << "Hz from audio file" << endl; | 621 << reader->getNativeRate() << "Hz from audio file" << endl; |
611 cerr << "(Note: Default may be overridden by transforms)" << endl; | 622 SVCERR << "(Note: Default may be overridden by transforms)" << endl; |
612 } | 623 } |
613 | 624 |
614 m_readyReaders[audioSource] = reader; | 625 m_readyReaders[audioSource] = reader; |
615 } | 626 } |
616 | 627 |
617 if (willMultiplex) { | 628 if (willMultiplex) { |
618 ++m_channels; // channel count is simply number of sources | 629 ++m_channels; // channel count is simply number of sources |
619 cerr << "Multiplexing, incremented target channel count to " | 630 SVCERR << "Multiplexing, incremented target channel count to " |
620 << m_channels << endl; | 631 << m_channels << endl; |
621 } | 632 } |
622 } | 633 } |
623 | 634 |
624 void FeatureExtractionManager::extractFeatures(QString audioSource) | 635 void FeatureExtractionManager::extractFeatures(QString audioSource) |
678 // can't use this; open it again | 689 // can't use this; open it again |
679 delete reader; | 690 delete reader; |
680 reader = 0; | 691 reader = 0; |
681 } | 692 } |
682 } | 693 } |
694 | |
683 if (!reader) { | 695 if (!reader) { |
684 ProgressPrinter retrievalProgress("Retrieving audio data..."); | 696 ProgressPrinter retrievalProgress("Retrieving audio data..."); |
685 FileSource fs(source, &retrievalProgress); | 697 FileSource fs(source, m_verbose ? &retrievalProgress : 0); |
686 fs.waitForData(); | 698 fs.waitForData(); |
687 reader = AudioFileReaderFactory::createReader(fs, m_sampleRate, | 699 |
688 m_normalise, | 700 AudioFileReaderFactory::Parameters params; |
689 &retrievalProgress); | 701 params.targetRate = m_sampleRate; |
690 retrievalProgress.done(); | 702 params.normalisation = (m_normalise ? |
691 } | 703 AudioFileReaderFactory::Normalisation::Peak : |
704 AudioFileReaderFactory::Normalisation::None); | |
705 | |
706 reader = AudioFileReaderFactory::createReader | |
707 (fs, params, m_verbose ? &retrievalProgress : 0); | |
708 if (m_verbose) retrievalProgress.done(); | |
709 } | |
710 | |
692 if (!reader) { | 711 if (!reader) { |
693 throw FailedToOpenFile(source); | 712 throw FailedToOpenFile(source); |
694 } | 713 } |
695 if (reader->getChannelCount() != m_channels || | 714 if (reader->getChannelCount() != m_channels || |
696 reader->getNativeRate() != m_sampleRate) { | 715 reader->getNativeRate() != m_sampleRate) { |
697 cerr << "NOTE: File will be mixed or resampled for processing, to: " | 716 SVCERR << "NOTE: File will be mixed or resampled for processing, to: " |
698 << m_channels << "ch at " | 717 << m_channels << "ch at " |
699 << m_sampleRate << "Hz" << endl; | 718 << m_sampleRate << "Hz" << endl; |
700 } | 719 } |
701 return reader; | 720 return reader; |
702 } | 721 } |
705 FeatureExtractionManager::extractFeaturesFor(AudioFileReader *reader, | 724 FeatureExtractionManager::extractFeaturesFor(AudioFileReader *reader, |
706 QString audioSource) | 725 QString audioSource) |
707 { | 726 { |
708 // Note: This also deletes reader | 727 // Note: This also deletes reader |
709 | 728 |
710 cerr << "Audio file \"" << audioSource.toStdString() << "\": " | 729 SVCERR << "Audio file \"" << audioSource.toStdString() << "\": " |
711 << reader->getChannelCount() << "ch at " | 730 << reader->getChannelCount() << "ch at " |
712 << reader->getNativeRate() << "Hz" << endl; | 731 << reader->getNativeRate() << "Hz" << endl; |
713 | 732 |
714 // allocate audio buffers | 733 // allocate audio buffers |
715 float **data = new float *[m_channels]; | 734 float **data = new float *[m_channels]; |
735 }; | 754 }; |
736 LifespanMgr lifemgr(reader, m_channels, data); | 755 LifespanMgr lifemgr(reader, m_channels, data); |
737 | 756 |
738 size_t frameCount = reader->getFrameCount(); | 757 size_t frameCount = reader->getFrameCount(); |
739 | 758 |
740 // cerr << "file has " << frameCount << " frames" << endl; | 759 SVDEBUG << "FeatureExtractionManager: file has " << frameCount << " frames" << endl; |
741 | 760 |
742 int earliestStartFrame = 0; | 761 int earliestStartFrame = 0; |
743 int latestEndFrame = frameCount; | 762 int latestEndFrame = frameCount; |
744 bool haveExtents = false; | 763 bool haveExtents = false; |
745 | 764 |
746 foreach (Plugin *plugin, m_orderedPlugins) { | 765 foreach (Plugin *plugin, m_orderedPlugins) { |
747 | 766 |
748 PluginMap::iterator pi = m_plugins.find(plugin); | 767 PluginMap::iterator pi = m_plugins.find(plugin); |
749 | 768 |
750 // std::cerr << "Calling reset on " << plugin << std::endl; | 769 SVDEBUG << "FeatureExtractionManager: Calling reset on " << plugin << endl; |
751 plugin->reset(); | 770 plugin->reset(); |
752 | 771 |
753 for (TransformWriterMap::iterator ti = pi->second.begin(); | 772 for (TransformWriterMap::iterator ti = pi->second.begin(); |
754 ti != pi->second.end(); ++ti) { | 773 ti != pi->second.end(); ++ti) { |
755 | 774 |
767 earliestStartFrame = startFrame; | 786 earliestStartFrame = startFrame; |
768 } | 787 } |
769 if (!haveExtents || startFrame + duration > latestEndFrame) { | 788 if (!haveExtents || startFrame + duration > latestEndFrame) { |
770 latestEndFrame = startFrame + duration; | 789 latestEndFrame = startFrame + duration; |
771 } | 790 } |
791 | |
772 /* | 792 /* |
773 cerr << "startFrame for transform " << startFrame << endl; | 793 SVDEBUG << "startFrame for transform " << startFrame << endl; |
774 cerr << "duration for transform " << duration << endl; | 794 SVDEBUG << "duration for transform " << duration << endl; |
775 cerr << "earliestStartFrame becomes " << earliestStartFrame << endl; | 795 SVDEBUG << "earliestStartFrame becomes " << earliestStartFrame << endl; |
776 cerr << "latestEndFrame becomes " << latestEndFrame << endl; | 796 SVDEBUG << "latestEndFrame becomes " << latestEndFrame << endl; |
777 */ | 797 */ |
778 haveExtents = true; | 798 haveExtents = true; |
779 | 799 |
780 string outputId = transform.getOutput().toStdString(); | 800 string outputId = transform.getOutput().toStdString(); |
781 if (m_pluginOutputs[plugin].find(outputId) == | 801 if (m_pluginOutputs[plugin].find(outputId) == |
782 m_pluginOutputs[plugin].end()) { | 802 m_pluginOutputs[plugin].end()) { |
783 // We shouldn't actually reach this point: | 803 // We shouldn't actually reach this point: |
784 // addFeatureExtractor tests whether the output exists | 804 // addFeatureExtractor tests whether the output exists |
785 cerr << "ERROR: Nonexistent plugin output \"" << outputId << "\" requested for transform \"" | 805 SVCERR << "ERROR: Nonexistent plugin output \"" << outputId << "\" requested for transform \"" |
786 << transform.getIdentifier().toStdString() << "\", ignoring this transform" | 806 << transform.getIdentifier().toStdString() << "\", ignoring this transform" |
787 << endl; | 807 << endl; |
788 /* | 808 |
789 cerr << "Known outputs for all plugins are as follows:" << endl; | 809 SVDEBUG << "Known outputs for all plugins are as follows:" << endl; |
790 for (PluginOutputMap::const_iterator k = m_pluginOutputs.begin(); | 810 for (PluginOutputMap::const_iterator k = m_pluginOutputs.begin(); |
791 k != m_pluginOutputs.end(); ++k) { | 811 k != m_pluginOutputs.end(); ++k) { |
792 cerr << "Plugin " << k->first << ": "; | 812 SVDEBUG << "Plugin " << k->first << ": "; |
793 if (k->second.empty()) { | 813 if (k->second.empty()) { |
794 cerr << "(none)"; | 814 SVDEBUG << "(none)"; |
795 } | 815 } |
796 for (OutputMap::const_iterator i = k->second.begin(); | 816 for (OutputMap::const_iterator i = k->second.begin(); |
797 i != k->second.end(); ++i) { | 817 i != k->second.end(); ++i) { |
798 cerr << "\"" << i->first << "\" "; | 818 SVDEBUG << "\"" << i->first << "\" "; |
799 } | 819 } |
800 cerr << endl; | 820 SVDEBUG << endl; |
801 } | 821 } |
802 */ | |
803 } | 822 } |
804 } | 823 } |
805 } | 824 } |
806 | 825 |
807 int startFrame = earliestStartFrame; | 826 int startFrame = earliestStartFrame; |
833 for (int i = startFrame; i < endFrame; i += m_blockSize) { | 852 for (int i = startFrame; i < endFrame; i += m_blockSize) { |
834 | 853 |
835 //!!! inefficient, although much of the inefficiency may be | 854 //!!! inefficient, although much of the inefficiency may be |
836 // susceptible to compiler optimisation | 855 // susceptible to compiler optimisation |
837 | 856 |
838 SampleBlock frames = reader->getInterleavedFrames(i, m_blockSize); | 857 auto frames = reader->getInterleavedFrames(i, m_blockSize); |
839 | 858 |
840 // We have to do our own channel handling here; we can't just | 859 // We have to do our own channel handling here; we can't just |
841 // leave it to the plugin adapter because the same plugin | 860 // leave it to the plugin adapter because the same plugin |
842 // adapter may have to serve for input files with various | 861 // adapter may have to serve for input files with various |
843 // numbers of channels (so the adapter is simply configured | 862 // numbers of channels (so the adapter is simply configured |
909 } | 928 } |
910 } | 929 } |
911 | 930 |
912 int pp = progress; | 931 int pp = progress; |
913 progress = int(((i - startFrame) * 100.0) / (endFrame - startFrame) + 0.1); | 932 progress = int(((i - startFrame) * 100.0) / (endFrame - startFrame) + 0.1); |
914 if (progress > pp) extractionProgress.setProgress(progress); | 933 if (progress > pp && m_verbose) extractionProgress.setProgress(progress); |
915 } | 934 } |
916 | 935 |
917 // std::cerr << "FeatureExtractionManager: deleting audio file reader" << std::endl; | 936 SVDEBUG << "FeatureExtractionManager: deleting audio file reader" << endl; |
918 | 937 |
919 lifemgr.destroy(); // deletes reader, data | 938 lifemgr.destroy(); // deletes reader, data |
920 | 939 |
921 foreach (Plugin *plugin, m_orderedPlugins) { | 940 foreach (Plugin *plugin, m_orderedPlugins) { |
922 | 941 |
930 if (!m_summaries.empty()) { | 949 if (!m_summaries.empty()) { |
931 // Summaries requested on the command line, for all transforms | 950 // Summaries requested on the command line, for all transforms |
932 PluginSummarisingAdapter *adapter = | 951 PluginSummarisingAdapter *adapter = |
933 dynamic_cast<PluginSummarisingAdapter *>(plugin); | 952 dynamic_cast<PluginSummarisingAdapter *>(plugin); |
934 if (!adapter) { | 953 if (!adapter) { |
935 cerr << "WARNING: Summaries requested, but plugin is not a summarising adapter" << endl; | 954 SVCERR << "WARNING: Summaries requested, but plugin is not a summarising adapter" << endl; |
936 } else { | 955 } else { |
937 for (SummaryNameSet::const_iterator sni = m_summaries.begin(); | 956 for (SummaryNameSet::const_iterator sni = m_summaries.begin(); |
938 sni != m_summaries.end(); ++sni) { | 957 sni != m_summaries.end(); ++sni) { |
939 featureSet.clear(); | 958 featureSet.clear(); |
940 //!!! problem here -- we are requesting summaries | 959 //!!! problem here -- we are requesting summaries |
953 | 972 |
954 // Summaries specified in transform definitions themselves | 973 // Summaries specified in transform definitions themselves |
955 writeSummaries(audioSource, plugin); | 974 writeSummaries(audioSource, plugin); |
956 } | 975 } |
957 | 976 |
958 extractionProgress.done(); | 977 if (m_verbose) extractionProgress.done(); |
959 | 978 |
960 finish(); | 979 finish(); |
961 | 980 |
962 TempDirectory::getInstance()->cleanup(); | 981 TempDirectory::getInstance()->cleanup(); |
963 } | 982 } |
971 for (TransformWriterMap::const_iterator ti = pi->second.begin(); | 990 for (TransformWriterMap::const_iterator ti = pi->second.begin(); |
972 ti != pi->second.end(); ++ti) { | 991 ti != pi->second.end(); ++ti) { |
973 | 992 |
974 const Transform &transform = ti->first; | 993 const Transform &transform = ti->first; |
975 | 994 |
976 // cerr << "FeatureExtractionManager::writeSummaries: plugin is " << plugin | 995 SVDEBUG << "FeatureExtractionManager::writeSummaries: plugin is " << plugin |
977 // << ", found transform: " << transform.toXmlString() << endl; | 996 << ", found transform: " << transform.toXmlString() << endl; |
978 | 997 |
979 Transform::SummaryType summaryType = transform.getSummaryType(); | 998 Transform::SummaryType summaryType = transform.getSummaryType(); |
980 PluginSummarisingAdapter::SummaryType pType = | 999 PluginSummarisingAdapter::SummaryType pType = |
981 (PluginSummarisingAdapter::SummaryType)summaryType; | 1000 (PluginSummarisingAdapter::SummaryType)summaryType; |
982 | 1001 |
983 if (transform.getSummaryType() == Transform::NoSummary) { | 1002 if (transform.getSummaryType() == Transform::NoSummary) { |
984 // cerr << "(no summary, continuing)" << endl; | 1003 SVDEBUG << "FeatureExtractionManager::writeSummaries: no summary for this transform" << endl; |
985 continue; | 1004 continue; |
986 } | 1005 } |
987 | 1006 |
988 PluginSummarisingAdapter *adapter = | 1007 PluginSummarisingAdapter *adapter = |
989 dynamic_cast<PluginSummarisingAdapter *>(plugin); | 1008 dynamic_cast<PluginSummarisingAdapter *>(plugin); |
990 if (!adapter) { | 1009 if (!adapter) { |
991 cerr << "FeatureExtractionManager::writeSummaries: INTERNAL ERROR: Summary requested for transform, but plugin is not a summarising adapter" << endl; | 1010 SVCERR << "FeatureExtractionManager::writeSummaries: INTERNAL ERROR: Summary requested for transform, but plugin is not a summarising adapter" << endl; |
992 continue; | 1011 continue; |
993 } | 1012 } |
994 | 1013 |
995 Plugin::FeatureSet featureSet = adapter->getSummaryForAllOutputs | 1014 Plugin::FeatureSet featureSet = adapter->getSummaryForAllOutputs |
996 (pType, PluginSummarisingAdapter::ContinuousTimeAverage); | 1015 (pType, PluginSummarisingAdapter::ContinuousTimeAverage); |
997 | 1016 |
998 // cerr << "summary type " << int(pType) << " for transform:" << endl << transform.toXmlString().toStdString()<< endl << "... feature set with " << featureSet.size() << " elts" << endl; | 1017 SVDEBUG << "summary type " << int(pType) << " for transform:" << endl << transform.toXmlString().toStdString()<< endl << "... feature set with " << featureSet.size() << " elts" << endl; |
999 | 1018 |
1000 writeFeatures(audioSource, plugin, featureSet, summaryType); | 1019 writeFeatures(audioSource, plugin, featureSet, summaryType); |
1001 } | 1020 } |
1002 } | 1021 } |
1003 | 1022 |
1016 ti != pi->second.end(); ++ti) { | 1035 ti != pi->second.end(); ++ti) { |
1017 | 1036 |
1018 const Transform &transform = ti->first; | 1037 const Transform &transform = ti->first; |
1019 const vector<FeatureWriter *> &writers = ti->second; | 1038 const vector<FeatureWriter *> &writers = ti->second; |
1020 | 1039 |
1021 // cerr << "writeFeatures: plugin " << plugin << " has transform: " << transform.toXmlString() << endl; | 1040 // SVDEBUG << "writeFeatures: plugin " << plugin << " has transform: " << transform.toXmlString() << endl; |
1022 | 1041 |
1023 if (transform.getSummaryType() == Transform::NoSummary && | 1042 if (transform.getSummaryType() == Transform::NoSummary && |
1024 !m_summaries.empty()) { | 1043 !m_summaries.empty()) { |
1025 // cerr << "transform has no summary, but summaries requested on command line, so going for it anyway" << endl; | 1044 SVDEBUG << "writeFeatures: transform has no summary, but summaries requested on command line, so going for it anyway" << endl; |
1026 } else if (transform.getSummaryType() != summaryType) { | 1045 } else if (transform.getSummaryType() != summaryType) { |
1027 // Either we're not writing a summary and the transform | 1046 // Either we're not writing a summary and the transform |
1028 // has one, or we're writing a summary but the transform | 1047 // has one, or we're writing a summary but the transform |
1029 // has none or a different one; either way, skip it | 1048 // has none or a different one; either way, skip it |
1030 // cerr << "summary type differs from passed-in one " << summaryType << endl; | 1049 SVDEBUG << "writeFeatures: transform summary type " << transform.getSummaryType() << " differs from passed-in one " << summaryType << ", skipping" << endl; |
1031 continue; | 1050 continue; |
1032 } | 1051 } |
1033 | 1052 |
1034 string outputId = transform.getOutput().toStdString(); | 1053 string outputId = transform.getOutput().toStdString(); |
1035 | 1054 |
1043 | 1062 |
1044 int outputIndex = m_pluginOutputIndices[outputId]; | 1063 int outputIndex = m_pluginOutputIndices[outputId]; |
1045 Plugin::FeatureSet::const_iterator fsi = features.find(outputIndex); | 1064 Plugin::FeatureSet::const_iterator fsi = features.find(outputIndex); |
1046 if (fsi == features.end()) continue; | 1065 if (fsi == features.end()) continue; |
1047 | 1066 |
1048 // cerr << "this transform has " << writers.size() << " writer(s)" << endl; | 1067 // SVDEBUG << "this transform has " << writers.size() << " writer(s)" << endl; |
1049 | 1068 |
1050 for (int j = 0; j < (int)writers.size(); ++j) { | 1069 for (int j = 0; j < (int)writers.size(); ++j) { |
1051 writers[j]->write | 1070 writers[j]->write |
1052 (audioSource, transform, desc, fsi->second, | 1071 (audioSource, transform, desc, fsi->second, |
1053 Transform::summaryTypeToString(summaryType).toStdString()); | 1072 Transform::summaryTypeToString(summaryType).toStdString()); |