use signal level meter class for meter calculation in the server (avoid doubling code), i.e., max calc and smoothing
This commit is contained in:
parent
938112d65d
commit
70cfdfc94c
8 changed files with 114 additions and 101 deletions
|
@ -31,12 +31,10 @@
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
TODO use signal level meter class for meter calculation in the server (avoid doubling code), i.e., max calc and smoothing
|
TODO add new register message which contains version and, e.g., max number of clients
|
||||||
|
|
||||||
TODO the new translation loading does not work on MacOS
|
TODO the new translation loading does not work on MacOS
|
||||||
|
|
||||||
TODO add new register message which contains version and, e.g., max number of clients
|
|
||||||
|
|
||||||
TODO https://github.com/corrados/jamulus/issues/341#issuecomment-647172946
|
TODO https://github.com/corrados/jamulus/issues/341#issuecomment-647172946
|
||||||
- generate .qm on compile time with lrelease
|
- generate .qm on compile time with lrelease
|
||||||
- download nsProcess.dll on Windows installer creation instead of put it in the repo
|
- download nsProcess.dll on Windows installer creation instead of put it in the repo
|
||||||
|
|
|
@ -35,7 +35,8 @@ CChannel::CChannel ( const bool bNIsServer ) :
|
||||||
iFadeInCntMax ( FADE_IN_NUM_FRAMES_DBLE_FRAMESIZE ),
|
iFadeInCntMax ( FADE_IN_NUM_FRAMES_DBLE_FRAMESIZE ),
|
||||||
bIsEnabled ( false ),
|
bIsEnabled ( false ),
|
||||||
bIsServer ( bNIsServer ),
|
bIsServer ( bNIsServer ),
|
||||||
iAudioFrameSizeSamples ( DOUBLE_SYSTEM_FRAME_SIZE_SAMPLES )
|
iAudioFrameSizeSamples ( DOUBLE_SYSTEM_FRAME_SIZE_SAMPLES ),
|
||||||
|
SignalLevelMeter ( false, 0.5 ) // server mode with mono out and faster smoothing
|
||||||
{
|
{
|
||||||
// reset network transport properties
|
// reset network transport properties
|
||||||
ResetNetworkTransportProperties();
|
ResetNetworkTransportProperties();
|
||||||
|
@ -568,6 +569,9 @@ EPutDataStat CChannel::PutAudioData ( const CVector<uint8_t>& vecbyData,
|
||||||
|
|
||||||
// init audio fade-in counter
|
// init audio fade-in counter
|
||||||
iFadeInCnt = 0;
|
iFadeInCnt = 0;
|
||||||
|
|
||||||
|
// init level meter
|
||||||
|
SignalLevelMeter.Reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
// reset time-out counter (note that this must be done after the
|
// reset time-out counter (note that this must be done after the
|
||||||
|
@ -658,6 +662,18 @@ void CChannel::PrepAndSendPacket ( CHighPrioSocket* pSocket,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
double CChannel::UpdateAndGetLevelForMeterdB ( const CVector<short>& vecsAudio,
|
||||||
|
const int iInSize,
|
||||||
|
const bool bIsStereoIn )
|
||||||
|
{
|
||||||
|
// update the signal level meter and immediately return the current value
|
||||||
|
SignalLevelMeter.Update ( vecsAudio,
|
||||||
|
iInSize,
|
||||||
|
bIsStereoIn );
|
||||||
|
|
||||||
|
return SignalLevelMeter.GetLevelForMeterdBLeftOrMono();
|
||||||
|
}
|
||||||
|
|
||||||
int CChannel::GetUploadRateKbps()
|
int CChannel::GetUploadRateKbps()
|
||||||
{
|
{
|
||||||
const int iAudioSizeOut = iNetwFrameSizeFact * iAudioFrameSizeSamples;
|
const int iAudioSizeOut = iNetwFrameSizeFact * iAudioFrameSizeSamples;
|
||||||
|
|
|
@ -175,8 +175,9 @@ public:
|
||||||
|
|
||||||
bool ChannelLevelsRequired() const { return bChannelLevelsRequired; }
|
bool ChannelLevelsRequired() const { return bChannelLevelsRequired; }
|
||||||
|
|
||||||
double GetPrevLevel() const { return dPrevLevel; }
|
double UpdateAndGetLevelForMeterdB ( const CVector<short>& vecsAudio,
|
||||||
void SetPrevLevel ( const double nPL ) { dPrevLevel = nPL; }
|
const int iInSize,
|
||||||
|
const bool bIsStereoIn );
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
bool ProtocolIsEnabled();
|
bool ProtocolIsEnabled();
|
||||||
|
@ -190,8 +191,6 @@ protected:
|
||||||
iNetwFrameSizeFact = FRAME_SIZE_FACTOR_PREFERRED;
|
iNetwFrameSizeFact = FRAME_SIZE_FACTOR_PREFERRED;
|
||||||
iNetwFrameSize = CELT_MINIMUM_NUM_BYTES;
|
iNetwFrameSize = CELT_MINIMUM_NUM_BYTES;
|
||||||
iNumAudioChannels = 1; // mono
|
iNumAudioChannels = 1; // mono
|
||||||
|
|
||||||
dPrevLevel = 0.0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// connection parameters
|
// connection parameters
|
||||||
|
@ -235,7 +234,8 @@ protected:
|
||||||
QMutex MutexConvBuf;
|
QMutex MutexConvBuf;
|
||||||
|
|
||||||
bool bChannelLevelsRequired;
|
bool bChannelLevelsRequired;
|
||||||
double dPrevLevel;
|
|
||||||
|
CStereoSignalLevelMeter SignalLevelMeter;
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void OnSendProtMessage ( CVector<uint8_t> vecMessage );
|
void OnSendProtMessage ( CVector<uint8_t> vecMessage );
|
||||||
|
|
|
@ -989,7 +989,9 @@ void CClient::ProcessAudioDataIntern ( CVector<int16_t>& vecsStereoSndCrd )
|
||||||
|
|
||||||
// Transmit signal ---------------------------------------------------------
|
// Transmit signal ---------------------------------------------------------
|
||||||
// update stereo signal level meter
|
// update stereo signal level meter
|
||||||
SignalLevelMeter.Update ( vecsStereoSndCrd );
|
SignalLevelMeter.Update ( vecsStereoSndCrd,
|
||||||
|
iMonoBlockSizeSam,
|
||||||
|
true );
|
||||||
|
|
||||||
// add reverberation effect if activated
|
// add reverberation effect if activated
|
||||||
if ( iReverbLevel != 0 )
|
if ( iReverbLevel != 0 )
|
||||||
|
|
|
@ -117,7 +117,7 @@ public:
|
||||||
bool IsRunning() { return Sound.IsRunning(); }
|
bool IsRunning() { return Sound.IsRunning(); }
|
||||||
bool SetServerAddr ( QString strNAddr );
|
bool SetServerAddr ( QString strNAddr );
|
||||||
|
|
||||||
double GetLevelForMeterdBLeft() { return SignalLevelMeter.GetLevelForMeterdBLeft(); }
|
double GetLevelForMeterdBLeft() { return SignalLevelMeter.GetLevelForMeterdBLeftOrMono(); }
|
||||||
double GetLevelForMeterdBRight() { return SignalLevelMeter.GetLevelForMeterdBRight(); }
|
double GetLevelForMeterdBRight() { return SignalLevelMeter.GetLevelForMeterdBRight(); }
|
||||||
|
|
||||||
bool GetAndResetbJitterBufferOKFlag();
|
bool GetAndResetbJitterBufferOKFlag();
|
||||||
|
|
|
@ -1663,7 +1663,6 @@ bool CServer::CreateLevelsForAllConChannels ( const int i
|
||||||
const CVector<CVector<int16_t> > vecvecsData,
|
const CVector<CVector<int16_t> > vecvecsData,
|
||||||
CVector<uint16_t>& vecLevelsOut )
|
CVector<uint16_t>& vecLevelsOut )
|
||||||
{
|
{
|
||||||
int i, j, k;
|
|
||||||
bool bLevelsWereUpdated = false;
|
bool bLevelsWereUpdated = false;
|
||||||
|
|
||||||
// low frequency updates
|
// low frequency updates
|
||||||
|
@ -1675,44 +1674,15 @@ bool CServer::CreateLevelsForAllConChannels ( const int i
|
||||||
// init return vector with zeros since we mix all channels on that vector
|
// init return vector with zeros since we mix all channels on that vector
|
||||||
vecLevelsOut.Reset ( 0 );
|
vecLevelsOut.Reset ( 0 );
|
||||||
|
|
||||||
for ( j = 0; j < iNumClients; j++ )
|
for ( int j = 0; j < iNumClients; j++ )
|
||||||
{
|
{
|
||||||
// get a reference to the audio data
|
// update and get signal level for meter in dB for each channel
|
||||||
const CVector<int16_t>& vecsData = vecvecsData[j];
|
const double dCurSigLevelForMeterdB = vecChannels[vecChanIDsCurConChan[j]].
|
||||||
|
UpdateAndGetLevelForMeterdB ( vecvecsData[j],
|
||||||
// Speed optimization:
|
iServerFrameSizeSamples,
|
||||||
// - we only make use of the negative values and ignore the positive ones (since
|
vecNumAudioChannels[j] > 1 );
|
||||||
// int16 has range {-32768, 32767}) -> we do not need to call the fabs() function
|
|
||||||
// - we only evaluate every third sample
|
|
||||||
int16_t sMax = 0;
|
|
||||||
|
|
||||||
if ( vecNumAudioChannels[j] == 1 )
|
|
||||||
{
|
|
||||||
// mono
|
|
||||||
for ( i = 0; i < iServerFrameSizeSamples; i += 3 )
|
|
||||||
{
|
|
||||||
sMax = std::min ( sMax, vecsData[i] );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// stereo
|
|
||||||
for ( i = 0, k = 0; i < iServerFrameSizeSamples; i += 3, k += 6 ) // 2 * 3 = 6 -> stereo
|
|
||||||
{
|
|
||||||
// left/right channels separately
|
|
||||||
sMax = std::min ( sMax, vecsData[k] );
|
|
||||||
sMax = std::min ( sMax, vecsData[k + 1] );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// smoothing
|
|
||||||
const int iChId = vecChanIDsCurConChan[j];
|
|
||||||
const double dCurLevel = std::max ( -static_cast<double> ( sMax ), vecChannels[iChId].GetPrevLevel() * 0.5 );
|
|
||||||
vecChannels[iChId].SetPrevLevel ( dCurLevel );
|
|
||||||
|
|
||||||
// logarithmic measure
|
|
||||||
double dCurSigLevelForMeterdB = CStereoSignalLevelMeter::CalcLogResultForMeter ( dCurLevel );
|
|
||||||
|
|
||||||
|
// map value to integer for transmission via the protocol (4 bit available)
|
||||||
vecLevelsOut[j] = static_cast<uint16_t> ( ceil ( dCurSigLevelForMeterdB ) );
|
vecLevelsOut[j] = static_cast<uint16_t> ( ceil ( dCurSigLevelForMeterdB ) );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
55
src/util.cpp
55
src/util.cpp
|
@ -28,11 +28,10 @@
|
||||||
|
|
||||||
/* Implementation *************************************************************/
|
/* Implementation *************************************************************/
|
||||||
// Input level meter implementation --------------------------------------------
|
// Input level meter implementation --------------------------------------------
|
||||||
void CStereoSignalLevelMeter::Update ( const CVector<short>& vecsAudio )
|
void CStereoSignalLevelMeter::Update ( const CVector<short>& vecsAudio,
|
||||||
|
const int iMonoBlockSizeSam,
|
||||||
|
const bool bIsStereoIn )
|
||||||
{
|
{
|
||||||
// get the stereo vector size
|
|
||||||
const int iStereoVecSize = vecsAudio.Size();
|
|
||||||
|
|
||||||
// Get maximum of current block
|
// Get maximum of current block
|
||||||
//
|
//
|
||||||
// Speed optimization:
|
// Speed optimization:
|
||||||
|
@ -43,32 +42,50 @@ void CStereoSignalLevelMeter::Update ( const CVector<short>& vecsAudio )
|
||||||
// With these speed optimizations we might loose some information in
|
// With these speed optimizations we might loose some information in
|
||||||
// special cases but for the average music signals the following code
|
// special cases but for the average music signals the following code
|
||||||
// should give good results.
|
// should give good results.
|
||||||
short sMaxL = 0;
|
short sMinLOrMono = 0;
|
||||||
short sMaxR = 0;
|
short sMinR = 0;
|
||||||
|
|
||||||
for ( int i = 0; i < iStereoVecSize; i += 6 ) // 2 * 3 = 6 -> stereo
|
if ( bIsStereoIn )
|
||||||
{
|
{
|
||||||
// left channel
|
// stereo in
|
||||||
sMaxL = std::min ( sMaxL, vecsAudio[i] );
|
for ( int i = 0; i < 2 * iMonoBlockSizeSam; i += 6 ) // 2 * 3 = 6 -> stereo
|
||||||
|
{
|
||||||
// right channel
|
// left (or mono) and right channel
|
||||||
sMaxR = std::min ( sMaxR, vecsAudio[i + 1] );
|
sMinLOrMono = std::min ( sMinLOrMono, vecsAudio[i] );
|
||||||
|
sMinR = std::min ( sMinR, vecsAudio[i + 1] );
|
||||||
}
|
}
|
||||||
|
|
||||||
dCurLevelL = UpdateCurLevel ( dCurLevelL, -sMaxL );
|
// in case of mono out use minimum of both channels
|
||||||
dCurLevelR = UpdateCurLevel ( dCurLevelR, -sMaxR );
|
if ( !bIsStereoOut )
|
||||||
|
{
|
||||||
|
sMinLOrMono = std::min ( sMinLOrMono, sMinR );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// mono in
|
||||||
|
for ( int i = 0; i < iMonoBlockSizeSam; i += 3 )
|
||||||
|
{
|
||||||
|
sMinLOrMono = std::min ( sMinLOrMono, vecsAudio[i] );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// apply smoothing, if in stereo out mode, do this for two channels
|
||||||
|
dCurLevelLOrMono = UpdateCurLevel ( dCurLevelLOrMono, -sMinLOrMono );
|
||||||
|
|
||||||
|
if ( bIsStereoOut )
|
||||||
|
{
|
||||||
|
dCurLevelR = UpdateCurLevel ( dCurLevelR, -sMinR );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
double CStereoSignalLevelMeter::UpdateCurLevel ( double dCurLevel,
|
double CStereoSignalLevelMeter::UpdateCurLevel ( double dCurLevel,
|
||||||
double dMax )
|
const double dMax )
|
||||||
{
|
{
|
||||||
// decrease max with time
|
// decrease max with time
|
||||||
if ( dCurLevel >= METER_FLY_BACK )
|
if ( dCurLevel >= METER_FLY_BACK )
|
||||||
{
|
{
|
||||||
// TODO Calculate factor from sample rate and frame size (64 or 128 samples frame size).
|
dCurLevel *= dSmoothingFactor;
|
||||||
// But tests with 128 and 64 samples frame size have shown that the meter fly back
|
|
||||||
// is ok for both numbers of samples frame size.
|
|
||||||
dCurLevel *= 0.97;
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
22
src/util.h
22
src/util.h
|
@ -712,25 +712,35 @@ enum ESkillLevel
|
||||||
class CStereoSignalLevelMeter
|
class CStereoSignalLevelMeter
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
CStereoSignalLevelMeter() { Reset(); }
|
// TODO Calculate smoothing factor from sample rate and frame size (64 or 128 samples frame size).
|
||||||
|
// But tests with 128 and 64 samples frame size have shown that the meter fly back
|
||||||
|
// is ok for both numbers of samples frame size with a factor of 0.97.
|
||||||
|
CStereoSignalLevelMeter ( const bool bNIsStereoOut = true,
|
||||||
|
const double dNSmoothingFactor = 0.97 ) :
|
||||||
|
dSmoothingFactor ( dNSmoothingFactor ), bIsStereoOut ( bNIsStereoOut ) { Reset(); }
|
||||||
|
|
||||||
void Update ( const CVector<short>& vecsAudio );
|
void Update ( const CVector<short>& vecsAudio,
|
||||||
double GetLevelForMeterdBLeft() { return CalcLogResultForMeter ( dCurLevelL ); }
|
const int iInSize,
|
||||||
|
const bool bIsStereoIn );
|
||||||
|
|
||||||
|
double GetLevelForMeterdBLeftOrMono() { return CalcLogResultForMeter ( dCurLevelLOrMono ); }
|
||||||
double GetLevelForMeterdBRight() { return CalcLogResultForMeter ( dCurLevelR ); }
|
double GetLevelForMeterdBRight() { return CalcLogResultForMeter ( dCurLevelR ); }
|
||||||
static double CalcLogResultForMeter ( const double& dLinearLevel );
|
static double CalcLogResultForMeter ( const double& dLinearLevel );
|
||||||
|
|
||||||
void Reset()
|
void Reset()
|
||||||
{
|
{
|
||||||
dCurLevelL = 0.0;
|
dCurLevelLOrMono = 0.0;
|
||||||
dCurLevelR = 0.0;
|
dCurLevelR = 0.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
double UpdateCurLevel ( double dCurLevel,
|
double UpdateCurLevel ( double dCurLevel,
|
||||||
double dMax );
|
const double dMax );
|
||||||
|
|
||||||
double dCurLevelL;
|
double dCurLevelLOrMono;
|
||||||
double dCurLevelR;
|
double dCurLevelR;
|
||||||
|
double dSmoothingFactor;
|
||||||
|
bool bIsStereoOut;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue