/*
	File:		IMAAudioPayload.c

	Contains:	Definition of IMAAudioPayload operations

	Copyright:	© 1997-1999 by Apple Computer, Inc., all rights reserved.
	
*/



#include "IMAAudioPayload.h"
#include <FixMath.h>
#include <Endian.h>



enum	/* fixed header fields */
{
	__kSampleRateWord			= 0,
	__kSampleRateSize			= 4,
	__kSampleRatePosition		= ( sizeof( UInt16 ) << 3 ) - __kSampleRateSize,
	
	__kChannelCountWord			= 0,
	__kChannelCountSize			= 3,
	__kChannelCountPosition		= __kSampleRatePosition - __kChannelCountSize,
	
	__kInterleaveCountWord		= 0,
	__kInterleaveCountSize		= 3,
	__kInterleaveCountPosition	= __kChannelCountPosition - __kInterleaveCountSize,
	
	__kInterleaveIndexWord		= 0,
	__kInterleaveIndexSize		= __kInterleaveCountSize,
	__kInterleaveIndexPosition	= __kInterleaveCountPosition - __kInterleaveIndexSize,
	
	__kInterleaveTailWord		= 0,
	__kInterleaveTailSize		= __kInterleaveCountSize,
	__kInterleaveTailPosition	= __kInterleaveIndexPosition - __kInterleaveTailSize
};



static unsigned long	__gSampleRates[] = {
							8000,
							11025,
							16000,
							22050,
							24000,
							32000,
							44100,
							48000 };



enum
{
	__kSampleRateCount = sizeof( __gSampleRates ) / sizeof( *__gSampleRates )
};



static
UInt32
__SetBitField(
	UInt16 *	inStorageUnit,
	UInt32		inPosition,
	UInt32		inSize,
	UInt32		inValue )
{
	UInt32	theMask = ( ( 1L << inSize ) - 1 ) << inPosition;
	
	
	*inStorageUnit =
		EndianU16_NtoB(
			( EndianU16_BtoN( *inStorageUnit ) & ( ~theMask ) ) |
			( theMask & ( inValue << inPosition ) ) );
	
	return( inValue & ( theMask >> inPosition ) );
}



static
UInt32
__BitField(
	const UInt16 *	inStorageUnit,
	UInt32			inPosition,
	UInt32			inSize )
{
	return( ( EndianU16_BtoN( *inStorageUnit ) >> inPosition ) & ( ( 1L << inSize ) - 1 ) );
}



UInt32
IMAAudioPayloadChannelCountLimit(
	void )
{
	return( 1L << __kChannelCountSize );
}



UInt32
IMAAudioPayloadInterleaveCountLimit(
	void )
{
	return( 1L << __kInterleaveCountSize );
}



IMAAudioPayload *
IMAAudioPayloadInitialize(
	IMAAudioPayload *	inPayload )
{
	UInt32	theCount = sizeof( *inPayload ) / sizeof( *inPayload->itsFixedHeader );
	
	
	while( theCount )
	{
		--theCount;
		inPayload->itsFixedHeader[ theCount ] = 0;
	}
	
	IMAAudioPayloadSetChannelCount( inPayload, 1 );
	IMAAudioPayloadSetSampleRate( inPayload, 0 );
	IMAAudioPayloadSetInterleaving( inPayload, 1, 0 );
	
	return( inPayload );
}



UInt32
IMAAudioPayloadSetChannelCount(
	IMAAudioPayload *	inPayload,
	UInt32				inChannelCount )
{
	UInt32	theResult;
	
	
	theResult =
		__SetBitField(
			&inPayload->itsFixedHeader[ __kChannelCountWord ], __kChannelCountPosition,
			__kChannelCountSize, inChannelCount - 1 ) + 1;
	
	return( theResult );
}



