Merge pull request #42 from pljones/feature/channel-meters

Feature/channel meters
This commit is contained in:
corrados 2020-04-06 20:13:29 +02:00 committed by GitHub
commit 94ad067047
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
23 changed files with 518 additions and 61 deletions

View file

@ -34,17 +34,29 @@ CChannelFader::CChannelFader ( QWidget* pNW,
// create new GUI control objects and store pointers to them (note that // create new GUI control objects and store pointers to them (note that
// QWidget takes the ownership of the pMainGrid so that this only has // QWidget takes the ownership of the pMainGrid so that this only has
// to be created locally in this constructor) // to be created locally in this constructor)
pFrame = new QFrame ( pNW ); pFrame = new QFrame ( pNW );
QVBoxLayout* pMainGrid = new QVBoxLayout ( pFrame );
pFader = new QSlider ( Qt::Vertical, pFrame ); pLevelsBox = new QWidget ( pFrame );
pcbMute = new QCheckBox ( "Mute", pFrame ); plbrChannelLevel = new CMultiColorLEDBar ( pLevelsBox );
pcbSolo = new QCheckBox ( "Solo", pFrame ); pFader = new QSlider ( Qt::Vertical, pLevelsBox );
pLabelInstBox = new QGroupBox ( pFrame );
plblLabel = new QLabel ( "", pFrame ); pMuteSoloBox = new QWidget ( pFrame );
plblInstrument = new QLabel ( pFrame ); pcbMute = new QCheckBox ( "Mute", pMuteSoloBox );
plblCountryFlag = new QLabel ( pFrame ); pcbSolo = new QCheckBox ( "Solo", pMuteSoloBox );
QHBoxLayout* pLabelGrid = new QHBoxLayout ( pLabelInstBox );
QVBoxLayout* pLabelPictGrid = new QVBoxLayout(); pLabelInstBox = new QGroupBox ( pFrame );
plblLabel = new QLabel ( "", pFrame );
plblInstrument = new QLabel ( pFrame );
plblCountryFlag = new QLabel ( pFrame );
QVBoxLayout* pMainGrid = new QVBoxLayout ( pFrame );
QHBoxLayout* pLevelsGrid = new QHBoxLayout ( pLevelsBox );
QVBoxLayout* pMuteSoloGrid = new QVBoxLayout ( pMuteSoloBox );
QHBoxLayout* pLabelGrid = new QHBoxLayout ( pLabelInstBox );
QVBoxLayout* pLabelPictGrid = new QVBoxLayout ( );
// setup channel level
plbrChannelLevel->setContentsMargins( 0, 3, 2, 3 );
// setup slider // setup slider
pFader->setPageStep ( 1 ); pFader->setPageStep ( 1 );
@ -62,18 +74,30 @@ CChannelFader::CChannelFader ( QWidget* pNW,
// set margins of the layouts to zero to get maximum space for the controls // set margins of the layouts to zero to get maximum space for the controls
pMainGrid->setContentsMargins ( 0, 0, 0, 0 ); pMainGrid->setContentsMargins ( 0, 0, 0, 0 );
pLevelsGrid->setContentsMargins ( 0, 0, 0, 0 );
pLevelsGrid->setSpacing ( 0 ); // only minimal space
pMuteSoloGrid->setContentsMargins ( 0, 0, 0, 0 );
pLabelGrid->setContentsMargins ( 0, 0, 0, 0 ); pLabelGrid->setContentsMargins ( 0, 0, 0, 0 );
pLabelGrid->setSpacing ( 2 ); // only minimal space between picture and text pLabelGrid->setSpacing ( 2 ); // only minimal space between picture and text
// add user controls to the grids // add user controls to the grids
pLabelPictGrid->addWidget ( plblCountryFlag, 0, Qt::AlignHCenter ); pLabelPictGrid->addWidget ( plblCountryFlag, 0, Qt::AlignHCenter );
pLabelPictGrid->addWidget ( plblInstrument, 0, Qt::AlignHCenter ); pLabelPictGrid->addWidget ( plblInstrument, 0, Qt::AlignHCenter );
pLabelGrid->addLayout ( pLabelPictGrid ); pLabelGrid->addLayout ( pLabelPictGrid );
pLabelGrid->addWidget ( plblLabel, 0, Qt::AlignVCenter ); pLabelGrid->addWidget ( plblLabel, 0, Qt::AlignVCenter );
pMainGrid->addWidget ( pFader, 0, Qt::AlignHCenter ); pLevelsGrid->addWidget ( plbrChannelLevel, 0, Qt::AlignRight );
pMainGrid->addWidget ( pcbMute, 0, Qt::AlignLeft ); pLevelsGrid->addWidget ( pFader, 0, Qt::AlignLeft );
pMainGrid->addWidget ( pcbSolo, 0, Qt::AlignLeft );
pMuteSoloGrid->addWidget ( pcbMute, 0, Qt::AlignLeft );
pMuteSoloGrid->addWidget ( pcbSolo, 0, Qt::AlignLeft );
pMainGrid->addWidget ( pLevelsBox, 0, Qt::AlignHCenter );
pMainGrid->addWidget ( pMuteSoloBox, 0, Qt::AlignHCenter );
pMainGrid->addWidget ( pLabelInstBox ); pMainGrid->addWidget ( pLabelInstBox );
// add fader frame to audio mixer board layout // add fader frame to audio mixer board layout
@ -83,17 +107,23 @@ CChannelFader::CChannelFader ( QWidget* pNW,
Reset(); Reset();
// add help text to controls // add help text to controls
plbrChannelLevel->setWhatsThis ( tr ( "<b>Channel Level:</b> Displays the "
"pre-fader audio level of this channel. All connected clients at the "
"server will be assigned an audio level, the same value for each client." ) );
plbrChannelLevel->setAccessibleName ( tr ( "Input level of the current audio "
"channel at the server" ) );
pFader->setWhatsThis ( tr ( "<b>Mixer Fader:</b> Adjusts the audio level of " pFader->setWhatsThis ( tr ( "<b>Mixer Fader:</b> Adjusts the audio level of "
"this channel. All connected clients at the server will be assigned " "this channel. All connected clients at the server will be assigned "
"an audio fader at each client." ) ); "an audio fader at each client, adjusting the local mix." ) );
pFader->setAccessibleName ( tr ( "Mixer level setting of the connected client " pFader->setAccessibleName ( tr ( "Local mix level setting of the current audio "
"at the server" ) ); "channel at the server" ) );
pcbMute->setWhatsThis ( tr ( "<b>Mute:</b> With the Mute checkbox, the current " pcbMute->setWhatsThis ( tr ( "<b>Mute:</b> With the Mute checkbox, the "
"audio channel can be muted." ) ); "audio channel can be muted." ) );
pcbMute->setAccessibleName ( tr ( "Mute button" ) ); pcbMute->setAccessibleName ( tr ( "Mute button" ) );
pcbSolo->setWhatsThis ( tr ( "<b>Solo:</b> With the Solo checkbox, the current " pcbSolo->setWhatsThis ( tr ( "<b>Solo:</b> With the Solo checkbox, the "
"audio channel can be set to solo which means that all other channels " "audio channel can be set to solo which means that all other channels "
"except of the current channel are muted. It is possible to set more than " "except of the current channel are muted. It is possible to set more than "
"one channel to solo." ) ); "one channel to solo." ) );
@ -158,6 +188,11 @@ void CChannelFader::SetGUIDesign ( const EGUIDesign eNewDesign )
} }
} }
void CChannelFader::SetDisplayChannelLevel ( const bool eNDCL )
{
plbrChannelLevel->setHidden( !eNDCL );
}
void CChannelFader::SetupFaderTag ( const ESkillLevel eSkillLevel ) void CChannelFader::SetupFaderTag ( const ESkillLevel eSkillLevel )
{ {
// setup group box for label/instrument picture: set a thick black border // setup group box for label/instrument picture: set a thick black border
@ -306,6 +341,11 @@ void CChannelFader::UpdateSoloState ( const bool bNewOtherSoloState )
} }
} }
void CChannelFader::SetChannelLevel ( const uint16_t iLevel )
{
plbrChannelLevel->setValue ( iLevel );
}
void CChannelFader::SetText ( const CChannelInfo& ChanInfo ) void CChannelFader::SetText ( const CChannelInfo& ChanInfo )
{ {
// store original received name // store original received name
@ -634,6 +674,17 @@ void CAudioMixerBoard::SetGUIDesign ( const EGUIDesign eNewDesign )
} }
} }
void CAudioMixerBoard::SetDisplayChannelLevels ( const bool eNDCL )
{
bDisplayChannelLevels = eNDCL;
// apply preference to child GUI controls
for ( int i = 0; i < MAX_NUM_CHANNELS; i++ )
{
vecpChanFader[i]->SetDisplayChannelLevel ( bDisplayChannelLevels );
}
}
void CAudioMixerBoard::HideAll() void CAudioMixerBoard::HideAll()
{ {
// make all controls invisible // make all controls invisible
@ -710,6 +761,9 @@ void CAudioMixerBoard::ApplyNewConClientList ( CVector<CChannelInfo>& vecChanInf
} }
} }
// At some future time a new level will arrive -- ???
vecpChanFader[i]->SetChannelLevel ( 0 );
// set the text in the fader // set the text in the fader
vecpChanFader[i]->SetText ( vecChanInfo[j] ); vecpChanFader[i]->SetText ( vecChanInfo[j] );
@ -857,3 +911,17 @@ bool CAudioMixerBoard::GetStoredFaderSettings ( const CChannelInfo& ChanInfo,
// return "not OK" since we did not find matching fader settings // return "not OK" since we did not find matching fader settings
return false; return false;
} }
void CAudioMixerBoard::SetChannelLevels ( const CVector<uint16_t>& vecChannelLevel )
{
const int iNumChannelLevels = vecChannelLevel.Size();
int i = 0;
for ( int iChId = 0; iChId < MAX_NUM_CHANNELS; iChId++ )
{
if ( vecpChanFader[iChId]->IsVisible() && i < iNumChannelLevels )
{
vecpChanFader[iChId]->SetChannelLevel ( vecChannelLevel[i++] );
}
}
}

