void CTCMarshalByValue::FinalRelease()
 {
   _TRACE0("CTCMarshalByValue::FinalRelease()\n");
 }
/* #FN#
   The main timing function that an emulated Atari is based on */
void
/* #AS#
   Nothing */
Timer_WaitForVBI( void )
{
	long  lSpareTicks;
	ULONG ulTimerLastVal = s_ulAtariHWNextTime;
	LARGE_INTEGER lnTicks;
	int nDelay = 50;

#ifdef _DEBUG
	DWORD   dwPlayCursor   = 0;
	DWORD   dwSaveCursor   = 0;
//	IDirectSoundBuffer_GetCurrentPosition( s_lpDSBuffer, &dwPlayCursor, &dwSaveCursor );
//	if (abs(dwSaveCursor-dwPlayCursor)<1000)_TRACE2("Sound cursor: %d, %d\n", dwPlayCursor, dwSaveCursor);
#endif _DEBUG

	QueryPerformanceCounter( &lnTicks );
	if( s_bTimerRollover )
	{
		while( lnTicks.LowPart > s_ulAtariHWNextTime && (s_ulAtariHWNextTime - lnTicks.LowPart < s_ulDeltaT) )
		{
			QueryPerformanceCounter( &lnTicks );
			lSpareTicks = ULONG_MAX - lnTicks.LowPart + 1;
			_ASSERT(lSpareTicks <= (long)s_ulDeltaT);
			if( lSpareTicks > s_nSleepThreshold )
			{
				SleepEx( SLEEP_TIME_IN_MS, TRUE );
				QueryPerformanceCounter( &lnTicks );
			}
		}
		s_bTimerRollover = FALSE;
	}
	lSpareTicks = (long)(s_ulAtariHWNextTime - lnTicks.LowPart);

	if( lSpareTicks > 0L )
	{
		if( !_IsFlagSet( g_Misc.ulState, MS_FULL_SPEED ) )
		{
			while( lSpareTicks > s_nSleepThreshold )
			{
				SleepEx( SLEEP_TIME_IN_MS, TRUE );
				QueryPerformanceCounter( &lnTicks );
				lSpareTicks = (long)(s_ulAtariHWNextTime - lnTicks.LowPart);
#ifdef _DEBUG
//				IDirectSoundBuffer_GetCurrentPosition( s_lpDSBuffer, &dwPlayCursor, &dwSaveCursor );
//				_TRACE3("Sound cursor: %d, %d, %d\n", dwPlayCursor, dwSaveCursor, Atari800_nframes);
#endif
			}
			while( s_ulAtariHWNextTime > lnTicks.LowPart && lnTicks.LowPart > ulTimerLastVal )
				QueryPerformanceCounter( &lnTicks );

			s_ulAtariHWNextTime += s_ulDeltaT;
		}
		else
		{
			if( lSpareTicks > (long)s_ulDeltaT )
				s_ulAtariHWNextTime = lnTicks.LowPart + s_ulDeltaT;
			else
				s_ulAtariHWNextTime += s_ulDeltaT;
		}
	}
	else
	{
		if( -lSpareTicks > (long)s_ulDeltaT )
			s_ulAtariHWNextTime = lnTicks.LowPart + 1;
		else
			s_ulAtariHWNextTime += s_ulDeltaT;
	}
	if( ulTimerLastVal > s_ulAtariHWNextTime )
		s_bTimerRollover = TRUE;

	if( _IsFlagSet( g_Sound.ulState, SS_DS_SOUND ) )
	{
		if( s_nFrameCnt > s_nFramesPerFrag )
		{
		
			/* SoundIsPaused indicates full speed mode in this case; if
			   the emulated Atari is paused, this routine is not invoked */
			if( !s_bSoundIsPaused )
			{
	//			_TRACE2("PrimaryThread.SndPlay_DSSound: s_nSaveFragNo: %d, s_nPlayFragNo: %d\n", s_nSaveFragNo, s_nPlayFragNo);

				/* There is spinlock used to synchronize the threads. We should
				   avoid this solution but it's rather fast and we don't really
				   need the interlocked functions or critical sections here */
				while( s_nSaveFragNo != s_nPlayFragNo && --nDelay )
					Sleep( 1 );
	#ifdef _DEBUG
				if( 0 == nDelay ) _TRACE0("!PrimaryThread.SndPlay_DSSound: Delay = 0!\n");
	#endif _DEBUG
			}
			/* The PlayFragNo indicator is incremented by a secondary thread so we can
			   synchronize the thread with primary thread's writes to a stream buffer */

			if( ++s_nSaveFragNo == s_nNumberOfFrags )
				s_nSaveFragNo = 0;

			s_pSaveCursor = &s_pSoundBuffer[ s_nSaveFragNo * s_dwFragSize ];

			s_dwFragPos  = 0;
			s_nUpdateCnt = 1;
			s_nFrameCnt  = 1;
		}
	}

} /* #OF# Timer_WaitForVBI */
 HRESULT CTCMarshalByValue::FinalConstruct()
 {
   _TRACE0("CTCMarshalByValue::FinalConstruct()\n");
   return S_OK;
 }