fixes for the client audio standard deviation measurement, added code for asio interface for using power of two size blocks (not enabled right now)
This commit is contained in:
parent
c206f84308
commit
e42c3afb81
6 changed files with 77 additions and 82 deletions
|
@ -200,7 +200,7 @@ void CClient::Init()
|
||||||
RespTimeMoAvBuf.Init ( LEN_MOV_AV_RESPONSE );
|
RespTimeMoAvBuf.Init ( LEN_MOV_AV_RESPONSE );
|
||||||
|
|
||||||
// init time for response time evaluation
|
// init time for response time evaluation
|
||||||
TimeLastBlock = QTime::currentTime();
|
TimeLastBlock = PreciseTime.elapsed();
|
||||||
|
|
||||||
AudioReverb.Clear();
|
AudioReverb.Clear();
|
||||||
}
|
}
|
||||||
|
@ -338,56 +338,8 @@ void CClient::run()
|
||||||
PostWinMessage ( MS_JIT_BUF_GET, MUL_COL_LED_RED );
|
PostWinMessage ( MS_JIT_BUF_GET, MUL_COL_LED_RED );
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef _DEBUG_
|
|
||||||
#if 0
|
|
||||||
#if 0
|
|
||||||
/* Determine network delay. We can do this very simple if only this client is
|
|
||||||
connected to the server. In this case, exactly the same audio material is
|
|
||||||
coming back and we can simply compare the samples */
|
|
||||||
/* store send data instatic buffer (may delay is 100 ms) */
|
|
||||||
const int iMaxDelaySamples = (int) ((float) 0.3 /*0.1*/ * SYSTEM_SAMPLE_RATE);
|
|
||||||
static CVector<short> vecsOutBuf(iMaxDelaySamples);
|
|
||||||
|
|
||||||
/* update buffer */
|
|
||||||
const int iBufDiff = iMaxDelaySamples - iBlockSizeSam;
|
|
||||||
for (i = 0; i < iBufDiff; i++)
|
|
||||||
vecsOutBuf[i + iBlockSizeSam] = vecsOutBuf[i];
|
|
||||||
for (i = 0; i < iBlockSizeSam; i++)
|
|
||||||
vecsOutBuf[i] = vecsNetwork[i];
|
|
||||||
|
|
||||||
/* now search for equal samples */
|
|
||||||
int iDelaySamples = 0;
|
|
||||||
for (i = 0; i < iMaxDelaySamples - 1; i++)
|
|
||||||
{
|
|
||||||
/* compare two successive samples */
|
|
||||||
if ((vecsOutBuf[i] == (short) vecdNetwData[0]) &&
|
|
||||||
(vecsOutBuf[i + 1] == (short) vecdNetwData[1]))
|
|
||||||
{
|
|
||||||
iDelaySamples = i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static FILE* pFileDelay = fopen("delay.dat", "w");
|
|
||||||
fprintf(pFileDelay, "%d\n", iDelaySamples);
|
|
||||||
fflush(pFileDelay);
|
|
||||||
#else
|
|
||||||
/* just store both, input and output, streams */
|
|
||||||
// fid=fopen('v.dat','r');x=fread(fid,'int16');fclose(fid);
|
|
||||||
static FILE* pFileDelay = fopen("v.dat", "wb");
|
|
||||||
short sData[2];
|
|
||||||
for (i = 0; i < iBlockSizeSam; i++)
|
|
||||||
{
|
|
||||||
sData[0] = vecsNetwork[i];
|
|
||||||
sData[1] = (short) vecdNetwData[i];
|
|
||||||
fwrite(&sData, size_t(2), size_t(2), pFileDelay);
|
|
||||||
}
|
|
||||||
fflush(pFileDelay);
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
// TEST
|
||||||
// fid=fopen('v.dat','r');x=fread(fid,'int16');fclose(fid);
|
// fid=fopen('v.dat','r');x=fread(fid,'int16');fclose(fid);
|
||||||
static FILE* pFileDelay = fopen("v.dat", "wb");
|
static FILE* pFileDelay = fopen("v.dat", "wb");
|
||||||
short sData[2];
|
short sData[2];
|
||||||
|
@ -399,7 +351,6 @@ for (i = 0; i < iBlockSizeSam; i++)
|
||||||
fflush(pFileDelay);
|
fflush(pFileDelay);
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
// check if channel is connected
|
// check if channel is connected
|
||||||
if ( Channel.IsConnected() )
|
if ( Channel.IsConnected() )
|
||||||
{
|
{
|
||||||
|
@ -443,12 +394,12 @@ fflush(pFileDelay);
|
||||||
|
|
||||||
// update response time measurement ------------------------------------
|
// update response time measurement ------------------------------------
|
||||||
// add time difference
|
// add time difference
|
||||||
const QTime CurTime = QTime::currentTime();
|
const int CurTime = PreciseTime.elapsed();
|
||||||
|
|
||||||
// we want to calculate the standard deviation (we assume that the mean
|
// we want to calculate the standard deviation (we assume that the mean
|
||||||
// is correct at the block period time)
|
// is correct at the block period time)
|
||||||
const double dCurAddVal =
|
const double dCurAddVal =
|
||||||
( (double) TimeLastBlock.msecsTo ( CurTime ) - MIN_BLOCK_DURATION_MS );
|
( (double) ( CurTime - TimeLastBlock ) - MIN_BLOCK_DURATION_MS );
|
||||||
|
|
||||||
RespTimeMoAvBuf.Add ( dCurAddVal * dCurAddVal ); // add squared value
|
RespTimeMoAvBuf.Add ( dCurAddVal * dCurAddVal ); // add squared value
|
||||||
|
|
||||||
|
|
|
@ -178,12 +178,12 @@ protected:
|
||||||
CAudioResample ResampleObjUpL; // left channel
|
CAudioResample ResampleObjUpL; // left channel
|
||||||
CAudioResample ResampleObjUpR; // right channel
|
CAudioResample ResampleObjUpR; // right channel
|
||||||
|
|
||||||
// for ping measurement
|
// for ping measurement and standard deviation of audio interface
|
||||||
CPreciseTime PreciseTime;
|
CPreciseTime PreciseTime;
|
||||||
|
|
||||||
// debugging, evaluating
|
// debugging, evaluating
|
||||||
CMovingAv<double> RespTimeMoAvBuf;
|
CMovingAv<double> RespTimeMoAvBuf;
|
||||||
QTime TimeLastBlock;
|
int TimeLastBlock;
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void OnSendProtMessage ( CVector<uint8_t> vecMessage );
|
void OnSendProtMessage ( CVector<uint8_t> vecMessage );
|
||||||
|
|
|
@ -357,6 +357,11 @@ void CLlconClientDlg::UpdateDisplay()
|
||||||
{
|
{
|
||||||
TextLabelStatus->setText ( tr ( "disconnected" ) );
|
TextLabelStatus->setText ( tr ( "disconnected" ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TEST
|
||||||
|
//TextLabelStatus->setText ( QString( "Std dev: %1" ).arg ( pClient->GetTimingStdDev() ) );
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void CLlconClientDlg::customEvent ( QEvent* Event )
|
void CLlconClientDlg::customEvent ( QEvent* Event )
|
||||||
|
|
|
@ -107,6 +107,7 @@ void CServer::Start()
|
||||||
|
|
||||||
// init time for response time evaluation
|
// init time for response time evaluation
|
||||||
TimeLastBlock = QTime::currentTime();
|
TimeLastBlock = QTime::currentTime();
|
||||||
|
RespTimeMoAvBuf.Reset();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -158,9 +159,19 @@ void CServer::OnTimer()
|
||||||
ChannelSet.PrepSendPacket ( vecChanID[i], vecsSendData ),
|
ChannelSet.PrepSendPacket ( vecChanID[i], vecsSendData ),
|
||||||
ChannelSet.GetAddress ( vecChanID[i] ) );
|
ChannelSet.GetAddress ( vecChanID[i] ) );
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Disable server if no clients are connected. In this case the server
|
||||||
|
// does not consume any significant CPU when no client is connected.
|
||||||
|
#ifndef _WIN32
|
||||||
|
// event handling of custom events seems not to work under Windows in this
|
||||||
|
// class, do not use automatic start/stop of server in Windows version
|
||||||
|
Stop();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
// update response time measurement ----------------------------------------
|
||||||
// update response time measurement ------------------------------------
|
|
||||||
// add time difference
|
// add time difference
|
||||||
const QTime CurTime = QTime::currentTime();
|
const QTime CurTime = QTime::currentTime();
|
||||||
|
|
||||||
|
@ -174,17 +185,6 @@ void CServer::OnTimer()
|
||||||
// store old time value
|
// store old time value
|
||||||
TimeLastBlock = CurTime;
|
TimeLastBlock = CurTime;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
// Disable server if no clients are connected. In this case the server
|
|
||||||
// does not consume any significant CPU when no client is connected.
|
|
||||||
#ifndef _WIN32
|
|
||||||
// event handling of custom events seems not to work under Windows in this
|
|
||||||
// class, do not use automatic start/stop of server in Windows version
|
|
||||||
Stop();
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
CVector<short> CServer::ProcessData ( CVector<CVector<double> >& vecvecdData,
|
CVector<short> CServer::ProcessData ( CVector<CVector<double> >& vecvecdData,
|
||||||
CVector<double>& vecdGains )
|
CVector<double>& vecdGains )
|
||||||
|
|
26
src/util.h
26
src/util.h
|
@ -269,6 +269,7 @@ public:
|
||||||
|
|
||||||
virtual void Init ( const int iNewSize );
|
virtual void Init ( const int iNewSize );
|
||||||
void InitVec ( const int iNewSize, const int iNewVecSize );
|
void InitVec ( const int iNewSize, const int iNewVecSize );
|
||||||
|
void Reset();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
int iCurIdx;
|
int iCurIdx;
|
||||||
|
@ -284,6 +285,14 @@ template<class TData> void CMovingAv<TData>::Init ( const int iNewSize )
|
||||||
CVector<TData>::Init ( iNewSize );
|
CVector<TData>::Init ( iNewSize );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<class TData> void CMovingAv<TData>::Reset()
|
||||||
|
{
|
||||||
|
iNorm = 0;
|
||||||
|
iCurIdx = 0;
|
||||||
|
tCurAvResult = TData ( 0 ); // only for scalars!
|
||||||
|
CVector<TData>::Reset ( TData ( 0 ) );
|
||||||
|
}
|
||||||
|
|
||||||
template<class TData> void CMovingAv<TData>::Add ( const TData tNewD )
|
template<class TData> void CMovingAv<TData>::Add ( const TData tNewD )
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
|
@ -433,6 +442,23 @@ protected:
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// Mathematics utilities -------------------------------------------------------
|
||||||
|
class LlconMath
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static int NextPowerOfTwo ( const int& iSizeIn )
|
||||||
|
{
|
||||||
|
// calculate the next power of 2 of the given size
|
||||||
|
int iPowerOfTwo = 1;
|
||||||
|
while ( iPowerOfTwo < iSizeIn )
|
||||||
|
{
|
||||||
|
iPowerOfTwo <<= 1; // multiply by 2
|
||||||
|
}
|
||||||
|
return iPowerOfTwo;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
// Precise time ----------------------------------------------------------------
|
// Precise time ----------------------------------------------------------------
|
||||||
// needed for ping measurement
|
// needed for ping measurement
|
||||||
class CPreciseTime
|
class CPreciseTime
|
||||||
|
|
|
@ -407,6 +407,7 @@ bool CSound::LoadAndInitializeFirstValidDriver()
|
||||||
std::string CSound::PrepareDriver()
|
std::string CSound::PrepareDriver()
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
int iDesiredBufferSizeMono;
|
||||||
|
|
||||||
// check the number of available channels
|
// check the number of available channels
|
||||||
long lNumInChan;
|
long lNumInChan;
|
||||||
|
@ -442,15 +443,31 @@ std::string CSound::PrepareDriver()
|
||||||
&HWBufferInfo.lPreferredSize,
|
&HWBufferInfo.lPreferredSize,
|
||||||
&HWBufferInfo.lGranularity );
|
&HWBufferInfo.lGranularity );
|
||||||
|
|
||||||
|
// calculate the desired mono buffer size
|
||||||
|
|
||||||
|
// TEST -> put this in the GUI and implement the code for the Linux driver, too
|
||||||
|
// setting this variable to false sets the previous behaviour
|
||||||
|
const bool bPreferPowerOfTwoAudioBufferSize = false;
|
||||||
|
|
||||||
|
if ( bPreferPowerOfTwoAudioBufferSize )
|
||||||
|
{
|
||||||
|
// use next power of 2 for desired block size mono
|
||||||
|
iDesiredBufferSizeMono = LlconMath().NextPowerOfTwo ( iBufferSizeMono );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
iDesiredBufferSizeMono = iBufferSizeMono;
|
||||||
|
}
|
||||||
|
|
||||||
// calculate "nearest" buffer size and set internal parameter accordingly
|
// calculate "nearest" buffer size and set internal parameter accordingly
|
||||||
// first check minimum and maximum values
|
// first check minimum and maximum values
|
||||||
if ( iBufferSizeMono < HWBufferInfo.lMinSize )
|
if ( iDesiredBufferSizeMono < HWBufferInfo.lMinSize )
|
||||||
{
|
{
|
||||||
iASIOBufferSizeMono = HWBufferInfo.lMinSize;
|
iASIOBufferSizeMono = HWBufferInfo.lMinSize;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if ( iBufferSizeMono > HWBufferInfo.lMaxSize )
|
if ( iDesiredBufferSizeMono > HWBufferInfo.lMaxSize )
|
||||||
{
|
{
|
||||||
iASIOBufferSizeMono = HWBufferInfo.lMaxSize;
|
iASIOBufferSizeMono = HWBufferInfo.lMaxSize;
|
||||||
}
|
}
|
||||||
|
@ -464,18 +481,14 @@ std::string CSound::PrepareDriver()
|
||||||
// test loop
|
// test loop
|
||||||
while ( ( iTrialBufSize <= HWBufferInfo.lMaxSize ) && ( !bSizeFound ) )
|
while ( ( iTrialBufSize <= HWBufferInfo.lMaxSize ) && ( !bSizeFound ) )
|
||||||
{
|
{
|
||||||
if ( iTrialBufSize >= iBufferSizeMono )
|
if ( iTrialBufSize >= iDesiredBufferSizeMono )
|
||||||
{
|
{
|
||||||
// test which buffer size fits better: the old one or the
|
// test which buffer size fits better: the old one or the
|
||||||
// current one
|
// current one
|
||||||
if ( ( iTrialBufSize - iBufferSizeMono ) <
|
if ( ( iTrialBufSize - iDesiredBufferSizeMono ) >
|
||||||
( iBufferSizeMono - iLastTrialBufSize ) )
|
( iDesiredBufferSizeMono - iLastTrialBufSize ) )
|
||||||
{
|
{
|
||||||
iBufferSizeMono = iTrialBufSize;
|
iTrialBufSize = iLastTrialBufSize;
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
iBufferSizeMono = iLastTrialBufSize;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// exit while loop
|
// exit while loop
|
||||||
|
|
Loading…
Reference in a new issue