// ------------------------------------------------------------------------------------------------
// MyStream.c
//
// Higher level stream functions
//
// This has been modified for R9 in that it now has a pool of stream instances and returns pointers
// to the instances rather then having the instance memory passed in from the application.
//
// COPYRIGHT (C) SEGA OF AMERICA, INC. 1998
// All rights reserved.
//
// Information and source code samples contained herein are 
// provided "as-is", without representations or warranties, and 
// are subject to change without notice.
//
// SEGA OF AMERICA, INC. cannot support modifications or 
// derivative works created from the sample source code provided. 
// Developers may use, reproduce, and modify portions or entire 
// sections of the sample source code for the purposes of creating
// Dreamcast applications.  
//
// Sample source code contained herein may not be appropriate 
// for use under all circumstances.  Please consult Developer 
// documentation provided along with your Dreamcast unit for
// additional information and suggestions.
//
//
// Author: Ralph "Cooksey" Thomas
//
// Tabs:	4
//
// Rev:		04/05/99	Added this header
//			04/07/99	Cleaned up.
// ------------------------------------------------------------------------------------------------


#include <am.h>
#include "MyStream.h"
#include "MyPrintf.h"

#define 			PLAY_BUFFER_SIZE				16384	// a reasonable default play buffer size
#define 			MY_STREAM_MAX_INSTANCES			8

KTU32				gMyPlayBufferSize							=	PLAY_BUFFER_SIZE;
volatile KTBOOL		gStreamCallbackFlag							=	KTFALSE;
volatile KTU32 *	gMyTransferBufferBaseAddress				=	KTNULL;
AM_STREAM			gMyStreamInstances[MY_STREAM_MAX_INSTANCES];
AM_STREAM_PTR		gMyActiveStreams[MY_STREAM_MAX_INSTANCES]	=	{KTNULL,KTNULL,KTNULL,KTNULL,};
volatile KTBOOL		gMyStreamFlags[MY_STREAM_MAX_INSTANCES]		=	{KTFALSE,KTFALSE,KTFALSE,KTFALSE,};
AM_STREAM_ISR		gMyStreamIsrs[MY_STREAM_MAX_INSTANCES]		=	{_amStreamIsr0,_amStreamIsr1,_amStreamIsr2,_amStreamIsr3};

KTBOOL 	_myStreamInstanceToIndex	(AM_STREAM_PTR theStream,volatile KTU32 *index);
KTBOOL 	_myStreamAddInstance		(AM_STREAM_PTR theStream);	// add an instance to the server queue
KTBOOL 	_myStreamRemoveInstance		(AM_STREAM_PTR theStream);	// remove an instance from the server queue
KTBOOL 	_myStreamFreeInstance		(AM_STREAM_PTR theStream);	// free a instance memory block
KTBOOL 	_myStreamAllocateInstance	(AM_STREAM_PTR *theStream); // allocate an instance from the pool

// **********************************************************************************************
// KTBOOL _myStreamInstanceToIndex(AM_STREAM_PTR theStream,volatile KTU32 *index)
//
// get the pool index based on the instance address
// **********************************************************************************************

KTBOOL _myStreamInstanceToIndex(AM_STREAM_PTR theStream,volatile KTU32 *index)
{
KTU32 i	=	0;


for(i=0;i<MY_STREAM_MAX_INSTANCES;i++)
	{
	if(theStream==&gMyStreamInstances[i])
		{
		*index	=	i;
		return KTTRUE;
		}
	}
	
return KTFALSE;
}

// **********************************************************************************************
// KTBOOL _myStreamAllocateInstance(AM_STREAM_PTR *theStream)
//
// get a stream instance from the pool
// **********************************************************************************************

KTBOOL _myStreamAllocateInstance(AM_STREAM_PTR *theStream)
{
KTU32 i	=	0;

for(i=0;i<MY_STREAM_MAX_INSTANCES;i++)
	{
	if(gMyStreamFlags[i]==KTFALSE)
		{
		*theStream			=	&gMyStreamInstances[i];
		gMyStreamFlags[i]	=	KTTRUE;
		return KTTRUE;
		}
	}

return KTFALSE;
}


