// ------------------------------------------------------------------------------------------------
// main.c
//
// This has the main function for the StrSfx testbed.
//
// 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	File Originated
// ------------------------------------------------------------------------------------------------



#include <shinobi.h>
#include <sg_chain.h>
#include <am.h>
#include "StrSfx.h"
#include "MyButton.h"
#include "MySfx.h"
#include "MyStream.h"
#include "MyFile.h"
#include "MyPrintf.h"
#include "MyInt.h"
#include "MyMalloc.h"
#include "MyAmSetup.h"


#define STREAM_FILE_NAME					"s_Hip101.str"
#define STREAM_TEST_PLAY_BUFFER_SIZE		16384
#define STREAM_TEST_TRANSFER_BUFFER_SIZE	(STREAM_TEST_PLAY_BUFFER_SIZE * 2)

#define MAX_AUDIO_INSTANCES					64
#define MAX_ONE_SHOTS						4

KTBOOL SfxSetup(void);
KTBOOL StreamSetup(void);

AM_BANK_PTR		gBank						=	KTNULL;
KTU32 			gTransferBufferSize			=	0;
KTU32 			gPlayBufferSize				=	0;
volatile KTU32 *gPlayBuffer					=	KTNULL;
volatile KTU32 *gTransferBuffer				=	KTNULL;
AM_STREAM_PTR	gStream						=	KTNULL;
KTU32			gStreamVolume				=	127;

extern AC_MESSAGE_MODE	gAcMessageMode;

