summaryrefslogtreecommitdiff
path: root/libs/appleutility/CoreAudio105/CAStreamBasicDescription.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'libs/appleutility/CoreAudio105/CAStreamBasicDescription.cpp')
-rw-r--r--libs/appleutility/CoreAudio105/CAStreamBasicDescription.cpp520
1 files changed, 520 insertions, 0 deletions
diff --git a/libs/appleutility/CoreAudio105/CAStreamBasicDescription.cpp b/libs/appleutility/CoreAudio105/CAStreamBasicDescription.cpp
new file mode 100644
index 0000000000..bc48dd0f76
--- /dev/null
+++ b/libs/appleutility/CoreAudio105/CAStreamBasicDescription.cpp
@@ -0,0 +1,520 @@
+/* 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.
+*/
+/*=============================================================================
+ CAStreamBasicDescription.cpp
+
+=============================================================================*/
+
+#include "CAConditionalMacros.h"
+
+#include "CAStreamBasicDescription.h"
+#include "CAMath.h"
+
+#if !defined(__COREAUDIO_USE_FLAT_INCLUDES__)
+ #include <CoreFoundation/CFByteOrder.h>
+#else
+ #include <CFByteOrder.h>
+#endif
+
+#pragma mark This file needs to compile on more earlier versions of the OS, so please keep that in mind when editing it
+
+const AudioStreamBasicDescription CAStreamBasicDescription::sEmpty = { 0.0, 0, 0, 0, 0, 0, 0, 0, 0 };
+
+CAStreamBasicDescription::CAStreamBasicDescription(double inSampleRate, UInt32 inFormatID,
+ UInt32 inBytesPerPacket, UInt32 inFramesPerPacket,
+ UInt32 inBytesPerFrame, UInt32 inChannelsPerFrame,
+ UInt32 inBitsPerChannel, UInt32 inFormatFlags)
+{
+ mSampleRate = inSampleRate;
+ mFormatID = inFormatID;
+ mBytesPerPacket = inBytesPerPacket;
+ mFramesPerPacket = inFramesPerPacket;
+ mBytesPerFrame = inBytesPerFrame;
+ mChannelsPerFrame = inChannelsPerFrame;
+ mBitsPerChannel = inBitsPerChannel;
+ mFormatFlags = inFormatFlags;
+}
+
+void CAStreamBasicDescription::PrintFormat(FILE *f, const char *indent, const char *name) const
+{
+ fprintf(f, "%s%s ", indent, name);
+ char formatID[5];
+ *(UInt32 *)formatID = CFSwapInt32HostToBig(mFormatID);
+ formatID[4] = '\0';
+ fprintf(f, "%2ld ch, %6.0f Hz, '%-4.4s' (0x%08lX) ",
+ NumberChannels(), mSampleRate, formatID,
+ mFormatFlags);
+ if (mFormatID == kAudioFormatLinearPCM) {
+ bool isInt = !(mFormatFlags & kLinearPCMFormatFlagIsFloat);
+ int wordSize = SampleWordSize();
+ const char *endian = (wordSize > 1) ?
+ ((mFormatFlags & kLinearPCMFormatFlagIsBigEndian) ? " big-endian" : " little-endian" ) : "";
+ const char *sign = isInt ?
+ ((mFormatFlags & kLinearPCMFormatFlagIsSignedInteger) ? " signed" : " unsigned") : "";
+ const char *floatInt = isInt ? "integer" : "float";
+ char packed[32];
+ if (wordSize > 0 && PackednessIsSignificant()) {
+ if (mFormatFlags & kLinearPCMFormatFlagIsPacked)
+ sprintf(packed, "packed in %d bytes", wordSize);
+ else
+ sprintf(packed, "unpacked in %d bytes", wordSize);
+ } else
+ packed[0] = '\0';
+ const char *align = (wordSize > 0 && AlignmentIsSignificant()) ?
+ ((mFormatFlags & kLinearPCMFormatFlagIsAlignedHigh) ? " high-aligned" : " low-aligned") : "";
+ const char *deinter = (mFormatFlags & kAudioFormatFlagIsNonInterleaved) ? ", deinterleaved" : "";
+ const char *commaSpace = (packed[0]!='\0') || (align[0]!='\0') ? ", " : "";
+
+ fprintf(f, "%ld-bit%s%s %s%s%s%s%s\n",
+ mBitsPerChannel, endian, sign, floatInt,
+ commaSpace, packed, align, deinter);
+ } else if (mFormatID == 'alac') { // kAudioFormatAppleLossless
+ int sourceBits = 0;
+ switch (mFormatFlags)
+ {
+ case 1: // kAppleLosslessFormatFlag_16BitSourceData
+ sourceBits = 16;
+ break;
+ case 2: // kAppleLosslessFormatFlag_20BitSourceData
+ sourceBits = 20;
+ break;
+ case 3: // kAppleLosslessFormatFlag_24BitSourceData
+ sourceBits = 24;
+ break;
+ case 4: // kAppleLosslessFormatFlag_32BitSourceData
+ sourceBits = 32;
+ break;
+ }
+ if (sourceBits)
+ fprintf(f, "from %d-bit source, ", sourceBits);
+ else
+ fprintf(f, "from UNKNOWN source bit depth, ");
+
+ fprintf(f, "%ld frames/packet\n", mFramesPerPacket);
+ }
+ else
+ fprintf(f, "%ld bits/channel, %ld bytes/packet, %ld frames/packet, %ld bytes/frame\n",
+ mBitsPerChannel, mBytesPerPacket, mFramesPerPacket, mBytesPerFrame);
+}
+
+void CAStreamBasicDescription::NormalizeLinearPCMFormat(AudioStreamBasicDescription& ioDescription)
+{
+ // the only thing that changes is to make mixable linear PCM into the canonical linear PCM format
+ if((ioDescription.mFormatID == kAudioFormatLinearPCM) && ((ioDescription.mFormatFlags & kIsNonMixableFlag) == 0))
+ {
+ // the canonical linear PCM format is 32 bit native endian floats
+ ioDescription.mFormatFlags = kAudioFormatFlagsNativeFloatPacked;
+ ioDescription.mBytesPerPacket = sizeof(Float32) * ioDescription.mChannelsPerFrame;
+ ioDescription.mFramesPerPacket = 1;
+ ioDescription.mBytesPerFrame = sizeof(Float32) * ioDescription.mChannelsPerFrame;
+ ioDescription.mBitsPerChannel = 8 * sizeof(Float32);
+ }
+}
+
+void CAStreamBasicDescription::ResetFormat(AudioStreamBasicDescription& ioDescription)
+{
+ ioDescription.mSampleRate = 0;
+ ioDescription.mFormatID = 0;
+ ioDescription.mBytesPerPacket = 0;
+ ioDescription.mFramesPerPacket = 0;
+ ioDescription.mBytesPerFrame = 0;
+ ioDescription.mChannelsPerFrame = 0;
+ ioDescription.mBitsPerChannel = 0;
+ ioDescription.mFormatFlags = 0;
+}
+
+void CAStreamBasicDescription::FillOutFormat(AudioStreamBasicDescription& ioDescription, const AudioStreamBasicDescription& inTemplateDescription)
+{
+ if(fiszero(ioDescription.mSampleRate))
+ {
+ ioDescription.mSampleRate = inTemplateDescription.mSampleRate;
+ }
+ if(ioDescription.mFormatID == 0)
+ {
+ ioDescription.mFormatID = inTemplateDescription.mFormatID;
+ }
+ if(ioDescription.mFormatFlags == 0)
+ {
+ ioDescription.mFormatFlags = inTemplateDescription.mFormatFlags;
+ }
+ if(ioDescription.mBytesPerPacket == 0)
+ {
+ ioDescription.mBytesPerPacket = inTemplateDescription.mBytesPerPacket;
+ }
+ if(ioDescription.mFramesPerPacket == 0)
+ {
+ ioDescription.mFramesPerPacket = inTemplateDescription.mFramesPerPacket;
+ }
+ if(ioDescription.mBytesPerFrame == 0)
+ {
+ ioDescription.mBytesPerFrame = inTemplateDescription.mBytesPerFrame;
+ }
+ if(ioDescription.mChannelsPerFrame == 0)
+ {
+ ioDescription.mChannelsPerFrame = inTemplateDescription.mChannelsPerFrame;
+ }
+ if(ioDescription.mBitsPerChannel == 0)
+ {
+ ioDescription.mBitsPerChannel = inTemplateDescription.mBitsPerChannel;
+ }
+}
+
+void CAStreamBasicDescription::GetSimpleName(const AudioStreamBasicDescription& inDescription, char* outName, bool inAbbreviate)
+{
+ switch(inDescription.mFormatID)
+ {
+ case kAudioFormatLinearPCM:
+ {
+ const char* theEndianString = NULL;
+ if((inDescription.mFormatFlags & kAudioFormatFlagIsBigEndian) != 0)
+ {
+ #if TARGET_RT_LITTLE_ENDIAN
+ theEndianString = "Big Endian";
+ #endif
+ }
+ else
+ {
+ #if TARGET_RT_BIG_ENDIAN
+ theEndianString = "Little Endian";
+ #endif
+ }
+
+ const char* theKindString = NULL;
+ if((inDescription.mFormatFlags & kAudioFormatFlagIsFloat) != 0)
+ {
+ theKindString = (inAbbreviate ? "Float" : "Floating Point");
+ }
+ else if((inDescription.mFormatFlags & kAudioFormatFlagIsSignedInteger) != 0)
+ {
+ theKindString = (inAbbreviate ? "SInt" : "Signed Integer");
+ }
+ else
+ {
+ theKindString = (inAbbreviate ? "UInt" : "Unsigned Integer");
+ }
+
+ const char* thePackingString = NULL;
+ if((inDescription.mFormatFlags & kAudioFormatFlagIsPacked) == 0)
+ {
+ if((inDescription.mFormatFlags & kAudioFormatFlagIsAlignedHigh) != 0)
+ {
+ thePackingString = "High";
+ }
+ else
+ {
+ thePackingString = "Low";
+ }
+ }
+
+ const char* theMixabilityString = NULL;
+ if((inDescription.mFormatFlags & kIsNonMixableFlag) == 0)
+ {
+ theMixabilityString = "Mixable";
+ }
+ else
+ {
+ theMixabilityString = "Unmixable";
+ }
+
+ if(inAbbreviate)
+ {
+ if(theEndianString != NULL)
+ {
+ if(thePackingString != NULL)
+ {
+ sprintf(outName, "%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);
+ }
+ else
+ {
+ sprintf(outName, "%s %d Ch %s %s%d", theMixabilityString, (int)inDescription.mChannelsPerFrame, theEndianString, theKindString, (int)inDescription.mBitsPerChannel);
+ }
+ }
+ else
+ {
+ if(thePackingString != NULL)
+ {
+ sprintf(outName, "%s %d Ch %s %s%d/%s%d", theMixabilityString, (int)inDescription.mChannelsPerFrame, thePackingString, theKindString, (int)inDescription.mBitsPerChannel, theKindString, (int)((inDescription.mBytesPerFrame / inDescription.mChannelsPerFrame) * 8));
+ }
+ else
+ {
+ sprintf(outName, "%s %d Ch %s%d", theMixabilityString, (int)inDescription.mChannelsPerFrame, theKindString, (int)inDescription.mBitsPerChannel);
+ }
+ }
+ }
+ else
+ {
+ if(theEndianString != NULL)
+ {
+ if(thePackingString != NULL)
+ {
+ sprintf(outName, "%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);
+ }
+ else
+ {
+ sprintf(outName, "%s %d Channel %d Bit %s %s", theMixabilityString, (int)inDescription.mChannelsPerFrame, (int)inDescription.mBitsPerChannel, theEndianString, theKindString);
+ }
+ }
+ else
+ {
+ if(thePackingString != NULL)
+ {
+ sprintf(outName, "%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);
+ }
+ else
+ {
+ sprintf(outName, "%s %d Channel %d Bit %s", theMixabilityString, (int)inDescription.mChannelsPerFrame, (int)inDescription.mBitsPerChannel, theKindString);
+ }
+ }
+ }
+ }
+ break;
+
+ case kAudioFormatAC3:
+ strcpy(outName, "AC-3");
+ break;
+
+ case kAudioFormat60958AC3:
+ strcpy(outName, "AC-3 for SPDIF");
+ break;
+
+ default:
+ {
+ char* the4CCString = (char*)&inDescription.mFormatID;
+ outName[0] = the4CCString[0];
+ outName[1] = the4CCString[1];
+ outName[2] = the4CCString[2];
+ outName[3] = the4CCString[3];
+ outName[4] = 0;
+ }
+ break;
+ };
+}
+
+#if CoreAudio_Debug
+#include "CALogMacros.h"
+
+void CAStreamBasicDescription::PrintToLog(const AudioStreamBasicDescription& inDesc)
+{
+ PrintFloat (" Sample Rate: ", inDesc.mSampleRate);
+ Print4CharCode (" Format ID: ", inDesc.mFormatID);
+ PrintHex (" Format Flags: ", inDesc.mFormatFlags);
+ PrintInt (" Bytes per Packet: ", inDesc.mBytesPerPacket);
+ PrintInt (" Frames per Packet: ", inDesc.mFramesPerPacket);
+ PrintInt (" Bytes per Frame: ", inDesc.mBytesPerFrame);
+ PrintInt (" Channels per Frame: ", inDesc.mChannelsPerFrame);
+ PrintInt (" Bits per Channel: ", inDesc.mBitsPerChannel);
+}
+#endif
+
+bool operator<(const AudioStreamBasicDescription& x, const AudioStreamBasicDescription& y)
+{
+ bool theAnswer = false;
+ bool isDone = false;
+
+ // note that if either side is 0, that field is skipped
+
+ // format ID is the first order sort
+ if((!isDone) && ((x.mFormatID != 0) && (y.mFormatID != 0)))
+ {
+ if(x.mFormatID != y.mFormatID)
+ {
+ // formats are sorted numerically except that linear
+ // PCM is always first
+ if(x.mFormatID == kAudioFormatLinearPCM)
+ {
+ theAnswer = true;
+ }
+ else if(y.mFormatID == kAudioFormatLinearPCM)
+ {
+ theAnswer = false;
+ }
+ else
+ {
+ theAnswer = x.mFormatID < y.mFormatID;
+ }
+ isDone = true;
+ }
+ }
+
+
+ // mixable is always better than non-mixable for linear PCM and should be the second order sort item
+ if((!isDone) && ((x.mFormatID == kAudioFormatLinearPCM) && (y.mFormatID == kAudioFormatLinearPCM)))
+ {
+ if(((x.mFormatFlags & kIsNonMixableFlag) == 0) && ((y.mFormatFlags & kIsNonMixableFlag) != 0))
+ {
+ theAnswer = true;
+ isDone = true;
+ }
+ else if(((x.mFormatFlags & kIsNonMixableFlag) != 0) && ((y.mFormatFlags & kIsNonMixableFlag) == 0))
+ {
+ theAnswer = false;
+ isDone = true;
+ }
+ }
+
+ // floating point vs integer for linear PCM only
+ if((!isDone) && ((x.mFormatID == kAudioFormatLinearPCM) && (y.mFormatID == kAudioFormatLinearPCM)))
+ {
+ if((x.mFormatFlags & kAudioFormatFlagIsFloat) != (y.mFormatFlags & kAudioFormatFlagIsFloat))
+ {
+ // floating point is better than integer
+ theAnswer = y.mFormatFlags & kAudioFormatFlagIsFloat;
+ isDone = true;
+ }
+ }
+
+ // bit depth
+ if((!isDone) && ((x.mBitsPerChannel != 0) && (y.mBitsPerChannel != 0)))
+ {
+ if(x.mBitsPerChannel != y.mBitsPerChannel)
+ {
+ // deeper bit depths are higher quality
+ theAnswer = x.mBitsPerChannel < y.mBitsPerChannel;
+ isDone = true;
+ }
+ }
+
+ // sample rate
+ if((!isDone) && fnonzero(x.mSampleRate) && fnonzero(y.mSampleRate))
+ {
+ if(fnotequal(x.mSampleRate, y.mSampleRate))
+ {
+ // higher sample rates are higher quality
+ theAnswer = x.mSampleRate < y.mSampleRate;
+ isDone = true;
+ }
+ }
+
+ // number of channels
+ if((!isDone) && ((x.mChannelsPerFrame != 0) && (y.mChannelsPerFrame != 0)))
+ {
+ if(x.mChannelsPerFrame != y.mChannelsPerFrame)
+ {
+ // more channels is higher quality
+ theAnswer = x.mChannelsPerFrame < y.mChannelsPerFrame;
+ isDone = true;
+ }
+ }
+
+ return theAnswer;
+}
+
+static bool MatchFormatFlags(const AudioStreamBasicDescription& x, const AudioStreamBasicDescription& y)
+{
+ UInt32 xFlags = x.mFormatFlags;
+ UInt32 yFlags = y.mFormatFlags;
+
+ // match wildcards
+ if (x.mFormatID == 0 || y.mFormatID == 0 || xFlags == 0 || yFlags == 0)
+ return true;
+
+ if (x.mFormatID == kAudioFormatLinearPCM)
+ {
+ // knock off the all clear flag
+ xFlags = xFlags & ~kAudioFormatFlagsAreAllClear;
+ yFlags = yFlags & ~kAudioFormatFlagsAreAllClear;
+
+ // if both kAudioFormatFlagIsPacked bits are set, then we don't care about the kAudioFormatFlagIsAlignedHigh bit.
+ if (xFlags & yFlags & kAudioFormatFlagIsPacked) {
+ xFlags = xFlags & ~kAudioFormatFlagIsAlignedHigh;
+ yFlags = yFlags & ~kAudioFormatFlagIsAlignedHigh;
+ }
+
+ // if both kAudioFormatFlagIsFloat bits are set, then we don't care about the kAudioFormatFlagIsSignedInteger bit.
+ if (xFlags & yFlags & kAudioFormatFlagIsFloat) {
+ xFlags = xFlags & ~kAudioFormatFlagIsSignedInteger;
+ yFlags = yFlags & ~kAudioFormatFlagIsSignedInteger;
+ }
+
+ // if the bit depth is 8 bits or less and the format is packed, we don't care about endianness
+ if((x.mBitsPerChannel <= 8) && ((xFlags & kAudioFormatFlagIsPacked) == kAudioFormatFlagIsPacked))
+ {
+ xFlags = xFlags & ~kAudioFormatFlagIsBigEndian;
+ }
+ if((y.mBitsPerChannel <= 8) && ((yFlags & kAudioFormatFlagIsPacked) == kAudioFormatFlagIsPacked))
+ {
+ yFlags = yFlags & ~kAudioFormatFlagIsBigEndian;
+ }
+
+ // if the number of channels is 0 or 1, we don't care about non-interleavedness
+ if (x.mChannelsPerFrame <= 1 && y.mChannelsPerFrame <= 1) {
+ xFlags &= ~kLinearPCMFormatFlagIsNonInterleaved;
+ yFlags &= ~kLinearPCMFormatFlagIsNonInterleaved;
+ }
+ }
+ return xFlags == yFlags;
+}
+
+bool operator==(const AudioStreamBasicDescription& x, const AudioStreamBasicDescription& y)
+{
+ // the semantics for equality are:
+ // 1) Values must match exactly
+ // 2) wildcard's are ignored in the comparison
+
+#define MATCH(name) ((x.name) == 0 || (y.name) == 0 || (x.name) == (y.name))
+
+ return
+ // check the sample rate
+ (fiszero(x.mSampleRate) || fiszero(y.mSampleRate) || fequal(x.mSampleRate, y.mSampleRate))
+
+ // check the format ids
+ && MATCH(mFormatID)
+
+ // check the format flags
+ && MatchFormatFlags(x, y)
+
+ // check the bytes per packet
+ && MATCH(mBytesPerPacket)
+
+ // check the frames per packet
+ && MATCH(mFramesPerPacket)
+
+ // check the bytes per frame
+ && MATCH(mBytesPerFrame)
+
+ // check the channels per frame
+ && MATCH(mChannelsPerFrame)
+
+ // check the channels per frame
+ && MATCH(mBitsPerChannel) ;
+}
+
+bool SanityCheck(const AudioStreamBasicDescription& x)
+{
+ return (x.mSampleRate >= 0.);
+}