// **********************************************************************************************
// KTBOOL _myStreamFreeInstance(AM_STREAM_PTR theStream)
// 
// release the instance memory back to the pool
// **********************************************************************************************

KTBOOL _myStreamFreeInstance(AM_STREAM_PTR theStream)
{
volatile KTU32	index	=	0;

if(_myStreamInstanceToIndex(theStream,&index)==KTFALSE)
	return KTFALSE;

gMyStreamFlags[index]	=	KTFALSE;	

return KTTRUE;
}


// **********************************************************************************************
// KTBOOL _myStreamAddInstance(AM_STREAM_PTR theStream)
//
// add an instance to the server queue
// **********************************************************************************************

KTBOOL _myStreamAddInstance(AM_STREAM_PTR theStream)
{
KTU32 	i	=	0;

for(i=0;i<MY_STREAM_MAX_INSTANCES;i++)
	{
	if(gMyActiveStreams[i]==KTNULL)
		{
		gMyActiveStreams[i]	=	theStream;
		return KTTRUE;
		}
	}
	
return KTFALSE;
}

// **********************************************************************************************
// KTBOOL _myStreamRemoveInstance(AM_STREAM_PTR theStream)
//
// remove an instance from the server queue
// **********************************************************************************************

KTBOOL _myStreamRemoveInstance(AM_STREAM_PTR theStream)
{
KTU32 	i	=	0;

for(i=0;i<MY_STREAM_MAX_INSTANCES;i++)
	{
	if(gMyActiveStreams[i]==theStream)
		{
		gMyActiveStreams[i]	=	KTNULL;
		return KTTRUE;
		}
	}
return KTFALSE;
}


// **********************************************************************************************
// void MyStreamServer(void)
//
// Serve data to the transfer and play buffers
// **********************************************************************************************


void MyStreamServer(void)
{
KTU32 	i	=	0;

for(i=0;i<MY_STREAM_MAX_INSTANCES;i++)
	{
	if(gMyActiveStreams[i] != KTNULL)
		{
		amStreamServer(gMyActiveStreams[i]);
		}
	}
}

// **********************************************************************************************
// KTBOOL MyStreamDestroy(AM_STREAM_PTR theStream)
//
// stop, close, release instance and remove from server queue
// **********************************************************************************************

KTBOOL MyStreamDestroy(AM_STREAM_PTR theStream)
{
if(MyStreamIsPlaying(theStream)==KTTRUE)
	amStreamStop(theStream);

amStreamClose(theStream);

// remove the instance from the server queue
if(_myStreamRemoveInstance(theStream)==KTFALSE)
	return KTFALSE;

// free the instance
if(_myStreamFreeInstance(theStream)==KTFALSE)
	return KTFALSE;
	
return KTTRUE;
}

// **********************************************************************************************
// KTBOOL MyStreamDestroyBuffer(AM_STREAM_PTR theStream)
//
// stop, release instance and remove from server queue (close is only necessary for file streams)
// **********************************************************************************************

KTBOOL MyStreamDestroyBuffer(AM_STREAM_PTR theStream)
{
if(MyStreamIsPlaying(theStream)==KTTRUE)
	amStreamStop(theStream);

// remove the instance from the server queue
if(_myStreamRemoveInstance(theStream)==KTFALSE)
	return KTFALSE;

// free the instance
if(_myStreamFreeInstance(theStream)==KTFALSE)
	return KTFALSE;
	
return KTTRUE;
}


// **********************************************************************************************
// void MyStreamSetPlayBufferSize(KTU32 playBufferSize)
// 
// set the default buffer sizes
// **********************************************************************************************

void MyStreamSetPlayBufferSize(KTU32 playBufferSize)
{
gMyPlayBufferSize		=	playBufferSize;
}

