#include "glover.h"

/*
new sound system

ULONG sfxPlay(vab,sfxNum);  //returns voice number used.  vab 0=gen. 1=level specific. sfxNum define (see sfx.h)
ULONG sfxPlay3D(vab,sfxNum,VECTOR *position);  //returns voice number used. vector, xyz. volume depends on distance from camera

to change volume of pitch, set the array varible before calling:-
sampleBank[vab].samples[sampleNum].leftVol = var;  //default DEFAULT_VOLUME
sampleBank[vab].samples[sampleNum].rightVol = var;  //default DEFAULT_VOLUME
sampleBank[vab].samples[sampleNum].pitch = var;  //default DEFAULT_PITCH

to change it while its playing:-
void sfxSetVolume(int voice, int vol);
void sfxSetPitch(int voice, int pitch);
void sfxStopVoice(int voice);
int sfxCalc3DPosition(VECTOR *position, int *leftVol, int *rightVol); //recalc position volume


*/








int volume=128;

//#define PLAY 0
//#define UPDATE 1

//#define SFX_QUEUESIZE 24
//#define SFX_NORMAL_PRIORITY 128

//#define SOUND_MIN_D 32
//#define SOUND_FALLOFF 32


//SFX3DQUEUE sfx3DQueue[SFX_QUEUESIZE];

//UBYTE globalfxvab;
//UBYTE hubfxvab;
//UBYTE atlantisfxvab;
//UBYTE carnivalfxvab;
//UBYTE fortressfxvab;
//UBYTE prehistfxvab;
//UBYTE piratesfxvab;
//UBYTE spacefxvab;

UBYTE levelfxvab;	// = one of the above

int levelFX, globalFX;

UBYTE	sfxvolume=128;


int music_bank_loaded = -1;

CDCTRL CDctrl;
//SFXCTRL SFXctrl;

char sound_rec[SPU_MALLOC_RECSIZ * (4+1)];

sfxBankType	sampleBank[2];

//#define MAX_GLOBALSAMPLES (12*16)
#define MAX_SAMPLES (12*16)
static UBYTE lastSampleCall[2][MAX_SAMPLES];
static UBYTE sfxFrame;



/*************************************************************************************/
//void PlaySFX(UBYTE vab,UBYTE sfx,UBYTE volume,UBYTE pitch)
//{
//	DB("PlaySFX\n");
//	SFXPlay(0,vab,sfx, volume, volume, pitch);
//}

//void SFXInitQueue(void)
//{
//	int i;
//
//	for(i=0; i<SFX_QUEUESIZE; i++)
//		sfx3DQueue[i].priority=0;
//}

/************************************************************************************/
void LoadMusic(void)
{
	switch(world)
	{
 		case 	HUB:
			levelFX=SFXLoad("HUB",1);
			break;
		case 	ATLANTIS:
			levelFX=SFXLoad("ATLANTIS",1);
			sampleBank[levelFX].samples[SFX_AT_SPANK_OOF & 0xff].pitch = DEFAULT_PITCH / 2;
			break;
		case	CARNIVAL:
			levelFX=SFXLoad("CARNIVAL",1);
			break;
		case	PIRATES:	 
			levelFX=SFXLoad("PIRATES",1);
			sampleBank[levelFX].samples[SFX_PI_SPANK_OOF & 0xff].pitch = DEFAULT_PITCH / 2;
			break;
		case	PREHISTORIC:
			levelFX=SFXLoad("PREHIST",1);
//			sampleBank[levelFX].samples[SFX_CRUMPET_ATTACK & 0xffff].pitch = DEFAULT_PITCH / 2;
			break;
		case	FORTRESS:  	 
			levelFX=SFXLoad("FORTRESS",1);
			break;
		case	SPACE:
			levelFX=SFXLoad("SPACE",1);
			break;
		default:
			DB("SFX: Invalid world ...\n");
	}

	sampleBank[globalFX].samples[SFX_GE_CRUMPET_ATTACK & 0xff].pitch = DEFAULT_PITCH / 2;

	music_bank_loaded = world;
	DB("SFX bank loaded = %d\n",music_bank_loaded);
}

/**************************************************************************
	FUNCTION:	sfxInitialise()
	PURPOSE:	Initialise sound processor & routines
	PARAMETERS:	none
	RETURNS:	none
**************************************************************************/

