// DS4QB++ slave - header file

// Defines

// Swap files
#define INFILE				"DS4QB.QBW"
#define OUTFILE				"DS4QB.VCW"
#define RECEIVECONFIRM		"DS4QB.QBS"
#define SENDCONFIRM			"DS4QB.VCS"

// Message id's
#define CMD_INITIALIZE		0
#define CMD_CLOSE			1
#define CMD_RESET			2 // Not used
#define CMD_LOADSND			3
#define CMD_PLAYSND			4
#define CMD_SETSNDATTR		5
#define CMD_GETSNDATTR		6
#define CMD_LOADMUSIC		7
#define CMD_PLAYMUSIC		8
#define CMD_SETMUSICATTR	9
#define CMD_GETMUSICATTR	10
#define CMD_STOPSND			11
#define CMD_PAUSEMUSIC		12
#define CMD_RESUMEMUSIC		13
#define CMD_STOPMUSIC		14
#define CMD_DELETESND		15
#define CMD_DELETEMUSIC		16
#define CMD_SETVOLUME		17
#define CMD_SETGLOBALVOLS	18
#define CMD_PLAY2DSOUNDS	19
#define CMD_PLAY3DSOUNDS	20
#define CMD_GETMUSICLENGTH	21
#define CMD_SETMUSICPOS		22
#define CMD_GETMUSICPOS		23
#define CMD_SET3DPOS		24
#define CMD_PLAYSND3D		25
#define CMD_SET3DFACTS		26
#define CMD_SETEAX			27
#define CMD_PLAYSOUNDS		28
#define CMD_PLAYSND2D		29
#define CMD_SET2DPOS	    30
#define CMD_SET2DDISTFACTOR 31
#define CMD_CDINIT			32
#define CMD_CDFREE			33
#define CMD_GETTRACKS		34
#define CMD_GETTRACKLENGTH	35
#define CMD_CDPLAY			36

#define DEFAULT				0xFFFF

#define WIN9X				1
#define WINNT				0

#define MP3MUSIC			1
#define MODMUSIC			2
#define CDMUSIC				513

// Macros
#define SGN(x)				((x > 0) ? 1 : (x < 0) ? -1 : 0)
#define TIMER				((float)(GetTickCount() / 1000))

// Typdefs
typedef unsigned char		UCHAR;

// Structs
typedef struct
{
	short int x;
	short int y;
	short int Angle;
} Snd2D;


// Classes
class SOUNDfx
{
private:
	HSAMPLE Handle;
	BASS_SAMPLE Info;
	HCHANNEL Channel[9];
	int Start_Freq;
	int Chan_Count;
	bool Paused;
public:
	bool Load(char *filename, DWORD flags);
	void Play(int freq, int volume, int pan, int looping);
	void Play2D(int freq, int volume, Snd2D snd, Snd2D ear);
	void Play3D(int freq, int volume, int looping, BASS_3DVECTOR Position, BASS_3DVECTOR Orientaion, BASS_3DVECTOR Velocity);
	void Stop();
	void SetInfo(int freq, int volume, int pan, int looping, DWORD flags);
	void Delete();
};

class MUSICpr
{
private:
	HMUSIC MODHandle;
	HSTREAM MP3Handle;
	void *mp3data;
	int xMusicType;
	bool looping;
public:
	int Length;

	int GetPos();
	bool Load(char *filename, DWORD flags, int MusicType);
	void Play();
	void Stop();
	void Pause();
	void Resume();
	void SetPos(int pos);
	void SetInfo(int pan, int amp);
	void Delete();
};

// Prototypes
int Buff2Long				(int pos);
int Buff2Int				(int pos);
void Int2Buff				(int pos, int val);
void Long2Buff				(char pos, int val);
int ScanInput				(void);
void SendOutput				(void);
int FindAngle				(int x1, int y1, int x2, int y2);
BASS_3DVECTOR Buff2V3D      (int pos);

// Global variables

// Windows
HINSTANCE hinstance_app =	NULL;

// Communication
FILE *handle;
UCHAR in_buffer[1024];
UCHAR out_buffer[1024];

// Sound/Music buffers
SOUNDfx Sounds[1024];
MUSICpr Musics[512];
// ...
Snd2D ear2d;
float distf2d = 1.0;
// ...
float cosine[360], sine[360];
float pi;

// Other globals
int Current_OS = WINNT;
bool No3d = true;
BASS_3DVECTOR TempV[3];
BASS_3DVECTOR *pTempV[3];
Snd2D TempSnd;

// SOUNDfx / MUSICpr class member functions

// SOUNDfx class
bool SOUNDfx::Load(char *filename, DWORD flags)
{
	Chan_Count = 0;

	Handle = BASS_SampleLoad(FALSE, filename, 0, 0, 10, BASS_SAMPLE_OVER_POS | flags);

	memset(&Info, 0, sizeof(Info));

	Start_Freq = Info.freq;

	if (Handle == NULL) return(true);
	return(false);
}

