Mercurial > hg > svcore
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 |