/*=============================================================================
	CAStreamBasicDescription.h
	
	$Log: CAStreamBasicDescription.h,v $
	Revision 1.21  2005/02/25 01:53:29  dwyatt
	[4006370] ChangeNumberChannels now checks for a sample word size of 0, in which case it computes it from the bit depth instead of making a stupid unusable stream description full of zeros
	
	Revision 1.20  2004/11/12 20:37:56  jcm10
	improve the IsMixable() test
	
	Revision 1.19  2004/08/19 19:08:24  jcm10
	make it build and work on a stock Panther system
	
	Revision 1.18  2004/06/25 01:14:20  jcm10
	fix up NormalizeLinearPCMFormat to support the IsNonMixable flag
	
	Revision 1.17  2003/12/16 02:01:56  dwyatt
	Windows compile
	
	Revision 1.16  2003/11/21 23:11:26  dwyatt
	fix flat header include
	
	Revision 1.15  2003/11/20 22:56:53  dwyatt
	__COREAUDIO_USE_FLAT_INCLUDES__
	
	Revision 1.14  2003/04/25 18:40:33  asynth
	add ASBD SanityCheck
	
	Revision 1.13  2003/04/25 02:29:37  ealdrich
	Work around for Windows issue.
	
	Revision 1.12  2003/04/24 21:49:03  jcm10
	move CAShowStreamDescription to CAShow.cpp
	
	Revision 1.11  2003/04/23 22:33:13  dwyatt
	more fallout of class merge
	
	Revision 1.10  2003/04/23 22:09:04  dwyatt
	CAAudioStreamBasicDescription merged into CAStreamBasicDescription
	
	Revision 1.9  2003/03/11 20:57:29  bills
	first pass at save/restore state
	
	Revision 1.8  2003/03/11 02:07:18  bills
	default const should clear the values (ie. memset(0))
	
	Revision 1.7  2003/03/11 02:03:40  bills
	remove inaccurate equality operators - use CAASBD ones..
	
	Revision 1.6  2003/03/11 00:30:53  bills
	add .cpp implementation of print calls
	
	Revision 1.5  2002/06/29 09:15:24  baron
	Tweak SampleWordSize() and BytesToFrames().
	
	Revision 1.4  2002/06/18 02:55:34  dwyatt
	fix IsInterleaved() for non-PC*M
	
	Revision 1.3  2002/06/07 19:31:12  bills
	remove include of AT/AT.h
	
	Revision 1.2  2002/06/06 01:52:31  dwyatt
	moved from Utility
	
	Revision 1.1  2002/05/09 19:14:39  dwyatt
	initial checkin
	
	created Tue May 07 2002, Doug Wyatt
	Copyright (c) 2002 Apple Computer, Inc.  All Rights Reserved

	$NoKeywords: $
=============================================================================*/

#ifndef __CAStreamBasicDescription_h__
#define __CAStreamBasicDescription_h__

#if !defined(__COREAUDIO_USE_FLAT_INCLUDES__)
	#include <CoreAudio/CoreAudioTypes.h>
	#include <CoreFoundation/CoreFoundation.h>
#else
	#include "CoreAudioTypes.h"
	#include "CoreFoundation.h"
#endif

#include "CADebugMacros.h"
#include <string.h>	// for memset, memcpy
#include <stdio.h>	// for FILE *

//  temporarily define a place holder for kAudioFormatFlagIsNonMixable since the constant
//  isn't on all Panther systems
#pragma mark	this needs to be removed eventually
enum { kIsNonMixableFlag = (1L << 6) };

