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
|