-
Notifications
You must be signed in to change notification settings - Fork 0
/
CAFFile.h
371 lines (308 loc) · 11.9 KB
/
CAFFile.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
/*
File: AudioToolbox/CAFFile.h
Contains: Tthe data structures contained within a CAF File
Copyright: (c) 2004 - 2008 by Apple, Inc., all rights reserved.
Bugs?: For bug reports, consult the following page on
the World Wide Web:
http://developer.apple.com/bugreporter/
*/
#ifndef _CAFFile_H_
#define _CAFFile_H_
#if !defined(__COREAUDIO_USE_FLAT_INCLUDES__)
#include <CoreAudio/CoreAudioTypes.h>
#else
#include <CoreAudioTypes.h>
#endif
#if TARGET_OS_WIN32
#define ATTRIBUTE_PACKED
#else
#define ATTRIBUTE_PACKED __attribute__((__packed__))
#endif
// In a CAF File all of these types' byte order is big endian.
// When reading or writing these values the program will need to flip byte order to native endian
// CAF File Header
enum {
kCAF_FileType = 'caff',
kCAF_FileVersion_Initial = 1
};
// CAF Chunk Types
enum {
kCAF_StreamDescriptionChunkID = 'desc',
kCAF_AudioDataChunkID = 'data',
kCAF_ChannelLayoutChunkID = 'chan',
kCAF_FillerChunkID = 'free',
kCAF_MarkerChunkID = 'mark',
kCAF_RegionChunkID = 'regn',
kCAF_InstrumentChunkID = 'inst',
kCAF_MagicCookieID = 'kuki',
kCAF_InfoStringsChunkID = 'info',
kCAF_EditCommentsChunkID = 'edct',
kCAF_PacketTableChunkID = 'pakt',
kCAF_StringsChunkID = 'strg',
kCAF_UUIDChunkID = 'uuid',
kCAF_PeakChunkID = 'peak',
kCAF_OverviewChunkID = 'ovvw',
kCAF_MIDIChunkID = 'midi',
kCAF_UMIDChunkID = 'umid',
kCAF_FormatListID = 'ldsc'
};
struct CAFFileHeader
{
UInt32 mFileType; // 'caff'
UInt16 mFileVersion; //initial revision set to 1
UInt16 mFileFlags; //initial revision set to 0
} ATTRIBUTE_PACKED;
typedef struct CAFFileHeader CAFFileHeader;
struct CAFChunkHeader
{
UInt32 mChunkType; // four char code
SInt64 mChunkSize; // size in bytes of the chunk data (not including this header).
// mChunkSize is SInt64 not UInt64 because negative values for
// the data size can have a special meaning
} ATTRIBUTE_PACKED;
typedef struct CAFChunkHeader CAFChunkHeader;
struct CAF_UUID_ChunkHeader
{
CAFChunkHeader mHeader;
UInt8 mUUID[16];
} ATTRIBUTE_PACKED;
typedef struct CAF_UUID_ChunkHeader CAF_UUID_ChunkHeader;
// Every file MUST have this chunk. It MUST be the first chunk in the file
struct CAFAudioDescription
{
Float64 mSampleRate;
UInt32 mFormatID;
UInt32 mFormatFlags;
UInt32 mBytesPerPacket;
UInt32 mFramesPerPacket;
UInt32 mChannelsPerFrame;
UInt32 mBitsPerChannel;
} ATTRIBUTE_PACKED;
typedef struct CAFAudioDescription CAFAudioDescription;
// these are the flags if the format ID is 'lpcm'
// <CoreAudio/CoreAudioTypes.h> declares some of the format constants
// that can be used as Data Formats in a CAF file
enum
{
kCAFLinearPCMFormatFlagIsFloat = (1L << 0),
kCAFLinearPCMFormatFlagIsLittleEndian = (1L << 1)
};
// 'ldsc' format list chunk.
// for data formats like AAC SBR which can be decompressed to multiple formats, this chunk contains a list of
// CAFAudioFormatListItem describing those formats. The list is ordered from best to worst by number of channels
// and sample rate in that order. mChannelLayoutTag is an AudioChannelLayoutTag as defined in CoreAudioTypes.h
struct CAFAudioFormatListItem
{
CAFAudioDescription mFormat;
UInt32 mChannelLayoutTag;
} ATTRIBUTE_PACKED;
// 'chan' Optional chunk.
// struct AudioChannelLayout as defined in CoreAudioTypes.h.
// 'free'
// this is a padding chunk for reserving space in the file. content is meaningless.
// 'kuki'
// this is the magic cookie chunk. bag of bytes.
// 'data' Every file MUST have this chunk.
// actual audio data can be any format as described by the 'asbd' chunk.
// if mChunkSize is < 0 then this is the last chunk in the file and the actual length
// should be determined from the file size.
// The motivation for this is to allow writing the files without seeking to update size fields after every
// write in order to keep the file legal.
// The program can put a -1 in the mChunkSize field and
// update it only once at the end of recording.
// If the program were to crash during recording then the file is still well defined.
// 'pakt' Required if either/or mBytesPerPacket or mFramesPerPacket in the Format Description are zero
// For formats that are packetized and have variable sized packets.
// The table is stored as an array of one or two variable length integers.
// (a) size in bytes of the data of a given packet.
// (b) number of frames in a given packet.
// These sizes are encoded as variable length integers
// The packet description entries are either one or two values depending on the format.
// There are three possibilities
// (1)
// If the format has variable bytes per packets (desc.mBytesPerPacket == 0) and constant frames per packet
// (desc.mFramesPerPacket != 0) then the packet table contains single entries representing the bytes in a given packet
// (2)
// If the format is a constant bit rate (desc.mBytesPerPacket != 0) but variable frames per packet
// (desc.mFramesPerPacket == 0) then the packet table entries contains single entries
// representing the number of frames in a given packet
// (3)
// If the format has variable frames per packet (asbd.mFramesPerPacket == 0) and variable bytes per packet
// (desc.mBytesPerPacket == 0) then the packet table entries are a duple of two values. The first value
// is the number of bytes in a given packet, the second value is the number of frames in a given packet
struct CAFPacketTableHeader
{
SInt64 mNumberPackets;
SInt64 mNumberValidFrames;
SInt32 mPrimingFrames;
SInt32 mRemainderFrames;
UInt8 mPacketDescriptions[1]; // this is a variable length array of mNumberPackets elements
} ATTRIBUTE_PACKED;
typedef struct CAFPacketTableHeader CAFPacketTableHeader;
struct CAFDataChunk
{
UInt32 mEditCount;
UInt8 mData[1]; // this is a variable length data field based off the size of the data chunk
} ATTRIBUTE_PACKED;
typedef struct CAFDataChunk CAFDataChunk;
// markers types
enum {
kCAFMarkerType_Generic = 0,
kCAFMarkerType_ProgramStart = 'pbeg',
kCAFMarkerType_ProgramEnd = 'pend',
kCAFMarkerType_TrackStart = 'tbeg',
kCAFMarkerType_TrackEnd = 'tend',
kCAFMarkerType_Index = 'indx',
kCAFMarkerType_RegionStart = 'rbeg',
kCAFMarkerType_RegionEnd = 'rend',
kCAFMarkerType_RegionSyncPoint = 'rsyc',
kCAFMarkerType_SelectionStart = 'sbeg',
kCAFMarkerType_SelectionEnd = 'send',
kCAFMarkerType_EditSourceBegin = 'cbeg',
kCAFMarkerType_EditSourceEnd = 'cend',
kCAFMarkerType_EditDestinationBegin = 'dbeg',
kCAFMarkerType_EditDestinationEnd = 'dend',
kCAFMarkerType_SustainLoopStart = 'slbg',
kCAFMarkerType_SustainLoopEnd = 'slen',
kCAFMarkerType_ReleaseLoopStart = 'rlbg',
kCAFMarkerType_ReleaseLoopEnd = 'rlen',
kCAFMarkerType_SavedPlayPosition = 'sply',
kCAFMarkerType_Tempo = 'tmpo',
kCAFMarkerType_TimeSignature = 'tsig',
kCAFMarkerType_KeySignature = 'ksig'
};
enum
{
kCAF_SMPTE_TimeTypeNone = 0,
kCAF_SMPTE_TimeType24 = 1,
kCAF_SMPTE_TimeType25 = 2,
kCAF_SMPTE_TimeType30Drop = 3,
kCAF_SMPTE_TimeType30 = 4,
kCAF_SMPTE_TimeType2997 = 5,
kCAF_SMPTE_TimeType2997Drop = 6,
kCAF_SMPTE_TimeType60 = 7,
kCAF_SMPTE_TimeType5994 = 8,
kCAF_SMPTE_TimeType60Drop = 9,
kCAF_SMPTE_TimeType5994Drop = 10,
kCAF_SMPTE_TimeType50 = 11,
kCAF_SMPTE_TimeType2398 = 12
};
struct CAF_SMPTE_Time
{
SInt8 mHours;
SInt8 mMinutes;
SInt8 mSeconds;
SInt8 mFrames;
UInt32 mSubFrameSampleOffset;
} ATTRIBUTE_PACKED;
typedef struct CAF_SMPTE_Time CAF_SMPTE_Time;
struct CAFMarker
{
UInt32 mType;
Float64 mFramePosition;
UInt32 mMarkerID;
CAF_SMPTE_Time mSMPTETime;
UInt32 mChannel;
} ATTRIBUTE_PACKED;
typedef struct CAFMarker CAFMarker;
struct CAFMarkerChunk
{
UInt32 mSMPTE_TimeType;
UInt32 mNumberMarkers;
CAFMarker mMarkers[1]; // this is a variable length array of mNumberMarkers elements
} ATTRIBUTE_PACKED;
typedef struct CAFMarkerChunk CAFMarkerChunk;
#define kCAFMarkerChunkHdrSize offsetof(CAFMarkerChunk, mMarkers)
enum {
kCAFRegionFlag_LoopEnable = 1,
kCAFRegionFlag_PlayForward = 2,
kCAFRegionFlag_PlayBackward = 4
};
struct CAFRegion
{
UInt32 mRegionID;
UInt32 mFlags;
UInt32 mNumberMarkers;
CAFMarker mMarkers[1]; // this is a variable length array of mNumberMarkers elements
} ATTRIBUTE_PACKED;
typedef struct CAFRegion CAFRegion;
/* because AudioFileRegions are variable length, you cannot access them as an array. Use NextAudioFileRegion to walk the list. */
#define NextCAFRegion(inCAFRegionPtr) \
((CAFRegion*)((char*)(inCAFRegionPtr) + offsetof(CAFRegion, mMarkers) + ((inCAFRegionPtr)->mNumberMarkers)*sizeof(CAFMarker)))
struct CAFRegionChunk
{
UInt32 mSMPTE_TimeType;
UInt32 mNumberRegions;
CAFRegion mRegions[1]; // this is a variable length array of mNumberRegions elements
} ATTRIBUTE_PACKED;
typedef struct CAFRegionChunk CAFRegionChunk;
#define kCAFRegionChunkHdrSize offsetof(CAFRegionChunk, mRegions)
struct CAFInstrumentChunk
{
Float32 mBaseNote;
UInt8 mMIDILowNote;
UInt8 mMIDIHighNote;
UInt8 mMIDILowVelocity;
UInt8 mMIDIHighVelocity;
Float32 mdBGain;
UInt32 mStartRegionID;
UInt32 mSustainRegionID;
UInt32 mReleaseRegionID;
UInt32 mInstrumentID;
} ATTRIBUTE_PACKED;
typedef struct CAFInstrumentChunk CAFInstrumentChunk;
struct CAFStringID {
UInt32 mStringID;
SInt64 mStringStartByteOffset;
} ATTRIBUTE_PACKED;
typedef struct CAFStringID CAFStringID;
struct CAFStrings
{
UInt32 mNumEntries;
CAFStringID mStringsIDs[1]; // this is a variable length array of mNumEntries elements
// this struct is only fictionally described due to the variable length fields
// UInt8 mStrings[ variable num elements ]; // null terminated UTF8 strings
} ATTRIBUTE_PACKED;
typedef struct CAFStrings CAFStrings;
struct CAFInfoStrings
{
UInt32 mNumEntries;
// These are only fictionally defined in the struct due to the variable length fields.
// struct {
// UInt8 mKey[ variable num elements ]; // null terminated UTF8 string
// UInt8 mValue[ variable num elements ]; // null terminated UTF8 string
// } mStrings[ variable num elements ];
} ATTRIBUTE_PACKED;
typedef struct CAFInfoStrings CAFInfoStrings;
struct CAFPositionPeak
{
Float32 mValue;
UInt64 mFrameNumber;
} ATTRIBUTE_PACKED;
typedef struct CAFPositionPeak CAFPositionPeak;
struct CAFPeakChunk
{
UInt32 mEditCount;
CAFPositionPeak mPeaks[1]; // this is a variable length array of peak elements (calculated from the size of the chunk)
} ATTRIBUTE_PACKED;
typedef struct CAFPeakChunk CAFPeakChunk;
struct CAFOverviewSample
{
SInt16 mMinValue;
SInt16 mMaxValue;
} ATTRIBUTE_PACKED;
typedef struct CAFOverviewSample CAFOverviewSample;
struct CAFOverviewChunk
{
UInt32 mEditCount;
UInt32 mNumFramesPerOVWSample;
CAFOverviewSample mData[1]; // data is of variable size, calculated from the sizeo of the chunk.
} ATTRIBUTE_PACKED;
typedef struct CAFOverviewChunk CAFOverviewChunk;
struct CAFUMIDChunk
{
UInt8 mBytes[64];
} ATTRIBUTE_PACKED;
typedef struct CAFUMIDChunk CAFUMIDChunk;
////////////////////////////////////////////////////////////////////////////////////////////////
#endif