////////////////////////////////////////////////////////////////////////////////
// Audio
////////////////////////////////////////////////////////////////////////////////
//
// Sound information thanks to toshi (wscamp wonderswan emulator)
// Note that sound is far from perfect for now.
////////////////////////////////////////////////////////////////////////////////

#include "./s2d/s2d.h"
using namespace s2d;

#include "../inc/rom.h"
#include "../inc/nec.h"
#include "../inc/ws.h"
#include "../inc/io.h"
#include "../inc/audio.h"

#define SNDP ws_ioRam[0x80]  
#define SNDV ws_ioRam[0x88]  
#define SNDSWP ws_ioRam[0x8C]  
#define SWPSTP ws_ioRam[0x8D]  
#define NSCTL ws_ioRam[0x8E]  
#define WAVDTP ws_ioRam[0x8F]  
#define SNDMOD ws_ioRam[0x90]  
#define SNDOUT ws_ioRam[0x91]  
#define PCSRL ws_ioRam[0x92]  
#define PCSRH ws_ioRam[0x93]  
#define DMASL ws_ioRam[0x40]  
#define DMASH ws_ioRam[0x41]  
#define DMASB ws_ioRam[0x42]  
#define DMADB ws_ioRam[0x43]  
#define DMADL ws_ioRam[0x44]  
#define DMADH ws_ioRam[0x45]  
#define DMACL ws_ioRam[0x46]  
#define DMACH ws_ioRam[0x47]  
#define DMACTL ws_ioRam[0x48]  
#define SDMASL ws_ioRam[0x4A]  
#define SDMASH ws_ioRam[0x4B]  
#define SDMASB ws_ioRam[0x4C]  
#define SDMACL ws_ioRam[0x4E]  
#define SDMACH ws_ioRam[0x4F]  
#define SDMACTL ws_ioRam[0x52]  

#define BPS   22050
#define BPSMAX  AUDIO_MAX_FREQUENCY
#define BPSMIN  AUDIO_MIN_FREQUENCY
#define BUFSIZE  1024
#define BUFSIZEN 0x10000
#define BUFSIZEP 159
#define PCMNUM  100
#define POFF  128
#define PDIV  3
#define PH   POFF+PDIV*8
#define PL   POFF-PDIV*7

int  WaveMap; 
int  ChPerInit;       
int  SwpTime;       
int  SwpStep;       
int  SwpCurPeriod;      

int  MainVol;       

int  ChCurVol[6]={-1,-1,-1,-1,-1,-1}; 
int  ChCurPer[6]={-1,-1,-1,-1,-1,-1}; 
long ChCurPan[6]={-1,-1,-1,-1,-1,-1}; 

unsigned char PData[4][BUFSIZE];  
unsigned char PDataP[BUFSIZEP<<4];

unsigned char PDataN[8][BUFSIZEN];  

int RandData[BUFSIZEN];     

int CntSwp=0;       
int PcmWrPos=0;       

const long TblChVol[16]={    // n/15 n=0~15
	-10000,-2352,-1750,-1398,-1148,-954,-796,-662,
	-546,-444,-352,-269,-194,-124,-60,0
};

const long TblMainVol[4]={    // 1,1/2,1/4,1/8
	0,-602,-1204,-1806
};

/// audio player
AudioPlayer* m_pAudioPlayer;
AudioData* m_pAudioData;
bool m_bUseAudio;
s32 m_AudioCnt;
/// end audio

UINT32  ws_audio_channel_isPlaying[6];

static unsigned int ws_audio_log;

