annotate data/fileio/AudioFileReaderFactory.cpp @ 1308:80c77916fe85 mp3-gapless

Update m4a files to exports from CoreAudio, rather than FAAC; update tests accordingly, and add test for spurious data after end of decode
author Chris Cannam <cannam@all-day-breakfast.com>
date Tue, 29 Nov 2016 14:25:57 +0000
parents 9f9f55a8af92
children ff9697592bef
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"
Chris@386 22 #include "QuickTimeFileReader.h"
luisf@665 23 #include "CoreAudioFileReader.h"
Chris@1098 24 #include "AudioFileSizeEstimator.h"
Chris@1098 25
Chris@1098 26 #include "base/StorageAdviser.h"
Chris@386 27
Chris@386 28 #include <QString>
Chris@386 29 #include <QFileInfo>
Chris@386 30 #include <iostream>
Chris@386 31
Chris@386 32 QString
Chris@386 33 AudioFileReaderFactory::getKnownExtensions()
Chris@386 34 {
Chris@386 35 std::set<QString> extensions;
Chris@386 36
Chris@386 37 WavFileReader::getSupportedExtensions(extensions);
Chris@386 38 #ifdef HAVE_MAD
Chris@386 39 MP3FileReader::getSupportedExtensions(extensions);
Chris@386 40 #endif
Chris@386 41 #ifdef HAVE_OGGZ
Chris@386 42 #ifdef HAVE_FISHSOUND
Chris@386 43 OggVorbisFileReader::getSupportedExtensions(extensions);
Chris@386 44 #endif
Chris@386 45 #endif
Chris@386 46 #ifdef HAVE_QUICKTIME
Chris@386 47 QuickTimeFileReader::getSupportedExtensions(extensions);
Chris@386 48 #endif
luisf@665 49 #ifdef HAVE_COREAUDIO
luisf@665 50 CoreAudioFileReader::getSupportedExtensions(extensions);
luisf@665 51 #endif
Chris@386 52
Chris@386 53 QString rv;
Chris@386 54 for (std::set<QString>::const_iterator i = extensions.begin();
Chris@386 55 i != extensions.end(); ++i) {
Chris@386 56 if (i != extensions.begin()) rv += " ";
Chris@386 57 rv += "*." + *i;
Chris@386 58 }
Chris@386 59
Chris@386 60 return rv;
Chris@386 61 }
Chris@386 62
Chris@386 63 AudioFileReader *
Chris@920 64 AudioFileReaderFactory::createReader(FileSource source,
Chris@1040 65 sv_samplerate_t targetRate,
Chris@920 66 bool normalised,
Chris@392 67 ProgressReporter *reporter)
Chris@386 68 {
Chris@920 69 return create(source, targetRate, normalised, false, reporter);
Chris@386 70 }
Chris@386 71
Chris@386 72 AudioFileReader *
Chris@920 73 AudioFileReaderFactory::createThreadingReader(FileSource source,
Chris@1040 74 sv_samplerate_t targetRate,
Chris@920 75 bool normalised,
Chris@392 76 ProgressReporter *reporter)
Chris@386 77 {
Chris@920 78 return create(source, targetRate, normalised, true, reporter);
Chris@386 79 }
Chris@386 80
Chris@386 81 AudioFileReader *
Chris@920 82 AudioFileReaderFactory::create(FileSource source,
Chris@1040 83 sv_samplerate_t targetRate,
Chris@920 84 bool normalised,
Chris@920 85 bool threading,
Chris@392 86 ProgressReporter *reporter)
Chris@386 87 {
Chris@386 88 QString err;
Chris@386 89
Chris@1279 90 SVDEBUG << "AudioFileReaderFactory::createReader(\"" << source.getLocation() << "\"): Requested rate: " << targetRate << (targetRate == 0 ? " (use source rate)" : "") << endl;
Chris@386 91
Chris@667 92 if (!source.isOK()) {
Chris@1279 93 SVDEBUG << "AudioFileReaderFactory::createReader(\"" << source.getLocation() << "\": Failed to retrieve source (transmission error?): " << source.getErrorString() << endl;
Chris@667 94 return 0;
Chris@667 95 }
Chris@667 96
Chris@667 97 if (!source.isAvailable()) {
Chris@1279 98 SVDEBUG << "AudioFileReaderFactory::createReader(\"" << source.getLocation() << "\": Source not found" << endl;
Chris@386 99 return 0;
Chris@386 100 }
Chris@386 101
Chris@386 102 AudioFileReader *reader = 0;
Chris@386 103
Chris@1098 104 sv_frame_t estimatedSamples =
Chris@1098 105 AudioFileSizeEstimator::estimate(source, targetRate);
Chris@1098 106
Chris@1097 107 CodedAudioFileReader::CacheMode cacheMode =
Chris@1097 108 CodedAudioFileReader::CacheInTemporaryFile;
Chris@1097 109
Chris@1098 110 if (estimatedSamples > 0) {
Chris@1098 111 size_t kb = (estimatedSamples * sizeof(float)) / 1024;
Chris@1098 112 StorageAdviser::Recommendation rec =
Chris@1098 113 StorageAdviser::recommend(StorageAdviser::SpeedCritical, kb, kb);
Chris@1277 114 if ((rec & StorageAdviser::UseMemory) ||
Chris@1277 115 (rec & StorageAdviser::PreferMemory)) {
Chris@1098 116 cacheMode = CodedAudioFileReader::CacheInMemory;
Chris@1098 117 }
Chris@1098 118 }
Chris@1098 119
Chris@1097 120 CodedAudioFileReader::DecodeMode decodeMode =
Chris@1097 121 (threading ?
Chris@1097 122 CodedAudioFileReader::DecodeThreaded :
Chris@1097 123 CodedAudioFileReader::DecodeAtOnce);
Chris@1097 124
Chris@386 125 // Try to construct a preferred reader based on the extension or
Chris@386 126 // MIME type.
Chris@386 127
Chris@1097 128 #define CHECK(reader) if (!reader->isOK()) { delete reader; reader = 0; }
Chris@1097 129
Chris@386 130 if (WavFileReader::supports(source)) {
Chris@386 131
Chris@386 132 reader = new WavFileReader(source);
Chris@386 133
Chris@1040 134 sv_samplerate_t fileRate = reader->getSampleRate();
Chris@386 135
Chris@823 136 if (reader->isOK() &&
Chris@823 137 (!reader->isQuicklySeekable() ||
Chris@920 138 normalised ||
Chris@1101 139 (cacheMode == CodedAudioFileReader::CacheInMemory) ||
Chris@823 140 (targetRate != 0 && fileRate != targetRate))) {
Chris@823 141
Chris@1279 142 SVDEBUG << "AudioFileReaderFactory::createReader: WAV file rate: " << reader->getSampleRate() << ", normalised " << normalised << ", seekable " << reader->isQuicklySeekable() << ", in memory " << (cacheMode == CodedAudioFileReader::CacheInMemory) << ", creating decoding reader" << endl;
Chris@1161 143
Chris@386 144 delete reader;
Chris@823 145 reader = new DecodingWavFileReader
Chris@386 146 (source,
Chris@1097 147 decodeMode, cacheMode,
Chris@823 148 targetRate ? targetRate : fileRate,
Chris@920 149 normalised,
Chris@392 150 reporter);
Chris@1097 151 CHECK(reader);
Chris@386 152 }
Chris@386 153 }
Chris@386 154
Chris@386 155 #ifdef HAVE_OGGZ
Chris@386 156 #ifdef HAVE_FISHSOUND
Chris@1097 157 if (!reader && OggVorbisFileReader::supports(source)) {
Chris@1097 158 reader = new OggVorbisFileReader
Chris@1097 159 (source, decodeMode, cacheMode, targetRate, normalised, reporter);
Chris@1097 160 CHECK(reader);
Chris@386 161 }
Chris@386 162 #endif
Chris@386 163 #endif
Chris@386 164
Chris@386 165 #ifdef HAVE_MAD
Chris@1097 166 if (!reader && MP3FileReader::supports(source)) {
Chris@1097 167 reader = new MP3FileReader
Chris@1305 168 (source, decodeMode, cacheMode, MP3FileReader::Gapless,
Chris@1305 169 targetRate, normalised, reporter);
Chris@1097 170 CHECK(reader);
Chris@386 171 }
Chris@386 172 #endif
Chris@386 173
Chris@386 174 #ifdef HAVE_QUICKTIME
Chris@1097 175 if (!reader && QuickTimeFileReader::supports(source)) {
Chris@1097 176 reader = new QuickTimeFileReader
Chris@1097 177 (source, decodeMode, cacheMode, targetRate, normalised, reporter);
Chris@1097 178 CHECK(reader);
Chris@440 179 }
Chris@440 180 #endif
Chris@440 181
luisf@665 182 #ifdef HAVE_COREAUDIO
Chris@1097 183 if (!reader && CoreAudioFileReader::supports(source)) {
Chris@1097 184 reader = new CoreAudioFileReader
Chris@1097 185 (source, decodeMode, cacheMode, targetRate, normalised, reporter);
Chris@1097 186 CHECK(reader);
luisf@665 187 }
luisf@665 188 #endif
luisf@665 189
Chris@1097 190 if (reader) {
Chris@1097 191 // The happy case: a reader recognised the file extension &
Chris@1097 192 // succeeded in opening the file
Chris@1097 193 return reader;
Chris@1097 194 }
Chris@1097 195
Chris@440 196 // If none of the readers claimed to support this file extension,
Chris@440 197 // perhaps the extension is missing or misleading. Try again,
Chris@440 198 // ignoring it. We have to be confident that the reader won't
Chris@440 199 // open just any old text file or whatever and pretend it's
Chris@440 200 // succeeded
Chris@440 201
Chris@1097 202 reader = new WavFileReader(source);
Chris@440 203
Chris@1097 204 sv_samplerate_t fileRate = reader->getSampleRate();
Chris@440 205
Chris@1097 206 if (reader->isOK() &&
Chris@1097 207 (!reader->isQuicklySeekable() ||
Chris@1097 208 normalised ||
Chris@1101 209 (cacheMode == CodedAudioFileReader::CacheInMemory) ||
Chris@1097 210 (targetRate != 0 && fileRate != targetRate))) {
Chris@823 211
Chris@1279 212 SVDEBUG << "AudioFileReaderFactory::createReader: WAV file rate: " << reader->getSampleRate() << ", normalised " << normalised << ", seekable " << reader->isQuicklySeekable() << ", in memory " << (cacheMode == CodedAudioFileReader::CacheInMemory) << ", creating decoding reader" << endl;
Chris@440 213
Chris@1097 214 delete reader;
Chris@1097 215 reader = new DecodingWavFileReader
Chris@1097 216 (source,
Chris@1097 217 decodeMode, cacheMode,
Chris@1097 218 targetRate ? targetRate : fileRate,
Chris@1097 219 normalised,
Chris@1097 220 reporter);
Chris@1097 221 }
Chris@440 222
Chris@1097 223 CHECK(reader);
Chris@440 224
Chris@440 225 #ifdef HAVE_OGGZ
Chris@440 226 #ifdef HAVE_FISHSOUND
Chris@440 227 if (!reader) {
Chris@440 228 reader = new OggVorbisFileReader
Chris@1097 229 (source, decodeMode, cacheMode, targetRate, normalised, reporter);
Chris@1097 230 CHECK(reader);
Chris@440 231 }
Chris@440 232 #endif
Chris@440 233 #endif
Chris@440 234
Chris@440 235 #ifdef HAVE_MAD
Chris@440 236 if (!reader) {
Chris@440 237 reader = new MP3FileReader
Chris@1305 238 (source, decodeMode, cacheMode, MP3FileReader::Gapless,
Chris@1305 239 targetRate, normalised, reporter);
Chris@1097 240 CHECK(reader);
Chris@440 241 }
Chris@440 242 #endif
Chris@440 243
Chris@440 244 #ifdef HAVE_QUICKTIME
Chris@440 245 if (!reader) {
Chris@440 246 reader = new QuickTimeFileReader
Chris@1097 247 (source, decodeMode, cacheMode, targetRate, normalised, reporter);
Chris@1097 248 CHECK(reader);
Chris@386 249 }
Chris@386 250 #endif
Chris@386 251
luisf@665 252 #ifdef HAVE_COREAUDIO
luisf@665 253 if (!reader) {
luisf@665 254 reader = new CoreAudioFileReader
Chris@1097 255 (source, decodeMode, cacheMode, targetRate, normalised, reporter);
Chris@1097 256 CHECK(reader);
luisf@665 257 }
luisf@665 258 #endif
luisf@665 259
Chris@1097 260 if (!reader) {
Chris@1279 261 SVDEBUG << "AudioFileReaderFactory::Failed to create a reader for "
Chris@1279 262 << "url \"" << source.getLocation()
Chris@1279 263 << "\" (content type \""
Chris@1279 264 << source.getContentType() << "\")" << endl;
Chris@1097 265 return nullptr;
Chris@386 266 }
Chris@1097 267
Chris@386 268 return reader;
Chris@386 269 }
Chris@386 270