UnsignedFixed
IMAAudioPayloadSetSampleRate(
	IMAAudioPayload *	inPayload,
	UnsignedFixed		inSampleRate )
{
	UnsignedFixed	theResult;
	UInt32			theRateCode = __kSampleRateCount;
	
	
	do
	{
		--theRateCode;
	}
	while( theRateCode  &&  inSampleRate < Long2Fix( __gSampleRates[ theRateCode ] ) );
	
	theRateCode =
		__SetBitField(
			&inPayload->itsFixedHeader[ __kSampleRateWord ], __kSampleRatePosition,
			__kSampleRateSize, theRateCode );
	
	if( theRateCode < __kSampleRateCount )
		theResult = Long2Fix( __gSampleRates[ theRateCode ] );
	else
		theResult = 0;
	
	return( theResult );
}



UInt32
IMAAudioPayloadSetInterleaving(
	IMAAudioPayload *	inPayload,
	UInt32				inInterleaveCount,
	UInt32				inInterleaveGroupFrameCount )
{
	UInt32	theResult;
	
	
	theResult =
		__SetBitField(
			&inPayload->itsFixedHeader[ __kInterleaveCountWord ],
			__kInterleaveCountPosition, __kInterleaveCountSize,
			inInterleaveCount - 1 ) + 1;
	
	__SetBitField(
		&inPayload->itsFixedHeader[ __kInterleaveIndexWord ], __kInterleaveIndexPosition,
		__kInterleaveIndexSize, 0 );
	
	__SetBitField(
		&inPayload->itsFixedHeader[ __kInterleaveTailWord ], __kInterleaveTailPosition,
		__kInterleaveTailSize, ( inInterleaveGroupFrameCount - 1 ) % theResult );
	
	return( theResult );
}



UInt32
IMAAudioPayloadIncrementInterleaveIndex(
	IMAAudioPayload *	inPayload )
{
	UInt32	theResult;
	
	
	theResult =
		__BitField(
			&inPayload->itsFixedHeader[ __kInterleaveIndexWord ],
			__kInterleaveIndexPosition, __kInterleaveIndexSize );
	
	theResult =
		__SetBitField(
			&inPayload->itsFixedHeader[ __kInterleaveIndexWord ],
			__kInterleaveIndexPosition, __kInterleaveIndexSize,
			( theResult + 1 ) % IMAAudioPayloadInterleaveCount( inPayload ) );
	
	return( theResult );
}



UInt32
IMAAudioPayloadChannelCount(
	const IMAAudioPayload *		inPayload )
{
	return(
		__BitField(
			&inPayload->itsFixedHeader[ __kChannelCountWord ],
			__kChannelCountPosition, __kChannelCountSize ) + 1 );
}



UnsignedFixed
IMAAudioPayloadSampleRate(
	const IMAAudioPayload *		inPayload )
{
	UnsignedFixed	theResult;
	UInt32			theRateCode;
	
	
	theRateCode =
		__BitField(
			&inPayload->itsFixedHeader[ __kSampleRateWord ],
			__kSampleRatePosition, __kSampleRateSize );
	
	if( theRateCode < __kSampleRateCount )
		theResult = Long2Fix( __gSampleRates[ theRateCode ] );
	else
		theResult = 0;
	
	return( theResult );
}



UInt32
IMAAudioPayloadInterleaveCount(
	const IMAAudioPayload *		inPayload )
{
	return(
		__BitField(
			&inPayload->itsFixedHeader[ __kInterleaveCountWord ],
			__kInterleaveCountPosition, __kInterleaveCountSize ) + 1 );
}



UInt32
IMAAudioPayloadInterleaveIndex(
	const IMAAudioPayload *		inPayload )
{
	return(
		__BitField(
			&inPayload->itsFixedHeader[ __kInterleaveIndexWord ],
			__kInterleaveIndexPosition, __kInterleaveIndexSize ) );
}



UInt32
IMAAudioPayloadInterleaveTail(
	const IMAAudioPayload *		inPayload )
{
	return(
		__BitField(
			&inPayload->itsFixedHeader[ __kInterleaveTailWord ],
			__kInterleaveTailPosition, __kInterleaveTailSize ) );
}
