/******************************************************************************\ * 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 "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: 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 GetIpAddressStringNoLastByte() const { // remove the last byte of the IP address return InetAddr.toString().section ( ".", 0, 2 ) + ".x"; } 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() : strName ( "" ), strTopic ( "" ), eCountry ( QLocale::AnyCountry ), strCity ( "" ), iNumClients ( 0 ), iMaxNumClients ( 0 ), bPermanentOnline ( false ) {} CServerCoreInfo ( const QString& NsName, const QString& NsTopic, const QLocale::Country& NeCountry, const QString& NsCity, const int NiNumClients, const int NiMaxNumClients, const bool NbPermOnline) : strName ( NsName ), strTopic ( NsTopic ), eCountry ( NeCountry ), strCity ( NsCity ), iNumClients ( NiNumClients ), iMaxNumClients ( NiMaxNumClients ), bPermanentOnline ( NbPermOnline ) {} public: // 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; // current number of connected clients int iNumClients; // 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 ( "", "", QLocale::AnyCountry, "", 0, 0, false ), InetAddr ( CHostAddress() ) {} CServerInfo ( const CHostAddress& NIAddr, const QString& NsName, const QString& NsTopic, const QLocale::Country& NeCountry, const QString& NsCity, const int NiNumClients, const int NiMaxNumClients, const bool NbPermOnline) : CServerCoreInfo ( NsName, NsTopic, NeCountry, NsCity, NiNumClients, NiMaxNumClients, NbPermOnline ), InetAddr ( NIAddr ) {} public: // internet address of the server CHostAddress InetAddr; }; // 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; }; // 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 = 4 ) { // 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; 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; }; // Error rate measurement ------------------------------------------------------ class CErrorRate { public: CErrorRate() {} void Init ( const int iHistoryLength ) { // initialize buffer ErrorsMovAvBuf.Init ( iHistoryLength ); } void Reset() { ErrorsMovAvBuf.Reset(); } void Update ( const bool bState ) { // add errors as values 0 and 1 to get correct error rate average if ( bState ) { ErrorsMovAvBuf.Add ( 1.0 ); } else { ErrorsMovAvBuf.Add ( 0.0 ); } } // return the standard deviation, for that we need to calculate // the sqaure root double GetAverage() { return ErrorsMovAvBuf.GetAverage(); } protected: CMovingAv ErrorsMovAvBuf; }; #endif /* !defined ( UTIL_HOIH934256GEKJH98_3_43445KJIUHF1912__INCLUDED_ ) */