/*=============================================================================
	CAAudioStreamBasicDesc.cp

	$Log: CAAudioStreamBasicDesc.cpp,v $
	Revision 1.16  2003/04/23 22:33:13  dwyatt
	more fallout of class merge
	
	Revision 1.15  2003/04/23 22:09:04  dwyatt
	CAAudioStreamBasicDescription merged into CAStreamBasicDescription
	
	Revision 1.14  2003/04/22 23:06:20  asynth
	shorter, faster, easier to read operator ==
	
	Revision 1.13  2003/04/12 01:37:21  jcm10
	add sEmpty
	
	Revision 1.12  2003/03/02 00:55:13  jcm10
	0 is wild card for format flags
	
	Revision 1.11  2003/02/22 00:57:20  jcm10
	fix the wild card format flags test
	
	Revision 1.10  2003/02/21 22:16:37  jcm10
	don't use kAudioFormatFlagNotValid directly so that this is still buildable on Jaguar
	
	Revision 1.9  2003/02/21 01:59:15  jcm10
	add FillOutFormat
	
	Revision 1.8  2003/02/10 21:00:52  jcm10
	still more tweaks to GetSimpleName
	
	Revision 1.7  2003/02/07 22:39:27  jcm10
	more GetSimpleName adjustments
	
	Revision 1.6  2003/01/30 22:30:59  jcm10
	add a flag to return abbreviated strings to GetSimpleName()
	
	Revision 1.5  2003/01/27 23:02:59  jcm10
	forgot some includes
	
	Revision 1.4  2003/01/27 20:07:04  jcm10
	add GetSimpleName()
	
	Revision 1.3  2002/06/01 02:15:26  ealdrich
	renamed so MS DevStudio will compile the file
	
	Revision 1.3  2002/04/26 19:47:15  jcm10
	change it back
	
	Revision 1.1  2002/04/26 19:43:33  jcm10
	renamed from CAAudioStreamBasicDesc.cp to CAAudioStreamBasicDesc.cpp
	
	Revision 1.1  2002/03/01 01:52:40  jcm10
	moved here from ../Utility
	
	Revision 1.15  2002/02/28 23:24:29  jcm10
	added the CA prefix to DebugMacros and LogMacros for more consistency
	
	Revision 1.14  2002/01/17 01:36:04  jcm10
	use kAudioFormatFlagsNativeEndian instead of a conditional
	
	Revision 1.13  2001/11/15 02:20:25  jcm10
	call standard C library fucntions without the namespace to
	make cpp-precomp happy
	
	Revision 1.12  2001/10/11 21:24:16  jcm10
	finish the first round of AC-3 support
	
	Revision 1.11  2001/10/08 19:43:45  jcm10
	add AC-3 public API and documentation changes
	
	Revision 1.10  2001/07/25 21:43:04  jcm10
	Add ResetFormat()
	
	Revision 1.9  2001/04/06 02:58:00  jcm10
	add NormalizeLinearPCMFormat
	
	Revision 1.8  2001/04/05 01:36:43  jcm10
	clean things up
	
	Revision 1.7  2001/03/27 00:51:47  jcm10
	make the release styles build again
	
	Revision 1.6  2001/03/27 00:42:20  jcm10
	add PrintToLog methods and reverse the logic of the sorting operators
	
	Revision 1.5  2001/03/20 22:12:36  jcm10
	remove extraneous Assert
	
	Revision 1.4  2001/01/05 03:13:06  jcm10
	remove the warnings
	
	Revision 1.3  2001/01/05 03:09:08  jcm10
	implement operator<
	
	Revision 1.2  2001/01/04 22:38:58  jcm10
	no longer needed
	
	Revision 1.1  2001/01/04 21:59:15  jcm10
	rename CAAudioStreamBasicDescription to CAAudioStreamBasicDesc
	
	Revision 1.1  2001/01/04 20:17:04  jcm10
	first checked in
	
	Revision 0.0  2000/12/20 12:38:51  jcm10
	created
		
	$NoKeywords: $
=============================================================================*/

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

#error "CAAudioStreamBasicDesc is now OBSOLETE -- replace with CAStreamBasicDescription"

#if 0	// THIS FILE IS NOW OBSOLETE -- REPLACE WITH CAStreamBasicDescription
#include "CADebugMacros.h"
#include "CALogMacros.h"

#include <stdio.h>
#include <string.h>

//=============================================================================
//	CAAudioStreamBasicDescription
//=============================================================================

const AudioStreamBasicDescription	CAAudioStreamBasicDescription::sEmpty = { 0.0, 0, 0, 0, 0, 0, 0, 0, 0 };

