/////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////
////																					 ////
////																					 ////
////							    - SCOLrecorder.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
/////////////////////////////////////////////////////////////////////////////////////////////
bool RecorderCreated = false ;


/////////////////////////////////////////////////////////////////////////////////////////////
// Global variables
/////////////////////////////////////////////////////////////////////////////////////////////
int AsRecorder ;
int REC_EVT ;


/* $MS : Ajout de la fonction de callBack pour le retour des device */
static int sNumDevices = 0;

static bool CALLBACK Pa_CountDevProc(LPGUID lpGUID,LPCTSTR lpszDesc,LPCTSTR lpszDrvName,LPVOID lpContext )
{
 	    sNumDevices++;
 	    return TRUE;
}

//////////////////////////////////////////////////////////////////////////////////////////////
///		asRecorderCreate														
//////////////////////////////////////////////////////////////////////////////////////////////
// fun [Chn] AsRecorder
int asRecorderCreate(mmachine m)
{
	MMechostr(1," fun [Chn] AsRecorder \n") ;

	DWORD pv ; 
	HRESULT hr ;
	// Init audio capture device
	sNumDevices = 0;
	if( FAILED( hr = DirectSoundCaptureEnumerate((LPDSENUMCALLBACK) Pa_CountDevProc,(VOID*)pv ) ) ) {MMpull(m) ; MMset(m,0,NIL) ; return 0 ;}
	/* $MS : Problem here : if sNumDevices is 1 says that there is no device capture active Why?...Contact Microsoft !*/
	if( sNumDevices == 0 || sNumDevices == 1) {MMechostr(1,"sNumDevices == 0 || sNumDevices == 1") ; MMpull(m) ; MMset(m,0,NIL) ; return 0 ;}

	MMechostr(1,"sNumDevices = %i \n",sNumDevices) ;
	if( !initDirectSound() ) { MMpull(m) ; MMset(m,0,NIL) ; return 0 ; }

	int flag = MTOI( MMpull(m) )  ;

	if( RecorderCreated ) { MMset(m,0,NIL) ; return 0 ; }

	HRecord* pHRecord = new HRecord() ;
	/* $MS : Here we had to test if microphone exist */
	
	
	RecorderCreated = true ;
	int	asRecorder = MMmalloc(m,1,TYPETAB) ;
	if ( asRecorder==NIL ) {SAFE_DELETE(pHRecord) ; MMset(m,0,NIL) ; return MERRMEM ; }

	
	/* $MS : Crash here on vista */
	MMstore(m, asRecorder, 0, (int)pHRecord) ;
	MMpush(m, PTOM(asRecorder)) ;
	MMechostr(1," End : fun [Chn] AsRecorder \n") ;
	return OBJcreate(m, AsRecorder, (int)pHRecord, -1, -1) ;
}



//////////////////////////////////////////////////////////////////////////////////////////////
///		asRecorderDestroy														
//////////////////////////////////////////////////////////////////////////////////////////////
// fun [AsRecorder] I
int asRecorderDestroy(mmachine m)
{
	int	asRecorder = MTOP(MMget(m,0)) ;
	if ( asRecorder==NIL ) { MMset(m,0,NIL) ; return 0 ; }

	OBJdelTM( m, AsRecorder, PTOM(asRecorder) ) ;	
	MMset(m,0,0);

	return 0 ;
}



// Delete the AsSnd ///////////////////////////////////////////////////////////////////////
int destroyAsRecorder(mmachine m,int handsys,int asRecorder)
{
	HRecord* pHRecord = (HRecord*) MMfetch(m, MTOP(asRecorder), 0) ;
	if( !pHRecord ) { MMset(m,0,NIL) ; return 0 ; }

	SAFE_DELETE( pHRecord ) ;
	RecorderCreated = false ;
	
	MMstore( m, MTOP(asRecorder), 0, NULL ) ;
	MMechostr(1,"AsRecorder destroyed\n");

	return 0;
}




//////////////////////////////////////////////////////////////////////////////////////////////
///		asRecorderInit													
//////////////////////////////////////////////////////////////////////////////////////////////
// fun [AsRecorder fun [AsRecorder u0 S] u1 u0 I I I I I I] AsRecorder
int asRecorderInit(mmachine m)
{
	int flag		 = MTOI( MMpull(m) )  ;
	int volume		 = MTOI( MMpull(m) )  ;
	int bitPerSample = MTOI( MMpull(m) )  ;
	int frequence	 = MTOI( MMpull(m) )  ;
	int nbChannels	 = MTOI( MMpull(m) )  ;
	int size		 = MTOI( MMpull(m) )  ;
	int reflex		 = MTOP( MMget(m,1) ) ;
	int	asRecorder		 = MTOP( MMget(m,2) ) ;

	if( asRecorder==NIL || reflex==NIL || frequence==NIL || bitPerSample==NIL || nbChannels==NIL || size==NIL ) 
		{ MMpull(m) ; MMpull(m) ; MMset(m,0,NIL) ; return 0 ; }

	HRecord* pHRecord = (HRecord*)MMfetch(m, asRecorder, 0) ;
	if( !pHRecord ) { MMpull(m) ; MMpull(m) ; MMset(m,0,NIL) ; return 0 ; }

	if( FAILED( pHRecord->Init( nbChannels, bitPerSample, frequence, volume==NIL ? 0 : volume ) ) ) 
	{ SAFE_DELETE( pHRecord ) ; MMpull(m) ; MMpull(m) ; MMset(m,0,NIL) ; return 0 ; }
	if( FAILED( pHRecord->Create( MsToChar( pHRecord->m_pwfx, size ), AsRecorder ) ) )
	{ 
		MMechostr(1, "Recorder device not available.\n" ) ;
		MMpull(m) ; MMpull(m) ; MMset(m,0,NIL) ; 
		return 0 ; 
	}

	return OBJaddreflex(m,AsRecorder,RFL_ASRECORDER) ;
}


//////////////////////////////////////////////////////////////////////////////////////////////
///		getRecEvent													
//////////////////////////////////////////////////////////////////////////////////////////////
int getRecEvent(mmachine m,HWND h,unsigned msg,UINT id,LONG param,int *ret)
{
	if( !RecorderCreated ) return 0 ;

	int k ;

	HRecord* pHRecord = (HRecord*)id ;

	int out = MMmalloc( m, STR_SIZE(pHRecord->m_NotifySize) , TYPEBUF ) ;
	MMstore( m, out, 0, pHRecord->m_NotifySize ) ;
	char *S = MMstartstr( m, out ) ;
	_memcpy( S, pHRecord->out, pHRecord->m_NotifySize ) ;
	S[ pHRecord->m_NotifySize ] = 0 ;

	if( !(k = OBJbeginreflex( m, AsRecorder, id, RFL_ASRECORDER ) ) )
	{
		MMpush( m, PTOM( out ) ) ;
		k = OBJcallreflex(m,1) ;
	}

	return k ;
}




//////////////////////////////////////////////////////////////////////////////////////////////
///		asRecorderStart													
//////////////////////////////////////////////////////////////////////////////////////////////
// fun [AsRecorder] AsRecorder
int asRecorderStart(mmachine m)
{
	int	asRecorder = MTOP( MMget(m,0) ) ;
	if( asRecorder==NIL ) { MMset(m,0,NIL) ; return 0 ; }

	HRecord* pHRecord = (HRecord*)MMfetch(m, asRecorder, 0) ;
	if( !pHRecord ) { MMset(m,0,NIL) ; return 0 ; }

	if( FAILED( pHRecord->Start() ) ) { MMset(m,0,NIL) ; return 0 ; }

	return 0 ;
}



//////////////////////////////////////////////////////////////////////////////////////////////
///		asRecorderStop													
//////////////////////////////////////////////////////////////////////////////////////////////
// fun [AsRecorder] AsRecorder
int asRecorderStop(mmachine m)
{
	int	asRecorder = MTOP( MMget(m,0) ) ;
	if( asRecorder==NIL ) { MMset(m,0,NIL) ; return 0 ; }

	HRecord* pHRecord = (HRecord*)MMfetch(m, asRecorder, 0) ;
	if( !pHRecord ) { MMset(m,0,NIL) ; return 0 ; }

	if( FAILED( pHRecord->Stop() ) ) { MMset(m,0,NIL) ; return 0 ; }

	return 0 ;
}







/////////////////////////////////////////////////////// DEFINITIONS
#define NBRECORDERPKG 6

char* RECORDERName [ NBRECORDERPKG ] = 
{
	"AsRecorder",					// AsRecorder,

	// Enregistrement
	"asRecorderCreate",				// asRecorderCreate,
	"asRecorderDestroy",			// asRecorderDestroy,
	"asRecorderInit",				// asRecorderInit,
	"asRecorderStart",				// asRecorderStart,
	"asRecorderStop",				// asRecorderStop,
} ;

char* RECORDERtype [ NBRECORDERPKG ] = 
{           
	NULL,																	// AsRecorder,
																					
	// Enregistrement														
	"fun [Chn I] AsRecorder",												// asRecorderCreate,
	"fun [AsRecorder] I",													// asRecorderDestroy,
	"fun [AsRecorder fun [AsRecorder u0 S] u1 u0 I I I I I I] AsRecorder",	// asRecorderInit,
	"fun [AsRecorder] AsRecorder",											// asRecorderStart,,
	"fun [AsRecorder] AsRecorder",											// asRecorderStop,

} ;


int RECORDERnarg [ NBRECORDERPKG ] = 
{
	TYPTYPE,						// AsRecorder,

	//Enregistrement
	2,								// asRecorderCreate,
	1,								// asRecorderDestroy,
	9,								// asRecorderInit,
	1,								// asRecorderStart,
	1,								// asRecorderStop,

} ;


int (*RECORDERfun[NBRECORDERPKG])(mmachine m)= 
{
	NULL,															// AsRecorder,																

	// Enregistrement
	asRecorderCreate,												// asRecorderCreate,
	asRecorderDestroy,												// asRecorderDestroy,
	asRecorderInit,													// asRecorderInit,
	asRecorderStart,												// asRecorderStart,
	asRecorderStop,													// asRecorderStop,

} ;



int SCOLloadRecorder(mmachine m,cbmachine w)
{
	AsRecorder = OBJregister( NB_RFL_ASRECORDER, 1, destroyAsRecorder, "AsRecorder" ) ;
	
	REC_EVT = OBJgetUserEvent() ;
	OBJdefEvent( REC_EVT,  (int (__cdecl *)(struct Mmachine *,int,unsigned int,int,int,int *))getRecEvent ) ;

	return PKhardpak( m, "Recorder", NBRECORDERPKG, RECORDERName, RECORDERfun, RECORDERnarg, RECORDERtype ) ;
}



int SCOLfreeRecorder()
{
	return 0;
}