// ------------------------------------------------------------------------------------------------
// main.c
//
// This has the main function for the str_sfx 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 <am.h>
#include "str_sfx.h"
#include "MySfx.h"
#include "MyStream.h"


#define STREAM_FILE_NAME					"s_Hip101.str"
#define MAX_AUDIO_INSTANCES					64
#define MAX_ONE_SHOTS						4

#define BASE_X			10
#define BASE_Y			10

#define INFO_1_X		BASE_X
#define INFO_1_Y		BASE_Y

#define INFO_2_X		BASE_X
#define INFO_2_Y		BASE_Y+2

#define INFO_3_X		BASE_X
#define INFO_3_Y		BASE_Y+4

#define INFO_4_X		BASE_X
#define INFO_4_Y		BASE_Y+6


#define STR_STATUS_X	BASE_X
#define STR_STATUS_Y	BASE_Y+8

#define STR_VOL_X		BASE_X
#define STR_VOL_Y		BASE_Y+10

#define AM_ERROR_X		BASE_X
#define AM_ERROR_Y		BASE_Y+12

#define AC_ERROR_X		BASE_X
#define AC_ERROR_Y		BASE_Y+14

void dcPrintf(short x,short y,const char *format,...);

// the button masks
#define PAD_X_BUTTON						(1 << 10)
#define PAD_Y_BUTTON						(1 << 9)
#define PAD_A_BUTTON						(1 << 2)
#define PAD_B_BUTTON						(1 << 1)
#define PAD_START_BUTTON					(1 << 3)
#define PAD_MOVE_LEFT						(1 << 6)
#define PAD_MOVE_RIGHT						(1 << 7)
#define PAD_MOVE_UP							(1 << 4)
#define PAD_MOVE_DOWN						(1 << 5)
#define PAD_R_TRIGGER						(1 << 16)
#define PAD_L_TRIGGER						(1 << 17)

AC_ERROR_PTR	gMyAcError;
AM_ERROR_PTR	gMyAmError;

KTBOOL MyStreamIoProc(KTSTRING fileName,ACFILE * sd,KTU8 * buffer,KTU32 * size,AM_FILE_OPERATION_MODE mode);
KTBOOL MyFileIoProc(KTSTRING fileName,ACFILE * fd,KTU8 * buffer,KTU32 * size,AM_FILE_OPERATION_MODE mode);