#ifdef __GNUC__
int main(void)
#else
void main(void)
#endif
{
	SYE_CBL_CABLE Cable;
	PDS_PERIPHERAL *	pad;
	KTU32				j								=	0;
	KTBOOL				heliLoopFlag					=	KTFALSE;
	KTBOOL				humLoopFlag						=	KTFALSE;
	KTBOOL				spaceLoopFlag					=	KTFALSE;
	KTU32				oneShotSounds[MAX_ONE_SHOTS] 	= {STRSFX_ELEVATOR_WAV,STRSFX_GLASS_WAV,STRSFX_HONK_WAV,STRSFX_PING_WAV};
	KTU32				oneShotIndex					=	0;
	AM_SOUND_PTR		oneShot							=	KTNULL;
	AM_SOUND_PTR		heliLoop						=	KTNULL;
	AM_SOUND_PTR		humLoop							=	KTNULL;
	AM_SOUND_PTR		spaceLoop						=	KTNULL;
	KTU8				myStreamVolume					=	AM_MAX_VOLUME; // AM_MAX_VOLUME = 127
	char 				streamMessage[80]				= 	{"Playing"};
	KTU32				volume							= 	127;
	KTU32				pan								=	64;
	KTU32 				numberOfSlotsAvailable			=	0;

	#ifdef __GNUC__
	shinobi_workaround();
	#endif

	njSetBorderColor(0x00000000);

	// Check the cable for NTSC or VGA 
	Cable = syCblCheckCable();

	switch( Cable )
		{
		case SYE_CBL_CABLE_VGA:
			sbInitSystem(NJD_RESOLUTION_VGA, NJD_FRAMEBUFFER_MODE_RGB565, 1);
			break;
	
		case SYE_CBL_CABLE_NTSC:
			sbInitSystem(NJD_RESOLUTION_640x480_NTSCNI, NJD_FRAMEBUFFER_MODE_RGB565, 1);
			break;
		}
	
	njInitVertexBuffer( 20000, 0, 20000, 0, 0 );
	njInitPrint( NULL, 0, NJD_TEXFMT_ARGB_1555 );
	njSetBackColor( 0x00000000, 0x00000000, 0x000000FF );
	njSetBorderColor(0x00000000);
	njPrintSize(12);	
	
	// ----------------------------------------------------------------------------------------------
	// Open the AM system
	// ----------------------------------------------------------------------------------------------

	if(MyAmSetup(KTFALSE)==KTFALSE)
		{
		MyDebugf("MyAmSetup() FAIL");
		return;
		}
	
	// ----------------------------------------------------------------------------------------------
	// Setup the sfx bank
	// ----------------------------------------------------------------------------------------------

	if(SfxSetup()==KTFALSE)
		{
		MyDebugf("SfxSetup() FAIL");
		return;
		}

	// ----------------------------------------------------------------------------------------------
	// Set up the buffers etc for the stream
	// ----------------------------------------------------------------------------------------------

	if(StreamSetup()==KTFALSE)
		{
		MyDebugf("StreamSetup() FAIL");
		return;
		}

	// ----------------------------------------------------------------------------------------------
	// Start the stream
	// ----------------------------------------------------------------------------------------------

	MyStreamStart(gStream);

	// ----------------------------------------------------------------------------------------------
	// Main loop
	// ----------------------------------------------------------------------------------------------
		
	while(1)
		{
		pad = (PDS_PERIPHERAL *)pdGetPeripheral(PDD_PORT_A0);
	
		MyDcPrintf(INFO_1_X,INFO_1_Y,"Triggers play one shot sounds.");
		MyDcPrintf(INFO_2_X,INFO_2_Y,"A, B or X toggle looping sounds.");
		MyDcPrintf(INFO_3_X,INFO_3_Y,"D-Pad u/d to change stream volume.");
		MyDcPrintf(INFO_4_X,INFO_4_Y,"D-Pad left - stop/right - start stream.");

		if(gAcMessageMode==AC_POLL_MESSAGES)
			MyDcPrintf(INFO_5_X,INFO_5_Y,"Message Mode: Polling");
		else
			MyDcPrintf(INFO_5_X,INFO_5_Y,"Message Mode: Interrupts");
	
		MyDcPrintf(STR_STATUS_X,STR_STATUS_Y,"Stream Status: %s",streamMessage);
		MyDcPrintf(STR_VOL_X,STR_VOL_Y,"Stream Volume: %u",myStreamVolume);
	
		MyDcPrintf(AM_ERROR_X,AM_ERROR_Y,"Am Error: %d Ac Error: %u",gMyAmError->number,gMyAcError->number);
	
		MyStreamServer();
		
		if(MyStreamIsPlaying(gStream)==KTFALSE)
			{
			strcpy(streamMessage,"Done");
			}

		if(pad->press & PAD_R_TRIGGER)
			{
			oneShot=MyPlaySoundEffect(gBank,oneShotSounds[oneShotIndex++],volume,pan);

			if(oneShotIndex >= MAX_ONE_SHOTS) oneShotIndex	=	0;
			}
		else if(pad->press & PAD_L_TRIGGER)
			{
			oneShot=MyPlaySoundEffect(gBank,oneShotSounds[oneShotIndex++],volume,pan);

			if(oneShotIndex >= MAX_ONE_SHOTS) oneShotIndex	=	0;
			}
		else if(pad->press & PAD_Y_BUTTON)
			{
			oneShot=MyPlaySoundEffect(gBank,oneShotSounds[oneShotIndex++],volume,pan);

			if(oneShotIndex >= MAX_ONE_SHOTS) oneShotIndex	=	0;
			}
		else if(pad->press & PAD_A_BUTTON)
			{
			if(heliLoopFlag==KTFALSE)
				{
				heliLoop	=	MyPlaySoundEffect(gBank,STRSFX_HELILOOP_WAV,volume,pan);
				heliLoopFlag	=	KTTRUE;
				}
			else
				{
				MyStopSoundEffect(heliLoop);
				heliLoopFlag	=	KTFALSE;
				}
			}
		else if(pad->press & PAD_B_BUTTON)
			{
			if(humLoopFlag==KTFALSE)
				{
				humLoop	=	MyPlaySoundEffect(gBank,STRSFX_MHUMLOOP_WAV,volume,pan);
				humLoopFlag	=	KTTRUE;
				}
			else
				{
				MyStopSoundEffect(humLoop);
				humLoopFlag	=	KTFALSE;
				}
			}
		else if(pad->press & PAD_X_BUTTON)
			{
			if(spaceLoopFlag==KTFALSE)
				{
				spaceLoop	=	MyPlaySoundEffect(gBank,STRSFX_MHUMLOOP_WAV,volume,pan);
				spaceLoopFlag	=	KTTRUE;
				}
			else
				{
				MyStopSoundEffect(spaceLoop);
				spaceLoopFlag	=	KTFALSE;
				}
			}
		else if(pad->press & PAD_MOVE_UP)
			{
			++myStreamVolume;
			
			if(myStreamVolume > AM_MAX_VOLUME)
				myStreamVolume = AM_MAX_VOLUME;
				
			MyStreamSetVolume(gStream,myStreamVolume);			 
			}
		else if(pad->press & PAD_MOVE_DOWN)
			{
			--myStreamVolume;
			
			if(myStreamVolume > AM_MAX_VOLUME) // its unsigned, underflow is positive
				myStreamVolume = 0;
	
			MyStreamSetVolume(gStream,myStreamVolume);			
			}
		else if(pad->press & PAD_MOVE_LEFT)
			{
			MyStreamStop(gStream);
			strcpy(streamMessage,"Stopped");
			}
		else if(pad->press & PAD_MOVE_RIGHT)
			{
			if(amStreamPlaying(gStream)==KTFALSE)
				{
				MyStreamDestroy(gStream);
	
				if((gStream=MyStreamPrepareFile(STREAM_FILE_NAME,gStreamVolume,64,gTransferBuffer,gPlayBuffer,KTNULL,AM_STREAM_NON_DMA))==KTNULL)
					return;
	
				MyStreamStart(gStream);

				strcpy(streamMessage,"Playing");
				}
			}
			
		njWaitVSync();
		}
	
	
	// ----------------------------------------------------------------------------------------------
	// Shutdown the am library
	// ----------------------------------------------------------------------------------------------
	
	MyAmShutdown();
}

