comparison data/fileio/CoreAudioFileReader.cpp @ 665:029dd9e5cc29 coreaudio_tests

tests for using coreaudio to read files in 64-bit mac osx
author luisf
date Thu, 18 Nov 2010 11:40:38 +0000
parents
children 964a20b5a747
comparison
equal deleted inserted replaced
623:f19437971e17 665:029dd9e5cc29
1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
2
3 /*
4 Sonic Visualiser
5 An audio file viewer and annotation editor.
6 Centre for Digital Music, Queen Mary, University of London.
7 This file copyright 2006-2007 Chris Cannam and QMUL.
8
9 Based on QTAudioFile.cpp from SoundBite, copyright 2006
10 Chris Sutton and Mark Levy.
11
12 This program is free software; you can redistribute it and/or
13 modify it under the terms of the GNU General Public License as
14 published by the Free Software Foundation; either version 2 of the
15 License, or (at your option) any later version. See the file
16 COPYING included with this distribution for more information.
17 */
18
19 #ifdef HAVE_COREAUDIO
20
21 #include "CoreAudioFileReader.h"
22 #include "base/Profiler.h"
23 #include "base/ProgressReporter.h"
24 #include "system/System.h"
25
26 #include <QFileInfo>
27
28
29 // TODO: implement for windows
30 #ifdef _WIN32
31 #include <QTML.h>
32 #include <Movies.h>
33 #else
34
35
36 #if !defined(__COREAUDIO_USE_FLAT_INCLUDES__)
37 #include <AudioToolbox/AudioToolbox.h>
38 #else
39 #include "AudioToolbox.h"
40 #include "ExtendedAudioFile.h"
41 #endif
42
43 #include "CAStreamBasicDescription.h"
44 #include "CAXException.h"
45
46
47
48
49 #endif
50
51 class CoreAudioFileReader::D
52 {
53 public:
54 D() : data(0), blockSize(1024) { }
55
56 AudioBufferList buffer;
57 float *data;
58 OSErr err;
59 AudioStreamBasicDescription asbd;
60 // file reference
61
62 ExtAudioFileRef *infile;
63 size_t blockSize;
64 };
65
66
67 CoreAudioFileReader::CoreAudioFileReader(FileSource source,
68 DecodeMode decodeMode,
69 CacheMode mode,
70 size_t targetRate,
71 ProgressReporter *reporter) :
72 CodedAudioFileReader(mode, targetRate),
73 m_source(source),
74 m_path(source.getLocalFilename()),
75 m_d(new D),
76 m_reporter(reporter),
77 m_cancelled(false),
78 m_completion(0),
79 m_decodeThread(0)
80 {
81 m_channelCount = 0;
82 m_fileRate = 0;
83
84 Profiler profiler("CoreAudioFileReader::CoreAudioFileReader", true);
85
86 std::cerr << "CoreAudioFileReader: path is \"" << m_path.toStdString() << "\"" << std::endl;
87
88 // TODO: check QT version
89
90 Handle dataRef;
91 OSType dataRefType;
92
93 // CFStringRef URLString = CFStringCreateWithCString
94 // (0, m_path.toLocal8Bit().data(), 0);
95
96 // what are these used for???
97 // ExtAudioFileRef *infile, outfile;
98
99 // Creates a new CFURL object for a file system entity using the native representation.
100 CFURLRef url = CFURLCreateFromFileSystemRepresentation
101 (kCFAllocatorDefault,
102 (const UInt8 *)m_path.toLocal8Bit().data(),
103 (CFIndex)m_path.length(),
104 false);
105
106 // first open the input file
107 m_d->err = ExtAudioFileOpenURL (url, m_d->infile);
108
109 if (m_d->err) {
110 m_error = QString("Error opening Audio File for CoreAudio decoder: code %1").arg(m_d->err);
111 return;
112 }
113 else {
114 std::cerr << "CoreAudio: opened URL" << std::endl;
115 }
116
117
118 // Get the audio data format
119 // the audio format gets stored in the &m_d->asbd
120 UInt32 thePropertySize = sizeof(m_d->asbd);
121
122
123 std::cerr << "CoreAudio: thePropertySize: " << thePropertySize << std::endl;
124
125 m_d->err = ExtAudioFileGetProperty(*m_d->infile, kAudioFilePropertyDataFormat, &thePropertySize, &m_d->asbd);
126
127 std::cerr << "CoreAudio: ExtAudioFileGetProperty res: " << &m_d->asbd << std::endl;
128
129 // CAStreamBasicDescription clientFormat = (inputFormat.mFormatID == kAudioFormatLinearPCM ? inputFormat : outputFormat);
130 // UInt32 size = sizeof(clientFormat);
131
132 // TODO: test input file's DRM rights
133
134 // are these already set?
135 m_channelCount = m_d->asbd.mChannelsPerFrame;
136 m_fileRate = m_d->asbd.mSampleRate;
137
138 std::cerr << "CoreAudio: Format ID: " << m_d->asbd.mFormatID << std::endl;
139 std::cerr << "CoreAudio: " << m_d->asbd.mChannelsPerFrame << " channels, " << m_fileRate << " kHz" << std::endl;
140
141
142
143 m_d->asbd.mFormatFlags =
144 kAudioFormatFlagIsFloat |
145 kAudioFormatFlagIsPacked |
146 kAudioFormatFlagsNativeEndian;
147 m_d->asbd.mBitsPerChannel = sizeof(float) * 8;
148 m_d->asbd.mBytesPerFrame = sizeof(float) * m_d->asbd.mChannelsPerFrame;
149 m_d->asbd.mBytesPerPacket = m_d->asbd.mBytesPerFrame;
150
151
152
153 /*
154
155 !!! what does this do exactly ?????
156
157 m_d->err = MovieAudioExtractionSetProperty
158 (m_d->extractionSessionRef,
159 kQTPropertyClass_MovieAudioExtraction_Audio,
160 kQTMovieAudioExtractionAudioPropertyID_AudioStreamBasicDescription,
161 sizeof(m_d->asbd),
162 &m_d->asbd);
163
164
165
166 if (m_d->err) {
167 m_error = QString("Error in QuickTime decoder property set: code %1").arg(m_d->err);
168 m_channelCount = 0;
169 return;
170 }
171
172 */
173
174 m_d->buffer.mNumberBuffers = 1;
175 m_d->buffer.mBuffers[0].mNumberChannels = m_channelCount;
176 m_d->buffer.mBuffers[0].mDataByteSize =
177 sizeof(float) * m_channelCount * m_d->blockSize;
178 m_d->data = new float[m_channelCount * m_d->blockSize];
179 m_d->buffer.mBuffers[0].mData = m_d->data;
180
181 initialiseDecodeCache();
182
183 // only decode at once for now
184 // if (decodeMode == DecodeAtOnce) {
185
186 if (m_reporter) {
187 connect(m_reporter, SIGNAL(cancelled()), this, SLOT(cancelled()));
188 m_reporter->setMessage
189 (tr("Decoding %1...").arg(QFileInfo(m_path).fileName()));
190 }
191
192 while (1) {
193
194 UInt32 framesRead = m_d->blockSize;
195
196 m_d->err = ExtAudioFileRead (*m_d->infile, &framesRead, &m_d->buffer);
197
198 if (m_d->err) {
199 m_error = QString("Error in CoreAudio decoding: code %1")
200 .arg(m_d->err);
201 break;
202 }
203
204 //!!! progress?
205
206 // std::cerr << "Read " << framesRead << " frames (block size " << m_d->blockSize << ")" << std::endl;
207
208 // QuickTime buffers are interleaved unless specified otherwise
209 addSamplesToDecodeCache(m_d->data, framesRead);
210
211 if (framesRead < m_d->blockSize) break;
212 }
213
214 finishDecodeCache();
215 endSerialised();
216
217 /*
218 TODO - close session
219 m_d->err = MovieAudioExtractionEnd(m_d->extractionSessionRef);
220 if (m_d->err) {
221 m_error = QString("Error ending QuickTime extraction session: code %1").arg(m_d->err);
222 }
223 */
224 m_completion = 100;
225
226
227
228 // } else {
229 // if (m_reporter) m_reporter->setProgress(100);
230 //
231 // if (m_channelCount > 0) {
232 // m_decodeThread = new DecodeThread(this);
233 // m_decodeThread->start();
234 // }
235 // }
236
237 std::cerr << "QuickTimeFileReader::QuickTimeFileReader: frame count is now " << getFrameCount() << ", error is \"\"" << m_error.toStdString() << "\"" << std::endl;
238 }
239
240
241
242
243
244 CoreAudioFileReader::~CoreAudioFileReader()
245 {
246 std::cerr << "CoreAudioFileReader::~CoreAudioFileReader" << std::endl;
247
248 if (m_decodeThread) {
249 m_cancelled = true;
250 m_decodeThread->wait();
251 delete m_decodeThread;
252 }
253
254 // SetMovieActive(m_d->movie, FALSE);
255 // DisposeMovie(m_d->movie);
256
257 delete[] m_d->data;
258 delete m_d;
259 }
260
261 void
262 CoreAudioFileReader::cancelled()
263 {
264 m_cancelled = true;
265 }
266
267 /*
268 void
269 CoreAudioFileReader::DecodeThread::run()
270 {
271 if (m_reader->m_cacheMode == CacheInTemporaryFile) {
272 m_reader->m_completion = 1;
273 m_reader->startSerialised("QuickTimeFileReader::Decode");
274 }
275
276 while (1) {
277
278 UInt32 framesRead = m_reader->m_d->blockSize;
279 UInt32 extractionFlags = 0;
280 m_reader->m_d->err = MovieAudioExtractionFillBuffer
281 (m_reader->m_d->extractionSessionRef, &framesRead,
282 &m_reader->m_d->buffer, &extractionFlags);
283 if (m_reader->m_d->err) {
284 m_reader->m_error = QString("Error in QuickTime decoding: code %1")
285 .arg(m_reader->m_d->err);
286 break;
287 }
288
289 // QuickTime buffers are interleaved unless specified otherwise
290 m_reader->addSamplesToDecodeCache(m_reader->m_d->data, framesRead);
291
292 if (framesRead < m_reader->m_d->blockSize) break;
293 }
294
295 m_reader->finishDecodeCache();
296
297 m_reader->m_d->err = MovieAudioExtractionEnd(m_reader->m_d->extractionSessionRef);
298 if (m_reader->m_d->err) {
299 m_reader->m_error = QString("Error ending QuickTime extraction session: code %1").arg(m_reader->m_d->err);
300 }
301
302 m_reader->m_completion = 100;
303 m_reader->endSerialised();
304 }
305 */
306
307
308 void
309 CoreAudioFileReader::getSupportedExtensions(std::set<QString> &extensions)
310 {
311 extensions.insert("aiff");
312 extensions.insert("aif");
313 extensions.insert("au");
314 extensions.insert("avi");
315 extensions.insert("m4a");
316 extensions.insert("m4b");
317 extensions.insert("m4p");
318 extensions.insert("m4v");
319 extensions.insert("mov");
320 extensions.insert("mp3");
321 extensions.insert("mp4");
322 extensions.insert("wav");
323 }
324
325 bool
326 CoreAudioFileReader::supportsExtension(QString extension)
327 {
328 std::set<QString> extensions;
329 getSupportedExtensions(extensions);
330 return (extensions.find(extension.toLower()) != extensions.end());
331 }
332
333 bool
334 CoreAudioFileReader::supportsContentType(QString type)
335 {
336 return (type == "audio/x-aiff" ||
337 type == "audio/x-wav" ||
338 type == "audio/mpeg" ||
339 type == "audio/basic" ||
340 type == "audio/x-aac" ||
341 type == "video/mp4" ||
342 type == "video/quicktime");
343 }
344
345 bool
346 CoreAudioFileReader::supports(FileSource &source)
347 {
348 return (supportsExtension(source.getExtension()) ||
349 supportsContentType(source.getContentType()));
350 }
351
352 #endif
353