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 "MP3FileReader.h"
|
Chris@1583
|
21 #include "BQAFileReader.h"
|
Chris@1098
|
22 #include "AudioFileSizeEstimator.h"
|
Chris@1098
|
23
|
Chris@1098
|
24 #include "base/StorageAdviser.h"
|
Chris@386
|
25
|
Chris@386
|
26 #include <QString>
|
Chris@386
|
27 #include <QFileInfo>
|
Chris@386
|
28 #include <iostream>
|
Chris@386
|
29
|
Chris@1583
|
30 using namespace std;
|
Chris@1583
|
31
|
Chris@386
|
32 QString
|
Chris@386
|
33 AudioFileReaderFactory::getKnownExtensions()
|
Chris@386
|
34 {
|
Chris@1583
|
35 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@1583
|
41 BQAFileReader::getSupportedExtensions(extensions);
|
Chris@386
|
42
|
Chris@386
|
43 QString rv;
|
Chris@1583
|
44 for (set<QString>::const_iterator i = extensions.begin();
|
Chris@386
|
45 i != extensions.end(); ++i) {
|
Chris@386
|
46 if (i != extensions.begin()) rv += " ";
|
Chris@386
|
47 rv += "*." + *i;
|
Chris@386
|
48 }
|
Chris@386
|
49
|
Chris@386
|
50 return rv;
|
Chris@386
|
51 }
|
Chris@386
|
52
|
Chris@1592
|
53 bool
|
Chris@1592
|
54 AudioFileReaderFactory::isSupported(FileSource source)
|
Chris@1592
|
55 {
|
Chris@1592
|
56 #ifdef HAVE_MAD
|
Chris@1592
|
57 if (MP3FileReader::supports(source)) {
|
Chris@1592
|
58 return true;
|
Chris@1592
|
59 }
|
Chris@1592
|
60 #endif
|
Chris@1592
|
61 if (WavFileReader::supports(source)) {
|
Chris@1592
|
62 return true;
|
Chris@1592
|
63 }
|
Chris@1592
|
64 if (BQAFileReader::supports(source)) {
|
Chris@1592
|
65 return true;
|
Chris@1592
|
66 }
|
Chris@1592
|
67 return false;
|
Chris@1592
|
68 }
|
Chris@1592
|
69
|
Chris@386
|
70 AudioFileReader *
|
Chris@1313
|
71 AudioFileReaderFactory::createReader(FileSource source,
|
Chris@1313
|
72 Parameters params,
|
Chris@392
|
73 ProgressReporter *reporter)
|
Chris@386
|
74 {
|
Chris@386
|
75 QString err;
|
Chris@386
|
76
|
Chris@1342
|
77 SVDEBUG << "AudioFileReaderFactory: url \"" << source.getLocation() << "\": requested rate: " << params.targetRate << (params.targetRate == 0 ? " (use source rate)" : "") << endl;
|
Chris@1342
|
78 SVDEBUG << "AudioFileReaderFactory: local filename \"" << source.getLocalFilename() << "\", content type \"" << source.getContentType() << "\"" << endl;
|
Chris@386
|
79
|
Chris@667
|
80 if (!source.isOK()) {
|
Chris@1342
|
81 SVCERR << "AudioFileReaderFactory::createReader(\"" << source.getLocation() << "\": Failed to retrieve source (transmission error?): " << source.getErrorString() << endl;
|
Chris@1582
|
82 return nullptr;
|
Chris@667
|
83 }
|
Chris@667
|
84
|
Chris@667
|
85 if (!source.isAvailable()) {
|
Chris@1342
|
86 SVCERR << "AudioFileReaderFactory::createReader(\"" << source.getLocation() << "\": Source not found" << endl;
|
Chris@1582
|
87 return nullptr;
|
Chris@386
|
88 }
|
Chris@386
|
89
|
Chris@1582
|
90 AudioFileReader *reader = nullptr;
|
Chris@386
|
91
|
Chris@1313
|
92 sv_samplerate_t targetRate = params.targetRate;
|
Chris@1313
|
93 bool normalised = (params.normalisation == Normalisation::Peak);
|
Chris@1313
|
94
|
Chris@1098
|
95 sv_frame_t estimatedSamples =
|
Chris@1098
|
96 AudioFileSizeEstimator::estimate(source, targetRate);
|
Chris@1098
|
97
|
Chris@1097
|
98 CodedAudioFileReader::CacheMode cacheMode =
|
Chris@1097
|
99 CodedAudioFileReader::CacheInTemporaryFile;
|
Chris@1097
|
100
|
Chris@1098
|
101 if (estimatedSamples > 0) {
|
Chris@1098
|
102 size_t kb = (estimatedSamples * sizeof(float)) / 1024;
|
Chris@1342
|
103 SVDEBUG << "AudioFileReaderFactory: checking where to potentially cache "
|
Chris@1342
|
104 << kb << "K of sample data" << endl;
|
Chris@1098
|
105 StorageAdviser::Recommendation rec =
|
Chris@1098
|
106 StorageAdviser::recommend(StorageAdviser::SpeedCritical, kb, kb);
|
Chris@1277
|
107 if ((rec & StorageAdviser::UseMemory) ||
|
Chris@1277
|
108 (rec & StorageAdviser::PreferMemory)) {
|
Chris@1342
|
109 SVDEBUG << "AudioFileReaderFactory: cacheing (if at all) in memory" << endl;
|
Chris@1098
|
110 cacheMode = CodedAudioFileReader::CacheInMemory;
|
Chris@1342
|
111 } else {
|
Chris@1342
|
112 SVDEBUG << "AudioFileReaderFactory: cacheing (if at all) on disc" << endl;
|
Chris@1098
|
113 }
|
Chris@1098
|
114 }
|
Chris@1098
|
115
|
Chris@1097
|
116 CodedAudioFileReader::DecodeMode decodeMode =
|
Chris@1313
|
117 (params.threadingMode == ThreadingMode::Threaded ?
|
Chris@1097
|
118 CodedAudioFileReader::DecodeThreaded :
|
Chris@1097
|
119 CodedAudioFileReader::DecodeAtOnce);
|
Chris@386
|
120
|
Chris@1313
|
121 // We go through the set of supported readers at most twice: once
|
Chris@1313
|
122 // picking out only the readers that claim to support the given
|
Chris@1313
|
123 // file's extension or MIME type, and (if that fails) again
|
Chris@1313
|
124 // providing the file to every reader in turn regardless of
|
Chris@1313
|
125 // extension or type. (If none of the readers claim to support a
|
Chris@1313
|
126 // file, that may just mean its extension is missing or
|
Chris@1313
|
127 // misleading. We have to be confident that the reader won't open
|
Chris@1313
|
128 // just any old text file or whatever and pretend it's succeeded.)
|
Chris@1097
|
129
|
Chris@1313
|
130 for (int any = 0; any <= 1; ++any) {
|
Chris@386
|
131
|
Chris@1313
|
132 bool anyReader = (any > 0);
|
Chris@386
|
133
|
Chris@1342
|
134 if (!anyReader) {
|
Chris@1342
|
135 SVDEBUG << "AudioFileReaderFactory: Checking whether any reader officially handles this source" << endl;
|
Chris@1342
|
136 } else {
|
Chris@1342
|
137 SVDEBUG << "AudioFileReaderFactory: Source not officially handled by any reader, trying again with each reader in turn"
|
Chris@1342
|
138 << endl;
|
Chris@1342
|
139 }
|
Chris@1359
|
140
|
Chris@1583
|
141 #ifdef HAVE_MAD
|
Chris@1592
|
142 // Having said we'll try any reader on the second pass, we
|
Chris@1592
|
143 // actually don't want to try the mp3 reader for anything not
|
Chris@1592
|
144 // identified as an mp3 - it can't identify files by header,
|
Chris@1592
|
145 // it'll try to read any data and then fail with
|
Chris@1592
|
146 // synchronisation errors - causing misleading and potentially
|
Chris@1592
|
147 // alarming warning messages at the least
|
Chris@1592
|
148 if (!anyReader) {
|
Chris@1592
|
149 if (MP3FileReader::supports(source)) {
|
Chris@1359
|
150
|
Chris@1592
|
151 MP3FileReader::GaplessMode gapless =
|
Chris@1592
|
152 params.gaplessMode == GaplessMode::Gapless ?
|
Chris@1592
|
153 MP3FileReader::GaplessMode::Gapless :
|
Chris@1592
|
154 MP3FileReader::GaplessMode::Gappy;
|
Chris@1583
|
155
|
Chris@1592
|
156 reader = new MP3FileReader
|
Chris@1592
|
157 (source, decodeMode, cacheMode, gapless,
|
Chris@1592
|
158 targetRate, normalised, reporter);
|
Chris@1359
|
159
|
Chris@1592
|
160 if (reader->isOK()) {
|
Chris@1592
|
161 SVDEBUG << "AudioFileReaderFactory: MP3 file reader is OK, returning it" << endl;
|
Chris@1592
|
162 return reader;
|
Chris@1592
|
163 } else {
|
Chris@1592
|
164 delete reader;
|
Chris@1592
|
165 }
|
Chris@1359
|
166 }
|
Chris@1359
|
167 }
|
Chris@1359
|
168 #endif
|
Chris@1342
|
169
|
Chris@1313
|
170 if (anyReader || WavFileReader::supports(source)) {
|
Chris@386
|
171
|
Chris@1313
|
172 reader = new WavFileReader(source);
|
Chris@823
|
173
|
Chris@1313
|
174 sv_samplerate_t fileRate = reader->getSampleRate();
|
Chris@1313
|
175
|
Chris@1313
|
176 if (reader->isOK() &&
|
Chris@1313
|
177 (!reader->isQuicklySeekable() ||
|
Chris@1313
|
178 normalised ||
|
Chris@1313
|
179 (cacheMode == CodedAudioFileReader::CacheInMemory) ||
|
Chris@1313
|
180 (targetRate != 0 && fileRate != targetRate))) {
|
Chris@1313
|
181
|
Chris@1342
|
182 SVDEBUG << "AudioFileReaderFactory: WAV file reader rate: " << reader->getSampleRate() << ", normalised " << normalised << ", seekable " << reader->isQuicklySeekable() << ", in memory " << (cacheMode == CodedAudioFileReader::CacheInMemory) << ", creating decoding reader" << endl;
|
Chris@1161
|
183
|
Chris@1313
|
184 delete reader;
|
Chris@1313
|
185 reader = new DecodingWavFileReader
|
Chris@1313
|
186 (source,
|
Chris@1313
|
187 decodeMode, cacheMode,
|
Chris@1313
|
188 targetRate ? targetRate : fileRate,
|
Chris@1313
|
189 normalised,
|
Chris@1313
|
190 reporter);
|
Chris@1313
|
191 }
|
Chris@1313
|
192
|
Chris@1313
|
193 if (reader->isOK()) {
|
Chris@1342
|
194 SVDEBUG << "AudioFileReaderFactory: WAV file reader is OK, returning it" << endl;
|
Chris@1313
|
195 return reader;
|
Chris@1313
|
196 } else {
|
Chris@1313
|
197 delete reader;
|
Chris@1313
|
198 }
|
Chris@386
|
199 }
|
Chris@1592
|
200
|
Chris@1592
|
201 if (anyReader || BQAFileReader::supports(source)) {
|
Chris@386
|
202
|
Chris@1592
|
203 reader = new BQAFileReader
|
Chris@1592
|
204 (source, decodeMode, cacheMode,
|
Chris@1313
|
205 targetRate, normalised, reporter);
|
Chris@1313
|
206
|
Chris@1313
|
207 if (reader->isOK()) {
|
Chris@1592
|
208 SVDEBUG << "AudioFileReaderFactory: BQA reader is OK, returning it" << endl;
|
Chris@1313
|
209 return reader;
|
Chris@1313
|
210 } else {
|
Chris@1313
|
211 delete reader;
|
Chris@1313
|
212 }
|
Chris@1313
|
213 }
|
Chris@1097
|
214 }
|
Chris@1097
|
215
|
Chris@1342
|
216 SVCERR << "AudioFileReaderFactory::Failed to create a reader for "
|
Chris@1342
|
217 << "url \"" << source.getLocation()
|
Chris@1342
|
218 << "\" (local filename \"" << source.getLocalFilename()
|
Chris@1342
|
219 << "\", content type \""
|
Chris@1342
|
220 << source.getContentType() << "\")" << endl;
|
Chris@1313
|
221 return nullptr;
|
Chris@386
|
222 }
|
Chris@386
|
223
|