// ----------------------------------------------------------------------------------------------
// MySfx.c
//
// Contains some higher level sfx playing code that manages it own instance memory pool. 
//
// 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/07/99	Added this header
// ----------------------------------------------------------------------------------------------


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

#define MAX_SFX_INSTANCES	64

AM_SOUND 	gMySfxInstances[MAX_SFX_INSTANCES];

// ***********************************************************************************************
// KTBOOL MyAllocateSfxInstance(AM_SOUND_PTR *theSound)
//
// ***********************************************************************************************

KTBOOL MyAllocateSfxInstance(AM_SOUND_PTR *theSound)
{
KTU32 maxDaVoices	=	AC_TOTAL_VOICES;
KTU32 i				=	0;

*theSound	=	KTNULL;	// no undefined result...

for(i=0;i<maxDaVoices;i++)
	{
	if(gMySfxInstances[i].isPlaying==KTFALSE)	
		{
		memset(&gMySfxInstances[i],0x00,sizeof(AM_SOUND));
		*theSound	=	&gMySfxInstances[i];
		return KTTRUE;
		}
	}

return KTFALSE;
}

// ***********************************************************************************************
// KTBOOL MySoundEffectIsPlaying(AM_SOUND_PTR theSound)
//
// ***********************************************************************************************

KTBOOL MySoundEffectIsPlaying(AM_SOUND_PTR theSound)
{
return amSoundIsPlaying(theSound);
}
 
// ***********************************************************************************************
// AM_BANK_PTR MyLoadBank(char *bankFileName)
//
// ***********************************************************************************************
 
AM_BANK_PTR MyLoadBank(char *bankFileName)
{
KTU32 			bankSize		=	0;
volatile KTU32 *aicaBuffer		=	KTNULL;
AM_BANK_PTR		tempSh4Buffer	=	KTNULL;

// ----------------------------------------------------------------------------------------------
// Get the size of the bank file 
// ----------------------------------------------------------------------------------------------

if(amBankGetSize(bankFileName,&bankSize)==KTFALSE)
	{
	MyDebugf("amBankGetSize(%s,bankSize=%u) FAIL// get the size of the bank\n",bankFileName,bankSize);
	return KTNULL;
	}
//else
//	MyDebugf("amFileGetSize(%s,bankSize=%u) // get the size of the bank\n",bankFileName,bankSize);

// ----------------------------------------------------------------------------------------------
// Get a buffer in SH4 memory to load the bank into 
// ----------------------------------------------------------------------------------------------

if((tempSh4Buffer=(AM_BANK_PTR)syMalloc(bankSize))==KTNULL)
	{
	MyDebugf("syMalloc(bankSize) FAIL// get a temp buffer in SH4 memory to load into\n",bankFileName,bankSize);
	return KTNULL;
	}
//else
//	MyDebugf("syMalloc(bankSize) // get a temp buffer in SH4 memory to load into\n",bankFileName,bankSize);

// ----------------------------------------------------------------------------------------------
// load the bank
// ----------------------------------------------------------------------------------------------

if(amBankLoad(bankFileName,tempSh4Buffer)==KTFALSE)
	{
	MyDebugf("amBankLoad(bankFileName,tempSh4Buffer) FAIL// load the bank\n");
	return KTNULL;
	}
//else
//	MyDebugf("amBankLoad(bankFileName,tempSh4Buffer) FAIL// load the bank\n");

// ----------------------------------------------------------------------------------------------
// Get a buffer in sound memory to transfer the bank into 
// ----------------------------------------------------------------------------------------------

if(amHeapAlloc(&aicaBuffer,bankSize,32,AM_PURGABLE_MEMORY,KTNULL)==KTFALSE)
	{
	MyDebugf("amHeapAlloc(0x%x,%u,%u,AM_PURGABLE_MEMORY,KTNULL) FAIL\n",aicaBuffer,bankSize,32);
	syFree(tempSh4Buffer);
	return KTNULL;
	}
//else
//	MyDebugf("amHeapAlloc(0x%x,%u,%u,AM_PURGABLE_MEMORY,KTNULL)\n",aicaBuffer,bankSize,32);

// ----------------------------------------------------------------------------------------------
// Transfer the bank from SH4 memory to AICA memory
// ----------------------------------------------------------------------------------------------

if(amBankTransfer(aicaBuffer,tempSh4Buffer,bankSize)==KTFALSE)
	{
	MyDebugf("amBankTransfer(aicaBuffer,tempSh4Buffer,bankSize) FAIL// get the size of the bank\n");
	syFree(tempSh4Buffer);
	return KTNULL;
	}
//else
//	MyDebugf("amBankTransfer(aicaBuffer,tempSh4Buffer,bankSize) // get the size of the bank\n");

// ----------------------------------------------------------------------------------------------
// free the temp buffer
// ----------------------------------------------------------------------------------------------

syFree(tempSh4Buffer);

return aicaBuffer;
}

