annotate data/fileio/AudioFileReaderFactory.cpp @ 1372:54366398e636

Handle exceptions raised during plugin processing (as opposed to on init/configure, which were already handled)
author Chris Cannam
date Tue, 31 Jan 2017 11:13:20 +0000
parents 1c9bbbb6116a
children 70e172e6cc59 c8fad3c14a2b
rev   line source
Chris@386 1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
Chris@386 2
Chris@386 3 /*
Chris@386 4 Sonic Visualiser
Chris@386 5 An audio file viewer and annotation editor.
Chris@386 6 Centre for Digital Music, Queen Mary, University of London.
Chris@386 7 This file copyright 2006 Chris Cannam and QMUL.
Chris@386 8
Chris@386 9 This program is free software; you can redistribute it and/or
Chris@386 10 modify it under the terms of the GNU General Public License as
Chris@386 11 published by the Free Software Foundation; either version 2 of the
Chris@386 12 License, or (at your option) any later version. See the file
Chris@386 13 COPYING included with this distribution for more information.
Chris@386 14 */
Chris@386 15
Chris@386 16 #include "AudioFileReaderFactory.h"
Chris@386 17
Chris@386 18 #include "WavFileReader.h"
Chris@823 19 #include "DecodingWavFileReader.h"
Chris@386 20 #include "OggVorbisFileReader.h"
Chris@386 21 #include "MP3FileReader.h"
luisf@665 22 #include "CoreAudioFileReader.h"
Chris@1098 23 #include "AudioFileSizeEstimator.h"
Chris@1098 24
Chris@1098 25 #include "base/StorageAdviser.h"
Chris@386 26
Chris@386 27 #include <QString>
Chris@386 28 #include <QFileInfo>
Chris@386 29 #include <iostream>
Chris@386 30
Chris@386 31 QString
Chris@386 32 AudioFileReaderFactory::getKnownExtensions()
Chris@386 33 {
Chris@386 34 std::set<QString> extensions;
Chris@386 35
Chris@386 36 WavFileReader::getSupportedExtensions(extensions);
Chris@386 37 #ifdef HAVE_MAD
Chris@386 38 MP3FileReader::getSupportedExtensions(extensions);
Chris@386 39 #endif
Chris@386 40 #ifdef HAVE_OGGZ
Chris@386 41 #ifdef HAVE_FISHSOUND
Chris@386 42 OggVorbisFileReader::getSupportedExtensions(extensions);
Chris@386 43 #endif
Chris@386 44 #endif
luisf@665 45 #ifdef HAVE_COREAUDIO
luisf@665 46 CoreAudioFileReader::getSupportedExtensions(extensions);
luisf@665 47 #endif
Chris@386 48
Chris@386 49 QString rv;
Chris@386 50 for (std::set<QString>::const_iterator i = extensions.begin();
Chris@386 51 i != extensions.end(); ++i) {
Chris@386 52 if (i != extensions.begin()) rv += " ";
Chris@386 53 rv += "*." + *i;
Chris@386 54 }
Chris@386 55
Chris@386 56 return rv;
Chris@386 57 }
Chris@386 58
Chris@386 59 AudioFileReader *
Chris@1313 60 AudioFileReaderFactory::createReader(FileSource source,
Chris@1313 61 Parameters params,
Chris@392 62 ProgressReporter *reporter)
Chris@386 63 {
Chris@386 64 QString err;
Chris@386 65
Chris@1342 66 SVDEBUG << "AudioFileReaderFactory: url \"" << source.getLocation() << "\": requested rate: " << params.targetRate << (params.targetRate == 0 ? " (use source rate)" : "") << endl;
Chris@1342 67 SVDEBUG << "AudioFileReaderFactory: local filename \"" << source.getLocalFilename() << "\", content type \"" << source.getContentType() << "\"" << endl;
Chris@386 68
Chris@667 69 if (!source.isOK()) {
Chris@1342 70 SVCERR << "AudioFileReaderFactory::createReader(\"" << source.getLocation() << "\": Failed to retrieve source (transmission error?): " << source.getErrorString() << endl;
Chris@667 71 return 0;
Chris@667 72 }
Chris@667 73
Chris@667 74 if (!source.isAvailable()) {
Chris@1342 75 SVCERR << "AudioFileReaderFactory::createReader(\"" << source.getLocation() << "\": Source not found" << endl;
Chris@386 76 return 0;
Chris@386 77 }
Chris@386 78
Chris@386 79 AudioFileReader *reader = 0;
Chris@386 80
Chris@1313 81 sv_samplerate_t targetRate = params.targetRate;
Chris@1313 82 bool normalised = (params.normalisation == Normalisation::Peak);
Chris@1313 83
Chris@1098 84 sv_frame_t estimatedSamples =
Chris@1098 85 AudioFileSizeEstimator::estimate(source, targetRate);
Chris@1098 86
Chris@1097 87 CodedAudioFileReader::CacheMode cacheMode =
Chris@1097 88 CodedAudioFileReader::CacheInTemporaryFile;
Chris@1097 89
Chris@1098 90 if (estimatedSamples > 0) {
Chris@1098 91 size_t kb = (estimatedSamples * sizeof(float)) / 1024;
Chris@1342 92 SVDEBUG << "AudioFileReaderFactory: checking where to potentially cache "
Chris@1342 93 << kb << "K of sample data" << endl;
Chris@1098 94 StorageAdviser::Recommendation rec =
Chris@1098 95 StorageAdviser::recommend(StorageAdviser::SpeedCritical, kb, kb);
Chris@1277 96 if ((rec & StorageAdviser::UseMemory) ||
Chris@1277 97 (rec & StorageAdviser::PreferMemory)) {
Chris@1342 98 SVDEBUG << "AudioFileReaderFactory: cacheing (if at all) in memory" << endl;
Chris@1098 99 cacheMode = CodedAudioFileReader::CacheInMemory;
Chris@1342 100 } else {
Chris@1342 101 SVDEBUG << "AudioFileReaderFactory: cacheing (if at all) on disc" << endl;
Chris@1098 102 }
Chris@1098 103 }
Chris@1098 104
Chris@1097 105 CodedAudioFileReader::DecodeMode decodeMode =
Chris@1313 106 (params.threadingMode == ThreadingMode::Threaded ?
Chris@1097 107 CodedAudioFileReader::DecodeThreaded :
Chris@1097 108 CodedAudioFileReader::DecodeAtOnce);
Chris@386 109
Chris@1313 110 // We go through the set of supported readers at most twice: once
Chris@1313 111 // picking out only the readers that claim to support the given
Chris@1313 112 // file's extension or MIME type, and (if that fails) again
Chris@1313 113 // providing the file to every reader in turn regardless of
Chris@1313 114 // extension or type. (If none of the readers claim to support a
Chris@1313 115 // file, that may just mean its extension is missing or
Chris@1313 116 // misleading. We have to be confident that the reader won't open
Chris@1313 117 // just any old text file or whatever and pretend it's succeeded.)
Chris@1097 118
Chris@1313 119 for (int any = 0; any <= 1; ++any) {
Chris@386 120
Chris@1313 121 bool anyReader = (any > 0);
Chris@386 122
Chris@1342 123 if (!anyReader) {
Chris@1342 124 SVDEBUG << "AudioFileReaderFactory: Checking whether any reader officially handles this source" << endl;
Chris@1342 125 } else {
Chris@1342 126 SVDEBUG << "AudioFileReaderFactory: Source not officially handled by any reader, trying again with each reader in turn"
Chris@1342 127 << endl;
Chris@1342 128 }
Chris@1359 129
Chris@1359 130 #ifdef HAVE_OGGZ
Chris@1359 131 #ifdef HAVE_FISHSOUND
Chris@1359 132 // If we have the "real" Ogg reader, use that first. Otherwise
Chris@1359 133 // the WavFileReader will likely accept Ogg files (as
Chris@1359 134 // libsndfile supports them) but it has no ability to return
Chris@1359 135 // file metadata, so we get a slightly less useful result.
Chris@1359 136 if (anyReader || OggVorbisFileReader::supports(source)) {
Chris@1359 137
Chris@1359 138 reader = new OggVorbisFileReader
Chris@1359 139 (source, decodeMode, cacheMode, targetRate, normalised, reporter);
Chris@1359 140
Chris@1359 141 if (reader->isOK()) {
Chris@1359 142 SVDEBUG << "AudioFileReaderFactory: Ogg file reader is OK, returning it" << endl;
Chris@1359 143 return reader;
Chris@1359 144 } else {
Chris@1359 145 delete reader;
Chris@1359 146 }
Chris@1359 147 }
Chris@1359 148 #endif
Chris@1359 149 #endif
Chris@1342 150
Chris@1313 151 if (anyReader || WavFileReader::supports(source)) {
Chris@386 152
Chris@1313 153 reader = new WavFileReader(source);
Chris@823 154
Chris@1313 155 sv_samplerate_t fileRate = reader->getSampleRate();
Chris@1313 156
Chris@1313 157 if (reader->isOK() &&
Chris@1313 158 (!reader->isQuicklySeekable() ||
Chris@1313 159 normalised ||
Chris@1313 160 (cacheMode == CodedAudioFileReader::CacheInMemory) ||
Chris@1313 161 (targetRate != 0 && fileRate != targetRate))) {
Chris@1313 162
Chris@1342 163 SVDEBUG << "AudioFileReaderFactory: WAV file reader rate: " << reader->getSampleRate() << ", normalised " << normalised << ", seekable " << reader->isQuicklySeekable() << ", in memory " << (cacheMode == CodedAudioFileReader::CacheInMemory) << ", creating decoding reader" << endl;
Chris@1161 164
Chris@1313 165 delete reader;
Chris@1313 166 reader = new DecodingWavFileReader
Chris@1313 167 (source,
Chris@1313 168 decodeMode, cacheMode,
Chris@1313 169 targetRate ? targetRate : fileRate,
Chris@1313 170 normalised,
Chris@1313 171 reporter);
Chris@1313 172 }
Chris@1313 173
Chris@1313 174 if (reader->isOK()) {
Chris@1342 175 SVDEBUG << "AudioFileReaderFactory: WAV file reader is OK, returning it" << endl;
Chris@1313 176 return reader;
Chris@1313 177 } else {
Chris@1313 178 delete reader;
Chris@1313 179 }
Chris@386 180 }
Chris@386 181
Chris@386 182 #ifdef HAVE_MAD
Chris@1313 183 if (anyReader || MP3FileReader::supports(source)) {
Chris@1313 184
Chris@1313 185 MP3FileReader::GaplessMode gapless =
Chris@1313 186 params.gaplessMode == GaplessMode::Gapless ?
Chris@1313 187 MP3FileReader::GaplessMode::Gapless :
Chris@1313 188 MP3FileReader::GaplessMode::Gappy;
Chris@1313 189
Chris@1313 190 reader = new MP3FileReader
Chris@1313 191 (source, decodeMode, cacheMode, gapless,
Chris@1313 192 targetRate, normalised, reporter);
Chris@1313 193
Chris@1313 194 if (reader->isOK()) {
Chris@1342 195 SVDEBUG << "AudioFileReaderFactory: MP3 file reader is OK, returning it" << endl;
Chris@1313 196 return reader;
Chris@1313 197 } else {
Chris@1313 198 delete reader;
Chris@1313 199 }
Chris@1313 200 }
Chris@386 201 #endif
Chris@386 202
luisf@665 203 #ifdef HAVE_COREAUDIO
Chris@1313 204 if (anyReader || CoreAudioFileReader::supports(source)) {
Chris@1313 205
Chris@1313 206 reader = new CoreAudioFileReader
Chris@1313 207 (source, decodeMode, cacheMode, targetRate, normalised, reporter);
Chris@1313 208
Chris@1313 209 if (reader->isOK()) {
Chris@1342 210 SVDEBUG << "AudioFileReaderFactory: CoreAudio reader is OK, returning it" << endl;
Chris@1313 211 return reader;
Chris@1313 212 } else {
Chris@1313 213 delete reader;
Chris@1313 214 }
Chris@1313 215 }
luisf@665 216 #endif
luisf@665 217
Chris@1097 218 }
Chris@1097 219
Chris@1342 220 SVCERR << "AudioFileReaderFactory::Failed to create a reader for "
Chris@1342 221 << "url \"" << source.getLocation()
Chris@1342 222 << "\" (local filename \"" << source.getLocalFilename()
Chris@1342 223 << "\", content type \""
Chris@1342 224 << source.getContentType() << "\")" << endl;
Chris@1313 225 return nullptr;
Chris@386 226 }
Chris@386 227