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



#include "..\Basic\ZooScene.h"
#include "..\SCOL\SCOLsound.h"

extern HSoundManager* pHSoundManager ;

int SoundPlay ;
const int SPlayID = 1 ;
int SoundRec ;
const int SRecID = 1 ;

extern mmachine	mm ;
int EASYREC_EVT ;
int EASYPLAY_EVT ;

HRecord* gHRecord = NULL ;
HAudio*	 gHAudio  = NULL ;


////////////////////////////////////////////////////////////////////////// Old Easy Sound Playing

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

	int nbchannel  = MTOI( MMpull(m) ) ;
	int resolution = MTOI( MMpull(m) ) ;
	int size	   = MTOI( MMpull(m) ) ;
	int frequency  = MTOI( MMpull(m) ) ;
	if( frequency==NIL || resolution==NIL || nbchannel==NIL || size==NIL ) { MMset(m,0,NIL) ; return 0 ; }

	if( gHAudio ) OBJdelTH( m, SoundPlay, SPlayID );

	gHAudio = new HAudio( true ) ;
	if( FAILED( gHAudio->SetData( nbchannel, resolution, frequency, size ) ) ) { SAFE_DELETE( gHAudio ) ; MMset(m,0,NIL) ; return 0 ; }	
	
	if( FAILED( gHAudio->CreateStreaming( DSBCAPS_CTRL ) ) ) { SAFE_DELETE( gHAudio ) ; MMset(m,0,NIL) ; return 0 ; }

	MMpush(m, ITOM(1));
	return OBJcreate(m, SoundPlay, SPlayID, -1, -1) ;
}


int destroySoundPlay(mmachine m,int handsys,int objPlay)
{
	SAFE_DELETE( gHAudio ) ;
	
	MMstore( m, MTOP(objPlay), 0, NULL ) ;
	return 0;
}


// fun [] I	
int _sndPlayStop( mmachine m )
{
	if( !gHAudio ) { MMpush( m, ITOM(1) ) ; return 0 ; }

	gHAudio->Stop() ;

	if( !OBJbeginreflex(mm, SoundPlay, SPlayID, RFL_PLAYCLOSE) ) OBJcallreflex(mm,0) ;
	OBJdelTH( m, SoundPlay, SPlayID );

	MMpush( m, ITOM(1) ) ;
	return 0 ;
}




// fun [SoundPlay fun [SoundPlay u0] u1 u0] SoundPlay
int _sndSetRflxPlayClose( mmachine m )
{
	int reflex	 = MTOP( MMget(m,1) ) ;
	int	soundPlay = MTOP( MMget(m,2) ) ;
	if( reflex==NIL || soundPlay==NIL )  { MMpull(m) ; MMpull(m) ; MMset(m,0,NIL) ; return 0 ; }

	return OBJaddreflex( m, SoundPlay, RFL_PLAYCLOSE ) ;
}


// fun [SoundPlay fun [SoundPlay u0] u1 u0] SoundPlay
int _sndSetRflxPlayOpen( mmachine m )
{
	int reflex	 = MTOP( MMget(m,1) ) ;
	int	soundPlay = MTOP( MMget(m,2) ) ;

	if( reflex==NIL || soundPlay==NIL )  { MMpull(m) ; MMpull(m) ; MMset(m,0,NIL) ; return 0 ; }

	if( OBJaddreflex( m, SoundPlay, RFL_PLAYOPEN ) ) { MMpull(m) ; MMpull(m) ; MMset(m,0,NIL) ; return 0 ; }

	if( !OBJbeginreflex(mm, SoundPlay, SPlayID, RFL_PLAYOPEN) ) OBJcallreflex(mm,0) ;

	return 0 ;
}




// fun [SoundPlay fun [SoundPlay u0 I] S u0] SoundPlay
int  _sndSetRflxPlayBuf( mmachine m )
{
	int reflex	 = MTOP( MMget(m,1) ) ;
	int	soundPlay = MTOP( MMget(m,2) ) ;
	if( reflex==NIL || soundPlay==NIL )  { MMpull(m) ; MMpull(m) ; MMset(m,0,NIL) ; return 0 ; }

	OBJaddreflex( m, SoundPlay, RFL_PLAYBUF ) ;

	gHAudio->Play( DSBPLAY_LOOPING ) ;

	return 0 ;
}