View file

@ -36,6 +36,7 @@
#include <QHostAddress> #include <QHostAddress>
#include "global.h" #include "global.h"
#include "util.h" #include "util.h"
#include "multicolorledbar.h"
/* Classes ********************************************************************/ /* Classes ********************************************************************/
@ -55,6 +56,7 @@ public:
bool IsSolo() { return pcbSolo->isChecked(); } bool IsSolo() { return pcbSolo->isChecked(); }
bool IsMute() { return pcbMute->isChecked(); } bool IsMute() { return pcbMute->isChecked(); }
void SetGUIDesign ( const EGUIDesign eNewDesign ); void SetGUIDesign ( const EGUIDesign eNewDesign );
void SetDisplayChannelLevel ( const bool eNDCL );
void UpdateSoloState ( const bool bNewOtherSoloState ); void UpdateSoloState ( const bool bNewOtherSoloState );
void SetFaderLevel ( const int iLevel ); void SetFaderLevel ( const int iLevel );
@ -62,6 +64,7 @@ public:
void SetFaderIsMute ( const bool bIsMute ); void SetFaderIsMute ( const bool bIsMute );
int GetFaderLevel() { return pFader->value(); } int GetFaderLevel() { return pFader->value(); }
void Reset(); void Reset();
void SetChannelLevel ( const uint16_t iLevel );
protected: protected:
double CalcFaderGain ( const int value ); double CalcFaderGain ( const int value );
@ -69,18 +72,24 @@ protected:
void SendFaderLevelToServer ( const int iLevel ); void SendFaderLevelToServer ( const int iLevel );
void SetupFaderTag ( const ESkillLevel eSkillLevel ); void SetupFaderTag ( const ESkillLevel eSkillLevel );
QFrame* pFrame; QFrame* pFrame;
QGroupBox* pLabelInstBox;
QSlider* pFader;
QCheckBox* pcbMute;
QCheckBox* pcbSolo;
QLabel* plblLabel;
QLabel* plblInstrument;
QLabel* plblCountryFlag;
QString strReceivedName; QWidget* pLevelsBox;
QWidget* pMuteSoloBox;
CMultiColorLEDBar* plbrChannelLevel;
QSlider* pFader;
bool bOtherChannelIsSolo; QCheckBox* pcbMute;
QCheckBox* pcbSolo;
QGroupBox* pLabelInstBox;
QLabel* plblLabel;
QLabel* plblInstrument;
QLabel* plblCountryFlag;
QString strReceivedName;
bool bOtherChannelIsSolo;
public slots: public slots:
void OnLevelValueChanged ( int value ) { SendFaderLevelToServer ( value ); } void OnLevelValueChanged ( int value ) { SendFaderLevelToServer ( value ); }
@ -103,10 +112,13 @@ public:
void ApplyNewConClientList ( CVector<CChannelInfo>& vecChanInfo ); void ApplyNewConClientList ( CVector<CChannelInfo>& vecChanInfo );
void SetServerName ( const QString& strNewServerName ); void SetServerName ( const QString& strNewServerName );
void SetGUIDesign ( const EGUIDesign eNewDesign ); void SetGUIDesign ( const EGUIDesign eNewDesign );
void SetDisplayChannelLevels ( const bool eNDCL );
void SetFaderLevel ( const int iChannelIdx, void SetFaderLevel ( const int iChannelIdx,
const int iValue ); const int iValue );
void SetChannelLevels ( const CVector<uint16_t>& vecChannelLevel );
// settings // settings
CVector<QString> vecStoredFaderTags; CVector<QString> vecStoredFaderTags;
CVector<int> vecStoredFaderLevels; CVector<int> vecStoredFaderLevels;
@ -129,6 +141,7 @@ protected:
CVector<CChannelFader*> vecpChanFader; CVector<CChannelFader*> vecpChanFader;
QGroupBox* pGroupBox; QGroupBox* pGroupBox;
QHBoxLayout* pMainLayout; QHBoxLayout* pMainLayout;
bool bDisplayChannelLevels;
bool bNoFaderVisible; bool bNoFaderVisible;
public slots: public slots:

View file

@ -102,6 +102,10 @@ qRegisterMetaType<CHostAddress> ( "CHostAddress" );
QObject::connect( &Protocol, QObject::connect( &Protocol,
SIGNAL ( LicenceRequired ( ELicenceType ) ), SIGNAL ( LicenceRequired ( ELicenceType ) ),
SIGNAL ( LicenceRequired ( ELicenceType ) ) ); SIGNAL ( LicenceRequired ( ELicenceType ) ) );
QObject::connect ( &Protocol,
SIGNAL ( ReqChannelLevelList ( bool ) ),
this, SLOT ( OnReqChannelLevelList ( bool ) ) );
} }
bool CChannel::ProtocolIsEnabled() bool CChannel::ProtocolIsEnabled()

View file

