comparison runner/FeatureExtractionManager.cpp @ 45:69c438d4b9d3

* Pick up default sample rate and channel count from first audio file (formerly they were hardcoded to 44100 and 1...)
author Chris Cannam
date Mon, 18 Oct 2010 14:17:48 +0100
parents 76ea8ffc4dfa
children 4d07f61dba3f
comparison
equal deleted inserted replaced
44:aa521baace07 45:69c438d4b9d3
57 // PluginBufferingAdapter handles this for us. It's likely to be 57 // PluginBufferingAdapter handles this for us. It's likely to be
58 // quicker to use larger sizes than smallish ones like 1024 58 // quicker to use larger sizes than smallish ones like 1024
59 m_blockSize(16384), 59 m_blockSize(16384),
60 m_defaultSampleRate(0), 60 m_defaultSampleRate(0),
61 m_sampleRate(0), 61 m_sampleRate(0),
62 m_channels(1) 62 m_channels(0)
63 { 63 {
64 } 64 }
65 65
66 FeatureExtractionManager::~FeatureExtractionManager() 66 FeatureExtractionManager::~FeatureExtractionManager()
67 { 67 {
68 for (PluginMap::iterator pi = m_plugins.begin(); 68 for (PluginMap::iterator pi = m_plugins.begin();
69 pi != m_plugins.end(); ++pi) { 69 pi != m_plugins.end(); ++pi) {
70 delete pi->first; 70 delete pi->first;
71 }
72 foreach (AudioFileReader *r, m_readyReaders) {
73 delete r;
71 } 74 }
72 } 75 }
73 76
74 void FeatureExtractionManager::setChannels(int channels) 77 void FeatureExtractionManager::setChannels(int channels)
75 { 78 {
377 Transform transform(qs); 380 Transform transform(qs);
378 381
379 return addFeatureExtractor(transform, writers); 382 return addFeatureExtractor(transform, writers);
380 } 383 }
381 384
382 void FeatureExtractionManager::extractFeatures(QString audioSource) 385 void FeatureExtractionManager::addSource(QString audioSource)
383 { 386 {
384 if (m_plugins.empty()) return;
385
386 testOutputFiles(audioSource);
387
388 ProgressPrinter retrievalProgress("Retrieving audio data...");
389
390 FileSource source(audioSource, &retrievalProgress);
391 if (!source.isAvailable()) {
392 cerr << "ERROR: File or URL \"" << audioSource.toStdString()
393 << "\" could not be located" << endl;
394 throw FileNotFound(audioSource);
395 }
396
397 source.waitForData();
398
399 if (QFileInfo(audioSource).suffix().toLower() == "m3u") { 387 if (QFileInfo(audioSource).suffix().toLower() == "m3u") {
388 ProgressPrinter retrievalProgress("Opening playlist file...");
389 FileSource source(audioSource, &retrievalProgress);
390 if (!source.isAvailable()) {
391 cerr << "ERROR: File or URL \"" << audioSource.toStdString()
392 << "\" could not be located" << endl;
393 throw FileNotFound(audioSource);
394 }
395 source.waitForData();
400 PlaylistFileReader reader(source); 396 PlaylistFileReader reader(source);
401 if (reader.isOK()) { 397 if (reader.isOK()) {
402 vector<QString> files = reader.load(); 398 vector<QString> files = reader.load();
403 for (int i = 0; i < (int)files.size(); ++i) { 399 for (int i = 0; i < (int)files.size(); ++i) {
404 extractFeatures(files[i]); 400 addSource(files[i]);
405 } 401 }
406 return; 402 return;
407 } else { 403 } else {
408 cerr << "ERROR: Playlist \"" << audioSource.toStdString() 404 cerr << "ERROR: Playlist \"" << audioSource.toStdString()
409 << "\" could not be opened" << endl; 405 << "\" could not be opened" << endl;
410 throw FileNotFound(audioSource); 406 throw FileNotFound(audioSource);
411 } 407 }
412 } 408 }
413 409
410 std::cerr << "Have audio source: \"" << audioSource.toStdString() << "\"" << std::endl;
411
412 // We don't actually do anything with it here, unless it's the
413 // first audio source and we need it to establish default channel
414 // count and sample rate
415
416 if (m_channels == 0 || m_defaultSampleRate == 0) {
417
418 ProgressPrinter retrievalProgress("Determining default rate and channel count from first input file...");
419
420 FileSource source(audioSource, &retrievalProgress);
421 if (!source.isAvailable()) {
422 cerr << "ERROR: File or URL \"" << audioSource.toStdString()
423 << "\" could not be located" << endl;
424 throw FileNotFound(audioSource);
425 }
426
427 source.waitForData();
428
429 // Open to determine validity, channel count, sample rate only
430 // (then close, and open again later with actual desired rate &c)
431
432 AudioFileReader *reader =
433 AudioFileReaderFactory::createReader(source, 0, &retrievalProgress);
434
435 if (!reader) {
436 throw FailedToOpenFile(audioSource);
437 }
438
439 retrievalProgress.done();
440
441 cerr << "File or URL \"" << audioSource.toStdString() << "\" opened successfully" << endl;
442
443 if (m_channels == 0) {
444 m_channels = reader->getChannelCount();
445 cerr << "Taking default channel count of "
446 << reader->getChannelCount() << " from file" << endl;
447 }
448
449 if (m_defaultSampleRate == 0) {
450 m_defaultSampleRate = reader->getNativeRate();
451 cerr << "Taking default sample rate of "
452 << reader->getNativeRate() << "Hz from file" << endl;
453 cerr << "(Note: Default may be overridden by transforms)" << endl;
454 }
455
456 m_readyReaders[audioSource] = reader;
457 }
458 }
459
460 void FeatureExtractionManager::extractFeatures(QString audioSource)
461 {
462 if (m_plugins.empty()) return;
463
464 testOutputFiles(audioSource);
465
414 if (m_sampleRate == 0) { 466 if (m_sampleRate == 0) {
415 cerr << "ERROR: Internal error in FeatureExtractionManager::extractFeatures: Plugin list is non-empty, but no sample rate set" << endl; 467 throw FileOperationFailed
416 exit(1); 468 (audioSource, "internal error: have sources and plugins, but no sample rate");
417 } 469 }
418 470 if (m_channels == 0) {
419 AudioFileReader *reader = 471 throw FileOperationFailed
420 AudioFileReaderFactory::createReader(source, m_sampleRate, &retrievalProgress); 472 (audioSource, "internal error: have sources and plugins, but no channel count");
421 473 }
474
475 AudioFileReader *reader = 0;
476
477 if (m_readyReaders.contains(audioSource)) {
478 reader = m_readyReaders[audioSource];
479 m_readyReaders.remove(audioSource);
480 if (reader->getChannelCount() != m_channels ||
481 reader->getSampleRate() != m_sampleRate) {
482 // can't use this; open it again
483 delete reader;
484 reader = 0;
485 }
486 }
487 if (!reader) {
488 ProgressPrinter retrievalProgress("Retrieving audio data...");
489 FileSource source(audioSource, &retrievalProgress);
490 source.waitForData();
491 reader = AudioFileReaderFactory::createReader
492 (source, m_sampleRate, &retrievalProgress);
493 retrievalProgress.done();
494 }
495
422 if (!reader) { 496 if (!reader) {
423 throw FailedToOpenFile(audioSource); 497 throw FailedToOpenFile(audioSource);
424 } 498 }
425 499
426 size_t channels = reader->getChannelCount(); 500 cerr << "Audio file \"" << audioSource.toStdString() << "\": "
427 501 << reader->getChannelCount() << "ch at "
428 retrievalProgress.done(); 502 << reader->getNativeRate() << "Hz" << endl;
429 503 if (reader->getChannelCount() != m_channels ||
430 cerr << "Opened " << channels << "-channel file or URL \"" << audioSource.toStdString() << "\"" << endl; 504 reader->getNativeRate() != m_sampleRate) {
431 505 cerr << "NOTE: File will be mixed or resampled for processing: "
432 // reject file if it has too few channels 506 << m_channels << "ch at "
433 if ((int)channels < m_channels) { 507 << m_sampleRate << "Hz" << endl;
434 delete reader; 508 }
435 throw FileOperationFailed 509
436 (audioSource,
437 QString("read sufficient channels (found %1, require %2)")
438 .arg(channels).arg(m_channels));
439 }
440
441 // allocate audio buffers 510 // allocate audio buffers
442 float **data = new float *[m_channels]; 511 float **data = new float *[m_channels];
443 for (int c = 0; c < m_channels; ++c) { 512 for (int c = 0; c < m_channels; ++c) {
444 data[c] = new float[m_blockSize]; 513 data[c] = new float[m_blockSize];
445 } 514 }