CAAudioStreamBasicDescription::CAAudioStreamBasicDescription()
{
	mSampleRate = 0;
	mFormatID = 0;
	mBytesPerPacket = 0;
	mFramesPerPacket = 0;
	mBytesPerFrame = 0;
	mChannelsPerFrame = 0;
	mBitsPerChannel = 0;
	mFormatFlags = 0;
}

CAAudioStreamBasicDescription::CAAudioStreamBasicDescription(const AudioStreamBasicDescription& v)
{
	mSampleRate = v.mSampleRate;
	mFormatID = v.mFormatID;
	mBytesPerPacket = v.mBytesPerPacket;
	mFramesPerPacket = v.mFramesPerPacket;
	mBytesPerFrame = v.mBytesPerFrame;
	mChannelsPerFrame = v.mChannelsPerFrame;
	mBitsPerChannel = v.mBitsPerChannel;
	mFormatFlags = v.mFormatFlags;
}

CAAudioStreamBasicDescription::CAAudioStreamBasicDescription(double inSampleRate, UInt32 inFormatID, UInt32 inBytesPerPacket, UInt32 inFramesPerPacket, UInt32 inBytesPerFrame, UInt32 inChannelsPerFrame, UInt32 inBitsPerChannel, UInt32 inFormatFlags)
{
	mSampleRate = inSampleRate;
	mFormatID = inFormatID;
	mBytesPerPacket = inBytesPerPacket;
	mFramesPerPacket = inFramesPerPacket;
	mBytesPerFrame = inBytesPerFrame;
	mChannelsPerFrame = inChannelsPerFrame;
	mBitsPerChannel = inBitsPerChannel;
	mFormatFlags = inFormatFlags;
}

CAAudioStreamBasicDescription&	CAAudioStreamBasicDescription::operator=(const AudioStreamBasicDescription& v)
{
	mSampleRate = v.mSampleRate;
	mFormatID = v.mFormatID;
	mBytesPerPacket = v.mBytesPerPacket;
	mFramesPerPacket = v.mFramesPerPacket;
	mBytesPerFrame = v.mBytesPerFrame;
	mChannelsPerFrame = v.mChannelsPerFrame;
	mBitsPerChannel = v.mBitsPerChannel;
	mFormatFlags = v.mFormatFlags;
	return *this;
}

void	CAAudioStreamBasicDescription::NormalizeLinearPCMFormat(AudioStreamBasicDescription& ioDescription)
{
	if(ioDescription.mFormatID == kAudioFormatLinearPCM)
	{
		//	we have to doctor the linear PCM format because we always
		//	only export 32 bit, native endian, fully packed floats
		ioDescription.mBitsPerChannel = sizeof(Float32) * 8;
		ioDescription.mBytesPerFrame = sizeof(Float32) * ioDescription.mChannelsPerFrame;
		ioDescription.mFramesPerPacket = 1;
		ioDescription.mBytesPerPacket = ioDescription.mFramesPerPacket * ioDescription.mBytesPerFrame;
		
		ioDescription.mFormatFlags = kAudioFormatFlagIsFloat | kAudioFormatFlagIsPacked;
		ioDescription.mFormatFlags |= kAudioFormatFlagsNativeEndian;
	}
}

void	CAAudioStreamBasicDescription::ResetFormat(AudioStreamBasicDescription& ioDescription)
{
	ioDescription.mSampleRate = 0;
	ioDescription.mFormatID = 0;
	ioDescription.mBytesPerPacket = 0;
	ioDescription.mFramesPerPacket = 0;
	ioDescription.mBytesPerFrame = 0;
	ioDescription.mChannelsPerFrame = 0;
	ioDescription.mBitsPerChannel = 0;
	ioDescription.mFormatFlags = 0;
}

void	CAAudioStreamBasicDescription::FillOutFormat(AudioStreamBasicDescription& ioDescription, const AudioStreamBasicDescription& inTemplateDescription)
{
	if(ioDescription.mSampleRate == 0)
	{
		ioDescription.mSampleRate = inTemplateDescription.mSampleRate;
	}
	if(ioDescription.mFormatID == 0)
	{
		ioDescription.mFormatID = inTemplateDescription.mFormatID;
	}
	if(ioDescription.mFormatFlags == 0)
	{
		ioDescription.mFormatFlags = inTemplateDescription.mFormatFlags;
	}
	if(ioDescription.mBytesPerPacket == 0)
	{
		ioDescription.mBytesPerPacket = inTemplateDescription.mBytesPerPacket;
	}
	if(ioDescription.mFramesPerPacket == 0)
	{
		ioDescription.mFramesPerPacket = inTemplateDescription.mFramesPerPacket;
	}
	if(ioDescription.mBytesPerFrame == 0)
	{
		ioDescription.mBytesPerFrame = inTemplateDescription.mBytesPerFrame;
	}
	if(ioDescription.mChannelsPerFrame == 0)
	{
		ioDescription.mChannelsPerFrame = inTemplateDescription.mChannelsPerFrame;
	}
	if(ioDescription.mBitsPerChannel == 0)
	{
		ioDescription.mBitsPerChannel = inTemplateDescription.mBitsPerChannel;
	}
}

