/////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////
////																					 ////
////																					 ////
////								  - SCOLSound.cpp -									 ////
////																					 ////
////																					 ////
////				Implémentation des fonctions SCOL de la librairie sonore			 ////
////									 Version  1.0									 ////
////																					 ////
////								  Hilaire Verschuere								 ////
////																					 ////
////																					 ////
/////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////



#include "..\SCOL\ZooSCOL.h"
#include "..\SCOL\SCOLsound.h"



/////////////////////////////////////////////////////////////////////////////////////////////
// Static variables
/////////////////////////////////////////////////////////////////////////////////////////////
HSoundManager* pHSoundManager = NULL ;
HWND hwnd ;


/////////////////////////////////////////////////////////////////////////////////////////////
// Global variables
/////////////////////////////////////////////////////////////////////////////////////////////
int	AsSnd ;
int SND_TIME ;
int SND_NEXT ;



//////////////////////////////////////////////////////////////////////////////////////////////
///	Initialize Direct Sound											
//////////////////////////////////////////////////////////////////////////////////////////////
bool initDirectSound()
{
	if ( pHSoundManager ) 
	{
		if( !pHSoundManager->IsDS_OK() ) return false ;
		return true ;
	}

	pHSoundManager = new HSoundManager() ;

	if( FAILED( pHSoundManager->Create( hwnd ) ) )
	{
		MMechostr(1, "Error initializing DirectSound.\n") ;
		return false ;
	}
	MMechostr(1, "DirectSound initialized.\n") ;
	
	return true ;
}





//////////////////////////////////////////////////////////////////////////////////////////////
///		asSndCreate 														
//////////////////////////////////////////////////////////////////////////////////////////////
// fun [Chn I] AsSnd
int asSndCreate(mmachine m)
{
	if( !initDirectSound() ) { MMpull(m) ; MMset(m,0,NIL) ; return 0 ; }

	int	flag = MTOI( MMpull(m) ) ; /* AS_SND_CTRL_3D | AS_SND_CTRL_CTRLFREQUENCY | AS_SND_CTRL_CTRLPAN */

	if( flag==NIL ) flag = 0 ;
	WSound* pWSound = new WSound( flag ) ;

	int	asSnd = MMmalloc(m,2,TYPETAB) ;
	if ( asSnd == NIL ) { SAFE_DELETE(pWSound) ; MMset(m,0,NIL) ; return MERRMEM ; }

	MMstore( m, asSnd, 0, (int)pWSound ) ;
	MMstore( m, asSnd, 1, 0 ) ;
	MMpush(m, PTOM(asSnd)) ;

	return OBJcreate(m, AsSnd, (int)pWSound, -1, -1) ;
}





//////////////////////////////////////////////////////////////////////////////////////////////
///		asSndDestroy														
//////////////////////////////////////////////////////////////////////////////////////////////
// fun [AsSnd] I
int asSndDestroy (mmachine m)
{
	int	asSnd = MTOP(MMget(m,0)) ;
	if ( asSnd == NIL ) { MMset(m,0,NIL) ; return 0 ; }

	WSound* pWSound = (WSound*)MMfetch(m, asSnd, 0) ;
	if( !pWSound ) { MMset(m,0,NIL) ; return 0 ; }
	
	if( pWSound->pZSound ) // Si il existe un H3d associé à l'AsSnd, on détruit ce H3d qui n a plus de raison d'exister
	{	
		int hash_tab = MTOP( MMfetch(m, asSnd, 1) ) ;
		int h3d = NodeTOHandle(m, hash_tab, (int)pWSound->pZSound ) ;
		if( h3d!=NIL)
		{
			ZScene* scene = pWSound->pZScene ;
			DeleteNode(m, hash_tab, (ZNode*)pWSound->pZSound);	// supprime réellement le pointeur C et sa descendance
			DelObj(m, hash_tab, h3d );							// supprime le pointeur C dans le H3d et dans la hash_tab
			scene->updateGraphList = true;
		}
	}
	
	OBJdelTM(m,AsSnd,PTOM(asSnd)) ;	
	MMset(m,0,0) ;

	return 0 ;
}


// Delete the AsSnd ///////////////////////////////////////////////////////////////////////
int destroyAsSnd(mmachine m,int handsys,int asSnd)
{
	WSound* pWSound = (WSound*) MMfetch(m, MTOP(asSnd), 0) ;
	if( !pWSound ) { MMset(m,0,NIL) ; return 0 ; }

	SAFE_DELETE( pWSound ) ;
	
	MMstore( m, MTOP(asSnd), 0, NULL ) ;
	MMechostr(1,"AsSnd destroyed\n");

	return 0;
}