//--------------------------------------------------------------------------------------------------------
void ws_audio_init(void)
{
	m_pAudioData = new AudioData[6];

	ws_audio_log=0;
	ws_audio_seal_init();
	ws_audio_reset();
}
//--------------------------------------------------------------------------------------------------------
void ws_audio_reset(void)
{
	WaveMap=-1;
	for (int i=0;i<6;i++)
	{
		ws_audio_stop_channel(i);
		ws_audio_play_channel(i);
		ws_audio_set_channel_frequency(i,0);
		if (i!=4) 
			ws_audio_set_channel_pan(i,0,0);
		ws_audio_clear_channel(i);
	}
	ws_audio_set_channel_frequency(4,0);
	ws_audio_set_channel_frequency(4,1792);
}
//--------------------------------------------------------------------------------------------------------
void ws_audio_port_write(DWORD port,UINT8 value)
{
	int n,i,j,k,b;

	switch (port)
	{
	case 0x48: if (value&0x80)
			   {
				   n=(DMACH<<8)|DMACL;
				   i=(DMASB<<16)|(DMASH<<8)|DMASL;
				   j=(DMADH<<8)|DMADL;
				   for(k=0;k<n;k++)
				   {
					   b=cpu_readmem20(i);
					   cpu_writemem20(j,b);
					   i++;
					   j++;
				   }
				   n=0;
				   DMASB=(UINT8)((i>>16)&0xFF);
				   DMASH=(UINT8)((i>>8)&0xFF);
				   DMASL=(UINT8)(i&0xFF);
				   DMADB=(UINT8)((j>>16)&0xFF);
				   DMADH=(UINT8)((j>>8)&0xFF);
				   DMADL=(UINT8)(j&0xFF);
				   DMACH=(UINT8)((n>>8)&0xFF);
				   DMACL=(UINT8)(n&0xFF);
				   value&=0x7F;
			   }
			   break;
	case 0x80:
	case 0x81: i=(((unsigned int)ws_ioRam[0x81])<<8)+((unsigned int)ws_ioRam[0x80]);
		ws_audio_set_channel_frequency(0,i);
		break;
	case 0x82:
	case 0x83: i=(((unsigned int)ws_ioRam[0x83])<<8)+((unsigned int)ws_ioRam[0x82]);
		ws_audio_set_channel_frequency(1,i);
		break;
	case 0x84:
	case 0x85: i=(((unsigned int)ws_ioRam[0x85])<<8)+((unsigned int)ws_ioRam[0x84]);
		ws_audio_set_channel_frequency(2,i);
		break;
	case 0x86:
	case 0x87: i=(((unsigned int)(ws_ioRam[0x87]&0x07))<<8)+((unsigned int)ws_ioRam[0x86]);
		ws_audio_set_channel_frequency(5,i);
		ws_audio_set_channel_frequency(3,i);
		break;
	case 0x88:
		ws_audio_set_channel_pan(0,(value&0xF0)>>4,value&0x0F);
		break;
	case 0x89:
		ws_audio_set_channel_pan(1,(value&0xF0)>>4,value&0x0F);
		break;
	case 0x8A:
		ws_audio_set_channel_pan(2,(value&0xF0)>>4,value&0x0F);
		break;
	case 0x8B:
		ws_audio_set_channel_pan(5,(value&0xF0)>>4,value&0x0F);
		ws_audio_set_channel_pan(3,(value&0xF0)>>4,value&0x0F);
		break;
	case 0x8C:
		SwpStep=(signed char)value;
		break;
	case 0x8D:
		SwpTime=(((unsigned int)value)+1)<<5;
		break;
	case 0x8E:
		ws_audio_set_channel_pdata(5,value&0x07);
		break;
	case 0x8F:
		WaveMap=((unsigned int)value)<<6;
		break;
	case 0x90:
		if (value&0x01)
			ws_audio_play_channel(0);
		else 
			ws_audio_stop_channel(0);

		if ((value&0x22)==0x02)
			ws_audio_play_channel(1);
		else 
			ws_audio_stop_channel(1);

		if (value&0x04)
			ws_audio_play_channel(2);
		else 
			ws_audio_stop_channel(2);

		if ((value&0x88)==0x08)
			ws_audio_play_channel(3);
		else 
			ws_audio_stop_channel(3);


		if (value&0x88)
			ws_audio_play_channel(5);
		else 
			ws_audio_stop_channel(5);
		break;
	case 0x91:
		MainVol=0;
		value|=0x80;
		break;
	case 0x92:
	case 0x93:
		break;
	case 0x94:
		MainVol=(value&0x0f)>>2;
		ws_audio_set_channel_pan(5,value&0x0F,value&0x0F);
		break;
	}
	ws_ioRam[port]=value;
}
//--------------------------------------------------------------------------------------------------------
UINT8 ws_audio_port_read(UINT8 port)
{
	return(ws_ioRam[port]);
}
//--------------------------------------------------------------------------------------------------------
void ws_audio_done(void)
{
	ws_audio_seal_done();
}
//--------------------------------------------------------------------------------------------------------
unsigned int ws_audio_mrand(unsigned int Degree)
{
#define BIT(n) (1<<n)
	typedef struct {
		unsigned int N;
		int InputBit;
		int Mask;
	} POLYNOMIAL;

	static POLYNOMIAL TblMask[]=
	{
		{ 2,BIT(2) ,BIT(0)|BIT(1)},
		{ 3,BIT(3) ,BIT(0)|BIT(1)},
		{ 4,BIT(4) ,BIT(0)|BIT(1)},
		{ 5,BIT(5) ,BIT(0)|BIT(2)},
		{ 6,BIT(6) ,BIT(0)|BIT(1)},
		{ 7,BIT(7) ,BIT(0)|BIT(1)},
		{ 8,BIT(8) ,BIT(0)|BIT(2)|BIT(3)|BIT(4)},
		{ 9,BIT(9) ,BIT(0)|BIT(4)},
		{10,BIT(10),BIT(0)|BIT(3)},
		{11,BIT(11),BIT(0)|BIT(2)},
		{12,BIT(12),BIT(0)|BIT(1)|BIT(4)|BIT(6)},
		{13,BIT(13),BIT(0)|BIT(1)|BIT(3)|BIT(4)},
		{14,BIT(14),BIT(0)|BIT(1)|BIT(4)|BIT(5)},
		{15,BIT(15),BIT(0)|BIT(1)},
		{NULL,NULL,NULL},
	};

	static POLYNOMIAL *pTbl=TblMask;
	static int ShiftReg=pTbl->InputBit-1;
	int XorReg=0;
	int Masked;

	if(pTbl->N!=Degree)
	{
		pTbl=TblMask;
		while(pTbl->N)
		{
			if(pTbl->N==Degree)
			{
				break;
			}
			pTbl++;
		}
		if(!pTbl->N)
		{
			pTbl--;
		}

		ShiftReg&=pTbl->InputBit-1;
		if(!ShiftReg)
		{
			ShiftReg=pTbl->InputBit-1;
		}
	}

	Masked=ShiftReg&pTbl->Mask;
	while(Masked)
	{
		XorReg^=Masked&0x01;
		Masked>>=1;
	}

	if(XorReg)
	{
		ShiftReg|=pTbl->InputBit;
	}
	else
	{
		ShiftReg&=~pTbl->InputBit;
	}
	ShiftReg>>=1;

	return ShiftReg;
}
//--------------------------------------------------------------------------------------------------------
int ws_audio_seal_init(void)
{
	int   i, j;
	AUDIOINFO info;
	AUDIOCAPS caps;
	UINT  rc;
	UINT  nDevId;

	s2d::Log::Output("audio: using audio library\n");

	// create the 4 pcm channels
	for (i=0;i<4;i++)
	{
		// create the channel
		// ACreateAudioVoice(&ws_audio_pcm_voice[i]);
		// ASetVoiceVolume  ( ws_audio_pcm_voice[i], AUDIO_MAX_VOLUME);
		// ASetVoicePanning ( ws_audio_pcm_voice[i], AUDIO_MIN_PANNING);

		// create a looped sound buffer
		// ws_audio_pcm_wave[i].nSampleRate = info.nSampleRate;
		// ws_audio_pcm_wave[i].dwLength  = BUFSIZE;
		// ws_audio_pcm_wave[i].dwLoopStart = 0;
		// ws_audio_pcm_wave[i].dwLoopEnd  = ws_audio_pcm_wave[i].dwLength;
		// ws_audio_pcm_wave[i].wFormat  = AUDIO_FORMAT_8BITS | AUDIO_FORMAT_MONO | AUDIO_FORMAT_LOOP;

		// ACreateAudioData(&ws_audio_pcm_wave[i]);

		// channel is not playing yet
		// ws_audio_channel_isPlaying[i]=0;

		// clear the channel
		// ws_audio_clear_channel(i);
	}

	// create the noise channel
	{
		// create the channel
		// ACreateAudioVoice(&ws_audio_noise_voice);
		// ASetVoiceVolume  ( ws_audio_noise_voice, AUDIO_MAX_VOLUME);
		// ASetVoicePanning ( ws_audio_noise_voice, AUDIO_MAX_PANNING>>1);


		// create a looped sound buffer
		// ws_audio_noise_wave.nSampleRate = info.nSampleRate;
		// ws_audio_noise_wave.dwLength = (BUFSIZEP<<4);
		// ws_audio_noise_wave.dwLoopStart = 0;
		// ws_audio_noise_wave.dwLoopEnd = ws_audio_noise_wave.dwLength;
		// ws_audio_noise_wave.wFormat  = AUDIO_FORMAT_8BITS | AUDIO_FORMAT_MONO | AUDIO_FORMAT_LOOP;

		// ACreateAudioData(&ws_audio_noise_wave);

		// channel is not playing yet
		// ws_audio_channel_isPlaying[4]=0;

		// clear the channel
		// ws_audio_clear_channel(4);
	}

	// create the sweep channel
	{
		// create the channel
		// ACreateAudioVoice(&ws_audio_sweep_voice);
		// ASetVoiceVolume  ( ws_audio_sweep_voice, AUDIO_MAX_VOLUME);
		// ASetVoicePanning ( ws_audio_sweep_voice, AUDIO_MAX_PANNING);

		// create a looped sound buffer
		// ws_audio_sweep_wave.nSampleRate = info.nSampleRate;
		// ws_audio_sweep_wave.dwLength = BUFSIZEN;
		// ws_audio_sweep_wave.dwLoopStart = 0;
		// ws_audio_sweep_wave.dwLoopEnd = ws_audio_sweep_wave.dwLength;
		// ws_audio_sweep_wave.wFormat  = AUDIO_FORMAT_8BITS | AUDIO_FORMAT_MONO | AUDIO_FORMAT_LOOP;

		// ACreateAudioData(&ws_audio_sweep_wave);

		// channel is not playing yet
		// ws_audio_channel_isPlaying[5]=0;

		// clear the channel
		// ws_audio_clear_channel(5);
	}

	// initialize the noise channel data
	int rand;
	for(i=0;i<8;i++)
	{
		for(j=0;j<BUFSIZEN;j++)
		{
			rand=ws_audio_mrand(15-i)&1;
			if(rand)
			{
				PDataN[i][j]=PH;
			}
			else
			{
				PDataN[i][j]=PL;
			}
		}
	}

	for(j=0;j<BUFSIZEN;j++)
	{
		RandData[j]=ws_audio_mrand(15);
	}

	int k=0;
	for(k=0;k<6;k++)
	{
		memcpy((char*)m_pAudioData[k].m_pBuffer,(char*)RandData[j], m_pAudioData[k].m_iLength);
		m_pAudioData[k].m_pBuffer = (s16*)PDataN[k];
		m_pAudioData[k].m_iLength = 512;
		m_pAudioData[k].m_iSize = 1024;
		m_pAudioData[k].m_iFrequency = 15960;

	}

	return(1);
}
//--------------------------------------------------------------------------------------------------------
void ws_audio_seal_done(void)
{
	int i;

	SAFE_DELETE_ARRAY( m_pAudioData );

	// stop channels
	for (i=0;i<6;i++)
		ws_audio_stop_channel(i);

	// destroy pcm wave data
	//for (i=0;i<4;i++)
	//ADestroyAudioData(&ws_audio_pcm_wave[i]);

	// destroy noise wave data
	//ADestroyAudioData(&ws_audio_noise_wave);

	// destroy sweep wave data
	//ADestroyAudioData(&ws_audio_sweep_wave);

	// release pcm channels
	//for (i=0;i<6;i++)
	//ADestroyAudioVoice(ws_audio_pcm_voice[i]);

	// release noise channel
	//ADestroyAudioVoice(ws_audio_noise_voice);

	// release sweep channel
	//ADestroyAudioVoice(ws_audio_sweep_voice);

	// close all channels
	//ACloseVoices();

	// close audio
	//ACloseAudio();
}
//--------------------------------------------------------------------------------------------------------
void ws_audio_clear_channel(int Channel)
{
	ChCurVol[Channel]=-1;
	ChCurPer[Channel]=-1;
	ChCurPan[Channel]=-1;

	if(Channel==5){
		//memset((char*)m_pAudioData[Channel].m_pBuffer, 0, BUFSIZEN);
	}
	else 
		if(Channel==4){
			//memset((char*)m_pAudioData[Channel].m_pBuffer, 0, (BUFSIZEP<<4));
		}
		else{
			//memset((char*)m_pAudioData[Channel].m_pBuffer, 0, BUFSIZEN);
		}
}
////////////////////////////////////////////////////////////////////////////////
// start playing a channel
////////////////////////////////////////////////////////////////////////////////
//
//
//
//
//
//
//
////////////////////////////////////////////////////////////////////////////////
int ws_audio_play_channel(int Channel)
{
	if (ws_audio_channel_isPlaying[Channel])
		return(0);

	ws_audio_channel_isPlaying[Channel]=1;
	if (Channel==5){
		//APlayVoice(ws_audio_sweep_voice, &ws_audio_sweep_wave);
		//m_pAudioPlayer->Play(&m_pAudioData[Channel],Channel,m_pAudioData[Channel].GetLength(),100,true);
	}
	else
		if (Channel==4){
			//APlayVoice(ws_audio_noise_voice, &ws_audio_noise_wave);
			//m_pAudioPlayer->Play(&m_pAudioData[Channel],Channel,m_pAudioData[Channel].GetLength(),100,true);
		}
		else{
			//APlayVoice(ws_audio_pcm_voice[Channel], &ws_audio_pcm_wave[Channel]);
			//m_pAudioPlayer->Play(&m_pAudioData[Channel],Channel,m_pAudioData[Channel].GetLength(),100,true);
		}
		return 0;
}
////////////////////////////////////////////////////////////////////////////////
//
////////////////////////////////////////////////////////////////////////////////
//
//
//
//
//
//
//
////////////////////////////////////////////////////////////////////////////////
void ws_audio_set_channel_frequency(int Channel,int Period)
{
	DWORD Freq;

	if(ChCurPer[Channel]==Period)
		return;

	ChCurPer[Channel]=Period;

	Freq=3072000/(2048-Period);

	if(Channel==2)
	{
		ChPerInit=Period;
		SwpCurPeriod=Period;
	}

	if(Freq>BPSMAX)
		Freq=BPSMAX;
	else 
		if(Freq<BPSMIN)
			Freq=BPSMIN;

	if (Channel==5){
		//ASetVoiceFrequency(ws_audio_sweep_voice,Freq);
	}
	else{
		if (Channel==4){
			//ASetVoiceFrequency(ws_audio_noise_voice,Freq);
		}
		else{
			//ASetVoiceFrequency(ws_audio_pcm_voice[Channel],Freq);
		}
	}
}
////////////////////////////////////////////////////////////////////////////////
//
////////////////////////////////////////////////////////////////////////////////
//
//
//
//
//
//
//
////////////////////////////////////////////////////////////////////////////////
void ws_audio_set_channel_volume(int Channel,int Vol)
{
	long volume;

	if(ChCurVol[Channel]==Vol)
		return;

	ChCurVol[Channel]=Vol;

	volume=TblChVol[ChCurVol[Channel]]+TblMainVol[MainVol];
	if (volume>10000) volume=10000;
	volume=((volume+10000)*0x3f)/20000;  
	if(volume<-10000)
		volume=-10000;

	if (Channel==5){
		//m_pAudioPlayer->SetChlVol(Channel, volume);
		//ASetVoiceVolume(ws_audio_sweep_voice,volume);
	}
	else{
		if (Channel==4){
			//m_pAudioPlayer->SetChlVol(Channel, volume);
			//ASetVoiceVolume(ws_audio_noise_voice,volume);
		}
		else{
			//m_pAudioPlayer->SetChlVol(Channel, volume);
			//ASetVoiceVolume(ws_audio_pcm_voice[Channel],volume);
		}
	}
}
////////////////////////////////////////////////////////////////////////////////
//
////////////////////////////////////////////////////////////////////////////////
//
//
//
//
//
//
//
////////////////////////////////////////////////////////////////////////////////
void ws_audio_set_channel_pan(int Channel,int Left,int Right)
{
	long pan;

	const long TblPan[16][16]=
	{
		{     0, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000},
		{-10000,     0,   602,   954,  1204,  1398,  1556,  1690,  1806,  1908,  2000,  2082,  2158,  2228,  2292,  2352},
		{-10000,  -602,     0,   352,   602,   796,   954,  1088,  1204,  1306,  1398,  1481,  1556,  1626,  1690,  1750},
		{-10000,  -954,  -352,     0,   250,   444,   602,   736,   852,   954,  1046,  1129,  1204,  1274,  1338,  1398},
		{-10000, -1204,  -602,  -250,     0,   194,   352,   486,   602,   704,   796,   879,   954,  1024,  1088,  1148},
		{-10000, -1398,  -796,  -444,  -194,     0,   158,   292,   408,   511,   602,   685,   760,   830,   894,   954},
		{-10000, -1556,  -954,  -602,  -352,  -158,     0,   134,   250,   352,   444,   526,   602,   672,   736,   796},
		{-10000, -1690, -1088,  -736,  -486,  -292,  -134,     0,   116,   218,   310,   393,   468,   538,   602,   662},
		{-10000, -1806, -1204,  -852,  -602,  -408,  -250,  -116,     0,   102,   194,   277,   352,   422,   486,   546},
		{-10000, -1908, -1306,  -954,  -704,  -511,  -352,  -218,  -102,     0,    92,   174,   250,   319,   384,   444},
		{-10000, -2000, -1398, -1046,  -796,  -602,  -444,  -310,  -194,   -92,     0,    83,   158,   228,   292,   352},
		{-10000, -2082, -1481, -1129,  -879,  -685,  -526,  -393,  -277,  -174,   -83,     0,    76,   145,   209,   269},
		{-10000, -2158, -1556, -1204,  -954,  -760,  -602,  -468,  -352,  -250,  -158,   -76,     0,    70,   134,   194},
		{-10000, -2228, -1626, -1274, -1024,  -830,  -672,  -538,  -422,  -319,  -228,  -145,   -70,     0,    64,   124},
		{-10000, -2292, -1690, -1338, -1088,  -894,  -736,  -602,  -486,  -384,  -292,  -209,  -134,   -64,     0,    60},
		{-10000, -2352, -1750, -1398, -1148,  -954,  -796,  -662,  -546,  -444,  -352,  -269,  -194,  -124,   -60,     0},
	};

	if(Left>Right)
		ws_audio_set_channel_volume(Channel,Left);
	else
		ws_audio_set_channel_volume(Channel,Right);

	pan=TblPan[Left][Right];

	if(ChCurPan[Channel]==pan)
		return;

	ChCurPan[Channel]=pan;

	if (pan>10000) 
		pan=10000;

	pan=((pan+10000)*AUDIO_MAX_PANNING)/20000;  

	if (Channel==5){
		//ASetVoicePanning(ws_audio_sweep_voice,pan);
	}
	else{
		if (Channel==4){
			//ASetVoicePanning(ws_audio_noise_voice,pan);
		}
		else{
			//ASetVoicePanning(ws_audio_pcm_voice[Channel],pan);
		}
	}
}
////////////////////////////////////////////////////////////////////////////////
//
////////////////////////////////////////////////////////////////////////////////
//
//
//
//
//
//
//
////////////////////////////////////////////////////////////////////////////////
void ws_audio_set_channel_pdata(int Channel,int Index)
{
	unsigned char *pData;

	if(Channel==5)
	{
		pData=PDataN[Index];
		memcpy((char*)m_pAudioData[Channel].m_pBuffer,(char*)pData, m_pAudioData[Channel].m_iLength);
		//m_pAudioPlayer->Play(&m_pAudioData[Channel],0,m_pAudioData[Channel].GetLength(),255,true);
	}
	else if(Channel==4)
	{
		pData=PDataP;
		memcpy((char*)m_pAudioData[Channel].m_pBuffer,(char*)pData, m_pAudioData[Channel].m_iLength);
		//m_pAudioPlayer->Play(&m_pAudioData[Channel],0,m_pAudioData[Channel].GetLength(),255,true);
	}
	else
	{
		pData=PData[Channel];
		memcpy((char*)m_pAudioData[Channel].m_pBuffer,(char*)pData, m_pAudioData[Channel].m_iLength);
		//m_pAudioPlayer->Play(&m_pAudioData[Channel],0,m_pAudioData[Channel].GetLength(),255,true);

		//AWriteAudioData(&ws_audio_pcm_wave[Channel], 0, ws_audio_pcm_wave[Channel].dwLength);
	}
}
////////////////////////////////////////////////////////////////////////////////
//
////////////////////////////////////////////////////////////////////////////////
//
//
//
//
//
//
//
////////////////////////////////////////////////////////////////////////////////
int ws_audio_int(void)
{
	int value;
	static int i;

	if((SwpStep)&&(SNDMOD&0x40))
	{
		if(CntSwp<0)
		{
			CntSwp=SwpTime;
			SwpCurPeriod+=SwpStep;
			SwpCurPeriod&=0x7FF;
			value=3072000/(2048-SwpCurPeriod);
			if(value>100000)
			{
				value=100000;
				ws_audio_set_channel_volume(2,0);
			}
			if(value<100)
			{
				value=100;
			}
			//ASetVoiceFrequency(ws_audio_pcm_voice[2],value);
		}
		CntSwp--;
	}
	i++;
	if(i>=BUFSIZEN)
	{
		i=0;
	}
	return RandData[i];
}
////////////////////////////////////////////////////////////////////////////////
//
////////////////////////////////////////////////////////////////////////////////
//
//
//
//
//
//
//
////////////////////////////////////////////////////////////////////////////////
static DWORD PCMPos=0;
DWORD TickZ=0,PcmCount;

