annotate data/fileio/CoreAudioFileReader.cpp @ 875:3e6ed8a8577b tonioni

Use a sparse time-value model only for outputs with fixed bin count of 1, not for those with unknown bin count. (Precursor to using more than one model for outputs with unknown bin count)
author Chris Cannam
date Tue, 28 Jan 2014 18:52:22 +0000
parents 2d53205f70cd
children f3cda3280398 59e7fe1b1003
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@819 36 D() : blockSize(1024), valid(false) { }
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;
Chris@819 43 bool valid;
luisf@665 44 };
luisf@665 45
Chris@743 46 static QString
Chris@743 47 codestr(OSStatus err)
Chris@743 48 {
Chris@743 49 char text[5];
Chris@743 50 UInt32 uerr = err;
Chris@743 51 text[0] = (uerr >> 24) & 0xff;
Chris@743 52 text[1] = (uerr >> 16) & 0xff;
Chris@743 53 text[2] = (uerr >> 8) & 0xff;
Chris@743 54 text[3] = (uerr) & 0xff;
Chris@743 55 text[4] = '\0';
Chris@794 56 return QString("%1 (%2)").arg(err).arg(QString::fromLocal8Bit(text));
Chris@743 57 }
luisf@665 58
luisf@665 59 CoreAudioFileReader::CoreAudioFileReader(FileSource source,
Chris@743 60 DecodeMode decodeMode,
Chris@743 61 CacheMode mode,
Chris@743 62 size_t targetRate,
Chris@743 63 ProgressReporter *reporter) :
luisf@665 64 CodedAudioFileReader(mode, targetRate),
luisf@665 65 m_source(source),
luisf@665 66 m_path(source.getLocalFilename()),
luisf@665 67 m_d(new D),
luisf@665 68 m_reporter(reporter),
luisf@665 69 m_cancelled(false),
luisf@665 70 m_completion(0),
luisf@665 71 m_decodeThread(0)
luisf@665 72 {
Chris@743 73 m_channelCount = 0;
Chris@743 74 m_fileRate = 0;
luisf@665 75
Chris@760 76 m_d->buffer.mBuffers[0].mData = 0;
Chris@760 77
Chris@743 78 Profiler profiler("CoreAudioFileReader::CoreAudioFileReader", true);
luisf@665 79
Chris@844 80 SVDEBUG << "CoreAudioFileReader: path is \"" << m_path << "\"" << endl;
luisf@665 81
Chris@743 82 QByteArray ba = m_path.toLocal8Bit();
luisf@665 83
Chris@743 84 CFURLRef url = CFURLCreateFromFileSystemRepresentation
Chris@743 85 (kCFAllocatorDefault,
Chris@743 86 (const UInt8 *)ba.data(),
Chris@743 87 (CFIndex)ba.length(),
Chris@743 88 false);
luisf@665 89
Chris@743 90 //!!! how do we find out if the file open fails because of DRM protection?
luisf@665 91
matthiasm@773 92 //#if (MACOSX_DEPLOYMENT_TARGET <= 1040 && MAC_OS_X_VERSION_MIN_REQUIRED <= 1040)
matthiasm@773 93 // FSRef fsref;
matthiasm@773 94 // if (!CFURLGetFSRef(url, &fsref)) { // returns Boolean, not error code
matthiasm@773 95 // m_error = "CoreAudioReadStream: Error looking up FS ref (file not found?)";
matthiasm@773 96 // return;
matthiasm@773 97 // }
matthiasm@773 98 // m_d->err = ExtAudioFileOpen(&fsref, &m_d->file);
matthiasm@773 99 //#else
Chris@743 100 m_d->err = ExtAudioFileOpenURL(url, &m_d->file);
matthiasm@773 101 //#endif
luisf@665 102
Chris@743 103 CFRelease(url);
luisf@665 104
Chris@743 105 if (m_d->err) {
Chris@743 106 m_error = "CoreAudioReadStream: Error opening file: code " + codestr(m_d->err);
Chris@743 107 return;
Chris@743 108 }
Chris@743 109 if (!m_d->file) {
Chris@743 110 m_error = "CoreAudioReadStream: Failed to open file, but no error reported!";
Chris@743 111 return;
Chris@743 112 }
Chris@743 113
Chris@743 114 UInt32 propsize = sizeof(AudioStreamBasicDescription);
Chris@743 115 m_d->err = ExtAudioFileGetProperty
Chris@743 116 (m_d->file, kExtAudioFileProperty_FileDataFormat, &propsize, &m_d->asbd);
Chris@743 117
Chris@743 118 if (m_d->err) {
Chris@743 119 m_error = "CoreAudioReadStream: Error in getting basic description: code " + codestr(m_d->err);
Chris@819 120 ExtAudioFileDispose(m_d->file);
Chris@743 121 return;
Chris@743 122 }
Chris@743 123
Chris@743 124 m_channelCount = m_d->asbd.mChannelsPerFrame;
Chris@755 125 m_fileRate = m_d->asbd.mSampleRate;
luisf@665 126
Chris@843 127 cerr << "CoreAudioReadStream: " << m_channelCount << " channels, " << m_fileRate << " Hz" << endl;
luisf@665 128
Chris@743 129 m_d->asbd.mFormatID = kAudioFormatLinearPCM;
Chris@743 130 m_d->asbd.mFormatFlags =
Chris@743 131 kAudioFormatFlagIsFloat |
Chris@743 132 kAudioFormatFlagIsPacked |
Chris@743 133 kAudioFormatFlagsNativeEndian;
Chris@743 134 m_d->asbd.mBitsPerChannel = sizeof(float) * 8;
Chris@743 135 m_d->asbd.mBytesPerFrame = sizeof(float) * m_channelCount;
Chris@743 136 m_d->asbd.mBytesPerPacket = sizeof(float) * m_channelCount;
Chris@743 137 m_d->asbd.mFramesPerPacket = 1;
Chris@743 138 m_d->asbd.mReserved = 0;
Chris@743 139
Chris@743 140 m_d->err = ExtAudioFileSetProperty
Chris@743 141 (m_d->file, kExtAudioFileProperty_ClientDataFormat, propsize, &m_d->asbd);
Chris@743 142
Chris@743 143 if (m_d->err) {
Chris@743 144 m_error = "CoreAudioReadStream: Error in setting client format: code " + codestr(m_d->err);
Chris@819 145 ExtAudioFileDispose(m_d->file);
Chris@743 146 return;
Chris@743 147 }
luisf@665 148
Chris@743 149 m_d->buffer.mNumberBuffers = 1;
Chris@743 150 m_d->buffer.mBuffers[0].mNumberChannels = m_channelCount;
Chris@743 151 m_d->buffer.mBuffers[0].mDataByteSize = sizeof(float) * m_channelCount * m_d->blockSize;
Chris@743 152 m_d->buffer.mBuffers[0].mData = new float[m_channelCount * m_d->blockSize];
luisf@665 153
Chris@819 154 m_d->valid = true;
Chris@819 155
Chris@743 156 initialiseDecodeCache();
luisf@665 157
Chris@743 158 if (m_reporter) {
Chris@743 159 connect(m_reporter, SIGNAL(cancelled()), this, SLOT(cancelled()));
Chris@743 160 m_reporter->setMessage
Chris@743 161 (tr("Decoding %1...").arg(QFileInfo(m_path).fileName()));
Chris@743 162 }
luisf@665 163
Chris@743 164 while (1) {
luisf@665 165
Chris@743 166 UInt32 framesRead = m_d->blockSize;
Chris@743 167 m_d->err = ExtAudioFileRead(m_d->file, &framesRead, &m_d->buffer);
luisf@665 168
Chris@743 169 if (m_d->err) {
Chris@743 170 m_error = QString("Error in CoreAudio decoding: code %1")
Chris@743 171 .arg(m_d->err);
Chris@743 172 break;
Chris@743 173 }
luisf@665 174
Chris@743 175 //!!! progress?
luisf@665 176
Chris@843 177 // cerr << "Read " << framesRead << " frames (block size " << m_d->blockSize << ")" << endl;
luisf@665 178
Chris@743 179 // buffers are interleaved unless specified otherwise
Chris@743 180 addSamplesToDecodeCache((float *)m_d->buffer.mBuffers[0].mData, framesRead);
luisf@665 181
Chris@743 182 if (framesRead < m_d->blockSize) break;
Chris@743 183 }
luisf@665 184
Chris@743 185 finishDecodeCache();
Chris@743 186 endSerialised();
luisf@665 187
Chris@743 188 m_completion = 100;
luisf@665 189 }
luisf@665 190
luisf@665 191
luisf@665 192 CoreAudioFileReader::~CoreAudioFileReader()
luisf@665 193 {
Chris@843 194 cerr << "CoreAudioFileReader::~CoreAudioFileReader" << endl;
Chris@819 195
Chris@819 196 if (m_d->valid) {
Chris@819 197 ExtAudioFileDispose(m_d->file);
Chris@819 198 delete[] m_d->buffer.mBuffers[0].mData;
Chris@819 199 }
Chris@819 200
Chris@743 201 delete m_d;
luisf@665 202 }
luisf@665 203
luisf@665 204 void
luisf@665 205 CoreAudioFileReader::cancelled()
luisf@665 206 {
luisf@665 207 m_cancelled = true;
luisf@665 208 }
luisf@665 209
luisf@665 210 void
luisf@665 211 CoreAudioFileReader::getSupportedExtensions(std::set<QString> &extensions)
luisf@665 212 {
Chris@743 213 extensions.insert("aiff");
Chris@743 214 extensions.insert("aif");
Chris@743 215 extensions.insert("au");
Chris@743 216 extensions.insert("m4a");
Chris@743 217 extensions.insert("m4b");
Chris@743 218 extensions.insert("m4p");
Chris@743 219 extensions.insert("mp3");
Chris@743 220 extensions.insert("mp4");
Chris@743 221 extensions.insert("wav");
luisf@665 222 }
luisf@665 223
luisf@665 224 bool
luisf@665 225 CoreAudioFileReader::supportsExtension(QString extension)
luisf@665 226 {
Chris@743 227 std::set<QString> extensions;
Chris@743 228 getSupportedExtensions(extensions);
Chris@743 229 return (extensions.find(extension.toLower()) != extensions.end());
luisf@665 230 }
luisf@665 231
luisf@665 232 bool
luisf@665 233 CoreAudioFileReader::supportsContentType(QString type)
luisf@665 234 {
Chris@743 235 return (type == "audio/x-aiff" ||
Chris@743 236 type == "audio/x-wav" ||
Chris@743 237 type == "audio/mpeg" ||
Chris@743 238 type == "audio/basic" ||
Chris@749 239 type == "audio/x-aac");
luisf@665 240 }
luisf@665 241
luisf@665 242 bool
luisf@665 243 CoreAudioFileReader::supports(FileSource &source)
luisf@665 244 {
Chris@743 245 return (supportsExtension(source.getExtension()) ||
Chris@743 246 supportsContentType(source.getContentType()));
luisf@665 247 }
luisf@665 248
luisf@665 249 #endif
luisf@665 250