41 #include "CAStreamBasicDescription.h"
44 #if !defined(__COREAUDIO_USE_FLAT_INCLUDES__)
45 #include <CoreFoundation/CFByteOrder.h>
47 #include <CFByteOrder.h>
50 #pragma mark This file needs to compile on earlier versions of the OS, so please keep that in mind when editing it
52 char *CAStringForOSType (OSType t,
char *writeLocation)
54 char *p = writeLocation;
55 unsigned char str[4], *q = str;
56 *(UInt32 *)str = CFSwapInt32HostToBig(t);
58 bool hasNonPrint =
false;
59 for (
int i = 0; i < 4; ++i) {
60 if (!(isprint(*q) && *q !=
'\\')) {
67 p += sprintf (p,
"0x");
71 for (
int i = 0; i < 4; ++i) {
73 p += sprintf(p,
"%02X", *q++);
85 const AudioStreamBasicDescription CAStreamBasicDescription::sEmpty = { 0.0, 0, 0, 0, 0, 0, 0, 0, 0 };
87 CAStreamBasicDescription::CAStreamBasicDescription(
double inSampleRate, UInt32 inFormatID,
88 UInt32 inBytesPerPacket, UInt32 inFramesPerPacket,
89 UInt32 inBytesPerFrame, UInt32 inChannelsPerFrame,
90 UInt32 inBitsPerChannel, UInt32 inFormatFlags)
92 mSampleRate = inSampleRate;
93 mFormatID = inFormatID;
94 mBytesPerPacket = inBytesPerPacket;
95 mFramesPerPacket = inFramesPerPacket;
96 mBytesPerFrame = inBytesPerFrame;
97 mChannelsPerFrame = inChannelsPerFrame;
98 mBitsPerChannel = inBitsPerChannel;
99 mFormatFlags = inFormatFlags;
103 char *CAStreamBasicDescription::AsString(
char *buf,
size_t _bufsize)
const
105 int bufsize = (int)_bufsize;
106 char *theBuffer = buf;
109 CAStringForOSType (mFormatID, formatID);
110 nc = snprintf(buf, bufsize,
"%2d ch, %6.0f Hz, %s (0x%08X) ", (
int)NumberChannels(), mSampleRate, formatID, (
int)mFormatFlags);
111 buf += nc;
if ((bufsize -= nc) <= 0)
goto exit;
112 if (mFormatID == kAudioFormatLinearPCM) {
113 bool isInt = !(mFormatFlags & kLinearPCMFormatFlagIsFloat);
114 int wordSize = SampleWordSize();
115 const char *endian = (wordSize > 1) ?
116 ((mFormatFlags & kLinearPCMFormatFlagIsBigEndian) ?
" big-endian" :
" little-endian" ) :
"";
117 const char *sign = isInt ?
118 ((mFormatFlags & kLinearPCMFormatFlagIsSignedInteger) ?
" signed" :
" unsigned") :
"";
119 const char *floatInt = isInt ?
"integer" :
"float";
121 if (wordSize > 0 && PackednessIsSignificant()) {
122 if (mFormatFlags & kLinearPCMFormatFlagIsPacked)
123 snprintf(packed,
sizeof(packed),
"packed in %d bytes", wordSize);
125 snprintf(packed,
sizeof(packed),
"unpacked in %d bytes", wordSize);
128 const char *align = (wordSize > 0 && AlignmentIsSignificant()) ?
129 ((mFormatFlags & kLinearPCMFormatFlagIsAlignedHigh) ?
" high-aligned" :
" low-aligned") :
"";
130 const char *deinter = (mFormatFlags & kAudioFormatFlagIsNonInterleaved) ?
", deinterleaved" :
"";
131 const char *commaSpace = (packed[0]!=
'\0') || (align[0]!=
'\0') ?
", " :
"";
134 int fracbits = (mFormatFlags & kLinearPCMFormatFlagsSampleFractionMask) >> kLinearPCMFormatFlagsSampleFractionShift;
136 snprintf(bitdepth,
sizeof(bitdepth),
"%d.%d", (
int)mBitsPerChannel - fracbits, fracbits);
138 snprintf(bitdepth,
sizeof(bitdepth),
"%d", (
int)mBitsPerChannel);
140 nc = snprintf(buf, bufsize,
"%s-bit%s%s %s%s%s%s%s",
141 bitdepth, endian, sign, floatInt,
142 commaSpace, packed, align, deinter);
144 }
else if (mFormatID ==
'alac') {
146 switch (mFormatFlags)
162 nc = snprintf(buf, bufsize,
"from %d-bit source, ", sourceBits);
164 nc = snprintf(buf, bufsize,
"from UNKNOWN source bit depth, ");
165 buf += nc;
if ((bufsize -= nc) <= 0)
goto exit;
166 nc = snprintf(buf, bufsize,
"%d frames/packet", (
int)mFramesPerPacket);
170 nc = snprintf(buf, bufsize,
"%d bits/channel, %d bytes/packet, %d frames/packet, %d bytes/frame",
171 (
int)mBitsPerChannel, (
int)mBytesPerPacket, (
int)mFramesPerPacket, (
int)mBytesPerFrame);
176 void CAStreamBasicDescription::NormalizeLinearPCMFormat(AudioStreamBasicDescription& ioDescription)
179 if((ioDescription.mFormatID == kAudioFormatLinearPCM) && ((ioDescription.mFormatFlags & kIsNonMixableFlag) == 0))
182 ioDescription.mFormatFlags = kAudioFormatFlagsCanonical;
183 ioDescription.mBytesPerPacket = SizeOf32(AudioSampleType) * ioDescription.mChannelsPerFrame;
184 ioDescription.mFramesPerPacket = 1;
185 ioDescription.mBytesPerFrame = SizeOf32(AudioSampleType) * ioDescription.mChannelsPerFrame;
186 ioDescription.mBitsPerChannel = 8 * SizeOf32(AudioSampleType);
190 void CAStreamBasicDescription::ResetFormat(AudioStreamBasicDescription& ioDescription)
192 ioDescription.mSampleRate = 0;
193 ioDescription.mFormatID = 0;
194 ioDescription.mBytesPerPacket = 0;
195 ioDescription.mFramesPerPacket = 0;
196 ioDescription.mBytesPerFrame = 0;
197 ioDescription.mChannelsPerFrame = 0;
198 ioDescription.mBitsPerChannel = 0;
199 ioDescription.mFormatFlags = 0;
202 void CAStreamBasicDescription::FillOutFormat(AudioStreamBasicDescription& ioDescription,
const AudioStreamBasicDescription& inTemplateDescription)
204 if(fiszero(ioDescription.mSampleRate))
206 ioDescription.mSampleRate = inTemplateDescription.mSampleRate;
208 if(ioDescription.mFormatID == 0)
210 ioDescription.mFormatID = inTemplateDescription.mFormatID;
212 if(ioDescription.mFormatFlags == 0)
214 ioDescription.mFormatFlags = inTemplateDescription.mFormatFlags;
216 if(ioDescription.mBytesPerPacket == 0)
218 ioDescription.mBytesPerPacket = inTemplateDescription.mBytesPerPacket;
220 if(ioDescription.mFramesPerPacket == 0)
222 ioDescription.mFramesPerPacket = inTemplateDescription.mFramesPerPacket;
224 if(ioDescription.mBytesPerFrame == 0)
226 ioDescription.mBytesPerFrame = inTemplateDescription.mBytesPerFrame;
228 if(ioDescription.mChannelsPerFrame == 0)
230 ioDescription.mChannelsPerFrame = inTemplateDescription.mChannelsPerFrame;
232 if(ioDescription.mBitsPerChannel == 0)
234 ioDescription.mBitsPerChannel = inTemplateDescription.mBitsPerChannel;
238 void CAStreamBasicDescription::GetSimpleName(
const AudioStreamBasicDescription& inDescription,
char* outName, UInt32 inMaxNameLength,
bool inAbbreviate)
240 switch(inDescription.mFormatID)
242 case kAudioFormatLinearPCM:
244 const char* theEndianString = NULL;
245 if((inDescription.mFormatFlags & kAudioFormatFlagIsBigEndian) != 0)
247 #if TARGET_RT_LITTLE_ENDIAN
248 theEndianString =
"Big Endian";
253 #if TARGET_RT_BIG_ENDIAN
254 theEndianString =
"Little Endian";
258 const char* theKindString = NULL;
259 if((inDescription.mFormatFlags & kAudioFormatFlagIsFloat) != 0)
261 theKindString = (inAbbreviate ?
"Float" :
"Floating Point");
263 else if((inDescription.mFormatFlags & kAudioFormatFlagIsSignedInteger) != 0)
265 theKindString = (inAbbreviate ?
"SInt" :
"Signed Integer");
269 theKindString = (inAbbreviate ?
"UInt" :
"Unsigned Integer");
272 const char* thePackingString = NULL;
273 if((inDescription.mFormatFlags & kAudioFormatFlagIsPacked) == 0)
275 if((inDescription.mFormatFlags & kAudioFormatFlagIsAlignedHigh) != 0)
277 thePackingString =
"High";
281 thePackingString =
"Low";
285 const char* theMixabilityString = NULL;
286 if((inDescription.mFormatFlags & kIsNonMixableFlag) == 0)
288 theMixabilityString =
"Mixable";
292 theMixabilityString =
"Unmixable";
297 if(theEndianString != NULL)
299 if(thePackingString != NULL)
301 snprintf(outName, inMaxNameLength,
"%s %d Ch %s %s %s%d/%s%d", theMixabilityString, (
int)inDescription.mChannelsPerFrame, theEndianString, thePackingString, theKindString, (
int)inDescription.mBitsPerChannel, theKindString, (
int)(inDescription.mBytesPerFrame / inDescription.mChannelsPerFrame) * 8);
305 snprintf(outName, inMaxNameLength,
"%s %d Ch %s %s%d", theMixabilityString, (
int)inDescription.mChannelsPerFrame, theEndianString, theKindString, (
int)inDescription.mBitsPerChannel);
310 if(thePackingString != NULL)
312 snprintf(outName, inMaxNameLength,
"%s %d Ch %s %s%d/%s%d", theMixabilityString, (
int)inDescription.mChannelsPerFrame, thePackingString, theKindString, (
int)inDescription.mBitsPerChannel, theKindString, (
int)((inDescription.mBytesPerFrame / inDescription.mChannelsPerFrame) * 8));
316 snprintf(outName, inMaxNameLength,
"%s %d Ch %s%d", theMixabilityString, (
int)inDescription.mChannelsPerFrame, theKindString, (
int)inDescription.mBitsPerChannel);
322 if(theEndianString != NULL)
324 if(thePackingString != NULL)
326 snprintf(outName, inMaxNameLength,
"%s %d Channel %d Bit %s %s Aligned %s in %d Bits", theMixabilityString, (
int)inDescription.mChannelsPerFrame, (
int)inDescription.mBitsPerChannel, theEndianString, theKindString, thePackingString, (
int)(inDescription.mBytesPerFrame / inDescription.mChannelsPerFrame) * 8);
330 snprintf(outName, inMaxNameLength,
"%s %d Channel %d Bit %s %s", theMixabilityString, (
int)inDescription.mChannelsPerFrame, (
int)inDescription.mBitsPerChannel, theEndianString, theKindString);
335 if(thePackingString != NULL)
337 snprintf(outName, inMaxNameLength,
"%s %d Channel %d Bit %s Aligned %s in %d Bits", theMixabilityString, (
int)inDescription.mChannelsPerFrame, (
int)inDescription.mBitsPerChannel, theKindString, thePackingString, (
int)(inDescription.mBytesPerFrame / inDescription.mChannelsPerFrame) * 8);
341 snprintf(outName, inMaxNameLength,
"%s %d Channel %d Bit %s", theMixabilityString, (
int)inDescription.mChannelsPerFrame, (
int)inDescription.mBitsPerChannel, theKindString);
348 case kAudioFormatAC3:
349 strlcpy(outName,
"AC-3",
sizeof(outName));
352 case kAudioFormat60958AC3:
353 strlcpy(outName,
"AC-3 for SPDIF",
sizeof(outName));
357 CACopy4CCToCString(outName, inDescription.mFormatID);
363 #include "CALogMacros.h"
365 void CAStreamBasicDescription::PrintToLog(
const AudioStreamBasicDescription& inDesc)
367 PrintFloat (
" Sample Rate: ", inDesc.mSampleRate);
368 Print4CharCode (
" Format ID: ", inDesc.mFormatID);
369 PrintHex (
" Format Flags: ", inDesc.mFormatFlags);
370 PrintInt (
" Bytes per Packet: ", inDesc.mBytesPerPacket);
371 PrintInt (
" Frames per Packet: ", inDesc.mFramesPerPacket);
372 PrintInt (
" Bytes per Frame: ", inDesc.mBytesPerFrame);
373 PrintInt (
" Channels per Frame: ", inDesc.mChannelsPerFrame);
374 PrintInt (
" Bits per Channel: ", inDesc.mBitsPerChannel);
378 bool operator<(
const AudioStreamBasicDescription& x,
const AudioStreamBasicDescription& y)
380 bool theAnswer =
false;
386 if((!isDone) && ((x.mFormatID != 0) && (y.mFormatID != 0)))
388 if(x.mFormatID != y.mFormatID)
392 if(x.mFormatID == kAudioFormatLinearPCM)
396 else if(y.mFormatID == kAudioFormatLinearPCM)
402 theAnswer = x.mFormatID < y.mFormatID;
410 if((!isDone) && ((x.mFormatID == kAudioFormatLinearPCM) && (y.mFormatID == kAudioFormatLinearPCM)))
412 if(((x.mFormatFlags & kIsNonMixableFlag) == 0) && ((y.mFormatFlags & kIsNonMixableFlag) != 0))
417 else if(((x.mFormatFlags & kIsNonMixableFlag) != 0) && ((y.mFormatFlags & kIsNonMixableFlag) == 0))
425 if((!isDone) && ((x.mFormatID == kAudioFormatLinearPCM) && (y.mFormatID == kAudioFormatLinearPCM)))
427 if((x.mFormatFlags & kAudioFormatFlagIsFloat) != (y.mFormatFlags & kAudioFormatFlagIsFloat))
430 theAnswer = y.mFormatFlags & kAudioFormatFlagIsFloat;
436 if((!isDone) && ((x.mBitsPerChannel != 0) && (y.mBitsPerChannel != 0)))
438 if(x.mBitsPerChannel != y.mBitsPerChannel)
441 theAnswer = x.mBitsPerChannel < y.mBitsPerChannel;
447 if((!isDone) && fnonzero(x.mSampleRate) && fnonzero(y.mSampleRate))
449 if(fnotequal(x.mSampleRate, y.mSampleRate))
452 theAnswer = x.mSampleRate < y.mSampleRate;
458 if((!isDone) && ((x.mChannelsPerFrame != 0) && (y.mChannelsPerFrame != 0)))
460 if(x.mChannelsPerFrame != y.mChannelsPerFrame)
463 theAnswer = x.mChannelsPerFrame < y.mChannelsPerFrame;
471 static bool MatchFormatFlags(
const AudioStreamBasicDescription& x,
const AudioStreamBasicDescription& y)
473 UInt32 xFlags = x.mFormatFlags;
474 UInt32 yFlags = y.mFormatFlags;
477 if (x.mFormatID == 0 || y.mFormatID == 0 || xFlags == 0 || yFlags == 0)
480 if (x.mFormatID == kAudioFormatLinearPCM)
483 xFlags = xFlags & ~kAudioFormatFlagsAreAllClear;
484 yFlags = yFlags & ~kAudioFormatFlagsAreAllClear;
487 if (xFlags & yFlags & kAudioFormatFlagIsPacked) {
488 xFlags = xFlags & ~kAudioFormatFlagIsAlignedHigh;
489 yFlags = yFlags & ~kAudioFormatFlagIsAlignedHigh;
493 if (xFlags & yFlags & kAudioFormatFlagIsFloat) {
494 xFlags = xFlags & ~kAudioFormatFlagIsSignedInteger;
495 yFlags = yFlags & ~kAudioFormatFlagIsSignedInteger;
499 if((x.mBitsPerChannel <= 8) && ((xFlags & kAudioFormatFlagIsPacked) == kAudioFormatFlagIsPacked))
501 xFlags = xFlags & ~kAudioFormatFlagIsBigEndian;
503 if((y.mBitsPerChannel <= 8) && ((yFlags & kAudioFormatFlagIsPacked) == kAudioFormatFlagIsPacked))
505 yFlags = yFlags & ~kAudioFormatFlagIsBigEndian;
509 if (x.mChannelsPerFrame <= 1 && y.mChannelsPerFrame <= 1) {
510 xFlags &= ~kLinearPCMFormatFlagIsNonInterleaved;
511 yFlags &= ~kLinearPCMFormatFlagIsNonInterleaved;
514 return xFlags == yFlags;
517 bool operator==(
const AudioStreamBasicDescription& x,
const AudioStreamBasicDescription& y)
523 #define MATCH(name) ((x.name) == 0 || (y.name) == 0 || (x.name) == (y.name))
527 (fiszero(x.mSampleRate) || fiszero(y.mSampleRate) || fequal(x.mSampleRate, y.mSampleRate))
533 && MatchFormatFlags(x, y)
536 && MATCH(mBytesPerPacket)
539 && MATCH(mFramesPerPacket)
542 && MATCH(mBytesPerFrame)
545 && MATCH(mChannelsPerFrame)
548 && MATCH(mBitsPerChannel) ;
551 bool CAStreamBasicDescription::IsEqual(
const AudioStreamBasicDescription &other,
bool interpretingWildcards)
const
553 if (interpretingWildcards)
554 return *
this == other;
555 return memcmp(
this, &other, offsetof(AudioStreamBasicDescription, mReserved)) == 0;
558 bool SanityCheck(
const AudioStreamBasicDescription& x)
565 (x.mSampleRate >= 0.)
566 && (x.mBytesPerPacket < 1000000)
567 && (x.mFramesPerPacket < 1000000)
568 && (x.mBytesPerFrame < 1000000)
569 && (x.mChannelsPerFrame <= 1024)
570 && (x.mBitsPerChannel <= 1024)
571 && (x.mFormatID != 0)
572 && !(x.mFormatID == kAudioFormatLinearPCM && (x.mFramesPerPacket != 1 || x.mBytesPerPacket != x.mBytesPerFrame));
bool TTFOUNDATION_EXPORT operator==(const TTObject &anObject, const TTObject &anotherObject)
Compare two objects for equality.