Synced string array in sfdb_ui.cc with ImportMode enum.
authorTaybin Rutkin <taybin@taybin.com>
Fri, 1 Sep 2006 01:59:41 +0000 (01:59 +0000)
committerTaybin Rutkin <taybin@taybin.com>
Fri, 1 Sep 2006 01:59:41 +0000 (01:59 +0000)
Cleaned up CoreAudioSource by using CAAudioFile.

git-svn-id: svn://localhost/ardour2/trunk@881 d708f5d6-7413-0410-9779-e7cbd77b26cf

gtk2_ardour/editing_syms.h
gtk2_ardour/sfdb_ui.cc
libs/appleutility/CAAudioFile.cpp [new file with mode: 0644]
libs/appleutility/CAAudioFile.h [new file with mode: 0644]
libs/appleutility/CABufferList.cpp [new file with mode: 0644]
libs/appleutility/CABufferList.h [new file with mode: 0644]
libs/appleutility/CAXException.cpp [new file with mode: 0644]
libs/appleutility/CAXException.h [new file with mode: 0644]
libs/ardour/ardour/coreaudiosource.h
libs/ardour/coreaudiosource.cc

index 654ddc8852111eedcb165653d2f4d030aec667b2..3a503e2cb57a73f59ffca7a8677f6c89a5945234 100644 (file)
@@ -54,7 +54,8 @@ DISPLAYCONTROL(ShowMeasures)
 DISPLAYCONTROL(ShowWaveforms)
 DISPLAYCONTROL(ShowWaveformsRecording)
 
-IMPORTMODE(ImportAsRegion)
-IMPORTMODE(ImportAsTrack)
-IMPORTMODE(ImportAsTapeTrack)
-IMPORTMODE(ImportToTrack)
+// if this is changed, remember to update the string table in sfdb_ui.cc
+IMPORTMODE(ImportAsRegion=0)
+IMPORTMODE(ImportToTrack=1)
+IMPORTMODE(ImportAsTrack=2)
+IMPORTMODE(ImportAsTapeTrack=3)
index 0f167776b01a511c11c344704bb68e46da8a0a08..5cfcf56337c85ce69ceb209faa3150372a9a9dd6 100644 (file)
@@ -36,6 +36,7 @@
 #include <ardour/source_factory.h>
 
 #include "ardour_ui.h"
+#include "editing.h"
 #include "gui_thread.h"
 #include "prompter.h"
 #include "sfdb_ui.h"
@@ -305,6 +306,15 @@ SoundFileBox::field_selected ()
        }
 }
 
+// this needs to be kept in sync with the ImportMode enum defined in editing.h and editing_syms.h.
+static const char *import_mode_strings[] = {
+       X_("Add to Region list"),
+       X_("Add to selected Track(s)"),
+       X_("Add as new Track(s)"),
+       X_("Add as new Tape Track(s)"),
+       0
+};
+
 SoundFileBrowser::SoundFileBrowser (string title, ARDOUR::Session* s)
        : ArdourDialog (title, false),
          chooser (Gtk::FILE_CHOOSER_ACTION_OPEN)
@@ -339,13 +349,6 @@ SoundFileChooser::SoundFileChooser (string title, ARDOUR::Session* s)
        show_all ();
 }
 
-static const char *import_mode_strings[] = {
-       X_("Add to Region list"),
-       X_("Add as new Track(s)"),
-       X_("Add to selected Track(s)"),
-       0
-};
-
 vector<string> SoundFileOmega::mode_strings;
 
 SoundFileOmega::SoundFileOmega (string title, ARDOUR::Session* s)
