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

#include <xtl.h>
//#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <malloc.h>
#include <io.h>
#include <fcntl.h>
#include <conio.h>
#include <time.h>
#include "log.h"
#include "rom.h"
#include "types.h"
#include "./nec/nec.h"
#include "memorysw.h"
#include "iosw.h"
#include "audio.h"
//#include "./seal/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 AUDIO_MAX_FREQUENCY             0x00080000L
#define AUDIO_MIN_FREQUENCY             0x00000200L
#define AUDIO_MAX_PANNING               0xFF

#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

#define byte unsigned char

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

int		MainVol=15;							
int		HardVol = 3 ;

int		ChCurVolL[6]={-1,-1,-1,-1,-1,-1};	
int		ChCurVolR[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};	
DWORD   CurFreq[6] = {22050, 22050, 22050, 22050 } ;

unsigned char PData[4][BUFSIZE];		
unsigned char PDataP[BUFSIZEP<<4];		
unsigned char PDataN[8][BUFSIZEN];		

int RandData[BUFSIZEN];					

int CntSwp=0;							
int PcmWrPos=0;							

int g_globalInit = 0 ;
void ws_pause( int pause);

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
};

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

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


////////////////////////////////////////////////////////////////////////////////
// seal audio specific
////////////////////////////////////////////////////////////////////////////////
//
//
//
//
//
//
//
////////////////////////////////////////////////////////////////////////////////

typedef struct WS_AUDIO_STRUCT {

	DWORD dwWritePos ;
	DWORD bufferLength ;
	unsigned char *buffer ;

} wsaudio ;

//HAC			ws_audio_pcm_voice[4];
//HAC			ws_audio_noise_voice;
//HAC			ws_audio_sweep_voice;

//AUDIOWAVE	ws_audio_pcm_wave[4];
//AUDIOWAVE	ws_audio_noise_wave;
//AUDIOWAVE	ws_audio_sweep_wave;

wsaudio		ws_audio_pcm_voice[4];
wsaudio		ws_audio_noise_voice;
wsaudio		ws_audio_sweep_voice;

LPDIRECTSOUNDBUFFER8 ws_audio_pcm_wave[4];
LPDIRECTSOUNDBUFFER8 ws_audio_noise_wave;
LPDIRECTSOUNDBUFFER8 ws_audio_sweep_wave;

UINT32		ws_audio_channel_isPlaying[6];

