#include "CEchoGals.h"
#include "CMtcSync.h"
MTC frames per second lookup
****************************************************************************/
static DWORD dwMtcFpsLookup[] =
{
24,
25,
30,
30
};
Construction, destruction and reset
****************************************************************************/
CMtcSync::CMtcSync( CEchoGals *pEG )
{
m_pEG = pEG;
pEG->GetAudioSampleRate( &m_dwBaseSampleRate );
m_dwFill = 0;
m_dwDrain = 0;
Reset();
}
CMtcSync::~CMtcSync()
{
}
void CMtcSync::Reset()
{
ECHO_DEBUGPRINTF(("\t **** CMtcSync::Reset\n"));
m_dwFramesPerSec = 30;
m_iSamplesPerDframe = (m_dwBaseSampleRate / m_dwFramesPerSec) * 2;
m_dwLastDframeTimestamp = 0;
m_dwLastDframe = 0;
m_dwCurrentDframe = 0;
m_iNumDframesSynced = 0;
m_iNumSamplesSynced = 0;
m_dwNextQfType = 0;
m_dwTemp = 0;
}
Methods for storing MTC data - called at interrupt time
****************************************************************************/
void CMtcSync::StoreTimestampHigh(DWORD dwData)
{
m_Buffer[ m_dwFill ].dwTimestamp = dwData << 16;
}
void CMtcSync::StoreTimestampLow(DWORD dwData)
{
m_Buffer[ m_dwFill ].dwTimestamp |= dwData;
}
void CMtcSync::StoreMtcData(DWORD dwData)
{
m_Buffer[ m_dwFill ].dwData = dwData;
m_dwFill++;
m_dwFill &= ECHO_MTC_QUEUE_SZ - 1;
}
Sync to MIDI time code
****************************************************************************/
void CMtcSync::Sync()
{
BOOL fRateAdjusted;
fRateAdjusted = FALSE;
while ( (FALSE == fRateAdjusted) && (m_dwFill != m_dwDrain) )
{
DWORD dwData,dwTimestamp,dwQfType,dwQfData;
dwData = m_Buffer[ m_dwDrain ].dwData;
dwTimestamp = m_Buffer[ m_dwDrain ].dwTimestamp;
ECHO_DEBUGPRINTF(("\n\tCMtcSync::Sync - data 0x%lx, timestamp 0x%lx\n",
dwData,dwTimestamp));
dwQfType = (dwData >> 4) & 0xf;
dwQfData = dwData & 0xf;
m_dwDrain++;
m_dwDrain &= ECHO_MTC_QUEUE_SZ - 1;
if (dwQfType != m_dwNextQfType)
{
ECHO_DEBUGPRINTF(("\tCMtcSync::Sync - quarter-frames out of sequence\n"));
Reset();
continue;
}
switch (dwQfType)
{
case MTC_QF_FRAME_LSN :
m_dwTemp = dwQfData;
ECHO_DEBUGPRINTF(("\t\tQF frame LSN %ld m_dwTemp %ld m_dwCurrentDframe %ld\n",
dwQfData,m_dwTemp,m_dwCurrentDframe));
break;
case MTC_QF_FRAME_MSN :
m_dwTemp |= dwQfData << 4;
m_dwTemp &= 0x1f;
m_dwCurrentDframe = m_dwTemp;
ECHO_DEBUGPRINTF(("\t\tQF frame MSN %ld m_dwTemp %ld m_dwCurrentDframe %ld\n",
dwQfData,m_dwTemp,m_dwCurrentDframe));
break;
case MTC_QF_SECOND_LSN :
m_dwTemp = dwQfData;
ECHO_DEBUGPRINTF(("\t\tQF second LSN %ld m_dwTemp %ld m_dwCurrentDframe %ld\n",
dwQfData,m_dwTemp,m_dwCurrentDframe));
break;
case MTC_QF_SECOND_MSN :
m_dwTemp |= dwQfData << 4;
m_dwTemp &= 0x3f;
m_dwCurrentDframe += m_dwTemp * m_dwFramesPerSec;
ECHO_DEBUGPRINTF(("\t\tQF second MSN %ld m_dwTemp %ld m_dwCurrentDframe %ld\n",
dwQfData,m_dwTemp,m_dwCurrentDframe));
break;
case MTC_QF_MINUTE_LSN :
m_dwTemp = dwQfData;
ECHO_DEBUGPRINTF(("\t\tQF minute LSN %ld m_dwTemp %ld m_dwCurrentDframe %ld\n",
dwQfData,m_dwTemp,m_dwCurrentDframe));
break;
case MTC_QF_MINUTE_MSN :
m_dwTemp |= dwQfData << 4;
m_dwTemp &= 0x3f;
m_dwCurrentDframe += m_dwTemp * m_dwFramesPerSec * 60;
ECHO_DEBUGPRINTF(("\t\tQF minute MSN %ld m_dwTemp %ld m_dwCurrentDframe %ld\n",
dwQfData,m_dwTemp,m_dwCurrentDframe));
break;
case MTC_QF_HOUR_LSN :
m_dwTemp = dwQfData;
ECHO_DEBUGPRINTF(("\t\tQF hour LSN %ld m_dwTemp %ld m_dwCurrentDframe %ld\n",
dwQfData,m_dwTemp,m_dwCurrentDframe));
break;
case MTC_QF_HOUR_MSN :
m_dwTemp |= dwQfData << 4;
m_dwTemp &= 0x1f;
m_dwCurrentDframe += m_dwTemp * m_dwFramesPerSec * 3600;
ECHO_DEBUGPRINTF(("\t\tQF hour MSN %ld m_dwCurrentDframe %ld m_dwCurrentDframe %ld\n",
dwQfData,m_dwTemp,m_dwCurrentDframe));
DWORD dwFpsIndex,dwFps;
dwFpsIndex = (dwQfData >> 1) & 3;
dwFps = dwMtcFpsLookup[ dwFpsIndex ];
m_dwFramesPerSec = dwFps;
m_iSamplesPerDframe = (m_dwBaseSampleRate / dwFps) * 2;
break;
default :
Reset();
break;
}
if (MTC_QF_HOUR_MSN != dwQfType)
{
m_dwNextQfType = dwQfType + 1;
continue;
}
INT32 iFrameDelta;
ECHO_DEBUGPRINTF(("\n\n\t\t\tCMtcSync::Sync - doubleframe %ld\n",m_dwCurrentDframe));
iFrameDelta = (INT32) (m_dwCurrentDframe - m_dwLastDframe);
if ((iFrameDelta > 3) || (iFrameDelta < 0))
{
DWORD dwDframe;
ECHO_DEBUGPRINTF(("\t****** CMtcSync::Sync - double-frames out of sequence\n"));
dwDframe = m_dwCurrentDframe;
Reset();
m_dwLastDframe = dwDframe;
continue;
}
if (m_dwLastDframeTimestamp > dwTimestamp)
{
ECHO_DEBUGPRINTF(("\tCMtcSync::Sync - timestamps have wrapped around"));
Reset();
continue;
}
INT32 iTimestampDelta,iActualTotalSamples,iExpectedTotalSamples,iVariance;
iTimestampDelta = (INT32) (dwTimestamp - m_dwLastDframeTimestamp);
if (iTimestampDelta > ((INT32) (m_iSamplesPerDframe * 2)) )
iTimestampDelta = m_iSamplesPerDframe * 2;
else if (iTimestampDelta < ((INT32) (m_iSamplesPerDframe / 2)) )
iTimestampDelta = m_iSamplesPerDframe / 2;
iExpectedTotalSamples = (m_iNumDframesSynced + 1) * m_iSamplesPerDframe;
ECHO_DEBUGPRINTF(("\t\t\tdwTimestamp 0x%lx m_dwLastDframeTimestamp 0x%lx\n",dwTimestamp,m_dwLastDframeTimestamp));
ECHO_DEBUGPRINTF(("\t\t\tBase rate %ld m_iSamplesPerDframe %ld iTimestampDelta %ld\n",
m_dwBaseSampleRate,m_iSamplesPerDframe,iTimestampDelta));
iActualTotalSamples = iTimestampDelta + m_iNumSamplesSynced;
iVariance = iActualTotalSamples - iExpectedTotalSamples;
if (iVariance < 0) iVariance = -iVariance;
ECHO_DEBUGPRINTF(("\t\t\tiExpectedTotalSamples %ld iVariance %ld\n",
iExpectedTotalSamples,iVariance));
if (iVariance > MTC_TOLERANCE)
{
DWORD dwSampleRate;
INT32 iRatio;
iRatio = (iExpectedTotalSamples << 12) / iActualTotalSamples;
if ( (iRatio < DAMPING_RATIO_LIMIT_LOW) ||
(iRatio > DAMPING_RATIO_LIMIT_HIGH))
{
iRatio = (iRatio * (0x1000 - MTC_DAMPING)) >> 12;
iRatio += MTC_DAMPING;
}
ECHO_DEBUGPRINTF(("\t\t\tiRatio 0x%08lx\n",iRatio));
ECHO_DEBUGPRINTF(("\t\t\tiExpectedTotalSamples %ld iActualTotalSamples %ld\n",
iExpectedTotalSamples,iActualTotalSamples));
ECHO_DEBUGPRINTF(("\t\t\tiTimestampDelta %ld m_iSamplesPerDframe %ld\n",
iTimestampDelta,m_iSamplesPerDframe));
dwSampleRate = m_pEG->GetDspCommObject()->GetSampleRate();
dwSampleRate = (iRatio * dwSampleRate ) >> 12;
if (m_dwBaseSampleRate > 50000)
{
if (dwSampleRate > 100000)
dwSampleRate = 100000;
else if (dwSampleRate < 50000)
dwSampleRate = 50000;
}
else
{
if (dwSampleRate > 50000)
dwSampleRate = 50000;
else if (dwSampleRate < MIN_MTC_1X_RATE)
dwSampleRate = MIN_MTC_1X_RATE;
}
ECHO_DEBUGPRINTF(("\t\t\tNew sample rate %ld\n",dwSampleRate));
m_pEG->GetDspCommObject()->SetSampleRate ( dwSampleRate );
m_iNumDframesSynced = 0;
m_iNumSamplesSynced = 0;
}
else
{
ECHO_DEBUGPRINTF(("\t\t\tClose enough - iVariance %ld\n",iVariance));
m_iNumDframesSynced++;
m_iNumSamplesSynced += iTimestampDelta;
if (m_iNumDframesSynced > MAX_DFRAME_SYNC_COUNT)
m_iNumDframesSynced >>= 1;
ECHO_DEBUGPRINTF(("\t\t\tm_iNumDframesSynced %ld m_iNumSamplesSynced %ld\n\n",
m_iNumDframesSynced,m_iNumSamplesSynced));
}
m_dwLastDframe = m_dwCurrentDframe;
m_dwLastDframeTimestamp = dwTimestamp;
m_dwNextQfType = 0;
}
}
New & delete
****************************************************************************/
PVOID CMtcSync::operator new( size_t Size )
{
PVOID pMemory;
ECHOSTATUS Status;
Status = OsAllocateNonPaged(Size,&pMemory);
if ( (ECHOSTATUS_OK != Status) || (NULL == pMemory ))
{
ECHO_DEBUGPRINTF(("CMtcSync::operator new - memory allocation failed\n"));
pMemory = NULL;
}
else
{
memset( pMemory, 0, Size );
}
return pMemory;
}
VOID CMtcSync::operator delete( PVOID pVoid )
{
if ( ECHOSTATUS_OK != OsFreeNonPaged( pVoid ) )
{
ECHO_DEBUGPRINTF( ("CMtcSync::operator delete memory free failed\n") );
}
}