AudioFileReaderFactory.cpp
Go to the documentation of this file.
1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
2 
3 /*
4  Sonic Visualiser
5  An audio file viewer and annotation editor.
6  Centre for Digital Music, Queen Mary, University of London.
7  This file copyright 2006 Chris Cannam and QMUL.
8 
9  This program is free software; you can redistribute it and/or
10  modify it under the terms of the GNU General Public License as
11  published by the Free Software Foundation; either version 2 of the
12  License, or (at your option) any later version. See the file
13  COPYING included with this distribution for more information.
14 */
15 
16 #include "AudioFileReaderFactory.h"
17 
18 #include "WavFileReader.h"
19 #include "DecodingWavFileReader.h"
20 #include "MP3FileReader.h"
21 #include "BQAFileReader.h"
22 #include "AudioFileSizeEstimator.h"
23 
24 #include "base/StorageAdviser.h"
25 
26 #include <QString>
27 #include <QFileInfo>
28 #include <iostream>
29 
30 using namespace std;
31 
32 QString
34 {
35  set<QString> extensions;
36 
38 #ifdef HAVE_MAD
40 #endif
42 
43  QString rv;
44  for (set<QString>::const_iterator i = extensions.begin();
45  i != extensions.end(); ++i) {
46  if (i != extensions.begin()) rv += " ";
47  rv += "*." + *i;
48  }
49 
50  return rv;
51 }
52 
53 bool
55 {
56 #ifdef HAVE_MAD
57  if (MP3FileReader::supports(source)) {
58  return true;
59  }
60 #endif
61  if (WavFileReader::supports(source)) {
62  return true;
63  }
64  if (BQAFileReader::supports(source)) {
65  return true;
66  }
67  return false;
68 }
69 
72  Parameters params,
73  ProgressReporter *reporter)
74 {
75  QString err;
76 
77  SVDEBUG << "AudioFileReaderFactory: url \"" << source.getLocation() << "\": requested rate: " << params.targetRate << (params.targetRate == 0 ? " (use source rate)" : "") << endl;
78  SVDEBUG << "AudioFileReaderFactory: local filename \"" << source.getLocalFilename() << "\", content type \"" << source.getContentType() << "\"" << endl;
79 
80  if (!source.isOK()) {
81  SVDEBUG << "AudioFileReaderFactory::createReader(\"" << source.getLocation() << "\": Failed to retrieve source (transmission error?): " << source.getErrorString() << endl;
82  return nullptr;
83  }
84 
85  if (!source.isAvailable()) {
86  SVDEBUG << "AudioFileReaderFactory::createReader(\"" << source.getLocation() << "\": Source not found" << endl;
87  return nullptr;
88  }
89 
90  AudioFileReader *reader = nullptr;
91 
92  sv_samplerate_t targetRate = params.targetRate;
93  bool normalised = (params.normalisation == Normalisation::Peak);
94 
95  sv_frame_t estimatedSamples =
96  AudioFileSizeEstimator::estimate(source, targetRate);
97 
100 
101  if (estimatedSamples > 0) {
102  size_t kb = (estimatedSamples * sizeof(float)) / 1024;
103  SVDEBUG << "AudioFileReaderFactory: checking where to potentially cache "
104  << kb << "K of sample data" << endl;
107  if ((rec & StorageAdviser::UseMemory) ||
109  SVDEBUG << "AudioFileReaderFactory: cacheing (if at all) in memory" << endl;
111  } else {
112  SVDEBUG << "AudioFileReaderFactory: cacheing (if at all) on disc" << endl;
113  }
114  }
115 
117  (params.threadingMode == ThreadingMode::Threaded ?
120 
121  // We go through the set of supported readers at most twice: once
122  // picking out only the readers that claim to support the given
123  // file's extension or MIME type, and (if that fails) again
124  // providing the file to every reader in turn regardless of
125  // extension or type. (If none of the readers claim to support a
126  // file, that may just mean its extension is missing or
127  // misleading. We have to be confident that the reader won't open
128  // just any old text file or whatever and pretend it's succeeded.)
129 
130  for (int any = 0; any <= 1; ++any) {
131 
132  bool anyReader = (any > 0);
133 
134  if (!anyReader) {
135  SVDEBUG << "AudioFileReaderFactory: Checking whether any reader officially handles this source" << endl;
136  } else {
137  SVDEBUG << "AudioFileReaderFactory: Source not officially handled by any reader, trying again with each reader in turn"
138  << endl;
139  }
140 
141 #ifdef HAVE_MAD
142  // Having said we'll try any reader on the second pass, we
143  // actually don't want to try the mp3 reader for anything not
144  // identified as an mp3 - it can't identify files by header,
145  // it'll try to read any data and then fail with
146  // synchronisation errors - causing misleading and potentially
147  // alarming warning messages at the least
148  if (!anyReader) {
149  if (MP3FileReader::supports(source)) {
150 
152  params.gaplessMode == GaplessMode::Gapless ?
155 
156  reader = new MP3FileReader
157  (source, decodeMode, cacheMode, gapless,
158  targetRate, normalised, reporter);
159 
160  if (reader->isOK()) {
161  SVDEBUG << "AudioFileReaderFactory: MP3 file reader is OK, returning it" << endl;
162  return reader;
163  } else {
164  delete reader;
165  }
166  }
167  }
168 #endif
169 
170  if (anyReader || WavFileReader::supports(source)) {
171 
172  reader = new WavFileReader(source);
173 
174  sv_samplerate_t fileRate = reader->getSampleRate();
175 
176  if (reader->isOK() &&
177  (!reader->isQuicklySeekable() ||
178  normalised ||
179  (cacheMode == CodedAudioFileReader::CacheInMemory) ||
180  (targetRate != 0 && fileRate != targetRate))) {
181 
182  SVDEBUG << "AudioFileReaderFactory: WAV file reader rate: " << reader->getSampleRate() << ", normalised " << normalised << ", seekable " << reader->isQuicklySeekable() << ", in memory " << (cacheMode == CodedAudioFileReader::CacheInMemory) << ", creating decoding reader" << endl;
183 
184  delete reader;
185  reader = new DecodingWavFileReader
186  (source,
187  decodeMode, cacheMode,
188  targetRate ? targetRate : fileRate,
189  normalised,
190  reporter);
191  }
192 
193  if (reader->isOK()) {
194  SVDEBUG << "AudioFileReaderFactory: WAV file reader is OK, returning it" << endl;
195  return reader;
196  } else {
197  delete reader;
198  }
199  }
200 
201  if (anyReader || BQAFileReader::supports(source)) {
202 
203  reader = new BQAFileReader
204  (source, decodeMode, cacheMode,
205  targetRate, normalised, reporter);
206 
207  if (reader->isOK()) {
208  SVDEBUG << "AudioFileReaderFactory: BQA reader is OK, returning it" << endl;
209  return reader;
210  } else {
211  delete reader;
212  }
213  }
214  }
215 
216  SVDEBUG << "AudioFileReaderFactory::Failed to create a reader for "
217  << "url \"" << source.getLocation()
218  << "\" (local filename \"" << source.getLocalFilename()
219  << "\", content type \""
220  << source.getContentType() << "\")" << endl;
221  return nullptr;
222 }
223 
double sv_samplerate_t
Sample rate.
Definition: BaseTypes.h:51
static bool isSupported(FileSource source)
Return true if the given source has a file extension that indicates a supported file type...
static bool supports(FileSource &source)
int64_t sv_frame_t
Frame index, the unit of our time axis.
Definition: BaseTypes.h:31
static void getSupportedExtensions(std::set< QString > &extensions)
QString getLocation() const
Return the location filename or URL as passed to the constructor.
Definition: FileSource.cpp:616
static void getSupportedExtensions(std::set< QString > &extensions)
GaplessMode
How the MP3FileReader should handle leading and trailing gaps.
Definition: MP3FileReader.h:41
Reader for audio files using libsndfile.
Definition: WavFileReader.h:41
GaplessMode gaplessMode
Gapless mode to use.
QString getLocalFilename() const
Return the name of the local file this FileSource refers to.
Definition: FileSource.cpp:622
static Recommendation recommend(Criteria criteria, size_t minimumSize, size_t maximumSize)
Recommend where to store some data, given certain storage and recall criteria.
Do not trim any samples.
static QString getKnownExtensions()
Return the file extensions that we have audio file readers for, in a format suitable for use with QFi...
QString getErrorString() const
Return an error message, if isOK() is false.
Definition: FileSource.cpp:650
sv_samplerate_t targetRate
Sample rate to open the file at.
static bool supports(FileSource &source)
static AudioFileReader * createReader(FileSource source, Parameters parameters, ProgressReporter *reporter=0)
Return an audio file reader initialised to the file at the given path, or NULL if no suitable reader ...
Trim unwanted samples from the start and end of the decoded audio.
FileSource is a class used to refer to the contents of a file that may be either local or at a remote...
Definition: FileSource.h:59
static void getSupportedExtensions(std::set< QString > &extensions)
QString getContentType() const
Return the MIME content type of this file, if known.
Definition: FileSource.cpp:634
static bool supports(FileSource &source)
#define SVDEBUG
Definition: Debug.h:106
bool isOK() const
Return true if the file was opened successfully and no error has subsequently occurred.
Audio file reader using bqaudiostream library AudioReadStream classes.
Definition: BQAFileReader.h:32
static sv_frame_t estimate(FileSource source, sv_samplerate_t targetRate=0)
Return an estimate of the number of samples (across all channels) in the given audio file...
virtual bool isQuicklySeekable() const =0
Return true if this file supports fast seek and random access.
Normalisation normalisation
Normalisation to use.
ThreadingMode threadingMode
Threading mode.
sv_samplerate_t getSampleRate() const
Return the samplerate at which the file is being read.
bool isOK() const
Return true if the FileSource object is valid and neither error nor cancellation occurred while retri...
Definition: FileSource.cpp:586
bool isAvailable()
Return true if the file or remote URL exists.
Definition: FileSource.cpp:544