@ -159,12 +159,18 @@ public:
void CreateReqConnClientsList() { Protocol.CreateReqConnClientsList(); } void CreateReqConnClientsList() { Protocol.CreateReqConnClientsList(); }
void CreateChatTextMes ( const QString& strChatText ) { Protocol.CreateChatTextMes ( strChatText ); } void CreateChatTextMes ( const QString& strChatText ) { Protocol.CreateChatTextMes ( strChatText ); }
void CreateLicReqMes ( const ELicenceType eLicenceType ) { Protocol.CreateLicenceRequiredMes ( eLicenceType ); } void CreateLicReqMes ( const ELicenceType eLicenceType ) { Protocol.CreateLicenceRequiredMes ( eLicenceType ); }
void CreateReqChannelLevelListMes ( bool bOptIn ) { Protocol.CreateReqChannelLevelListMes ( bOptIn ); }
void CreateConClientListMes ( const CVector<CChannelInfo>& vecChanInfo ) void CreateConClientListMes ( const CVector<CChannelInfo>& vecChanInfo )
{ Protocol.CreateConClientListMes ( vecChanInfo ); } { Protocol.CreateConClientListMes ( vecChanInfo ); }
CNetworkTransportProps GetNetworkTransportPropsFromCurrentSettings(); CNetworkTransportProps GetNetworkTransportPropsFromCurrentSettings();
bool ChannelLevelsRequired() const { return bChannelLevelsRequired; }
double GetPrevLevel() const { return dPrevLevel; }
void SetPrevLevel ( const double nPL ) { dPrevLevel = nPL; }
protected: protected:
bool ProtocolIsEnabled(); bool ProtocolIsEnabled();
@ -177,6 +183,8 @@ 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
@ -216,6 +224,9 @@ protected:
QMutex MutexSocketBuf; QMutex MutexSocketBuf;
QMutex MutexConvBuf; QMutex MutexConvBuf;
bool bChannelLevelsRequired;
double dPrevLevel;
public slots: public slots:
void OnSendProtMessage ( CVector<uint8_t> vecMessage ); void OnSendProtMessage ( CVector<uint8_t> vecMessage );
void OnJittBufSizeChange ( int iNewJitBufSize ); void OnJittBufSizeChange ( int iNewJitBufSize );
@ -249,6 +260,8 @@ public slots:
void OnNewConnection() { emit NewConnection(); } void OnNewConnection() { emit NewConnection(); }
void OnReqChannelLevelList ( bool bOptIn ) { bChannelLevelsRequired = bOptIn; }
signals: signals:
void MessReadyForSending ( CVector<uint8_t> vecMessage ); void MessReadyForSending ( CVector<uint8_t> vecMessage );
void NewConnection(); void NewConnection();

View file

@ -65,6 +65,7 @@ CClient::CClient ( const quint16 iPortNumber,
bFraSiFactDefSupported ( false ), bFraSiFactDefSupported ( false ),
bFraSiFactSafeSupported ( false ), bFraSiFactSafeSupported ( false ),
eGUIDesign ( GD_ORIGINAL ), eGUIDesign ( GD_ORIGINAL ),
bDisplayChannelLevels ( true ),
bJitterBufferOK ( true ), bJitterBufferOK ( true ),
strCentralServerAddress ( "" ), strCentralServerAddress ( "" ),
bUseDefaultCentralServerAddress ( true ), bUseDefaultCentralServerAddress ( true ),
@ -191,6 +192,10 @@ CClient::CClient ( const quint16 iPortNumber,
SIGNAL ( CLVersionAndOSReceived ( CHostAddress, COSUtil::EOpSystemType, QString ) ) ); SIGNAL ( CLVersionAndOSReceived ( CHostAddress, COSUtil::EOpSystemType, QString ) ) );
#endif #endif
QObject::connect ( &ConnLessProtocol,
SIGNAL ( CLChannelLevelListReceived ( CHostAddress, CVector<uint16_t> ) ),
this, SLOT ( OnCLChannelLevelListReceived ( CHostAddress, CVector<uint16_t> ) ) );
// other // other
QObject::connect ( &Sound, SIGNAL ( ReinitRequest ( int ) ), QObject::connect ( &Sound, SIGNAL ( ReinitRequest ( int ) ),
this, SLOT ( OnSndCrdReinitRequest ( int ) ) ); this, SLOT ( OnSndCrdReinitRequest ( int ) ) );
@ -279,6 +284,9 @@ void CClient::OnNewConnection()
// Same problem is with the jitter buffer message. // Same problem is with the jitter buffer message.
Channel.CreateReqConnClientsList(); Channel.CreateReqConnClientsList();
CreateServerJitterBufferMessage(); CreateServerJitterBufferMessage();
// send opt-in / out for Channel Level updates
Channel.CreateReqChannelLevelListMes ( bDisplayChannelLevels );
} }
void CClient::CreateServerJitterBufferMessage() void CClient::CreateServerJitterBufferMessage()
@ -387,6 +395,14 @@ bool CClient::GetAndResetbJitterBufferOKFlag()
return bSocketJitBufOKFlag; return bSocketJitBufOKFlag;
} }
void CClient::SetDisplayChannelLevels ( const bool bNDCL )
{
bDisplayChannelLevels = bNDCL;
// tell any connected server about the change
Channel.CreateReqChannelLevelListMes ( bDisplayChannelLevels );
}
void CClient::SetSndCrdPrefFrameSizeFactor ( const int iNewFactor ) void CClient::SetSndCrdPrefFrameSizeFactor ( const int iNewFactor )
{ {
// first check new input parameter // first check new input parameter
@ -598,6 +614,12 @@ void CClient::OnSndCrdReinitRequest ( int iSndCrdResetType )
} }
} }
void CClient::OnCLChannelLevelListReceived ( CHostAddress InetAddr,
CVector<uint16_t> vecLevelList )
{
emit CLChannelLevelListReceived ( InetAddr, vecLevelList );
}
void CClient::Start() void CClient::Start()
{ {
// always use the OPUS codec // always use the OPUS codec

View file

@ -128,6 +128,9 @@ public:
EGUIDesign GetGUIDesign() const { return eGUIDesign; } EGUIDesign GetGUIDesign() const { return eGUIDesign; }
void SetGUIDesign ( const EGUIDesign eNGD ) { eGUIDesign = eNGD; } void SetGUIDesign ( const EGUIDesign eNGD ) { eGUIDesign = eNGD; }
bool GetDisplayChannelLevels() const { return bDisplayChannelLevels; }
void SetDisplayChannelLevels ( const bool bNDCL );
EAudioQuality GetAudioQuality() const { return eAudioQuality; } EAudioQuality GetAudioQuality() const { return eAudioQuality; }
void SetAudioQuality ( const EAudioQuality eNAudioQuality ); void SetAudioQuality ( const EAudioQuality eNAudioQuality );
@ -359,6 +362,7 @@ protected:
int iStereoBlockSizeSam; int iStereoBlockSizeSam;
EGUIDesign eGUIDesign; EGUIDesign eGUIDesign;
bool bDisplayChannelLevels;
bool bJitterBufferOK; bool bJitterBufferOK;
@ -398,6 +402,9 @@ public slots:
void OnSndCrdReinitRequest ( int iSndCrdResetType ); void OnSndCrdReinitRequest ( int iSndCrdResetType );
void OnCLChannelLevelListReceived ( CHostAddress InetAddr,
CVector<uint16_t> vecLevelList );
signals: signals:
void ConClientListMesReceived ( CVector<CChannelInfo> vecChanInfo ); void ConClientListMesReceived ( CVector<CChannelInfo> vecChanInfo );
void ChatTextReceived ( QString strChatText ); void ChatTextReceived ( QString strChatText );
@ -420,6 +427,9 @@ signals:
QString strVersion ); QString strVersion );
#endif #endif
void CLChannelLevelListReceived ( CHostAddress InetAddr,
CVector<uint16_t> vecLevelList );
void Disconnected(); void Disconnected();
void ControllerInFaderLevel ( int iChannelIdx, int iValue ); void ControllerInFaderLevel ( int iChannelIdx, int iValue );
}; };

View file