//////////////////////////////////////////////////////////////////////////////////////////////
///		asSndCopy 														
//////////////////////////////////////////////////////////////////////////////////////////////
// fun [Chn AsSnd] AsSnd
int asSndCopy (mmachine m)
{
	int	asSnd = MTOP( MMpull(m) ) ;
	if( asSnd==NIL ) { MMset(m,0,NIL) ; return 0 ; }

	WSound* copyWSound ;
	WSound* pWSound = (WSound*)MMfetch(m, asSnd, 0) ;
	if( !pWSound ) { MMset(m,0,NIL) ; return 0 ; }

	if( !pWSound->pHSound )
	{
		MMpush(m, ITOM(pWSound->flag) ) ;
		return asSndCreate( m ) ;
	}

	if( pWSound->pHSound->m_streaming )
	{
		if( pWSound->pHSound->DataType )
		{
			copyWSound = new WSound( *pWSound ) ;
			if( FAILED( copyWSound->pHSound->CreateStreaming( copyWSound->flag ) ) ) { SAFE_DELETE( pWSound->pHSound ) ; MMset(m,0,NIL) ; return 0 ; }
		}
		else
		{
			MMpush(m, ITOM(pWSound->flag) ) ;
			asSndCreate( m ) ;

			int sizePath = strlen(pWSound->pHSound->m_fileName) ;
			int P = MMmalloc( m, STR_SIZE( sizePath ) , TYPEBUF ) ;
			MMstore( m, P, 0, sizePath ) ;
			char *S = MMstartstr( m , P ) ;
			_memcpy( S, pWSound->pHSound->m_fileName, sizePath ) ;
			S[ sizePath ] = 0 ;

			MMpush( m, PTOM( P ) ) ; 
			MMpush( m, ITOM( AS_SND_STREAMING ) ) ;

			return asSndLoad( m ) ;
		}
	}
	else copyWSound = new WSound( *pWSound ) ;

	int objSound2 = MMmalloc(m,2,TYPETAB) ;
	if ( objSound2 == NIL ) { SAFE_DELETE(copyWSound) ; MMset(m,0,NIL) ; return MERRMEM ; }

	MMstore( m, objSound2, 0, (int)copyWSound ) ;
	MMstore( m, objSound2, 1, 0 ) ;
	MMpush(m, PTOM(objSound2)) ;

	return OBJcreate(m, AsSnd, (int)copyWSound, -1, -1) ;
}




//////////////////////////////////////////////////////////////////////////////////////////////
///		asSndInit 
//////////////////////////////////////////////////////////////////////////////////////////////
// fun [AsSnd I I I I] AsSnd
int asSndInit (mmachine m)
{
	int flag		  = MTOI( MMpull(m) ) ;
	int bitPerSample  = MTOI( MMpull(m) ) ;
	int freq		  = MTOI( MMpull(m) ) ;
	int channel		  = MTOI( MMpull(m) ) ;
	int	asSnd	  = MTOP( MMget(m,0) ) ;
	if( asSnd==NIL || freq==NIL || bitPerSample==NIL || channel==NIL || flag==NIL ) { MMset(m,0,NIL) ; return 0 ; }
	
	WSound*  pWSound = (WSound*)MMfetch(m, asSnd, 0) ;
	if( !pWSound ) { MMset(m,0,NIL) ; return 0 ; }
	
	SAFE_DELETE( pWSound->pHSound ) ;
	pWSound->load( new HData( true ) ) ;

	if( FAILED( pWSound->pHSound->SetData( channel, bitPerSample, freq, flag ) ) ) 
	{ SAFE_DELETE( pWSound->pHSound ) ; MMset(m,0,NIL) ; return 0 ; }

	if( FAILED( pWSound->pHSound->CreateStreaming( pWSound->flag ) ) ) 
	{ SAFE_DELETE( pWSound->pHSound ) ; MMset(m,0,NIL) ; return 0 ; }

	return 0 ;	
}




//////////////////////////////////////////////////////////////////////////////////////////////
///		asSndFeed 
//////////////////////////////////////////////////////////////////////////////////////////////
// fun [AsSnd S I] AsSnd
int asSndFeed (mmachine m)
{
	int position = MTOI( MMpull(m) ) ;
	int string	 = MTOP( MMpull(m) ) ;
	int asSnd = MTOP( MMget(m,0) ) ;
	if( asSnd==NIL || ( (position==NIL || position==0) && string==NIL ) ) { MMset(m,0,NIL) ; return 0 ; }

	WSound* pWSound = (WSound*)MMfetch(m, asSnd, 0) ;
	if( !pWSound || !pWSound->pHSound || !pWSound->pHSound->DataType || !pWSound->pHSound->m_pwfx ) { MMset(m,0,NIL) ; return 0 ; }

	if( position==NIL ) position = 0 ;

	char* data = ( (string==NIL) ? NULL : (char*)MMstartstr(m,string) ) ;
	unsigned int dataSize = ( (string==NIL) ? 0 : MMsizestr(m, string) ) ;

	if( FAILED( pWSound->pHSound->AddData( data, dataSize, MsToChar( pWSound->pHSound->m_pwfx, position ) ) ) )
		{ MMset(m,0,NIL) ; return 0 ; }

	return 0 ;
}




//////////////////////////////////////////////////////////////////////////////////////////////
///		asSndLoad														
//////////////////////////////////////////////////////////////////////////////////////////////
// fun [AsSnd P I] AsSnd
int asSndLoad (mmachine m)
{	
	int flag      = MTOI( MMpull(m) ) ; /* AS_SND_STREAMING ou AS_SND_STATIC */
	int filename  = MTOP( MMpull(m) ) ;
	int	asSnd  = MTOP( MMget(m,0) ) ;
	if( asSnd==NIL || filename==NIL || flag==NIL ) { MMset(m,0,NIL) ; return 0 ; }

	WSound* pWSound = (WSound*)MMfetch(m, asSnd, 0) ;
	if( !pWSound ) { MMset(m,0,NIL) ;	return 0 ; }

	// Get the path of the file to open
	char* strFileName = (char*)MMstartstr(m,filename) ;	
	
	if( HWave::IsAWaveFile(strFileName) ) pWSound->load( new HWave( true ) ) ;
	else if( HMp3::IsAMp3File(strFileName) ) pWSound->load( new HMp3( true  ) ) ;
	else { MMechostr(1,"File %s not supported.\n", strFileName) ; MMset(m,0,NIL) ; return 0 ; }
	
    // Load the file
    if( FAILED( pWSound->pHSound->Open( strFileName ) ) )
    {
        MMechostr(1, "Bad file: %s", strFileName) ;
        SAFE_DELETE( pWSound->pHSound ) ;
		MMset(m,0,NIL) ;	
		return 0 ;
    }

	//If the file is smaller than the buffer, 
	if( ( ( (pWSound->pHSound->m_dwNotifySize*NB_PLAY_NOTIFICATIONS) > pWSound->pHSound->m_dwSize ) || (flag==AS_SND_STATIC) )  )
	{
		if( FAILED( pWSound->pHSound->CreateStatic( pWSound->flag ) ) ) { SAFE_DELETE( pWSound->pHSound ) ; MMset(m,0,NIL) ; return 0 ; }
	}
	// Set up the direct sound buffer.  Request the NOTIFY flag, so that we are notified as the sound buffer plays.
    else 
	{
		if( FAILED( pWSound->pHSound->CreateStreaming( pWSound->flag ) ) ) { SAFE_DELETE( pWSound->pHSound ) ; MMset(m,0,NIL) ; return 0 ; }
	}

	// Setting volume and pan for this buffer
	pWSound->SetVolume( pWSound->GetVolume() ) ;
	pWSound->SetPan( pWSound->GetPan() ) ;

	//Filling the buffer
	if( FAILED( pWSound->pHSound->FillBufferWithSound( 0L, pWSound->pHSound->m_dwDSBufferSize ) ) ) 
	{ 
		MMechostr(1, "Corrupt file %s.\n", strFileName) ;
		SAFE_DELETE( pWSound->pHSound ) ; 
		MMset(m,0,NIL) ; 
		return 0 ; 
	}

	return 0 ;
}



//////////////////////////////////////////////////////////////////////////////////////////////
///		asSndNext														
//////////////////////////////////////////////////////////////////////////////////////////////
// fun [AsSnd fun [AsSnd u0] u1 u0 P] AsSnd
int asSndNext (mmachine m)
{
	int filename = MTOP( MMpull(m) ) ;
	int reflex	 = MTOP( MMget(m,1) ) ;
	int	asSnd    = MTOP( MMget(m,2) ) ;
	
	if( asSnd==NIL ) { MMpull(m) ; MMpull(m) ; MMset(m,0,NIL) ; return 0 ; }

	WSound* pWSound = (WSound*)MMfetch(m, asSnd, 0) ;
	if( !pWSound ) { MMset(m,0,NIL) ;	return 0 ; }

	if( filename==NIL )
	{
		pWSound->pHSound->RemoveNextFile() ;
		MMpull(m) ; MMpull(m) ; MMset(m,0,NIL) ; return 0 ;
	}

	// Get the path of the file to open
	char* strFileName = (char*)MMstartstr(m,filename) ;	

	if( (pWSound->pHSound->WaveType || pWSound->pHSound->Mp3Type) && pWSound->pHSound->SameProperties( strFileName ) )
	{
		pWSound->pHSound->SetNextFile( strFileName ) ;
	}
	else
	{
		MMechostr( 0, "asSndNext error, bad AsSnd type." ) ;
		MMpull(m) ; MMpull(m) ; MMset(m,0,NIL) ; return 0 ; 
	}
	
	return OBJaddreflex(m,AsSnd,RFL_NEXT_ASSND) ;
}



//////////////////////////////////////////////////////////////////////////////////////////////
///		getNextEvent														
//////////////////////////////////////////////////////////////////////////////////////////////
int getNextEvent(mmachine m,HWND h,unsigned msg,UINT id,LONG param,int *ret)
{
	int k ;

	if( !(k = OBJbeginreflex( m, AsSnd, id, RFL_NEXT_ASSND ) ) ) k = OBJcallreflex(m,0) ;

	return k ;
}






///////////////////////////////////////////////////////////////////////////////////////////////
///		asSndPlay														
///////////////////////////////////////////////////////////////////////////////////////////////
// fun [AsSnd I] AsSnd
int asSndPlay (mmachine m)
{
	int	loop = MTOI( MMpull(m) ) ;
	int	asSnd = MTOP( MMget(m,0) ) ;
	if( asSnd==NIL ) { MMset(m,0,NIL) ; return 0 ; }

	WSound* pWSound = (WSound*)MMfetch(m, asSnd, 0) ;	
	if( !pWSound || !pWSound->pHSound  ) { MMset(m,0,NIL) ; return 0 ; }

    if( FAILED( pWSound->pHSound->Play( ( loop==NIL || loop==0 ) ? false : true ) ) ) { MMset(m,0,NIL) ; return 0 ; }
	
	return 0 ;
}