// Called once, and once only, from MAIN
void sfxInitialise(UBYTE vabnum)
{
	unsigned long loop;
	printf("\nInitialising sound system...");
	SpuInit ();									// initialise spu
	SpuSetCommonMasterVolume(DEFAULT_VOLUME,DEFAULT_VOLUME);	// set master volume to max
	SpuSetCommonCDMix(SPU_ON);					// turn cd audio off
	SpuSetCommonCDVolume(DEFAULT_VOLUME,DEFAULT_VOLUME);
	SpuSetTransferCallback(NULL);
	SpuInitMalloc(4,sound_rec);
	sfxFrame = 0;
	for (loop=vabnum*MAX_SAMPLES; loop<MAX_SAMPLES; loop++){
 		lastSampleCall[0][loop] = 0;
 		lastSampleCall[1][loop] = 0;
	}

	sampleBank[0].samples = NULL;
	sampleBank[1].samples = NULL;
}
 
////////////////////////////////////////////////////////////////////////////////
//
//  SFXLoad
//  -------
//
//  Loads a specific (hardwired) VB and VH pair in from datafile. This must 
//  be called before any other of the SFX Functions
//
////////////////////////////////////////////////////////////////////////////////

long SFXLoad(char *Filename,UBYTE vabnum)
{
	unsigned char	*vagData;
	unsigned char	*vagPtr;
	unsigned char	*vabData;
	unsigned short	numVags;
	unsigned short	numProgs;
	unsigned short	*vagInfo;
	unsigned long	vagLoop;
	unsigned long	spuAddr;
	unsigned long	spuWrittenSize;


	UBYTE bInitSuccess;
	UBYTE tempmess[40];
	LONG temp;
	int lastfilelength;
	int checksoundloaded=0;

	ASSERT(!sampleBank[vabnum].samples);
	if(sampleBank[vabnum].samples)
	{
		sfxDestroy(vabnum);
		DB("***** Attempting to load to an already-loaded sample bank!!! *****\n");
	}


//	SpuInitHot ();									// initialise spu

	sprintf(tempmess, "SOUND\\%s.VH", Filename);
	vabData=(UBYTE *)fileTempLoad(tempmess,0);

// This needs to be a tempload, because otherwise the "sample info" gets mallocced above it & we get some
// severe memory fragging.

	sprintf(tempmess,"SOUND\\%s.VB", Filename);
//	vagData=(UBYTE *)fileLoad(tempmess, &lastfilelength);
	vagData=(UBYTE *)fileTempLoad(tempmess, &lastfilelength);

	numVags = ((unsigned short *)vabData)[11];
	numProgs = ((unsigned short *)vabData)[9];
	
	if(numVags == 0)	return 0;

	vagPtr = vagData;
	vagInfo = (unsigned short *) (vabData + 2082 + (512 * numProgs));

	sampleBank[vabnum].numSamples = numVags;
//	sampleBank[vabnum].vh = vabData;	// coz it needs freeing. Not any more, it's temporary
	
//	debugPrintf("SFX: Found %d programs\n",numProgs);
//	debugPrintf("SFX: %d samples found\n",numVags);

#if (GOLDCD == NO) && (RELEASE == NO)
	sprintf(tempmess,"%s.SampleInfo", Filename);
  	sampleBank[vabnum].samples = MALLOC(sizeof(sfxSampleType) * sampleBank[vabnum].numSamples,tempmess);
#else
  	sampleBank[vabnum].samples = MALLOC(sizeof(sfxSampleType) * sampleBank[vabnum].numSamples,"SAMPLE INFO");
#endif
	if(sampleBank[vabnum].samples == NULL) return 0;

	spuAddr = SpuMalloc(lastfilelength);
  	sampleBank[vabnum].startAddr = spuAddr;
	
	if ((lastfilelength%8)!=0) 	lastfilelength += 8-(lastfilelength%8);
	sampleBank[vabnum].length = lastfilelength;


	if(spuAddr < 0x100f) debugPrintf("Sample Memory allocation failed %d,%d\n",spuAddr,lastfilelength);
//	else				 debugPrintf("Sample bank allocated at %d\n",spuAddr);



// SpuInit is done once, and that should be the lot init/start/quit-wise
//	SpuStart();									// start spu dma


//	SpuSetTransferMode(SPU_TRANSFER_BY_IO);  //more reliable than DMA transfer!!!
	SpuSetTransferMode(SPU_TRANSFER_BY_DMA);  //more reliable than DMA transfer!!!
	SpuSetTransferStartAddr(spuAddr);
	spuWrittenSize = SpuWritePartly(vagData,lastfilelength);

	if(spuWrittenSize != lastfilelength)
		debugPrintf("\nSFX: Could only upload %d bytes to SPU",spuWrittenSize);
	
	for(vagLoop = 0; vagLoop < numVags; vagLoop ++)
	{
		sampleBank[vabnum].samples[vagLoop].spuOffset = spuAddr;
		sampleBank[vabnum].samples[vagLoop].size = (*vagInfo << 3);
		sampleBank[vabnum].samples[vagLoop].pitch = DEFAULT_PITCH;
		sampleBank[vabnum].samples[vagLoop].leftVol = DEFAULT_VOLUME;
		sampleBank[vabnum].samples[vagLoop].rightVol = DEFAULT_VOLUME;
		spuAddr += (*vagInfo << 3);
//		debugPrintf("\nSFX: Sample %d, offset %d, size %d",vagLoop,sampleBank.samples[vagLoop].spuOffset - 0x1010,(*vagInfo << 3));
		vagInfo ++;
	}
	SpuIsTransferCompleted(SPU_TRANSFER_WAIT);
	if (checksoundloaded==140)printf("SOUND FAILED!!!!!!!!!!!!!!! %d,$%x\n",(int)vabnum,(int)spuAddr);
	else	debugPrintf("\nSFX: Sample upload complete\n");

// SpuInit is done once, and that should be the lot init/start/quit-wise
//	SpuQuit();									// start spu dma

	FREENULL(vagData);
	FREENULL(vabData);
	return vabnum; //SFXCtrl->nTotalVabsLoaded-1; //++;
}
/*******************************************************************************/