KTBOOL StreamSetup(void)
{
// ----------------------------------------------------------------------------------------------
// Set the default play buffer size for the stream
// ----------------------------------------------------------------------------------------------

MyStreamSetPlayBufferSize(STREAM_TEST_PLAY_BUFFER_SIZE);

// ----------------------------------------------------------------------------------------------
// Get the memory requirements
// ----------------------------------------------------------------------------------------------

if(MyStreamGetBufferSpecs(STREAM_FILE_NAME,&gTransferBufferSize,&gPlayBufferSize,AM_STREAM_NON_DMA)==KTFALSE)
	return KTFALSE;

// ----------------------------------------------------------------------------------------------
// get the necessary buffers lined up for the stream
//
// allocate memory for the play buffers.
//
// transfer buffer MUST! be in sh4 memory and 32 byte aligned or file reads will fail with the 
// GDFS file system.
// ----------------------------------------------------------------------------------------------


if(amHeapAlloc(&gPlayBuffer,gPlayBufferSize,32,AM_PURGABLE_MEMORY,KTNULL)==KTFALSE)
	{
	MyDebugf("amHeapAlloc(0x%x,%u,%u,AM_PURGABLE_MEMORY,KTNULL) FAIL\n",gPlayBuffer,gPlayBufferSize,32);
	return KTFALSE;
	}
else
	MyDebugf("amHeapAlloc(0x%x,%u,%u,AM_PURGABLE_MEMORY,KTNULL)\n",gPlayBuffer,gPlayBufferSize,32);

// ----------------------------------------------------------------------------------------------
// allocate memory for the transfer buffers.
//
// transfer buffer MUST! be in sh4 memory and 32 byte aligned or file reads will fail with the 
// GDFS file system.
// ----------------------------------------------------------------------------------------------

if((gTransferBuffer=(volatile KTU32 *)syMalloc(gTransferBufferSize))==KTNULL)
	{
	MyDebugf("syMalloc(gTransferBufferSize) FAIL\n");
	return KTFALSE;
	}
else
	MyDebugf("syMalloc(gTransferBufferSize)\n");

// ----------------------------------------------------------------------------------------------
// prepare the stream
// ----------------------------------------------------------------------------------------------

if((gStream=MyStreamPrepareFile(STREAM_FILE_NAME,gStreamVolume,64,gTransferBuffer,gPlayBuffer,KTNULL,AM_STREAM_NON_DMA))==KTNULL)
	return KTFALSE;

return KTTRUE;
}

KTBOOL SfxSetup(void)
{
// ----------------------------------------------------------------------------------------------
// Load a bank
// ----------------------------------------------------------------------------------------------

if((gBank=MyLoadBank(STRSFX_FILENAME))==KTNULL)
	{
	MyDebugf("MyLoadBank(0x%x,%s) FAIL",gBank,STRSFX_FILENAME);
	return KTFALSE;
	}
else
	{
	MyDebugf("MyLoadBank(0x%x,%s) // load a bank of sounds into sound memory",gBank,STRSFX_FILENAME);
	}

return KTTRUE;
}