// **********************************************************************************************
// KTBOOL MyStreamGetBufferSpecs(char *streamFileName,KTU32 *transferBufferSize,KTU32 *playBufferSize)
//
// get the buffer requirements for a file stream.
// **********************************************************************************************

KTBOOL MyStreamGetBufferSpecs(char *streamFileName,KTU32 *transferBufferSize,KTU32 *playBufferSize,AM_STREAM_TRANSFER_METHOD transferMethod)
{
AM_STREAM theStream;

// ----------------------------------------------------------------------------------------------
// init the stream object
// ----------------------------------------------------------------------------------------------

if(amStreamInitFile(&theStream,streamFileName)==KTFALSE)
	{
	MyDebugf("amStreamInitFile(theStream,%s) FAIL\n",streamFileName);
	return KTFALSE;
	}
else
	MyDebugf("amStreamInitFile(theStream,%s)\t\t// init the stream object\n",streamFileName);

// ----------------------------------------------------------------------------------------------
// set the buffer sizes
// ----------------------------------------------------------------------------------------------

if(amStreamSetBufferSizes(&theStream,gMyPlayBufferSize * 2,gMyPlayBufferSize)==KTFALSE)
	{
	MyDebugf("amStreamSetBufferSizes(&theStream,gMyPlayBufferSize * 2,gMyPlayBufferSize) FAIL// set the buffer sizes\n",gMyPlayBufferSize);
	return KTFALSE;
	}
else
	MyDebugf("amStreamSetBufferSizes(&theStream,gMyPlayBufferSize * 2,gMyPlayBufferSize)// set the buffer sizes\n",gMyPlayBufferSize);

// ----------------------------------------------------------------------------------------------
// open the stream
// ----------------------------------------------------------------------------------------------

if(amStreamOpen(&theStream)==KTFALSE)
	{
	MyDebugf("amStreamOpen(theStream) - %s FAIL\n",theStream.fileName);
	return KTFALSE;
	}
else
	MyDebugf("amStreamOpen(theStream) - %s\n",theStream.fileName);

// ----------------------------------------------------------------------------------------------
// Get the memory requirements, a stream with 8 mono tracks (8 tracks * 1 channel ea) will 
// require 1 transfer buffer that is ((tracks * channels) * playBufferSize) * 2 and 8 play 
// buffers. In other words the transfer buffer should be twice the sum of the size of the play 
// buffers for a given stream.
// ----------------------------------------------------------------------------------------------

if(amStreamGetMemoryRequirement(&theStream,transferBufferSize,playBufferSize)==KTFALSE)
	{
	MyDebugf("amStreamGetMemoryRequirement(theStream,&transferBufferSize,&playBufferSize) FAIL\n");
	return KTFALSE;
	}
else
	MyDebugf("amStreamGetMemoryRequirement(theStream,%u,%u) // find out how much memory is required\n",transferBufferSize,playBufferSize);



if(amStreamClose(&theStream)==KTFALSE)
	{
	MyDebugf("amStreamClose(theStream) FAIL\n");
	return KTFALSE;
	}
else
	MyDebugf("amStreamClose(theStream)\t// close the stream file\n");

return KTTRUE;
}

// **********************************************************************************************
// AM_STREAM_PTR MyStreamPrepareFile(char *streamFileName,KTU32 volume,KTU32 pan,volatile KTU32 *transferBuffer,volatile KTU32 *playBuffer)
//
// prepare a file for playback
// **********************************************************************************************