int getEasyPlayEvent( mmachine m, HWND h, unsigned msg, UINT id, LONG param, int *ret )
{
	if( !gHAudio ) return 0 ;

	char* pBuffer = (char*)id ;
	int sizeToRead = (int)param ;

	if( !OBJbeginreflex(mm, SoundPlay, SPlayID, RFL_PLAYBUF) )
	{
		MMpush( mm, ITOM(1) ) ;
		OBJcallreflex(mm,1) ;
		if( !gHAudio ) return 0 ;
		int s = MTOP( MMget( mm, -2 ) ) ;
		if( s==NIL ) _FillMemory( pBuffer, sizeToRead, (gHAudio->m_pwfx->wBitsPerSample == 8 ? 128 : 0) ) ;
		else
		{
			int size = MMsizestr(mm,s) ;
			char* in = MMstartstr(mm,s) ;
			if( size >= sizeToRead ) _memcpy( pBuffer, in, sizeToRead ) ;
			else
			{
				_memcpy( pBuffer, in, size ) ;
				_FillMemory( pBuffer+size, sizeToRead-size, (gHAudio->m_pwfx->wBitsPerSample == 8 ? 128 : 0) ) ;
			}
		}
	}
	else _FillMemory( pBuffer, sizeToRead, (gHAudio->m_pwfx->wBitsPerSample == 8 ? 128 : 0) ) ;

	return 0 ;
}




// fun [] I
int _sndSetPending( mmachine m)
{
	if( !gHAudio ) { MMpush( m, ITOM(1) ) ; return 0 ; }

	if( gHAudio->IsSoundPlaying() ) gHAudio->Stop() ;
	if( !OBJbeginreflex(mm, SoundPlay, SPlayID, RFL_PLAYCLOSE) ) OBJcallreflex(mm,0) ;

	OBJdelTH( m, SoundPlay, SPlayID );

	MMpush( m, ITOM(1) ) ;
	return 0 ;
}


// fun [] I
int _sndUnsetPending( mmachine m )
{
	if( !gHAudio ) { MMpush( m, ITOM(1) ) ; return 0 ; }

	if( !gHAudio->IsSoundPlaying() ) gHAudio->Play( DSBPLAY_LOOPING ) ;

	MMpush( m, ITOM(1) ) ;
	return 0 ;
}



////////////////////////////////////////////////////////////////////////// Old Easy Sound Recording

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

	int nbchannel  = MTOI( MMpull(m) ) ;
	int resolution = MTOI( MMpull(m) ) ;
	int size	   = MTOI( MMpull(m) ) ;
	int frequency  = MTOI( MMpull(m) ) ;
	if( frequency==NIL || resolution==NIL || nbchannel==NIL || size==NIL ) { MMset(m,0,NIL) ; return 0 ; }

	if( gHRecord ) OBJdelTH( m, SoundRec, SRecID );

	gHRecord = new HRecord() ;

	if( FAILED( gHRecord->Init( nbchannel, resolution, frequency, 0 ) ) ) { SAFE_DELETE( gHRecord ) ; MMset(m,0,NIL) ; return 0 ; }
	if( FAILED( gHRecord->Create( nbchannel*(resolution/8)*size, SoundRec)  ) ) { SAFE_DELETE( gHRecord ) ; MMset(m,0,NIL) ; return 0 ; }

	MMpush(m, ITOM(1)) ;

	return OBJcreate( m, SoundRec, SRecID, -1, -1 ) ;
}





int destroySoundRec(mmachine m,int handsys,int asRecorder)
{
	SAFE_DELETE( gHRecord ) ;
	
	MMstore( m, MTOP(asRecorder), 0, NULL ) ;
	return 0;
}


// fun [] I
int _sndRecStop( mmachine m )
{
	if( !gHRecord ) { MMpush( m, ITOM(1) ) ; return 0 ; }

	gHRecord->Stop() ;

	if( !OBJbeginreflex(mm, SoundRec, SRecID, RFL_RECCLOSE) )  OBJcallreflex(mm,0) ;
	OBJdelTH( m, SoundRec, SRecID );

	MMpush( m, ITOM(1) ) ;
	return 0 ;
}