// ***********************************************************************************************
// KTBOOL MyInstallEffectsPatch(AM_BANK_PTR theBank, KTU32 effectsProgramBankIndex,KTU32 effectsOutputBankIndex)
//
// ***********************************************************************************************

KTBOOL MyInstallEffectsPatch(AM_BANK_PTR theBank, KTU32 effectsProgramBankIndex,KTU32 effectsOutputBankIndex)
{
if(amDspFetchProgramBank(theBank,effectsProgramBankIndex)==KTFALSE)
	{
	MyDebugf("amDspFetchProgramBank(0x%x,%u) FAIL",theBank,effectsProgramBankIndex);
	return KTFALSE;
	}
else
	MyDebugf("amDspFetchProgramBank(0x%x,%u) // fetch and install a program bank",theBank,effectsProgramBankIndex);

if(amDspFetchOutputBank(theBank,effectsOutputBankIndex)==KTFALSE)
	{
	MyDebugf("amDspFetchOutputBank(0x%x,%u) FAIL",theBank,effectsOutputBankIndex);
	return KTFALSE;
	}
else
	MyDebugf("amDspFetchOutputBank(0x%x,%u) // fetch and install an output bank",theBank,effectsOutputBankIndex);

return KTTRUE;
}

// ***********************************************************************************************
// KTBOOL MyStopSoundEffect(AM_SOUND_PTR theSound)
//
// ***********************************************************************************************

KTBOOL MyStopSoundEffect(AM_SOUND_PTR theSound)
{
if(amSoundStop(theSound)==KTTRUE)
	return KTTRUE;
else
	return KTFALSE;
}

// ***********************************************************************************************
// AM_SOUND_PTR MyPlaySoundEffect(AM_BANK_PTR theBank,KTU32 soundNumber,KTU32 volume,KTU32 pan)
//
// ***********************************************************************************************


AM_SOUND_PTR MyPlaySoundEffect(AM_BANK_PTR theBank,KTU32 soundNumber,KTU32 volume,KTU32 pan)
{
AM_SOUND_PTR theSound	=	KTNULL;

// ----------------------------------------------------------------------------------------------
// Allocate a sound structure from the global array
// ----------------------------------------------------------------------------------------------

if(MyAllocateSfxInstance(&theSound)==KTFALSE)
	return KTNULL;

// ----------------------------------------------------------------------------------------------
// Fetch a pointer to the data 
// ----------------------------------------------------------------------------------------------

if(amSoundFetchSample((KTU32 *)theBank,soundNumber,theSound)==KTFALSE)
	return KTNULL;

// ----------------------------------------------------------------------------------------------
// get a voice channel
//
// NOTE: Once the voice is allocated to a sound object the sound either must be submitted to
// the play call or have the voice released via amSoundReleaseVoiceChannel().
//
// If the amSoundPlay() call fails it will release the voice from the sound, however if
// your application wants to abort the building of a sound post the call to amSoundAllocateVoice()
// it MUST call amSoundReleaseVoiceChannel() as demonstrated here.
// ----------------------------------------------------------------------------------------------

if(amSoundAllocateVoiceChannel(theSound)==KTFALSE)
	return KTNULL;

// ----------------------------------------------------------------------------------------------
// set the initial volume
//
// NOTE: Once the voice is allocated to a sound object the sound either must be submitted to
// the play call or have the voice released via amSoundReleaseVoiceChannel().
//
// If the amSoundPlay() call fails it will release the voice from the sound, however if
// your application wants to abort the building of a sound post the call to amSoundAllocateVoice()
// it MUST call amSoundReleaseVoiceChannel() as demonstrated here.
// ----------------------------------------------------------------------------------------------

if(amSoundSetVolume(theSound,volume)==KTFALSE)
	{
	amSoundReleaseVoiceChannel(theSound);
	return KTFALSE;
	}

// ----------------------------------------------------------------------------------------------
// set the initial pan
//
// NOTE: Once the voice is allocated to a sound object the sound either must be submitted to
// the play call or have the voice released via amSoundReleaseVoiceChannel().
//
// If the amSoundPlay() call fails it will release the voice from the sound, however if
// your application wants to abort the building of a sound post the call to amSoundAllocateVoice()
// it MUST call amSoundReleaseVoiceChannel() as demonstrated here.
// ----------------------------------------------------------------------------------------------

if(amSoundSetPan(theSound,pan)==KTFALSE)
	{
	amSoundReleaseVoiceChannel(theSound);
	return KTFALSE;
	}

// ----------------------------------------------------------------------------------------------
// make it play
//
// If amSoundPlay() fails it will release the voice channel
// ----------------------------------------------------------------------------------------------

if(amSoundPlay(theSound)==KTFALSE)
	return KTNULL;

return theSound;
}

