/*=============================================================================
    CAAudioChannelLayoutObject.cpp
 
	$Log: CAAudioChannelLayoutObject.cpp,v $
	Revision 1.15  2003/12/02 00:15:46  bills
	some fixes for ref counting thread-safe-ness
	
	Revision 1.14  2003/11/20 22:56:53  dwyatt
	__COREAUDIO_USE_FLAT_INCLUDES__
	
	Revision 1.13  2003/08/05 07:16:12  bills
	fix operator= (its num channel descs, not num channels!)
	
	Revision 1.12  2003/08/02 00:28:17  dwyatt
	remove AULayoutForTag
	
	Revision 1.11  2003/07/09 19:06:53  dwyatt
	cleanup - don't fill out channel descriptions based on layout tags
	
	Revision 1.10  2003/07/08 21:44:11  dwyatt
	inline some tiny methods for efficiency
	
	Revision 1.9  2003/07/08 06:27:22  bills
	fix layouts for numchannels, add "workaround" for AUValidator so it can run on Jag...
	
	Revision 1.8  2003/07/08 00:04:40  bills
	tweak print
	
	Revision 1.7  2003/07/07 23:34:20  bills
	public default constructor
	
	Revision 1.6  2003/07/07 21:50:38  dwyatt
	more refactoring
	
	Revision 1.5  2003/07/07 19:38:20  dwyatt
	use CAReferenceCounted
	
	Revision 1.4  2003/07/07 18:36:45  bills
	Add Save/Restore
	
	Revision 1.3  2003/06/02 19:25:15  bills
	tweaks
	
	Revision 1.2  2003/05/25 21:55:43  bills
	add Print method
	
	Revision 1.1  2003/05/25 02:44:50  bills
	CAAudioChannelLayout object
	

    Copyright (c) 2003 Apple Computer Inc.. All rights reserved.
=============================================================================*/

#include "CAAudioChannelLayout.h"
#if !defined(__COREAUDIO_USE_FLAT_INCLUDES__)
	#include <CoreServices/CoreServices.h>
	#include <AudioToolbox/AudioFormat.h>
#else
	#include <CoreServices.h>
	#include <AudioFormat.h>
#endif


CAAudioChannelLayout::CAAudioChannelLayout ()
{
	mLayoutHolder = new ACLRefCounter (offsetof(AudioChannelLayout, mChannelDescriptions));
}

//=============================================================================
//	CAAudioChannelLayout::CAAudioChannelLayout
//=============================================================================
CAAudioChannelLayout::CAAudioChannelLayout (UInt32 inNumberChannels, bool inChooseSurround)
{		
		// this chooses default layouts based on the number of channels...
	UInt32 theSize = CalculateByteSize (inNumberChannels);
		
	mLayoutHolder = new ACLRefCounter (theSize);
	
	AudioChannelLayout* layout = mLayoutHolder->GetLayout();

	layout->mNumberChannelDescriptions = inNumberChannels;
	
	switch (inNumberChannels) 
	{
		case 1:
			layout->mChannelLayoutTag = kAudioChannelLayoutTag_Mono;
			break;
		case 2:
			layout->mChannelLayoutTag = inChooseSurround ? kAudioChannelLayoutTag_Binaural : kAudioChannelLayoutTag_Stereo;
			break;
		case 4:
			layout->mChannelLayoutTag = inChooseSurround ? kAudioChannelLayoutTag_Ambisonic_B_Format : kAudioChannelLayoutTag_AudioUnit_4;
			break;
		case 5:
			layout->mChannelLayoutTag = inChooseSurround ? kAudioChannelLayoutTag_AudioUnit_5_0 : kAudioChannelLayoutTag_AudioUnit_5;
			break;
		case 6:
			layout->mChannelLayoutTag = inChooseSurround ? kAudioChannelLayoutTag_AudioUnit_6_0 : kAudioChannelLayoutTag_AudioUnit_6;
			break;
		case 7:
			layout->mChannelLayoutTag = kAudioChannelLayoutTag_AudioUnit_7_0;
			break;
		case 8:
			layout->mChannelLayoutTag = kAudioChannelLayoutTag_AudioUnit_8;
			break;
		default:
			// here we have a "broken" layout, in the sense that we haven't any idea how to lay this out
			// the layout itself is all set to zeros
			// ### no longer true ###
			SetAllToUnknown(*layout, inNumberChannels);
			break;
	}
}

//=============================================================================
//	CAAudioChannelLayout::CAAudioChannelLayout
//=============================================================================
CAAudioChannelLayout::CAAudioChannelLayout (AudioChannelLayoutTag inLayoutTag)
	: mLayoutHolder(NULL)
{
	SetWithTag(inLayoutTag);
}

//=============================================================================
//	CAAudioChannelLayout::CAAudioChannelLayout
//=============================================================================
CAAudioChannelLayout::CAAudioChannelLayout (const CAAudioChannelLayout &c)
	: mLayoutHolder(NULL)
{
	*this = c;
}


//=============================================================================
//	CAAudioChannelLayout::AudioChannelLayout
//=============================================================================
CAAudioChannelLayout::CAAudioChannelLayout (const AudioChannelLayout* inChannelLayout)
	: mLayoutHolder(NULL)
{
	*this = inChannelLayout;
}

//=============================================================================
//	CAAudioChannelLayout::~CAAudioChannelLayout
//=============================================================================
CAAudioChannelLayout::~CAAudioChannelLayout ()
{
	if (mLayoutHolder) {
		mLayoutHolder->release();
		mLayoutHolder = NULL;
	}
}

//=============================================================================
//	CAAudioChannelLayout::CAAudioChannelLayout
//=============================================================================
CAAudioChannelLayout& CAAudioChannelLayout::operator= (const CAAudioChannelLayout &c)
{
	if (mLayoutHolder != c.mLayoutHolder) {
		if (mLayoutHolder)
			mLayoutHolder->release();
	
		if ((mLayoutHolder = c.mLayoutHolder) != NULL)
			mLayoutHolder->retain();
	}
	
	return *this;
}

CAAudioChannelLayout&	CAAudioChannelLayout::operator= (const AudioChannelLayout* inChannelLayout)
{
	if (mLayoutHolder)
		mLayoutHolder->release();

	UInt32 theSize = CalculateByteSize (inChannelLayout->mNumberChannelDescriptions);
	
	mLayoutHolder = new ACLRefCounter (theSize);
	
	memcpy(mLayoutHolder->mLayout, inChannelLayout, theSize);
	return *this;
}

void	CAAudioChannelLayout::SetWithTag(AudioChannelLayoutTag inTag)
{
	if (mLayoutHolder)
		mLayoutHolder->release();
	
	mLayoutHolder = new ACLRefCounter(offsetof(AudioChannelLayout, mChannelDescriptions[0]));
	AudioChannelLayout* layout = mLayoutHolder->GetLayout();
	layout->mChannelLayoutTag = inTag;
}

//=============================================================================
//	CAAudioChannelLayout::operator==
//=============================================================================
bool		CAAudioChannelLayout::operator== (const CAAudioChannelLayout &c) const
{
	if (mLayoutHolder == c.mLayoutHolder)
		return true;
	return Layout() == c.Layout();
}

//=============================================================================
//	CAAudioChannelLayout::Print
//=============================================================================
void		CAAudioChannelLayout::Print (FILE* file) const
{
	CAShowAudioChannelLayout (file, &Layout());
}

