41 #include "CAAudioFileFormats.h"
45 CAAudioFileFormats *CAAudioFileFormats::sInstance = NULL;
47 CAAudioFileFormats *CAAudioFileFormats::Instance(
bool loadDataFormats)
49 if (sInstance == NULL)
50 sInstance =
new CAAudioFileFormats(loadDataFormats);
64 static int CompareFileFormatNames(
const void *va,
const void *vb)
66 CAAudioFileFormats::FileFormatInfo *a = (CAAudioFileFormats::FileFormatInfo *)va,
67 *b = (CAAudioFileFormats::FileFormatInfo *)vb;
68 return CFStringCompare(a->mFileTypeName, b->mFileTypeName,
69 kCFCompareCaseInsensitive | kCFCompareLocalized);
72 CAAudioFileFormats::CAAudioFileFormats(
bool loadDataFormats) :
73 mNumFileFormats(0), mFileFormats(NULL)
77 UInt32 *fileTypes = NULL;
80 err = AudioFileGetGlobalInfoSize(kAudioFileGlobalInfo_WritableTypes, 0, NULL, &size);
81 if (err != noErr)
goto bail;
82 mNumFileFormats = size /
sizeof(UInt32);
83 mFileFormats =
new FileFormatInfo[mNumFileFormats];
84 fileTypes =
new UInt32[mNumFileFormats];
85 err = AudioFileGetGlobalInfo(kAudioFileGlobalInfo_WritableTypes, 0, NULL, &size, fileTypes);
86 if (err != noErr)
goto bail;
89 for (
int i = 0; i < mNumFileFormats; ++i) {
90 FileFormatInfo *ffi = &mFileFormats[i];
91 OSType filetype = fileTypes[i];
93 ffi->mFileTypeID = filetype;
96 ffi->mFileTypeName = NULL;
97 size =
sizeof(CFStringRef);
98 err = AudioFileGetGlobalInfo(kAudioFileGlobalInfo_FileTypeName,
sizeof(UInt32), &filetype, &size, &ffi->mFileTypeName);
99 if (ffi->mFileTypeName)
100 CFRetain(ffi->mFileTypeName);
103 size =
sizeof(CFArrayRef);
104 err = AudioFileGetGlobalInfo(kAudioFileGlobalInfo_ExtensionsForType,
105 sizeof(OSType), &filetype, &size, &ffi->mExtensions);
107 ffi->mExtensions = NULL;
110 ffi->mNumDataFormats = 0;
111 ffi->mDataFormats = NULL;
114 ffi->LoadDataFormats();
118 qsort(mFileFormats, mNumFileFormats,
sizeof(FileFormatInfo), CompareFileFormatNames);
123 void CAAudioFileFormats::FileFormatInfo::LoadDataFormats()
125 if (mDataFormats != NULL)
return;
127 UInt32 *writableFormats = NULL, *readableFormats = NULL;
128 int nWritableFormats, nReadableFormats;
131 OSStatus err = AudioFormatGetPropertyInfo(kAudioFormatProperty_EncodeFormatIDs, 0, NULL, &size);
132 if (err != noErr)
goto bail;
133 nWritableFormats = size /
sizeof(UInt32);
134 writableFormats =
new UInt32[nWritableFormats];
135 err = AudioFormatGetProperty(kAudioFormatProperty_EncodeFormatIDs, 0, NULL, &size, writableFormats);
136 if (err != noErr)
goto bail;
139 err = AudioFormatGetPropertyInfo(kAudioFormatProperty_DecodeFormatIDs, 0, NULL, &size);
140 if (err != noErr)
goto bail;
141 nReadableFormats = size /
sizeof(UInt32);
142 readableFormats =
new UInt32[nReadableFormats];
143 err = AudioFormatGetProperty(kAudioFormatProperty_DecodeFormatIDs, 0, NULL, &size, readableFormats);
144 if (err != noErr)
goto bail;
146 err = AudioFileGetGlobalInfoSize(kAudioFileGlobalInfo_AvailableFormatIDs,
sizeof(UInt32), &mFileTypeID, &size);
148 mNumDataFormats = size /
sizeof(OSType);
149 OSType *formatIDs =
new OSType[mNumDataFormats];
150 err = AudioFileGetGlobalInfo(kAudioFileGlobalInfo_AvailableFormatIDs,
151 sizeof(UInt32), &mFileTypeID, &size, formatIDs);
153 mDataFormats =
new DataFormatInfo[mNumDataFormats];
154 for (
int j = 0; j < mNumDataFormats; ++j) {
156 bool anyBigEndian =
false, anyLittleEndian =
false;
157 DataFormatInfo *dfi = &mDataFormats[j];
158 dfi->mFormatID = formatIDs[j];
159 dfi->mReadable = (dfi->mFormatID == kAudioFormatLinearPCM);
160 dfi->mWritable = (dfi->mFormatID == kAudioFormatLinearPCM);
161 for (k = 0; k < nReadableFormats; ++k)
162 if (readableFormats[k] == dfi->mFormatID) {
163 dfi->mReadable =
true;
166 for (k = 0; k < nWritableFormats; ++k)
167 if (writableFormats[k] == dfi->mFormatID) {
168 dfi->mWritable =
true;
172 dfi->mNumVariants = 0;
173 AudioFileTypeAndFormatID tf = { mFileTypeID, dfi->mFormatID };
174 err = AudioFileGetGlobalInfoSize(kAudioFileGlobalInfo_AvailableStreamDescriptionsForFormat,
175 sizeof(AudioFileTypeAndFormatID), &tf, &size);
177 dfi->mNumVariants = size /
sizeof(AudioStreamBasicDescription);
178 dfi->mVariants =
new AudioStreamBasicDescription[dfi->mNumVariants];
179 err = AudioFileGetGlobalInfo(kAudioFileGlobalInfo_AvailableStreamDescriptionsForFormat,
180 sizeof(AudioFileTypeAndFormatID), &tf, &size, dfi->mVariants);
182 dfi->mNumVariants = 0;
183 delete[] dfi->mVariants;
184 dfi->mVariants = NULL;
186 for (k = 0; k < dfi->mNumVariants; ++k) {
187 AudioStreamBasicDescription *desc = &dfi->mVariants[k];
188 if (desc->mBitsPerChannel > 8) {
189 if (desc->mFormatFlags & kAudioFormatFlagIsBigEndian)
192 anyLittleEndian =
true;
198 dfi->mEitherEndianPCM = (anyBigEndian && anyLittleEndian);
204 delete[] readableFormats;
205 delete[] writableFormats;
209 bool CAAudioFileFormats::InferDataFormatFromFileFormat(AudioFileTypeID filetype, CAStreamBasicDescription &fmt)
212 for (
int i = 0; i < mNumFileFormats; ++i) {
213 FileFormatInfo *ffi = &mFileFormats[i];
214 ffi->LoadDataFormats();
215 if (ffi->mFileTypeID == filetype && ffi->mNumDataFormats > 0) {
216 DataFormatInfo *dfi = &ffi->mDataFormats[0];
217 if (ffi->mNumDataFormats > 1) {
219 for (
int j = 0; j < ffi->mNumDataFormats; ++j) {
220 if (ffi->mDataFormats[j].mFormatID == kAudioFormatLinearPCM) {
221 dfi = &ffi->mDataFormats[j];
226 memset(&fmt, 0,
sizeof(fmt));
227 fmt.mFormatID = dfi->mFormatID;
228 if (dfi->mNumVariants > 0) {
230 fmt = dfi->mVariants[0];
231 if (dfi->mNumVariants > 1 && dfi->mFormatID == kAudioFormatLinearPCM) {
233 for (
int j = 0; j < dfi->mNumVariants; ++j) {
234 AudioStreamBasicDescription *desc = &dfi->mVariants[j];
235 if (desc->mBitsPerChannel == 16) {
248 bool CAAudioFileFormats::InferFileFormatFromFilename(CFStringRef filename, AudioFileTypeID &filetype)
251 CFRange range = CFStringFind(filename, CFSTR(
"."), kCFCompareBackwards);
252 if (range.location == kCFNotFound)
return false;
254 range.length = CFStringGetLength(filename) - range.location;
255 CFStringRef ext = CFStringCreateWithSubstring(NULL, filename, range);
256 for (
int i = 0; i < mNumFileFormats; ++i) {
257 FileFormatInfo *ffi = &mFileFormats[i];
258 if (ffi->MatchExtension(ext)) {
259 filetype = ffi->mFileTypeID;
268 bool CAAudioFileFormats::InferFileFormatFromFilename(
const char *filename, AudioFileTypeID &filetype)
270 if (filename == NULL)
return false;
271 CFStringRef cfname = CFStringCreateWithCString(NULL, filename, kCFStringEncodingUTF8);
272 bool result = InferFileFormatFromFilename(cfname, filetype);
277 bool CAAudioFileFormats::InferFileFormatFromDataFormat(
const CAStreamBasicDescription &fmt,
278 AudioFileTypeID &filetype)
281 FileFormatInfo *theFileFormat = NULL;
282 for (
int i = 0; i < mNumFileFormats; ++i) {
283 FileFormatInfo *ffi = &mFileFormats[i];
284 ffi->LoadDataFormats();
285 DataFormatInfo *dfi = ffi->mDataFormats, *dfiend = dfi + ffi->mNumDataFormats;
286 for ( ; dfi < dfiend; ++dfi)
287 if (dfi->mFormatID == fmt.mFormatID) {
288 if (theFileFormat != NULL)
293 if (theFileFormat == NULL)
295 filetype = theFileFormat->mFileTypeID;
299 bool CAAudioFileFormats::IsKnownDataFormat(OSType dataFormat)
301 for (
int i = 0; i < mNumFileFormats; ++i) {
302 FileFormatInfo *ffi = &mFileFormats[i];
303 ffi->LoadDataFormats();
304 DataFormatInfo *dfi = ffi->mDataFormats, *dfiend = dfi + ffi->mNumDataFormats;
305 for ( ; dfi < dfiend; ++dfi)
306 if (dfi->mFormatID == dataFormat)
312 CAAudioFileFormats::FileFormatInfo * CAAudioFileFormats::FindFileFormat(UInt32 formatID)
314 for (
int i = 0; i < mNumFileFormats; ++i) {
315 FileFormatInfo *ffi = &mFileFormats[i];
316 if (ffi->mFileTypeID == formatID)
322 bool CAAudioFileFormats::FileFormatInfo::AnyWritableFormats()
325 DataFormatInfo *dfi = mDataFormats, *dfiend = dfi + mNumDataFormats;
326 for ( ; dfi < dfiend; ++dfi)
332 char *OSTypeToStr(
char *buf, OSType t)
335 char str[4], *q = str;
336 *(UInt32 *)str = CFSwapInt32HostToBig(t);
337 for (
int i = 0; i < 4; ++i) {
338 if (isprint(*q) && *q !=
'\\')
341 sprintf(p,
"\\x%02x", *q++);
349 int StrToOSType(
const char *str, OSType &t)
354 for (
int i = 0; i < 4; ++i) {
356 if ((buf[i] = *p++) ==
'\0') {
366 if (*++p !=
'x')
goto fail;
367 if (sscanf(++p,
"%02X", &x) != 1)
goto fail;
372 t = CFSwapInt32BigToHost(*(UInt32 *)buf);
380 void CAAudioFileFormats::DebugPrint()
382 for (
int i = 0; i < mNumFileFormats; ++i)
383 mFileFormats[i].DebugPrint();
386 void CAAudioFileFormats::FileFormatInfo::DebugPrint()
390 CFStringGetCString(mFileTypeName, ftypename,
sizeof(ftypename), kCFStringEncodingUTF8);
391 printf(
"File type: '%s' = %s\n Extensions:", OSTypeToStr(ftype, mFileTypeID), ftypename);
392 int i, n = NumberOfExtensions();
393 for (i = 0; i < n; ++i) {
394 GetExtension(i, ftype,
sizeof(ftype));
395 printf(
" .%s", ftype);
398 printf(
"\n Formats:\n");
399 for (i = 0; i < mNumDataFormats; ++i)
400 mDataFormats[i].DebugPrint();
403 void CAAudioFileFormats::DataFormatInfo::DebugPrint()
406 static const char *ny[] = {
"not ",
"" };
407 printf(
" '%s': %sreadable %swritable\n", OSTypeToStr(buf, mFormatID), ny[mReadable], ny[mWritable]);
408 for (
int i = 0; i < mNumVariants; ++i) {
409 CAStreamBasicDescription desc(mVariants[i]);
410 desc.PrintFormat(stdout,
" ",
"");