void ws_audio_set_pcm(int Data)
{
	DWORD tick=0;
	PDataP[PCMPos++]=(unsigned char)(Data+128);
	//TODO:ERROR
	//tick=GetTickCount();

	PcmCount++;
	if(tick>=TickZ)
	{
		TickZ=tick+125;
		PcmCount<<=3;
		if(PcmCount>=10000)
		{
			PcmCount=12000;
		}
		//ASetVoiceFrequency(ws_audio_noise_voice,PcmCount);
		PcmCount=0;
	}

	if(PCMPos>=BUFSIZEP)
		ws_audio_flash_pcm();
}
////////////////////////////////////////////////////////////////////////////////
//
////////////////////////////////////////////////////////////////////////////////
//
//
//
//
//
//
//
////////////////////////////////////////////////////////////////////////////////
void ws_audio_flash_pcm(void)
{
	LPVOID ptr1,ptr2;
	DWORD len1,len2;

	const DWORD WrPos[16]=
	{
		BUFSIZEP*0,BUFSIZEP*1,BUFSIZEP*2,BUFSIZEP*3,
		BUFSIZEP*4,BUFSIZEP*5,BUFSIZEP*6,BUFSIZEP*7,
		BUFSIZEP*8,BUFSIZEP*9,BUFSIZEP*10,BUFSIZEP*11,
		BUFSIZEP*12,BUFSIZEP*13,BUFSIZEP*14,BUFSIZEP*15,
	};

	len1=BUFSIZEP;

	//memcpy((char*)m_pAudioData[4].m_pBuffer[WrPos[PcmWrPos]], (char*)PDataP, len1);
	//m_pAudioPlayer->Play(&m_pAudioData[4],0,m_pAudioData[4].GetLength(),255,true);
	//AWriteAudioData(&ws_audio_noise_wave, 0, ws_audio_noise_wave.dwLength);

	PcmWrPos++;
	PcmWrPos&=0xF;
	PCMPos=0;
}
//--------------------------------------------------------------------------------------------------------
int ws_audio_stop_channel(int Channel)
{
	if (!ws_audio_channel_isPlaying[Channel])
		return(0);

	ws_audio_channel_isPlaying[Channel]=0;

	if (Channel==5)
	{
		//m_pAudioPlayer->Stop(5);
	}
	else{
		if (Channel==4){
			//m_pAudioPlayer->Stop(4);
		}
		else{
			//m_pAudioPlayer->Stop(Channel);
		}
	}
	return(0);
}
//--------------------------------------------------------------------------------------------------------
void ws_audio_set_channels_pbuf(int Addr,int Data)
{
	int i,j;

	i=(Addr&0x30)>>4;
	for(j=(Addr&0x0F)<<1;j<BUFSIZE;j+=32)
	{
		PData[i][j]   = (unsigned char)(POFF+PDIV*((Data&0x0F)-7));
		PData[i][j+1] = (unsigned char)(POFF+PDIV*(((Data&0xF0)>>4)-7));
	}
	if((Addr&0x0F)==0x0F)
		ws_audio_set_channel_pdata(i,0);
}
//--------------------------------------------------------------------------------------------------------
void ws_audio_rst_channel(int Channel)
{
	if(Channel==2)
	{
		ws_audio_set_channel_frequency(2,ChPerInit);
		SwpCurPeriod=ChPerInit;
	}
}

//--------------------------------------------------------------------------------------------------------
void ws_audio_write_byte(DWORD offset, UINT8 value)
{
	if (!((offset-WaveMap)&0xFFC0))
	{
		ws_audio_set_channels_pbuf(offset&0x003F,value);
		internalRam[offset]=value;
	}
}
//--------------------------------------------------------------------------------------------------------
void ws_audio_process(void)
{ 
	int i, j, b;
	i=ws_audio_int();
	PCSRL=(UINT8)(i&0xFF);
	PCSRH=(UINT8)((i>>8)&0xFF);
	if((SDMACTL&0x88)==0x80) 
	{
		i=(SDMACH<<8)|SDMACL;
		j=(SDMASB<<16)|(SDMASH<<8)|SDMASL;
		b=cpu_readmem20(j);
		if(!ws_audio_channel_isPlaying[5])
			b=0x80;
		ws_ioRam[0x89]=b;
		i--;
		j++;
		if(i<32)    
		{
			i=0;
			SDMACTL&=0x7F;
		}
		SDMASB=(UINT8)((j>>16)&0xFF);
		SDMASH=(UINT8)((j>>8)&0xFF);
		SDMASL=(UINT8)(j&0xFF);
		SDMACH=(UINT8)((i>>8)&0xFF);
		SDMACL=(UINT8)(i&0xFF);
	}
	else if((SNDMOD&0x22)==0x22)
	{
		b=ws_ioRam[0x89];
		if(!ws_audio_channel_isPlaying[4])
			b=0x80;
	}
	else
	{
		b=0x80;
	}
	b>>=1;
	b+=0x40;
	if(b>0xAA)
	{
		b=0xAA;
	}
	else if(b<0x55)
	{
		b=0x55;
	}
	ws_audio_set_pcm(b);
}

//--------------------------------------------------------------------------------------------------------
void PlayMusic(u32 ID,bool bRep)
{
	if(!m_bUseAudio){
		return;
	}
	if(ID>=m_AudioCnt){
		return;
	}
	m_pAudioPlayer->Play(&m_pAudioData[ID],0,m_pAudioData[ID].GetLength(),255,bRep);
}

//--------------------------------------------------------------------------------------------------------
void StopMusic()
{
	m_pAudioPlayer->Stop(0);
}

//--------------------------------------------------------------------------------------------------------
void PlaySound(u32 ID)
{
	if(!m_bUseAudio){
		return;
	}
	if(ID>=m_AudioCnt){
		return;
	}
	for(s32 i=1;i<AudioPlayer::MaxChannels;i++){
		if(m_pAudioPlayer->GetState(i) != AUDIO_PLAYING){
			m_pAudioPlayer->Play(&m_pAudioData[ID],i,m_pAudioData[ID].GetLength(),255,false);
			return;
		}
	}
} 

//--------------------------------------------------------------------------------------------------------
void StopAllSound()
{
	m_bUseAudio = false;
	m_pAudioPlayer->StopAll();
}