diff --git a/libs/appleutility/CAAudioFile.cpp b/libs/appleutility/CAAudioFile.cpp
new file mode 100644 (file)
index 0000000..e1e39b0
--- /dev/null
@@ -0,0 +1,1241 @@
+/*     Copyright:      � Copyright 2005 Apple Computer, Inc. All rights reserved.
+
+       Disclaimer:     IMPORTANT:  This Apple software is supplied to you by Apple Computer, Inc.
+                       ("Apple") in consideration of your agreement to the following terms, and your
+                       use, installation, modification or redistribution of this Apple software
+                       constitutes acceptance of these terms.  If you do not agree with these terms,
+                       please do not use, install, modify or redistribute this Apple software.
+
+                       In consideration of your agreement to abide by the following terms, and subject
+                       to these terms, Apple grants you a personal, non-exclusive license, under Apple�s
+                       copyrights in this original Apple software (the "Apple Software"), to use,
+                       reproduce, modify and redistribute the Apple Software, with or without
+                       modifications, in source and/or binary forms; provided that if you redistribute
+                       the Apple Software in its entirety and without modifications, you must retain
+                       this notice and the following text and disclaimers in all such redistributions of
+                       the Apple Software.  Neither the name, trademarks, service marks or logos of
+                       Apple Computer, Inc. may be used to endorse or promote products derived from the
+                       Apple Software without specific prior written permission from Apple.  Except as
+                       expressly stated in this notice, no other rights or licenses, express or implied,
+                       are granted by Apple herein, including but not limited to any patent rights that
+                       may be infringed by your derivative works or by other works in which the Apple
+                       Software may be incorporated.
+
+                       The Apple Software is provided by Apple on an "AS IS" basis.  APPLE MAKES NO
+                       WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED
+                       WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+                       PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN
+                       COMBINATION WITH YOUR PRODUCTS.
+
+                       IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR
+                       CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+                       GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+                       ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION
+                       OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT
+                       (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN
+                       ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+/*=============================================================================
+       CAAudioFile.cpp
+       
+=============================================================================*/
+
+#include "CAAudioFile.h"
+
+#if !CAAF_USE_EXTAUDIOFILE
+
+#include "CAXException.h"
+#include <algorithm>
+#include "CAHostTimeBase.h"
+#include "CADebugMacros.h"
+
+#if !defined(__COREAUDIO_USE_FLAT_INCLUDES__)
+       #include <AudioToolbox/AudioToolbox.h>
+#else
+       #include <AudioFormat.h>
+#endif
+
+#if DEBUG
+       //#define VERBOSE_IO 1
+       //#define VERBOSE_CONVERTER 1
+       //#define VERBOSE_CHANNELMAP 1
+       //#define LOG_FUNCTION_ENTRIES 1
+
+       #if VERBOSE_CHANNELMAP
+               #include "CAChannelLayouts.h"   // this is in Source/Tests/AudioFileTools/Utility
+       #endif
+#endif
+
+#if LOG_FUNCTION_ENTRIES
+       class FunctionLogger {
+       public:
+               FunctionLogger(const char *name, const char *fmt=NULL, ...) : mName(name) {
+                       Indent();
+                       printf("-> %s ", name);
+                       if (fmt) {
+                               va_list args;
+                               va_start(args, fmt);
+                               vprintf(fmt, args);
+                               va_end(args);
+                       }
+                       printf("\n");
+                       ++sIndent;
+               }
+               ~FunctionLogger() {
+                       --sIndent;
+                       Indent();
+                       printf("<- %s\n", mName);
+                       if (sIndent == 0)
+                               printf("\n");
+               }
+               
+               static void     Indent() {
+                       for (int i = sIndent; --i >= 0; ) {
+                               putchar(' '); putchar(' ');
+                       }
+               }
+               
+               const char *mName;
+               static int sIndent;
+       };
+       int FunctionLogger::sIndent = 0;
+
+       #define LOG_FUNCTION(name, format, ...) FunctionLogger _flog(name, format, ## __VA_ARGS__);
+#else
+       #define LOG_FUNCTION(name, format, foo)
+#endif
+
+static const UInt32 kDefaultIOBufferSizeBytes = 0x10000;
+
+#if CAAUDIOFILE_PROFILE
+       #define StartTiming(af, starttime) UInt64 starttime = af->mProfiling ? CAHostTimeBase::GetTheCurrentTime() : 0
+       #define ElapsedTime(af, starttime, counter) if (af->mProfiling) counter += (CAHostTimeBase::GetTheCurrentTime() - starttime)
+#else
+       #define StartTiming(af, starttime)
+       #define ElapsedTime(af, starttime, counter)
+#endif
+
+#define kNoMoreInputRightNow 'nein'
+
+// _______________________________________________________________________________________
+//
+CAAudioFile::CAAudioFile() :
+       mAudioFile(0),
+       mUseCache(false),
+       mFinishingEncoding(false),
+       mMode(kClosed),
+       mFileDataOffset(-1),
+       mFramesToSkipFollowingSeek(0),
+       
+       mClientOwnsIOBuffer(false),
+       mPacketDescs(NULL),
+       mNumPacketDescs(0),
+       mConverter(NULL),
+       mMagicCookie(NULL),
+       mWriteBufferList(NULL)
+#if CAAUDIOFILE_PROFILE
+    ,
+       mProfiling(false),
+       mTicksInConverter(0),
+       mTicksInReadInConverter(0),
+       mTicksInIO(0),
+       mInConverter(false)
+#endif
+{
+       mIOBufferList.mBuffers[0].mData = NULL;
+       mIOBufferList.mBuffers[0].mDataByteSize = 0;
+       mClientMaxPacketSize = 0;
+       mIOBufferSizeBytes = kDefaultIOBufferSizeBytes;
+}
+
+// _______________________________________________________________________________________
+//
+CAAudioFile::~CAAudioFile()
+{
+       Close();
+}
+
+// _______________________________________________________________________________________
+//
+void   CAAudioFile::Close()
+{
+       LOG_FUNCTION("CAAudioFile::Close", NULL, NULL);
+       if (mMode == kClosed)
+               return;
+       if (mMode == kWriting)
+               FlushEncoder();
+       CloseConverter();
+       if (mAudioFile != 0 && mOwnOpenFile) {
+               AudioFileClose(mAudioFile);
+               mAudioFile = 0;
+       }
+       if (!mClientOwnsIOBuffer) {
+               delete[] (Byte *)mIOBufferList.mBuffers[0].mData;
+               mIOBufferList.mBuffers[0].mData = NULL;
+               mIOBufferList.mBuffers[0].mDataByteSize = 0;
+       }
+       delete[] mPacketDescs;  mPacketDescs = NULL;    mNumPacketDescs = 0;
+       delete[] mMagicCookie;  mMagicCookie = NULL;
+       delete mWriteBufferList;        mWriteBufferList = NULL;
+       mMode = kClosed;
+}
+
+// _______________________________________________________________________________________
+//
+void   CAAudioFile::CloseConverter()
+{
+       if (mConverter) {
+#if VERBOSE_CONVERTER
+               printf("CAAudioFile %p : CloseConverter\n", this);
+#endif
+               AudioConverterDispose(mConverter);
+               mConverter = NULL;
+       }
+}
+
+// =======================================================================================
+
+// _______________________________________________________________________________________
+//
+void   CAAudioFile::Open(const FSRef &fsref)
+{
+       LOG_FUNCTION("CAAudioFile::Open", "%p", this);
+       XThrowIf(mMode != kClosed, kExtAudioFileError_InvalidOperationOrder, "file already open");
+       mFSRef = fsref;
+       XThrowIfError(AudioFileOpen(&mFSRef, fsRdPerm, 0, &mAudioFile), "open audio file");
+       mOwnOpenFile = true;
+       mMode = kReading;
+       GetExistingFileInfo();
+}
+
+// _______________________________________________________________________________________
+//
+void   CAAudioFile::Wrap(AudioFileID fileID, bool forWriting)
+{
+       LOG_FUNCTION("CAAudioFile::Wrap", "%p", this);
+       XThrowIf(mMode != kClosed, kExtAudioFileError_InvalidOperationOrder, "file already open");
+
+       mAudioFile = fileID;
+       mOwnOpenFile = false;
+       mMode = forWriting ? kPreparingToWrite : kReading;
+       GetExistingFileInfo();
+       if (forWriting)
+               FileFormatChanged();
+}
+
+// _______________________________________________________________________________________
+//
+void   CAAudioFile::CreateNew(const FSRef &parentDir, CFStringRef filename, AudioFileTypeID filetype, const AudioStreamBasicDescription &dataFormat, const AudioChannelLayout *layout)
+{
+       LOG_FUNCTION("CAAudioFile::CreateNew", "%p", this);
+       XThrowIf(mMode != kClosed, kExtAudioFileError_InvalidOperationOrder, "file already open");
+       
+       mFileDataFormat = dataFormat;
+       if (layout) {
+               mFileChannelLayout = layout;
+#if VERBOSE_CHANNELMAP
+               printf("PrepareNew passed channel layout: %s\n", CAChannelLayouts::ConstantToString(mFileChannelLayout.Tag()));
+#endif
+       }
+       mMode = kPreparingToCreate;
+       FileFormatChanged(&parentDir, filename, filetype);
+}
+
+// _______________________________________________________________________________________
+//
+// called to create the file -- or update its format/channel layout/properties based on an encoder 
+// setting change
+void   CAAudioFile::FileFormatChanged(const FSRef *parentDir, CFStringRef filename, AudioFileTypeID filetype)
+{
+       LOG_FUNCTION("CAAudioFile::FileFormatChanged", "%p", this);
+       XThrowIf(mMode != kPreparingToCreate && mMode != kPreparingToWrite, kExtAudioFileError_InvalidOperationOrder, "new file not prepared");
+       
+       UInt32 propertySize;
+       OSStatus err;
+       AudioStreamBasicDescription saveFileDataFormat = mFileDataFormat;
+       
+#if VERBOSE_CONVERTER
+       mFileDataFormat.PrintFormat(stdout, "", "Specified file data format");
+#endif
+       
+       // Find out the actual format the converter will produce. This is necessary in
+       // case the bitrate has forced a lower sample rate, which needs to be set correctly
+       // in the stream description passed to AudioFileCreate.
+       if (mConverter != NULL) {
+               propertySize = sizeof(AudioStreamBasicDescription);
+               Float64 origSampleRate = mFileDataFormat.mSampleRate;
+               XThrowIfError(AudioConverterGetProperty(mConverter, kAudioConverterCurrentOutputStreamDescription, &propertySize, &mFileDataFormat), "get audio converter's output stream description");
+               // do the same for the channel layout being output by the converter
+#if VERBOSE_CONVERTER
+               mFileDataFormat.PrintFormat(stdout, "", "Converter output");
+#endif
+               if (fiszero(mFileDataFormat.mSampleRate))
+                       mFileDataFormat.mSampleRate = origSampleRate;
+               err = AudioConverterGetPropertyInfo(mConverter, kAudioConverterOutputChannelLayout, &propertySize, NULL);
+               if (err == noErr && propertySize > 0) {
+                       AudioChannelLayout *layout = static_cast<AudioChannelLayout *>(malloc(propertySize));
+                       err = AudioConverterGetProperty(mConverter, kAudioConverterOutputChannelLayout, &propertySize, layout);
+                       if (err) {
+                               free(layout);
+                               XThrow(err, "couldn't get audio converter's output channel layout");
+                       }
+                       mFileChannelLayout = layout;
+#if VERBOSE_CHANNELMAP
+                       printf("got new file's channel layout from converter: %s\n", CAChannelLayouts::ConstantToString(mFileChannelLayout.Tag()));
+#endif
+                       free(layout);
+               }
+       }
+       
+       // create the output file
+       if (mMode == kPreparingToCreate) {
+               CAStreamBasicDescription newFileDataFormat = mFileDataFormat;
+               if (fiszero(newFileDataFormat.mSampleRate))
+                       newFileDataFormat.mSampleRate = 44100;  // just make something up for now
+#if VERBOSE_CONVERTER
+               newFileDataFormat.PrintFormat(stdout, "", "Applied to new file");
+#endif
+               XThrowIfError(AudioFileCreate(parentDir, filename, filetype, &newFileDataFormat, 0, &mFSRef, &mAudioFile), "create audio file");
+               mMode = kPreparingToWrite;
+               mOwnOpenFile = true;
+       } else if (saveFileDataFormat != mFileDataFormat || fnotequal(saveFileDataFormat.mSampleRate, mFileDataFormat.mSampleRate)) {
+               // second check must be explicit since operator== on ASBD treats SR of zero as "don't care"
+               if (fiszero(mFileDataFormat.mSampleRate))
+                       mFileDataFormat.mSampleRate = mClientDataFormat.mSampleRate;
+#if VERBOSE_CONVERTER
+               mFileDataFormat.PrintFormat(stdout, "", "Applied to new file");
+#endif
+               XThrowIf(fiszero(mFileDataFormat.mSampleRate), kExtAudioFileError_InvalidDataFormat, "file's sample rate is 0");
+               XThrowIfError(AudioFileSetProperty(mAudioFile, kAudioFilePropertyDataFormat, sizeof(AudioStreamBasicDescription), &mFileDataFormat), "couldn't update file's data format");
+       }
+
+       UInt32 deferSizeUpdates = 1;
+       err = AudioFileSetProperty(mAudioFile, kAudioFilePropertyDeferSizeUpdates, sizeof(UInt32), &deferSizeUpdates);
+
+       if (mConverter != NULL) {
+               // encoder
+               // get the magic cookie, if any, from the converter             
+               delete[] mMagicCookie;  mMagicCookie = NULL;
+               mMagicCookieSize = 0;
+
+               err = AudioConverterGetPropertyInfo(mConverter, kAudioConverterCompressionMagicCookie, &propertySize, NULL);
+               
+               // we can get a noErr result and also a propertySize == 0
+               // -- if the file format does support magic cookies, but this file doesn't have one.
+               if (err == noErr && propertySize > 0) {
+                       mMagicCookie = new Byte[propertySize];
+                       XThrowIfError(AudioConverterGetProperty(mConverter, kAudioConverterCompressionMagicCookie, &propertySize, mMagicCookie), "get audio converter's magic cookie");
+                       mMagicCookieSize = propertySize;        // the converter lies and tell us the wrong size
+                       // now set the magic cookie on the output file
+                       UInt32 willEatTheCookie = false;
+                       // the converter wants to give us one; will the file take it?
+                       err = AudioFileGetPropertyInfo(mAudioFile, kAudioFilePropertyMagicCookieData,
+                                       NULL, &willEatTheCookie);
+                       if (err == noErr && willEatTheCookie) {
+#if VERBOSE_CONVERTER
+                               printf("Setting cookie on encoded file\n");
+#endif
+                               XThrowIfError(AudioFileSetProperty(mAudioFile, kAudioFilePropertyMagicCookieData, mMagicCookieSize, mMagicCookie), "set audio file's magic cookie");
+                       }
+               }
+               
+               // get maximum packet size
+               propertySize = sizeof(UInt32);
+               XThrowIfError(AudioConverterGetProperty(mConverter, kAudioConverterPropertyMaximumOutputPacketSize, &propertySize, &mFileMaxPacketSize), "get audio converter's maximum output packet size");
+
+               AllocateBuffers(true /* okToFail */);
+       } else {
+               InitFileMaxPacketSize();
+       }
+       
+       if (mFileChannelLayout.IsValid() && mFileChannelLayout.NumberChannels() > 2) {
+               // don't bother tagging mono/stereo files
+               UInt32 isWritable;
+               err = AudioFileGetPropertyInfo(mAudioFile, kAudioFilePropertyChannelLayout, NULL, &isWritable);
+               if (!err && isWritable) {
+#if VERBOSE_CHANNELMAP
+                       printf("writing file's channel layout: %s\n", CAChannelLayouts::ConstantToString(mFileChannelLayout.Tag()));
+#endif
+                       err = AudioFileSetProperty(mAudioFile, kAudioFilePropertyChannelLayout, 
+                               mFileChannelLayout.Size(), &mFileChannelLayout.Layout());
+                       if (err)
+                               CAXException::Warning("could not set the file's channel layout", err);
+               } else {
+#if VERBOSE_CHANNELMAP
+                       printf("file won't accept a channel layout (write)\n");
+#endif
+               }
+       }
+       
+       UpdateClientMaxPacketSize();    // also sets mFrame0Offset
+       mPacketMark = 0;
+       mFrameMark = 0;
+}
+
+// _______________________________________________________________________________________
+//
+void   CAAudioFile::InitFileMaxPacketSize()
+{
+       LOG_FUNCTION("CAAudioFile::InitFileMaxPacketSize", "%p", this);
+       UInt32 propertySize = sizeof(UInt32);
+       OSStatus err = AudioFileGetProperty(mAudioFile, kAudioFilePropertyMaximumPacketSize, 
+               &propertySize, &mFileMaxPacketSize);
+       if (err) {
+               // workaround for 3361377: not all file formats' maximum packet sizes are supported
+               if (!mFileDataFormat.IsPCM())
+                       XThrowIfError(err, "get audio file's maximum packet size");
+               mFileMaxPacketSize = mFileDataFormat.mBytesPerFrame;
+       }
+       AllocateBuffers(true /* okToFail */);
+}
+
+
+// _______________________________________________________________________________________
+//
+SInt64  CAAudioFile::FileDataOffset()
+{
+       if (mFileDataOffset < 0) {
+               UInt32 propertySize = sizeof(SInt64);
+               XThrowIfError(AudioFileGetProperty(mAudioFile, kAudioFilePropertyDataOffset, &propertySize, &mFileDataOffset), "couldn't get file's data offset");
+       }
+       return mFileDataOffset;
+}
+
+// _______________________________________________________________________________________
+//
+SInt64  CAAudioFile::GetNumberFrames() const
+{
+       AudioFilePacketTableInfo pti;
+       UInt32 propertySize = sizeof(pti);
+       OSStatus err = AudioFileGetProperty(mAudioFile, kAudioFilePropertyPacketTableInfo, &propertySize, &pti);
+       if (err == noErr)
+               return pti.mNumberValidFrames;
+       return mFileDataFormat.mFramesPerPacket * GetNumberPackets() - mFrame0Offset;
+}
+
+// _______________________________________________________________________________________
+//
+void   CAAudioFile::SetNumberFrames(SInt64 nFrames)
+{
+       XThrowIf(mFileDataFormat.mFramesPerPacket != 1, kExtAudioFileError_InvalidDataFormat, "SetNumberFrames only supported for PCM");
+       XThrowIfError(AudioFileSetProperty(mAudioFile, kAudioFilePropertyAudioDataPacketCount, sizeof(SInt64), &nFrames), "Couldn't set number of packets on audio file");
+}
+
+// _______________________________________________________________________________________
+//
+// call for existing file, NOT new one - from Open() or Wrap()
+void   CAAudioFile::GetExistingFileInfo()
+{
+       LOG_FUNCTION("CAAudioFile::GetExistingFileInfo", "%p", this);
+       UInt32 propertySize;
+       OSStatus err;
+       
+       // get mFileDataFormat
+       propertySize = sizeof(AudioStreamBasicDescription);
+       XThrowIfError(AudioFileGetProperty(mAudioFile, kAudioFilePropertyDataFormat, &propertySize, &mFileDataFormat), "get audio file's data format");
+       
+       // get mFileChannelLayout
+       err = AudioFileGetPropertyInfo(mAudioFile, kAudioFilePropertyChannelLayout, &propertySize, NULL);
+       if (err == noErr && propertySize > 0) {
+               AudioChannelLayout *layout = static_cast<AudioChannelLayout *>(malloc(propertySize));
+               err = AudioFileGetProperty(mAudioFile, kAudioFilePropertyChannelLayout, &propertySize, layout);
+               if (err == noErr) {
+                       mFileChannelLayout = layout;
+#if VERBOSE_CHANNELMAP
+                       printf("existing file's channel layout: %s\n", CAChannelLayouts::ConstantToString(mFileChannelLayout.Tag()));
+#endif
+               }
+               free(layout);
+               XThrowIfError(err, "get audio file's channel layout");
+       }
+       if (mMode != kReading)
+               return;
+       
+#if 0
+       // get mNumberPackets
+       propertySize = sizeof(mNumberPackets);
+       XThrowIfError(AudioFileGetProperty(mAudioFile, kAudioFilePropertyAudioDataPacketCount, &propertySize, &mNumberPackets), "get audio file's packet count");
+#if VERBOSE_IO
+       printf("CAAudioFile::GetExistingFileInfo: %qd packets\n", mNumberPackets);
+#endif
+#endif
+       
+       // get mMagicCookie
+       err = AudioFileGetPropertyInfo(mAudioFile, kAudioFilePropertyMagicCookieData, &propertySize, NULL);
+       if (err == noErr && propertySize > 0) {
+               mMagicCookie = new Byte[propertySize];
+               mMagicCookieSize = propertySize;
+               XThrowIfError(AudioFileGetProperty(mAudioFile, kAudioFilePropertyMagicCookieData, &propertySize, mMagicCookie), "get audio file's magic cookie");
+       }
+       InitFileMaxPacketSize();
+       mPacketMark = 0;
+       mFrameMark = 0;
+       
+       UpdateClientMaxPacketSize();
+}
+
+// =======================================================================================
+
+// _______________________________________________________________________________________
+//
+void   CAAudioFile::SetFileChannelLayout(const CAAudioChannelLayout &layout)
+{
+       LOG_FUNCTION("CAAudioFile::SetFileChannelLayout", "%p", this);
+       mFileChannelLayout = layout;
+#if VERBOSE_CHANNELMAP
+       printf("file channel layout set explicitly (%s): %s\n", mMode == kReading ? "read" : "write", CAChannelLayouts::ConstantToString(mFileChannelLayout.Tag()));
+#endif
+       if (mMode != kReading)
+               FileFormatChanged();
+}
+
+// _______________________________________________________________________________________
+//
+void   CAAudioFile::SetClientFormat(const CAStreamBasicDescription &dataFormat, const CAAudioChannelLayout *layout)
+{
+       LOG_FUNCTION("CAAudioFile::SetClientFormat", "%p", this);
+       XThrowIf(!dataFormat.IsPCM(), kExtAudioFileError_NonPCMClientFormat, "non-PCM client format on audio file");
+       
+       bool dataFormatChanging = (mClientDataFormat.mFormatID == 0 || mClientDataFormat != dataFormat);
+       
+       if (dataFormatChanging) {
+               CloseConverter();
+               if (mWriteBufferList) {
+                       delete mWriteBufferList;
+                       mWriteBufferList = NULL;
+               }
+               mClientDataFormat = dataFormat;
+       }
+       
+       if (layout && layout->IsValid()) {
+               XThrowIf(layout->NumberChannels() != mClientDataFormat.NumberChannels(), kExtAudioFileError_InvalidChannelMap, "inappropriate channel map");
+               mClientChannelLayout = *layout;
+       }
+       
+       bool differentLayouts;
+       if (mClientChannelLayout.IsValid()) {
+               if (mFileChannelLayout.IsValid()) {
+                       differentLayouts = mClientChannelLayout.Tag() != mFileChannelLayout.Tag();
+#if VERBOSE_CHANNELMAP
+                       printf("two valid layouts, %s\n", differentLayouts ? "different" : "same");
+#endif
+               } else {
+                       differentLayouts = false;
+#if VERBOSE_CHANNELMAP
+                       printf("valid client layout, unknown file layout\n");
+#endif
+               }
+       } else {
+               differentLayouts = false;
+#if VERBOSE_CHANNELMAP
+               if (mFileChannelLayout.IsValid())
+                       printf("valid file layout, unknown client layout\n");
+               else
+                       printf("two invalid layouts\n");
+#endif
+       }
+       
+       if (mClientDataFormat != mFileDataFormat || differentLayouts) {
+               // We need an AudioConverter.
+               if (mMode == kReading) {
+                       // file -> client (decode)
+//mFileDataFormat.PrintFormat(  stdout, "", "File:   ");
+//mClientDataFormat.PrintFormat(stdout, "", "Client: ");
+
+                       if (mConverter == NULL)
+                               XThrowIfError(AudioConverterNew(&mFileDataFormat, &mClientDataFormat, &mConverter),
+                               "create audio converter");
+                       
+#if VERBOSE_CONVERTER
+                       printf("CAAudioFile %p -- created converter\n", this);
+                       CAShow(mConverter);
+#endif
+                       // set the magic cookie, if any (for decode)
+                       if (mMagicCookie)
+                               SetConverterProperty(kAudioConverterDecompressionMagicCookie, mMagicCookieSize, mMagicCookie, mFileDataFormat.IsPCM());
+                                       // we get cookies from some AIFF's but the converter barfs on them,
+                                       // so we set canFail to true for PCM
+
+                       SetConverterChannelLayout(false, mFileChannelLayout);
+                       SetConverterChannelLayout(true, mClientChannelLayout);
+                       
+                       // propagate leading/trailing frame counts
+                       if (mFileDataFormat.mBitsPerChannel == 0) {
+                               UInt32 propertySize;
+                               OSStatus err;
+                               AudioFilePacketTableInfo pti;
+                               propertySize = sizeof(pti);
+                               err = AudioFileGetProperty(mAudioFile, kAudioFilePropertyPacketTableInfo, &propertySize, &pti);
+                               if (err == noErr && (pti.mPrimingFrames > 0 || pti.mRemainderFrames > 0)) {
+                                       AudioConverterPrimeInfo primeInfo;
+                                       primeInfo.leadingFrames = pti.mPrimingFrames;
+                                       primeInfo.trailingFrames = pti.mRemainderFrames;
+                                       /* ignore any error. better to play it at all than not. */
+                                       /*err = */AudioConverterSetProperty(mConverter, kAudioConverterPrimeInfo, sizeof(primeInfo), &primeInfo);
+                                       //XThrowIfError(err, "couldn't set prime info on converter");
+                               }
+                       }
+               } else if (mMode == kPreparingToCreate || mMode == kPreparingToWrite) {
+                       // client -> file (encode)
+                       if (mConverter == NULL)
+                               XThrowIfError(AudioConverterNew(&mClientDataFormat, &mFileDataFormat, &mConverter), "create audio converter");
+                       mWriteBufferList = CABufferList::New("", mClientDataFormat);
+                       SetConverterChannelLayout(false, mClientChannelLayout);
+                       SetConverterChannelLayout(true, mFileChannelLayout);
+                       if (mMode == kPreparingToWrite)
+                               FileFormatChanged();
+               } else
+                       XThrowIfError(kExtAudioFileError_InvalidOperationOrder, "audio file format not yet known");
+       }
+       UpdateClientMaxPacketSize();
+}
+
+// _______________________________________________________________________________________
+//
+OSStatus       CAAudioFile::SetConverterProperty(      
+                                                                                       AudioConverterPropertyID        inPropertyID,
+                                                                                       UInt32                                          inPropertyDataSize,
+                                                                                       const void*                                     inPropertyData,
+                                                                                       bool                                            inCanFail)
+{
+       OSStatus err = noErr;
+       //LOG_FUNCTION("ExtAudioFile::SetConverterProperty", "%p %-4.4s", this, (char *)&inPropertyID);
+       if (inPropertyID == kAudioConverterPropertySettings && *(CFPropertyListRef *)inPropertyData == NULL)
+               ;
+       else {
+               err = AudioConverterSetProperty(mConverter, inPropertyID, inPropertyDataSize, inPropertyData);
+               if (!inCanFail) {
+                       XThrowIfError(err, "set audio converter property");
+               }
+       }
+       UpdateClientMaxPacketSize();
+       if (mMode == kPreparingToWrite)
+               FileFormatChanged();
+       return err;
+}
+
+// _______________________________________________________________________________________
+//
+void   CAAudioFile::SetConverterChannelLayout(bool output, const CAAudioChannelLayout &layout)
+{
+       LOG_FUNCTION("CAAudioFile::SetConverterChannelLayout", "%p", this);
+       OSStatus err;
+       
+       if (layout.IsValid()) {
+#if VERBOSE_CHANNELMAP
+               printf("Setting converter's %s channel layout: %s\n", output ? "output" : "input",
+                       CAChannelLayouts::ConstantToString(mFileChannelLayout.Tag()));
+#endif
+               if (output) {
+                       err = AudioConverterSetProperty(mConverter, kAudioConverterOutputChannelLayout,
+                               layout.Size(), &layout.Layout());
+                       XThrowIf(err && err != kAudioConverterErr_OperationNotSupported, err, "couldn't set converter's output channel layout");
+               } else {
+                       err = AudioConverterSetProperty(mConverter, kAudioConverterInputChannelLayout,
+                               layout.Size(), &layout.Layout());
+                       XThrowIf(err && err != kAudioConverterErr_OperationNotSupported, err, "couldn't set converter's input channel layout");
+               }
+               if (mMode == kPreparingToWrite)
+                       FileFormatChanged();
+       }
+}
+
+// _______________________________________________________________________________________
+//
+CFArrayRef  CAAudioFile::GetConverterConfig()
+{
+       CFArrayRef plist;
+       UInt32 propertySize = sizeof(plist);
+       XThrowIfError(AudioConverterGetProperty(mConverter, kAudioConverterPropertySettings, &propertySize, &plist), "get converter property settings");
+       return plist;
+}
+
+// _______________________________________________________________________________________
+//
+void   CAAudioFile::UpdateClientMaxPacketSize()
+{
+       LOG_FUNCTION("CAAudioFile::UpdateClientMaxPacketSize", "%p", this);
+       mFrame0Offset = 0;
+       if (mConverter != NULL) {
+               AudioConverterPropertyID property = (mMode == kReading) ? 
+                       kAudioConverterPropertyMaximumOutputPacketSize :
+                       kAudioConverterPropertyMaximumInputPacketSize;
+                       
+               UInt32 propertySize = sizeof(UInt32);
+               XThrowIfError(AudioConverterGetProperty(mConverter, property, &propertySize, &mClientMaxPacketSize),
+                       "get audio converter's maximum packet size");
+               
+               if (mFileDataFormat.mBitsPerChannel == 0) {
+                       AudioConverterPrimeInfo primeInfo;
+                       propertySize = sizeof(primeInfo);
+                       OSStatus err = AudioConverterGetProperty(mConverter, kAudioConverterPrimeInfo, &propertySize, &primeInfo);
+                       if (err == noErr)
+                               mFrame0Offset = primeInfo.leadingFrames;
+#if VERBOSE_CONVERTER
+                       printf("kAudioConverterPrimeInfo: err = %ld, leadingFrames = %ld\n", err, mFrame0Offset);
+#endif
+               }
+       } else {
+               mClientMaxPacketSize = mFileMaxPacketSize;
+       }
+}
+
+// _______________________________________________________________________________________
+//     Allocates: mIOBufferList, mIOBufferSizePackets, mPacketDescs
+//     Dependent on: mFileMaxPacketSize, mIOBufferSizeBytes
+void   CAAudioFile::AllocateBuffers(bool okToFail)
+{
+       LOG_FUNCTION("CAAudioFile::AllocateBuffers", "%p", this);
+       if (mFileMaxPacketSize == 0) {
+               if (okToFail)
+                       return;
+               XThrowIf(true, kExtAudioFileError_MaxPacketSizeUnknown, "file's maximum packet size is 0");
+       }
+       UInt32 bufferSizeBytes = mIOBufferSizeBytes = std::max(mIOBufferSizeBytes, mFileMaxPacketSize);
+               // must be big enough for at least one maximum size packet
+       
+       if (mIOBufferList.mBuffers[0].mDataByteSize != bufferSizeBytes) {
+               mIOBufferList.mNumberBuffers = 1;
+               mIOBufferList.mBuffers[0].mNumberChannels = mFileDataFormat.mChannelsPerFrame;
+               if (!mClientOwnsIOBuffer) {
+                       //printf("reallocating I/O buffer\n");
+                       delete[] (Byte *)mIOBufferList.mBuffers[0].mData;
+                       mIOBufferList.mBuffers[0].mData = new Byte[bufferSizeBytes];
+               }
+               mIOBufferList.mBuffers[0].mDataByteSize = bufferSizeBytes;
+               mIOBufferSizePackets = bufferSizeBytes / mFileMaxPacketSize;
+       }
+       
+       UInt32 propertySize = sizeof(UInt32);
+       UInt32 externallyFramed;
+       XThrowIfError(AudioFormatGetProperty(kAudioFormatProperty_FormatIsExternallyFramed,
+                       sizeof(AudioStreamBasicDescription), &mFileDataFormat, &propertySize, &externallyFramed),
+                       "is format externally framed");
+       if (mNumPacketDescs != (externallyFramed ? mIOBufferSizePackets : 0)) {
+               delete[] mPacketDescs;
+               mPacketDescs = NULL;
+               mNumPacketDescs = 0;
+
+               if (externallyFramed) {
+                       //printf("reallocating packet descs\n");
+                       mPacketDescs = new AudioStreamPacketDescription[mIOBufferSizePackets];
+                       mNumPacketDescs = mIOBufferSizePackets;
+               }
+       }
+}
+
+// _______________________________________________________________________________________
+//
+void   CAAudioFile::SetIOBuffer(void *buf)
+{
+       if (!mClientOwnsIOBuffer)
+               delete[] (Byte *)mIOBufferList.mBuffers[0].mData;
+       mIOBufferList.mBuffers[0].mData = buf;
+
+       if (buf == NULL) {
+               mClientOwnsIOBuffer = false;
+               SetIOBufferSizeBytes(mIOBufferSizeBytes);
+       } else {
+               mClientOwnsIOBuffer = true;
+               AllocateBuffers();
+       }
+//     printf("CAAudioFile::SetIOBuffer %p: %p, 0x%lx bytes, mClientOwns = %d\n", this, mIOBufferList.mBuffers[0].mData, mIOBufferSizeBytes, mClientOwnsIOBuffer);
+}
+
+// ===============================================================================
+
+/*
+For Tiger:
+added kAudioFilePropertyPacketToFrame and kAudioFilePropertyFrameToPacket.
+You pass in an AudioFramePacketTranslation struct, with the appropriate field filled in, to AudioFileGetProperty.
+
+       kAudioFilePropertyPacketToFrame                 =       'pkfr',
+               // pass a AudioFramePacketTranslation with mPacket filled out and get mFrame back. mFrameOffsetInPacket is ignored.
+       kAudioFilePropertyFrameToPacket                 =       'frpk',
+               // pass a AudioFramePacketTranslation with mFrame filled out and get mPacket and mFrameOffsetInPacket back.
+
+struct AudioFramePacketTranslation
+{
+       SInt64 mFrame;
+       SInt64 mPacket;
+       UInt32 mFrameOffsetInPacket;
+};
+*/
+
+SInt64  CAAudioFile::PacketToFrame(SInt64 packet) const
+{
+       AudioFramePacketTranslation trans;
+       UInt32 propertySize;
+       
+       switch (mFileDataFormat.mFramesPerPacket) {
+       case 1:
+               return packet;
+       case 0:
+               trans.mPacket = packet;
+               propertySize = sizeof(trans);
+               XThrowIfError(AudioFileGetProperty(mAudioFile, kAudioFilePropertyPacketToFrame, &propertySize, &trans),
+                       "packet <-> frame translation unimplemented for format with variable frames/packet");
+               return trans.mFrame;
+       }
+       return packet * mFileDataFormat.mFramesPerPacket;
+}
+
+SInt64 CAAudioFile::FrameToPacket(SInt64 inFrame) const
+{
+       AudioFramePacketTranslation trans;
+       UInt32 propertySize;
+       
+       switch (mFileDataFormat.mFramesPerPacket) {
+       case 1:
+               return inFrame;
+       case 0:
+               trans.mFrame = inFrame;
+               propertySize = sizeof(trans);
+               XThrowIfError(AudioFileGetProperty(mAudioFile, kAudioFilePropertyFrameToPacket, &propertySize, &trans),
+                       "packet <-> frame translation unimplemented for format with variable frames/packet");
+               return trans.mPacket;
+       }
+       return inFrame / mFileDataFormat.mFramesPerPacket;
+}
+
+// _______________________________________________________________________________________
+//
+
+SInt64  CAAudioFile::Tell() const      // frameNumber
+{
+       return mFrameMark - mFrame0Offset;
+}
+
+void   CAAudioFile::SeekToPacket(SInt64 packetNumber)
+{
+#if VERBOSE_IO
+       printf("CAAudioFile::SeekToPacket: %qd\n", packetNumber);
+#endif
+       XThrowIf(mMode != kReading || packetNumber < 0 /*|| packetNumber >= mNumberPackets*/ , kExtAudioFileError_InvalidSeek, "seek to packet in audio file");
+       if (mPacketMark == packetNumber)
+               return; // already there! don't reset converter
+       mPacketMark = packetNumber;
+       
+       mFrameMark = PacketToFrame(packetNumber) - mFrame0Offset;
+       mFramesToSkipFollowingSeek = 0;
+       if (mConverter)
+               // must reset -- if we reached end of stream. converter will no longer work otherwise
+               AudioConverterReset(mConverter);
+}
+
+/*
+       Example: AAC, 1024 frames/packet, 2112 frame offset
+       
+                                           2112
+                                             |
+    Absolute frames:  0       1024      2048 |    3072
+                      +---------+---------+--|------+---------+---------+
+    Packets:          |    0    |    1    |  | 2    |    3    |    4    |
+                      +---------+---------+--|------+---------+---------+
+    Client frames:  -2112   -1088       -64  |     960                                         SeekToFrame, TellFrame
+                                             |
+                                             0
+
+       *   Offset between absolute and client frames is mFrame0Offset.
+       *** mFrameMark is in client frames ***
+       
+       Examples:
+               clientFrame                                     0               960             1000    1024
+               absoluteFrame                           2112    3072    3112    3136
+               packet                                          0               0               0               1
+               tempFrameMark*                          -2112   -2112   -2112   -1088
+               mFramesToSkipFollowingSeek      2112    3072    3112    2112
+*/
+void   CAAudioFile::Seek(SInt64 clientFrame)
+{
+       if (clientFrame == mFrameMark)
+               return; // already there! don't reset converter
+
+       //SInt64 absoluteFrame = clientFrame + mFrame0Offset;
+       XThrowIf(mMode != kReading || clientFrame < 0 || !mClientDataFormat.IsPCM(), kExtAudioFileError_InvalidSeek, "seek to frame in audio file");
+
+#if VERBOSE_IO
+       SInt64 prevFrameMark = mFrameMark;
+#endif
+       
+       SInt64 packet;
+       packet = FrameToPacket(clientFrame);
+       if (packet < 0)
+               packet = 0;
+       SeekToPacket(packet);
+       // this will have backed up mFrameMark to match the beginning of the packet
+       mFramesToSkipFollowingSeek = std::max(UInt32(clientFrame - mFrameMark), UInt32(0));
+       mFrameMark = clientFrame;
+       
+#if VERBOSE_IO
+       printf("CAAudioFile::SeekToFrame: frame %qd (from %qd), packet %qd, skip %ld frames\n", mFrameMark, prevFrameMark, packet, mFramesToSkipFollowingSeek);
+#endif
+}
+
+// _______________________________________________________________________________________
+//
+void   CAAudioFile::Read(UInt32 &ioNumPackets, AudioBufferList *ioData)
+                       // May read fewer packets than requested if:
+                       //              buffer is not big enough
+                       //              file does not contain that many more packets
+                       // Note that eofErr is not fatal, just results in 0 packets returned
+                       // ioData's buffer sizes may be shortened
+{
+       XThrowIf(mClientMaxPacketSize == 0, kExtAudioFileError_MaxPacketSizeUnknown, "client maximum packet size is 0");
+       if (mIOBufferList.mBuffers[0].mData == NULL) {
+#if DEBUG
+               printf("warning: CAAudioFile::AllocateBuffers called from ReadPackets\n");
+#endif
+               AllocateBuffers();
+       }
+       UInt32 bufferSizeBytes = ioData->mBuffers[0].mDataByteSize;
+       UInt32 maxNumPackets = bufferSizeBytes / mClientMaxPacketSize;  
+       // older versions of AudioConverterFillComplexBuffer don't do this, so do our own sanity check
+       UInt32 nPackets = std::min(ioNumPackets, maxNumPackets);
+       
+       mMaxPacketsToRead = ~0UL;
+       
+       if (mClientDataFormat.mFramesPerPacket == 1) {  // PCM or equivalent
+               while (mFramesToSkipFollowingSeek > 0) {
+                       UInt32 skipFrames = std::min(mFramesToSkipFollowingSeek, maxNumPackets);
+                       UInt32 framesPerPacket;
+                       if ((framesPerPacket=mFileDataFormat.mFramesPerPacket) > 0)
+                               mMaxPacketsToRead = (skipFrames + framesPerPacket - 1) / framesPerPacket;
+
+                       if (mConverter == NULL) {
+                               XThrowIfError(ReadInputProc(NULL, &skipFrames, ioData, NULL, this), "read audio file");
+                       } else {
+#if CAAUDIOFILE_PROFILE
+                               mInConverter = true;
+#endif
+                               StartTiming(this, fill);
+                               XThrowIfError(AudioConverterFillComplexBuffer(mConverter, ReadInputProc, this, &skipFrames, ioData, NULL), "convert audio packets (pcm read)");
+                               ElapsedTime(this, fill, mTicksInConverter);
+#if CAAUDIOFILE_PROFILE
+                               mInConverter = false;
+#endif
+                       }
+                       if (skipFrames == 0) {  // hit EOF
+                               ioNumPackets = 0;
+                               return;
+                       }
+                       mFrameMark += skipFrames;
+#if VERBOSE_IO
+                       printf("CAAudioFile::ReadPackets: skipped %ld frames\n", skipFrames);
+#endif
+
+                       mFramesToSkipFollowingSeek -= skipFrames;
+
+                       // restore mDataByteSize
+                       for (int i = ioData->mNumberBuffers; --i >= 0 ; )
+                               ioData->mBuffers[i].mDataByteSize = bufferSizeBytes;
+               }
+       }
+       
+       if (mFileDataFormat.mFramesPerPacket > 0)
+               // don't read more packets than we are being asked to produce
+               mMaxPacketsToRead = nPackets / mFileDataFormat.mFramesPerPacket + 1;
+       if (mConverter == NULL) {
+               XThrowIfError(ReadInputProc(NULL, &nPackets, ioData, NULL, this), "read audio file");
+       } else {
+#if CAAUDIOFILE_PROFILE
+               mInConverter = true;
+#endif
+               StartTiming(this, fill);
+               XThrowIfError(AudioConverterFillComplexBuffer(mConverter, ReadInputProc, this, &nPackets, ioData, NULL), "convert audio packets (read)");
+               ElapsedTime(this, fill, mTicksInConverter);
+#if CAAUDIOFILE_PROFILE
+               mInConverter = false;
+#endif
+       }
+       if (mClientDataFormat.mFramesPerPacket == 1)
+               mFrameMark += nPackets;
+       
+       ioNumPackets = nPackets;
+}
+
+// _______________________________________________________________________________________
+//
+OSStatus CAAudioFile::ReadInputProc(   AudioConverterRef                               inAudioConverter,
+                                                                               UInt32*                                                 ioNumberDataPackets,
+                                                                               AudioBufferList*                                ioData,
+                                                                               AudioStreamPacketDescription**  outDataPacketDescription,
+                                                                               void*                                                   inUserData)
+{
+       CAAudioFile *This = static_cast<CAAudioFile *>(inUserData);
+
+#if 0
+       SInt64 remainingPacketsInFile = This->mNumberPackets - This->mPacketMark;
+       if (remainingPacketsInFile <= 0) {
+               *ioNumberDataPackets = 0;
+               ioData->mBuffers[0].mDataByteSize = 0;
+               if (outDataPacketDescription)
+                       *outDataPacketDescription = This->mPacketDescs;
+#if VERBOSE_IO
+               printf("CAAudioFile::ReadInputProc: EOF\n");
+#endif
+               return noErr;   // not eofErr; EOF is signified by 0 packets/0 bytes
+       }
+#endif
+       
+       // determine how much to read
+       AudioBufferList *readBuffer;
+       UInt32 readPackets;
+       if (inAudioConverter != NULL) {
+               // getting called from converter, need to use our I/O buffer
+               readBuffer = &This->mIOBufferList;
+               readPackets = This->mIOBufferSizePackets;
+       } else {
+               // getting called directly from ReadPackets, use supplied buffer
+               if (This->mFileMaxPacketSize == 0)
+                       return kExtAudioFileError_MaxPacketSizeUnknown;
+               readBuffer = ioData;
+               readPackets = std::min(*ioNumberDataPackets, readBuffer->mBuffers[0].mDataByteSize / This->mFileMaxPacketSize);
+                       // don't attempt to read more packets than will fit in the buffer
+       }
+       // don't try to read past EOF
+//     if (readPackets > remainingPacketsInFile)
+//             readPackets = remainingPacketsInFile;
+       // don't read more packets than necessary to produce the requested amount of converted data
+       if (readPackets > This->mMaxPacketsToRead) {
+#if VERBOSE_IO
+               printf("CAAudioFile::ReadInputProc: limiting read to %ld packets (from %ld)\n", This->mMaxPacketsToRead, readPackets);
+#endif
+               readPackets = This->mMaxPacketsToRead;
+       }
+       
+       // read
+       UInt32 bytesRead;
+       OSStatus err;
+       
+       StartTiming(This, read);
+       StartTiming(This, readinconv);
+       err = AudioFileReadPackets(This->mAudioFile, This->mUseCache, &bytesRead, This->mPacketDescs, This->mPacketMark, &readPackets, readBuffer->mBuffers[0].mData);
+#if CAAUDIOFILE_PROFILE
+       if (This->mInConverter) ElapsedTime(This, readinconv, This->mTicksInReadInConverter);
+#endif
+       ElapsedTime(This, read, This->mTicksInIO);
+
+       if (err) {
+               DebugMessageN1("Error %ld from AudioFileReadPackets!!!\n", err);
+               return err;
+       }
+       
+#if VERBOSE_IO
+       printf("CAAudioFile::ReadInputProc: read %ld packets (%qd-%qd), %ld bytes, err %ld\n", readPackets, This->mPacketMark, This->mPacketMark + readPackets, bytesRead, err);
+#if VERBOSE_IO >= 2
+       if (This->mPacketDescs) {
+               for (UInt32 i = 0; i < readPackets; ++i) {
+                       printf("  read packet %qd : offset %qd, length %ld\n", This->mPacketMark + i, This->mPacketDescs[i].mStartOffset, This->mPacketDescs[i].mDataByteSize);
+               }
+       }
+       printf("  read buffer:"); CAShowAudioBufferList(readBuffer, 0, 4);
+#endif
+#endif
+       if (readPackets == 0) {
+               *ioNumberDataPackets = 0;
+               ioData->mBuffers[0].mDataByteSize = 0;
+               return noErr;
+       }
+
+       if (outDataPacketDescription)
+               *outDataPacketDescription = This->mPacketDescs;
+       ioData->mBuffers[0].mDataByteSize = bytesRead;
+       ioData->mBuffers[0].mData = readBuffer->mBuffers[0].mData;
+
+       This->mPacketMark += readPackets;
+       if (This->mClientDataFormat.mFramesPerPacket != 1) {    // for PCM client formats we update in Read
+               // but for non-PCM client format (weird case) we must update here/now
+               if (This->mFileDataFormat.mFramesPerPacket > 0)
+                       This->mFrameMark += readPackets * This->mFileDataFormat.mFramesPerPacket;
+               else {
+                       for (UInt32 i = 0; i < readPackets; ++i)
+                               This->mFrameMark += This->mPacketDescs[i].mVariableFramesInPacket;
+               }
+       }
+       *ioNumberDataPackets = readPackets;
+       return noErr;
+}
+
+// _______________________________________________________________________________________
+//
+void   CAAudioFile::Write(UInt32 numPackets, const AudioBufferList *data)
+{
+       if (mIOBufferList.mBuffers[0].mData == NULL) {
+#if DEBUG
+               printf("warning: CAAudioFile::AllocateBuffers called from WritePackets\n");
+#endif
+               AllocateBuffers();
+       }
+
+       if (mMode == kPreparingToWrite)
+               mMode = kWriting;
+       else
+               XThrowIf(mMode != kWriting, kExtAudioFileError_InvalidOperationOrder, "can't write to this file");
+       if (mConverter != NULL) {
+               mWritePackets = numPackets;
+               mWriteBufferList->SetFrom(data);
+               WritePacketsFromCallback(WriteInputProc, this);
+       } else {
+               StartTiming(this, write);
+               XThrowIfError(AudioFileWritePackets(mAudioFile, mUseCache, data->mBuffers[0].mDataByteSize, 
+                                               NULL, mPacketMark, &numPackets, data->mBuffers[0].mData),
+                                               "write audio file");
+               ElapsedTime(this, write, mTicksInIO);
+#if VERBOSE_IO
+               printf("CAAudioFile::WritePackets: wrote %ld packets at %qd, %ld bytes\n", numPackets, mPacketMark, data->mBuffers[0].mDataByteSize);
+#endif
+               //mNumberPackets = 
+               mPacketMark += numPackets;
+               if (mFileDataFormat.mFramesPerPacket > 0)
+                       mFrameMark += numPackets * mFileDataFormat.mFramesPerPacket;
+               // else: shouldn't happen since we're only called when there's no converter
+       }
+}
+
+// _______________________________________________________________________________________
+//
+void   CAAudioFile::FlushEncoder()
+{
+       if (mConverter != NULL) {
+               mFinishingEncoding = true;
+               WritePacketsFromCallback(WriteInputProc, this);
+               mFinishingEncoding = false;
+
+               // get priming info from converter, set it on the file
+               if (mFileDataFormat.mBitsPerChannel == 0) {
+                       UInt32 propertySize;
+                       OSStatus err;
+                       AudioConverterPrimeInfo primeInfo;
+                       propertySize = sizeof(primeInfo);
+       
+                       err = AudioConverterGetProperty(mConverter, kAudioConverterPrimeInfo, &propertySize, &primeInfo);
+                       if (err == noErr) {
+                               AudioFilePacketTableInfo pti;
+                               propertySize = sizeof(pti);
+                               err = AudioFileGetProperty(mAudioFile, kAudioFilePropertyPacketTableInfo, &propertySize, &pti);
+                               if (err == noErr) {
+//printf("old packet table info: %qd valid, %ld priming, %ld remainder\n", pti.mNumberValidFrames, pti.mPrimingFrames, pti.mRemainderFrames);
+                                       UInt64 totalFrames = pti.mNumberValidFrames + pti.mPrimingFrames + pti.mRemainderFrames;
+                                       pti.mPrimingFrames = primeInfo.leadingFrames;
+                                       pti.mRemainderFrames = primeInfo.trailingFrames;
+                                       pti.mNumberValidFrames = totalFrames - pti.mPrimingFrames - pti.mRemainderFrames;
+//printf("new packet table info: %qd valid, %ld priming, %ld remainder\n", pti.mNumberValidFrames, pti.mPrimingFrames, pti.mRemainderFrames);
+                                       XThrowIfError(AudioFileSetProperty(mAudioFile, kAudioFilePropertyPacketTableInfo, sizeof(pti), &pti), "couldn't set packet table info on audio file");
+                               }
+                       }
+               }
+       }
+}
+
+// _______________________________________________________________________________________
+//
+OSStatus CAAudioFile::WriteInputProc(  AudioConverterRef                               /*inAudioConverter*/,
+                                                                               UInt32 *                                                ioNumberDataPackets,
+                                                                               AudioBufferList*                                ioData,
+                                                                               AudioStreamPacketDescription ** outDataPacketDescription,
+                                                                               void*                                                   inUserData)
+{
+       CAAudioFile *This = static_cast<CAAudioFile *>(inUserData);
+       if (This->mFinishingEncoding) {
+               *ioNumberDataPackets = 0;
+               ioData->mBuffers[0].mDataByteSize = 0;
+               ioData->mBuffers[0].mData = NULL;
+               if (outDataPacketDescription)
+                       *outDataPacketDescription = NULL;
+               return noErr;
+       }
+       UInt32 numPackets = This->mWritePackets;
+       if (numPackets == 0) {
+               return kNoMoreInputRightNow;
+       }
+       This->mWriteBufferList->ToAudioBufferList(ioData);
+       This->mWriteBufferList->BytesConsumed(numPackets * This->mClientDataFormat.mBytesPerFrame);
+       *ioNumberDataPackets = numPackets;
+       if (outDataPacketDescription)
+               *outDataPacketDescription = NULL;
+       This->mWritePackets -= numPackets;
+       return noErr;
+}
+
+// _______________________________________________________________________________________
+//
+#if VERBOSE_IO
+static void    hexdump(const void *addr, long len)
+{
+       const Byte *p = (Byte *)addr;
+       UInt32 offset = 0;
+       
+       if (len > 0x400) len = 0x400;
+       
+       while (len > 0) {
+               int n = len > 16 ? 16 : len;
+               printf("%08lX:  ", offset);
+               for (int i = 0; i < 16; ++i)
+                       if (i < n)
+                               printf("%02X ", p[i]);
+                       else printf("   ");
+               for (int i = 0; i < 16; ++i)
+                       if (i < n)
+                               putchar(p[i] >= ' ' && p[i] < 127 ? p[i] : '.');
+                       else putchar(' ');
+               putchar('\n');
+               p += 16;
+               len -= 16;
+               offset += 16;
+       }
+}
+#endif
+
+// _______________________________________________________________________________________
+//
+void   CAAudioFile::WritePacketsFromCallback(
+                                                               AudioConverterComplexInputDataProc      inInputDataProc,
+                                                               void *                                                          inInputDataProcUserData)
+{
+       while (true) {
+               // keep writing until we exhaust the input (temporary stop), or produce no output (EOF)
+               UInt32 numEncodedPackets = mIOBufferSizePackets;
+               mIOBufferList.mBuffers[0].mDataByteSize = mIOBufferSizeBytes;
+#if CAAUDIOFILE_PROFILE
+               mInConverter = true;
+#endif
+               StartTiming(this, fill);
+               OSStatus err = AudioConverterFillComplexBuffer(mConverter, inInputDataProc, inInputDataProcUserData, 
+                                       &numEncodedPackets, &mIOBufferList, mPacketDescs);
+               ElapsedTime(this, fill, mTicksInConverter);
+#if CAAUDIOFILE_PROFILE
+               mInConverter = false;
+#endif
+               XThrowIf(err != 0 && err != kNoMoreInputRightNow, err, "convert audio packets (write)");
+               if (numEncodedPackets == 0)
+                       break;
+               Byte *buf = (Byte *)mIOBufferList.mBuffers[0].mData;
+#if VERBOSE_IO
+               printf("CAAudioFile::WritePacketsFromCallback: wrote %ld packets, %ld bytes\n", numEncodedPackets, mIOBufferList.mBuffers[0].mDataByteSize);
+               if (mPacketDescs) {
+                       for (UInt32 i = 0; i < numEncodedPackets; ++i) {
+                               printf("  write packet %qd : offset %qd, length %ld\n", mPacketMark + i, mPacketDescs[i].mStartOffset, mPacketDescs[i].mDataByteSize);
+#if VERBOSE_IO >= 2
+                               hexdump(buf + mPacketDescs[i].mStartOffset, mPacketDescs[i].mDataByteSize);
+#endif
+                       }
+               }
+#endif
+               StartTiming(this, write);
+               XThrowIfError(AudioFileWritePackets(mAudioFile, mUseCache, mIOBufferList.mBuffers[0].mDataByteSize, mPacketDescs, mPacketMark, &numEncodedPackets, buf), "write audio file");
+               ElapsedTime(this, write, mTicksInIO);
+               mPacketMark += numEncodedPackets;
+               //mNumberPackets += numEncodedPackets;
+               if (mFileDataFormat.mFramesPerPacket > 0)
+                       mFrameMark += numEncodedPackets * mFileDataFormat.mFramesPerPacket;
+               else {
+                       for (UInt32 i = 0; i < numEncodedPackets; ++i)
+                               mFrameMark += mPacketDescs[i].mVariableFramesInPacket;
+               }
+               if (err == kNoMoreInputRightNow)
+                       break;
+       }
+}
+
+#endif // !CAAF_USE_EXTAUDIOFILE
diff --git a/libs/appleutility/CAAudioFile.h b/libs/appleutility/CAAudioFile.h
new file mode 100644 (file)
index 0000000..2cfb4f3
--- /dev/null
@@ -0,0 +1,439 @@
+/*     Copyright:      � Copyright 2005 Apple Computer, Inc. All rights reserved.
+
+       Disclaimer:     IMPORTANT:  This Apple software is supplied to you by Apple Computer, Inc.
+                       ("Apple") in consideration of your agreement to the following terms, and your
+                       use, installation, modification or redistribution of this Apple software
+                       constitutes acceptance of these terms.  If you do not agree with these terms,
+                       please do not use, install, modify or redistribute this Apple software.
+
+                       In consideration of your agreement to abide by the following terms, and subject
+                       to these terms, Apple grants you a personal, non-exclusive license, under Apple�s
+                       copyrights in this original Apple software (the "Apple Software"), to use,
+                       reproduce, modify and redistribute the Apple Software, with or without
+                       modifications, in source and/or binary forms; provided that if you redistribute
+                       the Apple Software in its entirety and without modifications, you must retain
+                       this notice and the following text and disclaimers in all such redistributions of
+                       the Apple Software.  Neither the name, trademarks, service marks or logos of
+                       Apple Computer, Inc. may be used to endorse or promote products derived from the
+                       Apple Software without specific prior written permission from Apple.  Except as
+                       expressly stated in this notice, no other rights or licenses, express or implied,
+                       are granted by Apple herein, including but not limited to any patent rights that
+                       may be infringed by your derivative works or by other works in which the Apple
+                       Software may be incorporated.
+
+                       The Apple Software is provided by Apple on an "AS IS" basis.  APPLE MAKES NO
+                       WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED
+                       WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+                       PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN
+                       COMBINATION WITH YOUR PRODUCTS.
+
+                       IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR
+                       CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+                       GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+                       ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION
+                       OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT
+                       (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN
+                       ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+/*=============================================================================
+       CAAudioFile.h
+       
+=============================================================================*/
+
+#ifndef __CAAudioFile_h__
+#define __CAAudioFile_h__
+
+#include <AvailabilityMacros.h>
+
+#if !defined(__COREAUDIO_USE_FLAT_INCLUDES__)
+       #include <AudioToolbox/AudioToolbox.h>
+#else
+       #include <AudioToolbox.h>
+#endif
+
+#include "CAStreamBasicDescription.h"
+#include "CABufferList.h"
+#include "CAAudioChannelLayout.h"
+#include "CAXException.h"
+#include "CAMath.h"
+
+#ifndef CAAF_USE_EXTAUDIOFILE
+// option: use AudioToolbox/ExtAudioFile.h? Only available on Tiger.
+       #if MAC_OS_X_VERSION_MIN_REQUIRED <= MAC_OS_X_VERSION_10_3
+               // we are building software that must be deployable on Panther or earlier
+               #define CAAF_USE_EXTAUDIOFILE 0
+       #else
+               // else we require Tiger and can use the API
+               #define CAAF_USE_EXTAUDIOFILE 1
+       #endif
+#endif
+
+#ifndef MAC_OS_X_VERSION_10_4
+       // we have pre-Tiger headers; add our own declarations
+       typedef UInt32 AudioFileTypeID;
+       enum {
+               kExtAudioFileError_InvalidProperty                      = -66561,
+               kExtAudioFileError_InvalidPropertySize          = -66562,
+               kExtAudioFileError_NonPCMClientFormat           = -66563,
+               kExtAudioFileError_InvalidChannelMap            = -66564,       // number of channels doesn't match format
+               kExtAudioFileError_InvalidOperationOrder        = -66565,
+               kExtAudioFileError_InvalidDataFormat            = -66566,
+               kExtAudioFileError_MaxPacketSizeUnknown         = -66567,
+               kExtAudioFileError_InvalidSeek                          = -66568,       // writing, or offset out of bounds
+               kExtAudioFileError_AsyncWriteTooLarge           = -66569,
+               kExtAudioFileError_AsyncWriteBufferOverflow     = -66570        // an async write could not be completed in time
+       };
+#else
+       #if !defined(__COREAUDIO_USE_FLAT_INCLUDES__)
+               #include <AudioToolbox/ExtendedAudioFile.h>
+       #else
+               #include "ExtendedAudioFile.h"
+       #endif
+#endif
+
+// _______________________________________________________________________________________
+// Wrapper class for an AudioFile, supporting encode/decode to/from a PCM client format
+class CAAudioFile {
+public:
+       // implementation-independent helpers
+       void    Open(const char *filePath) {
+               FSRef fsref;
+               XThrowIfError(FSPathMakeRef((UInt8 *)filePath, &fsref, NULL), "locate audio file");
+               Open(fsref);
+       }
+
+       bool                                                    HasConverter() const { return GetConverter() != NULL; }
+
+       double  GetDurationSeconds() {
+               double sr = GetFileDataFormat().mSampleRate;
+               return fnonzero(sr) ? GetNumberFrames() / sr : 0.;
+       }
+                               // will be 0 if the file's frames/packet is 0 (variable)
+                               // or the file's sample rate is 0 (unknown)
+
+#if CAAF_USE_EXTAUDIOFILE
+public:
+       CAAudioFile() : mExtAF(NULL) { }
+       virtual ~CAAudioFile() { if (mExtAF) Close(); }
+
+       void    Open(const FSRef &fsref) {
+                               // open an existing file
+               XThrowIfError(ExtAudioFileOpen(&fsref, &mExtAF), "ExtAudioFileOpen failed");
+       }
+       
+       void    CreateNew(const FSRef &inParentDir, CFStringRef inFileName,     AudioFileTypeID inFileType, const AudioStreamBasicDescription &inStreamDesc, const AudioChannelLayout *inChannelLayout=NULL) {
+               XThrowIfError(ExtAudioFileCreateNew(&inParentDir, inFileName, inFileType, &inStreamDesc, inChannelLayout, &mExtAF), "ExtAudioFileCreateNew failed");
+       }
+
+       void    Wrap(AudioFileID fileID, bool forWriting) {
+                               // use this to wrap an AudioFileID opened externally
+               XThrowIfError(ExtAudioFileWrapAudioFileID(fileID, forWriting, &mExtAF), "ExtAudioFileWrapAudioFileID failed");
+       }
+       
+       void    Close() {
+               XThrowIfError(ExtAudioFileDispose(mExtAF), "ExtAudioFileClose failed");
+               mExtAF = NULL;
+       }
+
+       const CAStreamBasicDescription &GetFileDataFormat() {
+               UInt32 size = sizeof(mFileDataFormat);
+               XThrowIfError(ExtAudioFileGetProperty(mExtAF, kExtAudioFileProperty_FileDataFormat, &size, &mFileDataFormat), "Couldn't get file's data format");
+               return mFileDataFormat;
+       }
+       
+       const CAAudioChannelLayout &    GetFileChannelLayout() {
+               return FetchChannelLayout(mFileChannelLayout, kExtAudioFileProperty_FileChannelLayout);
+       }
+       
+       void    SetFileChannelLayout(const CAAudioChannelLayout &layout) {
+               XThrowIfError(ExtAudioFileSetProperty(mExtAF, kExtAudioFileProperty_FileChannelLayout, layout.Size(), &layout.Layout()), "Couldn't set file's channel layout");
+               mFileChannelLayout = layout;
+       }
+
+       const CAStreamBasicDescription &GetClientDataFormat() {
+               UInt32 size = sizeof(mClientDataFormat);
+               XThrowIfError(ExtAudioFileGetProperty(mExtAF, kExtAudioFileProperty_ClientDataFormat, &size, &mClientDataFormat), "Couldn't get client data format");
+               return mClientDataFormat;
+       }
+       
+       const CAAudioChannelLayout &    GetClientChannelLayout() {
+               return FetchChannelLayout(mClientChannelLayout, kExtAudioFileProperty_ClientChannelLayout);
+       }
+       
+       void    SetClientFormat(const CAStreamBasicDescription &dataFormat, const CAAudioChannelLayout *layout=NULL) {
+               XThrowIfError(ExtAudioFileSetProperty(mExtAF, kExtAudioFileProperty_ClientDataFormat, sizeof(dataFormat), &dataFormat), "Couldn't set client format");
+               if (layout)
+                       SetClientChannelLayout(*layout);
+       }
+       
+       void    SetClientChannelLayout(const CAAudioChannelLayout &layout) {
+               XThrowIfError(ExtAudioFileSetProperty(mExtAF, kExtAudioFileProperty_ClientChannelLayout, layout.Size(), &layout.Layout()), "Couldn't set client channel layout");
+       }
+       
+       AudioConverterRef                               GetConverter() const {
+               UInt32 size = sizeof(AudioConverterRef);
+               AudioConverterRef converter;
+               XThrowIfError(ExtAudioFileGetProperty(mExtAF, kExtAudioFileProperty_AudioConverter, &size, &converter), "Couldn't get file's AudioConverter");
+               return converter;
+       }
+
+       OSStatus        SetConverterProperty(AudioConverterPropertyID inPropertyID,     UInt32 inPropertyDataSize, const void *inPropertyData, bool inCanFail=false)
+       {
+               OSStatus err = AudioConverterSetProperty(GetConverter(), inPropertyID, inPropertyDataSize, inPropertyData);
+               if (!inCanFail)
+                       XThrowIfError(err, "Couldn't set audio converter property");
+               if (!err) {
+                       // must tell the file that we have changed the converter; a NULL converter config is sufficient
+                       CFPropertyListRef config = NULL;
+                       XThrowIfError(ExtAudioFileSetProperty(mExtAF, kExtAudioFileProperty_ConverterConfig, sizeof(CFPropertyListRef), &config), "couldn't signal the file that the converter has changed");
+               }
+               return err;
+       }
+       
+       SInt64          GetNumberFrames() {
+               SInt64 length;
+               UInt32 size = sizeof(SInt64);
+               XThrowIfError(ExtAudioFileGetProperty(mExtAF, kExtAudioFileProperty_FileLengthFrames, &size, &length), "Couldn't get file's length");
+               return length;
+       }
+       
+       void            SetNumberFrames(SInt64 length) {
+               XThrowIfError(ExtAudioFileSetProperty(mExtAF, kExtAudioFileProperty_FileLengthFrames, sizeof(SInt64), &length), "Couldn't set file's length");
+       }
+       
+       void            Seek(SInt64 pos) {
+               XThrowIfError(ExtAudioFileSeek(mExtAF, pos), "Couldn't seek in audio file");
+       }
+       
+       SInt64          Tell() {
+               SInt64 pos;
+               XThrowIfError(ExtAudioFileTell(mExtAF, &pos), "Couldn't get file's mark");
+               return pos;
+       }
+       
+       void            Read(UInt32 &ioFrames, AudioBufferList *ioData) {
+               XThrowIfError(ExtAudioFileRead(mExtAF, &ioFrames, ioData), "Couldn't read audio file");
+       }
+
+       void            Write(UInt32 inFrames, const AudioBufferList *inData) {
+               XThrowIfError(ExtAudioFileWrite(mExtAF, inFrames, inData), "Couldn't write audio file");
+       }
+
+       void            SetIOBufferSizeBytes(UInt32 bufferSizeBytes) {
+               XThrowIfError(ExtAudioFileSetProperty(mExtAF, kExtAudioFileProperty_IOBufferSizeBytes, sizeof(UInt32), &bufferSizeBytes), "Couldn't set audio file's I/O buffer size");
+       }
+
+private:
+       const CAAudioChannelLayout &    FetchChannelLayout(CAAudioChannelLayout &layoutObj, ExtAudioFilePropertyID propID) {
+               UInt32 size;
+               XThrowIfError(ExtAudioFileGetPropertyInfo(mExtAF, propID, &size, NULL), "Couldn't get info about channel layout");
+               AudioChannelLayout *layout = (AudioChannelLayout *)malloc(size);
+               OSStatus err = ExtAudioFileGetProperty(mExtAF, propID, &size, layout);
+               if (err) {
+                       free(layout);
+                       XThrowIfError(err, "Couldn't get channel layout");
+               }
+               layoutObj = layout;
+               free(layout);
+               return layoutObj;
+       }
+
+
+private:
+       ExtAudioFileRef                         mExtAF;
+
+       CAStreamBasicDescription        mFileDataFormat;
+       CAAudioChannelLayout            mFileChannelLayout;
+
+       CAStreamBasicDescription        mClientDataFormat;
+       CAAudioChannelLayout            mClientChannelLayout;
+#endif
+
+#if !CAAF_USE_EXTAUDIOFILE
+       CAAudioFile();
+       virtual ~CAAudioFile();
+
+       // --- second-stage initializers ---
+       // Use exactly one of the following:
+       //              - Open
+       //              - PrepareNew followed by Create
+       //              - Wrap
+       
+       void    Open(const FSRef &fsref);
+                               // open an existing file
+
+       void    CreateNew(const FSRef &inParentDir, CFStringRef inFileName,     AudioFileTypeID inFileType, const AudioStreamBasicDescription &inStreamDesc, const AudioChannelLayout *inChannelLayout=NULL);
+       
+       void    Wrap(AudioFileID fileID, bool forWriting);
+                               // use this to wrap an AudioFileID opened externally
+
+       // ---
+
+       void    Close();
+                               // In case you want to close the file before the destructor executes
+       
+       // --- Data formats ---
+
+       // Allow specifying the file's channel layout. Must be called before SetClientFormat.
+       // When writing, the specified channel layout is written to the file (if the file format supports
+       // the channel layout). When reading, the specified layout overrides the one read from the file,
+       // if any.
+       void    SetFileChannelLayout(const CAAudioChannelLayout &layout);
+       
+       // This specifies the data format which the client will use for reading/writing the file,
+       // which may be different from the file's format. An AudioConverter is created if necessary.
+       // The client format must be linear PCM.
+       void    SetClientFormat(const CAStreamBasicDescription &dataFormat, const CAAudioChannelLayout *layout=NULL);
+       void    SetClientDataFormat(const CAStreamBasicDescription &dataFormat) { SetClientFormat(dataFormat, NULL); }
+       void    SetClientChannelLayout(const CAAudioChannelLayout &layout) { SetClientFormat(mClientDataFormat, &layout); }
+       
+       // Wrapping the underlying converter, if there is one
+       OSStatus        SetConverterProperty(AudioConverterPropertyID   inPropertyID,
+                                                                       UInt32                                          inPropertyDataSize,
+                                                                       const void *                            inPropertyData,
+                                                                       bool                                            inCanFail = false);
+       void            SetConverterConfig(CFArrayRef config) {
+                                       SetConverterProperty(kAudioConverterPropertySettings, sizeof(config), &config); }
+       CFArrayRef  GetConverterConfig();
+       
+       // --- I/O ---
+       // All I/O is sequential, but you can seek to an arbitrary position when reading.
+       // SeekToPacket and TellPacket's packet numbers are in the file's data format, not the client's.
+       // However, ReadPackets/WritePackets use packet counts in the client data format.
+
+       void    Read(UInt32 &ioNumFrames, AudioBufferList *ioData);
+       void    Write(UInt32 numFrames, const AudioBufferList *data);
+
+       // These can fail for files without a constant mFramesPerPacket
+       void    Seek(SInt64 frameNumber);
+       SInt64  Tell() const;   // frameNumber
+       
+       // --- Accessors ---
+       // note: client parameters only valid if SetClientFormat has been called
+       AudioFileID                                             GetAudioFileID() const { return mAudioFile; }
+       const CAStreamBasicDescription &GetFileDataFormat() const { return mFileDataFormat; }
+       const CAStreamBasicDescription &GetClientDataFormat() const { return mClientDataFormat; }
+       const CAAudioChannelLayout &    GetFileChannelLayout() const { return mFileChannelLayout; }
+       const CAAudioChannelLayout &    GetClientChannelLayout() const { return mClientChannelLayout; }
+       AudioConverterRef                               GetConverter() const { return mConverter; }
+
+       UInt32  GetFileMaxPacketSize() const { return mFileMaxPacketSize; }
+       UInt32  GetClientMaxPacketSize() const { return mClientMaxPacketSize; }
+       SInt64  GetNumberPackets() const {
+               SInt64 npackets;
+               UInt32 propertySize = sizeof(npackets);
+               XThrowIfError(AudioFileGetProperty(mAudioFile, kAudioFilePropertyAudioDataPacketCount, &propertySize, &npackets), "get audio file's packet count");
+               return npackets;
+       }
+       SInt64  GetNumberFrames() const;
+                               // will be 0 if the file's frames/packet is 0 (variable)
+       void    SetNumberFrames(SInt64 length); // should only be set on a PCM file
+       
+       // --- Tunable performance parameters ---
+       void    SetUseCache(bool b) { mUseCache = b; }
+       void    SetIOBufferSizeBytes(UInt32 bufferSizeBytes) { mIOBufferSizeBytes = bufferSizeBytes; }
+       UInt32  GetIOBufferSizeBytes() { return mIOBufferSizeBytes; }
+       void *  GetIOBuffer() { return mIOBufferList.mBuffers[0].mData; }
+       void    SetIOBuffer(void *buf);
+       
+       // -- Profiling ---
+#if CAAUDIOFILE_PROFILE
+       void    EnableProfiling(bool b) { mProfiling = b; }
+       UInt64  TicksInConverter() const { return (mTicksInConverter > 0) ? (mTicksInConverter - mTicksInReadInConverter) : 0; }
+       UInt64  TicksInIO() const { return mTicksInIO; }
+#endif
+       
+// _______________________________________________________________________________________
+private:
+       SInt64  FileDataOffset();
+       void    SeekToPacket(SInt64 packetNumber);
+       SInt64  TellPacket() const { return mPacketMark; }  // will be imprecise if SeekToFrame was called
+       
+       void    SetConverterChannelLayout(bool output, const CAAudioChannelLayout &layout);
+       void    WritePacketsFromCallback(
+                                                                       AudioConverterComplexInputDataProc      inInputDataProc,
+                                                                       void *                                                          inInputDataProcUserData);
+                               // will use I/O buffer size
+       void    InitFileMaxPacketSize();
+       void    FileFormatChanged(const FSRef *parentDir=0, CFStringRef filename=0, AudioFileTypeID filetype=0);
+
+       void    GetExistingFileInfo();
+       void    FlushEncoder();
+       void    CloseConverter();
+       void    UpdateClientMaxPacketSize();
+       void    AllocateBuffers(bool okToFail=false);
+       SInt64  PacketToFrame(SInt64 packet) const;
+       SInt64  FrameToPacket(SInt64 inFrame) const;
+
+       static OSStatus ReadInputProc(          AudioConverterRef                               inAudioConverter,
+                                                                               UInt32*                                                 ioNumberDataPackets,
+                                                                               AudioBufferList*                                ioData,
+                                                                               AudioStreamPacketDescription**  outDataPacketDescription,
+                                                                               void*                                                   inUserData);    
+
+       static OSStatus WriteInputProc(         AudioConverterRef                               inAudioConverter,
+                                                                               UInt32*                                                 ioNumberDataPackets,
+                                                                               AudioBufferList*                                ioData,
+                                                                               AudioStreamPacketDescription**  outDataPacketDescription,
+                                                                               void*                                                   inUserData);    
+// _______________________________________________________________________________________
+private:
+
+       // the file
+       FSRef                                           mFSRef;
+       AudioFileID                                     mAudioFile;
+       bool                                            mOwnOpenFile;
+       bool                                            mUseCache;
+       bool                                            mFinishingEncoding;
+       enum { kClosed, kReading, kPreparingToCreate, kPreparingToWrite, kWriting } mMode;
+       
+//     SInt64                                          mNumberPackets;         // in file's format
+       SInt64                                          mFileDataOffset;
+       SInt64                                          mPacketMark;            // in file's format
+       SInt64                                          mFrameMark;                     // this may be offset from the start of the file
+                                                                                                       // by the codec's latency; i.e. our frame 0 could
+                                                                                                       // lie at frame 2112 of a decoded AAC file
+       SInt32                                          mFrame0Offset;
+       UInt32                                          mFramesToSkipFollowingSeek;
+       
+       // buffers
+       UInt32                                          mIOBufferSizeBytes;
+       UInt32                                          mIOBufferSizePackets;
+       AudioBufferList                         mIOBufferList;          // only one buffer -- USE ACCESSOR so it can be lazily initialized
+       bool                                            mClientOwnsIOBuffer;
+       AudioStreamPacketDescription *mPacketDescs;
+       UInt32                                          mNumPacketDescs;
+       
+       // formats/conversion
+       AudioConverterRef                       mConverter;
+       CAStreamBasicDescription        mFileDataFormat;
+       CAStreamBasicDescription        mClientDataFormat;
+       CAAudioChannelLayout            mFileChannelLayout;
+       CAAudioChannelLayout            mClientChannelLayout;
+       UInt32                                          mFileMaxPacketSize;
+       UInt32                                          mClientMaxPacketSize;
+       
+       // cookie
+       Byte *                                          mMagicCookie;
+       UInt32                                          mMagicCookieSize;
+       
+       // for ReadPackets
+       UInt32                                          mMaxPacketsToRead;
+       
+       // for WritePackets
+       UInt32                                          mWritePackets;
+       CABufferList *                          mWriteBufferList;
+       
+#if CAAUDIOFILE_PROFILE
+       // performance
+       bool                                            mProfiling;
+       UInt64                                          mTicksInConverter;
+       UInt64                                          mTicksInReadInConverter;
+       UInt64                                          mTicksInIO;
+       bool                                            mInConverter;
+#endif
+
+#endif // CAAF_USE_EXTAUDIOFILE
+};
+
+#endif // __CAAudioFile_h__
diff --git a/libs/appleutility/CABufferList.cpp b/libs/appleutility/CABufferList.cpp
new file mode 100644 (file)
index 0000000..81298f9
--- /dev/null
@@ -0,0 +1,179 @@
+/*     Copyright:      � Copyright 2005 Apple Computer, Inc. All rights reserved.
+
+       Disclaimer:     IMPORTANT:  This Apple software is supplied to you by Apple Computer, Inc.
+                       ("Apple") in consideration of your agreement to the following terms, and your
+                       use, installation, modification or redistribution of this Apple software
+                       constitutes acceptance of these terms.  If you do not agree with these terms,
+                       please do not use, install, modify or redistribute this Apple software.
+
+                       In consideration of your agreement to abide by the following terms, and subject
+                       to these terms, Apple grants you a personal, non-exclusive license, under Apple�s
+                       copyrights in this original Apple software (the "Apple Software"), to use,
+                       reproduce, modify and redistribute the Apple Software, with or without
+                       modifications, in source and/or binary forms; provided that if you redistribute
+                       the Apple Software in its entirety and without modifications, you must retain
+                       this notice and the following text and disclaimers in all such redistributions of
+                       the Apple Software.  Neither the name, trademarks, service marks or logos of
+                       Apple Computer, Inc. may be used to endorse or promote products derived from the
+                       Apple Software without specific prior written permission from Apple.  Except as
+                       expressly stated in this notice, no other rights or licenses, express or implied,
+                       are granted by Apple herein, including but not limited to any patent rights that
+                       may be infringed by your derivative works or by other works in which the Apple
+                       Software may be incorporated.
+
+                       The Apple Software is provided by Apple on an "AS IS" basis.  APPLE MAKES NO
+                       WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED
+                       WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+                       PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN
+                       COMBINATION WITH YOUR PRODUCTS.
+
+                       IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR
+                       CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+                       GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+                       ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION
+                       OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT
+                       (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN
+                       ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+/*=============================================================================
+       CABufferList.cpp
+       
+=============================================================================*/
+
+#include "CABufferList.h"
+#if !defined(__COREAUDIO_USE_FLAT_INCLUDES__)
+       #include <CoreServices/CoreServices.h>
+#else
+       #include <Endian.h>
+#endif
+
+void           CABufferList::AllocateBuffers(UInt32 nBytes)
+{
+       if (nBytes <= GetNumBytes()) return;
+       
+       if (mNumberBuffers > 1)
+               // align successive buffers for Altivec and to take alternating
+               // cache line hits by spacing them by odd multiples of 16
+               nBytes = (nBytes + (0x10 - (nBytes & 0xF))) | 0x10;
+       UInt32 memorySize = nBytes * mNumberBuffers;
+       Byte *newMemory = new Byte[memorySize], *p = newMemory;
+       memset(newMemory, 0, memorySize);       // get page faults now, not later
+       
+       AudioBuffer *buf = mBuffers;
+       for (UInt32 i = mNumberBuffers; i--; ++buf) {
+               if (buf->mData != NULL && buf->mDataByteSize > 0)
+                       // preserve existing buffer contents
+                       memcpy(p, buf->mData, buf->mDataByteSize);
+               buf->mDataByteSize = nBytes;
+               buf->mData = p;
+               p += nBytes;
+       }
+       Byte *oldMemory = mBufferMemory;
+       mBufferMemory = newMemory;
+       delete[] oldMemory;
+}
+
+void           CABufferList::AllocateBuffersAndCopyFrom(UInt32 nBytes, CABufferList *inSrcList, CABufferList *inSetPtrList)
+{
+       if (mNumberBuffers != inSrcList->mNumberBuffers) return;
+       if (mNumberBuffers != inSetPtrList->mNumberBuffers) return;
+       if (nBytes <= GetNumBytes()) {
+               CopyAllFrom(inSrcList, inSetPtrList);
+               return;
+       }
+       inSetPtrList->VerifyNotTrashingOwnedBuffer();
+       UInt32 fromByteSize = inSrcList->GetNumBytes();
+       
+       if (mNumberBuffers > 1)
+               // align successive buffers for Altivec and to take alternating
+               // cache line hits by spacing them by odd multiples of 16
+               nBytes = (nBytes + (0x10 - (nBytes & 0xF))) | 0x10;
+       UInt32 memorySize = nBytes * mNumberBuffers;
+       Byte *newMemory = new Byte[memorySize], *p = newMemory;
+       memset(newMemory, 0, memorySize);       // make buffer "hot"
+       
+       AudioBuffer *buf = mBuffers;
+       AudioBuffer *ptrBuf = inSetPtrList->mBuffers;
+       AudioBuffer *srcBuf = inSrcList->mBuffers;
+       for (UInt32 i = mNumberBuffers; i--; ++buf, ++ptrBuf, ++srcBuf) {
+               if (srcBuf->mData != NULL && srcBuf->mDataByteSize > 0)
+                       // preserve existing buffer contents
+                       memmove(p, srcBuf->mData, srcBuf->mDataByteSize);
+               buf->mDataByteSize = nBytes;
+               buf->mData = p;
+               ptrBuf->mDataByteSize = srcBuf->mDataByteSize;
+               ptrBuf->mData = p;
+               p += nBytes;
+       }
+       Byte *oldMemory = mBufferMemory;
+       mBufferMemory = newMemory;
+       if (inSrcList != inSetPtrList)
+               inSrcList->BytesConsumed(fromByteSize);
+       delete[] oldMemory;
+}
+
+void           CABufferList::DeallocateBuffers()
+{
+       AudioBuffer *buf = mBuffers;
+       for (UInt32 i = mNumberBuffers; i--; ++buf) {
+               buf->mData = NULL;
+               buf->mDataByteSize = 0;
+       }
+       if (mBufferMemory != NULL) {
+               delete[] mBufferMemory;
+               mBufferMemory = NULL;
+       }
+    
+}
+
+extern "C" void CAShowAudioBufferList(const AudioBufferList *abl, int framesToPrint, int wordSize)
+{
+       printf("AudioBufferList @ %p:\n", abl);
+       const AudioBuffer *buf = abl->mBuffers;
+       for (UInt32 i = 0; i < abl->mNumberBuffers; ++i, ++buf) {
+               printf("  [%2ld]: %2ldch, %5ld bytes @ %8p", 
+                       i, buf->mNumberChannels, buf->mDataByteSize, buf->mData);
+               if (framesToPrint) {
+                       printf(":");
+                       Byte *p = (Byte *)buf->mData;
+                       for (int j = framesToPrint * buf->mNumberChannels; --j >= 0; )
+                               switch (wordSize) {
+                               case 0:
+                                       printf(" %6.3f", *(Float32 *)p);
+                                       p += sizeof(Float32);
+                                       break;
+                               case 1:
+                               case -1:
+                                       printf(" %02X", *p);
+                                       p += 1;
+                                       break;
+                               case 2:
+                                       printf(" %04X", EndianU16_BtoN(*(UInt16 *)p));
+                                       p += 2;
+                                       break;
+                               case 3:
+                                       printf(" %06X", (p[0] << 16) | (p[1] << 8) | p[2]);
+                                       p += 3;
+                                       break;
+                               case 4:
+                                       printf(" %08lX", EndianU32_BtoN(*(UInt32 *)p));
+                                       p += 4;
+                                       break;
+                               case -2:
+                                       printf(" %04X", EndianU16_LtoN(*(UInt16 *)p));
+                                       p += 2;
+                                       break;
+                               case -3:
+                                       printf(" %06X", (p[2] << 16) | (p[1] << 8) | p[0]);
+                                       p += 3;
+                                       break;
+                               case -4:
+                                       printf(" %08lX", EndianU32_LtoN(*(UInt32 *)p));
+                                       p += 4;
+                                       break;
+                               }
+               }
+               printf("\n");
+       }
+}
+
diff --git a/libs/appleutility/CABufferList.h b/libs/appleutility/CABufferList.h
new file mode 100644 (file)
index 0000000..3b0cef9
--- /dev/null
@@ -0,0 +1,300 @@
+/*     Copyright:      � Copyright 2005 Apple Computer, Inc. All rights reserved.
+
+       Disclaimer:     IMPORTANT:  This Apple software is supplied to you by Apple Computer, Inc.
+                       ("Apple") in consideration of your agreement to the following terms, and your
+                       use, installation, modification or redistribution of this Apple software
+                       constitutes acceptance of these terms.  If you do not agree with these terms,
+                       please do not use, install, modify or redistribute this Apple software.
+
+                       In consideration of your agreement to abide by the following terms, and subject
+                       to these terms, Apple grants you a personal, non-exclusive license, under Apple�s
+                       copyrights in this original Apple software (the "Apple Software"), to use,
+                       reproduce, modify and redistribute the Apple Software, with or without
+                       modifications, in source and/or binary forms; provided that if you redistribute
+                       the Apple Software in its entirety and without modifications, you must retain
+                       this notice and the following text and disclaimers in all such redistributions of
+                       the Apple Software.  Neither the name, trademarks, service marks or logos of
+                       Apple Computer, Inc. may be used to endorse or promote products derived from the
+                       Apple Software without specific prior written permission from Apple.  Except as
+                       expressly stated in this notice, no other rights or licenses, express or implied,
+                       are granted by Apple herein, including but not limited to any patent rights that
+                       may be infringed by your derivative works or by other works in which the Apple
+                       Software may be incorporated.
+
+                       The Apple Software is provided by Apple on an "AS IS" basis.  APPLE MAKES NO
+                       WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED
+                       WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+                       PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN
+                       COMBINATION WITH YOUR PRODUCTS.
+
+                       IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR
+                       CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+                       GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+                       ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION
+                       OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT
+                       (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN
+                       ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+/*=============================================================================
+       CABufferList.h
+       
+=============================================================================*/
+
+#ifndef __CABufferList_h__
+#define __CABufferList_h__
+
+#include <stddef.h>
+#include "CAStreamBasicDescription.h"
+#if !defined(__COREAUDIO_USE_FLAT_INCLUDES__)
+       #include <CoreServices/CoreServices.h>
+#else
+       #include <AssertMacros.h>
+#endif
+
+extern "C" void CAShowAudioBufferList(const AudioBufferList *abl, int framesToPrint, int wordSize);
+                               // wordSize: 0 = float32, else integer word size, negative if little-endian
+
+/* ____________________________________________________________________________
+//     CABufferList - variable length buffer list
+
+       This class is designed for use in non-simplistic cases. For AudioUnits, AUBufferList
+       is preferred.
+       
+       CABufferList can be used in one of two ways:
+               - as mutable pointers into non-owned memory
+               - as an immutable array of buffers (owns its own memory).
+
+       All buffers are assumed to have the same format (number of channels, word size), so that
+               we can assume their mDataByteSizes are all the same.
+____________________________________________________________________________ */
+class CABufferList {
+public:
+       void *  operator new(size_t /*size*/, int nBuffers) {
+                               return ::operator new(sizeof(CABufferList) + (nBuffers-1) * sizeof(AudioBuffer));
+                       }
+       static CABufferList *   New(const char *name, const CAStreamBasicDescription &format)
+       {
+               UInt32 numBuffers = format.NumberChannelStreams(), channelsPerBuffer = format.NumberInterleavedChannels();
+               return new(numBuffers) CABufferList(name, numBuffers, channelsPerBuffer);
+       }
+
+protected:
+       CABufferList(const char *name, UInt32 numBuffers, UInt32 channelsPerBuffer) :
+               mName(name),
+               mBufferMemory(NULL)
+       {
+               check(numBuffers > 0 /*&& channelsPerBuffer > 0*/);
+               mNumberBuffers = numBuffers;
+               AudioBuffer *buf = mBuffers;
+               for (UInt32 i = mNumberBuffers; i--; ++buf) {
+                       buf->mNumberChannels = channelsPerBuffer;
+                       buf->mDataByteSize = 0;
+                       buf->mData = NULL;
+               }
+       }
+
+public:
+       ~CABufferList()
+       {
+               if (mBufferMemory)
+                       delete[] mBufferMemory;
+       }
+       
+       const char *                            Name() { return mName; }
+       
+       const AudioBufferList &         GetBufferList() const { return *(AudioBufferList *)&mNumberBuffers; }
+       
+       AudioBufferList &                       GetModifiableBufferList()
+       {
+               VerifyNotTrashingOwnedBuffer();
+               return _GetBufferList();
+       }
+       
+       UInt32          GetNumBytes() const
+       {
+               return mBuffers[0].mDataByteSize;
+       }
+       
+       void            SetBytes(UInt32 nBytes, void *data)
+       {
+               VerifyNotTrashingOwnedBuffer();
+               check(mNumberBuffers == 1);
+               mBuffers[0].mDataByteSize = nBytes;
+               mBuffers[0].mData = data;
+       }
+       
+       void            CopyAllFrom(CABufferList *srcbl, CABufferList *ptrbl)
+                                       // copies bytes from srcbl
+                                       // make ptrbl reflect the length copied
+                                       // note that srcbl may be same as ptrbl!
+       {
+               // Note that this buffer *can* own memory and its pointers/lengths are not
+               // altered; only its buffer contents, which are copied from srcbl.
+               // The pointers/lengths in ptrbl are updated to reflect the addresses/lengths
+               // of the copied data, and srcbl's contents are consumed.
+               ptrbl->VerifyNotTrashingOwnedBuffer();
+               UInt32 nBytes = srcbl->GetNumBytes();
+               AudioBuffer *mybuf = mBuffers, *srcbuf = srcbl->mBuffers,
+                                       *ptrbuf = ptrbl->mBuffers;
+               for (UInt32 i = mNumberBuffers; i--; ++mybuf, ++srcbuf, ++ptrbuf) {
+                       memmove(mybuf->mData, srcbuf->mData, srcbuf->mDataByteSize);
+                       ptrbuf->mData = mybuf->mData;
+                       ptrbuf->mDataByteSize = srcbuf->mDataByteSize;
+               }
+               if (srcbl != ptrbl)
+                       srcbl->BytesConsumed(nBytes);
+       }
+       
+       void            AppendFrom(CABufferList *blp, UInt32 nBytes)
+       {
+               VerifyNotTrashingOwnedBuffer();
+               AudioBuffer *mybuf = mBuffers, *srcbuf = blp->mBuffers;
+               for (UInt32 i = mNumberBuffers; i--; ++mybuf, ++srcbuf) {
+                       check(nBytes <= srcbuf->mDataByteSize);
+                       memcpy((Byte *)mybuf->mData + mybuf->mDataByteSize, srcbuf->mData, nBytes);
+                       mybuf->mDataByteSize += nBytes;
+               }
+               blp->BytesConsumed(nBytes);
+       }
+       
+       void            PadWithZeroes(UInt32 desiredBufferSize)
+                                       // for cases where an algorithm (e.g. SRC) requires some
+                                       // padding to create silence following end-of-file
+       {
+               VerifyNotTrashingOwnedBuffer();
+               if (GetNumBytes() > desiredBufferSize) return;
+               AudioBuffer *buf = mBuffers;
+               for (UInt32 i = mNumberBuffers; i--; ++buf) {
+                       memset((Byte *)buf->mData + buf->mDataByteSize, 0, desiredBufferSize - buf->mDataByteSize);
+                       buf->mDataByteSize = desiredBufferSize;
+               }
+       }
+       
+       void            SetToZeroes(UInt32 nBytes)
+       {
+               VerifyNotTrashingOwnedBuffer();
+               AudioBuffer *buf = mBuffers;
+               for (UInt32 i = mNumberBuffers; i--; ++buf) {
+                       memset((Byte *)buf->mData, 0, nBytes);
+                       buf->mDataByteSize = nBytes;
+               }
+       }
+       
+       void            Reset()
+       {
+               DeallocateBuffers();
+       }
+       
+       Boolean SameDataAs(const CABufferList* anotherBufferList)
+       {
+               // check to see if two buffer lists point to the same memory.
+               if (mNumberBuffers != anotherBufferList->mNumberBuffers) return false;
+               
+               for (UInt32 i = 0; i < mNumberBuffers; ++i) {
+                       if (mBuffers[i].mData != anotherBufferList->mBuffers[i].mData) return false;
+               }
+               return true;
+       }
+       
+       void            BytesConsumed(UInt32 nBytes)
+                                       // advance buffer pointers, decrease buffer sizes
+       {
+               VerifyNotTrashingOwnedBuffer();
+               AudioBuffer *buf = mBuffers;
+               for (UInt32 i = mNumberBuffers; i--; ++buf) {
+                       check(nBytes <= buf->mDataByteSize);
+                       buf->mData = (Byte *)buf->mData + nBytes;
+                       buf->mDataByteSize -= nBytes;
+               }
+       }
+       
+       void            SetFrom(const AudioBufferList *abl)
+       {
+               VerifyNotTrashingOwnedBuffer();
+               memcpy(&_GetBufferList(), abl, (char *)&abl->mBuffers[abl->mNumberBuffers] - (char *)abl);
+       }
+       
+       void            SetFrom(const CABufferList *blp)
+       {
+               SetFrom(&blp->GetBufferList());
+       }
+       
+       void            SetFrom(const AudioBufferList *abl, UInt32 nBytes)
+       {
+               VerifyNotTrashingOwnedBuffer();
+               AudioBuffer *mybuf = mBuffers;
+               const AudioBuffer *srcbuf = abl->mBuffers;
+               for (UInt32 i = mNumberBuffers; i--; ++mybuf, ++srcbuf) {
+                       mybuf->mNumberChannels = srcbuf->mNumberChannels;
+                       mybuf->mDataByteSize = nBytes;
+                       mybuf->mData = srcbuf->mData;
+               }
+       }
+       
+       void            SetFrom(const CABufferList *blp, UInt32 nBytes)
+       {
+               SetFrom(&blp->GetBufferList(), nBytes);
+       }
+       
+       AudioBufferList *       ToAudioBufferList(AudioBufferList *abl) const
+       {
+               memcpy(abl, &GetBufferList(), (char *)&abl->mBuffers[mNumberBuffers] - (char *)abl);
+               return abl;
+       }
+       
+       void            AllocateBuffers(UInt32 nBytes);
+       void            AllocateBuffersAndCopyFrom(UInt32 nBytes, CABufferList *inCopyFromList, CABufferList *inSetPtrList);
+       
+       void            DeallocateBuffers();
+       
+       void            UseExternalBuffer(Byte *ptr, UInt32 nBytes);
+    
+       void            AdvanceBufferPointers(UInt32 nBytes)
+                                       // this is for bufferlists that function simply as
+                                       // an array of pointers into another bufferlist, being advanced,
+                                       // as in RenderOutput implementations
+       {
+               VerifyNotTrashingOwnedBuffer();
+               AudioBuffer *buf = mBuffers;
+               for (UInt32 i = mNumberBuffers; i--; ++buf) {
+                       buf->mData = (Byte *)buf->mData + nBytes;
+                       buf->mDataByteSize -= nBytes;
+               }
+       }
+       
+       void            SetNumBytes(UInt32 nBytes)
+       {
+               VerifyNotTrashingOwnedBuffer();
+               AudioBuffer *buf = mBuffers;
+               for (UInt32 i = mNumberBuffers; i--; ++buf)
+                       buf->mDataByteSize = nBytes;
+       }
+
+       void            Print(const char *label=NULL, int nframes=0, int wordSize=0) const
+       {
+               if (label == NULL)
+                       label = mName;
+               printf("%s - ", label);
+               CAShowAudioBufferList(&GetBufferList(), nframes, wordSize);
+               if (mBufferMemory)
+                       printf("  owned memory @ 0x%p:\n", mBufferMemory);
+       }
+
+protected:
+       AudioBufferList &       _GetBufferList() { return *(AudioBufferList *)&mNumberBuffers; }        // use with care
+                                                       // if we make this public, then we lose ability to call VerifyNotTrashingOwnedBuffer
+       void                            VerifyNotTrashingOwnedBuffer()
+       {
+               // This needs to be called from places where we are modifying the buffer list.
+               // It's an error to modify the buffer pointers or lengths if we own the buffer memory.
+               check(mBufferMemory == NULL);
+       }
+
+       const char *                                            mName;  // for debugging
+       Byte *                                                          mBufferMemory;
+       // the rest must exactly mirror the structure of AudioBufferList
+       UInt32                                                          mNumberBuffers;
+       AudioBuffer                                                     mBuffers[1];
+};
+
+#endif // __CABufferList_h__
diff --git a/libs/appleutility/CAXException.cpp b/libs/appleutility/CAXException.cpp
new file mode 100644 (file)
index 0000000..088575f
--- /dev/null
@@ -0,0 +1,45 @@
+/*     Copyright:      � Copyright 2005 Apple Computer, Inc. All rights reserved.
+
+       Disclaimer:     IMPORTANT:  This Apple software is supplied to you by Apple Computer, Inc.
+                       ("Apple") in consideration of your agreement to the following terms, and your
+                       use, installation, modification or redistribution of this Apple software
+                       constitutes acceptance of these terms.  If you do not agree with these terms,
+                       please do not use, install, modify or redistribute this Apple software.
+
+                       In consideration of your agreement to abide by the following terms, and subject
+                       to these terms, Apple grants you a personal, non-exclusive license, under Apple�s
+                       copyrights in this original Apple software (the "Apple Software"), to use,
+                       reproduce, modify and redistribute the Apple Software, with or without
+                       modifications, in source and/or binary forms; provided that if you redistribute
+                       the Apple Software in its entirety and without modifications, you must retain
+                       this notice and the following text and disclaimers in all such redistributions of
+                       the Apple Software.  Neither the name, trademarks, service marks or logos of
+                       Apple Computer, Inc. may be used to endorse or promote products derived from the
+                       Apple Software without specific prior written permission from Apple.  Except as
+                       expressly stated in this notice, no other rights or licenses, express or implied,
+                       are granted by Apple herein, including but not limited to any patent rights that
+                       may be infringed by your derivative works or by other works in which the Apple
+                       Software may be incorporated.
+
+                       The Apple Software is provided by Apple on an "AS IS" basis.  APPLE MAKES NO
+                       WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED
+                       WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+                       PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN
+                       COMBINATION WITH YOUR PRODUCTS.
+
+                       IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR
+                       CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+                       GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+                       ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION
+                       OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT
+                       (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN
+                       ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+/*=============================================================================
+       CAXException.cpp
+       
+=============================================================================*/
+
+#include "CAXException.h"
+
+CAXException::WarningHandler CAXException::sWarningHandler = NULL;
diff --git a/libs/appleutility/CAXException.h b/libs/appleutility/CAXException.h
new file mode 100644 (file)
index 0000000..7961197
--- /dev/null
@@ -0,0 +1,158 @@
+/*     Copyright:      � Copyright 2005 Apple Computer, Inc. All rights reserved.
+
+       Disclaimer:     IMPORTANT:  This Apple software is supplied to you by Apple Computer, Inc.
+                       ("Apple") in consideration of your agreement to the following terms, and your
+                       use, installation, modification or redistribution of this Apple software
+                       constitutes acceptance of these terms.  If you do not agree with these terms,
+                       please do not use, install, modify or redistribute this Apple software.
+
+                       In consideration of your agreement to abide by the following terms, and subject
+                       to these terms, Apple grants you a personal, non-exclusive license, under Apple�s
+                       copyrights in this original Apple software (the "Apple Software"), to use,
+                       reproduce, modify and redistribute the Apple Software, with or without
+                       modifications, in source and/or binary forms; provided that if you redistribute
+                       the Apple Software in its entirety and without modifications, you must retain
+                       this notice and the following text and disclaimers in all such redistributions of
+                       the Apple Software.  Neither the name, trademarks, service marks or logos of
+                       Apple Computer, Inc. may be used to endorse or promote products derived from the
+                       Apple Software without specific prior written permission from Apple.  Except as
+                       expressly stated in this notice, no other rights or licenses, express or implied,
+                       are granted by Apple herein, including but not limited to any patent rights that
+                       may be infringed by your derivative works or by other works in which the Apple
+                       Software may be incorporated.
+
+                       The Apple Software is provided by Apple on an "AS IS" basis.  APPLE MAKES NO
+                       WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED
+                       WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+                       PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN
+                       COMBINATION WITH YOUR PRODUCTS.
+
+                       IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR
+                       CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+                       GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+                       ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION
+                       OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT
+                       (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN
+                       ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+/*=============================================================================
+       CAXException.h
+       
+=============================================================================*/
+
+#ifndef __CAXException_h__
+#define __CAXException_h__
+
+#if !defined(__COREAUDIO_USE_FLAT_INCLUDES__)
+       #include <CoreServices/CoreServices.h>
+#else
+       #include <ConditionalMacros.h>
+       #include <CoreServices.h>
+#endif
+#include "CADebugMacros.h"
+#include <ctype.h>
+#include <stdio.h>
+#include <string.h>
+
+// An extended exception class that includes the name of the failed operation
+class CAXException {
+public:
+       CAXException(const char *operation, OSStatus err) :
+               mError(err)
+               {
+                       if (operation == NULL)
+                               mOperation[0] = '\0';
+                       else if (strlen(operation) >= sizeof(mOperation)) {
+                               memcpy(mOperation, operation, sizeof(mOperation) - 1);
+                               mOperation[sizeof(mOperation) - 1] = '\0';
+                       } else
+                               strcpy(mOperation, operation);
+               }
+       
+       char *FormatError(char *str) const
+       {
+               return FormatError(str, mError);
+       }
+       
+       char                            mOperation[256];
+       const OSStatus          mError;
+       
+       // -------------------------------------------------
+       
+       typedef void (*WarningHandler)(const char *msg, OSStatus err);
+       
+       /*static void Throw(const char *operation, OSStatus err)
+       {
+               throw CAXException(operation, err);
+       }*/
+       
+       static char *FormatError(char *str, OSStatus error)
+       {
+               // see if it appears to be a 4-char-code
+               *(UInt32 *)(str + 1) = EndianU32_NtoB(error);
+               if (isprint(str[1]) && isprint(str[2]) && isprint(str[3]) && isprint(str[4])) {
+                       str[0] = str[5] = '\'';
+                       str[6] = '\0';
+               } else
+                       // no, format it as an integer
+                       sprintf(str, "%ld", error);
+               return str;
+       }
+       
+       static void Warning(const char *s, OSStatus error)
+       {
+               if (sWarningHandler)
+                       (*sWarningHandler)(s, error);
+       }
+       
+       static void SetWarningHandler(WarningHandler f) { sWarningHandler = f; }
+private:
+       static WarningHandler   sWarningHandler;
+};
+
+#if    DEBUG || CoreAudio_Debug
+       #define XThrowIfError(error, operation) \
+               do {                                                                                                                                    \
+                       OSStatus __err = error;                                                                                         \
+                       if (__err) {                                                                                                                    \
+                               char __buf[12];                                                                                                 \
+                               DebugMessageN2("error %s: %4s\n", CAXException::FormatError(__buf, __err), operation);\
+                               STOP;                                                                                                                   \
+                               throw CAXException(operation, __err);           \
+                       }                                                                                                                                       \
+               } while (0)
+
+       #define XThrowIf(condition, error, operation) \
+               do {                                                                                                                                    \
+                       if (condition) {                                                                                                        \
+                               OSStatus __err = error;                                                                                 \
+                               char __buf[12];                                                                                                 \
+                               DebugMessageN2("error %s: %4s\n", CAXException::FormatError(__buf, __err), operation);\
+                               STOP;                                                                                                                   \
+                               throw CAXException(operation, __err);           \
+                       }                                                                                                                                       \
+               } while (0)
+
+#else
+       #define XThrowIfError(error, operation) \
+               do {                                                                                                                                    \
+                       OSStatus __err = error;                                                                                         \
+                       if (__err) {                                                                                                                    \
+                               throw CAXException(operation, __err);           \
+                       }                                                                                                                                       \
+               } while (0)
+
+       #define XThrowIf(condition, error, operation) \
+               do {                                                                                                                                    \
+                       if (condition) {                                                                                                        \
+                               OSStatus __err = error;                                                                                 \
+                               throw CAXException(operation, __err);           \
+                       }                                                                                                                                       \
+               } while (0)
+
+#endif
+
+#define XThrow(error, operation) XThrowIf(true, error, operation)
+#define XThrowIfErr(error) XThrowIfError(error, #error)
+
+#endif // __CAXException_h__
index cf25c466eef501b9cb627b01d63f2eea506ac9de..6aa3722ed72685f4f3a75f113ca6b770b23ae610 100644 (file)
@@ -20,8 +20,9 @@
 #ifndef __coreaudio_source_h__ 
 #define __coreaudio_source_h__
 
