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@1098
|
24 #include "AudioFileSizeEstimator.h"
|
Chris@1098
|
25
|
Chris@1098
|
26 #include "base/StorageAdviser.h"
|
Chris@386
|
27
|
Chris@386
|
28 #include <QString>
|
Chris@386
|
29 #include <QFileInfo>
|
Chris@386
|
30 #include <iostream>
|
Chris@386
|
31
|
Chris@1161
|
32 //#define DEBUG_AUDIO_FILE_READER_FACTORY 1
|
Chris@1161
|
33
|
Chris@386
|
34 QString
|
Chris@386
|
35 AudioFileReaderFactory::getKnownExtensions()
|
Chris@386
|
36 {
|
Chris@386
|
37 std::set<QString> extensions;
|
Chris@386
|
38
|
Chris@386
|
39 WavFileReader::getSupportedExtensions(extensions);
|
Chris@386
|
40 #ifdef HAVE_MAD
|
Chris@386
|
41 MP3FileReader::getSupportedExtensions(extensions);
|
Chris@386
|
42 #endif
|
Chris@386
|
43 #ifdef HAVE_OGGZ
|
Chris@386
|
44 #ifdef HAVE_FISHSOUND
|
Chris@386
|
45 OggVorbisFileReader::getSupportedExtensions(extensions);
|
Chris@386
|
46 #endif
|
Chris@386
|
47 #endif
|
Chris@386
|
48 #ifdef HAVE_QUICKTIME
|
Chris@386
|
49 QuickTimeFileReader::getSupportedExtensions(extensions);
|
Chris@386
|
50 #endif
|
luisf@665
|
51 #ifdef HAVE_COREAUDIO
|
luisf@665
|
52 CoreAudioFileReader::getSupportedExtensions(extensions);
|
luisf@665
|
53 #endif
|
Chris@386
|
54
|
Chris@386
|
55 QString rv;
|
Chris@386
|
56 for (std::set<QString>::const_iterator i = extensions.begin();
|
Chris@386
|
57 i != extensions.end(); ++i) {
|
Chris@386
|
58 if (i != extensions.begin()) rv += " ";
|
Chris@386
|
59 rv += "*." + *i;
|
Chris@386
|
60 }
|
Chris@386
|
61
|
Chris@386
|
62 return rv;
|
Chris@386
|
63 }
|
Chris@386
|
64
|
Chris@386
|
65 AudioFileReader *
|
Chris@920
|
66 AudioFileReaderFactory::createReader(FileSource source,
|
Chris@1040
|
67 sv_samplerate_t targetRate,
|
Chris@920
|
68 bool normalised,
|
Chris@392
|
69 ProgressReporter *reporter)
|
Chris@386
|
70 {
|
Chris@920
|
71 return create(source, targetRate, normalised, false, reporter);
|
Chris@386
|
72 }
|
Chris@386
|
73
|
Chris@386
|
74 AudioFileReader *
|
Chris@920
|
75 AudioFileReaderFactory::createThreadingReader(FileSource source,
|
Chris@1040
|
76 sv_samplerate_t targetRate,
|
Chris@920
|
77 bool normalised,
|
Chris@392
|
78 ProgressReporter *reporter)
|
Chris@386
|
79 {
|
Chris@920
|
80 return create(source, targetRate, normalised, true, reporter);
|
Chris@386
|
81 }
|
Chris@386
|
82
|
Chris@386
|
83 AudioFileReader *
|
Chris@920
|
84 AudioFileReaderFactory::create(FileSource source,
|
Chris@1040
|
85 sv_samplerate_t targetRate,
|
Chris@920
|
86 bool normalised,
|
Chris@920
|
87 bool threading,
|
Chris@392
|
88 ProgressReporter *reporter)
|
Chris@386
|
89 {
|
Chris@386
|
90 QString err;
|
Chris@386
|
91
|
Chris@1161
|
92 #ifdef DEBUG_AUDIO_FILE_READER_FACTORY
|
Chris@1161
|
93 cerr << "AudioFileReaderFactory::createReader(\"" << source.getLocation() << "\"): Requested rate: " << targetRate << endl;
|
Chris@1161
|
94 #endif
|
Chris@386
|
95
|
Chris@667
|
96 if (!source.isOK()) {
|
Chris@843
|
97 cerr << "AudioFileReaderFactory::createReader(\"" << source.getLocation() << "\": Failed to retrieve source (transmission error?): " << source.getErrorString() << endl;
|
Chris@667
|
98 return 0;
|
Chris@667
|
99 }
|
Chris@667
|
100
|
Chris@667
|
101 if (!source.isAvailable()) {
|
Chris@1161
|
102 cerr << "AudioFileReaderFactory::createReader(\"" << source.getLocation() << "\": Source not found" << endl;
|
Chris@386
|
103 return 0;
|
Chris@386
|
104 }
|
Chris@386
|
105
|
Chris@386
|
106 AudioFileReader *reader = 0;
|
Chris@386
|
107
|
Chris@1098
|
108 sv_frame_t estimatedSamples =
|
Chris@1098
|
109 AudioFileSizeEstimator::estimate(source, targetRate);
|
Chris@1098
|
110
|
Chris@1097
|
111 CodedAudioFileReader::CacheMode cacheMode =
|
Chris@1097
|
112 CodedAudioFileReader::CacheInTemporaryFile;
|
Chris@1097
|
113
|
Chris@1098
|
114 if (estimatedSamples > 0) {
|
Chris@1098
|
115 size_t kb = (estimatedSamples * sizeof(float)) / 1024;
|
Chris@1098
|
116 StorageAdviser::Recommendation rec =
|
Chris@1098
|
117 StorageAdviser::recommend(StorageAdviser::SpeedCritical, kb, kb);
|
Chris@1098
|
118 if (rec == StorageAdviser::UseMemory ||
|
Chris@1098
|
119 rec == StorageAdviser::PreferMemory) {
|
Chris@1098
|
120 cacheMode = CodedAudioFileReader::CacheInMemory;
|
Chris@1098
|
121 }
|
Chris@1098
|
122 }
|
Chris@1098
|
123
|
Chris@1097
|
124 CodedAudioFileReader::DecodeMode decodeMode =
|
Chris@1097
|
125 (threading ?
|
Chris@1097
|
126 CodedAudioFileReader::DecodeThreaded :
|
Chris@1097
|
127 CodedAudioFileReader::DecodeAtOnce);
|
Chris@1097
|
128
|
Chris@386
|
129 // Try to construct a preferred reader based on the extension or
|
Chris@386
|
130 // MIME type.
|
Chris@386
|
131
|
Chris@1097
|
132 #define CHECK(reader) if (!reader->isOK()) { delete reader; reader = 0; }
|
Chris@1097
|
133
|
Chris@386
|
134 if (WavFileReader::supports(source)) {
|
Chris@386
|
135
|
Chris@386
|
136 reader = new WavFileReader(source);
|
Chris@386
|
137
|
Chris@1040
|
138 sv_samplerate_t fileRate = reader->getSampleRate();
|
Chris@386
|
139
|
Chris@823
|
140 if (reader->isOK() &&
|
Chris@823
|
141 (!reader->isQuicklySeekable() ||
|
Chris@920
|
142 normalised ||
|
Chris@1101
|
143 (cacheMode == CodedAudioFileReader::CacheInMemory) ||
|
Chris@823
|
144 (targetRate != 0 && fileRate != targetRate))) {
|
Chris@823
|
145
|
Chris@1161
|
146 #ifdef DEBUG_AUDIO_FILE_READER_FACTORY
|
Chris@1170
|
147 cerr << "AudioFileReaderFactory::createReader: WAV file rate: " << reader->getSampleRate() << ", normalised " << normalised << ", seekable " << reader->isQuicklySeekable() << ", in memory " << (cacheMode == CodedAudioFileReader::CacheInMemory) << ", creating decoding reader" << endl;
|
Chris@1161
|
148 #endif
|
Chris@1161
|
149
|
Chris@386
|
150 delete reader;
|
Chris@823
|
151 reader = new DecodingWavFileReader
|
Chris@386
|
152 (source,
|
Chris@1097
|
153 decodeMode, cacheMode,
|
Chris@823
|
154 targetRate ? targetRate : fileRate,
|
Chris@920
|
155 normalised,
|
Chris@392
|
156 reporter);
|
Chris@1097
|
157 CHECK(reader);
|
Chris@386
|
158 }
|
Chris@386
|
159 }
|
Chris@386
|
160
|
Chris@386
|
161 #ifdef HAVE_OGGZ
|
Chris@386
|
162 #ifdef HAVE_FISHSOUND
|
Chris@1097
|
163 if (!reader && OggVorbisFileReader::supports(source)) {
|
Chris@1097
|
164 reader = new OggVorbisFileReader
|
Chris@1097
|
165 (source, decodeMode, cacheMode, targetRate, normalised, reporter);
|
Chris@1097
|
166 CHECK(reader);
|
Chris@386
|
167 }
|
Chris@386
|
168 #endif
|
Chris@386
|
169 #endif
|
Chris@386
|
170
|
Chris@386
|
171 #ifdef HAVE_MAD
|
Chris@1097
|
172 if (!reader && MP3FileReader::supports(source)) {
|
Chris@1097
|
173 reader = new MP3FileReader
|
Chris@1097
|
174 (source, decodeMode, cacheMode, targetRate, normalised, reporter);
|
Chris@1097
|
175 CHECK(reader);
|
Chris@386
|
176 }
|
Chris@386
|
177 #endif
|
Chris@386
|
178
|
Chris@386
|
179 #ifdef HAVE_QUICKTIME
|
Chris@1097
|
180 if (!reader && QuickTimeFileReader::supports(source)) {
|
Chris@1097
|
181 reader = new QuickTimeFileReader
|
Chris@1097
|
182 (source, decodeMode, cacheMode, targetRate, normalised, reporter);
|
Chris@1097
|
183 CHECK(reader);
|
Chris@440
|
184 }
|
Chris@440
|
185 #endif
|
Chris@440
|
186
|
luisf@665
|
187 #ifdef HAVE_COREAUDIO
|
Chris@1097
|
188 if (!reader && CoreAudioFileReader::supports(source)) {
|
Chris@1097
|
189 reader = new CoreAudioFileReader
|
Chris@1097
|
190 (source, decodeMode, cacheMode, targetRate, normalised, reporter);
|
Chris@1097
|
191 CHECK(reader);
|
luisf@665
|
192 }
|
luisf@665
|
193 #endif
|
luisf@665
|
194
|
Chris@1097
|
195 if (reader) {
|
Chris@1097
|
196 // The happy case: a reader recognised the file extension &
|
Chris@1097
|
197 // succeeded in opening the file
|
Chris@1097
|
198 return reader;
|
Chris@1097
|
199 }
|
Chris@1097
|
200
|
Chris@440
|
201 // If none of the readers claimed to support this file extension,
|
Chris@440
|
202 // perhaps the extension is missing or misleading. Try again,
|
Chris@440
|
203 // ignoring it. We have to be confident that the reader won't
|
Chris@440
|
204 // open just any old text file or whatever and pretend it's
|
Chris@440
|
205 // succeeded
|
Chris@440
|
206
|
Chris@1097
|
207 reader = new WavFileReader(source);
|
Chris@440
|
208
|
Chris@1097
|
209 sv_samplerate_t fileRate = reader->getSampleRate();
|
Chris@440
|
210
|
Chris@1097
|
211 if (reader->isOK() &&
|
Chris@1097
|
212 (!reader->isQuicklySeekable() ||
|
Chris@1097
|
213 normalised ||
|
Chris@1101
|
214 (cacheMode == CodedAudioFileReader::CacheInMemory) ||
|
Chris@1097
|
215 (targetRate != 0 && fileRate != targetRate))) {
|
Chris@823
|
216
|
Chris@1161
|
217 #ifdef DEBUG_AUDIO_FILE_READER_FACTORY
|
Chris@1170
|
218 cerr << "AudioFileReaderFactory::createReader: WAV file rate: " << reader->getSampleRate() << ", normalised " << normalised << ", seekable " << reader->isQuicklySeekable() << ", in memory " << (cacheMode == CodedAudioFileReader::CacheInMemory) << ", creating decoding reader" << endl;
|
Chris@1161
|
219 #endif
|
Chris@440
|
220
|
Chris@1097
|
221 delete reader;
|
Chris@1097
|
222 reader = new DecodingWavFileReader
|
Chris@1097
|
223 (source,
|
Chris@1097
|
224 decodeMode, cacheMode,
|
Chris@1097
|
225 targetRate ? targetRate : fileRate,
|
Chris@1097
|
226 normalised,
|
Chris@1097
|
227 reporter);
|
Chris@1097
|
228 }
|
Chris@440
|
229
|
Chris@1097
|
230 CHECK(reader);
|
Chris@440
|
231
|
Chris@440
|
232 #ifdef HAVE_OGGZ
|
Chris@440
|
233 #ifdef HAVE_FISHSOUND
|
Chris@440
|
234 if (!reader) {
|
Chris@440
|
235 reader = new OggVorbisFileReader
|
Chris@1097
|
236 (source, decodeMode, cacheMode, targetRate, normalised, reporter);
|
Chris@1097
|
237 CHECK(reader);
|
Chris@440
|
238 }
|
Chris@440
|
239 #endif
|
Chris@440
|
240 #endif
|
Chris@440
|
241
|
Chris@440
|
242 #ifdef HAVE_MAD
|
Chris@440
|
243 if (!reader) {
|
Chris@440
|
244 reader = new MP3FileReader
|
Chris@1097
|
245 (source, decodeMode, cacheMode, targetRate, normalised, reporter);
|
Chris@1097
|
246 CHECK(reader);
|
Chris@440
|
247 }
|
Chris@440
|
248 #endif
|
Chris@440
|
249
|
Chris@440
|
250 #ifdef HAVE_QUICKTIME
|
Chris@440
|
251 if (!reader) {
|
Chris@440
|
252 reader = new QuickTimeFileReader
|
Chris@1097
|
253 (source, decodeMode, cacheMode, targetRate, normalised, reporter);
|
Chris@1097
|
254 CHECK(reader);
|
Chris@386
|
255 }
|
Chris@386
|
256 #endif
|
Chris@386
|
257
|
luisf@665
|
258 #ifdef HAVE_COREAUDIO
|
luisf@665
|
259 if (!reader) {
|
luisf@665
|
260 reader = new CoreAudioFileReader
|
Chris@1097
|
261 (source, decodeMode, cacheMode, targetRate, normalised, reporter);
|
Chris@1097
|
262 CHECK(reader);
|
luisf@665
|
263 }
|
luisf@665
|
264 #endif
|
luisf@665
|
265
|
Chris@1097
|
266 if (!reader) {
|
Chris@1097
|
267 cerr << "AudioFileReaderFactory::Failed to create a reader for "
|
Chris@1097
|
268 << "url \"" << source.getLocation()
|
Chris@1097
|
269 << "\" (content type \""
|
Chris@1097
|
270 << source.getContentType() << "\")" << endl;
|
Chris@1097
|
271 return nullptr;
|
Chris@386
|
272 }
|
Chris@1097
|
273
|
Chris@386
|
274 return reader;
|
Chris@386
|
275 }
|
Chris@386
|
276
|