//=============================================================================
//	CAStreamBasicDescription
//
//	This is a wrapper class for the AudioStreamBasicDescription struct.
//	It adds a number of convenience routines, but otherwise adds nothing
//	to the footprint of the original struct.
//=============================================================================
class CAStreamBasicDescription : 
	public AudioStreamBasicDescription
{

//	Constants
public:
	static const AudioStreamBasicDescription	sEmpty;

//	Construction/Destruction
public:
	CAStreamBasicDescription() { memset (this, 0, sizeof(AudioStreamBasicDescription)); }
	
	CAStreamBasicDescription(const AudioStreamBasicDescription &desc)
	{
		SetFrom(desc);
	}
	
	CAStreamBasicDescription(		double inSampleRate,		UInt32 inFormatID,
									UInt32 inBytesPerPacket,	UInt32 inFramesPerPacket,
									UInt32 inBytesPerFrame,		UInt32 inChannelsPerFrame,
									UInt32 inBitsPerChannel,	UInt32 inFormatFlags);

//	Assignment
	CAStreamBasicDescription&	operator=(const AudioStreamBasicDescription& v) { SetFrom(v); return *this; }

	void	SetFrom(const AudioStreamBasicDescription &desc)
	{
		memcpy(this, &desc, sizeof(AudioStreamBasicDescription));
	}
	
	// _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
	//
	// interrogation
	
	bool	IsPCM() const { return mFormatID == kAudioFormatLinearPCM; }
	
	bool	PackednessIsSignificant() const
	{
		Assert(IsPCM(), "PackednessIsSignificant only applies for PCM");
		return (SampleWordSize() << 3) != mBitsPerChannel;
	}
	
	bool	AlignmentIsSignificant() const
	{
		return PackednessIsSignificant() || (mBitsPerChannel & 7) != 0;
	}
	
	bool	IsInterleaved() const
	{
		return !IsPCM() || !(mFormatFlags & kAudioFormatFlagIsNonInterleaved);
	}
	
	// for sanity with interleaved/deinterleaved possibilities, never access mChannelsPerFrame, use these:
	UInt32	NumberInterleavedChannels() const	{ return IsInterleaved() ? mChannelsPerFrame : 1; }	
	UInt32	NumberChannelStreams() const		{ return IsInterleaved() ? 1 : mChannelsPerFrame; }
	UInt32	NumberChannels() const				{ return mChannelsPerFrame; }
	UInt32	SampleWordSize() const				{ return (mBytesPerFrame > 0) ? mBytesPerFrame / NumberInterleavedChannels() :  0;}

	UInt32	FramesToBytes(UInt32 nframes) const	{ return nframes * mBytesPerFrame; }
	UInt32	BytesToFrames(UInt32 nbytes) const	{
		Assert(mBytesPerFrame > 0, "bytesPerFrame must be > 0 in BytesToFrames");
		return nbytes / mBytesPerFrame;
	}
	
	bool	SameChannelsAndInterleaving(const CAStreamBasicDescription &a) const
	{
		return this->NumberChannels() == a.NumberChannels() && this->IsInterleaved() == a.IsInterleaved();
	}
	
	// _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
	//
	//	manipulation
	
	void	SetCanonical(UInt32 nChannels, bool interleaved)
				// note: leaves sample rate untouched
	{
		mFormatID = kAudioFormatLinearPCM;
		mFormatFlags = kAudioFormatFlagsNativeFloatPacked;
		mBitsPerChannel = 32;
		mChannelsPerFrame = nChannels;
		mFramesPerPacket = 1;
		if (interleaved)
			mBytesPerPacket = mBytesPerFrame = nChannels * sizeof(Float32);
		else {
			mBytesPerPacket = mBytesPerFrame = sizeof(Float32);
			mFormatFlags |= kAudioFormatFlagIsNonInterleaved;
		}
	}
	
	void	ChangeNumberChannels(UInt32 nChannels, bool interleaved)
				// alter an existing format
	{
		Assert(IsPCM(), "ChangeNumberChannels only works for PCM formats");
		UInt32 wordSize = SampleWordSize();	// get this before changing ANYTHING
		if (wordSize == 0)
			wordSize = (mBitsPerChannel + 7) / 8;
		mChannelsPerFrame = nChannels;
		mFramesPerPacket = 1;
		if (interleaved) {
			mBytesPerPacket = mBytesPerFrame = nChannels * wordSize;
			mFormatFlags &= ~kAudioFormatFlagIsNonInterleaved;
		} else {
			mBytesPerPacket = mBytesPerFrame = wordSize;
			mFormatFlags |= kAudioFormatFlagIsNonInterleaved;
		}
	}
	
	// _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
	//
	//	other
	
	void	Print() const
	{
		Print (stdout);
	}

	void	Print(FILE* file) const
	{
		PrintFormat (file, "", "AudioStreamBasicDescription:");	
	}

	void PrintFormat(FILE *f, const char *indent, const char *name) const;

	OSStatus			Save(CFPropertyListRef *outData) const;
		
	OSStatus			Restore(CFPropertyListRef &inData);

//	Operations
	static bool			IsMixable(const AudioStreamBasicDescription& inDescription) { return (inDescription.mFormatID == kAudioFormatLinearPCM) && ((inDescription.mFormatFlags & kIsNonMixableFlag) == 0); }
	static void			NormalizeLinearPCMFormat(AudioStreamBasicDescription& ioDescription);
	static void			ResetFormat(AudioStreamBasicDescription& ioDescription);
	static void			FillOutFormat(AudioStreamBasicDescription& ioDescription, const AudioStreamBasicDescription& inTemplateDescription);
	static void			GetSimpleName(const AudioStreamBasicDescription& inDescription, char* outName, bool inAbbreviate);
#if CoreAudio_Debug
	static void			PrintToLog(const AudioStreamBasicDescription& inDesc);
#endif
};

bool		operator<(const AudioStreamBasicDescription& x, const AudioStreamBasicDescription& y);
bool		operator==(const AudioStreamBasicDescription& x, const AudioStreamBasicDescription& y);
#if TARGET_OS_MAC || (TARGET_OS_WIN32 && (_MSC_VER > 600))
inline bool	operator!=(const AudioStreamBasicDescription& x, const AudioStreamBasicDescription& y) { return !(x == y); }
inline bool	operator<=(const AudioStreamBasicDescription& x, const AudioStreamBasicDescription& y) { return (x < y) || (x == y); }
inline bool	operator>=(const AudioStreamBasicDescription& x, const AudioStreamBasicDescription& y) { return !(x < y); }
inline bool	operator>(const AudioStreamBasicDescription& x, const AudioStreamBasicDescription& y) { return !((x < y) || (x == y)); }
#endif

bool SanityCheck(const AudioStreamBasicDescription& x);


#endif // __CAStreamBasicDescription_h__
