comparison data/fileio/AudioFileReaderFactory.cpp @ 1313:ff9697592bef 3.0-integration

Add gapless preference to prefs dialog; much work on audio read tests
author Chris Cannam
date Thu, 01 Dec 2016 17:45:40 +0000
parents 9f9f55a8af92
children 7d24f92158a7
comparison
equal deleted inserted replaced
1312:079e553dc16e 1313:ff9697592bef
59 59
60 return rv; 60 return rv;
61 } 61 }
62 62
63 AudioFileReader * 63 AudioFileReader *
64 AudioFileReaderFactory::createReader(FileSource source, 64 AudioFileReaderFactory::createReader(FileSource source,
65 sv_samplerate_t targetRate, 65 Parameters params,
66 bool normalised,
67 ProgressReporter *reporter) 66 ProgressReporter *reporter)
68 { 67 {
69 return create(source, targetRate, normalised, false, reporter);
70 }
71
72 AudioFileReader *
73 AudioFileReaderFactory::createThreadingReader(FileSource source,
74 sv_samplerate_t targetRate,
75 bool normalised,
76 ProgressReporter *reporter)
77 {
78 return create(source, targetRate, normalised, true, reporter);
79 }
80
81 AudioFileReader *
82 AudioFileReaderFactory::create(FileSource source,
83 sv_samplerate_t targetRate,
84 bool normalised,
85 bool threading,
86 ProgressReporter *reporter)
87 {
88 QString err; 68 QString err;
89 69
90 SVDEBUG << "AudioFileReaderFactory::createReader(\"" << source.getLocation() << "\"): Requested rate: " << targetRate << (targetRate == 0 ? " (use source rate)" : "") << endl; 70 SVDEBUG << "AudioFileReaderFactory::createReader(\"" << source.getLocation() << "\"): Requested rate: " << params.targetRate << (params.targetRate == 0 ? " (use source rate)" : "") << endl;
91 71
92 if (!source.isOK()) { 72 if (!source.isOK()) {
93 SVDEBUG << "AudioFileReaderFactory::createReader(\"" << source.getLocation() << "\": Failed to retrieve source (transmission error?): " << source.getErrorString() << endl; 73 SVDEBUG << "AudioFileReaderFactory::createReader(\"" << source.getLocation() << "\": Failed to retrieve source (transmission error?): " << source.getErrorString() << endl;
94 return 0; 74 return 0;
95 } 75 }
99 return 0; 79 return 0;
100 } 80 }
101 81
102 AudioFileReader *reader = 0; 82 AudioFileReader *reader = 0;
103 83
84 sv_samplerate_t targetRate = params.targetRate;
85 bool normalised = (params.normalisation == Normalisation::Peak);
86
104 sv_frame_t estimatedSamples = 87 sv_frame_t estimatedSamples =
105 AudioFileSizeEstimator::estimate(source, targetRate); 88 AudioFileSizeEstimator::estimate(source, targetRate);
106 89
107 CodedAudioFileReader::CacheMode cacheMode = 90 CodedAudioFileReader::CacheMode cacheMode =
108 CodedAudioFileReader::CacheInTemporaryFile; 91 CodedAudioFileReader::CacheInTemporaryFile;
116 cacheMode = CodedAudioFileReader::CacheInMemory; 99 cacheMode = CodedAudioFileReader::CacheInMemory;
117 } 100 }
118 } 101 }
119 102
120 CodedAudioFileReader::DecodeMode decodeMode = 103 CodedAudioFileReader::DecodeMode decodeMode =
121 (threading ? 104 (params.threadingMode == ThreadingMode::Threaded ?
122 CodedAudioFileReader::DecodeThreaded : 105 CodedAudioFileReader::DecodeThreaded :
123 CodedAudioFileReader::DecodeAtOnce); 106 CodedAudioFileReader::DecodeAtOnce);
124 107
125 // Try to construct a preferred reader based on the extension or 108 // We go through the set of supported readers at most twice: once
126 // MIME type. 109 // picking out only the readers that claim to support the given
127 110 // file's extension or MIME type, and (if that fails) again
128 #define CHECK(reader) if (!reader->isOK()) { delete reader; reader = 0; } 111 // providing the file to every reader in turn regardless of
129 112 // extension or type. (If none of the readers claim to support a
130 if (WavFileReader::supports(source)) { 113 // file, that may just mean its extension is missing or
131 114 // misleading. We have to be confident that the reader won't open
132 reader = new WavFileReader(source); 115 // just any old text file or whatever and pretend it's succeeded.)
133 116
134 sv_samplerate_t fileRate = reader->getSampleRate(); 117 for (int any = 0; any <= 1; ++any) {
135 118
136 if (reader->isOK() && 119 bool anyReader = (any > 0);
137 (!reader->isQuicklySeekable() || 120
138 normalised || 121 if (anyReader || WavFileReader::supports(source)) {
139 (cacheMode == CodedAudioFileReader::CacheInMemory) || 122
140 (targetRate != 0 && fileRate != targetRate))) { 123 reader = new WavFileReader(source);
141 124
142 SVDEBUG << "AudioFileReaderFactory::createReader: WAV file rate: " << reader->getSampleRate() << ", normalised " << normalised << ", seekable " << reader->isQuicklySeekable() << ", in memory " << (cacheMode == CodedAudioFileReader::CacheInMemory) << ", creating decoding reader" << endl; 125 sv_samplerate_t fileRate = reader->getSampleRate();
126
127 if (reader->isOK() &&
128 (!reader->isQuicklySeekable() ||
129 normalised ||
130 (cacheMode == CodedAudioFileReader::CacheInMemory) ||
131 (targetRate != 0 && fileRate != targetRate))) {
132
133 SVDEBUG << "AudioFileReaderFactory::createReader: WAV file rate: " << reader->getSampleRate() << ", normalised " << normalised << ", seekable " << reader->isQuicklySeekable() << ", in memory " << (cacheMode == CodedAudioFileReader::CacheInMemory) << ", creating decoding reader" << endl;
143 134
144 delete reader; 135 delete reader;
145 reader = new DecodingWavFileReader 136 reader = new DecodingWavFileReader
146 (source, 137 (source,
147 decodeMode, cacheMode, 138 decodeMode, cacheMode,
148 targetRate ? targetRate : fileRate, 139 targetRate ? targetRate : fileRate,
149 normalised, 140 normalised,
150 reporter); 141 reporter);
151 CHECK(reader); 142 }
152 } 143
153 } 144 if (reader->isOK()) {
145 return reader;
146 } else {
147 delete reader;
148 }
149 }
154 150
155 #ifdef HAVE_OGGZ 151 #ifdef HAVE_OGGZ
156 #ifdef HAVE_FISHSOUND 152 #ifdef HAVE_FISHSOUND
157 if (!reader && OggVorbisFileReader::supports(source)) { 153 if (anyReader || OggVorbisFileReader::supports(source)) {
158 reader = new OggVorbisFileReader 154
159 (source, decodeMode, cacheMode, targetRate, normalised, reporter); 155 reader = new OggVorbisFileReader
160 CHECK(reader); 156 (source, decodeMode, cacheMode, targetRate, normalised, reporter);
161 } 157
158 if (reader->isOK()) {
159 return reader;
160 } else {
161 delete reader;
162 }
163 }
162 #endif 164 #endif
163 #endif 165 #endif
164 166
165 #ifdef HAVE_MAD 167 #ifdef HAVE_MAD
166 if (!reader && MP3FileReader::supports(source)) { 168 if (anyReader || MP3FileReader::supports(source)) {
167 reader = new MP3FileReader 169
168 (source, decodeMode, cacheMode, MP3FileReader::Gapless, 170 MP3FileReader::GaplessMode gapless =
169 targetRate, normalised, reporter); 171 params.gaplessMode == GaplessMode::Gapless ?
170 CHECK(reader); 172 MP3FileReader::GaplessMode::Gapless :
171 } 173 MP3FileReader::GaplessMode::Gappy;
174
175 reader = new MP3FileReader
176 (source, decodeMode, cacheMode, gapless,
177 targetRate, normalised, reporter);
178
179 if (reader->isOK()) {
180 return reader;
181 } else {
182 delete reader;
183 }
184 }
172 #endif 185 #endif
173 186
174 #ifdef HAVE_QUICKTIME 187 #ifdef HAVE_QUICKTIME
175 if (!reader && QuickTimeFileReader::supports(source)) { 188 if (anyReader || QuickTimeFileReader::supports(source)) {
176 reader = new QuickTimeFileReader 189
177 (source, decodeMode, cacheMode, targetRate, normalised, reporter); 190 reader = new QuickTimeFileReader
178 CHECK(reader); 191 (source, decodeMode, cacheMode, targetRate, normalised, reporter);
179 } 192
193 if (reader->isOK()) {
194 return reader;
195 } else {
196 delete reader;
197 }
198 }
180 #endif 199 #endif
181 200
182 #ifdef HAVE_COREAUDIO 201 #ifdef HAVE_COREAUDIO
183 if (!reader && CoreAudioFileReader::supports(source)) { 202 if (anyReader || CoreAudioFileReader::supports(source)) {
184 reader = new CoreAudioFileReader 203
185 (source, decodeMode, cacheMode, targetRate, normalised, reporter); 204 reader = new CoreAudioFileReader
186 CHECK(reader); 205 (source, decodeMode, cacheMode, targetRate, normalised, reporter);
187 } 206
188 #endif 207 if (reader->isOK()) {
189 208 return reader;
190 if (reader) { 209 } else {
191 // The happy case: a reader recognised the file extension & 210 delete reader;
192 // succeeded in opening the file 211 }
193 return reader; 212 }
194 } 213 #endif
195 214
196 // If none of the readers claimed to support this file extension, 215 }
197 // perhaps the extension is missing or misleading. Try again, 216
198 // ignoring it. We have to be confident that the reader won't 217 SVDEBUG << "AudioFileReaderFactory::Failed to create a reader for "
199 // open just any old text file or whatever and pretend it's 218 << "url \"" << source.getLocation()
200 // succeeded 219 << "\" (content type \""
201 220 << source.getContentType() << "\")" << endl;
202 reader = new WavFileReader(source); 221 return nullptr;
203
204 sv_samplerate_t fileRate = reader->getSampleRate();
205
206 if (reader->isOK() &&
207 (!reader->isQuicklySeekable() ||
208 normalised ||
209 (cacheMode == CodedAudioFileReader::CacheInMemory) ||
210 (targetRate != 0 && fileRate != targetRate))) {
211
212 SVDEBUG << "AudioFileReaderFactory::createReader: WAV file rate: " << reader->getSampleRate() << ", normalised " << normalised << ", seekable " << reader->isQuicklySeekable() << ", in memory " << (cacheMode == CodedAudioFileReader::CacheInMemory) << ", creating decoding reader" << endl;
213
214 delete reader;
215 reader = new DecodingWavFileReader
216 (source,
217 decodeMode, cacheMode,
218 targetRate ? targetRate : fileRate,
219 normalised,
220 reporter);
221 }
222
223 CHECK(reader);
224
225 #ifdef HAVE_OGGZ
226 #ifdef HAVE_FISHSOUND
227 if (!reader) {
228 reader = new OggVorbisFileReader
229 (source, decodeMode, cacheMode, targetRate, normalised, reporter);
230 CHECK(reader);
231 }
232 #endif
233 #endif
234
235 #ifdef HAVE_MAD
236 if (!reader) {
237 reader = new MP3FileReader
238 (source, decodeMode, cacheMode, MP3FileReader::Gapless,
239 targetRate, normalised, reporter);
240 CHECK(reader);
241 }
242 #endif
243
244 #ifdef HAVE_QUICKTIME
245 if (!reader) {
246 reader = new QuickTimeFileReader
247 (source, decodeMode, cacheMode, targetRate, normalised, reporter);
248 CHECK(reader);
249 }
250 #endif
251
252 #ifdef HAVE_COREAUDIO
253 if (!reader) {
254 reader = new CoreAudioFileReader
255 (source, decodeMode, cacheMode, targetRate, normalised, reporter);
256 CHECK(reader);
257 }
258 #endif
259
260 if (!reader) {
261 SVDEBUG << "AudioFileReaderFactory::Failed to create a reader for "
262 << "url \"" << source.getLocation()
263 << "\" (content type \""
264 << source.getContentType() << "\")" << endl;
265 return nullptr;
266 }
267
268 return reader;
269 } 222 }
270 223