// fun [SoundRec fun [SoundRec u0 S I] u1 u0] SoundRec
int _sndSetRflxRecBuf( mmachine m)
{
	int reflex	 = MTOP( MMget(m,1) ) ;
	int	soundRec = MTOP( MMget(m,2) ) ;
	if( reflex==NIL || soundRec==NIL )  { MMpull(m) ; MMpull(m) ; MMset(m,0,NIL) ; return 0 ; }
	
	OBJaddreflex( m, SoundRec, RFL_RECBUF );
	if( FAILED( gHRecord->Start() ) ) { MMpull(m) ; MMpull(m) ; MMset(m,0,NIL) ; return 0 ; }

	return 0 ;
}



int getEasyRecEvent(mmachine m,HWND h,unsigned msg,UINT id,LONG param,int *ret)
{
	if( !gHRecord ) return 0 ;

	int out = MMmalloc( m, STR_SIZE(gHRecord->m_NotifySize) , TYPEBUF ) ;
	if ( out == NIL ) { return MERRMEM ; }
	MMstore( m, out, 0, gHRecord->m_NotifySize ) ;
	char *S = MMstartstr( m, out ) ;
	_memcpy( S, gHRecord->out, gHRecord->m_NotifySize ) ;
	S[ gHRecord->m_NotifySize ] = 0 ;

	if( !OBJbeginreflex( m, SoundRec, SRecID, RFL_RECBUF ) )
	{
		MMpush( m, PTOM( out ) ) ;
		MMpush( mm, ITOM(1) ) ;
		OBJcallreflex(m,2) ;
	}

	return 0 ;
}



// fun [SoundRec fun [SoundRec u0] u1 u0] SoundRec
int _sndSetRflxRecClose( mmachine m)
{
	int reflex	 = MTOP( MMget(m,1) ) ;
	int	soundRec = MTOP( MMget(m,2) ) ;
	if( reflex==NIL || soundRec==NIL )  { MMpull(m) ; MMpull(m) ; MMset(m,0,NIL) ; return 0 ; }

	return OBJaddreflex( m, SoundRec, RFL_RECCLOSE ) ;
}


//fun [SoundRec fun [SoundRec u0] u1 u0] SoundRec
int _sndSetRflxRecOpen( mmachine m )
{ 
	int reflex	 = MTOP( MMget(m,1) ) ;
	int	soundRec = MTOP( MMget(m,2) ) ;
	if( reflex==NIL || soundRec==NIL )  { MMpull(m) ; MMpull(m) ; MMset(m,0,NIL) ; return 0 ; }

	if( OBJaddreflex( m, SoundRec, RFL_RECOPEN ) ) { MMpull(m) ; MMpull(m) ; MMset(m,0,NIL) ; return 0 ; }

	// appel du reflexe utilisateur s'il existe
	if( gHRecord ) if( !OBJbeginreflex(mm, SoundRec, SRecID, RFL_RECOPEN) ) OBJcallreflex(mm,0) ;

	return 0 ;
}




	





/////////////////////////////////////////////////////// DEFINITIONS
#define NBEASYSOUNDPKG 14

char* EASYSOUNDname [ NBEASYSOUNDPKG ] = 
{
	"SoundPlay",					// SoundPlay
	"SoundRec",						// SoundRec
	
	"_sndPlayStart",				// _sndPlayStart				 
	"_sndPlayStop",					// _sndPlayStop				 
	"_sndRecStart",					// _sndRecStart
	"_sndRecStop",					// _sndRecStop				
	"_sndSetPending",				// _sndSetPending			
	"_sndSetRflxPlayBuf",			// _sndSetRflxPlayBuf			
	"_sndSetRflxPlayClose",			// _sndSetRflxPlayClose		
	"_sndSetRflxPlayOpen",			// _sndSetRflxPlayOpen
	"_sndSetRflxRecBuf",			// _sndSetRflxRecBuf	
	"_sndSetRflxRecClose",			// _sndSetRflxRecClose	 
	"_sndSetRflxRecOpen",			// _sndSetRflxRecOpen	
	"_sndUnsetPending",				// _sndUnsetPending		
} ;



