char *CAStreamBasicDescription::AsString(char *buf, size_t bufsize) const { char *theBuffer = buf; int nc; char formatID[5]; *(UInt32 *)formatID = CFSwapInt32HostToBig(mFormatID); formatID[4] = '\0'; nc = snprintf(buf, bufsize, "%2d ch, %6.0f Hz, '%-4.4s' (0x%08X) ", (int)NumberChannels(), mSampleRate, formatID, (int)mFormatFlags); buf += nc; bufsize -= nc; 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') ? ", " : ""; char bitdepth[20]; #if CA_PREFER_FIXED_POINT int fracbits = (mFormatFlags & kLinearPCMFormatFlagsSampleFractionMask) >> kLinearPCMFormatFlagsSampleFractionShift; if (fracbits > 0) sprintf(bitdepth, "%d.%d", (int)mBitsPerChannel - fracbits, fracbits); else #endif sprintf(bitdepth, "%d", (int)mBitsPerChannel); nc = snprintf(buf, bufsize, "%s-bit%s%s %s%s%s%s%s", bitdepth, endian, sign, floatInt, commaSpace, packed, align, deinter); //buf += nc; bufsize -= nc; } else if (mFormatID == 'alac') { // kAudioFormatAppleLossless
char *CAStreamBasicDescription::AsString(char *buf, size_t _bufsize) const { int bufsize = (int)_bufsize; // must be signed to protect against overflow char *theBuffer = buf; int nc; char formatID[24]; CAStringForOSType (mFormatID, formatID); nc = snprintf(buf, bufsize, "%2d ch, %6.0f Hz, %s (0x%08X) ", (int)NumberChannels(), mSampleRate, formatID, (int)mFormatFlags); buf += nc; if ((bufsize -= nc) <= 0) goto exit; 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) snprintf(packed, sizeof(packed), "packed in %d bytes", wordSize); else snprintf(packed, sizeof(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') ? ", " : ""; char bitdepth[20]; int fracbits = (mFormatFlags & kLinearPCMFormatFlagsSampleFractionMask) >> kLinearPCMFormatFlagsSampleFractionShift; if (fracbits > 0) snprintf(bitdepth, sizeof(bitdepth), "%d.%d", (int)mBitsPerChannel - fracbits, fracbits); else snprintf(bitdepth, sizeof(bitdepth), "%d", (int)mBitsPerChannel); /* nc =*/ snprintf(buf, bufsize, "%s-bit%s%s %s%s%s%s%s", bitdepth, endian, sign, floatInt, commaSpace, packed, align, deinter); // buf += nc; if ((bufsize -= nc) <= 0) goto exit; } else if (mFormatID == 'alac') { // kAudioFormatAppleLossless
OSStatus PrintBuses (FILE* file, const char* str, AudioUnit au, AudioUnitScope inScope) { OSStatus result; UInt32 busCount; UInt32 theSize = sizeof(busCount); ca_require_noerr (result = AudioUnitGetProperty (au, kAudioUnitProperty_ElementCount, inScope, 0, &busCount, &theSize), home); fprintf (file, "\t%s Elements:\n\t\t", str); for (UInt32 i = 0; i < busCount; ++i) { Float32 val; ca_require_noerr (result = AudioUnitGetParameter (au, kMatrixMixerParam_Enable, inScope, i, &val), home); UInt32 numChans; ca_require_noerr (result = NumberChannels (au, inScope, i, numChans), home); char frameCharStart = (val != 0 ? '[' : '{'); char frameCharEnd = (val != 0 ? ']' : '}'); fprintf (file, "%d:%c%d, %c%c ", (int)i, frameCharStart, (int)numChans, (val != 0 ? 'T' : 'F'), frameCharEnd); } fprintf (file, "\n"); home: return result; }
void CAStreamBasicDescription::PrintFormat2(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, "%2d ch, %6.0f Hz, '%-4.4s' (0x%08X) ", (int)NumberChannels(), mSampleRate, formatID, (int)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, "%d-bit%s%s %s%s%s%s%s", (int)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, "%d frames/packet", (int)mFramesPerPacket); } else fprintf(f, "%d bits/channel, %d bytes/packet, %d frames/packet, %d bytes/frame", (int)mBitsPerChannel, (int)mBytesPerPacket, (int)mFramesPerPacket, (int)mBytesPerFrame); }
char *CAStreamBasicDescription::AsString(char *buf, size_t _bufsize, bool brief /*=false*/) const { int bufsize = (int)_bufsize; // must be signed to protect against overflow char *theBuffer = buf; int nc; char formatID[24]; CAStringForOSType(mFormatID, formatID, sizeof(formatID)); if (brief) { CommonPCMFormat com; bool interleaved; if (IdentifyCommonPCMFormat(com, &interleaved) && com != kPCMFormatOther) { const char *desc; switch (com) { case kPCMFormatInt16: desc = "Int16"; break; case kPCMFormatFixed824: desc = "Int8.24"; break; case kPCMFormatFloat32: desc = "Float32"; break; case kPCMFormatFloat64: desc = "Float64"; break; default: desc = NULL; break; } if (desc) { const char *inter =""; if (mChannelsPerFrame > 1) inter = !interleaved ? ", non-inter" : ", inter"; snprintf(buf, static_cast<size_t>(bufsize), "%2d ch, %6.0f Hz, %s%s", (int)mChannelsPerFrame, mSampleRate, desc, inter); return theBuffer; } } if (mChannelsPerFrame == 0 && mSampleRate == 0.0 && mFormatID == 0) { snprintf(buf, static_cast<size_t>(bufsize), "%2d ch, %6.0f Hz", (int)mChannelsPerFrame, mSampleRate); return theBuffer; } } nc = snprintf(buf, static_cast<size_t>(bufsize), "%2d ch, %6.0f Hz, %s (0x%08X) ", (int)NumberChannels(), mSampleRate, formatID, (int)mFormatFlags); buf += nc; if ((bufsize -= nc) <= 0) goto exit; if (mFormatID == kAudioFormatLinearPCM) { bool isInt = !(mFormatFlags & kLinearPCMFormatFlagIsFloat); int wordSize = static_cast<int>(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) snprintf(packed, sizeof(packed), "packed in %d bytes", wordSize); else snprintf(packed, sizeof(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') ? ", " : ""; char bitdepth[20]; int fracbits = (mFormatFlags & kLinearPCMFormatFlagsSampleFractionMask) >> kLinearPCMFormatFlagsSampleFractionShift; if (fracbits > 0) snprintf(bitdepth, sizeof(bitdepth), "%d.%d", (int)mBitsPerChannel - fracbits, fracbits); else snprintf(bitdepth, sizeof(bitdepth), "%d", (int)mBitsPerChannel); /*nc =*/ snprintf(buf, static_cast<size_t>(bufsize), "%s-bit%s%s %s%s%s%s%s", bitdepth, endian, sign, floatInt, commaSpace, packed, align, deinter); // buf += nc; if ((bufsize -= nc) <= 0) goto exit; } else if (mFormatID == 'alac') { // kAudioFormatAppleLossless
bool CAAudioUnit::CanDo (const CAAUChanHelper &inputs, const CAAUChanHelper &outputs) const { // first check our state // huh! if (inputs.mNumEls == 0 && outputs.mNumEls == 0) return false; UInt32 elCount; if (GetElementCount (kAudioUnitScope_Input, elCount)) { return false; } if (elCount != inputs.mNumEls) return false; if (GetElementCount (kAudioUnitScope_Output, elCount)) { return false; } if (elCount != outputs.mNumEls) return false; // (1) special cases (effects and sources (generators and instruments) only) UInt32 dataSize = 0; if (GetPropertyInfo (kAudioUnitProperty_SupportedNumChannels, kAudioUnitScope_Global, 0, &dataSize, NULL) != noErr) { if (Comp().Desc().IsEffect() || Comp().Desc().IsOffline()) { UInt32 numChan = outputs.mNumEls > 0 ? outputs.mChans[0] : inputs.mChans[0]; for (unsigned int in = 0; in < inputs.mNumEls; ++in) if (numChan != inputs.mChans[in]) return false; for (unsigned int out = 0; out < outputs.mNumEls; ++out) if (numChan != outputs.mChans[out]) return false; return true; } // in this case, all the channels have to match the current config if (Comp().Desc().IsGenerator() || Comp().Desc().IsMusicDevice()) { for (unsigned int in = 0; in < inputs.mNumEls; ++in) { UInt32 chan; if (NumberChannels (kAudioUnitScope_Input, in, chan)) return false; if (chan != UInt32(inputs.mChans[in])) return false; } for (unsigned int out = 0; out < outputs.mNumEls; ++out) { UInt32 chan; if (NumberChannels (kAudioUnitScope_Output, out, chan)) return false; if (chan != UInt32(outputs.mChans[out])) return false; } return true; } // if we get here we can't determine anything about channel capabilities return false; } StackAUChannelInfo info (dataSize); if (GetProperty (kAudioUnitProperty_SupportedNumChannels, kAudioUnitScope_Global, 0, info.mChanInfo, &dataSize) != noErr) { return false; } int numInfo = dataSize / sizeof(AUChannelInfo); // (2) Test for dynamic capability (or no elements on that scope) SInt32 dynInChans = 0; if (ValidateDynamicScope (kAudioUnitScope_Input, dynInChans, info.mChanInfo, numInfo)) { if (CheckDynCount (dynInChans, inputs) == false) return false; } SInt32 dynOutChans = 0; if (ValidateDynamicScope (kAudioUnitScope_Output, dynOutChans, info.mChanInfo, numInfo)) { if (CheckDynCount (dynOutChans, outputs) == false) return false; } if (dynOutChans && dynInChans) { return true; } // (3) Just need to test one side if (dynInChans || (inputs.mNumEls == 0)) { return CheckOneSide (outputs, true, info.mChanInfo, numInfo); } if (dynOutChans || (outputs.mNumEls == 0)) { return CheckOneSide (inputs, false, info.mChanInfo, numInfo); } // (4) - not a dynamic AU, has ins and outs, and has channel constraints so we test every possible pairing for (unsigned int in = 0; in < inputs.mNumEls; ++in) { bool testInAlready = false; for (unsigned int i = 0; i < in; ++i) { if (inputs.mChans[i] == inputs.mChans[in]) { testInAlready = true; break; } } if (!testInAlready) { for (unsigned int out = 0; out < outputs.mNumEls; ++out) { // try to save a little bit and not test the same pairing multiple times... bool testOutAlready = false; for (unsigned int i = 0; i < out; ++i) { if (outputs.mChans[i] == outputs.mChans[out]) { testOutAlready = true; break; } } if (!testOutAlready) { if (!ValidateChannelPair (inputs.mChans[in], outputs.mChans[out],info.mChanInfo, numInfo)) { return false; } } } } } return true; }
int CAAudioUnit::GetChannelInfo (AUChannelInfo** chaninfo, UInt32& cnt) { // this is the default assumption of an audio effect unit Boolean* isWritable = 0; UInt32 dataSize = 0; // lets see if the unit has any channel restrictions OSStatus result = AudioUnitGetPropertyInfo (AU(), kAudioUnitProperty_SupportedNumChannels, kAudioUnitScope_Global, 0, &dataSize, isWritable); //don't care if this is writable // if this property is NOT implemented an FX unit // is expected to deal with same channel valance in and out if (result) { if (Comp().Desc().IsEffect()) { return 1; } else if (Comp().Desc().IsGenerator() || Comp().Desc().IsMusicDevice()) { // directly query Bus Formats // Note that that these may refer to different subBusses // (eg. Kick, Snare,.. on a Drummachine) // eventually the Bus-Name for each configuration should be exposed // for the User to select.. UInt32 elCountIn, elCountOut; if (GetElementCount (kAudioUnitScope_Input, elCountIn)) return -1; if (GetElementCount (kAudioUnitScope_Output, elCountOut)) return -1; cnt = std::max(elCountIn, elCountOut); *chaninfo = (AUChannelInfo*) malloc (sizeof (AUChannelInfo) * cnt); for (unsigned int i = 0; i < elCountIn; ++i) { UInt32 numChans; if (NumberChannels (kAudioUnitScope_Input, i, numChans)) return -1; (*chaninfo)[i].inChannels = numChans; } for (unsigned int i = elCountIn; i < cnt; ++i) { (*chaninfo)[i].inChannels = 0; } for (unsigned int i = 0; i < elCountOut; ++i) { UInt32 numChans; if (NumberChannels (kAudioUnitScope_Output, i, numChans)) return -1; (*chaninfo)[i].outChannels = numChans; } for (unsigned int i = elCountOut; i < cnt; ++i) { (*chaninfo)[i].outChannels = 0; } return 0; } else { // the au should either really tell us about this // or we will assume the worst return -1; } } *chaninfo = (AUChannelInfo*) malloc (dataSize); cnt = dataSize / sizeof (AUChannelInfo); result = GetProperty (kAudioUnitProperty_SupportedNumChannels, kAudioUnitScope_Global, 0, *chaninfo, &dataSize); if (result) { return -1; } return 0; }