#include <dsound.h>

#ifdef __GNUC__ //MinGW

//Simple start and end structure, set as volatile so perhaps we can use -O1+ later
#define ASM_BEGIN asm volatile (
#define ASM_END );
//All commands need quotes and a newline and tab. C vars are _ prefixed
#define ASM_COMMAND(line) #line"\n\t"
#define ASM_COMMAND2(line, part2) #line", "#part2"\n\t"
#define ASM_COMMAND3(line, var) #line", _"#var"\n\t"
//Just for the prefix
#define ASM_CALL(func) ASM_COMMAND(call _ ## func)
//A function call is a simple register backup, call, restore
#define asm_call(func) ASM_BEGIN \
ASM_COMMAND(pushad) \
ASM_CALL(func) \
ASM_COMMAND(popad) \
ASM_END

#else //MSVC

#define ASM_BEGIN _asm {
#define ASM_END };

//MSVC is all straight foward about these
#define ASM_COMMAND(line) line
#define ASM_COMMAND2(line, part2) line, part2
#define ASM_COMMAND3(line, var) ASM_COMMAND2(line, var)
//Next is not really special either
#define ASM_CALL(func) ASM_COMMAND(call func)
//Using this weird style because of MSVCs bad parsing
#define asm_call(func) _asm pushad \
_asm call func \
_asm popad

#endif



//extern unsigned char SPCDisable, spcon, FPSOn, FPSAtStart;
//unsigned char DSPDisable;

int SoundEnabled=1;

#define BYTE   unsigned char
#define WORD   unsigned short
#define DWORD  unsigned long

//LPDIRECTSOUND8          lpDirectSound = NULL;
//LPDIRECTSOUNDBUFFER8    lpSoundBuffer = NULL;
IDirectSoundBuffer     *lpPrimaryBuffer = NULL;
DSBUFFERDESC dsbd;

LPVOID lpvPtr1;
DWORD dwBytes1;
LPVOID lpvPtr2;
DWORD dwBytes2;

extern "C" {
extern BYTE cfgsoundon;
extern BYTE StereoSound;
extern DWORD SoundQuality;
}

extern "C" { extern unsigned char PrimaryBuffer; }

extern "C" {
DWORD LastUsedPos=0;
}


DWORD FirstSound=1;

int UsePrimaryBuffer=0;
DWORD SoundBufferSize=1024*18;




extern "C" void CheckTimers(void);
extern "C" void WinUpdateDevices();

int DSPBuffer;

BYTE PrevStereoSound;
DWORD PrevSoundQuality;
extern LPDIRECTSOUND8  m_pDSound;
extern "C" int dprintf(char *Format, ...);


BOOL InitSound()
{

	dprintf("---------Init sound 1\n");
	WAVEFORMATEX wfx;
	//DSBCAPS dsbcaps;

	SoundEnabled = 0;

	if (cfgsoundon == 0) { dprintf("---------Init sound -1\n"); return FALSE; }

	//StereoSound=1;
	PrevSoundQuality=SoundQuality;
	PrevStereoSound=StereoSound;
	UsePrimaryBuffer=1;
	PrimaryBuffer=1;
	
	
	if (true)
	{

		//lpDirectSound->Initialize(NULL);// Initialize(NULL);
		dprintf("---------Init sound 2\n");
		if (PrimaryBuffer)
		{
			dprintf("---------Init sound 3\n");
			if (false)
			{
				dprintf("---------Init sound 4\n");
				if (false)
					return FALSE;
			}
			else {
				dprintf("---------Init sound 5\n");
				UsePrimaryBuffer=1;
			}
		}
		else
		{
			if (false)
			{
				if (false)
					return FALSE;
			}
			else 
			{
				dprintf("---------Init sound 6\n");
				UsePrimaryBuffer=0;
			}
		}
	}
	else
	{
		dprintf("---------Init sound 7.5\n");
		return FALSE;
	}
    

	wfx.wFormatTag = WAVE_FORMAT_PCM;

	switch (SoundQuality)
	{
	case 0:
		dprintf("---------Init sound 8000\n");
		wfx.nSamplesPerSec = 8000;
		SoundBufferSize=1024*2;
		break;
	case 1:
		dprintf("---------Init sound 11025\n");
		wfx.nSamplesPerSec = 11025;
		SoundBufferSize=1024*2;
		break;
	case 2:
		dprintf("---------Init sound 22050\n");
		wfx.nSamplesPerSec = 22050;
		SoundBufferSize=1024*4;
		break;
	case 3:
		dprintf("---------Init sound 44100\n");
		wfx.nSamplesPerSec = 44100;
		SoundBufferSize=1024*8;
		break;
	case 4:
		dprintf("---------Init sound 16000\n");
		wfx.nSamplesPerSec = 16000;
		SoundBufferSize=1024*4;
		break;
	case 5:
		dprintf("---------Init sound 32000\n");
		wfx.nSamplesPerSec = 32000;
		SoundBufferSize=1024*8;
		break;
	case 6:
		dprintf("---------Init sound 48000\n");
		wfx.nSamplesPerSec = 48000;
		SoundBufferSize=1024*8;
		break;
	default:
		dprintf("---------Init sound default 11025\n");
		wfx.nSamplesPerSec = 11025;
		SoundBufferSize=1024*2;
	}

	if (StereoSound==1)
	{
		dprintf("---------Init sound 7\n");
		wfx.nChannels = 2;
		wfx.nBlockAlign = 4;
		SoundBufferSize*=2;
	}
	else
	{
		dprintf("---------Init sound 8\n");
		wfx.nChannels = 1;
		wfx.nBlockAlign = 2;
	}

	wfx.wBitsPerSample = 16;
	wfx.nAvgBytesPerSec = wfx.nSamplesPerSec * wfx.nBlockAlign;
	wfx.cbSize=0;

	memset(&dsbd, 0, sizeof(DSBUFFERDESC));
	dsbd.dwSize = sizeof(DSBUFFERDESC);
	//dsbd.dwFlags = 0;//DSBCAPS_PRIMARYBUFFER;//DSBCAPS_GETCURRENTPOSITION2 | DSBCAPS_STICKYFOCUS;
	//if(UsePrimaryBuffer) dsbd.dwFlags |= DSBCAPS_PRIMARYBUFFER;
	dsbd.dwBufferBytes = SoundBufferSize;//UsePrimaryBuffer ? 0 : SoundBufferSize;
	//dsbd.lpwfxFormat = UsePrimaryBuffer ? NULL : &wfx;
    dsbd.lpwfxFormat = &wfx;

	if(m_pDSound == NULL) { dprintf("Direct Sound is NULL\n"); return FALSE; }

	if (DS_OK == m_pDSound->CreateSoundBuffer(&dsbd, &lpPrimaryBuffer, NULL))
	{
		dprintf("---------Init sound 9\n");
		if(!UsePrimaryBuffer)
		{
			if (true)
			{
				dprintf("---------Init sound 10\n");
				//if (DS_OK != lpSoundBuffer->Play(0,0,DSBPLAY_LOOPING))
				//{

				//	return FALSE;
				//}
			}
			else return FALSE;
		}
		else
		{
			dprintf("---------Init sound 11\n");
			//lpPrimaryBuffer->SetFormat(&wfx);
			//dsbcaps.dwSize=sizeof(DSBCAPS);
			//lpPrimaryBuffer->GetCaps(&dsbcaps);
			//SoundBufferSize=dsbcaps.dwBufferBytes;

			dprintf("Before buffer zero\n");
			void *mema=NULL,*memb=NULL;
            DWORD sizea=0,sizeb=0;
            lpPrimaryBuffer->Lock(0,SoundBufferSize, &mema, &sizea, &memb,&sizeb, 0);
            memset(mema,0,SoundBufferSize);
            lpPrimaryBuffer->Unlock(mema,sizea, memb,sizeb);

			dprintf("After buffer zero\n");
			if (DS_OK != lpPrimaryBuffer->Play(0,0,DSBPLAY_LOOPING))
			{
				dprintf("---------Init sound 12\n");
				return FALSE;
			}
		}

		dprintf("---------Init sound 13\n");
		SoundEnabled=1;
		FirstSound=0;
		return TRUE;
	}
	else
	{
		dprintf("---------Init sound 14\n");
		return FALSE;
	}
	dprintf("---------Init sound shouldnt bre here\n");
}