// ***********************************************************************************************
// AM_SOUND_PTR MyPlaySoundEffectFx(AM_BANK_PTR theBank,KTU32 soundNumber,KTU32 volume,KTU32 pan,KTU32 effectSourceMix,KTBOOL qSoundOnOrOff)
//
// ***********************************************************************************************

AM_SOUND_PTR MyPlaySoundEffectFx(AM_BANK_PTR theBank,KTU32 soundNumber,KTU32 volume,KTU32 pan,KTU32 effectSourceMix,KTBOOL qSoundOnOrOff)
{
KTU32 	dspMixerChannel	=	0;
AM_SOUND_PTR theSound	=	KTNULL;

// ----------------------------------------------------------------------------------------------
// Allocate a sound structure from the global array
// ----------------------------------------------------------------------------------------------

if(MyAllocateSfxInstance(&theSound)==KTFALSE)
	return KTNULL;

// ----------------------------------------------------------------------------------------------
// Figure out which mixer channel to use
// ----------------------------------------------------------------------------------------------

if(qSoundOnOrOff==KTTRUE)
	{
	dspMixerChannel	=	MY_SFX_QSOUND_CHANNEL;
	}
else
	dspMixerChannel	=	MY_SFX_REVERB_CHANNEL;
	
// ----------------------------------------------------------------------------------------------
// Fetch a pointer to the data 
// ----------------------------------------------------------------------------------------------

if(amSoundFetchSample((KTU32 *)theBank,soundNumber,theSound)==KTFALSE)
	return KTNULL;

// ----------------------------------------------------------------------------------------------
// get a voice channel
//
// NOTE: Once the voice is allocated to a sound object the sound either must be submitted to
// the play call or have the voice released via amSoundReleaseVoiceChannel().
//
// If the amSoundPlay() call fails it will release the voice from the sound, however if
// your application wants to abort the building of a sound post the call to amSoundAllocateVoice()
// it MUST call amSoundReleaseVoiceChannel() as demonstrated here.
// ----------------------------------------------------------------------------------------------

if(amSoundAllocateVoiceChannel(theSound)==KTFALSE)
	return KTNULL;

// ----------------------------------------------------------------------------------------------
// set the initial volume, 
//
//	NOTE: do this prior to setting the source mix as that is derived from theSound's volume
//
// NOTE: Once the voice is allocated to a sound object the sound either must be submitted to
// the play call or have the voice released via amSoundReleaseVoiceChannel().
//
// If the amSoundPlay() call fails it will release the voice from the sound, however if
// your application wants to abort the building of a sound post the call to amSoundAllocateVoice()
// it MUST call amSoundReleaseVoiceChannel() as demonstrated here.
// ----------------------------------------------------------------------------------------------

if(amSoundSetVolume(theSound,volume)==KTFALSE)
	{
	amSoundReleaseVoiceChannel(theSound);
	return KTFALSE;
	}

// ----------------------------------------------------------------------------------------------
// set the initial pan
//
// NOTE: Once the voice is allocated to a sound object the sound either must be submitted to
// the play call or have the voice released via amSoundReleaseVoiceChannel().
//
// If the amSoundPlay() call fails it will release the voice from the sound, however if
// your application wants to abort the building of a sound post the call to amSoundAllocateVoice()
// it MUST call amSoundReleaseVoiceChannel() as demonstrated here.
// ----------------------------------------------------------------------------------------------

if(amSoundSetPan(theSound,pan)==KTFALSE)
	{
	amSoundReleaseVoiceChannel(theSound);
	return KTFALSE;
	}

// ----------------------------------------------------------------------------------------------
// set the effect source mix and bus
//
// NOTE: Once the voice is allocated to a sound object the sound either must be submitted to
// the play call or have the voice released via amSoundReleaseVoiceChannel().
//
// If the amSoundPlay() call fails it will release the voice from the sound, however if
// your application wants to abort the building of a sound post the call to amSoundAllocateVoice()
// it MUST call amSoundReleaseVoiceChannel() as demonstrated here.
// ----------------------------------------------------------------------------------------------

if(amSoundSetEffectsBus(theSound,dspMixerChannel,effectSourceMix)==KTFALSE)
	{
	amSoundReleaseVoiceChannel(theSound);
	return KTFALSE;
	}

// ----------------------------------------------------------------------------------------------
// make it play
// ----------------------------------------------------------------------------------------------

if(amSoundPlay(theSound)==KTFALSE)
	return KTNULL;
	
return theSound;
}

