/*============================================================================= CAAudioBufferList.cp $Log: CAAudioBufferList.cpp,v $ Revision 1.1 2004/08/23 06:22:34 jcm10 first checked in Revision 1.8 2004/07/03 01:17:06 jcm10 add HasData() Revision 1.7 2004/05/15 00:15:46 jcm10 add sEmptyBufferList Revision 1.6 2004/02/12 01:50:44 jcm10 fixed GetBufferForChannel() Revision 1.5 2004/02/11 23:39:33 jcm10 improve the Copy() method to support varying forms of ABL's Revision 1.4 2003/03/12 01:58:48 jcm10 add CalculateByteSize() Revision 1.3 2002/10/04 00:36:27 dwyatt fix compile error: need string.h Revision 1.2 2002/09/27 22:16:21 jcm10 add Clear() and Sum() Revision 1.1 2002/03/01 01:52:40 jcm10 moved here from ../Utility Revision 1.4 2002/02/28 23:24:29 jcm10 added the CA prefix to DebugMacros and LogMacros for more consistency Revision 1.3 2001/11/15 02:20:25 jcm10 call standard C library fucntions without the namespace to make cpp-precomp happy Revision 1.2 2001/04/19 18:57:32 jcm10 initialize the mNumberBuffers field in Create() Revision 1.1 2001/04/05 01:36:12 jcm10 first checked in Revision 0.0 2001/04/04 16:55:43 jcm10 created $NoKeywords: $ =============================================================================*/ //============================================================================= // Includes //============================================================================= #include "CAAudioBufferList.h" #include "CADebugMacros.h" #include "CALogMacros.h" #include #include //============================================================================= // CAAudioBufferList //============================================================================= AudioBufferList* CAAudioBufferList::Create(UInt32 inNumberBuffers) { UInt32 theSize = CalculateByteSize(inNumberBuffers); AudioBufferList* theAnswer = static_cast(calloc(1, theSize)); if(theAnswer != NULL) { theAnswer->mNumberBuffers = inNumberBuffers; } return theAnswer; } void CAAudioBufferList::Destroy(AudioBufferList* inBufferList) { free(inBufferList); } UInt32 CAAudioBufferList::CalculateByteSize(UInt32 inNumberBuffers) { UInt32 theSize = sizeof(AudioBufferList) - sizeof(AudioBuffer); theSize += inNumberBuffers * sizeof(AudioBuffer); return theSize; } UInt32 CAAudioBufferList::GetTotalNumberChannels(const AudioBufferList& inBufferList) { UInt32 theAnswer = 0; for(UInt32 theIndex = 0; theIndex < inBufferList.mNumberBuffers; ++theIndex) { theAnswer += inBufferList.mBuffers[theIndex].mNumberChannels; } return theAnswer; } bool CAAudioBufferList::GetBufferForChannel(const AudioBufferList& inBufferList, UInt32 inChannel, UInt32& outBufferNumber, UInt32& outBufferChannel) { bool theAnswer = false; UInt32 theIndex = 0; while((theIndex < inBufferList.mNumberBuffers) && (inChannel >= inBufferList.mBuffers[theIndex].mNumberChannels)) { inChannel -= inBufferList.mBuffers[theIndex].mNumberChannels; ++theIndex; } if(theIndex < inBufferList.mNumberBuffers) { outBufferNumber = theIndex; outBufferChannel = inChannel; theAnswer = true; } return theAnswer; } void CAAudioBufferList::Clear(AudioBufferList& outBufferList) { // assumes that "0" is actually the 0 value for this stream format for(UInt32 theBufferIndex = 0; theBufferIndex < outBufferList.mNumberBuffers; ++theBufferIndex) { if(outBufferList.mBuffers[theBufferIndex].mData != NULL) { memset(outBufferList.mBuffers[theBufferIndex].mData, 0, outBufferList.mBuffers[theBufferIndex].mDataByteSize); } } } void CAAudioBufferList::Copy(const AudioBufferList& inSource, UInt32 inStartingSourceChannel, AudioBufferList& outDestination, UInt32 inStartingDestinationChannel) { // This is a brute force copy method that can handle ABL's that have different buffer layouts // This means that this method is probably not the fastest way to do this for all cases. // This method also assumes that both the source and destination sample formats are Float32 UInt32 theInputChannel = inStartingSourceChannel; UInt32 theNumberInputChannels = GetTotalNumberChannels(inSource); UInt32 theOutputChannel = inStartingDestinationChannel; UInt32 theNumberOutputChannels = GetTotalNumberChannels(outDestination); while((theInputChannel < theNumberInputChannels) && (theOutputChannel < theNumberOutputChannels)) { UInt32 theInputBufferIndex; UInt32 theInputBufferChannel; GetBufferForChannel(inSource, theInputChannel, theInputBufferIndex, theInputBufferChannel); UInt32 theOutputBufferIndex; UInt32 theOutputBufferChannel; GetBufferForChannel(inSource, theOutputChannel, theOutputBufferIndex, theOutputBufferChannel); CopyChannel(inSource.mBuffers[theInputBufferIndex], theInputBufferChannel, outDestination.mBuffers[theOutputBufferIndex], theOutputBufferChannel); ++theInputChannel; ++theOutputChannel; } } void CAAudioBufferList::CopyChannel(const AudioBuffer& inSource, UInt32 inSourceChannel, AudioBuffer& outDestination, UInt32 inDestinationChannel) { // set up the stuff for the loop UInt32 theNumberFramesToCopy = outDestination.mDataByteSize / (outDestination.mNumberChannels * sizeof(Float32)); const Float32* theSource = static_cast(inSource.mData); Float32* theDestination = static_cast(outDestination.mData); // loop through the data and copy the samples while(theNumberFramesToCopy > 0) { // copy the data theDestination[inDestinationChannel] = theSource[inSourceChannel]; // adjust the pointers --theNumberFramesToCopy; theSource += inSource.mNumberChannels; theDestination += outDestination.mNumberChannels; } } void CAAudioBufferList::Sum(const AudioBufferList& inSourceBufferList, AudioBufferList& ioSummedBufferList) { // assumes that the buffers are Float32 samples and the listst have the same layout // this is a lame algorithm, by the way. it could at least be unrolled a couple of times for(UInt32 theBufferIndex = 0; theBufferIndex < ioSummedBufferList.mNumberBuffers; ++theBufferIndex) { Float32* theSourceBuffer = static_cast(inSourceBufferList.mBuffers[theBufferIndex].mData); Float32* theSummedBuffer = static_cast(ioSummedBufferList.mBuffers[theBufferIndex].mData); UInt32 theNumberSamplesToMix = ioSummedBufferList.mBuffers[theBufferIndex].mDataByteSize / sizeof(Float32); if((theSourceBuffer != NULL) && (theSummedBuffer != NULL) && (theNumberSamplesToMix > 0)) { while(theNumberSamplesToMix > 0) { *theSummedBuffer += *theSourceBuffer; ++theSummedBuffer; ++theSourceBuffer; --theNumberSamplesToMix; } } } } bool CAAudioBufferList::HasData(AudioBufferList& inBufferList) { bool hasData = false; for(UInt32 theBufferIndex = 0; !hasData && (theBufferIndex < inBufferList.mNumberBuffers); ++theBufferIndex) { if(inBufferList.mBuffers[theBufferIndex].mData != NULL) { UInt32* theBuffer = (UInt32*)inBufferList.mBuffers[theBufferIndex].mData; UInt32 theNumberSamples = inBufferList.mBuffers[theBufferIndex].mDataByteSize / sizeof(UInt32); for(UInt32 theSampleIndex = 0; !hasData && (theSampleIndex < theNumberSamples); ++theSampleIndex) { hasData = theBuffer[theSampleIndex] != 0; } } } return hasData; } #if CoreAudio_Debug void CAAudioBufferList::PrintToLog(const AudioBufferList& inBufferList) { PrintInt(" Number streams: ", inBufferList.mNumberBuffers); for(UInt32 theIndex = 0; theIndex < inBufferList.mNumberBuffers; ++theIndex) { PrintIndexedInt(" Channels in stream", theIndex + 1, inBufferList.mBuffers[theIndex].mNumberChannels); PrintIndexedInt(" Buffer size of stream", theIndex + 1, inBufferList.mBuffers[theIndex].mDataByteSize); } } #endif AudioBufferList CAAudioBufferList::sEmptyBufferList = { 0, { 0, 0, NULL } };