AM_STREAM_PTR MyStreamPrepareFile(char *streamFileName,KTU32 volume,KTU32 pan,volatile KTU32 *transferBuffer,volatile KTU32 *playBuffer,AM_USER_CALLBACK userCallback,AM_STREAM_TRANSFER_METHOD transferMethod)
{
AM_STREAM_PTR 	theStream	=	KTNULL;
volatile KTU32	index		=	0;
AM_STREAM_ISR	isr			=	KTNULL;

// ----------------------------------------------------------------------------------------------
// get an instance
// ----------------------------------------------------------------------------------------------

if(_myStreamAllocateInstance(&theStream)==KTFALSE)
	return KTNULL;

if(_myStreamInstanceToIndex(theStream,&index)==KTFALSE)
	{
	_myStreamFreeInstance(theStream);
	return KTNULL;
	}

isr	=	gMyStreamIsrs[index];

// ----------------------------------------------------------------------------------------------
// init the stream object
// ----------------------------------------------------------------------------------------------

if(amStreamInitFile(theStream,streamFileName)==KTFALSE)
	{
	MyDebugf("amStreamInitFile(theStream,%s) FAIL\n",streamFileName);
	
	_myStreamFreeInstance(theStream);
	
	return KTNULL;
	}

// ----------------------------------------------------------------------------------------------
// set the buffer sizes
// ----------------------------------------------------------------------------------------------

if(amStreamSetBufferSizes(theStream,gMyPlayBufferSize * 2,gMyPlayBufferSize)==KTFALSE)
	{
	MyDebugf("amStreamSetBufferSizes(&theStream,gMyPlayBufferSize * 2,gMyPlayBufferSize) FAIL// set the buffer sizes\n",gMyPlayBufferSize);
	
	_myStreamFreeInstance(theStream);

	return KTNULL;
	}
else
	MyDebugf("amStreamSetBufferSizes(&theStream,gMyPlayBufferSize * 2,gMyPlayBufferSize)// set the buffer sizes\n",gMyPlayBufferSize);

// ----------------------------------------------------------------------------------------------
// open the stream
// ----------------------------------------------------------------------------------------------

if(amStreamOpen(theStream)==KTFALSE)
	{
	MyDebugf("amStreamOpen(theStream) - %s FAIL\n",theStream->fileName);
	
	_myStreamFreeInstance(theStream);

	return KTNULL;
	}

// ----------------------------------------------------------------------------------------------
// give the stream the buffers
// ----------------------------------------------------------------------------------------------

if(amStreamSetBuffers(theStream,transferBuffer,playBuffer)==KTFALSE)
	{
	MyDebugf("amStreamSetBuffers(theStream,0x%x,0x%x) FAIL\n",transferBuffer,playBuffer);

	amStreamClose(theStream);

	_myStreamFreeInstance(theStream);

	return KTNULL;
	}

// ----------------------------------------------------------------------------------------------
// allocate the voice channels
//
// NOTE: Once the voice is allocated to a stream object the stream either must be submitted to
// the play call or have the voice released via amStreamReleaseVoiceChannels().
//
// If the amStreamStart() call fails and the stream is to be aborted it must be done via the 
// app calling amStreamDestroy() (for file streams) or amStreamDestroyBuffer().
//
// Calling amStreamStop() or playing the stream to the end will also release the voice channels.
// ----------------------------------------------------------------------------------------------

if(amStreamAllocateVoiceChannels(theStream)==KTFALSE)
	{
	MyDebugf("amStreamAllocateVoiceChannels(theStream) FAIL\n");

	amStreamClose(theStream);

	_myStreamFreeInstance(theStream);

	return KTNULL;
	}

// ----------------------------------------------------------------------------------------------
// install the user callback if one is supplied
//
// NOTE: Once the voice is allocated to a stream object the stream either must be submitted to
// the play call or have the voice released via amStreamReleaseVoiceChannels().
//
// If the amStreamStart() call fails and the stream is to be aborted it must be done via the 
// app calling amStreamDestroy() (for file streams) or amStreamDestroyBuffer().
//
// Calling amStreamStop() or playing the stream to the end will also release the voice channels.
// ----------------------------------------------------------------------------------------------

if(userCallback != KTNULL)
	{
	if(amStreamInstallUserCallback(theStream,userCallback)==KTFALSE)
		{
		MyDebugf("amStreamInstallUserCallback(theStream,userCallback) FAIL\n");

		amStreamClose(theStream);
		
		amStreamReleaseVoiceChannels(theStream);

		_myStreamFreeInstance(theStream);

		return KTNULL;
		}
	}

// ----------------------------------------------------------------------------------------------
// prime buffers
//
// NOTE: Once the voice is allocated to a stream object the stream either must be submitted to
// the play call or have the voice released via amStreamReleaseVoiceChannels().
//
// If the amStreamStart() call fails and the stream is to be aborted it must be done via the 
// app calling amStreamDestroy() (for file streams) or amStreamDestroyBuffer().
//
// Calling amStreamStop() or playing the stream to the end will also release the voice channels.
// ----------------------------------------------------------------------------------------------

if(amStreamPrimeBuffers(theStream)==KTFALSE)
	{
	MyDebugf("amStreamPrimeBuffers(theStream) FAIL\n");

	amStreamClose(theStream);

	amStreamReleaseVoiceChannels(theStream);

	_myStreamFreeInstance(theStream);

	return KTNULL;
	}

// ----------------------------------------------------------------------------------------------
// set the isr, must be called after the voice channel(s) are allocated
//
// NOTE: Once the voice is allocated to a stream object the stream either must be submitted to
// the play call or have the voice released via amStreamReleaseVoiceChannels().
//
// If the amStreamStart() call fails and the stream is to be aborted it must be done via the 
// app calling amStreamDestroy() (for file streams) or amStreamDestroyBuffer().
//
// Calling amStreamStop() or playing the stream to the end will also release the voice channels.
// ----------------------------------------------------------------------------------------------

if(amStreamSetIsr(theStream,isr)==KTFALSE)
	{
	MyDebugf("amStreamSetIsr(theStream,isr) FAIL\n");

	amStreamClose(theStream);

	amStreamReleaseVoiceChannels(theStream);

	_myStreamFreeInstance(theStream);

	return KTNULL;
	}

// ----------------------------------------------------------------------------------------------
// set the volume and pan for track 0
// ----------------------------------------------------------------------------------------------

amStreamSetVolume(theStream,volume,0);

amStreamSetPan(theStream,pan,0);

// ----------------------------------------------------------------------------------------------
// add the instance to the server queue
//
// NOTE: Once the voice is allocated to a stream object the stream either must be submitted to
// the play call or have the voice released via amStreamReleaseVoiceChannels().
//
// If the amStreamStart() call fails and the stream is to be aborted it must be done via the 
// app calling amStreamDestroy() (for file streams) or amStreamDestroyBuffer().
//
// Calling amStreamStop() or playing the stream to the end will also release the voice channels.
// ----------------------------------------------------------------------------------------------

if(_myStreamAddInstance(theStream)==KTFALSE)
	{
	MyDebugf("_myStreamAddInstance(theStream) FAIL\n");

	amStreamClose(theStream);

	amStreamReleaseVoiceChannels(theStream);

	_myStreamFreeInstance(theStream);

	return KTNULL;
	}
	
return theStream;
}