void SOUNDfx::Play(int freq, int volume, int pan, int looping)
{
	int n_freq		= freq,
		n_volume	= volume,
		n_pan		= pan - 100;
	
	if(looping == DEFAULT) looping = -1;
	if(looping && looping != -1) looping = true; else looping = false;
	
	bool n_looping = (bool)looping;
	
	if(freq == 0xFFFFFF) n_freq		= -1;
	if(freq == 0xFFFFFE) n_freq		= Start_Freq;
	
	if(volume == DEFAULT) n_volume	= -1;
	if(pan == DEFAULT) n_pan		= -101;
		
	Channel[Chan_Count] = BASS_SamplePlayEx(Handle, 0, n_freq, n_volume, n_pan, n_looping);
	Chan_Count = (Chan_Count + 1) % 10;
}

void SOUNDfx::Play2D(int freq, int volume, Snd2D snd, Snd2D ear)
{
	int n_freq	 = freq,
		n_volume = volume,
		n_pan	 = 0;

	if(freq == 0xFFFFFF) n_freq	= -1;
	if(freq == 0xFFFFFE) n_freq	= Start_Freq;
	if(volume == DEFAULT)
	{
		BASS_SampleGetInfo(Handle, &Info);
		n_volume = Info.volume;
	}

	int   nearang = 270 - ear.Angle + 360 * (ear.Angle > 270);

	float _xv     = snd.x - ear.x,
		  _yv     = snd.y - ear.y;
	float xv      = (_xv * cosine[nearang] - _yv * sine[nearang]) / distf2d,
		  yv      = (_xv * sine[nearang] + _yv * cosine[nearang]) / distf2d;
	float xs      = xv * xv;
	float dist    = xs + yv * yv;
	//float As	  = snd.Angle - FindAngle(ear.x, ear.y, snd.x, snd.y),
	//Ae	  = ear.Angle - FindAngle(snd.x, snd.y, ear.x, ear.y);
	//float angdiff = 1.0 - fabs((.25 * sin(As / 2)) - (.25 * sin(Ae / 2)));

	if(dist < 1) dist = 1;
	
	// v = c/dē
	n_volume = n_volume / dist;
	if(abs(xs) < 1) n_pan = 0; else n_pan = 100 * SGN(xv) - (100 / (xs * SGN(xv)));

	Channel[Chan_Count] = BASS_SamplePlayEx(Handle, 0, n_freq, n_volume, n_pan, false);
	Chan_Count = (Chan_Count + 1) % 10;
}

void SOUNDfx::Play3D(int freq, int volume, int looping, BASS_3DVECTOR Position, BASS_3DVECTOR Orientaion, BASS_3DVECTOR Velocity)
{
	if(No3d) { Play(freq, volume, DEFAULT, looping); return; }

	int n_freq	 = freq,
		n_volume = volume;

	BASS_3DVECTOR *pPos	   = &Position;
	BASS_3DVECTOR *pOrient = &Orientaion;
	BASS_3DVECTOR *pVel	   = &Velocity;

	if(Position.x == 0xFFFFFF) pPos		 = NULL;
	if(Orientaion.x == 0xFFFFFF) pOrient = NULL;
	if(Velocity.x  == 0xFFFFFF) pVel	 = NULL;
	
	if(looping == DEFAULT) looping = -1;
	if(looping && looping != -1) looping = true; else looping = false;
	
	bool n_looping = (bool)looping;
	
	if(freq == 0xFFFFFF) n_freq		= -1;
	if(freq == 0xFFFFFE) n_freq		= Start_Freq;
	if(volume == DEFAULT) n_volume	= -1;
		
	Channel[Chan_Count] = BASS_SamplePlay3DEx(Handle, pPos, pOrient, pVel, 0, n_freq, n_volume, n_looping);
	Chan_Count = (Chan_Count + 1) % 10;
}

void SOUNDfx::Stop()
{
	BASS_SampleStop(Handle);
}

void SOUNDfx::SetInfo(int freq, int volume, int pan, int looping, DWORD flags)
{
	memset(&Info, 0, sizeof(Info));

	BASS_SampleGetInfo(Handle, &Info);
	
	if(freq != DEFAULT) Info.freq		= (DWORD)freq;
	if(Info.freq == 0xFFFFFE) Info.freq	= (DWORD)Start_Freq;
	if(volume != DEFAULT) Info.volume	= (DWORD)volume;
	if(pan != DEFAULT) Info.pan			= pan;
	if(flags != DEFAULT) Info.flags		= flags;
	if(looping != DEFAULT) Info.flags	= Info.flags & BASS_SAMPLE_LOOP;
	
	BASS_SampleSetInfo(Handle, &Info);

	for(int i = 0; i < 10; i++)
		BASS_ChannelSetAttributes(Channel[i], Info.freq, Info.volume, Info.pan);

}