void	CAAudioStreamBasicDescription::GetSimpleName(const AudioStreamBasicDescription& inDescription, char* outName, bool inAbbreviate)
{
	switch(inDescription.mFormatID)
	{
		case kAudioFormatLinearPCM:
			{
				const char* theEndianString = NULL;
				if((inDescription.mFormatFlags & kAudioFormatFlagIsBigEndian) != 0)
				{
					#if	TARGET_RT_LITTLE_ENDIAN
						theEndianString = "Big Endian";
					#endif
				}
				else
				{
					#if	TARGET_RT_BIG_ENDIAN
						theEndianString = "Little Endian";
					#endif
				}
				
				const char* theKindString = NULL;
				if((inDescription.mFormatFlags & kAudioFormatFlagIsFloat) != 0)
				{
					theKindString = (inAbbreviate ? "Float" : "Floating Point");
				}
				else if((inDescription.mFormatFlags & kAudioFormatFlagIsSignedInteger) != 0)
				{
					theKindString = (inAbbreviate ? "SInt" : "Signed Integer");
				}
				else
				{
					theKindString = (inAbbreviate ? "UInt" : "Unsigned Integer");
				}
				
				const char* thePackingString = NULL;
				if((inDescription.mFormatFlags & kAudioFormatFlagIsPacked) == 0)
				{
					if((inDescription.mFormatFlags & kAudioFormatFlagIsAlignedHigh) != 0)
					{
						thePackingString = "High";
					}
					else
					{
						thePackingString = "Low";
					}
				}
				
				if(inAbbreviate)
				{
					if(theEndianString != NULL)
					{
						if(thePackingString != NULL)
						{
							sprintf(outName, "%d Ch %s %s %s%d/%s%d", (int)inDescription.mChannelsPerFrame, theEndianString, thePackingString, theKindString, (int)inDescription.mBitsPerChannel, theKindString, (int)(inDescription.mBytesPerFrame / inDescription.mChannelsPerFrame) * 8);
						}
						else
						{
							sprintf(outName, "%d Ch %s %s%d", (int)inDescription.mChannelsPerFrame, theEndianString, theKindString, (int)inDescription.mBitsPerChannel);
						}
					}
					else
					{
						if(thePackingString != NULL)
						{
							sprintf(outName, "%d Ch %s %s%d/%s%d", (int)inDescription.mChannelsPerFrame, thePackingString, theKindString, (int)inDescription.mBitsPerChannel, theKindString, (int)((inDescription.mBytesPerFrame / inDescription.mChannelsPerFrame) * 8));
						}
						else
						{
							sprintf(outName, "%d Ch %s%d", (int)inDescription.mChannelsPerFrame, theKindString, (int)inDescription.mBitsPerChannel);
						}
					}
				}
				else
				{
					if(theEndianString != NULL)
					{
						if(thePackingString != NULL)
						{
							sprintf(outName, "%d Channel %d Bit %s %s Aligned %s in %d Bits", (int)inDescription.mChannelsPerFrame, (int)inDescription.mBitsPerChannel, theEndianString, theKindString, thePackingString, (int)(inDescription.mBytesPerFrame / inDescription.mChannelsPerFrame) * 8);
						}
						else
						{
							sprintf(outName, "%d Channel %d Bit %s %s", (int)inDescription.mChannelsPerFrame, (int)inDescription.mBitsPerChannel, theEndianString, theKindString);
						}
					}
					else
					{
						sprintf(outName, "%d Channel %d Bit %s", (int)inDescription.mChannelsPerFrame, (int)inDescription.mBitsPerChannel, theKindString);
						if(thePackingString != NULL)
						{
							sprintf(outName, "%d Channel %d Bit %s Aligned %s in %d Bits", (int)inDescription.mChannelsPerFrame, (int)inDescription.mBitsPerChannel, theKindString, thePackingString, (int)(inDescription.mBytesPerFrame / inDescription.mChannelsPerFrame) * 8);
						}
						else
						{
							sprintf(outName, "%d Channel %d Bit %s", (int)inDescription.mChannelsPerFrame, (int)inDescription.mBitsPerChannel, theKindString);
						}
					}
				}
			}
			break;
		
		case kAudioFormatAC3:
			strcpy(outName, "AC-3");
			break;
		
		case kAudioFormat60958AC3:
			strcpy(outName, "AC-3 for SPDIF");
			break;
		
		default:
			{
				char* the4CCString = (char*)&inDescription.mFormatID;
				outName[0] = the4CCString[0];
				outName[1] = the4CCString[1];
				outName[2] = the4CCString[2];
				outName[3] = the4CCString[3];
				outName[4] = 0;
			}
			break;
	};
}