BOOL ReInitSound()
{
	return true;

    /* 
   

   UsePrimaryBuffer=1;
   PrimaryBuffer=1;

   WAVEFORMATEX wfx;
	//DSBCAPS dsbcaps;

   //if (lpSoundBuffer)
   //{
   //   lpSoundBuffer->Stop();
   //   lpSoundBuffer->Release();
   //   lpSoundBuffer = NULL;
   //}

   if (lpPrimaryBuffer)
   {
      lpPrimaryBuffer->Stop();
      lpPrimaryBuffer->Release();
      lpPrimaryBuffer = NULL;
   }

   //if (cfgsoundon == 0)
   //{
      //SoundEnabled = 0;
      //ReleaseDirectSound();
      //return FALSE;
   //}
   else if (SoundEnabled == 0)
      return InitSound();

   SoundEnabled = 0;

   PrevSoundQuality=SoundQuality;
   PrevStereoSound=StereoSound;

   wfx.wFormatTag = WAVE_FORMAT_PCM;

   switch (SoundQuality)
   {
      case 0:
         wfx.nSamplesPerSec = 8000;
         SoundBufferSize=1024*2;
         break;
      case 1:
         wfx.nSamplesPerSec = 11025;
         SoundBufferSize=1024*2;
         break;
      case 2:
         wfx.nSamplesPerSec = 22050;
         SoundBufferSize=1024*4;
         break;
      case 3:
         wfx.nSamplesPerSec = 44100;
         SoundBufferSize=1024*8;
         break;
      case 4:
         wfx.nSamplesPerSec = 16000;
         SoundBufferSize=1024*4;
         break;
      case 5:
         wfx.nSamplesPerSec = 32000;
         SoundBufferSize=1024*8;
         break;
      case 6:
         wfx.nSamplesPerSec = 48000;
         SoundBufferSize=1024*8;
         break;
      default:
         wfx.nSamplesPerSec = 11025;
         SoundBufferSize=1024*2;
  }

   if (StereoSound==1)
   {
      wfx.nChannels = 2;
      wfx.nBlockAlign = 4;
      SoundBufferSize*=2;
   }
   else
   {
      wfx.nChannels = 1;
      wfx.nBlockAlign = 2;
   }

   wfx.wBitsPerSample = 16;
   wfx.nAvgBytesPerSec = wfx.nSamplesPerSec * wfx.nBlockAlign;
   wfx.cbSize=0;

   memset(&dsbd, 0, sizeof(DSBUFFERDESC));
   dsbd.dwSize = sizeof(DSBUFFERDESC);
   //dsbd.dwFlags = 0;//DSBCAPS_GETCURRENTPOSITION2 | DSBCAPS_STICKYFOCUS;
	//if(UsePrimaryBuffer) dsbd.dwFlags |= DSBCAPS_PRIMARYBUFFER;
   dsbd.dwBufferBytes = SoundBufferSize;// UsePrimaryBuffer ? 0 : SoundBufferSize;
   dsbd.lpwfxFormat = &wfx;//UsePrimaryBuffer ? NULL : &wfx;

   if (DS_OK == m_pDSound->CreateSoundBuffer(&dsbd, &lpPrimaryBuffer, NULL))
	{
		if(!UsePrimaryBuffer)
		{
	      if (true)
	      {
		      //if (DS_OK != lpSoundBuffer->Play(0,0,DSBPLAY_LOOPING))
		      //{
		      //   return FALSE;
		      //}
			}
			else return FALSE;
		}
		else
		{
			//lpPrimaryBuffer->SetFormat(&wfx);
			//dsbcaps.dwSize=sizeof(DSBCAPS);
			//lpPrimaryBuffer->GetCaps(&dsbcaps);
			//SoundBufferSize=dsbcaps.dwBufferBytes;

	      if (DS_OK != lpPrimaryBuffer->Play(0,0,DSBPLAY_LOOPING))
	      {
			//  dprintf("Fai;ed
	         return FALSE;
	      }
		}

      SoundEnabled=1;
      FirstSound=0;
      return TRUE;
   }
   else
   {
      return FALSE;
   }
   
   return TRUE;
   */
}

extern unsigned char MMXSupport;

extern "C" {
extern unsigned char spcon;
extern unsigned char soundon;
extern unsigned char DSPDisable;
extern unsigned char SPCDisable;
extern unsigned char cfgSoundQuality;
extern unsigned char cfgStereoSound;
}


extern "C" setSound();

int i;
DWORD T36HZEnabled=0;