static unsigned int ws_audio_log;
////////////////////////////////////////////////////////////////////////////////
//
////////////////////////////////////////////////////////////////////////////////
//
//
//
//
//
//
//
////////////////////////////////////////////////////////////////////////////////
void ws_audio_init(LPDIRECTSOUND8		dsound )
{
	ws_audio_log=0;
	ws_audio_seal_init(dsound );
	ws_audio_reset();
	//Sleep(3000) ;
}
////////////////////////////////////////////////////////////////////////////////
//
////////////////////////////////////////////////////////////////////////////////
//
//
//
//
//
//
//
////////////////////////////////////////////////////////////////////////////////
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);
	Sleep(250) ;
}
////////////////////////////////////////////////////////////////////////////////
//
////////////////////////////////////////////////////////////////////////////////
//
//
//
//
//
//
//
////////////////////////////////////////////////////////////////////////////////
void ws_audio_port_write(DWORD port,BYTE value)
{
	int n,i,j,k,b;

	ws_ioRam[port]=value;

	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=(byte)((i>>16)&0xFF);
					DMASH=(byte)((i>>8)&0xFF);
					DMASL=(byte)(i&0xFF);
					DMADB=(byte)((j>>16)&0xFF);
					DMADH=(byte)((j>>8)&0xFF);
					DMADL=(byte)(j&0xFF);
					DMACH=(byte)((n>>8)&0xFF);
					DMACL=(byte)(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:
				if ( value & 0x10 )
					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==0x88)
					ws_audio_play_channel(5);
				else 
					ws_audio_stop_channel(5);
				break;
	case 0x91:
				//MainVol=0;
				value|=0x80;
 				HardVol = (value>>1)&0x3;

 				ws_ioRam[port]=value;	// Always have external speaker

 				value=ws_ioRam[0x88];

 				ws_audio_set_channel_pan(0,(value&0xF0)>>4,value&0x0F);

 				value=ws_ioRam[0x89];

 				ws_audio_set_channel_pan(1,(value&0xF0)>>4,value&0x0F);

 				value=ws_ioRam[0x8A];

 				ws_audio_set_channel_pan(2,(value&0xF0)>>4,value&0x0F);

 				value=ws_ioRam[0x8B];

                 ws_audio_set_channel_pan(3,(value&0xF0)>>4,value&0x0F);

 				ws_audio_set_channel_pan(5,(value&0xF0)>>4,value&0x0F);

				break;

				//MainVol=0;
				//value|=0x80;
				//break;
	case 0x92:
	case 0x93:
				break;
	case 0x94:
				MainVol=(value&0x0f)>>2;
 				value=ws_ioRam[0x88];

 				ws_audio_set_channel_pan(0,(value&0xF0)>>4,value&0x0F);

 				value=ws_ioRam[0x89];

 				ws_audio_set_channel_pan(1,(value&0xF0)>>4,value&0x0F);

 				value=ws_ioRam[0x8A];

 				ws_audio_set_channel_pan(2,(value&0xF0)>>4,value&0x0F);

 				value=ws_ioRam[0x8B];

                 ws_audio_set_channel_pan(3,(value&0xF0)>>4,value&0x0F);

 				ws_audio_set_channel_pan(5,(value&0xF0)>>4,value&0x0F);

				//ws_audio_set_channel_pan(5,value&0x0F,value&0x0F);
				break;
	}
}
////////////////////////////////////////////////////////////////////////////////
//
////////////////////////////////////////////////////////////////////////////////
//
//
//
//
//
//
//
////////////////////////////////////////////////////////////////////////////////
BYTE ws_audio_port_read(BYTE 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)},
		{0,0,0},
	};

	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(LPDIRECTSOUND8		dsound )
{
	int			i, j;
    //AUDIOINFO	info;
    //AUDIOCAPS	caps;
    UINT		rc;
	UINT		nDevId;
	DSBUFFERDESC			stream_desc;
	WAVEFORMATEX			stream_format;
	HRESULT result;

	if ( g_globalInit == 0 )
	{

	for ( int i = 0 ; i < 4 ; i++ )
	{

		// make a format description for what we want
		stream_format.wBitsPerSample	= 8;
		stream_format.wFormatTag		= WAVE_FORMAT_PCM;
		stream_format.nChannels			= 1;
		stream_format.nSamplesPerSec	= 22050;
		stream_format.nBlockAlign		= stream_format.wBitsPerSample * stream_format.nChannels / 8;
		stream_format.nAvgBytesPerSec	= stream_format.nSamplesPerSec * stream_format.nBlockAlign;

		DSMIXBINVOLUMEPAIR dsmbvp[6] = {
			{DSMIXBIN_FRONT_LEFT, DSBVOLUME_MAX},   // left channel
			{DSMIXBIN_FRONT_RIGHT, DSBVOLUME_MAX},  // right channel
			{DSMIXBIN_FRONT_CENTER, DSBVOLUME_MAX}, // left channel
			{DSMIXBIN_LOW_FREQUENCY, DSBVOLUME_MAX},    // left channel
			{DSMIXBIN_BACK_LEFT, DSBVOLUME_MAX},    // left channel
			{DSMIXBIN_BACK_RIGHT, DSBVOLUME_MAX}};   // right channel
			
		DSMIXBINS dsmb;
		dsmb.dwMixBinCount = 6;
		dsmb.lpMixBinVolumePairs = dsmbvp;
		
		// create a buffer desc for the stream buffer
		stream_desc.dwSize				= sizeof(stream_desc);
		stream_desc.dwFlags				= 0 ;
		stream_desc.dwBufferBytes 		= 0; //we'll specify our own data
	//	stream_desc.dwBufferBytes 		= stream_buffer_size;
		stream_desc.lpwfxFormat			= &stream_format;
		stream_desc.lpMixBins			= &dsmb;
		
		// create the stream buffer
		if ((result = dsound->CreateSoundBuffer(&stream_desc, &(ws_audio_pcm_wave[i]), NULL)) != DS_OK)
		{
			ws_audio_pcm_wave[i] = NULL ;
			continue ;
		}
		
		ws_audio_pcm_voice[i].buffer = (byte*)malloc(BUFSIZE ) ;

		ws_audio_pcm_wave[i]->SetBufferData( ws_audio_pcm_voice[i].buffer, BUFSIZE ) ;
		ws_audio_pcm_wave[i]->SetPlayRegion( 0, BUFSIZE ) ;
		ws_audio_pcm_wave[i]->SetLoopRegion( 0, BUFSIZE ) ;

		memset( ws_audio_pcm_voice[i].buffer, 0, BUFSIZE);
		
		ws_audio_pcm_wave[i]->SetVolume( DSBVOLUME_MAX );
		ws_audio_pcm_wave[i]->SetCurrentPosition( 0 ) ;

		ws_audio_pcm_voice[i].bufferLength = BUFSIZE ;
		ws_audio_pcm_voice[i].dwWritePos = 0;

		ws_audio_channel_isPlaying[i]=0;

		// clear the channel
		ws_audio_clear_channel(i);

	}

	{
		stream_format.wBitsPerSample	= 8;
		stream_format.wFormatTag		= WAVE_FORMAT_PCM;
		stream_format.nChannels			= 1;
		stream_format.nSamplesPerSec	= 22050;
		stream_format.nBlockAlign		= stream_format.wBitsPerSample * stream_format.nChannels / 8;
		stream_format.nAvgBytesPerSec	= stream_format.nSamplesPerSec * stream_format.nBlockAlign;

		DSMIXBINVOLUMEPAIR dsmbvp[6] = {
			{DSMIXBIN_FRONT_LEFT, DSBVOLUME_MAX},   // left channel
			{DSMIXBIN_FRONT_RIGHT, DSBVOLUME_MAX},  // right channel
			{DSMIXBIN_FRONT_CENTER, DSBVOLUME_MAX}, // left channel
			{DSMIXBIN_LOW_FREQUENCY, DSBVOLUME_MAX},    // left channel
			{DSMIXBIN_BACK_LEFT, DSBVOLUME_MAX},    // left channel
			{DSMIXBIN_BACK_RIGHT, DSBVOLUME_MAX}};   // right channel
			
		DSMIXBINS dsmb;
		dsmb.dwMixBinCount = 6;
		dsmb.lpMixBinVolumePairs = dsmbvp;
		
		// create a buffer desc for the stream buffer
		stream_desc.dwSize				= sizeof(stream_desc);
		stream_desc.dwFlags				= 0 ;
		stream_desc.dwBufferBytes 		= 0; //we'll specify our own data
	//	stream_desc.dwBufferBytes 		= stream_buffer_size;
		stream_desc.lpwfxFormat			= &stream_format;
		stream_desc.lpMixBins			= &dsmb;
		
		// create the stream buffer
		if ((result = dsound->CreateSoundBuffer(&stream_desc, &(ws_audio_noise_wave), NULL)) != DS_OK)
		{
			ws_audio_noise_wave = NULL ;
		}
		
		ws_audio_noise_voice.buffer = (byte*)malloc(BUFSIZEP<<4 ) ;

		ws_audio_noise_wave->SetBufferData( ws_audio_noise_voice.buffer, BUFSIZEP<<4) ;
		ws_audio_noise_wave->SetPlayRegion( 0, BUFSIZEP<<4) ;
		ws_audio_noise_wave->SetLoopRegion( 0, BUFSIZEP<<4) ;

		memset( ws_audio_noise_voice.buffer, 0, BUFSIZEP<<4);
		
		ws_audio_noise_wave->SetVolume( DSBVOLUME_MAX );
		ws_audio_noise_wave->SetCurrentPosition( 0 ) ;

		ws_audio_noise_voice.bufferLength = BUFSIZEP<<4;
		ws_audio_noise_voice.dwWritePos = 0;

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

		// clear the channel
		ws_audio_clear_channel(4);

	}


	{
		stream_format.wBitsPerSample	= 8;
		stream_format.wFormatTag		= WAVE_FORMAT_PCM;
		stream_format.nChannels			= 1;
		stream_format.nSamplesPerSec	= 22050;
		stream_format.nBlockAlign		= stream_format.wBitsPerSample * stream_format.nChannels / 8;
		stream_format.nAvgBytesPerSec	= stream_format.nSamplesPerSec * stream_format.nBlockAlign;

		DSMIXBINVOLUMEPAIR dsmbvp[6] = {
			{DSMIXBIN_FRONT_LEFT, DSBVOLUME_MAX},   // left channel
			{DSMIXBIN_FRONT_RIGHT, DSBVOLUME_MAX},  // right channel
			{DSMIXBIN_FRONT_CENTER, DSBVOLUME_MAX}, // left channel
			{DSMIXBIN_LOW_FREQUENCY, DSBVOLUME_MAX},    // left channel
			{DSMIXBIN_BACK_LEFT, DSBVOLUME_MAX},    // left channel
			{DSMIXBIN_BACK_RIGHT, DSBVOLUME_MAX}};   // right channel
			
		DSMIXBINS dsmb;
		dsmb.dwMixBinCount = 6;
		dsmb.lpMixBinVolumePairs = dsmbvp;
		
		// create a buffer desc for the stream buffer
		stream_desc.dwSize				= sizeof(stream_desc);
		stream_desc.dwFlags				= 0 ;
		stream_desc.dwBufferBytes 		= 0; //we'll specify our own data
	//	stream_desc.dwBufferBytes 		= stream_buffer_size;
		stream_desc.lpwfxFormat			= &stream_format;
		stream_desc.lpMixBins			= &dsmb;
		
		// create the stream buffer
		if ((result = dsound->CreateSoundBuffer(&stream_desc, &(ws_audio_sweep_wave), NULL)) != DS_OK)
		{
			ws_audio_sweep_wave = NULL ;
		}
		
		ws_audio_sweep_voice.buffer = (byte*)malloc(BUFSIZEN) ;

		ws_audio_sweep_wave->SetBufferData( ws_audio_sweep_voice.buffer, BUFSIZEN) ;
		ws_audio_sweep_wave->SetPlayRegion( 0, BUFSIZEN) ;
		ws_audio_sweep_wave->SetLoopRegion( 0, BUFSIZEN) ;

		memset( ws_audio_sweep_voice.buffer, 0, BUFSIZEN);
		
		ws_audio_sweep_wave->SetVolume( DSBVOLUME_MAX );
		ws_audio_sweep_wave->SetCurrentPosition( 0 ) ;

		ws_audio_sweep_voice.bufferLength = BUFSIZEN;
		ws_audio_sweep_voice.dwWritePos = 0;

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

		// clear the channel
		ws_audio_clear_channel(5);

	}

	}

	g_globalInit = 1 ;

#if 0
	fprintf(log_get(),"audio: using seal audio library\n");
    /* initialize audio library */
	AInitialize();

    /* show registered device drivers */
    fprintf(log_get(),"audio: registered sound devices:\n");
    for (nDevId = 0; nDevId < AGetAudioNumDevs(); nDevId++) {
        AGetAudioDevCaps(nDevId, &caps);
        fprintf(log_get(),"audio:   %2d. %s\n", nDevId, caps.szProductName);
    }
    /* open audio device */
    info.nDeviceId = AUDIO_DEVICE_MAPPER;
    info.wFormat   = AUDIO_FORMAT_16BITS | AUDIO_FORMAT_STEREO;//|AUDIO_MIXER_BASS;
    info.nSampleRate = 22050;
    if ((rc = AOpenAudio(&info)) != AUDIO_ERROR_NONE) 
	{
        CHAR szText[80];
        AGetErrorText(rc, szText, sizeof(szText) - 1);
        fprintf(log_get(),"audio: error: %s\n", szText);
        return(0);
    }
	
	// open 6 voices ( 4 pcm, one noise, and one sweep)
	AOpenVoices(6);

	// 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);
	}
#endif
	
	ws_pause(1) ;
	// 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);
    }

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

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

#if 0
	// 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();
#endif
}
////////////////////////////////////////////////////////////////////////////////
//
////////////////////////////////////////////////////////////////////////////////
//
//
//
//
//
//
//
////////////////////////////////////////////////////////////////////////////////
void ws_audio_clear_channel(int Channel)
{
    ChCurVolL[Channel]=-1;
    ChCurVolR[Channel]=-1;
    ChCurPer[Channel]=-1;
    ChCurPan[Channel]=-1;

	if(Channel==5)
	{
		memset(ws_audio_sweep_voice.buffer,		0, ws_audio_sweep_voice.bufferLength );
		//AWriteAudioData(&ws_audio_sweep_wave,	0, ws_audio_sweep_wave.dwLength);
	}
	else 
	if(Channel==4)
	{
		memset(ws_audio_noise_voice.buffer,		0, ws_audio_noise_voice.bufferLength ) ;
		//AWriteAudioData(&ws_audio_noise_wave,	0, ws_audio_noise_wave.dwLength);
	}
	else
	{
		memset(ws_audio_pcm_voice[Channel].buffer,		0, ws_audio_pcm_voice[Channel].bufferLength ) ;
		//AWriteAudioData(&ws_audio_pcm_wave[Channel],	0, ws_audio_pcm_wave[Channel].dwLength);
	}
}
////////////////////////////////////////////////////////////////////////////////
// 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;

	//return 0;

	if (Channel==5)
	{
		ws_audio_sweep_wave->Play( 0, 0, DSBPLAY_LOOPING ) ;
		//APlayVoice(ws_audio_sweep_voice, &ws_audio_sweep_wave);
	}
	else
	if (Channel==4)
	{
		ws_audio_noise_wave->Play( 0, 0, DSBPLAY_LOOPING ) ;
		//APlayVoice(ws_audio_noise_voice, &ws_audio_noise_wave);
	}
	else
	{
		DWORD freq ;
		ws_audio_pcm_wave[Channel]->Play( 0, 0, DSBPLAY_LOOPING ) ;

		freq = 3072000/(2048-ChCurPer[Channel]) ;

		if(freq>DSBFREQUENCY_MAX )
			freq=DSBFREQUENCY_MAX;

		else 
		if(freq<DSBFREQUENCY_MIN )
			freq=DSBFREQUENCY_MIN ;

		ws_audio_pcm_wave[Channel]->SetFrequency(freq);
		//APlayVoice(ws_audio_pcm_voice[Channel], &ws_audio_pcm_wave[Channel]);
	}
	return 0;
}
////////////////////////////////////////////////////////////////////////////////
// stop playing a channel
////////////////////////////////////////////////////////////////////////////////
//
//
//
//
//
//
//
////////////////////////////////////////////////////////////////////////////////
int ws_audio_stop_channel(int Channel)
{
	DWORD dwStatus;
	LPDIRECTSOUNDBUFFER8 stream_buffer ;

	if (!ws_audio_channel_isPlaying[Channel])
		return(0);

	ws_audio_channel_isPlaying[Channel]=0;

	//return 0;

	if (Channel==5)
		stream_buffer = ws_audio_sweep_wave;
		//AStopVoice(ws_audio_sweep_voice);
	else
	if (Channel==4)
		stream_buffer = ws_audio_noise_wave ;
		//AStopVoice(ws_audio_noise_voice);
	else
		stream_buffer = ws_audio_pcm_wave[Channel] ;
		//AStopVoice(ws_audio_pcm_voice[Channel]);


	stream_buffer->StopEx( 0, DSBSTOPEX_IMMEDIATE );
	do
	{
		stream_buffer->GetStatus( (LPDWORD)(&dwStatus) );
	} while( dwStatus & DSBSTATUS_PLAYING );

	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>DSBFREQUENCY_MAX )
		Freq=DSBFREQUENCY_MAX;

	else 
	if(Freq<DSBFREQUENCY_MIN )
		Freq=DSBFREQUENCY_MIN ;

	CurFreq[Channel] = Freq ;

	//return ;

	if (Channel==5)
		ws_audio_sweep_wave->SetFrequency( Freq ) ;
		//ASetVoiceFrequency(ws_audio_sweep_voice,Freq);
	else
	if (Channel==4)
		ws_audio_noise_wave->SetFrequency( Freq ) ;
		//ASetVoiceFrequency(ws_audio_noise_voice,Freq);
	else
		ws_audio_pcm_wave[Channel]->SetFrequency( Freq ) ;
		//ASetVoiceFrequency(ws_audio_pcm_voice[Channel],Freq);
}
////////////////////////////////////////////////////////////////////////////////
//
////////////////////////////////////////////////////////////////////////////////
//
//
//
//
//
//
//
////////////////////////////////////////////////////////////////////////////////
void ws_audio_set_channel_volume(int Channel,int VolL, int VolR)
{
	long volumel, volumer;

    if( (ChCurVolL[Channel]==VolL) && (ChCurVolR[Channel]==VolR) )
    	return;

    ChCurVolL[Channel]=VolL;
    ChCurVolR[Channel]=VolR;

    //volumel=TblChVol[ChCurVolL[Channel]]+TblMainVol[MainVol];
    //volumer=TblChVol[ChCurVolR[Channel]]+TblMainVol[MainVol];

	volumel=(((VolL+1)*(MainVol+1)*(HardVol+1)/16)-1)&0x0F ;
	volumer=(((VolR+1)*(MainVol+1)*(HardVol+1)/16)-1)&0x0F;

	volumel = TblChVol[volumel];
	volumer = TblChVol[volumer];

	if (volumel<DSBVOLUME_MIN ) volumel=DSBVOLUME_MIN ;
	if (volumer<DSBVOLUME_MIN ) volumer=DSBVOLUME_MIN ;


	DSMIXBINVOLUMEPAIR dsmbvp[6] = {
		{DSMIXBIN_FRONT_LEFT, volumel},   // left channel
		{DSMIXBIN_FRONT_RIGHT, volumer},  // right channel
		{DSMIXBIN_FRONT_CENTER, max((volumel+volumer)/2, DSBVOLUME_MIN)}, // left channel
		{DSMIXBIN_LOW_FREQUENCY, max((volumel+volumer)/2, DSBVOLUME_MIN)},    // left channel
		{DSMIXBIN_BACK_LEFT, volumel},    // left channel
		{DSMIXBIN_BACK_RIGHT, volumer}};   // right channel
		
	DSMIXBINS dsmb;
	dsmb.dwMixBinCount = 6;
	dsmb.lpMixBinVolumePairs = dsmbvp;

	//return ;

	if (Channel==5)
		ws_audio_sweep_wave->SetMixBinVolumes( &dsmb ) ;
		//ASetVoiceVolume(ws_audio_sweep_voice,volume);
	else
	if (Channel==4)
	{
		ws_audio_noise_wave->SetMixBinVolumes( &dsmb ) ;
		//ASetVoiceVolume(ws_audio_noise_voice,volume);
	}
	else
	{
		ws_audio_pcm_wave[Channel]->SetMixBinVolumes( &dsmb ) ;
		//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, Right);
    //else
    	//ws_audio_set_channel_volume(Channel,Right);

    pan=TblPan[Left][Right];

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

    ChCurPan[Channel]=pan;


#if 0
	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);
	}
#endif 
}
////////////////////////////////////////////////////////////////////////////////
//
////////////////////////////////////////////////////////////////////////////////
//
//
//
//
//
//
//
////////////////////////////////////////////////////////////////////////////////
void ws_audio_set_channel_pdata(int Channel,int Index)
{
	unsigned char *pData;

	if(Channel==5)
	{
		pData=PDataN[Index];

		memcpy(ws_audio_sweep_voice.buffer,		pData, ws_audio_sweep_voice.bufferLength ) ;
		//AWriteAudioData(&ws_audio_sweep_wave,	0, ws_audio_sweep_wave.dwLength);
	}
	else if(Channel==4)
	{
		pData=PDataP;
		memcpy(ws_audio_noise_voice.buffer,		pData, ws_audio_noise_voice.bufferLength);
		//AWriteAudioData(&ws_audio_noise_wave,	0, ws_audio_noise_wave.dwLength);
	}
	else
	{
		pData=PData[Channel];
		memcpy(ws_audio_pcm_voice[Channel].buffer,		pData, ws_audio_pcm_voice[Channel].bufferLength ) ;
		//AWriteAudioData(&ws_audio_pcm_wave[Channel],	0, ws_audio_pcm_wave[Channel].dwLength);
	}
}
////////////////////////////////////////////////////////////////////////////////
//
////////////////////////////////////////////////////////////////////////////////
//
//
//
//
//
//
//
////////////////////////////////////////////////////////////////////////////////
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));
		PData[i][j] = (Data&0x0f)*17-128;
		PData[i][j+1] = ((Data>>4)&0x0f)*17-128;
	}
    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;
    }
}
////////////////////////////////////////////////////////////////////////////////
//
////////////////////////////////////////////////////////////////////////////////
//
//
//
//
//
//
//
////////////////////////////////////////////////////////////////////////////////
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>DSBFREQUENCY_MAX)
	        {
        		value=DSBFREQUENCY_MAX;
        		ws_audio_set_channel_volume(2,0,0);
	        }
	        if(value<DSBFREQUENCY_MIN )
	        {
        		value=DSBFREQUENCY_MIN ;
        	}
			//here
			ws_audio_pcm_wave[2]->SetFrequency( value ) ;
    		//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;
	DWORD freq ;
	PDataP[PCMPos++]=(unsigned char)(Data+128);
	tick=GetTickCount();
    PcmCount++;
    if(tick>=TickZ)
    {
    	TickZ=tick+125;
        PcmCount<<=3;
        if(PcmCount>=10000)
        {
        	PcmCount=12000;
        }
		freq = PcmCount ;

		if ( freq < DSBFREQUENCY_MIN  )
			freq = DSBFREQUENCY_MIN  ;

		if ( freq > DSBFREQUENCY_MAX )
			freq = DSBFREQUENCY_MAX ;

		//here
		ws_audio_noise_wave->SetFrequency( freq ) ;
		//ASetVoiceFrequency(ws_audio_noise_voice,PcmCount);
        PcmCount=0;
    }

	if(PCMPos>=BUFSIZEP)
		ws_audio_flash_pcm();
}
////////////////////////////////////////////////////////////////////////////////
//
////////////////////////////////////////////////////////////////////////////////
//
//
//
//
//
//
//
////////////////////////////////////////////////////////////////////////////////
void ws_audio_flash_pcm(void)
{
    HRESULT result;
    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(&ws_audio_noise_voice.buffer[WrPos[PcmWrPos]], PDataP, len1);
	//AWriteAudioData(&ws_audio_noise_wave,	0, ws_audio_noise_wave.dwLength);


    PcmWrPos++;
    PcmWrPos&=0xF;
	memset(PDataP,PL,sizeof(PDataP));
	PCMPos=0;

}
////////////////////////////////////////////////////////////////////////////////
//
////////////////////////////////////////////////////////////////////////////////
//
//
//
//
//
//
//
////////////////////////////////////////////////////////////////////////////////
void ws_audio_write_byte(DWORD offset, BYTE 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=(byte)(i&0xFF);
	PCSRH=(byte)((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=(byte)((j>>16)&0xFF);
		SDMASH=(byte)((j>>8)&0xFF);
		SDMASL=(byte)(j&0xFF);
		SDMACH=(byte)((i>>8)&0xFF);
		SDMACL=(byte)(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 ws_audio_readState(int fp)
{
	long lpdwPosition;
	long lpdwFrequency;
	unsigned int lpnVolume;
	unsigned int lpnPanning;
	int lpnStatus;
	unsigned char *pData;
	int voll[6], volr[6] ;

	read(fp,&PCMPos,sizeof(DWORD));
	read(fp,&TickZ,sizeof(DWORD));
	read(fp,&PcmCount,sizeof(DWORD));
	read(fp,&WaveMap,sizeof(int));
	read(fp,&ChPerInit,sizeof(int));
	read(fp,&SwpTime,sizeof(int));
	read(fp,&SwpStep,sizeof(int));
	read(fp,&SwpCurPeriod,sizeof(int));
	read(fp,&MainVol,sizeof(int));
	read(fp,&CntSwp,sizeof(int));
	read(fp,&PcmWrPos,sizeof(int));
	read(fp,voll,sizeof(int)*6);
	read(fp,volr,sizeof(int)*6);
	read(fp,CurFreq,sizeof(DWORD)*6);

	ChCurVolR[0] = -1 ;
	ChCurVolR[1] = -1 ;
	ChCurVolR[2] = -1 ;
	ChCurVolR[3] = -1 ;
	ChCurVolR[4] = -1 ;
	ChCurVolR[5] = -1 ;
	ChCurVolL[0] = -1 ;
	ChCurVolL[1] = -1 ;
	ChCurVolL[2] = -1 ;
	ChCurVolL[3] = -1 ;
	ChCurVolL[4] = -1 ;
	ChCurVolL[5] = -1 ;

	read(fp,ws_audio_channel_isPlaying,sizeof(UINT32)*6);

	read(fp,PData,sizeof(unsigned char)*4*BUFSIZE);
	read(fp,PDataP,sizeof(unsigned char)*(BUFSIZEP<<4));
	read(fp,PDataN,sizeof(unsigned char)*8*BUFSIZEN);
	read(fp,PDataN,sizeof(int)*BUFSIZEN);

	for (int i=0;i<4;i++)
	{
		read(fp,&lpdwPosition,sizeof(long));
		read(fp,&lpdwFrequency,sizeof(long));
		read(fp,&lpnVolume,sizeof(unsigned int));
		read(fp,&lpnPanning,sizeof(unsigned int));
		read(fp,&lpnStatus,sizeof(int));

		ws_audio_pcm_wave[i]->SetCurrentPosition( lpdwPosition ) ;
		ws_audio_pcm_wave[i]->SetFrequency( CurFreq[i] ) ;
		ws_audio_set_channel_volume( i, voll[i], volr[i] ) ;

		//ASetVoicePosition(ws_audio_pcm_voice[i],lpdwPosition);
		//ASetVoiceFrequency(ws_audio_pcm_voice[i], lpdwFrequency);
		//ASetVoiceVolume(ws_audio_pcm_voice[i], lpnVolume);
		//ASetVoicePanning(ws_audio_pcm_voice[i], lpnPanning);

		pData=PData[i];
		memcpy(ws_audio_pcm_voice[i].buffer,		pData, ws_audio_pcm_voice[i].bufferLength ) ;
		//AWriteAudioData(&ws_audio_pcm_wave[i],	0, ws_audio_pcm_wave[i].dwLength);
		if (ws_audio_channel_isPlaying[i])
			ws_audio_pcm_wave[i]->Play( 0, 0, DSBPLAY_LOOPING) ;
			//APlayVoice(ws_audio_pcm_voice[i], &ws_audio_pcm_wave[i]);
	}
	read(fp,&lpdwPosition,sizeof(long));
	read(fp,&lpdwFrequency,sizeof(long));
	read(fp,&lpnVolume,sizeof(unsigned int));
	read(fp,&lpnPanning,sizeof(unsigned int));
	read(fp,&lpnStatus,sizeof(int));

	ws_audio_noise_wave->SetCurrentPosition( lpdwPosition ) ;
	ws_audio_noise_wave->SetFrequency( CurFreq[4] ) ;
	ws_audio_set_channel_volume( 4, voll[4], volr[4] ) ;

	//ASetVoicePosition(ws_audio_noise_voice,lpdwPosition);
	//ASetVoiceFrequency(ws_audio_noise_voice, lpdwFrequency);
	//ASetVoiceVolume(ws_audio_noise_voice, lpnVolume);
	//ASetVoicePanning(ws_audio_noise_voice, lpnPanning);
	pData=PDataP;
	memcpy(ws_audio_noise_voice.buffer,		pData, ws_audio_noise_voice.bufferLength) ;
	//AWriteAudioData(&ws_audio_noise_wave,	0, ws_audio_noise_wave.dwLength);
	if (ws_audio_channel_isPlaying[4])
		ws_audio_noise_wave->Play( 0, 0, DSBPLAY_LOOPING) ;
			//APlayVoice(ws_audio_noise_voice, &ws_audio_noise_wave);
	
	read(fp,&lpdwPosition,sizeof(long));
	read(fp,&lpdwFrequency,sizeof(long));
	read(fp,&lpnVolume,sizeof(unsigned int));
	read(fp,&lpnPanning,sizeof(unsigned int));
	read(fp,&lpnStatus,sizeof(int));

	ws_audio_sweep_wave->SetCurrentPosition( lpdwPosition ) ;
	ws_audio_sweep_wave->SetFrequency( CurFreq[5] ) ;
	ws_audio_set_channel_volume( 5, voll[5], volr[5] ) ;

	//ASetVoicePosition(ws_audio_sweep_voice,lpdwPosition);
	//ASetVoiceFrequency(ws_audio_sweep_voice, lpdwFrequency);
	//ASetVoiceVolume(ws_audio_sweep_voice, lpnVolume);
	//ASetVoicePanning(ws_audio_sweep_voice, lpnPanning);
	pData=PDataN[0];
	memcpy(ws_audio_sweep_voice.buffer,		pData, ws_audio_sweep_voice.bufferLength ) ;
	//AWriteAudioData(&ws_audio_sweep_wave,	0, ws_audio_sweep_wave.dwLength);
	if (ws_audio_channel_isPlaying[5])
		ws_audio_sweep_wave->Play( 0, 0, DSBPLAY_LOOPING) ;
			//APlayVoice(ws_audio_sweep_voice, &ws_audio_sweep_wave);
	
}
////////////////////////////////////////////////////////////////////////////////
//
////////////////////////////////////////////////////////////////////////////////
//
//
//
//
//
//
//
////////////////////////////////////////////////////////////////////////////////
void ws_audio_writeState(int fp)
{
	DWORD lpdwPosition;
	DWORD lpdwPosition2;
	DWORD lpdwFrequency;
	unsigned int lpnVolume;
	unsigned int lpnPanning;
	int lpnStatus;

	write(fp,&PCMPos,sizeof(DWORD));
	write(fp,&TickZ,sizeof(DWORD));
	write(fp,&PcmCount,sizeof(DWORD));
	write(fp,&WaveMap,sizeof(int));
	write(fp,&ChPerInit,sizeof(int));
	write(fp,&SwpTime,sizeof(int));
	write(fp,&SwpStep,sizeof(int));
	write(fp,&SwpCurPeriod,sizeof(int));
	write(fp,&MainVol,sizeof(int));
	write(fp,&CntSwp,sizeof(int));
	write(fp,&PcmWrPos,sizeof(int));
	write(fp,ChCurVolL,sizeof(int)*6);
	write(fp,ChCurVolR,sizeof(int)*6);
	write(fp,CurFreq,sizeof(DWORD)*6);

	write(fp,ws_audio_channel_isPlaying,sizeof(UINT32)*6);

	write(fp,PData,sizeof(unsigned char)*4*BUFSIZE);
	write(fp,PDataP,sizeof(unsigned char)*(BUFSIZEP<<4));
	write(fp,PDataN,sizeof(unsigned char)*8*BUFSIZEN);
	write(fp,PDataN,sizeof(int)*BUFSIZEN);

	for (int i=0;i<4;i++)
	{
		ws_audio_pcm_wave[i]->GetCurrentPosition( (LPDWORD)(&lpdwPosition), NULL ) ;
		//ws_audio_pcm_wave[i]->GetFrequency( &lpdwFrequency ) ;

		//AGetVoicePosition(ws_audio_pcm_voice[i],&lpdwPosition);
		//AGetVoiceFrequency(ws_audio_pcm_voice[i], &lpdwFrequency);
		//AGetVoiceVolume(ws_audio_pcm_voice[i], &lpnVolume);
		//AGetVoicePanning(ws_audio_pcm_voice[i], &lpnPanning);
		//AGetVoiceStatus(ws_audio_pcm_voice[i], &lpnStatus);
		
		write(fp,&lpdwPosition,sizeof(long));
		write(fp,&lpdwFrequency,sizeof(long));
		write(fp,&lpnVolume,sizeof(unsigned int));
		write(fp,&lpnPanning,sizeof(unsigned int));
		write(fp,&lpnStatus,sizeof(int));
	}

	ws_audio_noise_wave->GetCurrentPosition( (LPDWORD)(&lpdwPosition), NULL ) ;
	//ws_audio_noise_wave->GetFrequency( &lpdwFrequency ) ;

	//AGetVoicePosition(ws_audio_noise_voice,&lpdwPosition);
	//AGetVoiceFrequency(ws_audio_noise_voice, &lpdwFrequency);
	//AGetVoiceVolume(ws_audio_noise_voice, &lpnVolume);
	//AGetVoicePanning(ws_audio_noise_voice, &lpnPanning);
	//AGetVoiceStatus(ws_audio_noise_voice, &lpnStatus);
	
	write(fp,&lpdwPosition,sizeof(long));
	write(fp,&lpdwFrequency,sizeof(long));
	write(fp,&lpnVolume,sizeof(unsigned int));
	write(fp,&lpnPanning,sizeof(unsigned int));
	write(fp,&lpnStatus,sizeof(int));

	ws_audio_sweep_wave->GetCurrentPosition( (LPDWORD)(&lpdwPosition), NULL ) ;
	//ws_audio_sweep_wave->GetFrequency( &lpdwFrequency ) ;

	//AGetVoicePosition(ws_audio_sweep_voice,&lpdwPosition);
	//AGetVoiceFrequency(ws_audio_sweep_voice, &lpdwFrequency);
	//AGetVoiceVolume(ws_audio_sweep_voice, &lpnVolume);
	//AGetVoicePanning(ws_audio_sweep_voice, &lpnPanning);
	//AGetVoiceStatus(ws_audio_sweep_voice, &lpnStatus);
	
	write(fp,&lpdwPosition,sizeof(long));
	write(fp,&lpdwFrequency,sizeof(long));
	write(fp,&lpnVolume,sizeof(unsigned int));
	write(fp,&lpnPanning,sizeof(unsigned int));
	write(fp,&lpnStatus,sizeof(int));
}

void ws_pause( int pause)
{

	DWORD dwStatus ;

	if (pause)
	{
		for ( int i = 0 ; i < 4 ; i++ )
		{
			ws_audio_pcm_wave[i]->StopEx( 0, DSBSTOPEX_IMMEDIATE );
			do
			{
				ws_audio_pcm_wave[i]->GetStatus( (LPDWORD)(&dwStatus) );
			} while( dwStatus & DSBSTATUS_PLAYING );
		}

		ws_audio_sweep_wave->StopEx( 0, DSBSTOPEX_IMMEDIATE );
		do
		{
			ws_audio_sweep_wave->GetStatus( (LPDWORD)(&dwStatus) );
		} while( dwStatus & DSBSTATUS_PLAYING );

		ws_audio_noise_wave->StopEx( 0, DSBSTOPEX_IMMEDIATE );
		do
		{
			ws_audio_noise_wave->GetStatus( (LPDWORD)(&dwStatus) );
		} while( dwStatus & DSBSTATUS_PLAYING );
	}
	else
	{

		for ( int i = 0 ; i < 4 ; i++ )
		{
			ws_audio_pcm_wave[i]->Play( 0, 0, DSBPLAY_LOOPING ) ;
		}
		ws_audio_sweep_wave->Play( 0, 0, DSBPLAY_LOOPING ) ;
		ws_audio_noise_wave->Play( 0, 0, DSBPLAY_LOOPING ) ;
	}
}
