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