@ -185,6 +185,9 @@ CClientDlg::CClientDlg ( CClient* pNCliP,
// reset mixer board // reset mixer board
MainMixerBoard->HideAll(); MainMixerBoard->HideAll();
// restore channel level display preference
MainMixerBoard->SetDisplayChannelLevels ( pClient->GetDisplayChannelLevels() );
// restore fader settings // restore fader settings
MainMixerBoard->vecStoredFaderTags = pClient->vecStoredFaderTags; MainMixerBoard->vecStoredFaderTags = pClient->vecStoredFaderTags;
MainMixerBoard->vecStoredFaderLevels = pClient->vecStoredFaderLevels; MainMixerBoard->vecStoredFaderLevels = pClient->vecStoredFaderLevels;
@ -483,6 +486,10 @@ CClientDlg::CClientDlg ( CClient* pNCliP,
SIGNAL ( ControllerInFaderLevel ( int, int ) ), SIGNAL ( ControllerInFaderLevel ( int, int ) ),
this, SLOT ( OnControllerInFaderLevel ( int, int ) ) ); this, SLOT ( OnControllerInFaderLevel ( int, int ) ) );
QObject::connect ( pClient,
SIGNAL ( CLChannelLevelListReceived ( CHostAddress, CVector<uint16_t> ) ),
this, SLOT ( OnCLChannelLevelListReceived ( CHostAddress, CVector<uint16_t> ) ) );
#ifdef ENABLE_CLIENT_VERSION_AND_OS_DEBUGGING #ifdef ENABLE_CLIENT_VERSION_AND_OS_DEBUGGING
QObject::connect ( pClient, QObject::connect ( pClient,
SIGNAL ( CLVersionAndOSReceived ( CHostAddress, COSUtil::EOpSystemType, QString ) ), SIGNAL ( CLVersionAndOSReceived ( CHostAddress, COSUtil::EOpSystemType, QString ) ),
@ -495,6 +502,9 @@ CClientDlg::CClientDlg ( CClient* pNCliP,
QObject::connect ( &ClientSettingsDlg, SIGNAL ( GUIDesignChanged() ), QObject::connect ( &ClientSettingsDlg, SIGNAL ( GUIDesignChanged() ),
this, SLOT ( OnGUIDesignChanged() ) ); this, SLOT ( OnGUIDesignChanged() ) );
QObject::connect ( &ClientSettingsDlg, SIGNAL ( DisplayChannelLevelsChanged() ),
this, SLOT ( OnDisplayChannelLevelsChanged() ) );
QObject::connect ( &ClientSettingsDlg, SIGNAL ( AudioChannelsChanged() ), QObject::connect ( &ClientSettingsDlg, SIGNAL ( AudioChannelsChanged() ),
this, SLOT ( OnAudioChannelsChanged() ) ); this, SLOT ( OnAudioChannelsChanged() ) );
@ -906,7 +916,7 @@ void CClientDlg::OnTimerSigMet()
// linear transformation of the input level range to the progress-bar // linear transformation of the input level range to the progress-bar
// range // range
dCurSigLevelL -= LOW_BOUND_SIG_METER; dCurSigLevelL -= LOW_BOUND_SIG_METER;
dCurSigLevelL *= NUM_STEPS_INP_LEV_METER / dCurSigLevelL *= NUM_STEPS_LED_BAR /
( UPPER_BOUND_SIG_METER - LOW_BOUND_SIG_METER ); ( UPPER_BOUND_SIG_METER - LOW_BOUND_SIG_METER );
// lower bound the signal // lower bound the signal
@ -916,7 +926,7 @@ void CClientDlg::OnTimerSigMet()
} }
dCurSigLevelR -= LOW_BOUND_SIG_METER; dCurSigLevelR -= LOW_BOUND_SIG_METER;
dCurSigLevelR *= NUM_STEPS_INP_LEV_METER / dCurSigLevelR *= NUM_STEPS_LED_BAR /
( UPPER_BOUND_SIG_METER - LOW_BOUND_SIG_METER ); ( UPPER_BOUND_SIG_METER - LOW_BOUND_SIG_METER );
// lower bound the signal // lower bound the signal

View file

@ -60,10 +60,6 @@
#define BUFFER_LED_UPDATE_TIME_MS 300 // ms #define BUFFER_LED_UPDATE_TIME_MS 300 // ms
#define LED_BAR_UPDATE_TIME_MS 1000 // ms #define LED_BAR_UPDATE_TIME_MS 1000 // ms
// range for signal level meter
#define LOW_BOUND_SIG_METER ( -50.0 ) // dB
#define UPPER_BOUND_SIG_METER ( 0.0 ) // dB
// number of ping times > upper bound until error message is shown // number of ping times > upper bound until error message is shown
#define NUM_HIGH_PINGS_UNTIL_ERROR 5 #define NUM_HIGH_PINGS_UNTIL_ERROR 5
@ -196,12 +192,19 @@ public slots:
CVector<CChannelInfo> vecChanInfo ) CVector<CChannelInfo> vecChanInfo )
{ ConnectDlg.SetConnClientsList ( InetAddr, vecChanInfo ); } { ConnectDlg.SetConnClientsList ( InetAddr, vecChanInfo ); }
void OnCLChannelLevelListReceived ( CHostAddress /* unused */,
CVector<uint16_t> vecLevelList )
{ MainMixerBoard->SetChannelLevels ( vecLevelList ); }
void OnConnectDlgAccepted(); void OnConnectDlgAccepted();
void OnDisconnected(); void OnDisconnected();
void OnGUIDesignChanged() void OnGUIDesignChanged()
{ SetGUIDesign ( pClient->GetGUIDesign() ); } { SetGUIDesign ( pClient->GetGUIDesign() ); }
void OnDisplayChannelLevelsChanged()
{ MainMixerBoard->SetDisplayChannelLevels ( pClient->GetDisplayChannelLevels() ); }
void OnAudioChannelsChanged() { UpdateRevSelection(); } void OnAudioChannelsChanged() { UpdateRevSelection(); }
void OnNumClientsChanged ( int iNewNumClients ); void OnNumClientsChanged ( int iNewNumClients );
void OnNewClientLevelChanged() { MainMixerBoard->iNewClientFaderLevel = pClient->iNewClientFaderLevel; } void OnNewClientLevelChanged() { MainMixerBoard->iNewClientFaderLevel = pClient->iNewClientFaderLevel; }

View file

