/*=============================================================================
	FormatConverterClient.h
	
	$Log: FormatConverterClient.h,v $
	Revision 2.10  2004/08/25 23:07:48  bills
	fix warning
	
	Revision 2.9  2003/11/21 22:27:18  dwyatt
	make Reset virtual
	
	Revision 2.8  2003/11/20 22:56:53  dwyatt
	__COREAUDIO_USE_FLAT_INCLUDES__
	
	Revision 2.7  2003/04/09 23:03:08  dwyatt
	minor refactoring
	
	Revision 2.6  2003/02/07 22:40:28  dwyatt
	redo 3020740 so that channel map is correctly preserved even across destroy/rebuild converter
	
	Revision 2.5  2003/02/05 22:12:41  dwyatt
	Add support for channel map
	
	Revision 2.4  2002/11/05 02:32:42  bills
	implement Reset call to call AUConverterReset [dwyatt]
	
	Revision 2.3  2002/06/29 20:37:14  dwyatt
	add a method for CAShow
	
	Revision 2.2  2002/06/14 09:03:39  dwyatt
	don't verify_noerr in FillComplexBuffer; failure is happening and
	the signal is confusing things badly
	
	Revision 2.1  2002/06/11 16:58:08  dwyatt
	return error from input proc
	
	Revision 2.0  2002/06/06 06:52:27  dwyatt
	moved from Utility
	
	Revision 1.3  2002/06/02 00:51:32  dwyatt
	fixes to complex conversions
	
	Revision 1.2  2002/05/20 02:19:30  dwyatt
	AudioUnit V2
	
	Revision 1.1.4.2  2002/04/22 18:04:24  dwyatt
	more v2 work
	
	Revision 1.1.4.1  2002/04/18 06:53:36  dwyatt
	initial checkin of deinterleave munge
	
	Revision 1.1  2001/12/17 13:30:32  luke
	copied from Source/Utility for inclusion in SDK
	
	Revision 1.8  2001/10/25 00:01:55  bills
	add back constructor needed for Puma build
	
	Revision 1.7  2001/10/20 01:19:53  dwyatt
	cache the src/dest formats in members
	
	Revision 1.6  2001/10/17 19:12:10  dwyatt
	add project
	
	Revision 1.5  2001/08/18 11:27:10  dwyatt
	add GetProperty wrapper method [2754217]
	
	Revision 1.4  2001/08/13 22:04:01  dwyatt
	check_noerr debugging macro removes code in production builds!  Use verify_noerr!
	D'oh!
	
	Revision 1.3  2001/07/28 18:03:05  dwyatt
	use check_noerr instead of verify_noerr
	
	Revision 1.2  2001/07/26 21:31:18  dwyatt
	add SetProperty
	
	Revision 1.1  2001/07/24 19:26:00  dwyatt
	initial checkin
	
	created 18 Jul 2001, 6:49, Doug Wyatt
	Copyright (c) 2001 Apple Computer, Inc.  All Rights Reserved
	
	$NoKeywords: $
=============================================================================*/

#ifndef __FormatConverterClient_h__
#define __FormatConverterClient_h__

#if !defined(__COREAUDIO_USE_FLAT_INCLUDES__)
	#include <AudioToolbox/AudioConverter.h>
#else
	#include <AudioConverter.h>
#endif
#include <vector>

extern "C" void CAShow(void *);

// ____________________________________________________________________________
//
// FormatConverterClient
// C++ wrapper for an AudioConverter
class FormatConverterClient {
public:
	FormatConverterClient() :
		mConverter(NULL)
	{
	}
	
		// ONLY NEEDED FOR Puma build - should be removed....
	FormatConverterClient(const AudioStreamBasicDescription &src, const AudioStreamBasicDescription &dest) :
		mConverter(NULL)
	{
		Initialize(src, dest);
	}
	
	virtual ~FormatConverterClient()
	{
		Destroy();
	}
	
	virtual OSStatus	Initialize(const AudioStreamBasicDescription &src, const AudioStreamBasicDescription &dest)
	{
		OSStatus err;
		Destroy();
		err = AudioConverterNew(&src, &dest, &mConverter);
		if (err) return err;
		mInputFormat = src;
		mOutputFormat = dest;
		return noErr;
	}
	
	void	Destroy()
	{
		if (mConverter) {
			verify_noerr(AudioConverterDispose(mConverter));
			mConverter = NULL;
		}
	}
	
	virtual OSStatus	Reset () { return (mConverter ? AudioConverterReset (mConverter) : noErr); }

