Merge pull request #506 from andrewcsmith/patch-2
[supercollider.git] / platform / mac / SuperColliderAU / AUSDK / CAStreamBasicDescription.cpp
blob370616a5eb0d7e84cf813171f11fa27b6182d5e5
1 /* Copyright © 2007 Apple Inc. All Rights Reserved.
3 Disclaimer: IMPORTANT: This Apple software is supplied to you by
4 Apple Inc. ("Apple") in consideration of your agreement to the
5 following terms, and your use, installation, modification or
6 redistribution of this Apple software constitutes acceptance of these
7 terms. If you do not agree with these terms, please do not use,
8 install, modify or redistribute this Apple software.
10 In consideration of your agreement to abide by the following terms, and
11 subject to these terms, Apple grants you a personal, non-exclusive
12 license, under Apple's copyrights in this original Apple software (the
13 "Apple Software"), to use, reproduce, modify and redistribute the Apple
14 Software, with or without modifications, in source and/or binary forms;
15 provided that if you redistribute the Apple Software in its entirety and
16 without modifications, you must retain this notice and the following
17 text and disclaimers in all such redistributions of the Apple Software.
18 Neither the name, trademarks, service marks or logos of Apple Inc.
19 may be used to endorse or promote products derived from the Apple
20 Software without specific prior written permission from Apple. Except
21 as expressly stated in this notice, no other rights or licenses, express
22 or implied, are granted by Apple herein, including but not limited to
23 any patent rights that may be infringed by your derivative works or by
24 other works in which the Apple Software may be incorporated.
26 The Apple Software is provided by Apple on an "AS IS" basis. APPLE
27 MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION
28 THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS
29 FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND
30 OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS.
32 IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL
33 OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
34 SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
35 INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION,
36 MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED
37 AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE),
38 STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE
39 POSSIBILITY OF SUCH DAMAGE.
41 /*=============================================================================
42 CAStreamBasicDescription.cpp
44 =============================================================================*/
46 #include "CAStreamBasicDescription.h"
47 #include "CAMath.h"
49 #if !defined(__COREAUDIO_USE_FLAT_INCLUDES__)
50 #include <CoreFoundation/CFByteOrder.h>
51 #else
52 #include <CFByteOrder.h>
53 #endif
55 #if TARGET_OS_WIN32
56 #include <stddef.h>
57 #endif
59 #pragma mark This file needs to compile on earlier versions of the OS, so please keep that in mind when editing it
61 const AudioStreamBasicDescription CAStreamBasicDescription::sEmpty = { 0.0, 0, 0, 0, 0, 0, 0, 0, 0 };
63 CAStreamBasicDescription::CAStreamBasicDescription(double inSampleRate, UInt32 inFormatID,
64 UInt32 inBytesPerPacket, UInt32 inFramesPerPacket,
65 UInt32 inBytesPerFrame, UInt32 inChannelsPerFrame,
66 UInt32 inBitsPerChannel, UInt32 inFormatFlags)
68 mSampleRate = inSampleRate;
69 mFormatID = inFormatID;
70 mBytesPerPacket = inBytesPerPacket;
71 mFramesPerPacket = inFramesPerPacket;
72 mBytesPerFrame = inBytesPerFrame;
73 mChannelsPerFrame = inChannelsPerFrame;
74 mBitsPerChannel = inBitsPerChannel;
75 mFormatFlags = inFormatFlags;
76 mReserved = 0;
79 void CAStreamBasicDescription::PrintFormat2(FILE *f, const char *indent, const char *name) const
81 fprintf(f, "%s%s ", indent, name);
82 char formatID[5];
83 *(UInt32 *)formatID = CFSwapInt32HostToBig(mFormatID);
84 formatID[4] = '\0';
85 fprintf(f, "%2d ch, %6.0f Hz, '%-4.4s' (0x%08X) ",
86 (int)NumberChannels(), mSampleRate, formatID,
87 (int)mFormatFlags);
88 if (mFormatID == kAudioFormatLinearPCM) {
89 bool isInt = !(mFormatFlags & kLinearPCMFormatFlagIsFloat);
90 int wordSize = SampleWordSize();
91 const char *endian = (wordSize > 1) ?
92 ((mFormatFlags & kLinearPCMFormatFlagIsBigEndian) ? " big-endian" : " little-endian" ) : "";
93 const char *sign = isInt ?
94 ((mFormatFlags & kLinearPCMFormatFlagIsSignedInteger) ? " signed" : " unsigned") : "";
95 const char *floatInt = isInt ? "integer" : "float";
96 char packed[32];
97 if (wordSize > 0 && PackednessIsSignificant()) {
98 if (mFormatFlags & kLinearPCMFormatFlagIsPacked)
99 sprintf(packed, "packed in %d bytes", wordSize);
100 else
101 sprintf(packed, "unpacked in %d bytes", wordSize);
102 } else
103 packed[0] = '\0';
104 const char *align = (wordSize > 0 && AlignmentIsSignificant()) ?
105 ((mFormatFlags & kLinearPCMFormatFlagIsAlignedHigh) ? " high-aligned" : " low-aligned") : "";
106 const char *deinter = (mFormatFlags & kAudioFormatFlagIsNonInterleaved) ? ", deinterleaved" : "";
107 const char *commaSpace = (packed[0]!='\0') || (align[0]!='\0') ? ", " : "";
109 fprintf(f, "%d-bit%s%s %s%s%s%s%s",
110 (int)mBitsPerChannel, endian, sign, floatInt,
111 commaSpace, packed, align, deinter);
112 } else if (mFormatID == 'alac') { // kAudioFormatAppleLossless
113 int sourceBits = 0;
114 switch (mFormatFlags)
116 case 1: // kAppleLosslessFormatFlag_16BitSourceData
117 sourceBits = 16;
118 break;
119 case 2: // kAppleLosslessFormatFlag_20BitSourceData
120 sourceBits = 20;
121 break;
122 case 3: // kAppleLosslessFormatFlag_24BitSourceData
123 sourceBits = 24;
124 break;
125 case 4: // kAppleLosslessFormatFlag_32BitSourceData
126 sourceBits = 32;
127 break;
129 if (sourceBits)
130 fprintf(f, "from %d-bit source, ", sourceBits);
131 else
132 fprintf(f, "from UNKNOWN source bit depth, ");
134 fprintf(f, "%d frames/packet", (int)mFramesPerPacket);
136 else
137 fprintf(f, "%d bits/channel, %d bytes/packet, %d frames/packet, %d bytes/frame",
138 (int)mBitsPerChannel, (int)mBytesPerPacket, (int)mFramesPerPacket, (int)mBytesPerFrame);
141 void CAStreamBasicDescription::NormalizeLinearPCMFormat(AudioStreamBasicDescription& ioDescription)
143 // the only thing that changes is to make mixable linear PCM into the canonical linear PCM format
144 if((ioDescription.mFormatID == kAudioFormatLinearPCM) && ((ioDescription.mFormatFlags & kIsNonMixableFlag) == 0))
146 // the canonical linear PCM format
147 ioDescription.mFormatFlags = kAudioFormatFlagsCanonical;
148 ioDescription.mBytesPerPacket = sizeof(AudioSampleType) * ioDescription.mChannelsPerFrame;
149 ioDescription.mFramesPerPacket = 1;
150 ioDescription.mBytesPerFrame = sizeof(AudioSampleType) * ioDescription.mChannelsPerFrame;
151 ioDescription.mBitsPerChannel = 8 * sizeof(AudioSampleType);
155 void CAStreamBasicDescription::ResetFormat(AudioStreamBasicDescription& ioDescription)
157 ioDescription.mSampleRate = 0;
158 ioDescription.mFormatID = 0;
159 ioDescription.mBytesPerPacket = 0;
160 ioDescription.mFramesPerPacket = 0;
161 ioDescription.mBytesPerFrame = 0;
162 ioDescription.mChannelsPerFrame = 0;
163 ioDescription.mBitsPerChannel = 0;
164 ioDescription.mFormatFlags = 0;
167 void CAStreamBasicDescription::FillOutFormat(AudioStreamBasicDescription& ioDescription, const AudioStreamBasicDescription& inTemplateDescription)
169 if(fiszero(ioDescription.mSampleRate))
171 ioDescription.mSampleRate = inTemplateDescription.mSampleRate;
173 if(ioDescription.mFormatID == 0)
175 ioDescription.mFormatID = inTemplateDescription.mFormatID;
177 if(ioDescription.mFormatFlags == 0)
179 ioDescription.mFormatFlags = inTemplateDescription.mFormatFlags;
181 if(ioDescription.mBytesPerPacket == 0)
183 ioDescription.mBytesPerPacket = inTemplateDescription.mBytesPerPacket;
185 if(ioDescription.mFramesPerPacket == 0)
187 ioDescription.mFramesPerPacket = inTemplateDescription.mFramesPerPacket;
189 if(ioDescription.mBytesPerFrame == 0)
191 ioDescription.mBytesPerFrame = inTemplateDescription.mBytesPerFrame;
193 if(ioDescription.mChannelsPerFrame == 0)
195 ioDescription.mChannelsPerFrame = inTemplateDescription.mChannelsPerFrame;
197 if(ioDescription.mBitsPerChannel == 0)
199 ioDescription.mBitsPerChannel = inTemplateDescription.mBitsPerChannel;
203 void CAStreamBasicDescription::GetSimpleName(const AudioStreamBasicDescription& inDescription, char* outName, bool inAbbreviate)
205 switch(inDescription.mFormatID)
207 case kAudioFormatLinearPCM:
209 const char* theEndianString = NULL;
210 if((inDescription.mFormatFlags & kAudioFormatFlagIsBigEndian) != 0)
212 #if TARGET_RT_LITTLE_ENDIAN
213 theEndianString = "Big Endian";
214 #endif
216 else
218 #if TARGET_RT_BIG_ENDIAN
219 theEndianString = "Little Endian";
220 #endif
223 const char* theKindString = NULL;
224 if((inDescription.mFormatFlags & kAudioFormatFlagIsFloat) != 0)
226 theKindString = (inAbbreviate ? "Float" : "Floating Point");
228 else if((inDescription.mFormatFlags & kAudioFormatFlagIsSignedInteger) != 0)
230 theKindString = (inAbbreviate ? "SInt" : "Signed Integer");
232 else
234 theKindString = (inAbbreviate ? "UInt" : "Unsigned Integer");
237 const char* thePackingString = NULL;
238 if((inDescription.mFormatFlags & kAudioFormatFlagIsPacked) == 0)
240 if((inDescription.mFormatFlags & kAudioFormatFlagIsAlignedHigh) != 0)
242 thePackingString = "High";
244 else
246 thePackingString = "Low";
250 const char* theMixabilityString = NULL;
251 if((inDescription.mFormatFlags & kIsNonMixableFlag) == 0)
253 theMixabilityString = "Mixable";
255 else
257 theMixabilityString = "Unmixable";
260 if(inAbbreviate)
262 if(theEndianString != NULL)
264 if(thePackingString != NULL)
266 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);
268 else
270 sprintf(outName, "%s %d Ch %s %s%d", theMixabilityString, (int)inDescription.mChannelsPerFrame, theEndianString, theKindString, (int)inDescription.mBitsPerChannel);
273 else
275 if(thePackingString != NULL)
277 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));
279 else
281 sprintf(outName, "%s %d Ch %s%d", theMixabilityString, (int)inDescription.mChannelsPerFrame, theKindString, (int)inDescription.mBitsPerChannel);
285 else
287 if(theEndianString != NULL)
289 if(thePackingString != NULL)
291 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);
293 else
295 sprintf(outName, "%s %d Channel %d Bit %s %s", theMixabilityString, (int)inDescription.mChannelsPerFrame, (int)inDescription.mBitsPerChannel, theEndianString, theKindString);
298 else
300 if(thePackingString != NULL)
302 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);
304 else
306 sprintf(outName, "%s %d Channel %d Bit %s", theMixabilityString, (int)inDescription.mChannelsPerFrame, (int)inDescription.mBitsPerChannel, theKindString);
311 break;
313 case kAudioFormatAC3:
314 strcpy(outName, "AC-3");
315 break;
317 case kAudioFormat60958AC3:
318 strcpy(outName, "AC-3 for SPDIF");
319 break;
321 default:
322 CACopy4CCToCString(outName, inDescription.mFormatID);
323 break;
327 #if CoreAudio_Debug
328 #include "CALogMacros.h"
330 void CAStreamBasicDescription::PrintToLog(const AudioStreamBasicDescription& inDesc)
332 PrintFloat (" Sample Rate: ", inDesc.mSampleRate);
333 Print4CharCode (" Format ID: ", inDesc.mFormatID);
334 PrintHex (" Format Flags: ", inDesc.mFormatFlags);
335 PrintInt (" Bytes per Packet: ", inDesc.mBytesPerPacket);
336 PrintInt (" Frames per Packet: ", inDesc.mFramesPerPacket);
337 PrintInt (" Bytes per Frame: ", inDesc.mBytesPerFrame);
338 PrintInt (" Channels per Frame: ", inDesc.mChannelsPerFrame);
339 PrintInt (" Bits per Channel: ", inDesc.mBitsPerChannel);
341 #endif
343 bool operator<(const AudioStreamBasicDescription& x, const AudioStreamBasicDescription& y)
345 bool theAnswer = false;
346 bool isDone = false;
348 // note that if either side is 0, that field is skipped
350 // format ID is the first order sort
351 if((!isDone) && ((x.mFormatID != 0) && (y.mFormatID != 0)))
353 if(x.mFormatID != y.mFormatID)
355 // formats are sorted numerically except that linear
356 // PCM is always first
357 if(x.mFormatID == kAudioFormatLinearPCM)
359 theAnswer = true;
361 else if(y.mFormatID == kAudioFormatLinearPCM)
363 theAnswer = false;
365 else
367 theAnswer = x.mFormatID < y.mFormatID;
369 isDone = true;
374 // mixable is always better than non-mixable for linear PCM and should be the second order sort item
375 if((!isDone) && ((x.mFormatID == kAudioFormatLinearPCM) && (y.mFormatID == kAudioFormatLinearPCM)))
377 if(((x.mFormatFlags & kIsNonMixableFlag) == 0) && ((y.mFormatFlags & kIsNonMixableFlag) != 0))
379 theAnswer = true;
380 isDone = true;
382 else if(((x.mFormatFlags & kIsNonMixableFlag) != 0) && ((y.mFormatFlags & kIsNonMixableFlag) == 0))
384 theAnswer = false;
385 isDone = true;
389 // floating point vs integer for linear PCM only
390 if((!isDone) && ((x.mFormatID == kAudioFormatLinearPCM) && (y.mFormatID == kAudioFormatLinearPCM)))
392 if((x.mFormatFlags & kAudioFormatFlagIsFloat) != (y.mFormatFlags & kAudioFormatFlagIsFloat))
394 // floating point is better than integer
395 theAnswer = y.mFormatFlags & kAudioFormatFlagIsFloat;
396 isDone = true;
400 // bit depth
401 if((!isDone) && ((x.mBitsPerChannel != 0) && (y.mBitsPerChannel != 0)))
403 if(x.mBitsPerChannel != y.mBitsPerChannel)
405 // deeper bit depths are higher quality
406 theAnswer = x.mBitsPerChannel < y.mBitsPerChannel;
407 isDone = true;
411 // sample rate
412 if((!isDone) && fnonzero(x.mSampleRate) && fnonzero(y.mSampleRate))
414 if(fnotequal(x.mSampleRate, y.mSampleRate))
416 // higher sample rates are higher quality
417 theAnswer = x.mSampleRate < y.mSampleRate;
418 isDone = true;
422 // number of channels
423 if((!isDone) && ((x.mChannelsPerFrame != 0) && (y.mChannelsPerFrame != 0)))
425 if(x.mChannelsPerFrame != y.mChannelsPerFrame)
427 // more channels is higher quality
428 theAnswer = x.mChannelsPerFrame < y.mChannelsPerFrame;
429 isDone = true;
433 return theAnswer;
436 static bool MatchFormatFlags(const AudioStreamBasicDescription& x, const AudioStreamBasicDescription& y)
438 UInt32 xFlags = x.mFormatFlags;
439 UInt32 yFlags = y.mFormatFlags;
441 // match wildcards
442 if (x.mFormatID == 0 || y.mFormatID == 0 || xFlags == 0 || yFlags == 0)
443 return true;
445 if (x.mFormatID == kAudioFormatLinearPCM)
447 // knock off the all clear flag
448 xFlags = xFlags & ~kAudioFormatFlagsAreAllClear;
449 yFlags = yFlags & ~kAudioFormatFlagsAreAllClear;
451 // if both kAudioFormatFlagIsPacked bits are set, then we don't care about the kAudioFormatFlagIsAlignedHigh bit.
452 if (xFlags & yFlags & kAudioFormatFlagIsPacked) {
453 xFlags = xFlags & ~kAudioFormatFlagIsAlignedHigh;
454 yFlags = yFlags & ~kAudioFormatFlagIsAlignedHigh;
457 // if both kAudioFormatFlagIsFloat bits are set, then we don't care about the kAudioFormatFlagIsSignedInteger bit.
458 if (xFlags & yFlags & kAudioFormatFlagIsFloat) {
459 xFlags = xFlags & ~kAudioFormatFlagIsSignedInteger;
460 yFlags = yFlags & ~kAudioFormatFlagIsSignedInteger;
463 // if the bit depth is 8 bits or less and the format is packed, we don't care about endianness
464 if((x.mBitsPerChannel <= 8) && ((xFlags & kAudioFormatFlagIsPacked) == kAudioFormatFlagIsPacked))
466 xFlags = xFlags & ~kAudioFormatFlagIsBigEndian;
468 if((y.mBitsPerChannel <= 8) && ((yFlags & kAudioFormatFlagIsPacked) == kAudioFormatFlagIsPacked))
470 yFlags = yFlags & ~kAudioFormatFlagIsBigEndian;
473 // if the number of channels is 0 or 1, we don't care about non-interleavedness
474 if (x.mChannelsPerFrame <= 1 && y.mChannelsPerFrame <= 1) {
475 xFlags &= ~kLinearPCMFormatFlagIsNonInterleaved;
476 yFlags &= ~kLinearPCMFormatFlagIsNonInterleaved;
479 return xFlags == yFlags;
482 bool operator==(const AudioStreamBasicDescription& x, const AudioStreamBasicDescription& y)
484 // the semantics for equality are:
485 // 1) Values must match exactly
486 // 2) wildcard's are ignored in the comparison
488 #define MATCH(name) ((x.name) == 0 || (y.name) == 0 || (x.name) == (y.name))
490 return
491 // check the sample rate
492 (fiszero(x.mSampleRate) || fiszero(y.mSampleRate) || fequal(x.mSampleRate, y.mSampleRate))
494 // check the format ids
495 && MATCH(mFormatID)
497 // check the format flags
498 && MatchFormatFlags(x, y)
500 // check the bytes per packet
501 && MATCH(mBytesPerPacket)
503 // check the frames per packet
504 && MATCH(mFramesPerPacket)
506 // check the bytes per frame
507 && MATCH(mBytesPerFrame)
509 // check the channels per frame
510 && MATCH(mChannelsPerFrame)
512 // check the channels per frame
513 && MATCH(mBitsPerChannel) ;
516 bool CAStreamBasicDescription::IsEqual(const AudioStreamBasicDescription &other, bool interpretingWildcards) const
518 if (interpretingWildcards)
519 return *this == other;
520 return memcmp(this, &other, offsetof(AudioStreamBasicDescription, mReserved)) == 0;
523 bool SanityCheck(const AudioStreamBasicDescription& x)
525 return (x.mSampleRate >= 0.);