// **********************************************************************************************
// KTBOOL MyStreamStop(AM_STREAM_PTR theStream)
//
// Stop a stream from playing
// **********************************************************************************************

KTBOOL MyStreamStop(AM_STREAM_PTR theStream)
{
return amStreamStop(theStream);
}

// **********************************************************************************************
// KTBOOL MyStreamIsPlaying(AM_STREAM_PTR theStream)
//
// See if a stream is playing
// **********************************************************************************************

KTBOOL MyStreamIsPlaying(AM_STREAM_PTR theStream)
{
return amStreamPlaying(theStream);
}

// **********************************************************************************************
// KTBOOL MyStreamStart(AM_STREAM_PTR theStream)
//
// start a stream playing
// **********************************************************************************************

KTBOOL MyStreamStart(AM_STREAM_PTR theStream)
{
// ----------------------------------------------------------------------------------------------
// start the stream
// ----------------------------------------------------------------------------------------------

// calling MyDebugf while a stream is playing will cause severe audio artifacts.
MyDebugf("amStreamStart(theStream) // start the stream\n");

if(amStreamStart(theStream)==KTFALSE)
	{
	MyDebugf("amStreamStart(theStream)==KTFALSE\n");
	return KTFALSE;
	}


return KTTRUE;
}

// **********************************************************************************************
// KTBOOL MyStreamSetVolume(AM_STREAM_PTR theStream,KTU32 volume)
// 
// set the volume on a stream
// **********************************************************************************************