#if CoreAudio_Debug
void	CAAudioStreamBasicDescription::PrintToLog(const AudioStreamBasicDescription& inDesc)
{
	PrintFloat		("  Sample Rate:        ", inDesc.mSampleRate);
	Print4CharCode	("  Format ID:          ", inDesc.mFormatID);
	PrintHex		("  Format Flags:       ", inDesc.mFormatFlags);
	PrintInt		("  Bytes per Packet:   ", inDesc.mBytesPerPacket);
	PrintInt		("  Frames per Packet:  ", inDesc.mFramesPerPacket);
	PrintInt		("  Bytes per Frame:    ", inDesc.mBytesPerFrame);
	PrintInt		("  Channels per Frame: ", inDesc.mChannelsPerFrame);
	PrintInt		("  Bits per Channel:   ", inDesc.mBitsPerChannel);
}
#endif

bool	operator<(const AudioStreamBasicDescription& x, const AudioStreamBasicDescription& y)
{
	bool theAnswer = false;
	bool isDone = false;
	
	//	note that if either side is 0, that field is skipped
	
	//	format ID is the first order sort
	if((!isDone) && ((x.mFormatID != 0) && (y.mFormatID != 0)))
	{
		if(x.mFormatID != y.mFormatID)
		{
			//	formats are sorted numerically except that linear
			//	PCM is always first
			if(x.mFormatID == kAudioFormatLinearPCM)
			{
				theAnswer = true;
			}
			else if(y.mFormatID == kAudioFormatLinearPCM)
			{
				theAnswer = false;
			}
			else
			{
				theAnswer = x.mFormatID < y.mFormatID;
			}
			isDone = true;
		}
	}
	
	//	floating point vs integer for linear PCM only
	if((!isDone) && ((x.mFormatID == kAudioFormatLinearPCM) && (y.mFormatID == kAudioFormatLinearPCM)))
	{
		if((x.mFormatFlags & kAudioFormatFlagIsFloat) != (y.mFormatFlags & kAudioFormatFlagIsFloat))
		{
			//	floating point is better than integer
			theAnswer = y.mFormatFlags & kAudioFormatFlagIsFloat;
			isDone = true;
		}
	}
	
	//	bit depth
	if((!isDone) && ((x.mBitsPerChannel != 0) && (y.mBitsPerChannel != 0)))
	{
		if(x.mBitsPerChannel != y.mBitsPerChannel)
		{
			//	deeper bit depths are higher quality
			theAnswer = x.mBitsPerChannel < y.mBitsPerChannel;
			isDone = true;
		}
	}
	
	//	sample rate
	if((!isDone) && ((x.mSampleRate != 0) && (y.mSampleRate != 0)))
	{
		if(x.mSampleRate != y.mSampleRate)
		{
			//	higher sample rates are higher quality
			theAnswer = x.mSampleRate < y.mSampleRate;
			isDone = true;
		}
	}
	
	//	number of channels
	if((!isDone) && ((x.mChannelsPerFrame != 0) && (y.mChannelsPerFrame != 0)))
	{
		if(x.mChannelsPerFrame != y.mChannelsPerFrame)
		{
			//	more channels is higher quality
			theAnswer = x.mChannelsPerFrame < y.mChannelsPerFrame;
			isDone = true;
		}
	}
	
	return theAnswer;
}


bool	operator==(const AudioStreamBasicDescription& x, const AudioStreamBasicDescription& y)
{
	//	the semantics for equality are:
	//		1) Values must match exactly
	//		2) wildcard's are ignored in the comparison
	
#define MATCH(name) ((x.name) == 0 || (y.name) == 0 || (x.name) == (y.name))
	
	return 
			//	check the sample rate
		MATCH(mSampleRate)
		
			//	check the format ids
		&& MATCH(mFormatID)
		
			//	check the format flags
		&& (x.mFormatID == 0 || y.mFormatID == 0 || MATCH(mFormatFlags)) 
			
			//	check the bytes per packet
		&& MATCH(mBytesPerPacket) 
		
			//	check the frames per packet
		&& MATCH(mFramesPerPacket) 
		
			//	check the bytes per frame
		&& MATCH(mBytesPerFrame) 
		
			//	check the channels per frame
		&& MATCH(mChannelsPerFrame) 
		
			//	check the channels per frame
		&& MATCH(mBitsPerChannel) ;
}
#endif