	OSStatus	SetProperty(AudioConverterPropertyID	inPropertyID,
							UInt32						inPropertyDataSize,
							const void *				inPropertyData)
	{
		return AudioConverterSetProperty(mConverter, inPropertyID, inPropertyDataSize, inPropertyData);
	}
	
	OSStatus	GetProperty(AudioConverterPropertyID	inPropertyID,
							UInt32 &					ioPropertyDataSize,
							void *						outPropertyData)
	{
		return AudioConverterGetProperty(mConverter, inPropertyID, &ioPropertyDataSize, outPropertyData);
	}

	OSStatus	GetPropertyInfo(AudioConverterPropertyID	inPropertyID,
								UInt32 &					outPropertyDataSize,
								Boolean &					outWritable)
	{
		return AudioConverterGetPropertyInfo(mConverter, inPropertyID, &outPropertyDataSize, &outWritable);
	}

	void	SetQuality(UInt32 inQuality)
	{
		SetProperty(kAudioConverterSampleRateConverterQuality, sizeof(UInt32), &inQuality );
	}

#if 0	
	OSStatus	ConvertBuffer(void *src, UInt32 srcSize, void *dest, UInt32 destSize)
	{
		OSStatus err;
		verify_noerr(err = AudioConverterConvertBuffer(mConverter, srcSize, src, &destSize, dest));
		return err;
	}
	
	OSStatus	FillBuffer(	UInt32&							ioOutputDataSize,
							void*							outOutputData)
	{
		OSStatus err;
		verify_noerr(err = AudioConverterFillBuffer(mConverter, InputProc, this, &ioOutputDataSize, outOutputData));
		return err;
	}
#endif

	OSStatus	FillComplexBuffer(	UInt32 &							ioOutputDataPacketSize,
									AudioBufferList &					outOutputData,
									AudioStreamPacketDescription*		outPacketDescription)
	{
		OSStatus err;
		err = AudioConverterFillComplexBuffer(mConverter, InputProc, this,
			&ioOutputDataPacketSize, &outOutputData, outPacketDescription);
		//printf("\n\nFillComplexBuffer returned %ld packets\n", ioOutputDataPacketSize);
		//DumpBufferList(outOutputData);
		return err;
	}
	
	const AudioStreamBasicDescription &	GetInputFormat()	{ return mInputFormat; }

	const AudioStreamBasicDescription &	GetOutputFormat()	{ return mOutputFormat; }	
	
protected:
	virtual OSStatus	FormatConverterInputProc(	
								UInt32 &						ioNumberDataPackets,
								AudioBufferList &				ioData,
								AudioStreamPacketDescription**	outDataPacketDescription) = 0;
	
private:
	static OSStatus	InputProc(	AudioConverterRef				inAudioConverter,
								UInt32*							ioNumberDataPackets,
								AudioBufferList*				ioData,
								AudioStreamPacketDescription**	outDataPacketDescription,
								void*							inUserData)
	{
		OSStatus err;
		try {
			FormatConverterClient *This = (FormatConverterClient *)inUserData;
			AudioBuffer *buf = ioData->mBuffers;
			UInt32 nBytes = *ioNumberDataPackets * This->mInputFormat.mBytesPerPacket;
			for (UInt32 i = ioData->mNumberBuffers; i--; ++buf) {
				buf->mDataByteSize = nBytes;
			}
//printf("\n\nInputProc - %ld packets, %ld bytes\n", *ioNumberDataPackets, nBytes);
			err = This->FormatConverterInputProc(*ioNumberDataPackets, *ioData, outDataPacketDescription);
//DumpBufferList(*ioData);
		} catch (OSStatus res) {
			return res;
		}
		catch (...) {
			return -1;
		}
		return err;
	}

#if DEBUG
public:
	void Show()
	{
		CAShow(mConverter);
	}

	static void	DumpBufferList(AudioBufferList &abl)
	{
		printf("%ld buffers:\n", abl.mNumberBuffers);
		AudioBuffer *buf = abl.mBuffers;
		for (UInt32 i = 0; i < abl.mNumberBuffers; ++i, ++buf) {
			printf("buffer[%ld]:\n", i);
			DumpBuffer(buf);
		}
	}
	
	static void	DumpBuffer(AudioBuffer *buf)
	{
		printf("  channels=%ld, ptr=0x%X, size=%ld\n", buf->mNumberChannels, int(buf->mData), buf->mDataByteSize);
		Float32 *p = static_cast<Float32 *>(buf->mData);
		for (int i = buf->mDataByteSize / sizeof(Float32); i--; ++p)
			printf("%f\n", *p);
	}
#endif

protected:
	AudioConverterRef			mConverter;
	AudioStreamBasicDescription	mInputFormat, mOutputFormat;
};

#endif // __FormatConverterClient_h__
