annotate data/fileio/CoreAudioFileReader.cpp @ 795:dc20458f6f85 qt5

Don't need to check for Dataquay, and in fact we can pick up the wrong version if we do. Just assume it is available (building in e.g. sv subdir configuration)
author Chris Cannam
date Tue, 07 May 2013 15:41:58 +0100
parents 12f78ebc82bf
children 51cf0c35e9b0
rev   line source
luisf@665 1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
luisf@665 2
luisf@665 3 /*
luisf@665 4 Sonic Visualiser
luisf@665 5 An audio file viewer and annotation editor.
luisf@665 6 Centre for Digital Music, Queen Mary, University of London.
Chris@748 7 This file copyright 2006-2012 Chris Cannam and QMUL.
luisf@665 8
luisf@665 9 This program is free software; you can redistribute it and/or
luisf@665 10 modify it under the terms of the GNU General Public License as
luisf@665 11 published by the Free Software Foundation; either version 2 of the
luisf@665 12 License, or (at your option) any later version. See the file
luisf@665 13 COPYING included with this distribution for more information.
luisf@665 14 */
luisf@665 15
luisf@665 16 #ifdef HAVE_COREAUDIO
luisf@665 17
luisf@665 18 #include "CoreAudioFileReader.h"
luisf@665 19 #include "base/Profiler.h"
luisf@665 20 #include "base/ProgressReporter.h"
luisf@665 21 #include "system/System.h"
luisf@665 22
luisf@665 23 #include <QFileInfo>
luisf@665 24
luisf@665 25 #if !defined(__COREAUDIO_USE_FLAT_INCLUDES__)
luisf@665 26 #include <AudioToolbox/AudioToolbox.h>
Chris@743 27 #include <AudioToolbox/ExtendedAudioFile.h>
luisf@665 28 #else
luisf@665 29 #include "AudioToolbox.h"
luisf@665 30 #include "ExtendedAudioFile.h"
luisf@665 31 #endif
luisf@665 32
luisf@665 33 class CoreAudioFileReader::D
luisf@665 34 {
luisf@665 35 public:
Chris@743 36 D() : blockSize(1024) { }
luisf@665 37
Chris@743 38 ExtAudioFileRef file;
Chris@743 39 AudioBufferList buffer;
Chris@743 40 OSStatus err;
Chris@743 41 AudioStreamBasicDescription asbd;
Chris@743 42 int blockSize;
luisf@665 43 };
luisf@665 44
Chris@743 45 static QString
Chris@743 46 codestr(OSStatus err)
Chris@743 47 {
Chris@743 48 char text[5];
Chris@743 49 UInt32 uerr = err;
Chris@743 50 text[0] = (uerr >> 24) & 0xff;
Chris@743 51 text[1] = (uerr >> 16) & 0xff;
Chris@743 52 text[2] = (uerr >> 8) & 0xff;
Chris@743 53 text[3] = (uerr) & 0xff;
Chris@743 54 text[4] = '\0';
Chris@794 55 return QString("%1 (%2)").arg(err).arg(QString::fromLocal8Bit(text));
Chris@743 56 }
luisf@665 57
luisf@665 58 CoreAudioFileReader::CoreAudioFileReader(FileSource source,
Chris@743 59 DecodeMode decodeMode,
Chris@743 60 CacheMode mode,
Chris@743 61 size_t targetRate,
Chris@743 62 ProgressReporter *reporter) :
luisf@665 63 CodedAudioFileReader(mode, targetRate),
luisf@665 64 m_source(source),
luisf@665 65 m_path(source.getLocalFilename()),
luisf@665 66 m_d(new D),
luisf@665 67 m_reporter(reporter),
luisf@665 68 m_cancelled(false),
luisf@665 69 m_completion(0),
luisf@665 70 m_decodeThread(0)
luisf@665 71 {
Chris@743 72 m_channelCount = 0;
Chris@743 73 m_fileRate = 0;
luisf@665 74
Chris@760 75 m_d->buffer.mBuffers[0].mData = 0;
Chris@760 76
Chris@743 77 Profiler profiler("CoreAudioFileReader::CoreAudioFileReader", true);
luisf@665 78
Chris@759 79 SVDEBUG << "CoreAudioFileReader: path is \"" << m_path.toStdString() << "\"" << endl;
luisf@665 80
Chris@743 81 QByteArray ba = m_path.toLocal8Bit();
luisf@665 82
Chris@743 83 CFURLRef url = CFURLCreateFromFileSystemRepresentation
Chris@743 84 (kCFAllocatorDefault,
Chris@743 85 (const UInt8 *)ba.data(),
Chris@743 86 (CFIndex)ba.length(),
Chris@743 87 false);
luisf@665 88
Chris@743 89 //!!! how do we find out if the file open fails because of DRM protection?
luisf@665 90
Chris@743 91 #if (MACOSX_DEPLOYMENT_TARGET <= 1040 && MAC_OS_X_VERSION_MIN_REQUIRED <= 1040)
Chris@743 92 FSRef fsref;
Chris@743 93 if (!CFURLGetFSRef(url, &fsref)) { // returns Boolean, not error code
Chris@743 94 m_error = "CoreAudioReadStream: Error looking up FS ref (file not found?)";
Chris@743 95 return;
Chris@743 96 }
Chris@743 97 m_d->err = ExtAudioFileOpen(&fsref, &m_d->file);
Chris@743 98 #else
Chris@743 99 m_d->err = ExtAudioFileOpenURL(url, &m_d->file);
Chris@743 100 #endif
luisf@665 101
Chris@743 102 CFRelease(url);
luisf@665 103
Chris@743 104 if (m_d->err) {
Chris@743 105 m_error = "CoreAudioReadStream: Error opening file: code " + codestr(m_d->err);
Chris@743 106 return;
Chris@743 107 }
Chris@743 108 if (!m_d->file) {
Chris@743 109 m_error = "CoreAudioReadStream: Failed to open file, but no error reported!";
Chris@743 110 return;
Chris@743 111 }
Chris@743 112
Chris@743 113 UInt32 propsize = sizeof(AudioStreamBasicDescription);
Chris@743 114 m_d->err = ExtAudioFileGetProperty
Chris@743 115 (m_d->file, kExtAudioFileProperty_FileDataFormat, &propsize, &m_d->asbd);
Chris@743 116
Chris@743 117 if (m_d->err) {
Chris@743 118 m_error = "CoreAudioReadStream: Error in getting basic description: code " + codestr(m_d->err);
Chris@743 119 return;
Chris@743 120 }
Chris@743 121
Chris@743 122 m_channelCount = m_d->asbd.mChannelsPerFrame;
Chris@755 123 m_fileRate = m_d->asbd.mSampleRate;
luisf@665 124
Chris@759 125 std::cerr << "CoreAudioReadStream: " << m_channelCount << " channels, " << m_fileRate << " Hz" << std::endl;
luisf@665 126
Chris@743 127 m_d->asbd.mFormatID = kAudioFormatLinearPCM;
Chris@743 128 m_d->asbd.mFormatFlags =
Chris@743 129 kAudioFormatFlagIsFloat |
Chris@743 130 kAudioFormatFlagIsPacked |
Chris@743 131 kAudioFormatFlagsNativeEndian;
Chris@743 132 m_d->asbd.mBitsPerChannel = sizeof(float) * 8;
Chris@743 133 m_d->asbd.mBytesPerFrame = sizeof(float) * m_channelCount;
Chris@743 134 m_d->asbd.mBytesPerPacket = sizeof(float) * m_channelCount;
Chris@743 135 m_d->asbd.mFramesPerPacket = 1;
Chris@743 136 m_d->asbd.mReserved = 0;
Chris@743 137
Chris@743 138 m_d->err = ExtAudioFileSetProperty
Chris@743 139 (m_d->file, kExtAudioFileProperty_ClientDataFormat, propsize, &m_d->asbd);
Chris@743 140
Chris@743 141 if (m_d->err) {
Chris@743 142 m_error = "CoreAudioReadStream: Error in setting client format: code " + codestr(m_d->err);
Chris@743 143 return;
Chris@743 144 }
luisf@665 145
Chris@743 146 m_d->buffer.mNumberBuffers = 1;
Chris@743 147 m_d->buffer.mBuffers[0].mNumberChannels = m_channelCount;
Chris@743 148 m_d->buffer.mBuffers[0].mDataByteSize = sizeof(float) * m_channelCount * m_d->blockSize;
Chris@743 149 m_d->buffer.mBuffers[0].mData = new float[m_channelCount * m_d->blockSize];
luisf@665 150
Chris@743 151 initialiseDecodeCache();
luisf@665 152
Chris@743 153 if (m_reporter) {
Chris@743 154 connect(m_reporter, SIGNAL(cancelled()), this, SLOT(cancelled()));
Chris@743 155 m_reporter->setMessage
Chris@743 156 (tr("Decoding %1...").arg(QFileInfo(m_path).fileName()));
Chris@743 157 }
luisf@665 158
Chris@743 159 while (1) {
luisf@665 160
Chris@743 161 UInt32 framesRead = m_d->blockSize;
Chris@743 162 m_d->err = ExtAudioFileRead(m_d->file, &framesRead, &m_d->buffer);
luisf@665 163
Chris@743 164 if (m_d->err) {
Chris@743 165 m_error = QString("Error in CoreAudio decoding: code %1")
Chris@743 166 .arg(m_d->err);
Chris@743 167 break;
Chris@743 168 }
luisf@665 169
Chris@743 170 //!!! progress?
luisf@665 171
Chris@743 172 // std::cerr << "Read " << framesRead << " frames (block size " << m_d->blockSize << ")" << std::endl;
luisf@665 173
Chris@743 174 // buffers are interleaved unless specified otherwise
Chris@743 175 addSamplesToDecodeCache((float *)m_d->buffer.mBuffers[0].mData, framesRead);
luisf@665 176
Chris@743 177 if (framesRead < m_d->blockSize) break;
Chris@743 178 }
luisf@665 179
Chris@743 180 finishDecodeCache();
Chris@743 181 endSerialised();
luisf@665 182
Chris@743 183 m_completion = 100;
luisf@665 184
Chris@743 185 ExtAudioFileDispose(m_d->file);
luisf@665 186 }
luisf@665 187
luisf@665 188
luisf@665 189 CoreAudioFileReader::~CoreAudioFileReader()
luisf@665 190 {
Chris@743 191 std::cerr << "CoreAudioFileReader::~CoreAudioFileReader" << std::endl;
Chris@743 192 delete[] m_d->buffer.mBuffers[0].mData;
Chris@743 193 delete m_d;
luisf@665 194 }
luisf@665 195
luisf@665 196 void
luisf@665 197 CoreAudioFileReader::cancelled()
luisf@665 198 {
luisf@665 199 m_cancelled = true;
luisf@665 200 }
luisf@665 201
luisf@665 202 void
luisf@665 203 CoreAudioFileReader::getSupportedExtensions(std::set<QString> &extensions)
luisf@665 204 {
Chris@743 205 extensions.insert("aiff");
Chris@743 206 extensions.insert("aif");
Chris@743 207 extensions.insert("au");
Chris@743 208 extensions.insert("m4a");
Chris@743 209 extensions.insert("m4b");
Chris@743 210 extensions.insert("m4p");
Chris@743 211 extensions.insert("mp3");
Chris@743 212 extensions.insert("mp4");
Chris@743 213 extensions.insert("wav");
luisf@665 214 }
luisf@665 215
luisf@665 216 bool
luisf@665 217 CoreAudioFileReader::supportsExtension(QString extension)
luisf@665 218 {
Chris@743 219 std::set<QString> extensions;
Chris@743 220 getSupportedExtensions(extensions);
Chris@743 221 return (extensions.find(extension.toLower()) != extensions.end());
luisf@665 222 }
luisf@665 223
luisf@665 224 bool
luisf@665 225 CoreAudioFileReader::supportsContentType(QString type)
luisf@665 226 {
Chris@743 227 return (type == "audio/x-aiff" ||
Chris@743 228 type == "audio/x-wav" ||
Chris@743 229 type == "audio/mpeg" ||
Chris@743 230 type == "audio/basic" ||
Chris@749 231 type == "audio/x-aac");
luisf@665 232 }
luisf@665 233
luisf@665 234 bool
luisf@665 235 CoreAudioFileReader::supports(FileSource &source)
luisf@665 236 {
Chris@743 237 return (supportsExtension(source.getExtension()) ||
Chris@743 238 supportsContentType(source.getContentType()));
luisf@665 239 }
luisf@665 240
luisf@665 241 #endif
luisf@665 242