+#include <appleutility/CAAudioFile.h>
+
 #include <ardour/audiofilesource.h>
-#include <AudioToolbox/ExtendedAudioFile.h>
 
 namespace ARDOUR {
 
@@ -45,7 +46,7 @@ class CoreAudioSource : public AudioFileSource {
        
 
   private:
-       ExtAudioFileRef af;
+       mutable CAAudioFile af;
        uint16_t n_channels;
 
        mutable float *tmpbuf;
index 0d7e690a25b2f343e1811398f4518ca951c1f1f5..fa22dde3471e407558e17fc67065cb4761ce1d1d 100644 (file)
@@ -20,6 +20,9 @@
 #include <pbd/error.h>
 #include <ardour/coreaudiosource.h>
 
+#include <appleutility/CAAudioFile.h>
+#include <appleutility/CAStreamBasicDescription.h>
+
 #include "i18n.h"
 
 #include <AudioToolbox/AudioFormat.h>
@@ -43,93 +46,48 @@ void
 CoreAudioSource::init (const string& idstr)
 {
        string::size_type pos;
-       string file;
 
        tmpbuf = 0;
        tmpbufsize = 0;
-       af = 0;
-       OSStatus err = noErr;
 
        _name = idstr;
 
        if ((pos = idstr.find_last_of (':')) == string::npos) {
                channel = 0;
-               file = idstr;
+               _path = idstr;
        } else {
                channel = atoi (idstr.substr (pos+1).c_str());
-               file = idstr.substr (0, pos);
-       }
-
-       /* note that we temporarily truncated _id at the colon */
-       FSRef fsr;
-       err = FSPathMakeRef ((UInt8*)file.c_str(), &fsr, 0);
-       if (err != noErr) {
-               error << string_compose (_("Could not make reference to file: %1"), name()) << endmsg;
-               throw failed_constructor();
-       }
-
-       err = ExtAudioFileOpen (&fsr, &af);
-       if (err != noErr) {
-               error << string_compose (_("Could not open file: %1"), name()) << endmsg;
-               ExtAudioFileDispose (af);
-               throw failed_constructor();
+               _path = idstr.substr (0, pos);
        }
 
-       AudioStreamBasicDescription file_asbd;
-       memset(&file_asbd, 0, sizeof(AudioStreamBasicDescription));
-       size_t asbd_size = sizeof(AudioStreamBasicDescription);
-       err = ExtAudioFileGetProperty(af,
-                       kExtAudioFileProperty_FileDataFormat, &asbd_size, &file_asbd);
-       if (err != noErr) {
-               error << string_compose (_("Could not get file data format for file: %1"), name()) << endmsg;
-               ExtAudioFileDispose (af);
-               throw failed_constructor();
-       }
-       n_channels = file_asbd.mChannelsPerFrame;
-
-       cerr << "number of channels: " << n_channels << endl;
+       cerr << "CoreAudioSource::init() " << name() << endl;
        
-       if (channel >= n_channels) {
-               error << string_compose(_("CoreAudioSource: file only contains %1 channels; %2 is invalid as a channel number"), n_channels, channel) << endmsg;
-               ExtAudioFileDispose (af);
-               throw failed_constructor();
-       }
+       /* note that we temporarily truncated _id at the colon */
+       try {
+               af.Open(_path.c_str());
 
-       int64_t ca_frames;
-       size_t prop_size = sizeof(int64_t);
+               CAStreamBasicDescription file_asbd (af.GetFileDataFormat());
+               n_channels = file_asbd.NumberChannels();
+               cerr << "number of channels: " << n_channels << endl;
+               
+               if (channel >= n_channels) {
+                       error << string_compose("CoreAudioSource: file only contains %1 channels; %2 is invalid as a channel number (%3)", n_channels, channel, name()) << endmsg;
+                       throw failed_constructor();
+               }
 
-       err = ExtAudioFileGetProperty(af, kExtAudioFileProperty_FileLengthFrames, &prop_size, &ca_frames);
-       if (err != noErr) {
-               error << string_compose (_("Could not get file length for file: %1"), name()) << endmsg;
-               ExtAudioFileDispose (af);
-               throw failed_constructor();
-       }
+               _length = af.GetNumberFrames();
 
-       _length = ca_frames;
-       _path = file;
-
-       AudioStreamBasicDescription client_asbd;
-       memset(&client_asbd, 0, sizeof(AudioStreamBasicDescription));
-       client_asbd.mSampleRate = file_asbd.mSampleRate;
-       client_asbd.mFormatID = kAudioFormatLinearPCM;
-       client_asbd.mFormatFlags = kLinearPCMFormatFlagIsFloat;
-       client_asbd.mBytesPerPacket = file_asbd.mChannelsPerFrame * 4;
-       client_asbd.mFramesPerPacket = 1;
-       client_asbd.mBytesPerFrame = client_asbd.mBytesPerPacket;
-       client_asbd.mChannelsPerFrame = file_asbd.mChannelsPerFrame;
-       client_asbd.mBitsPerChannel = 32;
-
-       err = ExtAudioFileSetProperty (af, kExtAudioFileProperty_ClientDataFormat, asbd_size, &client_asbd);
-       if (err != noErr) {
-               error << string_compose (_("Could not set client data format for file: %1"), name()) << endmsg;
-               ExtAudioFileDispose (af);
+               CAStreamBasicDescription client_asbd(file_asbd);
+               client_asbd.SetCanonical(client_asbd.NumberChannels(), false);
+               af.SetClientFormat (client_asbd);
+       } catch (CAXException& cax) {
+               error << string_compose ("CoreAudioSource: %1 (%2)", cax.mOperation, name()) << endmsg;
                throw failed_constructor ();
        }
        
        if (_build_peakfiles) {
-               if (initialize_peakfile (false, file)) {
-                       error << string_compose(_("initialize peakfile failed for file %1"), name()) << endmsg;
-                       ExtAudioFileDispose (af);
+               if (initialize_peakfile (false, _path)) {
+                       error << string_compose("CoreAudioSource: initialize peakfile failed (%1)", name()) << endmsg;
                        throw failed_constructor ();
                }
        }
@@ -137,41 +95,44 @@ CoreAudioSource::init (const string& idstr)
 
 CoreAudioSource::~CoreAudioSource ()
 {
+       cerr << "CoreAudioSource::~CoreAudioSource() " << name() << endl;
        GoingAway (); /* EMIT SIGNAL */
 
-       if (af) {
-               ExtAudioFileDispose (af);
-       }
-
        if (tmpbuf) {
                delete [] tmpbuf;
        }
+       
+       cerr << "deletion done" << endl;
 }
 
 jack_nframes_t
 CoreAudioSource::read_unlocked (Sample *dst, jack_nframes_t start, jack_nframes_t cnt) const
 {
-       OSStatus err = noErr;
-
-       err = ExtAudioFileSeek(af, start);
-       if (err != noErr) {
-               error << string_compose(_("CoreAudioSource: could not seek to frame %1 within %2 (%3)"), start, _name.substr (1), err) << endmsg;
+       try {
+               af.Seek (start);
+       } catch (CAXException& cax) {
+               error << string_compose("CoreAudioSource: %1 to %2 (%3)", cax.mOperation, start, _name.substr (1)) << endmsg;
                return 0;
        }
 
        AudioBufferList abl;
        abl.mNumberBuffers = 1;
        abl.mBuffers[0].mNumberChannels = n_channels;
-       abl.mBuffers[0].mDataByteSize = cnt * sizeof(Sample);
-       abl.mBuffers[0].mData = dst;
 
+       UInt32 new_cnt = cnt;
        if (n_channels == 1) {
-               err = ExtAudioFileRead(af, (UInt32*) &cnt, &abl);
-               _read_data_count = cnt * sizeof(float);
-               return cnt;
+               abl.mBuffers[0].mDataByteSize = cnt * sizeof(Sample);
+               abl.mBuffers[0].mData = dst;
+               try {
+                       af.Read (new_cnt, &abl);
+               } catch (CAXException& cax) {
+                       error << string_compose("CoreAudioSource: %1 (%2)", cax.mOperation, _name);
+               }
+               _read_data_count = new_cnt * sizeof(float);
+               return new_cnt;
        }
 
-       uint32_t real_cnt = cnt * n_channels;
+       UInt32 real_cnt = cnt * n_channels;
 
        {
                Glib::Mutex::Lock lm (_tmpbuf_lock);
@@ -185,10 +146,16 @@ CoreAudioSource::read_unlocked (Sample *dst, jack_nframes_t start, jack_nframes_
                        tmpbuf = new float[tmpbufsize];
                }
 
-               abl.mBuffers[0].mDataByteSize = real_cnt * sizeof(Sample);
+               abl.mBuffers[0].mDataByteSize = tmpbufsize * sizeof(Sample);
                abl.mBuffers[0].mData = tmpbuf;
+
+               cerr << "channel: " << channel << endl;
                
-               err = ExtAudioFileRead(af, (UInt32*) &real_cnt, &abl);
+               try {
+                       af.Read (real_cnt, &abl);
+               } catch (CAXException& cax) {
+                       error << string_compose("CoreAudioSource: %1 (%2)", cax.mOperation, _name);
+               }
                float *ptr = tmpbuf + channel;
                real_cnt /= n_channels;
                
@@ -208,15 +175,12 @@ CoreAudioSource::read_unlocked (Sample *dst, jack_nframes_t start, jack_nframes_
 float
 CoreAudioSource::sample_rate() const
 {
-        AudioStreamBasicDescription client_asbd;
-        memset(&client_asbd, 0, sizeof(AudioStreamBasicDescription));
+       CAStreamBasicDescription client_asbd;
 
-       OSStatus err = noErr;
-       size_t asbd_size = sizeof(AudioStreamBasicDescription);
-
-        err = ExtAudioFileSetProperty (af, kExtAudioFileProperty_ClientDataFormat, asbd_size, &client_asbd);
-        if (err != noErr) {
-               error << string_compose(_("Could not detect samplerate for: %1"), name()) << endmsg;
+       try {
+               client_asbd = af.GetClientDataFormat ();
+       } catch (CAXException& cax) {
+               error << string_compose("CoreAudioSource: %1 (%2)", cax.mOperation, _name);
                return 0.0;
        }
 
@@ -228,4 +192,3 @@ CoreAudioSource::update_header (jack_nframes_t when, struct tm&, time_t)
 {
        return 0;
 }
-