annotate data/fileio/AudioFileReaderFactory.cpp @ 1552:05c3fbaec8ea

Introduce RelativelyFineZoomConstraint, which encodes more-or-less the scheme that was already used for the horizontal thumbwheel in the pane (which overrode the layers' own zoom constraints unless they said they couldn't support any other)
author Chris Cannam
date Wed, 10 Oct 2018 14:32:34 +0100
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