//////////////////////////////////////////////////////////////////////////////////////////////
///		asSndStop														
//////////////////////////////////////////////////////////////////////////////////////////////
// fun [AsSnd] AsSnd
int asSndStop (mmachine m)
{
	int	asSnd = MTOP( MMget(m,0) ) ;
	if( asSnd==NIL ) { MMset(m,0,NIL) ; return 0 ; }

	WSound* pWSound = (WSound*)MMfetch(m, asSnd, 0) ;
	if( !pWSound || !pWSound->pHSound ) { MMset(m,0,NIL) ; return 0 ; }

	if( FAILED( pWSound->pHSound->Stop() ) ) { MMset(m,0,NIL) ; return 0 ; }

	return 0 ;
}



//////////////////////////////////////////////////////////////////////////////////////////////
///		asSndIsPlaying
//////////////////////////////////////////////////////////////////////////////////////////////
// fun [AsSnd] I
int asSndIsPlaying (mmachine m)
{
	int	asSnd = MTOP( MMget(m,0) ) ;
	if( asSnd==NIL ) { MMset(m,0,NIL) ; return 0 ; }

	WSound* pWSound = (WSound*)MMfetch(m, asSnd, 0) ;
	if( !pWSound || !pWSound->pHSound ) { MMset(m,0,NIL) ; return 0 ; }

	MMset( m, 0, ITOM((int)pWSound->pHSound->IsSoundPlaying()) ) ;

	return 0 ;
}





//////////////////////////////////////////////////////////////////////////////////////////////
///		asEnableAllSnd														
//////////////////////////////////////////////////////////////////////////////////////////////
// fun [] I
int asEnableAllSnd (mmachine m)
{
	if( !initDirectSound() ) { MMpush(m,NIL) ; return 0 ; }

	(pHSoundManager)->EnableSound() ;
	
	MMpush(m,ITOM(0)) ;
	return 0 ;
}



//////////////////////////////////////////////////////////////////////////////////////////////
///		asDisableAllSnd														
//////////////////////////////////////////////////////////////////////////////////////////////
// fun [] I
int asDisableAllSnd (mmachine m)
{
	if( !initDirectSound() ) { MMpush(m,NIL) ; return 0 ; }

	(pHSoundManager)->DisableSound() ;
	
	MMpush(m,ITOM(0)) ;
	return 0 ;
}




//////////////////////////////////////////////////////////////////////////////////////////////
///		asSndReset														
//////////////////////////////////////////////////////////////////////////////////////////////
// fun [AsSnd] AsSnd
int asSndReset (mmachine m)
{
	int	asSnd = MTOP( MMget(m,0) ) ;
	if( asSnd==NIL ) { MMset(m,0,NIL) ; return 0 ; }

	WSound*  pWSound = (WSound*)MMfetch(m, asSnd, 0) ;
	if( !pWSound || !pWSound->pHSound ) { MMset(m,0,NIL) ; return 0 ; }

	if( FAILED( pWSound->pHSound->Reset() ) ) { MMset(m,0,NIL) ; return 0 ; }

	return 0 ;
}



//////////////////////////////////////////////////////////////////////////////////////////////
///		asSndGetSize														
//////////////////////////////////////////////////////////////////////////////////////////////
// fun [AsSnd] I
int asSndGetSize (mmachine m)
{
	int	asSnd = MTOP( MMget(m,0) ) ;
	if( asSnd==NIL ) { MMset(m,0,NIL) ; return 0 ; }

	WSound*  pWSound = (WSound*)MMfetch(m, asSnd, 0) ;
	if( !pWSound || !pWSound->pHSound ) { MMset(m,0,NIL) ; return 0 ; }
	
	int size = pWSound->pHSound->GetSizeMs() ;
	if( size < 0 ) { MMset(m,0,NIL) ; return 0 ; }

	MMset(m,0,ITOM( size ) ) ;
	return 0 ;
}



//////////////////////////////////////////////////////////////////////////////////////////////
///		asSndSetTime														
//////////////////////////////////////////////////////////////////////////////////////////////
// fun [AsSnd I I] AsSnd
int asSndSetTime (mmachine m)
{
	int	flag	 = MTOI( MMpull(m) ) ;
	int	time	 = MTOI( MMpull(m) ) ;
	int	asSnd = MTOP( MMget(m,0) ) ;
	if( asSnd==NIL || flag==NIL || time==NIL ) { MMset(m,0,NIL) ; return 0 ; }

	WSound* pWSound = (WSound*)MMfetch(m, asSnd, 0) ;
	if( !pWSound || !pWSound->pHSound || !pWSound->pHSound->m_pwfx ) { MMset(m,0,NIL) ; return 0 ; }

	if( time < 0 ) time = 0 ;
 
	if( FAILED( pWSound->pHSound->SetPosition( MsToChar( pWSound->pHSound->m_pwfx, time ), flag) ) ) { MMset(m,0,NIL) ; return 0 ; }

	return 0 ;
}



//////////////////////////////////////////////////////////////////////////////////////////////
///		asSndGetTime														
//////////////////////////////////////////////////////////////////////////////////////////////
// fun [AsSnd] I
int asSndGetTime (mmachine m)
{
	int	asSnd = MTOP( MMget(m,0) ) ;
	if( asSnd==NIL ) { MMset(m,0,NIL) ; return 0 ; }

	WSound* pWSound = (WSound*)MMfetch(m, asSnd, 0) ;
	if( !pWSound || !pWSound->pHSound || !pWSound->pHSound->m_pwfx ) { MMset(m,0,NIL) ; return 0 ; }
	
	int time = CharToMs( pWSound->pHSound->m_pwfx, pWSound->pHSound->GetPlayProgress() ) ;
	if( time < 0 ) { MMset(m,0,NIL) ; return 0 ; }

	MMset(m,0,ITOM( time ) ) ;
	return 0 ;
}



