Synced string array in sfdb_ui.cc with ImportMode enum.
[ardour.git] / libs / appleutility / CAAudioFile.h
1 /*      Copyright:      � Copyright 2005 Apple Computer, Inc. All rights reserved.
2
3         Disclaimer:     IMPORTANT:  This Apple software is supplied to you by Apple Computer, Inc.
4                         ("Apple") in consideration of your agreement to the following terms, and your
5                         use, installation, modification or redistribution of this Apple software
6                         constitutes acceptance of these terms.  If you do not agree with these terms,
7                         please do not use, install, modify or redistribute this Apple software.
8
9                         In consideration of your agreement to abide by the following terms, and subject
10                         to these terms, Apple grants you a personal, non-exclusive license, under Apple�s
11                         copyrights in this original Apple software (the "Apple Software"), to use,
12                         reproduce, modify and redistribute the Apple Software, with or without
13                         modifications, in source and/or binary forms; provided that if you redistribute
14                         the Apple Software in its entirety and without modifications, you must retain
15                         this notice and the following text and disclaimers in all such redistributions of
16                         the Apple Software.  Neither the name, trademarks, service marks or logos of
17                         Apple Computer, Inc. may be used to endorse or promote products derived from the
18                         Apple Software without specific prior written permission from Apple.  Except as
19                         expressly stated in this notice, no other rights or licenses, express or implied,
20                         are granted by Apple herein, including but not limited to any patent rights that
21                         may be infringed by your derivative works or by other works in which the Apple
22                         Software may be incorporated.
23
24                         The Apple Software is provided by Apple on an "AS IS" basis.  APPLE MAKES NO
25                         WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED
26                         WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
27                         PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN
28                         COMBINATION WITH YOUR PRODUCTS.
29
30                         IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR
31                         CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
32                         GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
33                         ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION
34                         OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT
35                         (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN
36                         ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
37 */
38 /*=============================================================================
39         CAAudioFile.h
40         
41 =============================================================================*/
42
43 #ifndef __CAAudioFile_h__
44 #define __CAAudioFile_h__
45
46 #include <AvailabilityMacros.h>
47
48 #if !defined(__COREAUDIO_USE_FLAT_INCLUDES__)
49         #include <AudioToolbox/AudioToolbox.h>
50 #else
51         #include <AudioToolbox.h>
52 #endif
53
54 #include "CAStreamBasicDescription.h"
55 #include "CABufferList.h"
56 #include "CAAudioChannelLayout.h"
57 #include "CAXException.h"
58 #include "CAMath.h"
59
60 #ifndef CAAF_USE_EXTAUDIOFILE
61 // option: use AudioToolbox/ExtAudioFile.h? Only available on Tiger.
62         #if MAC_OS_X_VERSION_MIN_REQUIRED <= MAC_OS_X_VERSION_10_3
63                 // we are building software that must be deployable on Panther or earlier
64                 #define CAAF_USE_EXTAUDIOFILE 0
65         #else
66                 // else we require Tiger and can use the API
67                 #define CAAF_USE_EXTAUDIOFILE 1
68         #endif
69 #endif
70
71 #ifndef MAC_OS_X_VERSION_10_4
72         // we have pre-Tiger headers; add our own declarations
73         typedef UInt32 AudioFileTypeID;
74         enum {
75                 kExtAudioFileError_InvalidProperty                      = -66561,
76                 kExtAudioFileError_InvalidPropertySize          = -66562,
77                 kExtAudioFileError_NonPCMClientFormat           = -66563,
78                 kExtAudioFileError_InvalidChannelMap            = -66564,       // number of channels doesn't match format
79                 kExtAudioFileError_InvalidOperationOrder        = -66565,
80                 kExtAudioFileError_InvalidDataFormat            = -66566,
81                 kExtAudioFileError_MaxPacketSizeUnknown         = -66567,
82                 kExtAudioFileError_InvalidSeek                          = -66568,       // writing, or offset out of bounds
83                 kExtAudioFileError_AsyncWriteTooLarge           = -66569,
84                 kExtAudioFileError_AsyncWriteBufferOverflow     = -66570        // an async write could not be completed in time
85         };
86 #else
87         #if !defined(__COREAUDIO_USE_FLAT_INCLUDES__)
88                 #include <AudioToolbox/ExtendedAudioFile.h>
89         #else
90                 #include "ExtendedAudioFile.h"
91         #endif
92 #endif
93
94 // _______________________________________________________________________________________
95 // Wrapper class for an AudioFile, supporting encode/decode to/from a PCM client format
96 class CAAudioFile {
97 public:
98         // implementation-independent helpers
99         void    Open(const char *filePath) {
100                 FSRef fsref;
101                 XThrowIfError(FSPathMakeRef((UInt8 *)filePath, &fsref, NULL), "locate audio file");
102                 Open(fsref);
103         }
104
105         bool                                                    HasConverter() const { return GetConverter() != NULL; }
106
107         double  GetDurationSeconds() {
108                 double sr = GetFileDataFormat().mSampleRate;
109                 return fnonzero(sr) ? GetNumberFrames() / sr : 0.;
110         }
111                                 // will be 0 if the file's frames/packet is 0 (variable)
112                                 // or the file's sample rate is 0 (unknown)
113
114 #if CAAF_USE_EXTAUDIOFILE
115 public:
116         CAAudioFile() : mExtAF(NULL) { }
117         virtual ~CAAudioFile() { if (mExtAF) Close(); }
118
119         void    Open(const FSRef &fsref) {
120                                 // open an existing file
121                 XThrowIfError(ExtAudioFileOpen(&fsref, &mExtAF), "ExtAudioFileOpen failed");
122         }
123         
124         void    CreateNew(const FSRef &inParentDir, CFStringRef inFileName,     AudioFileTypeID inFileType, const AudioStreamBasicDescription &inStreamDesc, const AudioChannelLayout *inChannelLayout=NULL) {
125                 XThrowIfError(ExtAudioFileCreateNew(&inParentDir, inFileName, inFileType, &inStreamDesc, inChannelLayout, &mExtAF), "ExtAudioFileCreateNew failed");
126         }
127
128         void    Wrap(AudioFileID fileID, bool forWriting) {
129                                 // use this to wrap an AudioFileID opened externally
130                 XThrowIfError(ExtAudioFileWrapAudioFileID(fileID, forWriting, &mExtAF), "ExtAudioFileWrapAudioFileID failed");
131         }
132         
133         void    Close() {
134                 XThrowIfError(ExtAudioFileDispose(mExtAF), "ExtAudioFileClose failed");
135                 mExtAF = NULL;
136         }
137
138         const CAStreamBasicDescription &GetFileDataFormat() {
139                 UInt32 size = sizeof(mFileDataFormat);
140                 XThrowIfError(ExtAudioFileGetProperty(mExtAF, kExtAudioFileProperty_FileDataFormat, &size, &mFileDataFormat), "Couldn't get file's data format");
141                 return mFileDataFormat;
142         }
143         
144         const CAAudioChannelLayout &    GetFileChannelLayout() {
145                 return FetchChannelLayout(mFileChannelLayout, kExtAudioFileProperty_FileChannelLayout);
146         }
147         
148         void    SetFileChannelLayout(const CAAudioChannelLayout &layout) {
149                 XThrowIfError(ExtAudioFileSetProperty(mExtAF, kExtAudioFileProperty_FileChannelLayout, layout.Size(), &layout.Layout()), "Couldn't set file's channel layout");
150                 mFileChannelLayout = layout;
151         }
152
153         const CAStreamBasicDescription &GetClientDataFormat() {
154                 UInt32 size = sizeof(mClientDataFormat);
155                 XThrowIfError(ExtAudioFileGetProperty(mExtAF, kExtAudioFileProperty_ClientDataFormat, &size, &mClientDataFormat), "Couldn't get client data format");
156                 return mClientDataFormat;
157         }
158         
159         const CAAudioChannelLayout &    GetClientChannelLayout() {
160                 return FetchChannelLayout(mClientChannelLayout, kExtAudioFileProperty_ClientChannelLayout);
161         }
162         
163         void    SetClientFormat(const CAStreamBasicDescription &dataFormat, const CAAudioChannelLayout *layout=NULL) {
164                 XThrowIfError(ExtAudioFileSetProperty(mExtAF, kExtAudioFileProperty_ClientDataFormat, sizeof(dataFormat), &dataFormat), "Couldn't set client format");
165                 if (layout)
166                         SetClientChannelLayout(*layout);
167         }
168         
169         void    SetClientChannelLayout(const CAAudioChannelLayout &layout) {
170                 XThrowIfError(ExtAudioFileSetProperty(mExtAF, kExtAudioFileProperty_ClientChannelLayout, layout.Size(), &layout.Layout()), "Couldn't set client channel layout");
171         }
172         
173         AudioConverterRef                               GetConverter() const {
174                 UInt32 size = sizeof(AudioConverterRef);
175                 AudioConverterRef converter;
176                 XThrowIfError(ExtAudioFileGetProperty(mExtAF, kExtAudioFileProperty_AudioConverter, &size, &converter), "Couldn't get file's AudioConverter");
177                 return converter;
178         }
179
180         OSStatus        SetConverterProperty(AudioConverterPropertyID inPropertyID,     UInt32 inPropertyDataSize, const void *inPropertyData, bool inCanFail=false)
181         {
182                 OSStatus err = AudioConverterSetProperty(GetConverter(), inPropertyID, inPropertyDataSize, inPropertyData);
183                 if (!inCanFail)
184                         XThrowIfError(err, "Couldn't set audio converter property");
185                 if (!err) {
186                         // must tell the file that we have changed the converter; a NULL converter config is sufficient
187                         CFPropertyListRef config = NULL;
188                         XThrowIfError(ExtAudioFileSetProperty(mExtAF, kExtAudioFileProperty_ConverterConfig, sizeof(CFPropertyListRef), &config), "couldn't signal the file that the converter has changed");
189                 }
190                 return err;
191         }
192         
193         SInt64          GetNumberFrames() {
194                 SInt64 length;
195                 UInt32 size = sizeof(SInt64);
196                 XThrowIfError(ExtAudioFileGetProperty(mExtAF, kExtAudioFileProperty_FileLengthFrames, &size, &length), "Couldn't get file's length");
197                 return length;
198         }
199         
200         void            SetNumberFrames(SInt64 length) {
201                 XThrowIfError(ExtAudioFileSetProperty(mExtAF, kExtAudioFileProperty_FileLengthFrames, sizeof(SInt64), &length), "Couldn't set file's length");
202         }
203         
204         void            Seek(SInt64 pos) {
205                 XThrowIfError(ExtAudioFileSeek(mExtAF, pos), "Couldn't seek in audio file");
206         }
207         
208         SInt64          Tell() {
209                 SInt64 pos;
210                 XThrowIfError(ExtAudioFileTell(mExtAF, &pos), "Couldn't get file's mark");
211                 return pos;
212         }
213         
214         void            Read(UInt32 &ioFrames, AudioBufferList *ioData) {
215                 XThrowIfError(ExtAudioFileRead(mExtAF, &ioFrames, ioData), "Couldn't read audio file");
216         }
217
218         void            Write(UInt32 inFrames, const AudioBufferList *inData) {
219                 XThrowIfError(ExtAudioFileWrite(mExtAF, inFrames, inData), "Couldn't write audio file");
220         }
221
222         void            SetIOBufferSizeBytes(UInt32 bufferSizeBytes) {
223                 XThrowIfError(ExtAudioFileSetProperty(mExtAF, kExtAudioFileProperty_IOBufferSizeBytes, sizeof(UInt32), &bufferSizeBytes), "Couldn't set audio file's I/O buffer size");
224         }
225
226 private:
227         const CAAudioChannelLayout &    FetchChannelLayout(CAAudioChannelLayout &layoutObj, ExtAudioFilePropertyID propID) {
228                 UInt32 size;
229                 XThrowIfError(ExtAudioFileGetPropertyInfo(mExtAF, propID, &size, NULL), "Couldn't get info about channel layout");
230                 AudioChannelLayout *layout = (AudioChannelLayout *)malloc(size);
231                 OSStatus err = ExtAudioFileGetProperty(mExtAF, propID, &size, layout);
232                 if (err) {
233                         free(layout);
234                         XThrowIfError(err, "Couldn't get channel layout");
235                 }
236                 layoutObj = layout;
237                 free(layout);
238                 return layoutObj;
239         }
240
241
242 private:
243         ExtAudioFileRef                         mExtAF;
244
245         CAStreamBasicDescription        mFileDataFormat;
246         CAAudioChannelLayout            mFileChannelLayout;
247
248         CAStreamBasicDescription        mClientDataFormat;
249         CAAudioChannelLayout            mClientChannelLayout;
250 #endif
251
252 #if !CAAF_USE_EXTAUDIOFILE
253         CAAudioFile();
254         virtual ~CAAudioFile();
255
256         // --- second-stage initializers ---
257         // Use exactly one of the following:
258         //              - Open
259         //              - PrepareNew followed by Create
260         //              - Wrap
261         
262         void    Open(const FSRef &fsref);
263                                 // open an existing file
264
265         void    CreateNew(const FSRef &inParentDir, CFStringRef inFileName,     AudioFileTypeID inFileType, const AudioStreamBasicDescription &inStreamDesc, const AudioChannelLayout *inChannelLayout=NULL);
266         
267         void    Wrap(AudioFileID fileID, bool forWriting);
268                                 // use this to wrap an AudioFileID opened externally
269
270         // ---
271
272         void    Close();
273                                 // In case you want to close the file before the destructor executes
274         
275         // --- Data formats ---
276
277         // Allow specifying the file's channel layout. Must be called before SetClientFormat.
278         // When writing, the specified channel layout is written to the file (if the file format supports
279         // the channel layout). When reading, the specified layout overrides the one read from the file,
280         // if any.
281         void    SetFileChannelLayout(const CAAudioChannelLayout &layout);
282         
283         // This specifies the data format which the client will use for reading/writing the file,
284         // which may be different from the file's format. An AudioConverter is created if necessary.
285         // The client format must be linear PCM.
286         void    SetClientFormat(const CAStreamBasicDescription &dataFormat, const CAAudioChannelLayout *layout=NULL);
287         void    SetClientDataFormat(const CAStreamBasicDescription &dataFormat) { SetClientFormat(dataFormat, NULL); }
288         void    SetClientChannelLayout(const CAAudioChannelLayout &layout) { SetClientFormat(mClientDataFormat, &layout); }
289         
290         // Wrapping the underlying converter, if there is one
291         OSStatus        SetConverterProperty(AudioConverterPropertyID   inPropertyID,
292                                                                         UInt32                                          inPropertyDataSize,
293                                                                         const void *                            inPropertyData,
294                                                                         bool                                            inCanFail = false);
295         void            SetConverterConfig(CFArrayRef config) {
296                                         SetConverterProperty(kAudioConverterPropertySettings, sizeof(config), &config); }
297         CFArrayRef  GetConverterConfig();
298         
299         // --- I/O ---
300         // All I/O is sequential, but you can seek to an arbitrary position when reading.
301         // SeekToPacket and TellPacket's packet numbers are in the file's data format, not the client's.
302         // However, ReadPackets/WritePackets use packet counts in the client data format.
303
304         void    Read(UInt32 &ioNumFrames, AudioBufferList *ioData);
305         void    Write(UInt32 numFrames, const AudioBufferList *data);
306
307         // These can fail for files without a constant mFramesPerPacket
308         void    Seek(SInt64 frameNumber);
309         SInt64  Tell() const;   // frameNumber
310         
311         // --- Accessors ---
312         // note: client parameters only valid if SetClientFormat has been called
313         AudioFileID                                             GetAudioFileID() const { return mAudioFile; }
314         const CAStreamBasicDescription &GetFileDataFormat() const { return mFileDataFormat; }
315         const CAStreamBasicDescription &GetClientDataFormat() const { return mClientDataFormat; }
316         const CAAudioChannelLayout &    GetFileChannelLayout() const { return mFileChannelLayout; }
317         const CAAudioChannelLayout &    GetClientChannelLayout() const { return mClientChannelLayout; }
318         AudioConverterRef                               GetConverter() const { return mConverter; }
319
320         UInt32  GetFileMaxPacketSize() const { return mFileMaxPacketSize; }
321         UInt32  GetClientMaxPacketSize() const { return mClientMaxPacketSize; }
322         SInt64  GetNumberPackets() const {
323                 SInt64 npackets;
324                 UInt32 propertySize = sizeof(npackets);
325                 XThrowIfError(AudioFileGetProperty(mAudioFile, kAudioFilePropertyAudioDataPacketCount, &propertySize, &npackets), "get audio file's packet count");
326                 return npackets;
327         }
328         SInt64  GetNumberFrames() const;
329                                 // will be 0 if the file's frames/packet is 0 (variable)
330         void    SetNumberFrames(SInt64 length); // should only be set on a PCM file
331         
332         // --- Tunable performance parameters ---
333         void    SetUseCache(bool b) { mUseCache = b; }
334         void    SetIOBufferSizeBytes(UInt32 bufferSizeBytes) { mIOBufferSizeBytes = bufferSizeBytes; }
335         UInt32  GetIOBufferSizeBytes() { return mIOBufferSizeBytes; }
336         void *  GetIOBuffer() { return mIOBufferList.mBuffers[0].mData; }
337         void    SetIOBuffer(void *buf);
338         
339         // -- Profiling ---
340 #if CAAUDIOFILE_PROFILE
341         void    EnableProfiling(bool b) { mProfiling = b; }
342         UInt64  TicksInConverter() const { return (mTicksInConverter > 0) ? (mTicksInConverter - mTicksInReadInConverter) : 0; }
343         UInt64  TicksInIO() const { return mTicksInIO; }
344 #endif
345         
346 // _______________________________________________________________________________________
347 private:
348         SInt64  FileDataOffset();
349         void    SeekToPacket(SInt64 packetNumber);
350         SInt64  TellPacket() const { return mPacketMark; }  // will be imprecise if SeekToFrame was called
351         
352         void    SetConverterChannelLayout(bool output, const CAAudioChannelLayout &layout);
353         void    WritePacketsFromCallback(
354                                                                         AudioConverterComplexInputDataProc      inInputDataProc,
355                                                                         void *                                                          inInputDataProcUserData);
356                                 // will use I/O buffer size
357         void    InitFileMaxPacketSize();
358         void    FileFormatChanged(const FSRef *parentDir=0, CFStringRef filename=0, AudioFileTypeID filetype=0);
359
360         void    GetExistingFileInfo();
361         void    FlushEncoder();
362         void    CloseConverter();
363         void    UpdateClientMaxPacketSize();
364         void    AllocateBuffers(bool okToFail=false);
365         SInt64  PacketToFrame(SInt64 packet) const;
366         SInt64  FrameToPacket(SInt64 inFrame) const;
367
368         static OSStatus ReadInputProc(          AudioConverterRef                               inAudioConverter,
369                                                                                 UInt32*                                                 ioNumberDataPackets,
370                                                                                 AudioBufferList*                                ioData,
371                                                                                 AudioStreamPacketDescription**  outDataPacketDescription,
372                                                                                 void*                                                   inUserData);    
373
374         static OSStatus WriteInputProc(         AudioConverterRef                               inAudioConverter,
375                                                                                 UInt32*                                                 ioNumberDataPackets,
376                                                                                 AudioBufferList*                                ioData,
377                                                                                 AudioStreamPacketDescription**  outDataPacketDescription,
378                                                                                 void*                                                   inUserData);    
379 // _______________________________________________________________________________________
380 private:
381
382         // the file
383         FSRef                                           mFSRef;
384         AudioFileID                                     mAudioFile;
385         bool                                            mOwnOpenFile;
386         bool                                            mUseCache;
387         bool                                            mFinishingEncoding;
388         enum { kClosed, kReading, kPreparingToCreate, kPreparingToWrite, kWriting } mMode;
389         
390 //      SInt64                                          mNumberPackets;         // in file's format
391         SInt64                                          mFileDataOffset;
392         SInt64                                          mPacketMark;            // in file's format
393         SInt64                                          mFrameMark;                     // this may be offset from the start of the file
394                                                                                                         // by the codec's latency; i.e. our frame 0 could
395                                                                                                         // lie at frame 2112 of a decoded AAC file
396         SInt32                                          mFrame0Offset;
397         UInt32                                          mFramesToSkipFollowingSeek;
398         
399         // buffers
400         UInt32                                          mIOBufferSizeBytes;
401         UInt32                                          mIOBufferSizePackets;
402         AudioBufferList                         mIOBufferList;          // only one buffer -- USE ACCESSOR so it can be lazily initialized
403         bool                                            mClientOwnsIOBuffer;
404         AudioStreamPacketDescription *mPacketDescs;
405         UInt32                                          mNumPacketDescs;
406         
407         // formats/conversion
408         AudioConverterRef                       mConverter;
409         CAStreamBasicDescription        mFileDataFormat;
410         CAStreamBasicDescription        mClientDataFormat;
411         CAAudioChannelLayout            mFileChannelLayout;
412         CAAudioChannelLayout            mClientChannelLayout;
413         UInt32                                          mFileMaxPacketSize;
414         UInt32                                          mClientMaxPacketSize;
415         
416         // cookie
417         Byte *                                          mMagicCookie;
418         UInt32                                          mMagicCookieSize;
419         
420         // for ReadPackets
421         UInt32                                          mMaxPacketsToRead;
422         
423         // for WritePackets
424         UInt32                                          mWritePackets;
425         CABufferList *                          mWriteBufferList;
426         
427 #if CAAUDIOFILE_PROFILE
428         // performance
429         bool                                            mProfiling;
430         UInt64                                          mTicksInConverter;
431         UInt64                                          mTicksInReadInConverter;
432         UInt64                                          mTicksInIO;
433         bool                                            mInConverter;
434 #endif
435
436 #endif // CAAF_USE_EXTAUDIOFILE
437 };
438
439 #endif // __CAAudioFile_h__