annotate data/fileio/AudioFileReaderFactory.cpp @ 1288:5ef9b4d4bbdb 3.0-integration

Filter out Xing/LAME info frames, rather than letting them go to the mp3 decoder as if they were audio frames. Fixes the 1152-sample zero pad at start of some decoded mp3 files (distinct from decoder delay). The logic here is based on the madplay code.
author Chris Cannam
date Thu, 24 Nov 2016 13:32:04 +0000
parents 0a9193dc136b
children 9f9f55a8af92
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@1097 168 (source, decodeMode, cacheMode, targetRate, normalised, reporter);
Chris@1097 169 CHECK(reader);
Chris@386 170 }
Chris@386 171 #endif
Chris@386 172
Chris@386 173 #ifdef HAVE_QUICKTIME
Chris@1097 174 if (!reader && QuickTimeFileReader::supports(source)) {
Chris@1097 175 reader = new QuickTimeFileReader
Chris@1097 176 (source, decodeMode, cacheMode, targetRate, normalised, reporter);
Chris@1097 177 CHECK(reader);
Chris@440 178 }
Chris@440 179 #endif
Chris@440 180
luisf@665 181 #ifdef HAVE_COREAUDIO
Chris@1097 182 if (!reader && CoreAudioFileReader::supports(source)) {
Chris@1097 183 reader = new CoreAudioFileReader
Chris@1097 184 (source, decodeMode, cacheMode, targetRate, normalised, reporter);
Chris@1097 185 CHECK(reader);
luisf@665 186 }
luisf@665 187 #endif
luisf@665 188
Chris@1097 189 if (reader) {
Chris@1097 190 // The happy case: a reader recognised the file extension &
Chris@1097 191 // succeeded in opening the file
Chris@1097 192 return reader;
Chris@1097 193 }
Chris@1097 194
Chris@440 195 // If none of the readers claimed to support this file extension,
Chris@440 196 // perhaps the extension is missing or misleading. Try again,
Chris@440 197 // ignoring it. We have to be confident that the reader won't
Chris@440 198 // open just any old text file or whatever and pretend it's
Chris@440 199 // succeeded
Chris@440 200
Chris@1097 201 reader = new WavFileReader(source);
Chris@440 202
Chris@1097 203 sv_samplerate_t fileRate = reader->getSampleRate();
Chris@440 204
Chris@1097 205 if (reader->isOK() &&
Chris@1097 206 (!reader->isQuicklySeekable() ||
Chris@1097 207 normalised ||
Chris@1101 208 (cacheMode == CodedAudioFileReader::CacheInMemory) ||
Chris@1097 209 (targetRate != 0 && fileRate != targetRate))) {
Chris@823 210
Chris@1279 211 SVDEBUG << "AudioFileReaderFactory::createReader: WAV file rate: " << reader->getSampleRate() << ", normalised " << normalised << ", seekable " << reader->isQuicklySeekable() << ", in memory " << (cacheMode == CodedAudioFileReader::CacheInMemory) << ", creating decoding reader" << endl;
Chris@440 212
Chris@1097 213 delete reader;
Chris@1097 214 reader = new DecodingWavFileReader
Chris@1097 215 (source,
Chris@1097 216 decodeMode, cacheMode,
Chris@1097 217 targetRate ? targetRate : fileRate,
Chris@1097 218 normalised,
Chris@1097 219 reporter);
Chris@1097 220 }
Chris@440 221
Chris@1097 222 CHECK(reader);
Chris@440 223
Chris@440 224 #ifdef HAVE_OGGZ
Chris@440 225 #ifdef HAVE_FISHSOUND
Chris@440 226 if (!reader) {
Chris@440 227 reader = new OggVorbisFileReader
Chris@1097 228 (source, decodeMode, cacheMode, targetRate, normalised, reporter);
Chris@1097 229 CHECK(reader);
Chris@440 230 }
Chris@440 231 #endif
Chris@440 232 #endif
Chris@440 233
Chris@440 234 #ifdef HAVE_MAD
Chris@440 235 if (!reader) {
Chris@440 236 reader = new MP3FileReader
Chris@1097 237 (source, decodeMode, cacheMode, targetRate, normalised, reporter);
Chris@1097 238 CHECK(reader);
Chris@440 239 }
Chris@440 240 #endif
Chris@440 241
Chris@440 242 #ifdef HAVE_QUICKTIME
Chris@440 243 if (!reader) {
Chris@440 244 reader = new QuickTimeFileReader
Chris@1097 245 (source, decodeMode, cacheMode, targetRate, normalised, reporter);
Chris@1097 246 CHECK(reader);
Chris@386 247 }
Chris@386 248 #endif
Chris@386 249
luisf@665 250 #ifdef HAVE_COREAUDIO
luisf@665 251 if (!reader) {
luisf@665 252 reader = new CoreAudioFileReader
Chris@1097 253 (source, decodeMode, cacheMode, targetRate, normalised, reporter);
Chris@1097 254 CHECK(reader);
luisf@665 255 }
luisf@665 256 #endif
luisf@665 257
Chris@1097 258 if (!reader) {
Chris@1279 259 SVDEBUG << "AudioFileReaderFactory::Failed to create a reader for "
Chris@1279 260 << "url \"" << source.getLocation()
Chris@1279 261 << "\" (content type \""
Chris@1279 262 << source.getContentType() << "\")" << endl;
Chris@1097 263 return nullptr;
Chris@386 264 }
Chris@1097 265
Chris@386 266 return reader;
Chris@386 267 }
Chris@386 268