//////////////////////////////////////////////////////////////////////////////////////////////
///		asSetVolume 														
//////////////////////////////////////////////////////////////////////////////////////////////
// fun [I] I
int asSetVolume  (mmachine m)
{
	if( !initDirectSound() ) { MMset(m,0,NIL) ; return 0 ; }

	int	globalVolume = MTOI( MMget(m,0) ) ;
	if( globalVolume==NIL ) { MMset(m,0,NIL) ; return 0 ; }

	(pHSoundManager)->SetGlobalVolume((float)globalVolume) ;
	
	MMset(m,0,ITOM(globalVolume)) ;
	return 0 ;
}




//////////////////////////////////////////////////////////////////////////////////////////////
///		asGetVolume 														
//////////////////////////////////////////////////////////////////////////////////////////////
// fun [] I
int asGetVolume  (mmachine m)
{
	if( !initDirectSound() ) { MMpush(m,NIL) ; return 0 ; }

	int	globalVolume = (int)pHSoundManager->GetGlobalVolume() ;
	
	MMpush(m,ITOM(globalVolume)) ;
	return 0 ;
}



//////////////////////////////////////////////////////////////////////////////////////////////
///		asSndSetVolume														
//////////////////////////////////////////////////////////////////////////////////////////////
// fun [AsSnd I] AsSnd
int asSndSetVolume (mmachine m)
{
	int	volume	 = MTOI( MMpull(m) ) ;
	int	asSnd = MTOP( MMget(m,0) ) ;
	if( asSnd==NIL  || volume==NIL ) { MMset(m,0,NIL) ; return 0 ; }

	WSound* pWSound = (WSound*)MMfetch(m, asSnd, 0) ;
	if( !pWSound ) { MMset(m,0,NIL) ; return 0 ; }
		
	if( FAILED( pWSound->SetVolume(volume) ) )
	{
		MMechostr(1, "Setting AsSnd volume error\n") ;
        MMset(m,0,NIL) ;	
		return 0 ;
	}

	return 0 ;
}



//////////////////////////////////////////////////////////////////////////////////////////////
///		asSndGetVolume														
//////////////////////////////////////////////////////////////////////////////////////////////
// fun [AsSnd] I
int asSndGetVolume (mmachine m)
{
	int	asSnd = MTOP( MMget(m,0) ) ;
	if( asSnd==NIL ) { MMset(m,0,NIL) ; return 0 ; }

	WSound* pWSound = (WSound*)MMfetch(m, asSnd, 0) ;
	if( !pWSound ) { MMset(m,0,NIL) ; return 0 ; }
		
	MMset(m,0,ITOM( pWSound->GetVolume() ) ) ;

	return 0 ;
}



//////////////////////////////////////////////////////////////////////////////////////////////
///		asSndSetPan 														
//////////////////////////////////////////////////////////////////////////////////////////////
// fun [AsSnd I] AsSnd
int asSndSetPan  (mmachine m)
{
	int	pan	     = MTOI( MMpull(m) ) ;
	int	asSnd = MTOP( MMget(m,0) ) ;
	if( asSnd==NIL || pan==NIL ) { MMset(m,0,NIL) ; return 0 ; }

	WSound* pWSound = (WSound*)MMfetch(m, asSnd, 0) ;
	if( !pWSound || !(pWSound->flag & DSBCAPS_CTRLPAN) ) { MMset(m,0,NIL) ; return 0 ; }
	
	if( FAILED( pWSound->SetPan( pan ) ) )
	{
		MMechostr(1, "Setting AsSnd pan error\n") ;
        MMset(m,0,NIL) ;	
		return 0 ;
	}

	return 0 ;
}



//////////////////////////////////////////////////////////////////////////////////////////////
///		asSndGetPan														
//////////////////////////////////////////////////////////////////////////////////////////////
// fun [AsSnd] I
int asSndGetPan (mmachine m)
{
	int	asSnd = MTOP( MMget(m,0) ) ;
	if( asSnd==NIL ) { MMset(m,0,NIL) ; return 0 ; }

	WSound* pWSound = (WSound*)MMfetch(m, asSnd, 0) ;
	if( !pWSound || !(pWSound->flag & DSBCAPS_CTRLPAN) ) { MMset(m,0,NIL) ; return 0 ; }
	
	MMset(m,0,ITOM( pWSound->GetPan() )) ;

	return 0 ;
}



//////////////////////////////////////////////////////////////////////////////////////////////
///		asSndSetFrequency														
//////////////////////////////////////////////////////////////////////////////////////////////
// fun [AsSnd I] AsSnd
int asSndSetFrequency (mmachine m)
{
	int	freq     = MTOI( MMpull(m) ) ;
	int	asSnd = MTOP( MMget(m,0) ) ;
	if( asSnd==NIL || freq==NIL ) { MMset(m,0,NIL) ; return 0 ; }

	WSound* pWSound = (WSound*)MMfetch(m, asSnd, 0) ;
	if( !pWSound || !(pWSound->flag & DSBCAPS_CTRLFREQUENCY) || !pWSound->pHSound ) { MMset(m,0,NIL) ; return 0 ; }
	
	if( FAILED( pWSound->pHSound->SetFrequency(freq) ) )
	{
		MMechostr(1, "Setting AsSnd frequency error\n") ;
        MMset(m,0,NIL) ;	
		return 0 ;
	}

	return 0 ;
}