KTBOOL MyStreamSetVolume(AM_STREAM_PTR theStream,KTU32 volume)
{
return amStreamSetVolume(theStream,volume,0);
}

// **********************************************************************************************
// KTBOOL MyStreamRestart(AM_STREAM_PTR theStream)
//
// restart a previously prepared/playing file stream that has been stopped or has finished
// **********************************************************************************************

KTBOOL MyStreamRestart(AM_STREAM_PTR theStream,AM_USER_CALLBACK userCallback)
{
AM_STREAM_ISR	isr	=	KTNULL;
volatile KTU32 index	=	0;

// ----------------------------------------------------------------------------------------------
// get an ISR
// ----------------------------------------------------------------------------------------------

if(_myStreamInstanceToIndex(theStream,&index)==KTFALSE)
	return KTFALSE;

isr	=	gMyStreamIsrs[index];

// ----------------------------------------------------------------------------------------------
// rewind to the beginning of the file
// ----------------------------------------------------------------------------------------------

if(amStreamRewind(theStream)==KTFALSE)
	{
	MyDebugf("amStreamRewind(theStream) FAIL\n");
	return;
	}

// ----------------------------------------------------------------------------------------------
// allocate the voice channel
// ----------------------------------------------------------------------------------------------

if(amStreamAllocateVoiceChannels(theStream)==KTFALSE)
	{
	MyDebugf("amStreamAllocateVoiceChannels(theStream) FAIL\n");
	return;
	}

// ----------------------------------------------------------------------------------------------
// prime buffers
// ----------------------------------------------------------------------------------------------

if(amStreamPrimeBuffers(theStream)==KTFALSE)
	{
	MyDebugf("amStreamPrimeBuffers(theStream) FAIL\n");
	return;
	}

// ----------------------------------------------------------------------------------------------
// install the user callback if one is supplied
// ----------------------------------------------------------------------------------------------

if(userCallback != KTNULL)
	{
	if(amStreamInstallUserCallback(theStream,userCallback)==KTFALSE)
		{
		MyDebugf("amStreamInstallUserCallback(theStream,userCallback) FAIL\n");
		return KTNULL;
		}
	}

// ----------------------------------------------------------------------------------------------
// set the isr, must be called after the voice channel(s) are allocated
// ----------------------------------------------------------------------------------------------

if(amStreamSetIsr(theStream,isr)==KTFALSE)
	{
	MyDebugf("amStreamSetIsr(theStream,_amStreamIsr0) FAIL\n");
	return;
	}

// ----------------------------------------------------------------------------------------------
// start the stream
// ----------------------------------------------------------------------------------------------

if(amStreamStart(theStream)==KTFALSE)
	{
	MyDebugf("amStreamStart(theStream)==KTFALSE\n");
	return;
	}
}

// **********************************************************************************************
// KTBOOL MyStreamSetMix(AM_STREAM_PTR theStream,AM_STREAM_MIX_PTR theMix)
//
// Set the mix for a multi track stream
// **********************************************************************************************


KTBOOL MyStreamSetMix(AM_STREAM_PTR theStream,AM_STREAM_MIX_PTR theMix)
{
return(amStreamSetMix(theStream,theMix));
}