/////////////////////////////////////////////////////////////////////////////////
//	
//	SFXPlay
//	-------
//
//	Plays a sound on the next available voice. If this sound has already 
//	played, then switches it off first.  
//
//	All SsUtKeyOff Does Is Free a sound channel by killing the current sound
//	playing on it. So to schedule sounds properly we must know when they 
//	started and their length.
//there are 24 sound channels!
//UBYTE usethissfxchannel=0;

//void SFXShutUp(SFXHANDLE h)
//{
//	int result;
//
//	DB("Muting channel %d\n", h);
//
//	result=SsUtKeyOffV(h);
//	if(result==-1)
//		DB("Sound wouldn't mute!\n");
//
//	sfx3DQueue[h].priority=0;
//	sfx3DQueue[h].endTimer=0;
//}
/*********************************************************************************/
//OLD DONT USE!!!
//SFXHANDLE SFXPlayNME3D(int vab, int sfx, UBYTE vol, ENEMYPOS *pEnemy, UBYTE pitch, int time)
//{
//	int channel=0;
//
//	sfxPlay3D(vab,sfx,&pEnemy->pos);


/*	channel=SFXGetFreeChannel(time);

	sfx3DQueue[channel].pPos=NULL;
	sfx3DQueue[channel].pEnemy=pEnemy;
	sfx3DQueue[channel].volume=vol;
	sfx3DQueue[channel].pitch=pitch;
	sfx3DQueue[channel].vab=vab;
	sfx3DQueue[channel].sfx=sfx;
	sfx3DQueue[channel].timer=0;

	SFXSet3DChannel(channel, PLAY);
*/
//	return(channel);
//}

/**************************************************************************/

//OLD DONT USE!!!
//SFXHANDLE SFXPlay3D(int vab, int sfx, UBYTE vol, VECTOR *pObj, UBYTE pitch, int time)
//{
//	int channel=0;
//
//	channel=SFXGetFreeChannel(time);
//
//	sfx3DQueue[channel].pEnemy=NULL;
//	sfx3DQueue[channel].pPos=pObj;
//	sfx3DQueue[channel].volume=vol;
//	sfx3DQueue[channel].pitch=pitch;
//	sfx3DQueue[channel].vab=vab;
//	sfx3DQueue[channel].sfx=sfx;
//	sfx3DQueue[channel].timer=0;
//
//	SFXSet3DChannel(channel, PLAY);
//		   printf("play 3dsfx\n");
//	sfxPlay3D(vab,sfx,pObj);
//	sfxPlaySound3D(vab,sfx,pObj);
//	return(channel);
//}