//////////////////////////////////////////////////////////////////////////////////////////////
///		asSndGetFrequency														
//////////////////////////////////////////////////////////////////////////////////////////////
// fun [AsSnd] I
int asSndGetFrequency (mmachine m)
{
	int	asSnd = MTOP( MMget(m,0) ) ;
	if( asSnd==NIL ) { MMset(m,0,NIL) ; return 0 ; }

	WSound* pWSound = (WSound*)MMfetch(m, asSnd, 0) ;
	if( !pWSound || !(pWSound->flag & DSBCAPS_CTRLFREQUENCY) || !pWSound->pHSound ) { MMset(m,0,NIL) ; return 0 ; }
	
	int freq = pWSound->pHSound->GetFrequency() ;
	if( !freq ) { MMset(m,0,NIL) ; return 0 ; }

	MMset(m,0,ITOM( freq )) ;

	return 0 ;
}



//////////////////////////////////////////////////////////////////////////////////////////////
///		asSndSetCallbackTime														
//////////////////////////////////////////////////////////////////////////////////////////////
// fun [AsSnd fun [AsSnd u0] u1 u0 [I r1]] AsSnd
int asSndSetCallbackTime(mmachine m)
{
	int times	 = MTOP( MMpull(m) ) ;
	int reflex	 = MTOP( MMget(m,1) ) ;
	int	asSnd = MTOP( MMget(m,2) ) ;
	if( asSnd==NIL ) { MMpull(m) ; MMpull(m) ; MMset(m,0,NIL) ; return 0 ; }

	WSound* pWSound = (WSound*)MMfetch(m, asSnd, 0) ;
	if( !pWSound || !pWSound->pHSound || !pWSound->pHSound->m_pwfx || pWSound->pHSound->IsSoundPlaying() || (pWSound->pHSound->DataType & AS_SND_LINEAR) ) { MMpull(m) ; MMpull(m) ; MMset(m,0,NIL) ; return 0 ; }

	if( pWSound->pHSound->pHSndNotify )
	{
		pWSound->pHSound->pHSndNotify->Stop() ;
		pWSound->pHSound->pHSndNotify->RemoveEvt() ;
	}

	if( reflex==NIL || times==NIL ) 
	{ 
		MMpull(m) ; MMpull(m) ;
		if( pWSound->pHSound->m_streaming )
		{
			pWSound->pHSound->pHSndNotify->SetNotify() ;
			pWSound->pHSound->pHSndNotify->Start() ;
		}
		else SAFE_DELETE( pWSound->pHSound->pHSndNotify ) ;

		return 0 ; 
	}
	else
	{
		if( !pWSound->pHSound->pHSndNotify ) pWSound->pHSound->pHSndNotify = new HSndNotify( pWSound->pHSound ) ;
		pWSound->pHSound->pHSndNotify->SetHandler( (int)pWSound ) ;

		while( times != NIL )
		{
			int time = MTOI( MMfetch(m, times, 0) ) ;
			if( time == AS_SND_END_REFLEX ) pWSound->pHSound->pHSndNotify->AddEndEvt() ;
			else
			{
				int pos = MsToChar( pWSound->pHSound->m_pwfx, time ) ;
				if( pos>=0 && pos<=pWSound->pHSound->m_dwSize ) pWSound->pHSound->pHSndNotify->AddEvt( pos, false ) ;
				else MMechostr( 1, "Time Event out of AsSnd.\n" ) ;
			}
			times = MTOP( MMfetch(m, times, 1) ) ;
		}
	}

	pWSound->pHSound->pHSndNotify->SetNotify() ;
	pWSound->pHSound->pHSndNotify->Start() ;

	return OBJaddreflex(m,AsSnd,RFL_EVT_ASSND) ;
}



//////////////////////////////////////////////////////////////////////////////////////////////
///		getSoundEvent														
//////////////////////////////////////////////////////////////////////////////////////////////
int getSoundEvent(mmachine m,HWND h,unsigned msg,UINT id,LONG param,int *ret)
{
	int k ;

	if( !(k = OBJbeginreflex( m, AsSnd, id, RFL_EVT_ASSND ) ) ) k = OBJcallreflex(m,0) ;

	return k ;
}










/////////////////////////////////////////////////////// DEFINITIONS
#define NBSOUNDPKG 38