void SOUNDfx::Delete()
{
	Stop();
	BASS_SampleFree(Handle);
}

// MUSICpr class

bool MUSICpr::Load(char *filename, DWORD flags, int MusicType)
{
	FILE *Handle;
	int lent;

	xMusicType = MusicType;

	if(xMusicType == MP3MUSIC)
	{
		if(flags & BASS_SAMPLE_LOOP)
				looping = true;
			else
				looping = false;

		if(flags & 8192) flags = (flags ^ 8192) & BASS_MP3_HALFRATE;

		if(flags & 4096)
		{
			Handle = fopen(filename, "rb");
			fseek(Handle, 0, SEEK_END);
			lent = ftell(Handle);
			mp3data = malloc(lent);
			rewind(Handle);
			fread(mp3data, lent, 1, Handle);
			fclose(Handle);

			flags = flags ^ 4096;

			MP3Handle = BASS_StreamCreateFile(TRUE, mp3data, 0, lent, BASS_MP3_SETPOS | flags);
		} else {
			MP3Handle = BASS_StreamCreateFile(FALSE, filename, 0, 0, BASS_MP3_SETPOS | flags);
		}

		Length = BASS_StreamGetLength(MP3Handle);

		if(MP3Handle == NULL) return(true);
	} else if(xMusicType == MODMUSIC)
	{
		MODHandle = BASS_MusicLoad(FALSE, filename, 0, 0, flags);
		
		Length = BASS_MusicGetLength(MODHandle, false);

		if(MODHandle == NULL) return(true);
	}

	return(false);
}

void MUSICpr::Play()
{
	if(xMusicType == MP3MUSIC)
	{
		if(looping)
				BASS_StreamPlay(MP3Handle, false, BASS_SAMPLE_LOOP);
			else
				BASS_StreamPlay(MP3Handle, false, NULL);
	} else if(xMusicType == MODMUSIC)
	{
		BASS_MusicPlayEx(MODHandle, 0, -1, TRUE);
	}
}

void MUSICpr::Stop()
{
	if(xMusicType == MP3MUSIC)
	{
		BASS_ChannelStop(MP3Handle);
		BASS_ChannelSetPosition(MP3Handle, 0);
	} else if(xMusicType == MODMUSIC)
	{
		BASS_ChannelStop(MODHandle);
		BASS_ChannelSetPosition(MODHandle, 0);
	}
}

void MUSICpr::Pause()
{
	if(xMusicType == MP3MUSIC)
	{
		BASS_ChannelPause(MP3Handle);
	} else if(xMusicType == MODMUSIC)
	{
		BASS_ChannelPause(MODHandle);
	}
}

void MUSICpr::Resume()
{
	if(xMusicType == MP3MUSIC)
	{
		BASS_ChannelResume(MP3Handle);
	} else if(xMusicType == MODMUSIC)
	{
		BASS_ChannelResume(MODHandle);
	}
}

void MUSICpr::Delete()
{
	Stop();

	if(xMusicType == MP3MUSIC)
	{
		if(mp3data) free(mp3data);
		BASS_StreamFree(MP3Handle);
	} else if(xMusicType == MODMUSIC)
	{
		BASS_MusicFree(MODHandle);
	}
	
	xMusicType = 0;
}

void MUSICpr::SetInfo(int pan, int amp)
{
	if(xMusicType == MP3MUSIC)
	{
		BASS_ChannelSetAttributes(MP3Handle, -1, (DWORD)amp, -1);
	} else if(xMusicType == MODMUSIC)
	{
		if(amp != DEFAULT) BASS_ChannelSetAttributes(MODHandle, -1, (DWORD)amp, -1);
		if(pan != DEFAULT) BASS_MusicSetPanSep(MODHandle, (DWORD)pan);
	}
}

void MUSICpr::SetPos(int pos)
{
	if(xMusicType == MP3MUSIC)
	{
		BASS_ChannelSetPosition(MP3Handle, pos);
	} else if(xMusicType == MODMUSIC)
	{
		BASS_ChannelSetPosition(MODHandle, pos);
	}
}

int MUSICpr::GetPos()
{
	int pos = 0;
	//char blah[25];

	//FILE *fhandle;

	if(xMusicType == MP3MUSIC)
	{
		pos = BASS_ChannelGetPosition(MP3Handle);
		
		//fhandle = fopen("temp.txt", "at");
		//fseek(fhandle, 0, SEEK_END);
		//
		//sprintf(&blah[0], "%d\n", pos);
		//fwrite(&blah, 1, strlen(&blah[0]), fhandle);
		//
		//fclose(fhandle);
		
	} else if(xMusicType == MODMUSIC)
	{
		pos = BASS_ChannelGetPosition(MODHandle);
	}

	return(pos);
}