extern "C" {
short Buffer[1800*2];
short *Sound;

DWORD CurrentPos;
DWORD WritePos;

extern void SoundProcess();
extern int DSPBuffer;
int * DSPBuffer1;

extern "C" {
volatile int SPCSize;
volatile int buffer_ptr;
}

void UpdateVFrame(void)
{
	//dprintf("UpdateVFrame: soundon: %d, spcon: %d, DSPDisable: %d, SPCDisable: %d, StereoSound: %d, cfgSoundQuality: %d, cfgStereoSound %d, cfgsoundon %d\n", soundon, spcon, DSPDisable, SPCDisable, StereoSound, cfgSoundQuality, cfgStereoSound, cfgsoundon);
  
  
  int DataNeeded;
  SPCSize=256;

  if (StereoSound==1) SPCSize=256;

  WinUpdateDevices();
  CheckTimers();

  
   
  if (SoundEnabled == 0) { dprintf("SOUND NOT ENABLED!!!!!!!!!!!!!!!!!!!!\n"); return; }

  lpPrimaryBuffer->GetCurrentPosition(&CurrentPos,&WritePos);

  if (LastUsedPos <= CurrentPos)
    DataNeeded=CurrentPos-LastUsedPos;
  else
    DataNeeded=SoundBufferSize - LastUsedPos + CurrentPos;

  DataNeeded/=(SPCSize*2);
  DataNeeded*=(SPCSize*2);

 // dprintf("soundon: %d, spcon: %d, DSPDisable: %d, SPCDisable: %d, StereoSound: %d, cfgSoundQuality: %d, cfgStereoSound %d, cfgsoundon %d\n", soundon, spcon, DSPDisable, SPCDisable, StereoSound, cfgSoundQuality, cfgStereoSound, cfgsoundon);
 // setSound();
 
  
  while (DataNeeded>0)
  {
    
	//dprintf("Before: soundon: %d, spcon: %d, DSPDisable: %d, SPCDisable: %d, StereoSound: %d, cfgSoundQuality: %d, cfgStereoSound %d, cfgsoundon %d\n", soundon, spcon, DSPDisable, SPCDisable, StereoSound, cfgSoundQuality, cfgStereoSound, cfgsoundon);
    asm_call(SoundProcess);
	//dprintf("After: soundon: %d, spcon: %d, DSPDisable: %d, SPCDisable: %d, StereoSound: %d, cfgSoundQuality: %d, cfgStereoSound %d, cfgsoundon %d\n", soundon, spcon, DSPDisable, SPCDisable, StereoSound, cfgSoundQuality, cfgStereoSound, cfgsoundon);
	//setSound();

	




    DSPBuffer1=(int *)&DSPBuffer;

    buffer_ptr = (int)&Buffer[0];

	//for(int i2 = 0; i2 < 512; i2++) {
	//	dprintf("0x%x ", Buffer[i2]);
	//}
	//dprintf("\n");
	for(i=0;i<SPCSize;i++)
    {
          Buffer[i]=DSPBuffer1[i];
          if (DSPBuffer1[i]>32767)Buffer[i]=32767;
          if (DSPBuffer1[i]<-32767)Buffer[i]=-32767;
    }

	lpPrimaryBuffer->Lock(LastUsedPos,SPCSize*2, &lpvPtr1, &dwBytes1, &lpvPtr2, &dwBytes2, 0);
    Sound=(short *)lpvPtr1;
    memcpy(lpvPtr1, &Buffer[0], dwBytes1); if (NULL != lpvPtr2) memcpy(lpvPtr2, &Buffer[0]+dwBytes1, dwBytes2);
    lpPrimaryBuffer->Unlock(lpvPtr1, dwBytes1, lpvPtr2, dwBytes2);
    LastUsedPos+=SPCSize*2;
    if (LastUsedPos==SoundBufferSize) LastUsedPos=0;
    DataNeeded-=(SPCSize*2);
  }

 // dprintf("U - End: soundon: %d, spcon: %d, DSPDisable: %d, SPCDisable: %d, StereoSound: %d, cfgSoundQuality: %d, cfgStereoSound %d, cfgsoundon %d\n", soundon, spcon, DSPDisable, SPCDisable, StereoSound, cfgSoundQuality, cfgStereoSound, cfgsoundon);
  //setSound();
}


}