char* SOUNDname [ NBSOUNDPKG ] = 
{
	"AsSnd",						// AsSnd,

	"AS_SND_STATIC",				// AS_SND_STATIC,
	"AS_SND_STREAMING",				// AS_SND_STREAMING,								

	"AS_SND_BEGIN",					// AS_SND_BEGIN,
	"AS_SND_CURRENT",				// AS_SND_CURRENT,
	"AS_SND_END",					// AS_SND_END,
		
	"AS_SND_CTRL3D",				// AS_SND_CTRL3D,
	"AS_SND_CTRLFREQUENCY",			// AS_SND_CTRLFREQUENCY,
	"AS_SND_CTRLPAN",				// AS_SND_CTRLPAN,

	"AS_SND_LINEAR",				// AS_SND_LINEAR
	"AS_SND_CIRCULAR",				// AS_SND_CIRCULAR

	"AS_SND_END_REFLEX",			// AS_SND_END_REFLEX
	"AS_SND_LOOP",					// AS_SND_LOOP

	// Son 2D		
	"asSndCreate",					// asSndCreate,
	"asSndDestroy",					// asSndDestroy,
	"asSndInit",					// asSndInit ,
	"asSndFeed",					// asSndFeed ,
	"asSndLoad",					// asSndLoad,
	"asSndNext",					// asSndNext,
	"asSndCopy",					// asSndCopy 
	"asSndPlay",					// asSndPlay,
	"asSndStop",					// asSndStop,
	"asSndIsPlaying",				// asSndIsPlaying
	"asEnableAllSnd",				// asEnableAllSnd,
	"asDisableAllSnd",				// asDisableAllSndAllSnd,
	"asSndReset",					// asSndReset,
	"asSndGetSize",					// asSndGetSize,
	"asSndSetTime",					// asSndSetTime,
	"asSndGetTime",					// asSndGetTime
	"asSndSetVolume",				// asSndSetVolume,
	"asSndGetVolume",				// asSndGetVolume,
	"asSetVolume",					// asSetVolume ,
	"asGetVolume",					// asGetVolume ,
	"asSndSetPan",					// asSndSetPan ,
	"asSndGetPan",					// asSndGetPan
	"asSndSetFrequency",			// asSndSetFrequency
	"asSndGetFrequency",			// asSndGetFrequency
	"asSndSetCallbackTime",			// asSndSetCallbackTime
} ;

char * SOUNDtype [ NBSOUNDPKG ] = 
{
////// TYPES                          
	NULL,																	// AsSnd,
																					
	"I",																	// AS_SND_STATIC,
	"I",																	// AS_SND_STREAMING,
																					
	"I",																	// AS_SND_BEGIN,
	"I",																	// AS_SND_CURRENT,
	"I",																	// AS_SND_END,
																				
	"I",																	// AS_SND_CTRL3D,
	"I",																	// AS_SND_CTRLFREQUENCY,
	"I",																	// AS_SND_CTRLPAN,
																			
	"I",																	// AS_SND_LINEAR
	"I",																	// AS_SND_CIRCULAR
																			
	"I",																	// AS_SND_END_REFLEX
	"I",																	// AS_SND_LOOP
																			
	// Son 2D																
	"fun [Chn I] AsSnd",													// asSndCreate,
	"fun [AsSnd] I",														// asSndDestroy,																				
	"fun [AsSnd I I I I] AsSnd",											// asSndInit ,
	"fun [AsSnd S I] AsSnd",												// asSndFeed 																						
	"fun [AsSnd P I] AsSnd",												// asSndLoad,
	"fun [AsSnd fun [AsSnd u0] u1 u0 P] AsSnd",								// asSndNext
	"fun [Chn AsSnd] AsSnd",												// asSndCopy 																			
	"fun [AsSnd I] AsSnd",													// asSndPlay,
	"fun [AsSnd] AsSnd",													// asSndStop,
	"fun [AsSnd] I",														// asSndIsPlaying
	"fun [] I",																// asEnableAllSnd,
	"fun [] I",																// asDisableAllSnd,
	"fun [AsSnd] AsSnd",													// asSndReset,
	"fun [AsSnd] I",														// asSndGetSize,
	"fun [AsSnd I I] AsSnd",												// asSndSetTime,
	"fun [AsSnd] I",														// asSndGetTime
	"fun [AsSnd I] AsSnd",													// asSndSetVolume,
	"fun [AsSnd] I",														// asSndGetVolume
	"fun [I] I",															// asSetVolume ,
	"fun [] I",																// asGetVolume ,
	"fun [AsSnd I] AsSnd",													// asSndSetPan ,
	"fun [AsSnd] I",														// asSndGetPan,
	"fun [AsSnd I] AsSnd",													// asSndSetFrequency,
	"fun [AsSnd] I",														// asSndGetFrequency,
	"fun [AsSnd fun [AsSnd u0] u1 u0 [I r1]] AsSnd",						// asSndSetCallbackTime																		
} ;


int SOUNDnarg [ NBSOUNDPKG ] = 
{
	TYPTYPE,						// AsSnd,

	TYPVAR,							// AS_SND_STATIC,
	TYPVAR,							// AS_SND_STREAMING,
	
	TYPVAR,							// AS_SND_BEGIN,
	TYPVAR,							// AS_SND_CURRENT,
	TYPVAR,							// AS_SND_END,

	TYPVAR,							// AS_SND_CTRL3D,
	TYPVAR,							// AS_SND_CTRLFREQUENCY,
	TYPVAR,							// AS_SND_CTRLPAN,

	TYPVAR,							// AS_SND_LINEAR
	TYPVAR,							// AS_SND_CIRCULAR

	TYPVAR,							// AS_SND_END_REFLEX
	TYPVAR,							// AS_SND_LOOP

	// Son 2D
	2,								// asSndCreate,
	1,								// asSndDestroy,
	5,								// asSndInit 
	3,								// asSndFeed 
	3,								// asSndLoad,
	4,								// asSndNext,
	2,								// asSndCopy 
	2,								// asSndPlay,
	1,								// asSndStop,
	1,								// asSndIsPlaying
	0,								// asEnableAllSnd,
	0,								// asDisableAllSnd,
	1,								// asSndReset,
	1,								// asSndGetSize,
	3,								// asSndSetTime,
	1,								// asSndGetTime,
	2,								// asSndSetVolume,
	1,								// asSndGetVolume
	1,								// asSetVolume ,
	0,								// asGetVolume ,
	2,								// asSndSetPan ,
	1,								// asSndGetPan,
	2,								// asSndSetFrequency,
	1,								// asSndGetFrequency,
	4,								// asSndSetCallbackTime
} ;