/**************************************************************************
	FUNCTION:	sfxCalc3DPosition()
	PURPOSE:	calculate volume of sound at position in world
	PARAMETERS:	position, left and right volumes to return
	RETURNS:	none
**************************************************************************/


// position is a 4096'd vector
static int sfxCalc3DPosition(VECTOR *position, int *leftVol, int *rightVol, int zerodist)
{
	int cameraAngle, soundAngle, offsetAngle;
	int	distanceX, distanceY, distanceZ, distance;
	int tmpLeftVol, tmpRightVol;
	ULONG calc;

	// get the sound's distance from the camera
	distanceX = (position->vx>>12) - CamVars.camera.vpx;
	distanceY = (position->vy>>12) - CamVars.camera.vpy;
	distanceZ = (position->vz>>12) - CamVars.camera.vpz;

	calc=distanceX * distanceX + distanceY * distanceY + distanceZ * distanceZ;

	if (calc==0) distance=0;
	else {FASTSQRT(distance,calc);}
	distance>>=16;
//	distance = fast_sqrt(distanceX * distanceX + distanceZ * distanceZ) >> 16;

	// if sound is too far to be heard, don't bother with positioning
//	DB("dist = %d / %d\n",distance,zerodist);
	if(distance > zerodist)
	{
//		debugPrintf("\nsound @ %d dist, too far away!",distance);
		return 0;
	}
	

	// find the angle of the sound with respect to the camera's position
	cameraAngle = calc_angle(CamVars.camera.vrx - CamVars.camera.vpx,CamVars.camera.vrz -CamVars.camera.vpz);
	soundAngle = calc_angle((position->vx>>12) - CamVars.camera.vpx, (position->vz>>12) - CamVars.camera.vpz);
	
	offsetAngle = findShortestAngle(soundAngle & 4095, cameraAngle & 4095);

	// calculate some temporary volumes

	if(abs(offsetAngle) > 1024)					// sound is behind us
	{
		if(offsetAngle > 0)
		{
//			offsetAngle -= 2048;
			offsetAngle = 2048 - offsetAngle;	// 1024...2048
		}
		else
		{
//			offsetAngle += 2048;
			offsetAngle = -2048 - offsetAngle;
		}
	}
	
	// standard stereo panning
	tmpRightVol = (offsetAngle + 1024) * 8;
	tmpLeftVol  = 16384 - tmpRightVol;

	if(distance)
	{
		*leftVol = ((-tmpLeftVol * distance) / zerodist) + tmpLeftVol;
		*rightVol = ((-tmpRightVol * distance) / zerodist) + tmpRightVol;
	}
//	DB("leftvol = %d, rightvol = %d, dist = %d\n",*leftVol,*rightVol, distance);
	return 1;
}




// Do a stereo sfx at full volume
// (eg - level bosses)
static int sfxCalc3DAngle(VECTOR *position, int *leftVol, int *rightVol)
{
	int cameraAngle, soundAngle, offsetAngle;
	int	distanceX, distanceZ, distance;
	int tmpLeftVol, tmpRightVol;
	ULONG calc;


	// get the sound's distance from the camera
	distanceX = (position->vx>>12) - CamVars.camera.vpx;
	distanceZ = (position->vz>>12) - CamVars.camera.vpz;

	calc=distanceX * distanceX + distanceZ * distanceZ;

	if (calc==0) distance=0;
	else {FASTSQRT(distance,calc);}
	distance>>=16;
//	distance = fast_sqrt(distanceX * distanceX + distanceZ * distanceZ) >> 16;


	// find the angle of the sound with respect to the camera's position
	cameraAngle = calc_angle(CamVars.camera.vrx - CamVars.camera.vpx,CamVars.camera.vrz -CamVars.camera.vpz);
	soundAngle = calc_angle((position->vx>>12) - CamVars.camera.vpx, (position->vz>>12) - CamVars.camera.vpz);
	
	offsetAngle = findShortestAngle(soundAngle & 4095, cameraAngle & 4095);

	// calculate some temporary volumes
/*
	if(abs(offsetAngle) > 1024)					// sound is behind us
	{
		if(offsetAngle > 0)
		{
			offsetAngle -= 2048;
		}
		else
		{
			offsetAngle += 2048;
		}
	}
*/
	if(abs(offsetAngle) > 1024)					// sound is behind us
	{
		if(offsetAngle > 0)
		{
			offsetAngle = 2048 - offsetAngle;
		}
		else
		{
			offsetAngle = -2048 - offsetAngle;
		}
	}

	// standard stereo panning
	tmpRightVol = (offsetAngle + 1024) * 8;
	tmpLeftVol = 16384 - tmpRightVol;

	if(distance)
	{
		*leftVol = tmpLeftVol;
		*rightVol = tmpRightVol;
	}
//	DB("leftvol = %d, rightvol = %d, dist = %d\n",*leftVol,*rightVol, distance);
	return 1;
}


