Mercurial > hg > sonic-annotator
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 } |