From d571f5328b00cc220a7979f5e322eba45f93b90f Mon Sep 17 00:00:00 2001 From: Volker Fischer Date: Sat, 11 Jun 2011 05:19:48 +0000 Subject: [PATCH] backup checkin, including lots of test code... --- ChangeLog | 2 +- src/buffer.cpp | 205 ++++- src/buffer.h | 175 +++- src/channel.cpp | 19 +- src/channel.h | 7 +- src/client.cpp | 15 + src/client.h | 2 - src/clientsettingsdlg.cpp | 15 +- src/clientsettingsdlgbase.ui | 60 +- src/global.h | 2 +- src/llconclientdlg.cpp | 5 + src/server.cpp | 19 - src/server.h | 2 - src/util.h | 1659 ++++++++++++++++++---------------- 14 files changed, 1269 insertions(+), 918 deletions(-) diff --git a/ChangeLog b/ChangeLog index 8134c649..7324fb48 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,4 +1,4 @@ -4.0.0 +3.2.0 - new GUI style of the main window, added switch for selecting the GUI style in the settings window diff --git a/src/buffer.cpp b/src/buffer.cpp index 89824ec6..90857564 100755 --- a/src/buffer.cpp +++ b/src/buffer.cpp @@ -54,11 +54,37 @@ bool CNetBuf::Put ( const CVector& vecbyData, // Check if there is not enough space available -> correct if ( GetAvailSpace() < iInSize ) { +/* // not enough space in buffer for put operation, correct buffer to // prepare for new data Clear ( CT_PUT ); bPutOK = false; // return error flag +*/ + +/* +// TEST invalidate last written block for better PLC +// ATTENTION: We assume that mem size is factor of block size here!!!! +if ( !bIsSimulation ) +{ + if ( iPutPos == 0 ) + { + for ( int iPos = iMemSize - iInSize; iPos < iMemSize; iPos++ ) + { + vecMemory[iPos] = 0; + } + } + else + { + for ( int iPos = iPutPos - iInSize; iPos < iPutPos; iPos++ ) + { + vecMemory[iPos] = 0; + } + } +} +*/ + +return false; // check for special case: buffer memory is not sufficient if ( iInSize > iMemSize ) @@ -86,7 +112,7 @@ bool CNetBuf::Get ( CVector& vecbyData ) { return false; } - +/* // check for invalid data in buffer if ( iNumInvalidElements > 0 ) { @@ -96,15 +122,19 @@ bool CNetBuf::Get ( CVector& vecbyData ) bGetOK = false; // return error flag } +*/ // Check if there is not enough data available -> correct if ( GetAvailData() < iInSize ) { +/* // not enough data in buffer for get operation, correct buffer to // prepare for getting data Clear ( CT_GET ); bGetOK = false; // return error flag +*/ +return false; // check for special case: buffer memory is not sufficient if ( iInSize > iMemSize ) @@ -118,11 +148,33 @@ bool CNetBuf::Get ( CVector& vecbyData ) // class) CBufferBase::Get ( vecbyData ); +/* +// TEST check for all zero packet +bool bAllZeroPacket = true; +for ( int iPos = 0; iPos < iInSize; iPos++ ) +{ + if ( vecbyData[iPos] != 0 ) + { + bAllZeroPacket = false; + } +} +if ( bAllZeroPacket ) +{ + return false; +} +*/ + return bGetOK; } void CNetBuf::Clear ( const EClearType eClearType ) { + +// TEST +CBufferBase::Clear ( eClearType ); + + +/* // Define the number of blocks bound for the "random offset" (1) algorithm. // If we are above the bound, we use the "middle of buffer" (2) algorithm. // @@ -177,6 +229,13 @@ void CNetBuf::Clear ( const EClearType eClearType ) // 1: 0 / 2: 0 / 3: 1 / 4: 1 / 5: 2 ...) iNewFillLevel = ( ( ( iMemSize - iBlockSize) / 2 ) / iBlockSize ) * iBlockSize; + + +// TEST +iNewFillLevel += static_cast ( static_cast ( rand() ) * + iNumBlocksBoundInclForRandom / RAND_MAX ) * iBlockSize - + iNumBlocksBoundInclForRandom / 2 * iBlockSize; + } } @@ -184,7 +243,10 @@ void CNetBuf::Clear ( const EClearType eClearType ) if ( eClearType == CT_GET ) { // clear buffer since we had a buffer underrun - vecMemory.Reset ( 0 ); + if ( !bIsSimulation ) + { + vecMemory.Reset ( 0 ); + } // reset buffer pointers so that they are at maximum distance after // the get operation (assign new fill level value to the get pointer) @@ -233,4 +295,143 @@ void CNetBuf::Clear ( const EClearType eClearType ) eBufState = CNetBuf::BS_OK; } } + +// TEST +//iNumInvalidElements = 8 * iMemSize; +*/ +} + + +/* Network buffer with statistic calculations implementation ******************/ +CNetBufWithStats::CNetBufWithStats() : + CNetBuf ( false ) // base class init: no simulation mode +{ + // define the sizes of the simulation buffers, + // must be NUM_STAT_SIMULATION_BUFFERS elements! + viBufSizesForSim[0] = 2; + viBufSizesForSim[1] = 3; + viBufSizesForSim[2] = 4; + viBufSizesForSim[3] = 5; + viBufSizesForSim[4] = 6; + viBufSizesForSim[5] = 7; + viBufSizesForSim[6] = 8; + viBufSizesForSim[7] = 9; + viBufSizesForSim[8] = 10; + viBufSizesForSim[9] = 12; + viBufSizesForSim[10] = 14; + viBufSizesForSim[11] = 17; + viBufSizesForSim[12] = 20; + + // set all simulation buffers in simulation mode + for ( int i = 0; i < NUM_STAT_SIMULATION_BUFFERS; i++ ) + { + SimulationBuffer[i].SetIsSimulation ( true ); + } +} + +void CNetBufWithStats::Init ( const int iNewBlockSize, + const int iNewNumBlocks, + const bool bPreserve ) +{ + // call base class Init + CNetBuf::Init ( iNewBlockSize, iNewNumBlocks, bPreserve ); + + // inits for statistics calculation + if ( !bPreserve ) + { + for ( int i = 0; i < NUM_STAT_SIMULATION_BUFFERS; i++ ) + { + // init simulation buffers with the correct size + SimulationBuffer[i].Init ( iNewBlockSize, viBufSizesForSim[i] ); + + // init statistics + ErrorRateStatistic[i].Init ( 80000, true );//TEST!!!!!//MAX_STATISTIC_COUNT ); + } + } +} + +bool CNetBufWithStats::Put ( const CVector& vecbyData, + const int iInSize ) +{ + // call base class Put + const bool bPutOK = CNetBuf::Put ( vecbyData, iInSize ); + + // update statistics calculations + for ( int i = 0; i < NUM_STAT_SIMULATION_BUFFERS; i++ ) + { + ErrorRateStatistic[i].Update ( + !SimulationBuffer[i].Put ( vecbyData, iInSize ) ); + } + + return bPutOK; +} + +bool CNetBufWithStats::Get ( CVector& vecbyData ) +{ + // call base class Get + const bool bGetOK = CNetBuf::Get ( vecbyData ); + + // update statistics calculations + for ( int i = 0; i < NUM_STAT_SIMULATION_BUFFERS; i++ ) + { + ErrorRateStatistic[i].Update ( + !SimulationBuffer[i].Get ( vecbyData ) ); + } + + return bGetOK; +} + +// TEST +int CNetBufWithStats::GetAutoSetting() +{ + +/* +// TEST +if ( ErrorRateStatistic[NUM_STAT_SIMULATION_BUFFERS - 1].GetAverage() > 0.06 ) +{ + for ( int i = 0; i < NUM_STAT_SIMULATION_BUFFERS; i++ ) + { + ErrorRateStatistic[i].Reset(); + } +} +*/ + + + for ( int i = 0; i < NUM_STAT_SIMULATION_BUFFERS - 1; i++ ) + { + if ( ErrorRateStatistic[i].GetAverage() <= 0.005)//TEST!!!!! 0.005 ) + { + return viBufSizesForSim[i]; + } + } + return viBufSizesForSim[NUM_STAT_SIMULATION_BUFFERS - 1]; +} + + +// TEST for debugging +void CNetBufWithStats::StoreAllSimAverages() +{ + + FILE* pFile = fopen ( "c:\\temp\\test.dat", "w" ); + + + for ( int i = 0; i < NUM_STAT_SIMULATION_BUFFERS - 1; i++ ) + { + fprintf ( pFile, "%e, ", ErrorRateStatistic[i].GetAverage() ); + } + fprintf ( pFile, "%e", ErrorRateStatistic[NUM_STAT_SIMULATION_BUFFERS - 1].GetAverage() ); + fprintf ( pFile, "\n" ); + + +/* +const int iLen = ErrorRateStatistic[4].ErrorsMovAvBuf.Size(); +for ( int i = 0; i < iLen; i++ ) +{ + fprintf ( pFile, "%e\n", ErrorRateStatistic[4].ErrorsMovAvBuf[i] ); +} +*/ + fclose ( pFile ); + +// scilab: +// close;x=read('c:/temp/test.dat',-1,13);plot2d([2,3,4,5,6,7,8,9,10,12,14,17,20], x, style=-1 , logflag = 'nl');plot2d([2 20],[1 1]*0.01);plot2d([2 20],[1 1]*0.005);x } diff --git a/src/buffer.h b/src/buffer.h index e6fcc7e8..a445e14a 100755 --- a/src/buffer.h +++ b/src/buffer.h @@ -29,18 +29,37 @@ #include "global.h" +/* Definitions ****************************************************************/ +// each regular buffer access lead to a count for put and get, assuming 2.33 ms +// blocks we have 30 s / 2.33 ms * 2 = 25714 +//#define MAX_STATISTIC_COUNT 25714 + +// TEST +// 7 / 0.00266 * 2 = 5263.1579 +#define MAX_STATISTIC_COUNT 3759 + + +// number of simulation network jitter buffers for evaluating the statistic +#define NUM_STAT_SIMULATION_BUFFERS 13 + + /* Classes ********************************************************************/ // Buffer base class ----------------------------------------------------------- template class CBufferBase { public: - CBufferBase() : bIsInitialized ( false ) {} + CBufferBase ( const bool bNIsSim = false ) : + bIsSimulation ( bNIsSim ), bIsInitialized ( false ) {} + + void SetIsSimulation ( const bool bNIsSim ) { bIsSimulation = bNIsSim; } virtual void Init ( const int iNewMemSize, const bool bPreserve = false ) { + // in simulation mode the size is not changed during operation -> we do + // not have to implement special code for this case // only enter the "preserve" branch, if object was already initialized - if ( bPreserve && bIsInitialized ) + if ( bPreserve && ( !bIsSimulation ) && bIsInitialized ) { // copy old data in new vector using get pointer as zero per // definition @@ -143,7 +162,10 @@ public: else { // allocate memory for actual data buffer - vecMemory.Init ( iNewMemSize ); + if ( !bIsSimulation ) + { + vecMemory.Init ( iNewMemSize ); + } // init buffer pointers and buffer state (empty buffer) iGetPos = 0; @@ -161,31 +183,44 @@ public: virtual bool Put ( const CVector& vecData, const int iInSize ) { - // copy new data in internal buffer - int iCurPos = 0; - if ( iPutPos + iInSize > iMemSize ) + if ( bIsSimulation ) { - // remaining space size for second block - const int iRemSpace = iPutPos + iInSize - iMemSize; - - // data must be written in two steps because of wrap around - while ( iPutPos < iMemSize ) + // in this simulation only the buffer pointers and the buffer state + // is updated, no actual data is transferred + iPutPos += iInSize; + if ( iPutPos >= iMemSize ) { - vecMemory[iPutPos++] = vecData[iCurPos++]; - } - - for ( iPutPos = 0; iPutPos < iRemSpace; iPutPos++ ) - { - vecMemory[iPutPos] = vecData[iCurPos++]; + iPutPos -= iMemSize; } } else { - // data can be written in one step - const int iEnd = iPutPos + iInSize; - while ( iPutPos < iEnd ) + // copy new data in internal buffer + int iCurPos = 0; + if ( iPutPos + iInSize > iMemSize ) { - vecMemory[iPutPos++] = vecData[iCurPos++]; + // remaining space size for second block + const int iRemSpace = iPutPos + iInSize - iMemSize; + + // data must be written in two steps because of wrap around + while ( iPutPos < iMemSize ) + { + vecMemory[iPutPos++] = vecData[iCurPos++]; + } + + for ( iPutPos = 0; iPutPos < iRemSpace; iPutPos++ ) + { + vecMemory[iPutPos] = vecData[iCurPos++]; + } + } + else + { + // data can be written in one step + const int iEnd = iPutPos + iInSize; + while ( iPutPos < iEnd ) + { + vecMemory[iPutPos++] = vecData[iCurPos++]; + } } } @@ -207,31 +242,44 @@ public: // get size of data to be get from the buffer const int iInSize = vecData.Size(); - // copy data from internal buffer in output buffer - int iCurPos = 0; - if ( iGetPos + iInSize > iMemSize ) + if ( bIsSimulation ) { - // remaining data size for second block - const int iRemData = iGetPos + iInSize - iMemSize; - - // data must be read in two steps because of wrap around - while ( iGetPos < iMemSize ) + // in this simulation only the buffer pointers and the buffer state + // is updated, no actual data is transferred + iGetPos += iInSize; + if ( iGetPos >= iMemSize ) { - vecData[iCurPos++] = vecMemory[iGetPos++]; - } - - for ( iGetPos = 0; iGetPos < iRemData; iGetPos++ ) - { - vecData[iCurPos++] = vecMemory[iGetPos]; + iGetPos -= iMemSize; } } else { - // data can be read in one step - const int iEnd = iGetPos + iInSize; - while ( iGetPos < iEnd ) + // copy data from internal buffer in output buffer + int iCurPos = 0; + if ( iGetPos + iInSize > iMemSize ) { - vecData[iCurPos++] = vecMemory[iGetPos++]; + // remaining data size for second block + const int iRemData = iGetPos + iInSize - iMemSize; + + // data must be read in two steps because of wrap around + while ( iGetPos < iMemSize ) + { + vecData[iCurPos++] = vecMemory[iGetPos++]; + } + + for ( iGetPos = 0; iGetPos < iRemData; iGetPos++ ) + { + vecData[iCurPos++] = vecMemory[iGetPos]; + } + } + else + { + // data can be read in one step + const int iEnd = iGetPos + iInSize; + while ( iGetPos < iEnd ) + { + vecData[iCurPos++] = vecMemory[iGetPos++]; + } } } @@ -292,12 +340,28 @@ public: protected: enum EBufState { BS_OK, BS_FULL, BS_EMPTY }; + enum EClearType { CT_PUT, CT_GET }; + + virtual void Clear ( const EClearType eClearType ) + { + // clear memory + if ( !bIsSimulation ) + { + vecMemory.Reset ( 0 ); + } + + // init buffer pointers and buffer state (empty buffer) + iGetPos = 0; + iPutPos = 0; + eBufState = CBufferBase::BS_EMPTY; + } CVector vecMemory; int iMemSize; int iGetPos; int iPutPos; EBufState eBufState; + bool bIsSimulation; bool bIsInitialized; }; @@ -306,6 +370,9 @@ protected: class CNetBuf : public CBufferBase { public: + CNetBuf ( const bool bNewIsSim = false ) : + CBufferBase ( bNewIsSim ) {} + virtual void Init ( const int iNewBlockSize, const int iNewNumBlocks, const bool bPreserve = false ); @@ -316,15 +383,39 @@ public: virtual bool Get ( CVector& vecbyData ); protected: - enum EClearType { CT_PUT, CT_GET }; - - void Clear ( const EClearType eClearType ); + virtual void Clear ( const EClearType eClearType ); int iBlockSize; int iNumInvalidElements; }; +// Network buffer (jitter buffer) with statistic calculations ------------------ +class CNetBufWithStats : public CNetBuf +{ +public: + CNetBufWithStats(); + + virtual void Init ( const int iNewBlockSize, + const int iNewNumBlocks, + const bool bPreserve = false ); + + virtual bool Put ( const CVector& vecbyData, const int iInSize ); + virtual bool Get ( CVector& vecbyData ); + +// TEST +void StoreAllSimAverages(); +int GetAutoSetting(); + +protected: + // statistic (do not use the vector class since the classes do not have + // appropriate copy constructor/operator) + CErrorRate ErrorRateStatistic[NUM_STAT_SIMULATION_BUFFERS]; + CNetBuf SimulationBuffer[NUM_STAT_SIMULATION_BUFFERS]; + int viBufSizesForSim[NUM_STAT_SIMULATION_BUFFERS]; +}; + + // Conversion buffer (very simple buffer) -------------------------------------- // For this very simple buffer no wrap around mechanism is implemented. We // assume here, that the applied buffers are an integer fraction of the total diff --git a/src/channel.cpp b/src/channel.cpp index 517bd65b..a2427662 100755 --- a/src/channel.cpp +++ b/src/channel.cpp @@ -611,6 +611,20 @@ void CChannel::UpdateSocketBufferSize ( const double dLocalStdDev ) // do nothing if ( bDoAutoSockBufSize ) { + +// TEST +SetSockBufNumFrames ( SockBuf.GetAutoSetting(), true ); + +/* +#ifdef _WIN32 +// TEST +static FILE* pFile = fopen ( "c:\\temp\\test.dat", "w" ); +fprintf ( pFile, "%d\n", SockBuf.GetAutoSetting() ); +fflush ( pFile ); +#endif +*/ + +/* // We use the time response measurement for the automatic setting. // Assumptions: // - the audio interface/network jitter is assumed to be Gaussian @@ -633,7 +647,7 @@ void CChannel::UpdateSocketBufferSize ( const double dLocalStdDev ) const double dEstCurBufSet = ( SYSTEM_BLOCK_DURATION_MS_FLOAT + 3.3 * ( CycleTimeVariance.GetStdDev() + dLocalStdDev ) ) / SYSTEM_BLOCK_DURATION_MS_FLOAT + 0.5; - +*/ /* // TEST //if (bIsServer) { @@ -643,7 +657,7 @@ fflush ( pFile ); // close;x=read('c:/temp/test.dat',-1,3);plot(x) //} */ - +/* // upper/lower hysteresis decision const int iUpperHystDec = LlconMath().round ( dEstCurBufSet - dHysteresis ); const int iLowerHystDec = LlconMath().round ( dEstCurBufSet + dHysteresis ); @@ -667,5 +681,6 @@ fflush ( pFile ); SetSockBufNumFrames ( iUpperHystDec, true ); } } +*/ } } diff --git a/src/channel.h b/src/channel.h index c9e20533..c685709c 100755 --- a/src/channel.h +++ b/src/channel.h @@ -132,6 +132,11 @@ public: void CreateNetTranspPropsMessFromCurrentSettings(); + +// TEST +void StoreAllSimAverages() { SockBuf.StoreAllSimAverages(); } + + protected: bool ProtocolIsEnabled(); @@ -145,7 +150,7 @@ protected: CVector vecdGains; // network jitter-buffer - CNetBuf SockBuf; + CNetBufWithStats SockBuf; int iCurSockBufNumFrames; bool bDoAutoSockBufSize; diff --git a/src/client.cpp b/src/client.cpp index c055cc1f..ffd831c1 100755 --- a/src/client.cpp +++ b/src/client.cpp @@ -924,6 +924,21 @@ void CClient::ProcessAudioDataIntern ( CVector& vecsStereoSndCrd ) } } + +/* +// TEST +// fid=fopen('v.dat','r');x=fread(fid,'int16');fclose(fid); +static FILE* pFileDelay = fopen("c:\\temp\\test2.dat", "wb"); +short sData[2]; +for (i = 0; i < iMonoBlockSizeSam; i++) +{ + sData[0] = (short) vecsAudioSndCrdMono[i]; + fwrite(&sData, size_t(2), size_t(1), pFileDelay); +} +fflush(pFileDelay); +*/ + + // check if channel is connected if ( Channel.IsConnected() ) { diff --git a/src/client.h b/src/client.h index 010ff3a3..abf6716d 100755 --- a/src/client.h +++ b/src/client.h @@ -92,8 +92,6 @@ public: double MicLevelR() { return SignalLevelMeter.MicLevelRight(); } bool IsConnected() { return Channel.IsConnected(); } - double GetTimingStdDev() { return CycleTimeVariance.GetStdDev(); } - bool GetOpenChatOnNewMessage() const { return bOpenChatOnNewMessage; } void SetOpenChatOnNewMessage ( const bool bNV ) { bOpenChatOnNewMessage = bNV; } diff --git a/src/clientsettingsdlg.cpp b/src/clientsettingsdlg.cpp index 605bda6a..0d1fa80c 100755 --- a/src/clientsettingsdlg.cpp +++ b/src/clientsettingsdlg.cpp @@ -271,9 +271,9 @@ CClientSettingsDlg::CClientSettingsDlg ( CClient* pNCliP, QWidget* parent, // init delay and other information controls ledOverallDelay->SetUpdateTime ( 2 * PING_UPDATE_TIME_MS ); ledOverallDelay->Reset(); - lblPingTimeValue->setText ( "" ); - lblOverallDelayValue->setText ( "" ); - lblUpstreamValue->setText ( "" ); + lblPingTimeValue->setText ( "---" ); + lblOverallDelayValue->setText ( "---" ); + lblUpstreamValue->setText ( "---" ); // init slider controls --- @@ -350,8 +350,7 @@ CClientSettingsDlg::CClientSettingsDlg ( CClient* pNCliP, QWidget* parent, ", preferred" ) ); rbtBufferDelayDefault->setText ( GenSndCrdBufferDelayString ( - FRAME_SIZE_FACTOR_DEFAULT * SYSTEM_FRAME_SIZE_SAMPLES, - ", default" ) ); + FRAME_SIZE_FACTOR_DEFAULT * SYSTEM_FRAME_SIZE_SAMPLES ) ); rbtBufferDelaySafe->setText ( GenSndCrdBufferDelayString ( FRAME_SIZE_FACTOR_SAFE * SYSTEM_FRAME_SIZE_SAMPLES ) ); @@ -741,9 +740,9 @@ void CClientSettingsDlg::UpdateDisplay() if ( !pClient->IsRunning() ) { // clear text labels with client parameters - lblPingTimeValue->setText ( "" ); - lblOverallDelayValue->setText ( "" ); - lblUpstreamValue->setText ( "" ); + lblPingTimeValue->setText ( "---" ); + lblOverallDelayValue->setText ( "---" ); + lblUpstreamValue->setText ( "---" ); } else { diff --git a/src/clientsettingsdlgbase.ui b/src/clientsettingsdlgbase.ui index 0d5d8351..ee700923 100755 --- a/src/clientsettingsdlgbase.ui +++ b/src/clientsettingsdlgbase.ui @@ -564,6 +564,30 @@ + + + + + + Audio Stream Rate + + + + + + + + 0 + 20 + + + + val + + + + + @@ -622,12 +646,6 @@ 20 - - - 75 - true - - val @@ -659,36 +677,6 @@ - - - - - - Audio Stream Rate - - - - - - - - 0 - 20 - - - - - 75 - true - - - - val - - - - - diff --git a/src/global.h b/src/global.h index 6750808c..0babadf5 100755 --- a/src/global.h +++ b/src/global.h @@ -60,7 +60,7 @@ LED bar: lbr // version and application name (always use this version) #undef VERSION -#define VERSION "4.0.0cvs" +#define VERSION "3.2.0cvs" #define APP_NAME "llcon" // Windows registry key name of auto run entry for the server diff --git a/src/llconclientdlg.cpp b/src/llconclientdlg.cpp index 9be0a76f..af667422 100755 --- a/src/llconclientdlg.cpp +++ b/src/llconclientdlg.cpp @@ -943,6 +943,11 @@ void CLlconClientDlg::UpdateDisplay() chbChat->setChecked ( true ); chbChat->blockSignals ( false ); } + + +// TEST +pClient->GetChannel()->StoreAllSimAverages(); + } void CLlconClientDlg::SetGUIDesign ( const EGUIDesign eNewDesign ) diff --git a/src/server.cpp b/src/server.cpp index 85a2aebd..3f953435 100755 --- a/src/server.cpp +++ b/src/server.cpp @@ -1218,25 +1218,6 @@ void CServer::WriteHTMLChannelList() streamFileOut << "" << endl; } -bool CServer::GetTimingStdDev ( double& dCurTiStdDev ) -{ - dCurTiStdDev = 0.0; // init return value - - // only return value if server is active and the actual measurement is - // updated - if ( IsRunning() ) - { - // return the standard deviation - dCurTiStdDev = CycleTimeVariance.GetStdDev(); - - return true; - } - else - { - return false; - } -} - void CServer::customEvent ( QEvent* pEvent ) { if ( pEvent->type() == QEvent::User + 11 ) diff --git a/src/server.h b/src/server.h index f81b7403..8aaa152b 100755 --- a/src/server.h +++ b/src/server.h @@ -116,8 +116,6 @@ public: void Stop(); bool IsRunning() { return HighPrecisionTimer.isActive(); } - bool GetTimingStdDev ( double& dCurTiStdDev ); - bool PutData ( const CVector& vecbyRecBuf, const int iNumBytesRead, const CHostAddress& HostAdr ); diff --git a/src/util.h b/src/util.h index d4be259f..f2651508 100755 --- a/src/util.h +++ b/src/util.h @@ -1,807 +1,862 @@ -/******************************************************************************\ - * Copyright (c) 2004-2011 - * - * Author(s): - * Volker Fischer - * - ****************************************************************************** - * - * This program is free software; you can redistribute it and/or modify it under - * the terms of the GNU General Public License as published by the Free Software - * Foundation; either version 2 of the License, or (at your option) any later - * version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more - * details. - * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * -\******************************************************************************/ - -#if !defined ( UTIL_HOIH934256GEKJH98_3_43445KJIUHF1912__INCLUDED_ ) -#define UTIL_HOIH934256GEKJH98_3_43445KJIUHF1912__INCLUDED_ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "global.h" -using namespace std; // because of the library: "vector" -#ifdef _WIN32 -# include "../windows/moc/aboutdlgbase.h" -# include -# include -#else -# ifdef _IS_QMAKE_CONFIG -# include "ui_aboutdlgbase.h" -# else -# include "moc/aboutdlgbase.h" -# endif -#endif - - -/* Definitions ****************************************************************/ -#define METER_FLY_BACK 2 - - -/* Global functions ***********************************************************/ -// converting double to short -inline short Double2Short ( const double dInput ) -{ - // lower bound - if ( dInput < _MINSHORT ) - { - return _MINSHORT; - } - - // upper bound - if ( dInput > _MAXSHORT ) - { - return _MAXSHORT; - } - - return (short) dInput; -} - -// debug error handling -void DebugError ( const QString& pchErDescr, - const QString& pchPar1Descr, - const double dPar1, - const QString& pchPar2Descr, - const double dPar2 ); - - -/******************************************************************************\ -* CVector Base Class * -\******************************************************************************/ -template class CVector : public std::vector -{ -public: - CVector() : iVectorSize ( 0 ) { pData = this->begin(); } - CVector ( const int iNeSi ) { Init(iNeSi); } - CVector ( const int iNeSi, const TData tInVa ) { Init ( iNeSi, tInVa ); } - - // Copy constructor: The order of the initialization list must not be - // changed. First, the base class must be initialized, then the pData - // pointer must be set to the new data source. The bit access is, by - // default, reset. - CVector ( const CVector& vecI ) : - std::vector ( static_cast&> ( vecI ) ), - iVectorSize ( vecI.Size() ) { pData = this->begin(); } - - void Init ( const int iNewSize ); - - // use this init to give all elements a defined value - void Init ( const int iNewSize, const TData tIniVal ); - void Reset ( const TData tResetVal ); - - void Enlarge ( const int iAddedSize ); - void Add ( const TData& tI ) { Enlarge ( 1 ); pData[iVectorSize - 1] = tI; } - - inline int Size() const { return iVectorSize; } - - // This operator allows for a l-value assignment of this object: - // CVector[x] = y is possible - inline TData& operator[] ( const int iPos ) { -#ifdef _DEBUG_ - if ( ( iPos < 0 ) || ( iPos > iVectorSize - 1 ) ) - { - DebugError ( "Writing vector out of bounds", "Vector size", - iVectorSize, "New parameter", iPos ); - } -#endif - return pData[iPos]; } - - inline TData operator[] ( const int iPos ) const { -#ifdef _DEBUG_ - if ( ( iPos < 0 ) || ( iPos > iVectorSize - 1 ) ) - { - DebugError ( "Reading vector out of bounds", "Vector size", - iVectorSize, "New parameter", iPos ); - } -#endif - return pData[iPos]; } - - inline CVector& operator= ( const CVector& vecI ) { -#ifdef _DEBUG_ - // Vectors which shall be copied MUST have same size! (If this is - // satisfied, the parameter "iVectorSize" must not be adjusted as - // a side effect) - if ( vecI.Size() != iVectorSize ) - { - DebugError ( "Vector operator=() different size", "Vector size", - iVectorSize, "New parameter", vecI.Size() ); - } -#endif - vector::operator= ( vecI ); - - // reset my data pointer in case, the operator=() of the base class - // did change the actual memory - pData = this->begin(); - - return *this; - } - -protected: - typename std::vector::iterator pData; - int iVectorSize; -}; - - -/* Implementation *************************************************************/ -template void CVector::Init ( const int iNewSize ) -{ - iVectorSize = iNewSize; - - // clear old buffer and reserve memory for new buffer, get iterator - // for pointer operations - this->clear(); - this->resize ( iNewSize ); - pData = this->begin(); -} - -template void CVector::Init ( const int iNewSize, - const TData tIniVal ) -{ - // call actual init routine - Init ( iNewSize ); - - // set values - Reset ( tIniVal ); -} - -template void CVector::Enlarge ( const int iAddedSize ) -{ - iVectorSize += iAddedSize; - this->resize ( iVectorSize ); - - // we have to reset the pointer since it could be that the vector size was - // zero before enlarging the vector - pData = this->begin(); -} - -template void CVector::Reset ( const TData tResetVal ) -{ - // set all values to reset value - for ( int i = 0; i < iVectorSize; i++ ) - { - pData[i] = tResetVal; - } -} - - -/******************************************************************************\ -* CFIFO Class (First In, First Out) * -\******************************************************************************/ -template class CFIFO : public CVector -{ -public: - CFIFO() : CVector(), iCurIdx ( 0 ) {} - CFIFO ( const int iNeSi ) : CVector(iNeSi), iCurIdx ( 0 ) {} - CFIFO ( const int iNeSi, const TData tInVa ) : - CVector ( iNeSi, tInVa ), iCurIdx ( 0 ) {} - - void Add ( const TData tNewD ); - inline TData Get() { return this->pData[iCurIdx]; } - - virtual void Init ( const int iNewSize ); - virtual void Init ( const int iNewSize, const TData tIniVal ); - -protected: - int iCurIdx; -}; - -template void CFIFO::Init ( const int iNewSize ) -{ - iCurIdx = 0; - CVector::Init ( iNewSize ); -} - -template void CFIFO::Init ( const int iNewSize, - const TData tIniVal ) -{ - iCurIdx = 0; - CVector::Init ( iNewSize, tIniVal ); -} - -template void CFIFO::Add ( const TData tNewD ) -{ - this->pData[iCurIdx] = tNewD; - - // increment index - iCurIdx++; - if ( iCurIdx >= this->iVectorSize ) - { - iCurIdx = 0; - } -} - - -/******************************************************************************\ -* CMovingAv Class (Moving Average) * -\******************************************************************************/ -template class CMovingAv : public CVector -{ -public: - CMovingAv() : CVector(), iCurIdx ( 0 ), iNorm ( 0 ), - tCurAvResult ( TData ( 0 ) ) {} - CMovingAv ( const int iNeSi ) : CVector ( iNeSi ), iCurIdx ( 0 ), - iNorm ( 0 ), tCurAvResult ( TData ( 0 ) ) {} - CMovingAv ( const int iNeSi, const TData tInVa ) : - CVector ( iNeSi, tInVa ), iCurIdx ( 0 ), iNorm ( 0 ), - tCurAvResult ( TData ( 0 ) ) {} - - void Add ( const TData tNewD ); - inline TData GetAverage() - { - if ( this->iNorm == 0 ) - { - return TData ( 0 ); - } - else - { - return tCurAvResult / this->iNorm; - } - } - - virtual void Init ( const int iNewSize ); - void InitVec ( const int iNewSize, const int iNewVecSize ); - void Reset(); - bool IsInitialized() { return ( this->iNorm == this->iVectorSize ); } - -protected: - int iCurIdx; - int iNorm; - TData tCurAvResult; -}; - -template void CMovingAv::Init ( const int iNewSize ) -{ - iNorm = 0; - iCurIdx = 0; - tCurAvResult = TData ( 0 ); // only for scalars! - CVector::Init ( iNewSize ); -} - -template void CMovingAv::Reset() -{ - iNorm = 0; - iCurIdx = 0; - tCurAvResult = TData ( 0 ); // only for scalars! - CVector::Reset ( TData ( 0 ) ); -} - -template void CMovingAv::Add ( const TData tNewD ) -{ -/* - Optimized calculation of the moving average. We only add a new value and - subtract the old value from the result. We only need one addition and a - history buffer. -*/ - // subtract oldest value - tCurAvResult -= this->pData[iCurIdx]; - - // add new value and write in memory - tCurAvResult += tNewD; - this->pData[iCurIdx] = tNewD; - - // increase position pointer and test if wrap - iCurIdx++; - if ( iCurIdx >= this->iVectorSize ) - { - iCurIdx = 0; - } - - // take care of norm - if ( this->iNorm < this->iVectorSize ) - { - this->iNorm++; - } -} - - -/******************************************************************************\ -* GUI Utilities * -\******************************************************************************/ -// About dialog ---------------------------------------------------------------- -class CAboutDlg : public QDialog, private Ui_CAboutDlgBase -{ - Q_OBJECT - -public: - CAboutDlg ( QWidget* parent = 0 ); - - static QString GetVersionAndNameStr ( const bool bWithHtml = true ); -}; - - -// Help menu ------------------------------------------------------------------- -class CLlconHelpMenu : public QMenu -{ - Q_OBJECT - -public: - CLlconHelpMenu ( QWidget* parent = 0 ); - -protected: - CAboutDlg AboutDlg; - -public slots: - void OnHelpWhatsThis() { QWhatsThis::enterWhatsThisMode(); } - void OnHelpAbout() { AboutDlg.exec(); } - void OnHelpDownloadLink() - { QDesktopServices::openUrl ( QUrl ( LLCON_DOWNLOAD_URL ) ); } -}; - - -/******************************************************************************\ -* Other Classes * -\******************************************************************************/ -// Stereo signal level meter --------------------------------------------------- -class CStereoSignalLevelMeter -{ -public: - CStereoSignalLevelMeter() { Reset(); } - - void Update ( CVector& vecsAudio ); - double MicLevelLeft() { return CalcLogResult ( dCurLevelL ); } - double MicLevelRight() { return CalcLogResult ( dCurLevelR ); } - void Reset() { dCurLevelL = 0.0; dCurLevelR = 0.0; } - -protected: - double CalcLogResult ( const double& dLinearLevel ); - double UpdateCurLevel ( double dCurLevel, const short& sMax ); - - double dCurLevelL; - double dCurLevelR; -}; - - -// Host address ---------------------------------------------------------------- -class CHostAddress -{ -public: - enum EStringMode - { - SM_IP_PORT, - SM_IP_NO_LAST_BYTE, - SM_IP_NO_LAST_BYTE_PORT - }; - - CHostAddress() : - InetAddr ( static_cast ( 0 ) ), - iPort ( 0 ) {} - - CHostAddress ( const QHostAddress NInetAddr, - const quint16 iNPort ) : - InetAddr ( NInetAddr ), - iPort ( iNPort ) {} - - CHostAddress ( const CHostAddress& NHAddr ) : - InetAddr ( NHAddr.InetAddr ), - iPort ( NHAddr.iPort ) {} - - // copy operator - CHostAddress& operator= ( const CHostAddress& NHAddr ) - { - InetAddr = NHAddr.InetAddr; - iPort = NHAddr.iPort; - return *this; - } - - // compare operator - bool operator== ( const CHostAddress& CompAddr ) // compare operator - { - return ( ( CompAddr.InetAddr == InetAddr ) && - ( CompAddr.iPort == iPort ) ); - } - - QString toString ( const EStringMode eStringMode = SM_IP_PORT ) const - { - QString strReturn = InetAddr.toString(); - - // special case: for local host address, we do not replace the last byte - if ( ( ( eStringMode == SM_IP_NO_LAST_BYTE ) || - ( eStringMode == SM_IP_NO_LAST_BYTE_PORT ) ) && - ( InetAddr != QHostAddress ( QHostAddress::LocalHost ) ) ) - { - // replace last byte by an "x" - strReturn = strReturn.section ( ".", 0, 2 ) + ".x"; - } - - if ( ( eStringMode == SM_IP_PORT ) || - ( eStringMode == SM_IP_NO_LAST_BYTE_PORT ) ) - { - // add port number after a semicolon - strReturn += ":" + QString().setNum ( iPort ); - } - - return strReturn; - } - - QHostAddress InetAddr; - quint16 iPort; -}; - - -// Short info of a channel ----------------------------------------------------- -class CChannelShortInfo -{ -public: - CChannelShortInfo() : - iChanID ( 0 ), - iIpAddr ( 0 ), - strName ( "" ) {} - - CChannelShortInfo ( const int iNID, - const quint32 nIP, - const QString nN ) : - iChanID ( iNID ), - iIpAddr ( nIP ), - strName ( nN ) {} - - int iChanID; - quint32 iIpAddr; - QString strName; -}; - - -// Server info ----------------------------------------------------------------- -class CServerCoreInfo -{ -public: - CServerCoreInfo() : - iLocalPortNumber ( 0 ), - strName ( "" ), - strTopic ( "" ), - eCountry ( QLocale::AnyCountry ), - strCity ( "" ), - iMaxNumClients ( 0 ), - bPermanentOnline ( false ) {} - - CServerCoreInfo ( - const quint16 NLocPort, - const QString& NsName, - const QString& NsTopic, - const QLocale::Country& NeCountry, - const QString& NsCity, - const int NiMaxNumClients, - const bool NbPermOnline) : - iLocalPortNumber ( NLocPort ), - strName ( NsName ), - strTopic ( NsTopic ), - eCountry ( NeCountry ), - strCity ( NsCity ), - iMaxNumClients ( NiMaxNumClients ), - bPermanentOnline ( NbPermOnline ) {} - -public: - // local port number of the server - quint16 iLocalPortNumber; - - // name of the server - QString strName; - - // topic of the current jam session or server - QString strTopic; - - // country in which the server is located - QLocale::Country eCountry; - - // city in which the server is located - QString strCity; - - // maximum number of clients which can connect to the server at the same - // time - int iMaxNumClients; - - // is the server permanently online or not (flag) - bool bPermanentOnline; -}; - -class CServerInfo : public CServerCoreInfo -{ -public: - CServerInfo() : - CServerCoreInfo ( 0, - "", - "", - QLocale::AnyCountry, - "", - 0, - false ), HostAddr ( CHostAddress() ) {} - - CServerInfo ( - const CHostAddress& NHAddr, - const quint16 NLocPort, - const QString& NsName, - const QString& NsTopic, - const QLocale::Country& NeCountry, - const QString& NsCity, - const int NiMaxNumClients, - const bool NbPermOnline) : - CServerCoreInfo ( NLocPort, - NsName, - NsTopic, - NeCountry, - NsCity, - NiMaxNumClients, - NbPermOnline ), HostAddr ( NHAddr ) {} - -public: - // internet address of the server - CHostAddress HostAddr; -}; - - -// Audio compression type enum ------------------------------------------------- -enum EAudComprType -{ - CT_NONE = 0, - CT_CELT = 1 -}; - - -// Get data status enum -------------------------------------------------------- -enum EGetDataStat -{ - GS_BUFFER_OK, - GS_BUFFER_UNDERRUN, - GS_CHAN_NOW_DISCONNECTED, - GS_CHAN_NOT_CONNECTED -}; - - -// GUI design enum ------------------------------------------------------------- -enum EGUIDesign -{ - GD_STANDARD = 0, - GD_ORIGINAL = 1 -}; - - -// Network transport properties ------------------------------------------------ -class CNetworkTransportProps -{ -public: - CNetworkTransportProps() : - iBaseNetworkPacketSize ( 0 ), - iBlockSizeFact ( 0 ), - iNumAudioChannels ( 0 ), - iSampleRate ( 0 ), - eAudioCodingType ( CT_NONE ), - iAudioCodingArg ( 0 ) {} - - CNetworkTransportProps ( const uint32_t iNBNPS, - const uint16_t iNBSF, - const uint32_t iNNACH, - const uint32_t iNSR, - const EAudComprType eNACT, - const uint32_t iNVers, - const int32_t iNACA ) : - iBaseNetworkPacketSize ( iNBNPS ), - iBlockSizeFact ( iNBSF ), - iNumAudioChannels ( iNNACH ), - iSampleRate ( iNSR ), - eAudioCodingType ( eNACT ), - iVersion ( iNVers ), - iAudioCodingArg ( iNACA ) {} - - uint32_t iBaseNetworkPacketSize; - uint16_t iBlockSizeFact; - uint32_t iNumAudioChannels; - uint32_t iSampleRate; - EAudComprType eAudioCodingType; - uint32_t iVersion; - int32_t iAudioCodingArg; -}; - - -// Network utility functions --------------------------------------------------- -class LlconNetwUtil -{ -public: - static bool ParseNetworkAddress ( QString strAddress, - CHostAddress& HostAddress ); -}; - - -// Audio reverbration ---------------------------------------------------------- -class CAudioReverb -{ -public: - CAudioReverb() {} - - void Init ( const int iSampleRate, const double rT60 = (double) 5.0 ); - void Clear(); - double ProcessSample ( const double input ); - -protected: - void setT60 ( const double rT60, const int iSampleRate ); - bool isPrime ( const int number ); - - CFIFO allpassDelays_[3]; - CFIFO combDelays_[4]; - double allpassCoefficient_; - double combCoefficient_[4]; -}; - - -// CRC ------------------------------------------------------------------------- -class CCRC -{ -public: - CCRC() : iPoly ( ( 1 << 5 ) | ( 1 << 12 ) ), iBitOutMask ( 1 << 16 ) - { Reset(); } - - void Reset(); - void AddByte ( const uint8_t byNewInput ); - bool CheckCRC ( const uint32_t iCRC ) { return iCRC == GetCRC(); } - uint32_t GetCRC(); - -protected: - uint32_t iPoly; - uint32_t iBitOutMask; - uint32_t iStateShiftReg; -}; - - -// Mathematics utilities ------------------------------------------------------- -class LlconMath -{ -public: - static int round ( double x ) - { - return (int) ( ( x - floor ( x ) ) >= 0.5 ) ? ceil(x) : floor(x); - } -}; - - -// Precise time ---------------------------------------------------------------- -// required for ping measurement -class CPreciseTime -{ -public: -#ifdef _WIN32 - // for the Windows version we have to define a minimum timer precision - // -> set it to 1 ms - CPreciseTime() { timeBeginPeriod ( 1 ); } - virtual ~CPreciseTime() { timeEndPeriod ( 1 ); } -#endif - - // precise time (on Windows the QTime is not precise enough) - int elapsed() - { -#ifdef _WIN32 - return timeGetTime(); -#else - return QTime().elapsed(); -#endif - } -}; - - -/******************************************************************************\ -* Statistics * -\******************************************************************************/ -// Cycle time variance measurement --------------------------------------------- -// use for, e.g., measuring the variance of a timer -class CCycleTimeVariance -{ -public: - CCycleTimeVariance() : iBlockLengthAtSystemSampleRate ( 0 ), - dIntervalTime ( 0.0 ), iNewValueBoundFactor ( 0 ) {} - - void Init ( const int iNewBlockLengthAtSystemSampleRate, - const int iNewSystemSampleRateHz, - const int iHistoryLengthTimeSec, - const int iNewNewValueBoundFactor = MAX_NET_BUF_SIZE_NUM_BL ) - { - // store block size and new value bound factor - iBlockLengthAtSystemSampleRate = iNewBlockLengthAtSystemSampleRate; - iNewValueBoundFactor = iNewNewValueBoundFactor; - - // calculate interval time - dIntervalTime = static_cast ( - iBlockLengthAtSystemSampleRate ) * 1000 / iNewSystemSampleRateHz; - - // calculate actual moving average length and initialize buffer - RespTimeMoAvBuf.Init ( iHistoryLengthTimeSec * - iNewSystemSampleRateHz / iNewBlockLengthAtSystemSampleRate ); - } - - int GetBlockLength() { return iBlockLengthAtSystemSampleRate; } - - void Reset() - { - TimeLastBlock = PreciseTime.elapsed(); - RespTimeMoAvBuf.Reset(); - } - - double Update() - { - // add time difference - const int CurTime = PreciseTime.elapsed(); - - // we want to calculate the standard deviation (we assume that the mean - // is correct at the block period time) - const double dCurAddVal = - static_cast ( CurTime - TimeLastBlock ) - dIntervalTime; - -/* +/******************************************************************************\ + * Copyright (c) 2004-2011 + * + * Author(s): + * Volker Fischer + * + ****************************************************************************** + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free Software + * Foundation; either version 2 of the License, or (at your option) any later + * version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * +\******************************************************************************/ + +#if !defined ( UTIL_HOIH934256GEKJH98_3_43445KJIUHF1912__INCLUDED_ ) +#define UTIL_HOIH934256GEKJH98_3_43445KJIUHF1912__INCLUDED_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "global.h" +using namespace std; // because of the library: "vector" +#ifdef _WIN32 +# include "../windows/moc/aboutdlgbase.h" +# include +# include +#else +# ifdef _IS_QMAKE_CONFIG +# include "ui_aboutdlgbase.h" +# else +# include "moc/aboutdlgbase.h" +# endif +#endif + + +/* Definitions ****************************************************************/ +#define METER_FLY_BACK 2 + + +/* Global functions ***********************************************************/ +// converting double to short +inline short Double2Short ( const double dInput ) +{ + // lower bound + if ( dInput < _MINSHORT ) + { + return _MINSHORT; + } + + // upper bound + if ( dInput > _MAXSHORT ) + { + return _MAXSHORT; + } + + return (short) dInput; +} + +// debug error handling +void DebugError ( const QString& pchErDescr, + const QString& pchPar1Descr, + const double dPar1, + const QString& pchPar2Descr, + const double dPar2 ); + + +/******************************************************************************\ +* CVector Base Class * +\******************************************************************************/ +template class CVector : public std::vector +{ +public: + CVector() : iVectorSize ( 0 ) { pData = this->begin(); } + CVector ( const int iNeSi ) { Init(iNeSi); } + CVector ( const int iNeSi, const TData tInVa ) { Init ( iNeSi, tInVa ); } + + // Copy constructor: The order of the initialization list must not be + // changed. First, the base class must be initialized, then the pData + // pointer must be set to the new data source. The bit access is, by + // default, reset. + CVector ( const CVector& vecI ) : + std::vector ( static_cast&> ( vecI ) ), + iVectorSize ( vecI.Size() ) { pData = this->begin(); } + + void Init ( const int iNewSize ); + + // use this init to give all elements a defined value + void Init ( const int iNewSize, const TData tIniVal ); + void Reset ( const TData tResetVal ); + + void Enlarge ( const int iAddedSize ); + void Add ( const TData& tI ) { Enlarge ( 1 ); pData[iVectorSize - 1] = tI; } + + inline int Size() const { return iVectorSize; } + + // This operator allows for a l-value assignment of this object: + // CVector[x] = y is possible + inline TData& operator[] ( const int iPos ) { +#ifdef _DEBUG_ + if ( ( iPos < 0 ) || ( iPos > iVectorSize - 1 ) ) + { + DebugError ( "Writing vector out of bounds", "Vector size", + iVectorSize, "New parameter", iPos ); + } +#endif + return pData[iPos]; } + + inline TData operator[] ( const int iPos ) const { +#ifdef _DEBUG_ + if ( ( iPos < 0 ) || ( iPos > iVectorSize - 1 ) ) + { + DebugError ( "Reading vector out of bounds", "Vector size", + iVectorSize, "New parameter", iPos ); + } +#endif + return pData[iPos]; } + + inline CVector& operator= ( const CVector& vecI ) { +#ifdef _DEBUG_ + // Vectors which shall be copied MUST have same size! (If this is + // satisfied, the parameter "iVectorSize" must not be adjusted as + // a side effect) + if ( vecI.Size() != iVectorSize ) + { + DebugError ( "Vector operator=() different size", "Vector size", + iVectorSize, "New parameter", vecI.Size() ); + } +#endif + vector::operator= ( vecI ); + + // reset my data pointer in case, the operator=() of the base class + // did change the actual memory + pData = this->begin(); + + return *this; + } + +protected: + typename std::vector::iterator pData; + int iVectorSize; +}; + + +/* Implementation *************************************************************/ +template void CVector::Init ( const int iNewSize ) +{ + iVectorSize = iNewSize; + + // clear old buffer and reserve memory for new buffer, get iterator + // for pointer operations + this->clear(); + this->resize ( iNewSize ); + pData = this->begin(); +} + +template void CVector::Init ( const int iNewSize, + const TData tIniVal ) +{ + // call actual init routine + Init ( iNewSize ); + + // set values + Reset ( tIniVal ); +} + +template void CVector::Enlarge ( const int iAddedSize ) +{ + iVectorSize += iAddedSize; + this->resize ( iVectorSize ); + + // we have to reset the pointer since it could be that the vector size was + // zero before enlarging the vector + pData = this->begin(); +} + +template void CVector::Reset ( const TData tResetVal ) +{ + // set all values to reset value + for ( int i = 0; i < iVectorSize; i++ ) + { + pData[i] = tResetVal; + } +} + + +/******************************************************************************\ +* CFIFO Class (First In, First Out) * +\******************************************************************************/ +template class CFIFO : public CVector +{ +public: + CFIFO() : CVector(), iCurIdx ( 0 ) {} + CFIFO ( const int iNeSi ) : CVector(iNeSi), iCurIdx ( 0 ) {} + CFIFO ( const int iNeSi, const TData tInVa ) : + CVector ( iNeSi, tInVa ), iCurIdx ( 0 ) {} + + void Add ( const TData tNewD ); + inline TData Get() { return this->pData[iCurIdx]; } + + virtual void Init ( const int iNewSize ); + virtual void Init ( const int iNewSize, const TData tIniVal ); + +protected: + int iCurIdx; +}; + +template void CFIFO::Init ( const int iNewSize ) +{ + iCurIdx = 0; + CVector::Init ( iNewSize ); +} + +template void CFIFO::Init ( const int iNewSize, + const TData tIniVal ) +{ + iCurIdx = 0; + CVector::Init ( iNewSize, tIniVal ); +} + +template void CFIFO::Add ( const TData tNewD ) +{ + this->pData[iCurIdx] = tNewD; + + // increment index + iCurIdx++; + if ( iCurIdx >= this->iVectorSize ) + { + iCurIdx = 0; + } +} + + +/******************************************************************************\ +* CMovingAv Class (Moving Average) * +\******************************************************************************/ +template class CMovingAv : public CVector +{ +public: + CMovingAv() : + CVector(), + iCurIdx ( 0 ), + iNorm ( 0 ), + tCurAvResult ( TData ( 0 ) ), + tNoDataResult ( TData ( 0 ) ) {} + + void Add ( const TData tNewD ); + + void Init ( const int iNewSize, + const TData tNNoDRes = TData ( 0 ) ); + + void Reset(); + + inline TData GetAverage() + { + if ( this->iNorm == 0 ) + { + return tNoDataResult; + } + else + { + return tCurAvResult / this->iNorm; + } + } + + bool IsInitialized() { return ( this->iNorm == this->iVectorSize ); } + +protected: + int iCurIdx; + int iNorm; + TData tCurAvResult; + TData tNoDataResult; +}; + +template void CMovingAv::Init ( const int iNewSize, + const TData tNNoDRes ) +{ + iNorm = 0; + iCurIdx = 0; + tCurAvResult = TData ( 0 ); // only for scalars! + tNoDataResult = tNNoDRes; + CVector::Init ( iNewSize ); +} + +template void CMovingAv::Reset() +{ + iNorm = 0; + iCurIdx = 0; + tCurAvResult = TData ( 0 ); // only for scalars! + CVector::Reset ( TData ( 0 ) ); +} + +template void CMovingAv::Add ( const TData tNewD ) +{ +/* + Optimized calculation of the moving average. We only add a new value and + subtract the old value from the result. We only need one addition and a + history buffer. +*/ + // subtract oldest value + tCurAvResult -= this->pData[iCurIdx]; + + // add new value and write in memory + tCurAvResult += tNewD; + this->pData[iCurIdx] = tNewD; + + // increase position pointer and test if wrap + iCurIdx++; + if ( iCurIdx >= this->iVectorSize ) + { + iCurIdx = 0; + } + + // take care of norm + if ( this->iNorm < this->iVectorSize ) + { + this->iNorm++; + } +} + + +/******************************************************************************\ +* GUI Utilities * +\******************************************************************************/ +// About dialog ---------------------------------------------------------------- +class CAboutDlg : public QDialog, private Ui_CAboutDlgBase +{ + Q_OBJECT + +public: + CAboutDlg ( QWidget* parent = 0 ); + + static QString GetVersionAndNameStr ( const bool bWithHtml = true ); +}; + + +// Help menu ------------------------------------------------------------------- +class CLlconHelpMenu : public QMenu +{ + Q_OBJECT + +public: + CLlconHelpMenu ( QWidget* parent = 0 ); + +protected: + CAboutDlg AboutDlg; + +public slots: + void OnHelpWhatsThis() { QWhatsThis::enterWhatsThisMode(); } + void OnHelpAbout() { AboutDlg.exec(); } + void OnHelpDownloadLink() + { QDesktopServices::openUrl ( QUrl ( LLCON_DOWNLOAD_URL ) ); } +}; + + +/******************************************************************************\ +* Other Classes * +\******************************************************************************/ +// Stereo signal level meter --------------------------------------------------- +class CStereoSignalLevelMeter +{ +public: + CStereoSignalLevelMeter() { Reset(); } + + void Update ( CVector& vecsAudio ); + double MicLevelLeft() { return CalcLogResult ( dCurLevelL ); } + double MicLevelRight() { return CalcLogResult ( dCurLevelR ); } + void Reset() { dCurLevelL = 0.0; dCurLevelR = 0.0; } + +protected: + double CalcLogResult ( const double& dLinearLevel ); + double UpdateCurLevel ( double dCurLevel, const short& sMax ); + + double dCurLevelL; + double dCurLevelR; +}; + + +// Host address ---------------------------------------------------------------- +class CHostAddress +{ +public: + enum EStringMode + { + SM_IP_PORT, + SM_IP_NO_LAST_BYTE, + SM_IP_NO_LAST_BYTE_PORT + }; + + CHostAddress() : + InetAddr ( static_cast ( 0 ) ), + iPort ( 0 ) {} + + CHostAddress ( const QHostAddress NInetAddr, + const quint16 iNPort ) : + InetAddr ( NInetAddr ), + iPort ( iNPort ) {} + + CHostAddress ( const CHostAddress& NHAddr ) : + InetAddr ( NHAddr.InetAddr ), + iPort ( NHAddr.iPort ) {} + + // copy operator + CHostAddress& operator= ( const CHostAddress& NHAddr ) + { + InetAddr = NHAddr.InetAddr; + iPort = NHAddr.iPort; + return *this; + } + + // compare operator + bool operator== ( const CHostAddress& CompAddr ) // compare operator + { + return ( ( CompAddr.InetAddr == InetAddr ) && + ( CompAddr.iPort == iPort ) ); + } + + QString toString ( const EStringMode eStringMode = SM_IP_PORT ) const + { + QString strReturn = InetAddr.toString(); + + // special case: for local host address, we do not replace the last byte + if ( ( ( eStringMode == SM_IP_NO_LAST_BYTE ) || + ( eStringMode == SM_IP_NO_LAST_BYTE_PORT ) ) && + ( InetAddr != QHostAddress ( QHostAddress::LocalHost ) ) ) + { + // replace last byte by an "x" + strReturn = strReturn.section ( ".", 0, 2 ) + ".x"; + } + + if ( ( eStringMode == SM_IP_PORT ) || + ( eStringMode == SM_IP_NO_LAST_BYTE_PORT ) ) + { + // add port number after a semicolon + strReturn += ":" + QString().setNum ( iPort ); + } + + return strReturn; + } + + QHostAddress InetAddr; + quint16 iPort; +}; + + +// Short info of a channel ----------------------------------------------------- +class CChannelShortInfo +{ +public: + CChannelShortInfo() : + iChanID ( 0 ), + iIpAddr ( 0 ), + strName ( "" ) {} + + CChannelShortInfo ( const int iNID, + const quint32 nIP, + const QString nN ) : + iChanID ( iNID ), + iIpAddr ( nIP ), + strName ( nN ) {} + + int iChanID; + quint32 iIpAddr; + QString strName; +}; + + +// Server info ----------------------------------------------------------------- +class CServerCoreInfo +{ +public: + CServerCoreInfo() : + iLocalPortNumber ( 0 ), + strName ( "" ), + strTopic ( "" ), + eCountry ( QLocale::AnyCountry ), + strCity ( "" ), + iMaxNumClients ( 0 ), + bPermanentOnline ( false ) {} + + CServerCoreInfo ( + const quint16 NLocPort, + const QString& NsName, + const QString& NsTopic, + const QLocale::Country& NeCountry, + const QString& NsCity, + const int NiMaxNumClients, + const bool NbPermOnline) : + iLocalPortNumber ( NLocPort ), + strName ( NsName ), + strTopic ( NsTopic ), + eCountry ( NeCountry ), + strCity ( NsCity ), + iMaxNumClients ( NiMaxNumClients ), + bPermanentOnline ( NbPermOnline ) {} + +public: + // local port number of the server + quint16 iLocalPortNumber; + + // name of the server + QString strName; + + // topic of the current jam session or server + QString strTopic; + + // country in which the server is located + QLocale::Country eCountry; + + // city in which the server is located + QString strCity; + + // maximum number of clients which can connect to the server at the same + // time + int iMaxNumClients; + + // is the server permanently online or not (flag) + bool bPermanentOnline; +}; + +class CServerInfo : public CServerCoreInfo +{ +public: + CServerInfo() : + CServerCoreInfo ( 0, + "", + "", + QLocale::AnyCountry, + "", + 0, + false ), HostAddr ( CHostAddress() ) {} + + CServerInfo ( + const CHostAddress& NHAddr, + const quint16 NLocPort, + const QString& NsName, + const QString& NsTopic, + const QLocale::Country& NeCountry, + const QString& NsCity, + const int NiMaxNumClients, + const bool NbPermOnline) : + CServerCoreInfo ( NLocPort, + NsName, + NsTopic, + NeCountry, + NsCity, + NiMaxNumClients, + NbPermOnline ), HostAddr ( NHAddr ) {} + +public: + // internet address of the server + CHostAddress HostAddr; +}; + + +// Audio compression type enum ------------------------------------------------- +enum EAudComprType +{ + CT_NONE = 0, + CT_CELT = 1 +}; + + +// Get data status enum -------------------------------------------------------- +enum EGetDataStat +{ + GS_BUFFER_OK, + GS_BUFFER_UNDERRUN, + GS_CHAN_NOW_DISCONNECTED, + GS_CHAN_NOT_CONNECTED +}; + + +// GUI design enum ------------------------------------------------------------- +enum EGUIDesign +{ + GD_STANDARD = 0, + GD_ORIGINAL = 1 +}; + + +// Network transport properties ------------------------------------------------ +class CNetworkTransportProps +{ +public: + CNetworkTransportProps() : + iBaseNetworkPacketSize ( 0 ), + iBlockSizeFact ( 0 ), + iNumAudioChannels ( 0 ), + iSampleRate ( 0 ), + eAudioCodingType ( CT_NONE ), + iAudioCodingArg ( 0 ) {} + + CNetworkTransportProps ( const uint32_t iNBNPS, + const uint16_t iNBSF, + const uint32_t iNNACH, + const uint32_t iNSR, + const EAudComprType eNACT, + const uint32_t iNVers, + const int32_t iNACA ) : + iBaseNetworkPacketSize ( iNBNPS ), + iBlockSizeFact ( iNBSF ), + iNumAudioChannels ( iNNACH ), + iSampleRate ( iNSR ), + eAudioCodingType ( eNACT ), + iVersion ( iNVers ), + iAudioCodingArg ( iNACA ) {} + + uint32_t iBaseNetworkPacketSize; + uint16_t iBlockSizeFact; + uint32_t iNumAudioChannels; + uint32_t iSampleRate; + EAudComprType eAudioCodingType; + uint32_t iVersion; + int32_t iAudioCodingArg; +}; + + +// Network utility functions --------------------------------------------------- +class LlconNetwUtil +{ +public: + static bool ParseNetworkAddress ( QString strAddress, + CHostAddress& HostAddress ); +}; + + +// Audio reverbration ---------------------------------------------------------- +class CAudioReverb +{ +public: + CAudioReverb() {} + + void Init ( const int iSampleRate, const double rT60 = (double) 5.0 ); + void Clear(); + double ProcessSample ( const double input ); + +protected: + void setT60 ( const double rT60, const int iSampleRate ); + bool isPrime ( const int number ); + + CFIFO allpassDelays_[3]; + CFIFO combDelays_[4]; + double allpassCoefficient_; + double combCoefficient_[4]; +}; + + +// CRC ------------------------------------------------------------------------- +class CCRC +{ +public: + CCRC() : iPoly ( ( 1 << 5 ) | ( 1 << 12 ) ), iBitOutMask ( 1 << 16 ) + { Reset(); } + + void Reset(); + void AddByte ( const uint8_t byNewInput ); + bool CheckCRC ( const uint32_t iCRC ) { return iCRC == GetCRC(); } + uint32_t GetCRC(); + +protected: + uint32_t iPoly; + uint32_t iBitOutMask; + uint32_t iStateShiftReg; +}; + + +// Mathematics utilities ------------------------------------------------------- +class LlconMath +{ +public: + static int round ( double x ) + { + return (int) ( ( x - floor ( x ) ) >= 0.5 ) ? ceil(x) : floor(x); + } +}; + + +// Precise time ---------------------------------------------------------------- +// required for ping measurement +class CPreciseTime +{ +public: +#ifdef _WIN32 + // for the Windows version we have to define a minimum timer precision + // -> set it to 1 ms + CPreciseTime() { timeBeginPeriod ( 1 ); } + virtual ~CPreciseTime() { timeEndPeriod ( 1 ); } +#endif + + // precise time (on Windows the QTime is not precise enough) + int elapsed() + { +#ifdef _WIN32 + return timeGetTime(); +#else + return QTime().elapsed(); +#endif + } +}; + + +/******************************************************************************\ +* Statistics * +\******************************************************************************/ +// Cycle time variance measurement --------------------------------------------- +// use for, e.g., measuring the variance of a timer +class CCycleTimeVariance +{ +public: + CCycleTimeVariance() : iBlockLengthAtSystemSampleRate ( 0 ), + dIntervalTime ( 0.0 ), iNewValueBoundFactor ( 0 ) {} + + void Init ( const int iNewBlockLengthAtSystemSampleRate, + const int iNewSystemSampleRateHz, + const int iHistoryLengthTimeSec, + const int iNewNewValueBoundFactor = MAX_NET_BUF_SIZE_NUM_BL ) + { + // store block size and new value bound factor + iBlockLengthAtSystemSampleRate = iNewBlockLengthAtSystemSampleRate; + iNewValueBoundFactor = iNewNewValueBoundFactor; + + // calculate interval time + dIntervalTime = static_cast ( + iBlockLengthAtSystemSampleRate ) * 1000 / iNewSystemSampleRateHz; + + // calculate actual moving average length and initialize buffer + RespTimeMoAvBuf.Init ( iHistoryLengthTimeSec * + iNewSystemSampleRateHz / iNewBlockLengthAtSystemSampleRate ); + } + + int GetBlockLength() { return iBlockLengthAtSystemSampleRate; } + + void Reset() + { + TimeLastBlock = PreciseTime.elapsed(); + RespTimeMoAvBuf.Reset(); + } + + double Update() + { + // add time difference + const int CurTime = PreciseTime.elapsed(); + + // we want to calculate the standard deviation (we assume that the mean + // is correct at the block period time) + const double dCurAddVal = + static_cast ( CurTime - TimeLastBlock ) - dIntervalTime; + +/* // TEST static FILE* pFile = fopen ( "c:\\temp\\test.dat", "w" ); fprintf ( pFile, "%e %e\n", dCurAddVal, iNewValueBoundFactor * dIntervalTime ); fflush ( pFile ); // close;x=read('c:/temp/test.dat',-1,2);plot(x) -*/ - - if ( iNewValueBoundFactor > 0 ) - { - // check if new value is in range - if ( fabs ( dCurAddVal ) < ( iNewValueBoundFactor * dIntervalTime ) ) - { - // add squared value - RespTimeMoAvBuf.Add ( dCurAddVal * dCurAddVal ); - } - } - else - { - // new value bound is not used, add new value (add squared value) - RespTimeMoAvBuf.Add ( dCurAddVal * dCurAddVal ); - } - - // store old time value - TimeLastBlock = CurTime; - - return dCurAddVal; - } - - // return the standard deviation, for that we need to calculate - // the sqaure root - double GetStdDev() { return sqrt ( RespTimeMoAvBuf.GetAverage() ); } - - bool IsInitialized() { return RespTimeMoAvBuf.IsInitialized(); } - -protected: - CPreciseTime PreciseTime; - CMovingAv RespTimeMoAvBuf; - int TimeLastBlock; - int iBlockLengthAtSystemSampleRate; - double dIntervalTime; - int iNewValueBoundFactor; -}; - -#endif /* !defined ( UTIL_HOIH934256GEKJH98_3_43445KJIUHF1912__INCLUDED_ ) */ +*/ + + // check if new value is in range (lower and upper bound) + if ( ( fabs ( dCurAddVal ) <= ( iNewValueBoundFactor * dIntervalTime ) ) )// && +// ( fabs ( dCurAddVal ) >= dIntervalTime ) ) + { + // add squared value + RespTimeMoAvBuf.Add ( dCurAddVal * dCurAddVal ); + } + + // store old time value + TimeLastBlock = CurTime; + + return dCurAddVal; + } + + // return the standard deviation, for that we need to calculate + // the sqaure root + double GetStdDev() { return sqrt ( RespTimeMoAvBuf.GetAverage() ); } + + bool IsInitialized() { return RespTimeMoAvBuf.IsInitialized(); } + +protected: + CPreciseTime PreciseTime; + CMovingAv RespTimeMoAvBuf; + int TimeLastBlock; + int iBlockLengthAtSystemSampleRate; + double dIntervalTime; + int iNewValueBoundFactor; +}; + + +// Error rate measurement ------------------------------------------------------ +class CErrorRate +{ +public: + CErrorRate() {} + + void Init ( const int iHistoryLength, + const bool bNBlockOnDoubleErr = false ) + { + // initialize buffer (use "no data result" of 1.0 which stands for the + // worst error rate possible) + ErrorsMovAvBuf.Init ( iHistoryLength, 1.0f ); + + bPreviousState = true; + + // store setting + bBlockOnDoubleErrors = bNBlockOnDoubleErr; + } + + void Reset() + { + ErrorsMovAvBuf.Reset(); + bPreviousState = true; + } + + void Update ( const bool bState ) + { + // if two states were false, do not use the new value + if ( bBlockOnDoubleErrors && bPreviousState && bState ) + { + return; + } + + // add errors as values 0 and 1 to get correct error rate average + if ( bState ) + { + ErrorsMovAvBuf.Add ( 1.0f ); + } + else + { + ErrorsMovAvBuf.Add ( 0.0f ); + + } + + // store state + bPreviousState = bState; + } + + double GetAverage() { return ErrorsMovAvBuf.GetAverage(); } + +protected: + CMovingAv ErrorsMovAvBuf; + bool bBlockOnDoubleErrors; + bool bPreviousState; +}; + +#endif /* !defined ( UTIL_HOIH934256GEKJH98_3_43445KJIUHF1912__INCLUDED_ ) */