/**************************************************************************
	FUNCTION:	sfxPlay()
	PURPOSE:	Plays the requested sample
	PARAMETERS:	sample number
	RETURNS:	none
**************************************************************************/

ULONG lastVoiceUsed=0;
unsigned long sfxPlay(int vab,int sfxNum)
{
	unsigned long voiceLoop;
	ULONG j;
/*	if (gameInfo.frame < sfxFrame)
	{
		int loop;
		for (loop=0; loop<MAX_SAMPLES; loop++)
			lastSampleCall[loop] = 0;
		debugPrintf("\nreseting sound timing");
	}
	sfxFrame = gameInfo.frame;

	if (lastSampleCall[sfxNum]+2 > sfxFrame) return -1;

	lastSampleCall[sfxNum] = sfxFrame;
*/

	SFX_CHECKBANK((vab),(sfxNum));

	for(j = 0; j < 23; j++)
	{
		voiceLoop=(j+lastVoiceUsed+1)MOD 24;
		if(SpuGetKeyStatus(1 << voiceLoop) != SPU_ON)
		{
			SpuSetVoiceVolume(voiceLoop,(sampleBank[vab].samples[sfxNum].leftVol*sfxvolume)/128
					,(sampleBank[vab].samples[sfxNum].rightVol*sfxvolume)/128);	// channel, left vol, right vol,
			SpuSetVoicePitch(voiceLoop,	sampleBank[vab].samples[sfxNum].pitch);		// channel, pitch
			SpuSetVoiceStartAddr(voiceLoop, sampleBank[vab].samples[sfxNum].spuOffset);	// channel, spu offset
			SpuSetKey(SPU_ON, 1 << voiceLoop);										// on/off, 1 << channel
		  //	printf("vab %d,sfx %d, play sfx\n",vab,sfxNum);
			lastVoiceUsed=voiceLoop;
			return voiceLoop;
		}
	}
	debugPrintf("\nSFX: Run out of audio channels!");
	return -1;

}

/**************************************************************************
	FUNCTION:	sfxPlaySound3D()
	PURPOSE:	Plays the requested sound in 3D space
	PARAMETERS:	sample number, position in space
	RETURNS:	none
**************************************************************************/

ULONG sfxPlay3D(int vab,int sampleNum, VECTOR *position)
{
	int leftVol, rightVol;

	SFX_CHECKBANK(vab,sampleNum);

  	if(sfxCalc3DPosition(position, &leftVol, &rightVol,1000))
  	{
//		DB("lr = %d %d\n",leftVol,rightVol);
  		sampleBank[vab].samples[sampleNum].leftVol = leftVol;
  		sampleBank[vab].samples[sampleNum].rightVol = rightVol;
  		return sfxPlay(vab,sampleNum);
  	}
return 0;
}
/**************************************************************************/
void sfxDestroy(UBYTE vabnum)
{
	SpuReverbAttr r_attr;

//	DB("Music bank loaded = %d,vabnum=%d, samples = %8x\n",music_bank_loaded,vabnum,(int)sampleBank[vabnum].samples);

	ASSERT(sampleBank[vabnum].samples);
	if(!sampleBank[vabnum].samples)
	{
		DB(" Attempting to destroy an unused sample bank\n");
		return;
	}


	if(vabnum == 1)
		music_bank_loaded = -1;

	SpuSetTransferCallback(NULL);
	SpuSetKey(SPU_OFF,0xFFFFFFFF);
	FREE(sampleBank[vabnum].samples);	
	sampleBank[vabnum].samples = NULL;

//	FREE(sampleBank[vabnum].vh);	// done during load
	SpuFree(sampleBank[vabnum].startAddr);

	r_attr.mask = (SPU_REV_MODE);
	r_attr.mode = SPU_REV_MODE_OFF;
	SpuSetReverbModeParam (&r_attr);

// This really shouldn't be here, now should it?
//	SpuQuit();	

	SpuSetReverb(SPU_OFF);
}
/***************************************************************************/
void sfxDisplayDebug()
{
	char status[25];
	int i;
	SpuGetAllKeysStatus(status);
	for (i=0; i<24; i++)
	{
		switch (status[i])
		{
			case SPU_OFF:			status[i]='-'; break;
			case SPU_ON:			status[i]='X'; break;
			case SPU_OFF_ENV_ON:	status[i]='<'; break;
			case SPU_ON_ENV_OFF:	status[i]='>'; break;
		}
	}
	status[24]=0;
	debugPrintf("\n%s",status);
}
/***************************************************************************************/
void sfxSetVolume(int voice, int vol)
{
	if ((voice < 0) || (voice > 23)) return;
	SpuSetVoiceVolume(voice,(vol*sfxvolume)/128,(vol*sfxvolume)/128);	// channel, left vol, right vol,
}
/**************************************************************************/
void sfxSetPitch(int voice, int pitch)
{
//	if(voice<0) return;
//	if(voice>23) return;

	SpuSetVoicePitch(voice,pitch);
}
/***************************************************************************************/
void sfxStopVoice(int voice)
{
	SpuSetKey(SPU_OFF, 1 << voice);
}
/**************************************************************************/

ULONG sfxPlayNME3D(int vab,int sampleNum, ENEMYPOS *nme)
{
	int leftVol, rightVol;
	SFX_CHECKBANK(vab,sampleNum);
//	sampleNum = sampleNum & 0xff;

  	if(sfxCalc3DPosition(&nme->pos, &leftVol, &rightVol,nmeinfo[nme->type].visdist))
  	{
  		sampleBank[vab].samples[sampleNum].leftVol = leftVol>>1;
  		sampleBank[vab].samples[sampleNum].rightVol = rightVol>>1;
   		return sfxPlay(vab,sampleNum);
  	}
	return 0;
}

ULONG sfxPlayFull3D(int vab,int sampleNum, VECTOR *pos)
{
	int leftVol, rightVol;
	SFX_CHECKBANK(vab,sampleNum);

  	if(sfxCalc3DAngle(pos, &leftVol, &rightVol))
  	{
  		sampleBank[vab].samples[sampleNum].leftVol = leftVol;
  		sampleBank[vab].samples[sampleNum].rightVol = rightVol;
  
  		return sfxPlay(vab,sampleNum);
  	}
	return 0;
}
ULONG sfxPlayFullVol3D(int vab,int sampleNum, VECTOR *pos, int vol)
{
	int leftVol, rightVol;

	SFX_CHECKBANK(vab,sampleNum);
  	if(sfxCalc3DAngle(pos, &leftVol, &rightVol))
  	{
  		sampleBank[vab].samples[sampleNum].leftVol  = (leftVol * vol) >>8;
  		sampleBank[vab].samples[sampleNum].rightVol = (rightVol * vol) >>8;
  
  		return sfxPlay(vab,sampleNum);
  	}
	return 0;
}


ULONG sfxPlayVol3D(int vab,int sampleNum, VECTOR *position, int vol)
{
	int leftVol, rightVol;

	SFX_CHECKBANK(vab,sampleNum);
  	if(sfxCalc3DPosition(position, &leftVol, &rightVol,1000))
  	{
  		sampleBank[vab].samples[sampleNum].leftVol  = (leftVol * vol) >>8;
  		sampleBank[vab].samples[sampleNum].rightVol = (rightVol * vol) >>8;
  
  		return sfxPlay(vab,sampleNum);
  	}
return 0;
}


// play a sound effect that was parsed in as a "platform move" or whatever
void sfxPlayParsed(VECTOR *pos,short sfx,short pitch,short vol)
{
	int bank,pit;
	int leftVol, rightVol;

//	DB("Playing LND sample %d\n",sfx);

	if(((sfx) >> 8) != (GENERIC+1) )
	{
		bank = levelFX;
	}
	else
	{
		bank = globalFX;
	}



	{
		int world;
// feck, I got the worlds in the wrong order
		static int remaps[] = {0,1,2,3,6,4,5,7,8};

		static int maxes[] =
		{
			-1,
			NUM_HUB_FX - SFX_HUB_BASE,
			NUM_ATLANTIS_FX - SFX_AT_BASE,
			NUM_CARNIVAL_FX - SFX_CA_BASE,
			NUM_FORTRESS_FX - SFX_FF_BASE,
			NUM_PIRATES_FX - SFX_PI_BASE,
			NUM_PREHISTORIC_FX - SFX_PR_BASE,
//			NUM_FORTRESS_FX - SFX_FF_BASE,
			NUM_SPACE_FX - SFX_SP_BASE,
			SFX_GE_ROTORBLADE+1-SFX_GENERIC_BASE
		};

		world = sfx>>8;
		if(world <= 0 || world > 8 || ((sfx & 0xff) > maxes[world]))
		{
			DB("LND sample is buggered: sfx number %d\n", sfx);
			return;
		}

		world = remaps[world];
		sfx = (sfx & 0xff) | (world << 8);

	}



	SFX_CHECKBANK(bank,sfx);
	sfx &= 0xff;

//	DB("Playing sfx %d pitch %d vol %d\n",sfx,pitch, vol);
	pit=(((int)pitch) * DEFAULT_PITCH) >> 7;
	sfxSetSamplePitch(bank,sfx,pit);

  	if(sfxCalc3DPosition(pos, &leftVol, &rightVol,1200))
  	{
//		DB("lr = %d %d\n",leftVol,rightVol);
  		sampleBank[bank].samples[sfx].leftVol = (leftVol * (int)vol) >> 7;
  		sampleBank[bank].samples[sfx].rightVol = (rightVol * (int)vol) >> 7;
  		sfxPlay(bank,sfx);
  	}

// just in case someone decides to play it normally
	sfxSetSamplePitch(bank, sfx, DEFAULT_PITCH);
	sfxSetSampleVolume(bank, sfx,DEFAULT_VOLUME);
}


void sfxPlayAmbient(AMBIENTSOUNDSTR *snd)
{
	int bank,pit;
	int leftVol, rightVol;
	int sfx = snd->def.num;
	VECTOR pos;

	pos.vx = ((int)( snd->def.x)) << 12;
	pos.vy = ((int)(-snd->def.y)) << 12;
	pos.vz = ((int)(-snd->def.z)) << 12;

//				DB("ambient sound %d\n",snd->def.num);

//	DB("Playing LND sample %d\n",sfx);

	if(((sfx) >> 8) != (GENERIC+1) )
	{
		bank = levelFX;
	}
	else
	{
		bank = globalFX;
	}



	{
		int world;
// feck, I got the worlds in the wrong order
		static int remaps[] = {0,1,2,3,6,4,5,7,8};

		static int maxes[] =
		{
			-1,
			NUM_HUB_FX - SFX_HUB_BASE,
			NUM_ATLANTIS_FX - SFX_AT_BASE,
			NUM_CARNIVAL_FX - SFX_CA_BASE,
			NUM_FORTRESS_FX - SFX_FF_BASE,
			NUM_PIRATES_FX - SFX_PI_BASE,
			NUM_PREHISTORIC_FX - SFX_PR_BASE,
//			NUM_FORTRESS_FX - SFX_FF_BASE,
			NUM_SPACE_FX - SFX_SP_BASE,
			SFX_GE_ROTORBLADE+1-SFX_GENERIC_BASE
		};

		world = sfx>>8;
		if(world <= 0 || world > 8 || ((sfx & 0xff) > maxes[world]))
		{
			DB("LND sample is buggered: sfx number %d\n", sfx);
			return;
		}

		world = remaps[world];
		sfx = (sfx & 0xff) | (world << 8);

	}



	SFX_CHECKBANK(bank,sfx);
	sfx &= 0xff;

//	DB("Playing sfx %d pitch %d vol %d\n",sfx,pitch, vol);
	pit=(((int)snd->def.pitch) * DEFAULT_PITCH) >> 7;
	sfxSetSamplePitch(bank,sfx,pit);

  	if(sfxCalc3DPosition(&pos, &leftVol, &rightVol,snd->def.radius))
  	{
//		DB("lr = %d %d\n",leftVol,rightVol);
  		sampleBank[bank].samples[sfx].leftVol = (leftVol * (int)snd->def.volume) >> 7;
  		sampleBank[bank].samples[sfx].rightVol = (rightVol * (int)snd->def.volume) >> 7;
  		sfxPlay(bank,sfx);
  	}

// just in case someone decides to play it normally
	sfxSetSamplePitch(bank, sfx, DEFAULT_PITCH);
	sfxSetSampleVolume(bank, sfx,DEFAULT_VOLUME);
}
