Chris@386: /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ Chris@386: Chris@386: /* Chris@386: Sonic Visualiser Chris@386: An audio file viewer and annotation editor. Chris@386: Centre for Digital Music, Queen Mary, University of London. Chris@386: This file copyright 2006 Chris Cannam and QMUL. Chris@386: Chris@386: This program is free software; you can redistribute it and/or Chris@386: modify it under the terms of the GNU General Public License as Chris@386: published by the Free Software Foundation; either version 2 of the Chris@386: License, or (at your option) any later version. See the file Chris@386: COPYING included with this distribution for more information. Chris@386: */ Chris@386: Chris@386: #include "AudioFileReaderFactory.h" Chris@386: Chris@386: #include "WavFileReader.h" Chris@823: #include "DecodingWavFileReader.h" Chris@386: #include "OggVorbisFileReader.h" Chris@386: #include "MP3FileReader.h" Chris@386: #include "QuickTimeFileReader.h" luisf@665: #include "CoreAudioFileReader.h" Chris@1098: #include "AudioFileSizeEstimator.h" Chris@1098: Chris@1098: #include "base/StorageAdviser.h" Chris@386: Chris@386: #include Chris@386: #include Chris@386: #include Chris@386: Chris@1161: //#define DEBUG_AUDIO_FILE_READER_FACTORY 1 Chris@1161: Chris@386: QString Chris@386: AudioFileReaderFactory::getKnownExtensions() Chris@386: { Chris@386: std::set extensions; Chris@386: Chris@386: WavFileReader::getSupportedExtensions(extensions); Chris@386: #ifdef HAVE_MAD Chris@386: MP3FileReader::getSupportedExtensions(extensions); Chris@386: #endif Chris@386: #ifdef HAVE_OGGZ Chris@386: #ifdef HAVE_FISHSOUND Chris@386: OggVorbisFileReader::getSupportedExtensions(extensions); Chris@386: #endif Chris@386: #endif Chris@386: #ifdef HAVE_QUICKTIME Chris@386: QuickTimeFileReader::getSupportedExtensions(extensions); Chris@386: #endif luisf@665: #ifdef HAVE_COREAUDIO luisf@665: CoreAudioFileReader::getSupportedExtensions(extensions); luisf@665: #endif Chris@386: Chris@386: QString rv; Chris@386: for (std::set::const_iterator i = extensions.begin(); Chris@386: i != extensions.end(); ++i) { Chris@386: if (i != extensions.begin()) rv += " "; Chris@386: rv += "*." + *i; Chris@386: } Chris@386: Chris@386: return rv; Chris@386: } Chris@386: Chris@386: AudioFileReader * Chris@920: AudioFileReaderFactory::createReader(FileSource source, Chris@1040: sv_samplerate_t targetRate, Chris@920: bool normalised, Chris@392: ProgressReporter *reporter) Chris@386: { Chris@920: return create(source, targetRate, normalised, false, reporter); Chris@386: } Chris@386: Chris@386: AudioFileReader * Chris@920: AudioFileReaderFactory::createThreadingReader(FileSource source, Chris@1040: sv_samplerate_t targetRate, Chris@920: bool normalised, Chris@392: ProgressReporter *reporter) Chris@386: { Chris@920: return create(source, targetRate, normalised, true, reporter); Chris@386: } Chris@386: Chris@386: AudioFileReader * Chris@920: AudioFileReaderFactory::create(FileSource source, Chris@1040: sv_samplerate_t targetRate, Chris@920: bool normalised, Chris@920: bool threading, Chris@392: ProgressReporter *reporter) Chris@386: { Chris@386: QString err; Chris@386: Chris@1161: #ifdef DEBUG_AUDIO_FILE_READER_FACTORY Chris@1161: cerr << "AudioFileReaderFactory::createReader(\"" << source.getLocation() << "\"): Requested rate: " << targetRate << endl; Chris@1161: #endif Chris@386: Chris@667: if (!source.isOK()) { Chris@843: cerr << "AudioFileReaderFactory::createReader(\"" << source.getLocation() << "\": Failed to retrieve source (transmission error?): " << source.getErrorString() << endl; Chris@667: return 0; Chris@667: } Chris@667: Chris@667: if (!source.isAvailable()) { Chris@1161: cerr << "AudioFileReaderFactory::createReader(\"" << source.getLocation() << "\": Source not found" << endl; Chris@386: return 0; Chris@386: } Chris@386: Chris@386: AudioFileReader *reader = 0; Chris@386: Chris@1098: sv_frame_t estimatedSamples = Chris@1098: AudioFileSizeEstimator::estimate(source, targetRate); Chris@1098: Chris@1097: CodedAudioFileReader::CacheMode cacheMode = Chris@1097: CodedAudioFileReader::CacheInTemporaryFile; Chris@1097: Chris@1098: if (estimatedSamples > 0) { Chris@1098: size_t kb = (estimatedSamples * sizeof(float)) / 1024; Chris@1098: StorageAdviser::Recommendation rec = Chris@1098: StorageAdviser::recommend(StorageAdviser::SpeedCritical, kb, kb); Chris@1277: if ((rec & StorageAdviser::UseMemory) || Chris@1277: (rec & StorageAdviser::PreferMemory)) { Chris@1098: cacheMode = CodedAudioFileReader::CacheInMemory; Chris@1098: } Chris@1098: } Chris@1098: Chris@1097: CodedAudioFileReader::DecodeMode decodeMode = Chris@1097: (threading ? Chris@1097: CodedAudioFileReader::DecodeThreaded : Chris@1097: CodedAudioFileReader::DecodeAtOnce); Chris@1097: Chris@386: // Try to construct a preferred reader based on the extension or Chris@386: // MIME type. Chris@386: Chris@1097: #define CHECK(reader) if (!reader->isOK()) { delete reader; reader = 0; } Chris@1097: Chris@386: if (WavFileReader::supports(source)) { Chris@386: Chris@386: reader = new WavFileReader(source); Chris@386: Chris@1040: sv_samplerate_t fileRate = reader->getSampleRate(); Chris@386: Chris@823: if (reader->isOK() && Chris@823: (!reader->isQuicklySeekable() || Chris@920: normalised || Chris@1101: (cacheMode == CodedAudioFileReader::CacheInMemory) || Chris@823: (targetRate != 0 && fileRate != targetRate))) { Chris@823: Chris@1161: #ifdef DEBUG_AUDIO_FILE_READER_FACTORY Chris@1170: cerr << "AudioFileReaderFactory::createReader: WAV file rate: " << reader->getSampleRate() << ", normalised " << normalised << ", seekable " << reader->isQuicklySeekable() << ", in memory " << (cacheMode == CodedAudioFileReader::CacheInMemory) << ", creating decoding reader" << endl; Chris@1161: #endif Chris@1161: Chris@386: delete reader; Chris@823: reader = new DecodingWavFileReader Chris@386: (source, Chris@1097: decodeMode, cacheMode, Chris@823: targetRate ? targetRate : fileRate, Chris@920: normalised, Chris@392: reporter); Chris@1097: CHECK(reader); Chris@386: } Chris@386: } Chris@386: Chris@386: #ifdef HAVE_OGGZ Chris@386: #ifdef HAVE_FISHSOUND Chris@1097: if (!reader && OggVorbisFileReader::supports(source)) { Chris@1097: reader = new OggVorbisFileReader Chris@1097: (source, decodeMode, cacheMode, targetRate, normalised, reporter); Chris@1097: CHECK(reader); Chris@386: } Chris@386: #endif Chris@386: #endif Chris@386: Chris@386: #ifdef HAVE_MAD Chris@1097: if (!reader && MP3FileReader::supports(source)) { Chris@1097: reader = new MP3FileReader Chris@1097: (source, decodeMode, cacheMode, targetRate, normalised, reporter); Chris@1097: CHECK(reader); Chris@386: } Chris@386: #endif Chris@386: Chris@386: #ifdef HAVE_QUICKTIME Chris@1097: if (!reader && QuickTimeFileReader::supports(source)) { Chris@1097: reader = new QuickTimeFileReader Chris@1097: (source, decodeMode, cacheMode, targetRate, normalised, reporter); Chris@1097: CHECK(reader); Chris@440: } Chris@440: #endif Chris@440: luisf@665: #ifdef HAVE_COREAUDIO Chris@1097: if (!reader && CoreAudioFileReader::supports(source)) { Chris@1097: reader = new CoreAudioFileReader Chris@1097: (source, decodeMode, cacheMode, targetRate, normalised, reporter); Chris@1097: CHECK(reader); luisf@665: } luisf@665: #endif luisf@665: Chris@1097: if (reader) { Chris@1097: // The happy case: a reader recognised the file extension & Chris@1097: // succeeded in opening the file Chris@1097: return reader; Chris@1097: } Chris@1097: Chris@440: // If none of the readers claimed to support this file extension, Chris@440: // perhaps the extension is missing or misleading. Try again, Chris@440: // ignoring it. We have to be confident that the reader won't Chris@440: // open just any old text file or whatever and pretend it's Chris@440: // succeeded Chris@440: Chris@1097: reader = new WavFileReader(source); Chris@440: Chris@1097: sv_samplerate_t fileRate = reader->getSampleRate(); Chris@440: Chris@1097: if (reader->isOK() && Chris@1097: (!reader->isQuicklySeekable() || Chris@1097: normalised || Chris@1101: (cacheMode == CodedAudioFileReader::CacheInMemory) || Chris@1097: (targetRate != 0 && fileRate != targetRate))) { Chris@823: Chris@1161: #ifdef DEBUG_AUDIO_FILE_READER_FACTORY Chris@1170: cerr << "AudioFileReaderFactory::createReader: WAV file rate: " << reader->getSampleRate() << ", normalised " << normalised << ", seekable " << reader->isQuicklySeekable() << ", in memory " << (cacheMode == CodedAudioFileReader::CacheInMemory) << ", creating decoding reader" << endl; Chris@1161: #endif Chris@440: Chris@1097: delete reader; Chris@1097: reader = new DecodingWavFileReader Chris@1097: (source, Chris@1097: decodeMode, cacheMode, Chris@1097: targetRate ? targetRate : fileRate, Chris@1097: normalised, Chris@1097: reporter); Chris@1097: } Chris@440: Chris@1097: CHECK(reader); Chris@440: Chris@440: #ifdef HAVE_OGGZ Chris@440: #ifdef HAVE_FISHSOUND Chris@440: if (!reader) { Chris@440: reader = new OggVorbisFileReader Chris@1097: (source, decodeMode, cacheMode, targetRate, normalised, reporter); Chris@1097: CHECK(reader); Chris@440: } Chris@440: #endif Chris@440: #endif Chris@440: Chris@440: #ifdef HAVE_MAD Chris@440: if (!reader) { Chris@440: reader = new MP3FileReader Chris@1097: (source, decodeMode, cacheMode, targetRate, normalised, reporter); Chris@1097: CHECK(reader); Chris@440: } Chris@440: #endif Chris@440: Chris@440: #ifdef HAVE_QUICKTIME Chris@440: if (!reader) { Chris@440: reader = new QuickTimeFileReader Chris@1097: (source, decodeMode, cacheMode, targetRate, normalised, reporter); Chris@1097: CHECK(reader); Chris@386: } Chris@386: #endif Chris@386: luisf@665: #ifdef HAVE_COREAUDIO luisf@665: if (!reader) { luisf@665: reader = new CoreAudioFileReader Chris@1097: (source, decodeMode, cacheMode, targetRate, normalised, reporter); Chris@1097: CHECK(reader); luisf@665: } luisf@665: #endif luisf@665: Chris@1097: if (!reader) { Chris@1097: cerr << "AudioFileReaderFactory::Failed to create a reader for " Chris@1097: << "url \"" << source.getLocation() Chris@1097: << "\" (content type \"" Chris@1097: << source.getContentType() << "\")" << endl; Chris@1097: return nullptr; Chris@386: } Chris@1097: Chris@386: return reader; Chris@386: } Chris@386: