#include "dsound.h"
#include <stdio.h>
#include <stdlib.h>
#include "../PceNativeCall.h"
#include "../SimNative.h"
#include "../modplay.h"
#include "../e_utils.h"
#include "../finetune.h"

extern unsigned long ARMlet_Main(const void* emulStateP, void *userData, Call68KFuncType *call68KFuncP);

//MOD variables:=====
typedef struct {
   long file_is_open; //For WIN32 
   long out_file;     //For WIN32

   char* resonance_buffer; //256 bytes
   
   void* record_buf;
   long record_pos;

   void* echo_buffer;
   long echo_size;
   long echo_pointer;
   long echo_flange_delay;
   long echo_vol;

   void* reverb_offset;
   long reverb_number;

   long win32_frameCount;
   void* win32_buffer;

   char *rec_pointer;
   long rec_count;
   long rec_add;

   char *_arm_code;
   channel *_channels;
   long _patternticks;
   long _onetick;
   ulong _sp;
   ulong _speed;
   ulong _bpm;
   note **_patterndata;
   note **_patterndata2;
   module *_song;
   module *_song2;
   char *_buffer;
   channel *_one;
   uint *_fine;
   uint *_fine2;
   ulong _sampleticksconst;
   char *_pp;
   char **_sampledata;
   char **_sampledata2;
   long i2, size;
   ulong _update;
   uint _tablepos;
   uint _patternpos;
   uint _num_of_mods;
   uint _playrate;
   uint _buffer_size;
   uint CHANNELS;
   uint VOLUME;
   char _scope[60];
   char _status;
} user_info;
user_info mod_info;

char status=0; //0-pause; 1-one sample mode; 2-play; 3-one pattern play;
ulong frequency = 44100;

ulong CHANNELS = 4;
#define CHANNELS_MAX 12
#define PAT_SIZE (ulong)(CHANNELS*4*64)

module song;
char *sampledata[31];
note *patterndata[64]; //Array of pointers to patterns.
uint VOLUME = 64;
uint ECHO = 100;
uint ECHOLEN = 24;
uchar CLASSIC = 0;
uchar reverb_offset[10];
long reverb_number = 10;
char echo_buffer[ 128000 ];

uint    maxp; //maximal pattern number in song;
uint    playrate;
uint    tablepos;
uint    patternpos;
ulong   patternticks;
ulong   patternticksaim;
ulong   sampleticksconst;
channel channels[CHANNELS_MAX];

channel one[2]; //One channel mode.

ulong bpm,onetick,speed,sp;

char pp[1900]; //Table of periods.

int current_volume = 32;

uchar sin_tab[256] =
  {
0, 3, 6, 9, 12, 15, 18, 21, 25, 28, 31, 34, 37, 40, 43, 46,
49, 52, 56, 59, 62, 65, 68, 71, 74, 77, 80, 83, 86, 89, 92, 95, 
97, 100, 103, 106, 109, 112, 115, 117, 120, 123, 126, 128, 131, 134, 136, 139, 
142, 144, 147, 149, 152, 154, 157, 159, 162, 164, 167, 169, 171, 174, 176, 178, 
180, 183, 185, 187, 189, 191, 193, 195, 197, 199, 201, 203, 205, 207, 209, 211, 
212, 214, 216, 217, 219, 221, 222, 224, 225, 227, 228, 229, 231, 232, 233, 235, 
236, 237, 238, 239, 240, 242, 243, 243, 244, 245, 246, 247, 248, 249, 249, 250, 
251, 251, 252, 252, 253, 253, 254, 254, 254, 255, 255, 255, 255, 255, 255, 255, 
255, 255, 255, 255, 255, 255, 255, 255, 254, 254, 254, 253, 253, 252, 252, 251, 
251, 250, 249, 249, 248, 247, 246, 245, 245, 244, 243, 242, 241, 240, 238, 237, 
236, 235, 234, 232, 231, 230, 228, 227, 225, 224, 222, 221, 219, 218, 216, 214, 
213, 211, 209, 207, 205, 203, 201, 200, 198, 196, 194, 191, 189, 187, 185, 183, 
181, 179, 176, 174, 172, 169, 167, 165, 162, 160, 157, 155, 152, 150, 147, 145, 
142, 139, 137, 134, 131, 129, 126, 123, 120, 118, 115, 112, 109, 106, 104, 101, 
98, 95, 92, 89, 86, 83, 80, 77, 74, 71, 68, 65, 62, 59, 56, 53, 
50, 47, 44, 41, 37, 34, 31, 28, 25, 22, 19, 16, 12, 9, 6, 3
  };

long buffer_count = 8000;
long out_buffer[ 8000 ];
//===================

void main_mod_init( void );
void main_mod_close( void );
int load_mod( char *filename );
int load_pdb( char *filename );
int load_opened_file( FILE *f );
void show_mod_info( void );
void channels_setup( void );
void convert_song_for_ARM( void );
void start_clear( void );
void mod_play( void );
void tables_init( void );
void set_volume( long vol );
void echo_setup( long echo_volume, long size_in_ticks );
void create_user_info( void );
void render_piece_of_sound( void *buf, long buf_size );

void sound_init( void );
void sound_close( void );

int main()
{
	main_mod_init();
	
	printf( "\n" );
	printf( " .------------------------. .--------------------------.\n" );
	printf( " |                        | |                          |\n" );
	printf( " |   PsyTexx MOD Player   | |   Contact info:          |\n" );
	printf( " |           by           | |   nightradio@gmail.com   |\n" );
	printf( " |      Alex Zolotov      | |   www.warmplace.ru       |\n" );
	printf( " |                        | |                          |\n" );
	printf( " `------------------------` `--------------------------`\n" );
	printf( "\n" );
	printf( " Controls: UP      - volume up\n" );
	printf( "           DOWN    - volume down\n" );
	printf( "           ESCAPE  - exit\n" );
	load_pdb( "Moon Explorers.PDB" );
	//load_mod( "SoulVoyage.MOD" );
	//load_mod( "AT.MOD" );
	set_volume( current_volume );
	mod_play();

	INPUT_RECORD keyin;
	unsigned long r;
	while (ReadConsoleInput(GetStdHandle(STD_INPUT_HANDLE),&keyin,1,&r)) 
	{
		if(keyin.Event.KeyEvent.wVirtualKeyCode==VK_ESCAPE) break;
		if(keyin.Event.KeyEvent.wVirtualKeyCode==VK_UP) 
		{
			current_volume++;
			set_volume( current_volume );
		}
		if(keyin.Event.KeyEvent.wVirtualKeyCode==VK_DOWN)
		{
			current_volume--;
			if( current_volume < 0 ) current_volume = 0;
			set_volume( current_volume );
		}
	}

	main_mod_close();
	
	return 0;
}

void main_mod_init( void )
{
	int a;
	for( a = 0; a < 64; a++ )
	{
		patterndata[ a ] = (note*)malloc( CHANNELS_MAX * 4 * 64 );
	}
	for( a = 0; a < 31; a++ )
	{
		sampledata[ a ] = (char*)malloc( 70000 );
	}
	tables_init();
	create_user_info();
	sound_init();
}

void main_mod_close( void )
{
	int a;
	for( a = 0; a < 64; a++ )
	{
		free( patterndata[ a ] );
	}
	for( a = 0; a < 31; a++ )
	{
		free( sampledata[ a ] );
	}
	sound_close();
}

int load_mod( char *filename )
{
	FILE *f = fopen( filename, "rb" );
	if( f )
	{
		load_opened_file( f );
		fclose( f );
		return 1;
	}
	return 0;
}

int load_pdb( char *filename )
{
	FILE *f = fopen( filename, "rb" );
	if( f )
	{
		fseek( f, 0x164, 0 );
		load_opened_file( f );
		fclose( f );
		return 1;
	}
	return 0;
}

int load_opened_file( FILE *f )
{
	uint i;
	sample *sptr;

	//load header
	fread( &song, 1084, 1, f );
	channels_setup();
		
	maxp = 0;
	for( i = 0; i < 128; i++ )
	{
		if( song.patterntable[i] > maxp )
			maxp = song.patterntable[i];
    }
	if( maxp > 63 ) maxp = 63;
        
	for( i = 0; i < 64; i++ )
	{
		if( i <= maxp )  fread( patterndata[i], PAT_SIZE, 1, f );
	}
	convert_song_for_ARM();
    for( i = 0; i < 31; i++ ) 
	{
		sptr = song.samples[ i ];
		sptr->length = (uint)ByteSwap16( sptr->length );
		sptr->replen = (uint)ByteSwap16( sptr->replen );
		sptr->reppnt = (uint)ByteSwap16( sptr->reppnt );
		sptr->length *= 2;
		sptr->reppnt *= 2;
		sptr->replen *= 2;
		if (sptr->length == 0) continue;
		fread( sampledata[i], sptr->length, 1, f );
        if( sptr->replen + sptr->reppnt > sptr->length )
			sptr->replen = sptr->length - sptr->reppnt;
	}

	ECHO = song.title[19];
	ECHOLEN = song.title[18];
	if( ECHOLEN > 24 ) ECHO = 24;
	if( ECHOLEN == 0 ) ECHOLEN = 24;
	if( ECHO == 0 ) ECHO = 100;

	channels_setup();
	start_clear();
	echo_setup( ECHO, ECHOLEN );
	create_user_info();

    return 1;
}

void show_mod_info( void )
{
	int a;
	for( a = 0; a < 31; a++ )
	{
		for( int s = 0; s < 20; s++ )
			printf( "%c", song.samples[ a ]->name[ s ] );
		printf( "\n" );
	}
}

void channels_setup( void )
{
	ulong cc;
	long vol;
	
	//channels setup:
	CHANNELS = 4;
	if(song.signature[0]=='6') CHANNELS = 6;
	if(song.signature[0]=='8') CHANNELS = 8;
	if(song.signature[0]=='O') CHANNELS = 8;
	if(song.signature[0]=='C') CHANNELS = 12;
	if(song.signature[0]=='X') CHANNELS = 16;
    mod_info.CHANNELS = (uint)CHANNELS;
	for( vol = 32, cc = 0; cc < CHANNELS>>1; cc ++, vol += (64/CHANNELS) )
	{
		channels[cc].global_volume_l = 64;
		channels[cc].global_volume_r = (uint)vol;
	}
	for( vol = 64, cc = CHANNELS>>1; cc < CHANNELS; cc ++, vol -= (64/CHANNELS) )
	{
		channels[cc].global_volume_l = (uint)vol;
		channels[cc].global_volume_r = 64;
	}
	//==============
}

void convert_song_for_ARM( void )
{
	int i = 0;
	char *ss = (char*)&song._samples;
	for( i = 0; i < 31; i++ )
	{
		song.samples[ i ] = (sample*)ss;
		ss += 30;
	}
}

void start_clear( void )
{
	uint a;
	for( a = 0; a < CHANNELS; a++ ) 
	{
		channels[a].volume = 0; channels[a].period = 1; channels[a].echo_volume = 0;
		channels[a].pitch = 0;
		channels[a].spec_effects = 0;
		channels[a].cutoff = 255;
		channels[a].cold_volume = 0;
		channels[a].res_volume = 1;//ByteSwap32(1);
		channels[a].res_ptr = 0;
		channels[a].res_delta = 255<<15;
		channels[a].wah_offset = 256<<16;//ByteSwap32(256<<16);
		channels[a].wah_amp = 1500;//ByteSwap32(1500);
		channels[a].wah_add = -1500;//ByteSwap32(-1500);
		channels[a].p_delta=0;
		channels[a].v_up=0;
		channels[a].v_down=0;
		channels[a].anticlick = 0;
		channels[a].anticlick_start = 0;
		channels[a].previous_value = 0;
	  
		channels[a].echo_volume = ByteSwap32( 0 );
        channels[a].sampdata = 0;
		channels[a].length = 0;
		channels[a].replen = 0;
		channels[a].reppnt = 0;
		channels[a].delta = 0;
		channels[a].ticks = 0;
		channels[a].rep = 0;
	}
	for( a = 0; a < 2; a++ ) 
	{
		one[0].echo_volume = 0;
		one[0].pitch = 0;
		one[0].spec_effects = 0;
		one[0].cutoff = 255;
		one[a].cold_volume = 0;
		one[a].res_volume = 1;//ByteSwap32(1);
		one[a].res_ptr = 0;
		one[a].res_delta = 255<<15;//ByteSwap32(255<<15);
		one[a].wah_offset = 256<<16;//ByteSwap32(256<<16);
		one[a].wah_amp = 1500;//ByteSwap32(1500);
		one[a].wah_add = -1500;//ByteSwap32(-1500);
		one[a].p_delta=0;
		one[a].v_up=0;
		one[a].v_down=0;
		one[a].anticlick = 0;
		one[a].anticlick_start = 0;
		one[a].previous_value = 0;
	}
	convert_song_for_ARM();
}

void mod_play( void )
{
	mod_info._playrate = (uint)frequency;
	mod_info._tablepos = 0;
	mod_info._patternpos = 0;
	mod_info._bpm = 125 ;
	mod_info._onetick = (((ulong)mod_info._playrate*25)<<8)/(mod_info._bpm*10);
	mod_info._patternticks = ByteSwap32( mod_info._onetick + 1 );
	mod_info._speed = ByteSwap32( 6 );
	mod_info._sp = ByteSwap32( 2 );
	mod_info._sampleticksconst = ByteSwap32( (3546894UL / mod_info._playrate)<<16 );
	mod_info._status = 2;
	
	mod_info._playrate = (uint)ByteSwap16( mod_info._playrate );
	mod_info._bpm = ByteSwap32( 125 );
	mod_info._onetick = ByteSwap32( mod_info._onetick );
}

void tables_init(void)
{
	int r;
	int s;
	pp[1712]=0;pp[1616]=1;pp[1524]=2;pp[1440]=3;pp[1356]=4;pp[1280]=5;
	pp[1208]=6;pp[1140]=7;pp[1076]=8;pp[1016]=9;pp[960]=10;pp[906]=11;
	pp[856]=12;pp[808]=13;pp[762]=14;pp[720]=15;pp[678]=16;pp[640]=17;
	pp[604]=18;pp[570]=19;pp[538]=20;pp[508]=21;pp[480]=22;pp[453]=23;
	pp[428]=24;pp[404]=25;pp[381]=26;pp[360]=27;pp[339]=28;pp[320]=29;
	pp[302]=30;pp[285]=31;pp[269]=32;pp[254]=33;pp[240]=34;pp[226]=35;
	pp[214]=36;pp[202]=37;pp[190]=38;pp[180]=39;pp[170]=40;pp[160]=41;
	pp[151]=42;pp[143]=43;pp[135]=44;pp[127]=45;pp[120]=46;pp[113]=47;
	pp[107]=48;pp[101]=49;pp[95]=50;pp[90]=51;pp[85]=52;pp[80]=53;
	pp[75]=54;pp[71]=55;pp[67]=56;pp[63]=57;pp[60]=58;pp[56]=59;
	for( r = 0; r < reverb_number; r++ )
	{
		reverb_offset[r] = (uchar)rand();
		reverb_offset[r] >>= 1;
		reverb_offset[r] <<= 1;
	}
	//Sin table:
	for( r = 0; r < 256; r++ )
	{
		s = sin_tab[ r ];
		s -= 128;
		sin_tab[ r ] = (char)s;
	}
}

void set_volume( long vol )
{
	VOLUME = (uint)vol;
	mod_info.VOLUME = (uint)vol;
}

void echo_setup( long echo_volume, long size_in_ticks )
{
	if( CLASSIC == 0 ) 
	{
		mod_info.echo_buffer = (void*)echo_buffer;
		mod_info.echo_size = size_in_ticks;
		mod_info.echo_vol = echo_volume;
		song.title[19] = (uchar)echo_volume;
		song.title[18] = (uchar)size_in_ticks;
		mod_info.echo_pointer = 0;
	}
	else
	{
		mod_info.echo_buffer = 0;
	}
}

void create_user_info( void )
{
	mod_info.resonance_buffer = (char*)sin_tab;
	mod_info.reverb_offset = (void*)reverb_offset;
	mod_info.reverb_number = reverb_number;
	mod_info.record_pos = 61000;
	mod_info.rec_pointer = 0;
	mod_info.rec_count = 0;
	mod_info.rec_add = 0;
	mod_info._arm_code = 0;
	mod_info._channels = (channel*)ByteSwap32( channels );
	mod_info._patternticks = ByteSwap32( patternticks );
	mod_info._onetick = ByteSwap32( onetick );
	mod_info._sp = ByteSwap32( sp );
	mod_info._speed = ByteSwap32( speed );
	mod_info._bpm = ByteSwap32( bpm );
	mod_info._patterndata = (note**)ByteSwap32( patterndata );
	mod_info._patterndata2 = patterndata;
	mod_info._song = (module*)ByteSwap32( &song );
	mod_info._song2 = &song;
	mod_info._tablepos = (uint)ByteSwap16( tablepos );
	mod_info._patternpos = (uint)ByteSwap16( patternpos );
	mod_info._status = status;
	mod_info._one = (channel*)ByteSwap32( one );
	mod_info._fine = (uint*)ByteSwap32( fine );
	mod_info._fine2 = (uint*)ByteSwap32( fine );
	mod_info._sampleticksconst = ByteSwap32( sampleticksconst );
	mod_info._pp = (char*)ByteSwap32( pp );
	mod_info._sampledata = (char**)ByteSwap32( sampledata );
	mod_info._sampledata2 = sampledata;
	mod_info._num_of_mods = 1;
	mod_info._playrate = (uint)ByteSwap16( (uint)frequency );
	mod_info.CHANNELS = (uint)CHANNELS;
	mod_info.VOLUME = VOLUME;
}

void render_piece_of_sound( void *buf, long buf_size )
{
	mod_info.win32_buffer = buf;
	mod_info.win32_frameCount = buf_size;
	ARMlet_Main( 0, &mod_info, 0 );
}


// ######################################
// ######### DIRECT SOUND PART: #########
// ######################################


#define NUMEVENTS 2
LPDIRECTSOUND               lpds;
DSBUFFERDESC                dsbdesc;
LPDIRECTSOUNDBUFFER         lpdsb = 0;
LPDIRECTSOUNDBUFFER         lpdsbPrimary;
LPDIRECTSOUNDNOTIFY         lpdsNotify;
WAVEFORMATEX                *pwfx;
HMMIO                       hmmio;
MMCKINFO                    mmckinfoData, mmckinfoParent;
DSBPOSITIONNOTIFY           rgdsbpn[NUMEVENTS];
HANDLE                      rghEvent[NUMEVENTS];

//Sound thread:
HANDLE sound_thread;
SECURITY_ATTRIBUTES atr;
bool StreamToBuffer( ulong dwPos )
{
	LONG            lNumToWrite;
	DWORD           dwStartOfs;
	VOID            *lpvPtr1, *lpvPtr2;
	DWORD           dwBytes1, dwBytes2;
	static DWORD    dwStopNextTime = 0xFFFF;
 
	if (dwStopNextTime == dwPos)   // All data has been played
	{
		lpdsb->Stop();
		dwStopNextTime = 0xFFFF;
		return TRUE;
	}

	if (dwStopNextTime != 0xFFFF)  // No more to stream, but keep
		                           // playing to end of data
		return TRUE;

	if (dwPos == 0)
		dwStartOfs = rgdsbpn[NUMEVENTS - 1].dwOffset;
	else
		dwStartOfs = rgdsbpn[dwPos-1].dwOffset;

	lNumToWrite = (LONG) rgdsbpn[dwPos].dwOffset - dwStartOfs;
	if (lNumToWrite < 0) lNumToWrite += dsbdesc.dwBufferBytes;

	IDirectSoundBuffer_Lock(lpdsb,
                 dwStartOfs,       // Offset of lock start
                 lNumToWrite,      // Number of bytes to lock
                 &lpvPtr1,         // Address of lock start
                 &dwBytes1,        // Count of bytes locked
                 &lpvPtr2,         // Address of wrap around
                 &dwBytes2,        // Count of wrap around bytes
                 0);               // Flags

	//Write data to the locked buffer:
	render_piece_of_sound( lpvPtr1, dwBytes1 >> 2 );

	IDirectSoundBuffer_Unlock(lpdsb, lpvPtr1, dwBytes1, lpvPtr2, dwBytes2);

	return TRUE;
}

unsigned long __stdcall sound_callback( void *par )
{
	while( 1 )
	{
	    DWORD dwEvt = MsgWaitForMultipleObjects(
				NUMEVENTS,      // How many possible events
				rghEvent,       // Location of handles
				FALSE,          // Wait for all?
				INFINITE,       // How long to wait
				QS_ALLINPUT);   // Any message is an event
 
	    dwEvt -= WAIT_OBJECT_0;
 
	    // If the event was set by the buffer, there's input
	    // to process. 
 
	    if (dwEvt < NUMEVENTS) 
	    {
		if( lpdsb )	StreamToBuffer(dwEvt); // copy data to output stream
	    }
	}
	return 0;
}

void sound_init( void )
{
	HWND hWnd = GetForegroundWindow();
	if( hWnd == NULL )
	{
		hWnd = GetDesktopWindow();
	}
	if FAILED( DirectSoundCreate( 0, &lpds, NULL ) )
	{
		MessageBox( hWnd,"DSound: DirectSoundCreate error","PsyTexx Error",MB_OK);
		return;
	}
	if FAILED( IDirectSound_SetCooperativeLevel(
               lpds, hWnd, DSSCL_PRIORITY ) )
	{
		MessageBox( hWnd,"DSound: SetCooperativeLevel error","PsyTexx Error",MB_OK);
        return;
	}

	// Obtain primary buffer

    ZeroMemory( &dsbdesc, sizeof(DSBUFFERDESC) );
    dsbdesc.dwSize = sizeof(DSBUFFERDESC);
    dsbdesc.dwFlags = DSBCAPS_PRIMARYBUFFER;
    if FAILED( lpds->CreateSoundBuffer(&dsbdesc, &lpdsbPrimary, NULL) )
	{
		MessageBox( hWnd,"DSound: CreateSoundBuffer error","PsyTexx Error",MB_OK);
		return;
	}

    // Set primary buffer format

    WAVEFORMATEX wfx;
    memset(&wfx, 0, sizeof(WAVEFORMATEX)); 
    wfx.wFormatTag = WAVE_FORMAT_PCM; 
    wfx.nChannels = 2; 
    wfx.nSamplesPerSec = 44100; 
    wfx.wBitsPerSample = 16; 
    wfx.nBlockAlign = wfx.wBitsPerSample / 8 * wfx.nChannels;
    wfx.nAvgBytesPerSec = wfx.nSamplesPerSec * wfx.nBlockAlign;
    lpdsbPrimary->SetFormat(&wfx);

	pwfx = &wfx;

	// Secondary buffer:
	
	memset(&dsbdesc, 0, sizeof(DSBUFFERDESC)); 
    dsbdesc.dwSize = sizeof(DSBUFFERDESC); 
    dsbdesc.dwFlags = 
            DSBCAPS_GETCURRENTPOSITION2   // Always a good idea
            | DSBCAPS_GLOBALFOCUS         // Allows background playing
            | DSBCAPS_CTRLPOSITIONNOTIFY; // Needed for notification
 
    // The size of the buffer is arbitrary, but should be at least
    // two seconds, to keep data writes well ahead of the play
    // position.
 
    dsbdesc.dwBufferBytes = 32000;  
    dsbdesc.lpwfxFormat = pwfx; 

    if FAILED( IDirectSound_CreateSoundBuffer(
              lpds, &dsbdesc, &lpdsb, NULL) )
    {
		MessageBox( hWnd,"DSound: Create secondary buffer error","PsyTexx Error",MB_OK);
		return;
	}

	//Create buffer events:
	
	for (int i = 0; i < NUMEVENTS; i++)
    {
        rghEvent[i] = CreateEvent(NULL, FALSE, FALSE, NULL);
        if (NULL == rghEvent[i]) 
		{
			MessageBox( hWnd,"DSound: Create event error","PsyTexx Error",MB_OK);
			return;
		}
    }
	rgdsbpn[0].dwOffset = 0;
    rgdsbpn[0].hEventNotify = rghEvent[0];
    rgdsbpn[1].dwOffset = (dsbdesc.dwBufferBytes/2);
    rgdsbpn[1].hEventNotify = rghEvent[1];
	
	if FAILED( lpdsb->QueryInterface( IID_IDirectSoundNotify, (VOID **)&lpdsNotify) )
	{
		MessageBox( hWnd,"DSound: QueryInterface error","PsyTexx Error",MB_OK);
		return;
	}
 
    if FAILED(IDirectSoundNotify_SetNotificationPositions(
             lpdsNotify, NUMEVENTS, rgdsbpn))
    {
        IDirectSoundNotify_Release(lpdsNotify);
		MessageBox( hWnd,"DSound: SetNotificationPositions error","PsyTexx Error",MB_OK);
		return;
    }

	IDirectSoundBuffer_Play( lpdsb, 0, 0, DSBPLAY_LOOPING );

	//Create main thread:
	atr.nLength = sizeof(atr);
	atr.lpSecurityDescriptor = 0;
	atr.bInheritHandle = 0;
	sound_thread = CreateThread( &atr, 4096, &sound_callback, 0, 0, 0 );
}

void sound_close( void )
{
    CloseHandle( sound_thread );
    if( lpdsb )
    {
        if (lpdsNotify)
	    lpdsNotify->Release();
	if (lpds)
	    lpds->Release();
    }
}