@ -189,6 +189,12 @@ CClientSettingsDlg::CClientSettingsDlg ( CClient* pNCliP, QWidget* parent,
chbGUIDesignFancy->setAccessibleName ( tr ( "Fancy skin check box" ) ); chbGUIDesignFancy->setAccessibleName ( tr ( "Fancy skin check box" ) );
// display channel levels
chbDisplayChannelLevels->setWhatsThis ( tr ( "<b>Display Channel Levels:</b> "
"If enabled, each client channel will display a pre-fader level bar." ) );
chbDisplayChannelLevels->setAccessibleName ( tr ( "Display channel levels check box" ) );
// audio channels // audio channels
QString strAudioChannels = tr ( "<b>Audio Channels:</b> " QString strAudioChannels = tr ( "<b>Audio Channels:</b> "
"Select the number of audio channels to be used. There are three " "Select the number of audio channels to be used. There are three "
@ -323,6 +329,9 @@ CClientSettingsDlg::CClientSettingsDlg ( CClient* pNCliP, QWidget* parent,
chbGUIDesignFancy->setCheckState ( Qt::Checked ); chbGUIDesignFancy->setCheckState ( Qt::Checked );
} }
// Display Channel Levels check box
chbDisplayChannelLevels->setCheckState ( pClient->GetDisplayChannelLevels() ? Qt::Checked : Qt::Unchecked );
// "Audio Channels" combo box // "Audio Channels" combo box
cbxAudioChannels->clear(); cbxAudioChannels->clear();
cbxAudioChannels->addItem ( "Mono" ); // CC_MONO cbxAudioChannels->addItem ( "Mono" ); // CC_MONO
@ -386,6 +395,9 @@ CClientSettingsDlg::CClientSettingsDlg ( CClient* pNCliP, QWidget* parent,
QObject::connect ( chbGUIDesignFancy, SIGNAL ( stateChanged ( int ) ), QObject::connect ( chbGUIDesignFancy, SIGNAL ( stateChanged ( int ) ),
this, SLOT ( OnGUIDesignFancyStateChanged ( int ) ) ); this, SLOT ( OnGUIDesignFancyStateChanged ( int ) ) );
QObject::connect ( chbDisplayChannelLevels, SIGNAL ( stateChanged ( int ) ),
this, SLOT ( OnDisplayChannelLevelsStateChanged ( int ) ) );
QObject::connect ( chbAutoJitBuf, SIGNAL ( stateChanged ( int ) ), QObject::connect ( chbAutoJitBuf, SIGNAL ( stateChanged ( int ) ),
this, SLOT ( OnAutoJitBufStateChanged ( int ) ) ); this, SLOT ( OnAutoJitBufStateChanged ( int ) ) );
@ -704,6 +716,12 @@ void CClientSettingsDlg::OnGUIDesignFancyStateChanged ( int value )
UpdateDisplay(); UpdateDisplay();
} }
void CClientSettingsDlg::OnDisplayChannelLevelsStateChanged ( int value )
{
pClient->SetDisplayChannelLevels ( value != Qt::Unchecked );
emit DisplayChannelLevelsChanged();
}
void CClientSettingsDlg::OnDefaultCentralServerStateChanged ( int value ) void CClientSettingsDlg::OnDefaultCentralServerStateChanged ( int value )
{ {
// apply new setting to the client // apply new setting to the client

View file

@ -90,6 +90,7 @@ protected:
void OnSliderSndCrdBufferDelay ( int value ); void OnSliderSndCrdBufferDelay ( int value );
void OnAutoJitBufStateChanged ( int value ); void OnAutoJitBufStateChanged ( int value );
void OnGUIDesignFancyStateChanged ( int value ); void OnGUIDesignFancyStateChanged ( int value );
void OnDisplayChannelLevelsStateChanged ( int value );
void OnDefaultCentralServerStateChanged ( int value ); void OnDefaultCentralServerStateChanged ( int value );
void OnCentralServerAddressEditingFinished(); void OnCentralServerAddressEditingFinished();
void OnNewClientLevelEditingFinished(); void OnNewClientLevelEditingFinished();
@ -105,6 +106,7 @@ protected:
signals: signals:
void GUIDesignChanged(); void GUIDesignChanged();
void DisplayChannelLevelsChanged();
void AudioChannelsChanged(); void AudioChannelsChanged();
void NewClientLevelChanged(); void NewClientLevelChanged();
}; };

View file

@ -530,11 +530,22 @@
</layout> </layout>
</item> </item>
<item> <item>
<widget class="QCheckBox" name="chbGUIDesignFancy"> <layout class="QHBoxLayout">
<property name="text"> <item>
<string>Fancy Skin</string> <widget class="QCheckBox" name="chbGUIDesignFancy">
</property> <property name="text">
</widget> <string>Fancy Skin</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="chbDisplayChannelLevels">
<property name="text">
<string>Display Channel Levels</string>
</property>
</widget>
</item>
</layout>
</item> </item>
<item> <item>
<layout class="QHBoxLayout"> <layout class="QHBoxLayout">
@ -719,6 +730,7 @@
<tabstop>cbxAudioQuality</tabstop> <tabstop>cbxAudioQuality</tabstop>
<tabstop>edtNewClientLevel</tabstop> <tabstop>edtNewClientLevel</tabstop>
<tabstop>chbGUIDesignFancy</tabstop> <tabstop>chbGUIDesignFancy</tabstop>
<tabstop>chbDisplayChannelFaders</tabstop>
<tabstop>chbDefaultCentralServer</tabstop> <tabstop>chbDefaultCentralServer</tabstop>
<tabstop>edtCentralServerAddress</tabstop> <tabstop>edtCentralServerAddress</tabstop>
</tabstops> </tabstops>

View file

@ -169,10 +169,14 @@ LED bar: lbr
// maximum number of fader settings to be stored (together with the fader tags) // maximum number of fader settings to be stored (together with the fader tags)
#define MAX_NUM_STORED_FADER_SETTINGS 100 #define MAX_NUM_STORED_FADER_SETTINGS 100
// defines for LED input level meter // defines for LED level meter CMultiColorLEDBar
#define NUM_STEPS_INP_LEV_METER 8 #define NUM_STEPS_LED_BAR 8
#define RED_BOUND_INP_LEV_METER 7 #define RED_BOUND_LED_BAR 7
#define YELLOW_BOUND_INP_LEV_METER 5 #define YELLOW_BOUND_LED_BAR 5
// range for signal level meter
#define LOW_BOUND_SIG_METER ( -50.0 ) // dB
#define UPPER_BOUND_SIG_METER ( 0.0 ) // dB
// Maximum number of connected clients at the server. If you want to change this // Maximum number of connected clients at the server. If you want to change this
// paramter you have to modify the code on some places, too! The code tag // paramter you have to modify the code on some places, too! The code tag
@ -195,6 +199,9 @@ LED bar: lbr
// list // list
#define PING_UPDATE_TIME_SERVER_LIST_MS 2000 // ms #define PING_UPDATE_TIME_SERVER_LIST_MS 2000 // ms
// defines the interval between Channel Level updates from the server
#define CHANNEL_LEVEL_UPDATE_INTERVAL 100 // number of frames
// time-out until a registered server is deleted from the server list if no // time-out until a registered server is deleted from the server list if no
// new registering was made in minutes // new registering was made in minutes
#define SERVLIST_TIME_OUT_MINUTES 60 // minutes #define SERVLIST_TIME_OUT_MINUTES 60 // minutes

View file

@ -33,7 +33,7 @@ CMultiColorLEDBar::CMultiColorLEDBar ( QWidget* parent, Qt::WindowFlags f )
: QFrame ( parent, f ) : QFrame ( parent, f )
{ {
// set total number of LEDs // set total number of LEDs
iNumLEDs = NUM_STEPS_INP_LEV_METER; iNumLEDs = NUM_STEPS_LED_BAR;
// create layout and set spacing to zero // create layout and set spacing to zero
pMainLayout = new QVBoxLayout ( this ); pMainLayout = new QVBoxLayout ( this );
@ -105,14 +105,14 @@ void CMultiColorLEDBar::setValue ( const int value )
if ( iLEDIdx < value ) if ( iLEDIdx < value )
{ {
// check which color we should use (green, yellow or red) // check which color we should use (green, yellow or red)
if ( iLEDIdx < YELLOW_BOUND_INP_LEV_METER ) if ( iLEDIdx < YELLOW_BOUND_LED_BAR )
{ {
// green region // green region
vecpLEDs[iLEDIdx]->setColor ( cLED::RL_GREEN ); vecpLEDs[iLEDIdx]->setColor ( cLED::RL_GREEN );
} }
else else
{ {
if ( iLEDIdx < RED_BOUND_INP_LEV_METER ) if ( iLEDIdx < RED_BOUND_LED_BAR )
{ {
// yellow region // yellow region
vecpLEDs[iLEDIdx]->setColor ( cLED::RL_YELLOW ); vecpLEDs[iLEDIdx]->setColor ( cLED::RL_YELLOW );

View file

@ -153,6 +153,14 @@ MESSAGES (with connection)
| 1 byte licence type | | 1 byte licence type |
+---------------------+ +---------------------+
- PROTMESSID_CLM_REQ_CHANNEL_LEVEL_LIST: Opt in or out of the channel level list
+---------------+
| 1 byte option |
+---------------+
option is boolean, true to opt in, false to opt out
// #### COMPATIBILITY OLD VERSION, TO BE REMOVED #### // #### COMPATIBILITY OLD VERSION, TO BE REMOVED ####
- PROTMESSID_OPUS_SUPPORTED: Informs that OPUS codec is supported - PROTMESSID_OPUS_SUPPORTED: Informs that OPUS codec is supported
@ -276,6 +284,27 @@ CONNECTION LESS MESSAGES
note: does not have any data -> n = 0 note: does not have any data -> n = 0
- PROTMESSID_CLM_CHANNEL_LEVEL_LIST: The channel level list
+----------------------------------+
| ( ( n + 1 ) / 2 ) * 4 bit values |
+----------------------------------+
n is number of connected clients
the values are the maximum channel levels for a client frame converted
to the range of CMultiColorLEDBar in 4 bits, two entries per byte
with the earlier channel in the lower half of the byte
where an odd number of clients is connected, there will be four unused
upper bits in the final byte, containing 0xF (which is out of range)
the server may compute them message when any client has used
PROTMESSID_CLM_REQ_CHANNEL_LEVEL_LIST to opt in
the server may issue to message only to a client that has used
PROTMESSID_CLM_REQ_CHANNEL_LEVEL_LIST to opt in
****************************************************************************** ******************************************************************************
* *
@ -549,6 +578,10 @@ if ( rand() < ( RAND_MAX / 2 ) ) return false;
case PROTMESSID_LICENCE_REQUIRED: case PROTMESSID_LICENCE_REQUIRED:
bRet = EvaluateLicenceRequiredMes ( vecbyMesBodyData ); bRet = EvaluateLicenceRequiredMes ( vecbyMesBodyData );
break; break;
case PROTMESSID_REQ_CHANNEL_LEVEL_LIST:
bRet = EvaluateReqChannelLevelListMes ( vecbyMesBodyData );
break;
} }
// immediately send acknowledge message // immediately send acknowledge message
@ -634,6 +667,10 @@ if ( rand() < ( RAND_MAX / 2 ) ) return false;
case PROTMESSID_CLM_REQ_CONN_CLIENTS_LIST: case PROTMESSID_CLM_REQ_CONN_CLIENTS_LIST:
bRet = EvaluateCLReqConnClientsListMes ( InetAddr ); bRet = EvaluateCLReqConnClientsListMes ( InetAddr );
break; break;
case PROTMESSID_CLM_CHANNEL_LEVEL_LIST:
bRet = EvaluateCLChannelLevelListMes ( InetAddr, vecbyMesBodyData );
break;
} }
} }
else else
@ -1234,6 +1271,40 @@ void CProtocol::CreateOpusSupportedMes()
CVector<uint8_t> ( 0 ) ); CVector<uint8_t> ( 0 ) );
} }
void CProtocol::CreateReqChannelLevelListMes ( const bool bRCL )
{
CVector<uint8_t> vecData ( 1 ); // 1 byte of data
int iPos = 0; // init position pointer
PutValOnStream ( vecData, iPos,
static_cast<uint32_t> ( bRCL ), 1 );
CreateAndSendMessage ( PROTMESSID_REQ_CHANNEL_LEVEL_LIST, vecData );
}
bool CProtocol::EvaluateReqChannelLevelListMes ( const CVector<uint8_t>& vecData )
{
int iPos = 0; // init position pointer
// check size
if ( vecData.Size() != 1 )
{
return true; // return error code
}
// extract opt in / out for channel levels
uint32_t val = GetValFromStream ( vecData, iPos, 1 );
if ( val != 0 && val != 1 )
{
return true; // return error code
}
// invoke message action
emit ReqChannelLevelList ( static_cast<bool> ( val ) );
return false; // no error
}
// Connection less messages ---------------------------------------------------- // Connection less messages ----------------------------------------------------
void CProtocol::CreateCLPingMes ( const CHostAddress& InetAddr, const int iMs ) void CProtocol::CreateCLPingMes ( const CHostAddress& InetAddr, const int iMs )
@ -1936,6 +2007,70 @@ bool CProtocol::EvaluateCLReqConnClientsListMes ( const CHostAddress& InetAddr )
return false; // no error return false; // no error
} }
void CProtocol::CreateCLChannelLevelListMes ( const CHostAddress& InetAddr,
const CVector<uint16_t>& vecLevelList,
const int iNumClients )
{
// This must be a multiple of bytes at four bits per client
const int iNumBytes = ( iNumClients + 1 ) / 2;
CVector<uint8_t> vecData( iNumBytes );
int iPos = 0; // init position pointer
for ( int i = 0, j = 0; i < iNumClients; i += 2 /* pack two per byte */, j++ )
{
uint16_t levelLo = vecLevelList[i] & 0x0F;
uint16_t levelHi = ( i + 1 < iNumClients ) ? vecLevelList[i + 1] & 0x0F : 0x0F;
uint8_t byte = static_cast<uint8_t> ( levelLo | ( levelHi << 4 ) );
PutValOnStream ( vecData, iPos,
static_cast<uint32_t> ( byte ), 1 );
}
CreateAndImmSendConLessMessage ( PROTMESSID_CLM_CHANNEL_LEVEL_LIST,
vecData,
InetAddr );
}
bool CProtocol::EvaluateCLChannelLevelListMes ( const CHostAddress& InetAddr,
const CVector<uint8_t>& vecData )
{
int iPos = 0; // init position pointer
const int iDataLen = vecData.Size(); // four bits per channel, 2 channels per byte
// may have one too many entries, last being 0xF
int iVecLen = iDataLen * 2; // one ushort per channel
if ( iVecLen > MAX_NUM_CHANNELS )
{
return true; // return error code
}
CVector<uint16_t> vecLevelList ( iVecLen );
for (int i = 0, j = 0; i < iDataLen; i++, j += 2 )
{
uint8_t byte = static_cast<uint8_t> ( GetValFromStream ( vecData, iPos, 1 ) );
uint16_t levelLo = byte & 0x0F;
uint16_t levelHi = ( byte >> 4 ) & 0x0F;
vecLevelList[j] = levelLo;
if ( levelHi != 0x0F )
{
vecLevelList[j + 1] = levelHi;
}
else
{
vecLevelList.resize ( iVecLen - 1 );
break;
}
}
// invoke message action
emit CLChannelLevelListReceived ( InetAddr, vecLevelList );
return false; // no error
}
/******************************************************************************\ /******************************************************************************\
* Message generation and parsing * * Message generation and parsing *

View file

@ -54,6 +54,7 @@
#define PROTMESSID_CHANNEL_INFOS 25 // set channel infos #define PROTMESSID_CHANNEL_INFOS 25 // set channel infos
#define PROTMESSID_OPUS_SUPPORTED 26 // tells that OPUS codec is supported #define PROTMESSID_OPUS_SUPPORTED 26 // tells that OPUS codec is supported
#define PROTMESSID_LICENCE_REQUIRED 27 // licence required #define PROTMESSID_LICENCE_REQUIRED 27 // licence required
#define PROTMESSID_REQ_CHANNEL_LEVEL_LIST 28 // request the channel level list
// message IDs of connection less messages (CLM) // message IDs of connection less messages (CLM)
// DEFINITION -> start at 1000, end at 1999, see IsConnectionLessMessageID // DEFINITION -> start at 1000, end at 1999, see IsConnectionLessMessageID
@ -71,6 +72,7 @@
#define PROTMESSID_CLM_REQ_VERSION_AND_OS 1012 // request version number and operating system #define PROTMESSID_CLM_REQ_VERSION_AND_OS 1012 // request version number and operating system
#define PROTMESSID_CLM_CONN_CLIENTS_LIST 1013 // channel infos for connected clients #define PROTMESSID_CLM_CONN_CLIENTS_LIST 1013 // channel infos for connected clients
#define PROTMESSID_CLM_REQ_CONN_CLIENTS_LIST 1014 // request the connected clients list #define PROTMESSID_CLM_REQ_CONN_CLIENTS_LIST 1014 // request the connected clients list
#define PROTMESSID_CLM_CHANNEL_LEVEL_LIST 1015 // channel level list
// lengths of message as defined in protocol.cpp file // lengths of message as defined in protocol.cpp file
#define MESS_HEADER_LENGTH_BYTE 7 // TAG (2), ID (2), cnt (1), length (2) #define MESS_HEADER_LENGTH_BYTE 7 // TAG (2), ID (2), cnt (1), length (2)
@ -102,6 +104,7 @@ public:
void CreateReqNetwTranspPropsMes(); void CreateReqNetwTranspPropsMes();
void CreateLicenceRequiredMes ( const ELicenceType eLicenceType ); void CreateLicenceRequiredMes ( const ELicenceType eLicenceType );
void CreateOpusSupportedMes(); void CreateOpusSupportedMes();
void CreateReqChannelLevelListMes ( const bool bRCL );
void CreateCLPingMes ( const CHostAddress& InetAddr, const int iMs ); void CreateCLPingMes ( const CHostAddress& InetAddr, const int iMs );
void CreateCLPingWithNumClientsMes ( const CHostAddress& InetAddr, void CreateCLPingWithNumClientsMes ( const CHostAddress& InetAddr,
@ -123,6 +126,9 @@ public:
void CreateCLConnClientsListMes ( const CHostAddress& InetAddr, void CreateCLConnClientsListMes ( const CHostAddress& InetAddr,
const CVector<CChannelInfo>& vecChanInfo ); const CVector<CChannelInfo>& vecChanInfo );
void CreateCLReqConnClientsListMes ( const CHostAddress& InetAddr ); void CreateCLReqConnClientsListMes ( const CHostAddress& InetAddr );
void CreateCLChannelLevelListMes ( const CHostAddress& InetAddr,
const CVector<uint16_t>& vecLevelList,
const int iNumClients );
static bool ParseMessageFrame ( const CVector<uint8_t>& vecbyData, static bool ParseMessageFrame ( const CVector<uint8_t>& vecbyData,
const int iNumBytesIn, const int iNumBytesIn,
@ -205,17 +211,18 @@ protected:
const CVector<uint8_t>& vecData, const CVector<uint8_t>& vecData,
const CHostAddress& InetAddr ); const CHostAddress& InetAddr );
bool EvaluateJitBufMes ( const CVector<uint8_t>& vecData ); bool EvaluateJitBufMes ( const CVector<uint8_t>& vecData );
bool EvaluateReqJitBufMes(); bool EvaluateReqJitBufMes();
bool EvaluateChanGainMes ( const CVector<uint8_t>& vecData ); bool EvaluateChanGainMes ( const CVector<uint8_t>& vecData );
bool EvaluateConClientListMes ( const CVector<uint8_t>& vecData ); bool EvaluateConClientListMes ( const CVector<uint8_t>& vecData );
bool EvaluateReqConnClientsList(); bool EvaluateReqConnClientsList();
bool EvaluateChanInfoMes ( const CVector<uint8_t>& vecData ); bool EvaluateChanInfoMes ( const CVector<uint8_t>& vecData );
bool EvaluateReqChanInfoMes(); bool EvaluateReqChanInfoMes();
bool EvaluateChatTextMes ( const CVector<uint8_t>& vecData ); bool EvaluateChatTextMes ( const CVector<uint8_t>& vecData );
bool EvaluateNetwTranspPropsMes ( const CVector<uint8_t>& vecData ); bool EvaluateNetwTranspPropsMes ( const CVector<uint8_t>& vecData );
bool EvaluateReqNetwTranspPropsMes(); bool EvaluateReqNetwTranspPropsMes();
bool EvaluateLicenceRequiredMes ( const CVector<uint8_t>& vecData ); bool EvaluateLicenceRequiredMes ( const CVector<uint8_t>& vecData );
bool EvaluateReqChannelLevelListMes ( const CVector<uint8_t>& vecData );
bool EvaluateCLPingMes ( const CHostAddress& InetAddr, bool EvaluateCLPingMes ( const CHostAddress& InetAddr,
const CVector<uint8_t>& vecData ); const CVector<uint8_t>& vecData );
@ -236,6 +243,8 @@ protected:
bool EvaluateCLConnClientsListMes ( const CHostAddress& InetAddr, bool EvaluateCLConnClientsListMes ( const CHostAddress& InetAddr,
const CVector<uint8_t>& vecData ); const CVector<uint8_t>& vecData );
bool EvaluateCLReqConnClientsListMes ( const CHostAddress& InetAddr ); bool EvaluateCLReqConnClientsListMes ( const CHostAddress& InetAddr );
bool EvaluateCLChannelLevelListMes ( const CHostAddress& InetAddr,
const CVector<uint8_t>& vecData );
int iOldRecID; int iOldRecID;
int iOldRecCnt; int iOldRecCnt;
@ -270,6 +279,7 @@ signals:
void NetTranspPropsReceived ( CNetworkTransportProps NetworkTransportProps ); void NetTranspPropsReceived ( CNetworkTransportProps NetworkTransportProps );
void ReqNetTranspProps(); void ReqNetTranspProps();
void LicenceRequired ( ELicenceType eLicenceType ); void LicenceRequired ( ELicenceType eLicenceType );
void ReqChannelLevelList ( bool bOptIn );
void CLPingReceived ( CHostAddress InetAddr, void CLPingReceived ( CHostAddress InetAddr,
int iMs ); int iMs );
@ -291,4 +301,6 @@ signals:
void CLConnClientsListMesReceived ( CHostAddress InetAddr, void CLConnClientsListMesReceived ( CHostAddress InetAddr,
CVector<CChannelInfo> vecChanInfo ); CVector<CChannelInfo> vecChanInfo );
void CLReqConnClientsList ( CHostAddress InetAddr ); void CLReqConnClientsList ( CHostAddress InetAddr );
void CLChannelLevelListReceived ( CHostAddress InetAddr,
CVector<uint16_t> vecLevelList );
}; };

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 41 KiB

After

Width:  |  Height:  |  Size: 60 KiB

View file

@ -81,11 +81,11 @@ The reverberation effect requires significant CPU so that it should only be used
level fader is set to minimum (which is the default setting), the reverberation effect is switched off and does level fader is set to minimum (which is the default setting), the reverberation effect is switched off and does
not cause any additional CPU usage. not cause any additional CPU usage.
### Local audio input fader ### Local audio pan / balance control
![Local audio input fader](audiofader.jpg) ![Local audio pan / balance control](audiofader.jpg)
With the audio fader, the relative levels of the left and right local audio channels can be changed. For a mono signal With the balance control, the relative levels of the left and right local audio channels can be changed. For a mono signal
it acts like a panning between the two channels. If, e.g., a microphone is connected to the right input channel and it acts like a panning between the two channels. If, e.g., a microphone is connected to the right input channel and
an instrument is connected to the left input channel which is much louder than the microphone, move the audio fader an instrument is connected to the left input channel which is much louder than the microphone, move the audio fader
in a direction where the label above the fader shows L -x, where x is the current attenuation indicator. in a direction where the label above the fader shows L -x, where x is the current attenuation indicator.
@ -94,11 +94,13 @@ in a direction where the label above the fader shows L -x, where x is the curren
![Audio faders](faders.jpg) ![Audio faders](faders.jpg)
In the audio mixer frame, a fader for each connected client at the server is shown. This includes a fader for the own signal. In the audio mixer frame, a fader is shown for each connected client at the server, including yourself.
With the faders, the audio level of each client can be modified individually. The faders allow you to adjust the level of what you hear without affecting what others hear.
The VU meter shows the input level at the server - that is, what you are sending.
With the Mute checkbox, the current audio channel can be muted. With the Solo checkbox, the current audio channel can Using the Mute checkbox prevents the indicated channel being heard in your local mix.
be set to solo which means that all other channels except of the current channel are muted.
The solo checkboxes allow you to hear only one, or several, channels, with those not soloed being muted.
Settings Window Settings Window
--------------- ---------------
@ -206,6 +208,12 @@ that client was already stored.
If enabled, a fancy skin will be applied to the main window. If enabled, a fancy skin will be applied to the main window.
### Display channel levels
![Display channel levels](displaychannellevels.png)
If enabled, the channel input level for each connected client will be displayed in the mixer.
### Central server address ### Central server address
![Central server address](centralserveraddress.png) ![Central server address](centralserveraddress.png)

Binary file not shown.

Before

Width:  |  Height:  |  Size: 54 KiB

After

Width:  |  Height:  |  Size: 71 KiB

View file

@ -335,6 +335,8 @@ CServer::CServer ( const int iNewMaxNumChan,
// allocate worst case memory for the coded data // allocate worst case memory for the coded data
vecbyCodedData.Init ( MAX_SIZE_BYTES_NETW_BUF ); vecbyCodedData.Init ( MAX_SIZE_BYTES_NETW_BUF );
// allocate worst case memory for the channel levels
vecChannelLevels.Init ( iMaxNumChannels );
// enable history graph (if requested) // enable history graph (if requested)
if ( !strHistoryFileName.isEmpty() ) if ( !strHistoryFileName.isEmpty() )
@ -864,6 +866,7 @@ JitterMeas.Measure();
// some inits // some inits
int iNumClients = 0; // init connected client counter int iNumClients = 0; // init connected client counter
bool bChannelIsNowDisconnected = false; bool bChannelIsNowDisconnected = false;
bool bSendChannelLevels = false;
// Make put and get calls thread safe. Do not forget to unlock mutex // Make put and get calls thread safe. Do not forget to unlock mutex
// afterwards! // afterwards!
@ -1007,6 +1010,29 @@ JitterMeas.Measure();
// one client is connected. // one client is connected.
if ( iNumClients > 0 ) if ( iNumClients > 0 )
{ {
// Low frequency updates
if ( iFrameCount > CHANNEL_LEVEL_UPDATE_INTERVAL )
{
iFrameCount = 0;
// Calculate channel levels if any client has requested them
for ( int i = 0; i < iNumClients; i++ )
{
if ( vecChannels[ vecChanIDsCurConChan[i] ].ChannelLevelsRequired() )
{
bSendChannelLevels = true;
CreateLevelsForAllConChannels ( iNumClients,
vecNumAudioChannels,
vecvecsData,
vecChannelLevels );
break;
}
}
}
iFrameCount++;
for ( int i = 0; i < iNumClients; i++ ) for ( int i = 0; i < iNumClients; i++ )
{ {
// get actual ID of current channel // get actual ID of current channel
@ -1095,6 +1121,12 @@ opus_custom_encoder_ctl ( CurOpusEncoder,
// update socket buffer size // update socket buffer size
vecChannels[iCurChanID].UpdateSocketBufferSize(); vecChannels[iCurChanID].UpdateSocketBufferSize();
// send channel levels
if ( bSendChannelLevels && vecChannels[iCurChanID].ChannelLevelsRequired() )
{
ConnLessProtocol.CreateCLChannelLevelListMes ( vecChannels[iCurChanID].GetAddress(), vecChannelLevels, iNumClients );
}
} }
} }
else else
@ -1574,3 +1606,69 @@ void CServer::customEvent ( QEvent* pEvent )
} }
} }
} }
/// @brief Compute frame peak level for each client
void CServer::CreateLevelsForAllConChannels ( const int iNumClients,
const CVector<int>& vecNumAudioChannels,
const CVector<CVector<int16_t> > vecvecsData,
CVector<uint16_t>& vecLevelsOut )
{
int i, j, k;
// init return vector with zeros since we mix all channels on that vector
vecLevelsOut.Reset ( 0 );
for ( j = 0; j < iNumClients; j++ )
{
// get a reference to the audio data
const CVector<int16_t>& vecsData = vecvecsData[j];
double dCurLevel = 0.0;
if ( vecNumAudioChannels[j] == 1 )
{
// mono
for ( i = 0; i < SYSTEM_FRAME_SIZE_SAMPLES; i += 3 )
{
dCurLevel = std::max ( dCurLevel, std::abs ( static_cast<double> ( vecsData[i] ) ) );
}
}
else
{
// stereo: apply stereo-to-mono attenuation
for ( i = 0, k = 0; i < SYSTEM_FRAME_SIZE_SAMPLES; i += 3, k += 6 )
{
double sMix = ( static_cast<double> ( vecsData[k] ) + vecsData[k + 1] ) / 2;
dCurLevel = std::max ( dCurLevel, std::abs ( sMix ) );
}
}
// smoothing
int iChId = vecChanIDsCurConChan [ j ];
dCurLevel = std::max ( dCurLevel, vecChannels[ iChId ].GetPrevLevel() * 0.5 );
vecChannels[ iChId ].SetPrevLevel ( dCurLevel );
// logarithmic measure
const double dNormChanLevel = dCurLevel / _MAXSHORT;
double dCurSigLevel;
if ( dNormChanLevel > 0 )
{
dCurSigLevel = 20.0 * log10 ( dNormChanLevel );
}
else
{
dCurSigLevel = -100000.0; // large negative value
}
// map to signal level meter
dCurSigLevel -= LOW_BOUND_SIG_METER;
dCurSigLevel *= NUM_STEPS_LED_BAR /
( UPPER_BOUND_SIG_METER - LOW_BOUND_SIG_METER );
if ( dCurSigLevel < 0 )
{
dCurSigLevel = 0;
}
vecLevelsOut[j] = static_cast<uint16_t> ( ceil ( dCurSigLevel ) );
}
}

View file

@ -28,6 +28,7 @@
#include <QTimer> #include <QTimer>
#include <QDateTime> #include <QDateTime>
#include <QHostAddress> #include <QHostAddress>
#include <algorithm>
#ifdef USE_OPUS_SHARED_LIB #ifdef USE_OPUS_SHARED_LIB
# include "opus/opus_custom.h" # include "opus/opus_custom.h"
#else #else
@ -225,6 +226,11 @@ protected:
// if server mode is normal or double system frame size // if server mode is normal or double system frame size
bool bUseDoubleSystemFrameSize; bool bUseDoubleSystemFrameSize;
void CreateLevelsForAllConChannels ( const int iNumClients,
const CVector<int>& vecNumAudioChannels,
const CVector<CVector<int16_t> > vecvecsData,
CVector<uint16_t>& vecLevelsOut );
// do not use the vector class since CChannel does not have appropriate // do not use the vector class since CChannel does not have appropriate
// copy constructor/operator // copy constructor/operator
CChannel vecChannels[MAX_NUM_CHANNELS]; CChannel vecChannels[MAX_NUM_CHANNELS];
@ -255,12 +261,18 @@ protected:
CVector<int16_t> vecsSendData; CVector<int16_t> vecsSendData;
CVector<uint8_t> vecbyCodedData; CVector<uint8_t> vecbyCodedData;
// Channel levels
CVector<uint16_t> vecChannelLevels;
// actual working objects // actual working objects
CHighPrioSocket Socket; CHighPrioSocket Socket;
// logging // logging
CServerLogging Logging; CServerLogging Logging;
// channel level update frame interval counter
uint16_t iFrameCount;
// recording thread // recording thread
recorder::CJamRecorder JamRecorder; recorder::CJamRecorder JamRecorder;
bool bEnableRecording; bool bEnableRecording;

View file

@ -250,6 +250,12 @@ void CSettings::Load()
pClient->SetGUIDesign ( static_cast<EGUIDesign> ( iValue ) ); pClient->SetGUIDesign ( static_cast<EGUIDesign> ( iValue ) );
} }
// display channel levels preference
if ( GetFlagIniSet ( IniXMLDocument, "client", "displaychannellevels", bValue ) )
{
pClient->SetDisplayChannelLevels ( bValue );
}
// audio channels // audio channels
if ( GetNumericIniSet ( IniXMLDocument, "client", "audiochannels", if ( GetNumericIniSet ( IniXMLDocument, "client", "audiochannels",
0, 2 /* CC_STEREO */, iValue ) ) 0, 2 /* CC_STEREO */, iValue ) )
@ -490,6 +496,10 @@ void CSettings::Save()
SetNumericIniSet ( IniXMLDocument, "client", "guidesign", SetNumericIniSet ( IniXMLDocument, "client", "guidesign",
static_cast<int> ( pClient->GetGUIDesign() ) ); static_cast<int> ( pClient->GetGUIDesign() ) );
// display channel levels preference
SetFlagIniSet ( IniXMLDocument, "client", "displaychannellevels",
pClient->GetDisplayChannelLevels() );
// audio channels // audio channels
SetNumericIniSet ( IniXMLDocument, "client", "audiochannels", SetNumericIniSet ( IniXMLDocument, "client", "audiochannels",
static_cast<int> ( pClient->GetAudioChannels() ) ); static_cast<int> ( pClient->GetAudioChannels() ) );