int (*SOUNDfun[NBSOUNDPKG])(mmachine m)= 
{
	NULL,															// AsSnd,
																	
	(int (__cdecl *)(struct Mmachine *))(2*AS_SND_STATIC),			// AS_SND_STATIC,
	(int (__cdecl *)(struct Mmachine *))(2*AS_SND_STREAMING),		// AS_SND_STREAMING,
																	
	(int (__cdecl *)(struct Mmachine *))(2*SEEK_SET),				// AS_SND_BEGIN,
	(int (__cdecl *)(struct Mmachine *))(2*SEEK_CUR),				// AS_SND_CURRENT,
	(int (__cdecl *)(struct Mmachine *))(2*SEEK_END),				// AS_SND_END,
																	
	(int (__cdecl *)(struct Mmachine *))(2*DSBCAPS_3D),				// AS_SND_CTRL3D,
	(int (__cdecl *)(struct Mmachine *))(2*DSBCAPS_CTRLFREQUENCY),	// AS_SND_CTRLFREQUENCY,
	(int (__cdecl *)(struct Mmachine *))(2*DSBCAPS_CTRLPAN),		// AS_SND_CTRLPAN,

	(int (__cdecl *)(struct Mmachine *))(2*AS_SND_LINEAR),			// AS_SND_LINEAR
	(int (__cdecl *)(struct Mmachine *))(2*AS_SND_CIRCULAR),		// AS_SND_CIRCULAR

	(int (__cdecl *)(struct Mmachine *))(2*AS_SND_END_REFLEX),		// AS_SND_END_REFLEX
	(int (__cdecl *)(struct Mmachine *))(2*AS_SND_LOOP),			// AS_SND_LOOP
 
	// Son 2D													
	asSndCreate,													// asSndCreate,
	asSndDestroy,													// asSndDestroy,
	asSndInit,														// asSndInit 
	asSndFeed,														// asSndFeed 
	asSndLoad,														// asSndLoad,
	asSndNext,														// asSndNext,
	asSndCopy,														// asSndCopy 
	asSndPlay,														// asSndPlay,
	asSndStop,														// asSndStop,
	asSndIsPlaying,													// asSndIsPlaying,
	asEnableAllSnd,													// asEnableAllSnd,
	asDisableAllSnd,												// asDisableAllSnd,
	asSndReset,														// asSndReset,
	asSndGetSize,													// asSndGetSize,
	asSndSetTime,													// asSndSetTime,
	asSndGetTime,													// asSndGetTime,
	asSndSetVolume,													// asSndSetVolume,
	asSndGetVolume,													// asSndGetVolume,
	asSetVolume,													// asSetVolume ,
	asGetVolume,													// asGetVolume ,
	asSndSetPan,													// asSndSetPan ,
	asSndGetPan,													// asSndGetPan,
	asSndSetFrequency,												// asSndSetFrequency,
	asSndGetFrequency,												// asSndGetFrequency,
	asSndSetCallbackTime,											// asSndSetCallbackTime																	
} ;




int SCOLloadSound(mmachine m,cbmachine w)
{
	int res = 0 ;

	hwnd = (HWND)SCgetExtra("hscol") ;
	
	AsSnd =	OBJregister( NB_RFL_ASSND, 1, destroyAsSnd, "AsSnd") ;
	
	SND_TIME = OBJgetUserEvent() ;
	OBJdefEvent( SND_TIME, (int (__cdecl *)(struct Mmachine *,int,unsigned int,int,int,int *))getSoundEvent ) ;

	SND_NEXT = OBJgetUserEvent() ;
	OBJdefEvent( SND_NEXT, (int (__cdecl *)(struct Mmachine *,int,unsigned int,int,int,int *))getNextEvent ) ;

	res += SCOLload3dSound(m, w) ;	
	res += SCOLloadRecorder(m, w) ;	
	res += SCOLloadWave(m, w) ;	
	res += SCOLloadMP3(m, w) ;		
	res += SCOLloadSDSound(m, w) ;
	res += SCOLloadEasySound(m, w) ;
	
	res += PKhardpak( m, "Sound", NBSOUNDPKG, SOUNDname, SOUNDfun, SOUNDnarg, SOUNDtype ) ;

	return res ;
}



int SCOLfreeSound()
{
	SCOLfree3dSound() ;
	SCOLfreeRecorder() ;
	SCOLfreeWave() ;
	SCOLfreeMP3() ;
	SCOLfreeSDSound() ;
	SCOLfreeEasySound() ;
	SAFE_DELETE(pHSoundManager) ;
	MMechostr(1,"Release DirectSound.\n");

	return 0;
}