void main(void)
{
	SYE_CBL_CABLE Cable;
	PDS_PERIPHERAL *	pad;
	KTU32 				instanceNumber					=	0;	
	AM_BANK_PTR			myBank							=	KTNULL;
	KTU32				j								=	0;
	KTBOOL				heliLoopFlag					=	KTFALSE;
	KTBOOL				humLoopFlag						=	KTFALSE;
	KTBOOL				spaceLoopFlag					=	KTFALSE;
	KTU32				oneShotSounds[MAX_ONE_SHOTS] 	= {STR_SFX_ELEVATOR_WAV,STR_SFX_GLASS_WAV,STR_SFX_HONK_WAV,STR_SFX_PING_WAV};
	KTU32				oneShotIndex					=	0;
	AM_SOUND 			gSound[MAX_AUDIO_INSTANCES];
	AM_SOUND 			heliLoop;
	AM_SOUND 			humLoop;
	AM_SOUND 			spaceLoop;
	AM_STREAM			myStream;
	KTU8				myStreamVolume					=	AM_MAX_VOLUME; // AM_MAX_VOLUME = 127
	char 				streamMessage[80]				= {"Playing"};

	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 );
	
	// ----------------------------------------------------------------------------------------------
	// Initialize the am library
	// ----------------------------------------------------------------------------------------------
	
	// install a custom file IO proc, see MyFile.c
	amFileInstallAlternateIoManager(MyFileIoProc);

	// Install a custom stream IO proc,, see MyFile.c
	amStreamIoInstallAlternateIoManager(MyStreamIoProc);


	if(amInit()==KTFALSE)
		return;
	
	// ----------------------------------------------------------------------------------------------
	// Load a bank
	// ----------------------------------------------------------------------------------------------
	
	if((myBank=MyLoadBank(STR_SFX_FILENAME))==KTNULL)
		{
		acPrintf("MyLoadBank(0x%x,%s) FAIL",myBank,STR_SFX_FILENAME);
		return;
		}
	else
		{
		acPrintf("MyLoadBank(0x%x,%s) // load a bank of sounds into sound memory",myBank,STR_SFX_FILENAME);
		}
	
	memset(&myStream,0x00,sizeof(AM_STREAM));
	
	MyStreamStart(&myStream,STREAM_FILE_NAME);
		
	while(1)
		{
		pad = (PDS_PERIPHERAL *)pdGetPeripheral(PDD_PORT_A0);
	
		dcPrintf(INFO_1_X,INFO_1_Y,"Press the triggers on controller 1 to play one shot sounds.");
		dcPrintf(INFO_2_X,INFO_2_Y,"Press the A, B or X on controller 1 to toggle looping sounds.");
		dcPrintf(INFO_3_X,INFO_3_Y,"Press the D-Pad up or down to change stream volume.");
		dcPrintf(INFO_4_X,INFO_4_Y,"Press the D-Pad left to stop or right to start stream.");
	
		dcPrintf(STR_STATUS_X,STR_STATUS_Y,"Stream Status: %s",streamMessage);
		dcPrintf(STR_VOL_X,STR_VOL_Y,"Stream Volume: %u",myStreamVolume);
	
		dcPrintf(AM_ERROR_X,AM_ERROR_Y,"Am Error Number: %d",gAmError.number);
		dcPrintf(AC_ERROR_X,AC_ERROR_Y,"Ac Error Number: %d",gAcError.number);
	
		MyStreamServer(&myStream);
	
		if(amErrorExists()==KTTRUE)
			{
			gMyAmError	=	amErrorGetLast();
			}
	
		if(acErrorExists()==KTTRUE)
			{
			gMyAcError	=	acErrorGetLast();
			}
	
		if(MyStreamIsDone()==KTTRUE)
			{
			strcpy(streamMessage,"Done");
			}
	
		if(pad->press & PAD_R_TRIGGER)
			{
			MyPlaySoundEffect(myBank,&gSound[instanceNumber++],oneShotSounds[oneShotIndex++]);
	
			if(oneShotIndex >= MAX_ONE_SHOTS) oneShotIndex	=	0;
			}
		else if(pad->press & PAD_L_TRIGGER)
			{
			MyPlaySoundEffect(myBank,&gSound[instanceNumber++],oneShotSounds[oneShotIndex++]);
	
			if(oneShotIndex >= MAX_ONE_SHOTS) oneShotIndex	=	0;
			}
		else if(pad->press & PAD_Y_BUTTON)
			{
			MyPlaySoundEffect(myBank,&gSound[instanceNumber++],oneShotSounds[oneShotIndex++]);
	
			if(oneShotIndex >= MAX_ONE_SHOTS) oneShotIndex	=	0;
			}
		else if(pad->press & PAD_A_BUTTON)
			{
			if(heliLoopFlag==KTFALSE)
				{
				MyPlaySoundEffect(myBank,&heliLoop,STR_SFX_HELILOOP_WAV);
				heliLoopFlag	=	KTTRUE;
				}
			else
				{
				MyStopSoundEffect(&heliLoop);
				heliLoopFlag	=	KTFALSE;
				}
			}
		else if(pad->press & PAD_B_BUTTON)
			{
			if(humLoopFlag==KTFALSE)
				{
				MyPlaySoundEffect(myBank,&humLoop,STR_SFX_MHUMLOOP_WAV);
				humLoopFlag	=	KTTRUE;
				}
			else
				{
				MyStopSoundEffect(&humLoop);
				humLoopFlag	=	KTFALSE;
				}
			}
		else if(pad->press & PAD_X_BUTTON)
			{
			if(spaceLoopFlag==KTFALSE)
				{
				MyPlaySoundEffect(myBank,&spaceLoop,STR_SFX_MHUMLOOP_WAV);
				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(&myStream,myStreamVolume);			 
			}
		else if(pad->press & PAD_MOVE_DOWN)
			{
			--myStreamVolume;
			
			if(myStreamVolume > AM_MAX_VOLUME) // its unsigned, underflow is positive
				myStreamVolume = 0;
	
			MyStreamSetVolume(&myStream,myStreamVolume);			
			}
		else if(pad->press & PAD_MOVE_LEFT)
			{
			MyStreamStop(&myStream);
			strcpy(streamMessage,"Stopped");
			}
		else if(pad->press & PAD_MOVE_RIGHT)
			{
			if(amStreamPlaying(&myStream)==KTFALSE)
				{
				MyStreamClearCallbackFlag();
				MyStreamRestart(&myStream);
				strcpy(streamMessage,"Playing");
				}
			}
			
		if(instanceNumber >= MAX_AUDIO_INSTANCES)
			instanceNumber	=	0;
	
		njWaitVSync();
		}
	
	
	// ----------------------------------------------------------------------------------------------
	// Shutdown the am library
	// ----------------------------------------------------------------------------------------------
	
	amShutdown();
}

