/*=============================================================================
	CAAudioChannelLayout.cpp

	$Log: CAAudioChannelLayout.cpp,v $
	Revision 1.10  2005/01/06 01:51:32  dwyatt
	gcc4 / newline at EOF
	
	Revision 1.9  2003/07/09 19:06:53  dwyatt
	cleanup - don't fill out channel descriptions based on layout tags
	
	Revision 1.8  2003/07/07 23:34:20  bills
	public default constructor
	
	Revision 1.7  2003/07/07 21:50:38  dwyatt
	more refactoring
	
	Revision 1.6  2003/07/07 19:38:08  dwyatt
	fix bug in show
	
	Revision 1.5  2003/07/07 18:36:45  bills
	Add Save/Restore
	
	Revision 1.4  2003/06/21 02:25:30  bills
	NumberChannels test is now complete
	
	Revision 1.3  2003/06/02 19:25:15  bills
	tweaks
	
	Revision 1.2  2003/05/25 02:44:25  bills
	fix bug in SetUnknown and add operator==
	
	Revision 1.1  2003/05/04 00:00:16  jcm10
	first checked in
	
	Revision 0.0  Sat May 03 2003 10:08:57 US/Pacific  moorf
	Created
		
	$NoKeywords: $
=============================================================================*/

//=============================================================================
//	Includes
//=============================================================================

//	Self Include
#include "CAAudioChannelLayout.h"
#include <stdlib.h>
#include <string.h>

//=============================================================================
//	CAAudioChannelLayout
//=============================================================================

AudioChannelLayout*	CAAudioChannelLayout::Create(UInt32 inNumberChannelDescriptions)
{
	UInt32 theSize = CalculateByteSize(inNumberChannelDescriptions);
	AudioChannelLayout* theAnswer = static_cast<AudioChannelLayout*>(calloc(1, theSize));
	if(theAnswer != NULL)
	{
		SetAllToUnknown(*theAnswer, inNumberChannelDescriptions);
	}
	return theAnswer;
}

void	CAAudioChannelLayout::Destroy(AudioChannelLayout* inChannelLayout)
{
	free(inChannelLayout);
}

void	CAAudioChannelLayout::SetAllToUnknown(AudioChannelLayout& outChannelLayout, UInt32 inNumberChannelDescriptions)
{
	outChannelLayout.mChannelLayoutTag = kAudioChannelLayoutTag_UseChannelDescriptions;
	outChannelLayout.mChannelBitmap = 0;
	outChannelLayout.mNumberChannelDescriptions = inNumberChannelDescriptions;
	for(UInt32 theChannelIndex = 0; theChannelIndex < inNumberChannelDescriptions; ++theChannelIndex)
	{
		outChannelLayout.mChannelDescriptions[theChannelIndex].mChannelLabel = kAudioChannelLabel_Unknown;
		outChannelLayout.mChannelDescriptions[theChannelIndex].mChannelFlags = 0;
		outChannelLayout.mChannelDescriptions[theChannelIndex].mCoordinates[0] = 0;
		outChannelLayout.mChannelDescriptions[theChannelIndex].mCoordinates[1] = 0;
		outChannelLayout.mChannelDescriptions[theChannelIndex].mCoordinates[2] = 0;
	}
}

bool	operator== (const AudioChannelLayout &x, const AudioChannelLayout &y)
{
	// compare based on the number of channel descriptions present
	// (this may be too strict a comparison if all you care about are matching layout tags)
	UInt32 theSize1 = CAAudioChannelLayout::CalculateByteSize(x.mNumberChannelDescriptions);
	UInt32 theSize2 = CAAudioChannelLayout::CalculateByteSize(y.mNumberChannelDescriptions);
	
	if (theSize1 != theSize2)
		return false;
		
	return !memcmp (&x, &y, theSize1);
}

// counting the one bits in a word
inline UInt32 CountOnes(UInt32 x)
{
	// secret magic algorithm for counting bits in a word.
	UInt32 t;
	x = x - ((x >> 1) & 0x55555555);
	t = ((x >> 2) & 0x33333333);
	x = (x & 0x33333333) + t;
	x = (x + (x >> 4)) & 0x0F0F0F0F;
	x = x + (x << 8);
	x = x + (x << 16);
	return x >> 24;
}

UInt32	CAAudioChannelLayout::NumberChannels (const AudioChannelLayout& inLayout)
{
	if (inLayout.mChannelLayoutTag == kAudioChannelLayoutTag_UseChannelDescriptions)
		return inLayout.mNumberChannelDescriptions;
	
	if (inLayout.mChannelLayoutTag == kAudioChannelLayoutTag_UseChannelBitmap)
		return CountOnes (inLayout.mChannelBitmap);

	return AudioChannelLayoutTag_GetNumberOfChannels(inLayout.mChannelLayoutTag);
}

void 	CAShowAudioChannelLayout (FILE* file, const AudioChannelLayout *layout)
{
	fprintf (file, "\tTag=0x%lX, ", layout->mChannelLayoutTag);
	if (layout->mChannelLayoutTag == kAudioChannelLayoutTag_UseChannelBitmap)
		fprintf (file, "Using Bitmap:0x%lX\n", layout->mChannelBitmap);
	else {
		fprintf (file, "Num Chan Descs=%ld\n", layout->mNumberChannelDescriptions);
		const AudioChannelDescription *desc = layout->mChannelDescriptions;
		for (unsigned int i = 0; i < layout->mNumberChannelDescriptions; ++i, ++desc) {
			fprintf (file, "\t\tLabel=%ld, Flags=0x%lX, ", desc->mChannelLabel, desc->mChannelFlags);
			fprintf (file, "[az=%f,el=%f,dist=%f]\n", desc->mCoordinates[0], desc->mCoordinates[1], desc->mCoordinates[2]);
		}
	}
}