// **********************************************************************************************
// 
// AM_STREAM_PTR MyStreamPrepareBuffer(	volatile KTU32 *buffer,	
// 										KTU32 size,
// 										volatile KTU32 *playBuffer,
// 										KTU32 volume,
// 										KTU32 pan,
// 										KTU32 sampleRate,
// 										KTU32 bitDepth,
// 										AM_TRACK_TYPE monoOrStereo,
// 										AM_USER_CALLBACK userCallback)
// 
//
// This will prepare a buffer stream, the transfer method is implicitly NON_DMA as the DMA 
// streamer will currently only play a single mono or stereo stream. A method such as this
// can be used to play sound effects that exceed 64k
// **********************************************************************************************

AM_STREAM_PTR MyStreamPrepareBuffer(	volatile KTU32 *buffer,	
										KTU32 size,
										volatile KTU32 *playBuffer,
										KTU32 volume,
										KTU32 pan,
										KTU32 sampleRate,
										KTU32 bitDepth,
										AM_TRACK_TYPE monoOrStereo,
										AM_USER_CALLBACK userCallback)
{
AM_STREAM_PTR 	theStream	=	KTNULL;
volatile KTU32	index		=	0;
AM_STREAM_ISR	isr			=	KTNULL;

// ----------------------------------------------------------------------------------------------
// get an instance
// ----------------------------------------------------------------------------------------------

if(_myStreamAllocateInstance(&theStream)==KTFALSE)
	return KTNULL;

if(_myStreamInstanceToIndex(theStream,&index)==KTFALSE)
	{
	_myStreamFreeInstance(theStream);
	return KTNULL;
	}
	
isr	=	gMyStreamIsrs[index];

// ----------------------------------------------------------------------------------------------
// init the stream object
// ----------------------------------------------------------------------------------------------

if(amStreamInitBuffer(theStream,buffer,size,sampleRate,bitDepth,monoOrStereo)==KTFALSE)
	{
	MyDebugf("amStreamInitBuffer() FAIL\n");
	
	_myStreamFreeInstance(theStream);
	
	return KTNULL;
	}
	
// ----------------------------------------------------------------------------------------------
// set the buffer sizes
// ----------------------------------------------------------------------------------------------

if(amStreamSetBufferSizes(theStream,size,gMyPlayBufferSize)==KTFALSE)
	{
	MyDebugf("amStreamSetBufferSizes(&theStream,gMyPlayBufferSize * 2,gMyPlayBufferSize) FAIL// set the buffer sizes\n",gMyPlayBufferSize);
	
	_myStreamFreeInstance(theStream);
	
	return KTNULL;
	}
else
	MyDebugf("amStreamSetBufferSizes(&theStream,gMyPlayBufferSize * 2,gMyPlayBufferSize)// set the buffer sizes\n",gMyPlayBufferSize);

// ----------------------------------------------------------------------------------------------
// open the stream
// ----------------------------------------------------------------------------------------------

if(amStreamOpen(theStream)==KTFALSE)
	{
	MyDebugf("amStreamOpen(theStream) FAIL\n");
	
	_myStreamFreeInstance(theStream);
	
	return KTNULL;
	}

// ----------------------------------------------------------------------------------------------
// give the stream the buffers
// ----------------------------------------------------------------------------------------------

if(amStreamSetBuffers(theStream,buffer,playBuffer)==KTFALSE)
	{
	MyDebugf("amStreamSetBuffers() FAIL\n");

	_myStreamFreeInstance(theStream);

	return KTNULL;
	}

// ----------------------------------------------------------------------------------------------
// allocate the voice channels
//
// NOTE: Once the voice is allocated to a stream object the stream either must be submitted to
// the play call or have the voice released via amStreamReleaseVoiceChannels().
//
// If the amStreamStart() call fails and the stream is to be aborted it must be done via the 
// app calling amStreamDestroy() (for file streams) or amStreamDestroyBuffer().
//
// Calling amStreamStop() or playing the stream to the end will also release the voice channels.
// ----------------------------------------------------------------------------------------------

if(amStreamAllocateVoiceChannels(theStream)==KTFALSE)
	{
	MyDebugf("amStreamAllocateVoiceChannels(theStream) FAIL\n");

	_myStreamFreeInstance(theStream);

	return KTNULL;
	}

// ----------------------------------------------------------------------------------------------
// install the user callback if one is supplied
//
// NOTE: Once the voice is allocated to a stream object the stream either must be submitted to
// the play call or have the voice released via amStreamReleaseVoiceChannels().
//
// If the amStreamStart() call fails and the stream is to be aborted it must be done via the 
// app calling amStreamDestroy() (for file streams) or amStreamDestroyBuffer().
//
// Calling amStreamStop() or playing the stream to the end will also release the voice channels.
// ----------------------------------------------------------------------------------------------

if(userCallback != KTNULL)
	{
	if(amStreamInstallUserCallback(theStream,userCallback)==KTFALSE)
		{
		MyDebugf("amStreamInstallUserCallback(theStream,userCallback) FAIL\n");
		
		amStreamReleaseVoiceChannels(theStream);

		_myStreamFreeInstance(theStream);

		return KTNULL;
		}
	}

// ----------------------------------------------------------------------------------------------
// prime buffers
//
// NOTE: Once the voice is allocated to a stream object the stream either must be submitted to
// the play call or have the voice released via amStreamReleaseVoiceChannels().
//
// If the amStreamStart() call fails and the stream is to be aborted it must be done via the 
// app calling amStreamDestroy() (for file streams) or amStreamDestroyBuffer().
//
// Calling amStreamStop() or playing the stream to the end will also release the voice channels.
// ----------------------------------------------------------------------------------------------

if(amStreamPrimeBuffers(theStream)==KTFALSE)
	{
	MyDebugf("amStreamPrimeBuffers(theStream) FAIL\n");
		
	amStreamReleaseVoiceChannels(theStream);

	_myStreamFreeInstance(theStream);

	return KTNULL;
	}

// ----------------------------------------------------------------------------------------------
// set the isr, must be called after the voice channel(s) are allocated
//
// NOTE: Once the voice is allocated to a stream object the stream either must be submitted to
// the play call or have the voice released via amStreamReleaseVoiceChannels().
//
// If the amStreamStart() call fails and the stream is to be aborted it must be done via the 
// app calling amStreamDestroy() (for file streams) or amStreamDestroyBuffer().
//
// Calling amStreamStop() or playing the stream to the end will also release the voice channels.
// ----------------------------------------------------------------------------------------------

if(amStreamSetIsr(theStream,isr)==KTFALSE)
	{
	MyDebugf("amStreamSetIsr(theStream,isr) FAIL\n");
		
	amStreamReleaseVoiceChannels(theStream);

	_myStreamFreeInstance(theStream);

	return KTNULL;
	}

// ----------------------------------------------------------------------------------------------
// set the volume and pan for track 0
// ----------------------------------------------------------------------------------------------

amStreamSetVolume	(theStream,volume,0);
amStreamSetPan		(theStream,pan,0);

// ----------------------------------------------------------------------------------------------
// add the instance to the server queue
//
// NOTE: Once the voice is allocated to a stream object the stream either must be submitted to
// the play call or have the voice released via amStreamReleaseVoiceChannels().
//
// If the amStreamStart() call fails and the stream is to be aborted it must be done via the 
// app calling amStreamDestroy() (for file streams) or amStreamDestroyBuffer().
//
// Calling amStreamStop() or playing the stream to the end will also release the voice channels.
// ----------------------------------------------------------------------------------------------

if(_myStreamAddInstance(theStream)==KTFALSE)
	{
	MyDebugf("_myStreamAddInstance(theStream) FAIL\n");
		
	amStreamReleaseVoiceChannels(theStream);

	_myStreamFreeInstance(theStream);

	return KTNULL;
	}
	
return theStream;
}

