annotate data/fileio/AudioFileReaderFactory.cpp @ 823:f0558e69a074

Rename Resampling- to DecodingWavFileReader, and use it whenever we have an audio file that is not quickly seekable using libsndfile. Avoids very slow performance when analysing ogg files.
author Chris Cannam
date Wed, 17 Jul 2013 15:40:01 +0100
parents babed5be1ae7
children e802e550a1f2
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@386 24
Chris@386 25 #include <QString>
Chris@386 26 #include <QFileInfo>
Chris@386 27 #include <iostream>
Chris@386 28
Chris@386 29 QString
Chris@386 30 AudioFileReaderFactory::getKnownExtensions()
Chris@386 31 {
Chris@386 32 std::set<QString> extensions;
Chris@386 33
Chris@386 34 WavFileReader::getSupportedExtensions(extensions);
Chris@386 35 #ifdef HAVE_MAD
Chris@386 36 MP3FileReader::getSupportedExtensions(extensions);
Chris@386 37 #endif
Chris@386 38 #ifdef HAVE_OGGZ
Chris@386 39 #ifdef HAVE_FISHSOUND
Chris@386 40 OggVorbisFileReader::getSupportedExtensions(extensions);
Chris@386 41 #endif
Chris@386 42 #endif
Chris@386 43 #ifdef HAVE_QUICKTIME
Chris@386 44 QuickTimeFileReader::getSupportedExtensions(extensions);
Chris@386 45 #endif
luisf@665 46 #ifdef HAVE_COREAUDIO
luisf@665 47 CoreAudioFileReader::getSupportedExtensions(extensions);
luisf@665 48 #endif
Chris@386 49
Chris@386 50 QString rv;
Chris@386 51 for (std::set<QString>::const_iterator i = extensions.begin();
Chris@386 52 i != extensions.end(); ++i) {
Chris@386 53 if (i != extensions.begin()) rv += " ";
Chris@386 54 rv += "*." + *i;
Chris@386 55 }
Chris@386 56
Chris@386 57 return rv;
Chris@386 58 }
Chris@386 59
Chris@386 60 AudioFileReader *
Chris@392 61 AudioFileReaderFactory::createReader(FileSource source, size_t targetRate,
Chris@392 62 ProgressReporter *reporter)
Chris@386 63 {
Chris@392 64 return create(source, targetRate, false, reporter);
Chris@386 65 }
Chris@386 66
Chris@386 67 AudioFileReader *
Chris@392 68 AudioFileReaderFactory::createThreadingReader(FileSource source, size_t targetRate,
Chris@392 69 ProgressReporter *reporter)
Chris@386 70 {
Chris@392 71 return create(source, targetRate, true, reporter);
Chris@386 72 }
Chris@386 73
Chris@386 74 AudioFileReader *
Chris@392 75 AudioFileReaderFactory::create(FileSource source, size_t targetRate, bool threading,
Chris@392 76 ProgressReporter *reporter)
Chris@386 77 {
Chris@386 78 QString err;
Chris@386 79
Chris@742 80 SVDEBUG << "AudioFileReaderFactory::createReader(\"" << source.getLocation() << "\"): Requested rate: " << targetRate << endl;
Chris@386 81
Chris@667 82 if (!source.isOK()) {
Chris@686 83 std::cerr << "AudioFileReaderFactory::createReader(\"" << source.getLocation() << "\": Failed to retrieve source (transmission error?): " << source.getErrorString() << std::endl;
Chris@667 84 return 0;
Chris@667 85 }
Chris@667 86
Chris@667 87 if (!source.isAvailable()) {
Chris@690 88 SVDEBUG << "AudioFileReaderFactory::createReader(\"" << source.getLocation() << "\": Source not found" << endl;
Chris@386 89 return 0;
Chris@386 90 }
Chris@386 91
Chris@386 92 AudioFileReader *reader = 0;
Chris@386 93
Chris@386 94 // Try to construct a preferred reader based on the extension or
Chris@386 95 // MIME type.
Chris@386 96
Chris@386 97 if (WavFileReader::supports(source)) {
Chris@386 98
Chris@386 99 reader = new WavFileReader(source);
Chris@386 100
Chris@823 101 int fileRate = reader->getSampleRate();
Chris@386 102
Chris@823 103 if (reader->isOK() &&
Chris@823 104 (!reader->isQuicklySeekable() ||
Chris@823 105 (targetRate != 0 && fileRate != targetRate))) {
Chris@823 106
Chris@823 107 SVDEBUG << "AudioFileReaderFactory::createReader: WAV file rate: " << reader->getSampleRate() << ", seekable " << reader->isQuicklySeekable() << ", creating decoding reader" << endl;
Chris@386 108
Chris@386 109 delete reader;
Chris@823 110 reader = new DecodingWavFileReader
Chris@386 111 (source,
Chris@386 112 threading ?
Chris@823 113 DecodingWavFileReader::ResampleThreaded :
Chris@823 114 DecodingWavFileReader::ResampleAtOnce,
Chris@823 115 DecodingWavFileReader::CacheInTemporaryFile,
Chris@823 116 targetRate ? targetRate : fileRate,
Chris@392 117 reporter);
Chris@440 118 if (!reader->isOK()) {
Chris@440 119 delete reader;
Chris@440 120 reader = 0;
Chris@440 121 }
Chris@386 122 }
Chris@386 123 }
Chris@386 124
Chris@386 125 #ifdef HAVE_OGGZ
Chris@386 126 #ifdef HAVE_FISHSOUND
Chris@386 127 if (!reader) {
Chris@386 128 if (OggVorbisFileReader::supports(source)) {
Chris@386 129 reader = new OggVorbisFileReader
Chris@386 130 (source,
Chris@386 131 threading ?
Chris@386 132 OggVorbisFileReader::DecodeThreaded :
Chris@386 133 OggVorbisFileReader::DecodeAtOnce,
Chris@386 134 OggVorbisFileReader::CacheInTemporaryFile,
Chris@392 135 targetRate,
Chris@392 136 reporter);
Chris@440 137 if (!reader->isOK()) {
Chris@440 138 delete reader;
Chris@440 139 reader = 0;
Chris@440 140 }
Chris@386 141 }
Chris@386 142 }
Chris@386 143 #endif
Chris@386 144 #endif
Chris@386 145
Chris@386 146 #ifdef HAVE_MAD
Chris@386 147 if (!reader) {
Chris@386 148 if (MP3FileReader::supports(source)) {
Chris@386 149 reader = new MP3FileReader
Chris@386 150 (source,
Chris@386 151 threading ?
Chris@386 152 MP3FileReader::DecodeThreaded :
Chris@386 153 MP3FileReader::DecodeAtOnce,
Chris@386 154 MP3FileReader::CacheInTemporaryFile,
Chris@392 155 targetRate,
Chris@392 156 reporter);
Chris@440 157 if (!reader->isOK()) {
Chris@440 158 delete reader;
Chris@440 159 reader = 0;
Chris@440 160 }
Chris@386 161 }
Chris@386 162 }
Chris@386 163 #endif
Chris@386 164
Chris@386 165 #ifdef HAVE_QUICKTIME
Chris@386 166 if (!reader) {
Chris@386 167 if (QuickTimeFileReader::supports(source)) {
Chris@386 168 reader = new QuickTimeFileReader
Chris@386 169 (source,
Chris@386 170 threading ?
Chris@386 171 QuickTimeFileReader::DecodeThreaded :
Chris@386 172 QuickTimeFileReader::DecodeAtOnce,
Chris@386 173 QuickTimeFileReader::CacheInTemporaryFile,
Chris@392 174 targetRate,
Chris@392 175 reporter);
Chris@440 176 if (!reader->isOK()) {
Chris@440 177 delete reader;
Chris@440 178 reader = 0;
Chris@440 179 }
Chris@440 180 }
Chris@440 181 }
Chris@440 182 #endif
Chris@440 183
luisf@665 184 #ifdef HAVE_COREAUDIO
luisf@665 185 if (!reader) {
luisf@665 186 if (CoreAudioFileReader::supports(source)) {
luisf@665 187 reader = new CoreAudioFileReader
luisf@665 188 (source,
luisf@665 189 threading ?
luisf@665 190 CoreAudioFileReader::DecodeThreaded :
luisf@665 191 CoreAudioFileReader::DecodeAtOnce,
luisf@665 192 CoreAudioFileReader::CacheInTemporaryFile,
luisf@665 193 targetRate,
luisf@665 194 reporter);
luisf@665 195 if (!reader->isOK()) {
luisf@665 196 delete reader;
luisf@665 197 reader = 0;
luisf@665 198 }
luisf@665 199 }
luisf@665 200 }
luisf@665 201 #endif
luisf@665 202
luisf@665 203
Chris@440 204 // If none of the readers claimed to support this file extension,
Chris@440 205 // perhaps the extension is missing or misleading. Try again,
Chris@440 206 // ignoring it. We have to be confident that the reader won't
Chris@440 207 // open just any old text file or whatever and pretend it's
Chris@440 208 // succeeded
Chris@440 209
Chris@440 210 if (!reader) {
Chris@440 211
Chris@440 212 reader = new WavFileReader(source);
Chris@440 213
Chris@823 214 int fileRate = reader->getSampleRate();
Chris@440 215
Chris@823 216 if (reader->isOK() &&
Chris@823 217 (!reader->isQuicklySeekable() ||
Chris@823 218 (targetRate != 0 && fileRate != targetRate))) {
Chris@823 219
Chris@823 220 SVDEBUG << "AudioFileReaderFactory::createReader: WAV file rate: " << reader->getSampleRate() << ", seekable " << reader->isQuicklySeekable() << ", creating decoding reader" << endl;
Chris@440 221
Chris@440 222 delete reader;
Chris@823 223 reader = new DecodingWavFileReader
Chris@440 224 (source,
Chris@440 225 threading ?
Chris@823 226 DecodingWavFileReader::ResampleThreaded :
Chris@823 227 DecodingWavFileReader::ResampleAtOnce,
Chris@823 228 DecodingWavFileReader::CacheInTemporaryFile,
Chris@823 229 targetRate ? targetRate : fileRate,
Chris@440 230 reporter);
Chris@440 231 }
Chris@440 232
Chris@440 233 if (!reader->isOK()) {
Chris@440 234 delete reader;
Chris@440 235 reader = 0;
Chris@440 236 }
Chris@440 237 }
Chris@440 238
Chris@440 239 #ifdef HAVE_OGGZ
Chris@440 240 #ifdef HAVE_FISHSOUND
Chris@440 241 if (!reader) {
Chris@440 242 reader = new OggVorbisFileReader
Chris@440 243 (source,
Chris@440 244 threading ?
Chris@440 245 OggVorbisFileReader::DecodeThreaded :
Chris@440 246 OggVorbisFileReader::DecodeAtOnce,
Chris@440 247 OggVorbisFileReader::CacheInTemporaryFile,
Chris@440 248 targetRate,
Chris@440 249 reporter);
Chris@440 250
Chris@440 251 if (!reader->isOK()) {
Chris@440 252 delete reader;
Chris@440 253 reader = 0;
Chris@440 254 }
Chris@440 255 }
Chris@440 256 #endif
Chris@440 257 #endif
Chris@440 258
Chris@440 259 #ifdef HAVE_MAD
Chris@440 260 if (!reader) {
Chris@440 261 reader = new MP3FileReader
Chris@440 262 (source,
Chris@440 263 threading ?
Chris@440 264 MP3FileReader::DecodeThreaded :
Chris@440 265 MP3FileReader::DecodeAtOnce,
Chris@440 266 MP3FileReader::CacheInTemporaryFile,
Chris@440 267 targetRate,
Chris@440 268 reporter);
Chris@440 269
Chris@440 270 if (!reader->isOK()) {
Chris@440 271 delete reader;
Chris@440 272 reader = 0;
Chris@440 273 }
Chris@440 274 }
Chris@440 275 #endif
Chris@440 276
Chris@440 277 #ifdef HAVE_QUICKTIME
Chris@440 278 if (!reader) {
Chris@440 279 reader = new QuickTimeFileReader
Chris@440 280 (source,
Chris@440 281 threading ?
Chris@440 282 QuickTimeFileReader::DecodeThreaded :
Chris@440 283 QuickTimeFileReader::DecodeAtOnce,
Chris@440 284 QuickTimeFileReader::CacheInTemporaryFile,
Chris@440 285 targetRate,
Chris@440 286 reporter);
Chris@440 287
Chris@440 288 if (!reader->isOK()) {
Chris@440 289 delete reader;
Chris@440 290 reader = 0;
Chris@386 291 }
Chris@386 292 }
Chris@386 293 #endif
Chris@386 294
luisf@665 295 #ifdef HAVE_COREAUDIO
luisf@665 296 if (!reader) {
luisf@665 297 reader = new CoreAudioFileReader
luisf@665 298 (source,
luisf@665 299 threading ?
luisf@665 300 CoreAudioFileReader::DecodeThreaded :
luisf@665 301 CoreAudioFileReader::DecodeAtOnce,
luisf@665 302 CoreAudioFileReader::CacheInTemporaryFile,
luisf@665 303 targetRate,
luisf@665 304 reporter);
luisf@665 305
luisf@665 306 if (!reader->isOK()) {
luisf@665 307 delete reader;
luisf@665 308 reader = 0;
luisf@665 309 }
luisf@665 310 }
luisf@665 311 #endif
luisf@665 312
Chris@386 313 if (reader) {
Chris@386 314 if (reader->isOK()) {
Chris@756 315 SVDEBUG << "AudioFileReaderFactory: Reader is OK" << endl;
Chris@386 316 return reader;
Chris@386 317 }
Chris@386 318 std::cerr << "AudioFileReaderFactory: Preferred reader for "
Chris@386 319 << "url \"" << source.getLocation().toStdString()
Chris@386 320 << "\" (content type \""
Chris@686 321 << source.getContentType() << "\") failed";
Chris@386 322
Chris@386 323 if (reader->getError() != "") {
Chris@686 324 std::cerr << ": \"" << reader->getError() << "\"";
Chris@386 325 }
Chris@386 326 std::cerr << std::endl;
Chris@386 327 delete reader;
Chris@386 328 reader = 0;
Chris@386 329 }
Chris@386 330
Chris@386 331 std::cerr << "AudioFileReaderFactory: No reader" << std::endl;
Chris@386 332 return reader;
Chris@386 333 }
Chris@386 334