char* EASYSOUNDtype [ NBEASYSOUNDPKG ] = 
{
	NULL,													// SoundPlay
	NULL,													// SoundRec

	"fun [Chn I I I I] SoundPlay",							// _sndPlayStart				 
	"fun [] I",												// _sndPlayStop				 
	"fun [Chn I I I I] SoundRec",							// _sndRecStart
	"fun [] I",												// _sndRecStop				
	"fun [] I",												// _sndSetPending			
	"fun [SoundPlay fun [SoundPlay u0 I] S u0] SoundPlay",	// _sndSetRflxPlayBuf			
	"fun [SoundPlay fun [SoundPlay u0] u1 u0] SoundPlay",	// _sndSetRflxPlayClose		
	"fun [SoundPlay fun [SoundPlay u0] u1 u0] SoundPlay",	// _sndSetRflxPlayOpen
	"fun [SoundRec fun [SoundRec u0 S I] u1 u0] SoundRec",	// _sndSetRflxRecBuf	
	"fun [SoundRec fun [SoundRec u0] u1 u0] SoundRec",		// _sndSetRflxRecClose	 
	"fun [SoundRec fun [SoundRec u0] u1 u0] SoundRec",		// _sndSetRflxRecOpen	
	"fun [] I",												// _sndUnsetPending	
} ;



int EASYSOUNDnarg [ NBEASYSOUNDPKG ] = 
{

	TYPTYPE,	// SoundPlay
	TYPTYPE,	// SoundRec
	
	5,			// _sndPlayStart				 
	0,			// _sndPlayStop				 
	5,			// _sndRecStart
	0,			// _sndRecStop				
	0,			// _sndSetPending			
	3,			// _sndSetRflxPlayBuf			
	3,			// _sndSetRflxPlayClose		
	3,			// _sndSetRflxPlayOpen
	3,			// _sndSetRflxRecBuf	
	3,			// _sndSetRflxRecClose	 
	3,			// _sndSetRflxRecOpen	
	0,			// _sndUnsetPending	
} ;


int (*EASYSOUNDfun[NBEASYSOUNDPKG])(mmachine m)= 
{
	NULL,					// SoundPlay
	NULL,					// SoundRec
	
	_sndPlayStart,			// _sndPlayStart				 
	_sndPlayStop,			// _sndPlayStop				 
	_sndRecStart,			// _sndRecStart
	_sndRecStop,			// _sndRecStop				
	_sndSetPending,			// _sndSetPending			
	_sndSetRflxPlayBuf,		// _sndSetRflxPlayBuf			
	_sndSetRflxPlayClose,	// _sndSetRflxPlayClose		
	_sndSetRflxPlayOpen,	// _sndSetRflxPlayOpen
	_sndSetRflxRecBuf,		// _sndSetRflxRecBuf	
	_sndSetRflxRecClose,	// _sndSetRflxRecClose	 
	_sndSetRflxRecOpen,		// _sndSetRflxRecOpen	
	_sndUnsetPending,		// _sndUnsetPending		
} ;


int SCOLloadEasySound(mmachine m,cbmachine w)
{	
	SoundPlay = OBJregister( NB_RFL_SOUNDPLAY, 1, destroySoundPlay, "SoundPlay" ); 
	SoundRec  = OBJregister( NB_RFL_SOUNDREC,  1, destroySoundRec,  "SoundRec" );

	EASYREC_EVT  = OBJgetUserEvent() ;
	EASYPLAY_EVT  = OBJgetUserEvent() ;
	OBJdefEvent( EASYREC_EVT,   (int (__cdecl *)(struct Mmachine *,int,unsigned int,int,int,int *))getEasyRecEvent ) ;
	OBJdefEvent( EASYPLAY_EVT,  (int (__cdecl *)(struct Mmachine *,int,unsigned int,int,int,int *))getEasyPlayEvent ) ;

	return PKhardpak( m, "EasySound deprecated", NBEASYSOUNDPKG, EASYSOUNDname, EASYSOUNDfun, EASYSOUNDnarg, EASYSOUNDtype ) ;
}


int SCOLfreeEasySound()
{
	return 0;
}