diff --git a/src/audiomixerboard.cpp b/src/audiomixerboard.cpp
index 62221cd0..1737c6d9 100755
--- a/src/audiomixerboard.cpp
+++ b/src/audiomixerboard.cpp
@@ -84,10 +84,10 @@ CChannelFader::CChannelFader ( QWidget* pNW,
"Only one channel at a time can be set to solo." );
pcbSolo->setAccessibleName ( "Solo button" );
- pLabel->setWhatsThis ( "Mixer Fader Label: Label (fader tag) "
- "identifying the connected client. The tag name can be set in the "
- "clients main window." );
- pLabel->setAccessibleName ( "Mixer level label (fader tag)" );
+ pLabel->setWhatsThis ( "Fader Tag: The fader tag "
+ "identifies the connected client. The tag name can be set in the "
+ "main window." );
+ pLabel->setAccessibleName ( "Mixer channel label (fader tag)" );
// Connections -------------------------------------------------------------
diff --git a/src/chatdlg.cpp b/src/chatdlg.cpp
index 7f1c53c5..eb95ce2b 100755
--- a/src/chatdlg.cpp
+++ b/src/chatdlg.cpp
@@ -33,8 +33,19 @@ CChatDlg::CChatDlg ( QWidget* parent, Qt::WindowFlags f ) :
// Add help text to controls -----------------------------------------------
- edtLocalInputText->setAccessibleName ( "New chat text edit box" );
- txvChatWindow->setAccessibleName ( "Chat history" );
+ // chat window
+ txvChatWindow->setWhatsThis ( tr ( "Chat Window: The chat window "
+ "shows a history of all chat messages." ) );
+
+ txvChatWindow->setAccessibleName ( tr ( "Chat history" ) );
+
+ // input message text
+ edtLocalInputText->setWhatsThis ( tr ( "Input Message Text: Enter "
+ "the chat message text in the edit box and press enter to send the "
+ "message to the server which distributes the message to all connected "
+ "clients. Your message will then show up in the chat window." ) );
+
+ edtLocalInputText->setAccessibleName ( tr ( "New chat text edit box" ) );
// clear chat window and edit line
diff --git a/src/connectdlg.cpp b/src/connectdlg.cpp
index 9454f175..10bb7a99 100755
--- a/src/connectdlg.cpp
+++ b/src/connectdlg.cpp
@@ -39,10 +39,25 @@ CConnectDlg::CConnectDlg ( QWidget* parent, Qt::WindowFlags f )
// Add help text to controls -----------------------------------------------
+ // server list
+ lvwServers->setWhatsThis ( tr ( "Server List: The server list shows "
+ "a list of available servers which are registered at the central "
+ "server. Select a server from the list and press the connect button to "
+ "connect to this server. Alternatively, double click a server from "
+ "the list to connect to it.
"
+ "Note that it may take some time to retrieve the server list from the "
+ "central server. If no valid central server address is specified in "
+ "the settings, no server list will be available." ) );
+
+ lvwServers->setAccessibleName ( tr ( "Server list view" ) );
+
// server address
QString strServAddrH = tr ( "Server Address: The IP address or URL "
- "of the server running the llcon server software must be set here. "
- "A list of the most recent used server URLs is available for "
+ "of the server running the llcon server software must be set here. An "
+ "optional port number can be added after the IP address or URL using "
+ "a comma as a separator, e.g, " ) + DEFAULT_SERVER_ADDRESS + ":" +
+ QString().setNum ( LLCON_DEFAULT_PORT_NUMBER ) + tr ( ". A list of "
+ "the most recent used server IP addresses or URLs is available for "
"selection." );
lblServerAddr->setWhatsThis ( strServAddrH );
@@ -50,7 +65,7 @@ CConnectDlg::CConnectDlg ( QWidget* parent, Qt::WindowFlags f )
cbxServerAddr->setAccessibleName ( tr ( "Server address edit box" ) );
cbxServerAddr->setAccessibleDescription ( tr ( "Holds the current server "
- "URL. It also stores old URLs in the combo box list." ) );
+ "IP address or URL. It also stores old URLs in the combo box list." ) );
// init server address combo box (max MAX_NUM_SERVER_ADDR_ITEMS entries)
diff --git a/src/llconclientdlg.cpp b/src/llconclientdlg.cpp
index 233fbeed..19120256 100755
--- a/src/llconclientdlg.cpp
+++ b/src/llconclientdlg.cpp
@@ -1,966 +1,967 @@
-/******************************************************************************\
- * 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
- *
-\******************************************************************************/
-
-#include "llconclientdlg.h"
-
-
-/* Implementation *************************************************************/
-CLlconClientDlg::CLlconClientDlg ( CClient* pNCliP,
- const bool bNewConnectOnStartup,
- const bool bNewDisalbeLEDs,
- QWidget* parent,
- Qt::WindowFlags f ) :
- QDialog ( parent, f ),
- pClient ( pNCliP ),
- bUnreadChatMessage ( false ),
- ClientSettingsDlg ( pNCliP, parent, Qt::Window ),
- ChatDlg ( parent, Qt::Window ),
- ConnectDlg ( parent, Qt::Dialog )
-{
- setupUi ( this );
-
-
- // Add help text to controls -----------------------------------------------
- // input level meter
- QString strInpLevH = tr ( "Input Level Meter: The input level "
- "indicators show the current input level of the two stereo channels "
- "of the current selected audio input. The upper level display belongs "
- "to the left channel and the lower level display to the right channel "
- "of the audio input.
"
- "Make sure not to clip the input signal to avoid distortions of the "
- "audio signal." );
-
- QString strInpLevHTT = tr ( "If the llcon software is connected and "
- "you play your instrument/sing in the microphone, the LED level "
- "meter should flicker. If this is not the case, you have "
- "probably selected the wrong input channel (e.g. line in instead "
- "of the microphone input) or set the input gain too low in the "
- "(Windows) audio mixer.
For a proper usage of the llcon software, "
- "you should not hear your singing/instrument in the loudspeaker or "
- "your headphone when the llcon software is not connected. This can "
- "be achieved by muting your input audio channel in the Playback "
- "mixer (not the Recording mixer!)." ) + TOOLTIP_COM_END_TEXT;
-
- QString strInpLevHAccText = tr ( "Input level meter" );
- QString strInpLevHAccDescr = tr ( "Simulates an analog LED level meter." );
-
- lblInputLEDMeter->setWhatsThis ( strInpLevH );
- lblLevelMeterLeft->setWhatsThis ( strInpLevH );
- lblLevelMeterRight->setWhatsThis ( strInpLevH );
- lbrInputLevelL->setWhatsThis ( strInpLevH );
- lbrInputLevelL->setAccessibleName ( strInpLevHAccText );
- lbrInputLevelL->setAccessibleDescription ( strInpLevHAccDescr );
- lbrInputLevelL->setToolTip ( strInpLevHTT );
- lbrInputLevelR->setWhatsThis ( strInpLevH );
- lbrInputLevelR->setAccessibleName ( strInpLevHAccText );
- lbrInputLevelR->setAccessibleDescription ( strInpLevHAccDescr );
- lbrInputLevelR->setToolTip ( strInpLevHTT );
-
- // connect/disconnect button
- butConnect->setWhatsThis ( tr ( "Connect / Disconnect Button:"
- " Push this button to connect the server. A valid IP address has "
- "to be specified before. If the client is connected, pressing this "
- "button will disconnect the connection." ) );
-
- butConnect->setAccessibleName (
- tr ( "Connect and disconnect toggle button" ) );
-
- butConnect->setAccessibleDescription ( tr ( "Clicking on this "
- "button changes the caption of the button from Connect to "
- "Disconnect, i.e., it implements a toggle functionality for connecting "
- "and disconnecting the llcon software." ) );
-
- // fader tag
- QString strFaderTag = tr ( "Fader Tag: The fader tag of the local "
- "client is set in the fader tag edit box. This tag will appear "
- "at your fader on the mixer board when you are connected to a llcon "
- "server. This tag will also show up at each client which is connected "
- "to the same server as the local client. If the fader tag is empty, "
- "the IP address of the client is displayed instead." );
-
- QString strFaderTagTT = tr ( "Set your name and/or instrument and/or "
- "pseoudonym here so that the other musicians can identify you." ) +
- TOOLTIP_COM_END_TEXT;
-
- lblServerTag->setWhatsThis ( strFaderTag );
- lblServerTag->setToolTip ( strFaderTagTT );
- edtFaderTag->setWhatsThis ( strFaderTag );
- edtFaderTag->setToolTip ( strFaderTagTT );
-
- edtFaderTag->setAccessibleName ( tr ( "Fader tag edit box" ) );
-
- // local audio input fader
- QString strAudFader = tr ( "Local Audio Input Fader: With the "
- "audio fader, the relative levels of the left and right local audio "
- "channels can be changed. 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 in "
- "a direction where the label above the fader shows L -x, where "
- "x is the current attenuation indication. " );
-
- lblAudioPan->setWhatsThis ( strAudFader );
- sldAudioPan->setWhatsThis ( strAudFader );
-
- sldAudioPan->setAccessibleName ( tr ( "Local audio input fader (left/right)" ) );
-
- // reverberation level
- QString strAudReverb = tr ( "Reverberation Level: A reverberation "
- "effect can be applied to one local audio channel. The channel "
- "selection and the reverberation level can be modified. If, e.g., "
- "the microphone signal is fed into the right audio channel of the "
- "sound card and a reverberation effect shall be applied, set the "
- "channel selector to right and move the fader upwards until the "
- "desired reverberation level is reached.
"
- "The reverberation effect requires significant CPU so that it should "
- "only be used on fast PCs. If the reverberation 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." );
-
- lblAudioReverb->setWhatsThis ( strAudReverb );
- sldAudioReverb->setWhatsThis ( strAudReverb );
-
- sldAudioReverb->setAccessibleName ( tr ( "Reverberation effect level setting" ) );
-
- // reverberation channel selection
- QString strRevChanSel = tr ( "Reverberation Channel Selection: "
- "With these radio buttons the audio input channel on which the "
- "reverberation effect is applied can be chosen. Either the left "
- "or right input channel can be selected." );
-
- rbtReverbSelL->setWhatsThis ( strRevChanSel );
- rbtReverbSelL->setAccessibleName ( tr ( "Left channel selection for reverberation" ) );
- rbtReverbSelR->setWhatsThis ( strRevChanSel );
- rbtReverbSelR->setAccessibleName ( tr ( "Right channel selection for reverberation" ) );
-
- // connection LED
- QString strLEDConnection = tr ( "Connection Status LED: "
- "The connection status LED indicator shows the current connection "
- "status. If the light is green, a successful connection to the "
- "server is established. If the light blinks red right after "
- "pressing the connect button, the server address is invalid. "
- "If the light turns red and stays red, the connection to the "
- "server is lost." );
-
- lblConnection->setWhatsThis ( strLEDConnection );
- ledConnection->setWhatsThis ( strLEDConnection );
-
- ledConnection->setAccessibleName ( tr ( "Connection status LED indicator" ) );
-
- // delay LED
- QString strLEDDelay = tr ( "Delay Status LED: "
- "The delay status LED indicator shows the current audio delay "
- "status. If the light is green, the delay is perfect for a jam "
- "session. If the ligth is yellow, a session is still possible but "
- "it may be harder to play. If the light is red, the delay is too "
- "large for jamming." );
-
- lblDelay->setWhatsThis ( strLEDDelay );
- ledDelay->setWhatsThis ( strLEDDelay );
- ledDelay->setToolTip ( tr ( "If this LED indicator turns red, "
- "you will not have much fun using the llcon software." ) +
- TOOLTIP_COM_END_TEXT );
-
- ledDelay->setAccessibleName ( tr ( "Delay status LED indicator" ) );
-
- // buffers LED
- QString strLEDBuffers = tr ( "Buffers Status LED: "
- "The buffers status LED indicator shows the current audio/streaming "
- "status. If the light is green, there are no buffer overruns/underruns "
- "and the audio stream is not interrupted. If the light is red, the "
- "audio stream is interrupted caused by one of the following problems:"
- "
"
- "- The network jitter buffer is not large enough for the current "
- "network/audio interface jitter.
"
- "- The sound card buffer delay (buffer size) is set to a too small "
- "value.
"
- "- The upload or download stream rate is too high for the current "
- "available internet bandwidth.
"
- "- The CPU of the client or server is at 100%.
"
- "
" );
-
- lblBuffers->setWhatsThis ( strLEDBuffers );
- ledBuffers->setWhatsThis ( strLEDBuffers );
-
- ledBuffers->setAccessibleName ( tr ( "Buffers status LED indicator" ) );
-
- // chat LED
- QString strLEDChat = tr ( "Chat Status LED: "
- "If the option Open Chat on New Message is not activated, this "
- "status LED will turn green on a new received chat message." );
-
- lblChat->setWhatsThis ( strLEDChat );
- ledChat->setWhatsThis ( strLEDChat );
-
- ledBuffers->setAccessibleName ( tr ( "Chat status LED indicator" ) );
-
-
- // init GUI design
- SetGUIDesign ( pClient->GetGUIDesign() );
-
- // reset mixer board
- MainMixerBoard->HideAll();
-
- // init fader tag line edit
- edtFaderTag->setText ( pClient->strName );
-
- // init status label
- OnTimerStatus();
-
- // init connection button text
- butConnect->setText ( CON_BUT_CONNECTTEXT );
-
- // init input level meter bars
- lbrInputLevelL->setValue ( 0 );
- lbrInputLevelR->setValue ( 0 );
-
- // init status LEDs
- ledConnection->SetUpdateTime ( 2 * LED_BAR_UPDATE_TIME_MS );
- ledChat->SetUpdateTime ( 2 * LED_BAR_UPDATE_TIME_MS );
- ledDelay->SetUpdateTime ( 2 * PING_UPDATE_TIME_MS );
- ledDelay->Reset();
-
-
- // init slider controls ---
- // audio in fader
- sldAudioPan->setRange ( AUD_FADER_IN_MIN, AUD_FADER_IN_MAX );
- sldAudioPan->setTickInterval ( AUD_FADER_IN_MAX / 5 );
- UpdateAudioFaderSlider();
-
- // audio reverberation
- sldAudioReverb->setRange ( 0, AUD_REVERB_MAX );
- const int iCurAudReverb = pClient->GetReverbLevel();
- sldAudioReverb->setValue ( iCurAudReverb );
- sldAudioReverb->setTickInterval ( AUD_REVERB_MAX / 5 );
-
- // init reverb channel
- UpdateRevSelection();
-
-
- // connect on startup ---
- if ( bNewConnectOnStartup )
- {
- // since the software starts up right now, the previous state was
- // "not connected" so that a call to "OnConnectDisconBut()" will
- // start the connection
- OnConnectDisconBut();
- }
-
-
- // disable controls on request ---
- // disable LEDs in main window if requested
- if ( bNewDisalbeLEDs )
- {
- lbrInputLevelL->setEnabled ( false );
- lbrInputLevelR->setEnabled ( false );
- ledConnection->setEnabled ( false );
- ledBuffers->setEnabled ( false );
- ledDelay->setEnabled ( false );
- ledChat->setEnabled ( false );
- butConnect->setFocus();
- }
-
-
- // Mac Workaround:
- // If the connect button is the default button, on Mac it is highlighted
- // by fading in and out a blue backgroud color. This operation consumes so
- // much CPU that we get audio interruptions.
- // Better solution: increase thread priority of worker thread (since the
- // user can always highlight the button manually, too) -> TODO
-#if defined ( __APPLE__ ) || defined ( __MACOSX )
- butConnect->setDefault ( false );
-#endif
-
-
- // View menu --------------------------------------------------------------
- pViewMenu = new QMenu ( "&View", this );
-
- pViewMenu->addAction ( tr ( "&Chat..." ), this,
- SLOT ( OnOpenChatDialog() ) );
-
- pViewMenu->addAction ( tr ( "&General Settings..." ), this,
- SLOT ( OnOpenGeneralSettings() ) );
-
- pViewMenu->addSeparator();
-
- pViewMenu->addAction ( tr ( "E&xit" ), this,
- SLOT ( close() ), QKeySequence ( Qt::CTRL + Qt::Key_Q ) );
-
-
- // Main menu bar -----------------------------------------------------------
- pMenu = new QMenuBar ( this );
-
- pMenu->addMenu ( pViewMenu );
- pMenu->addMenu ( new CLlconHelpMenu ( this ) );
-
- // Now tell the layout about the menu
- layout()->setMenuBar ( pMenu );
-
-
- // Connections -------------------------------------------------------------
- // push-buttons
- QObject::connect ( butConnect, SIGNAL ( clicked() ),
- this, SLOT ( OnConnectDisconBut() ) );
-
- // timers
- QObject::connect ( &TimerSigMet, SIGNAL ( timeout() ),
- this, SLOT ( OnTimerSigMet() ) );
-
- QObject::connect ( &TimerStatus, SIGNAL ( timeout() ),
- this, SLOT ( OnTimerStatus() ) );
-
- QObject::connect ( &TimerPing, SIGNAL ( timeout() ),
- this, SLOT ( OnTimerPing() ) );
-
- // sliders
- QObject::connect ( sldAudioPan, SIGNAL ( valueChanged ( int ) ),
- this, SLOT ( OnAudioPanValueChanged ( int ) ) );
-
- QObject::connect ( sldAudioReverb, SIGNAL ( valueChanged ( int ) ),
- this, SLOT ( OnAudioReverbValueChanged ( int ) ) );
-
- // radio buttons
- QObject::connect ( rbtReverbSelL, SIGNAL ( clicked() ),
- this, SLOT ( OnReverbSelLClicked() ) );
-
- QObject::connect ( rbtReverbSelR, SIGNAL ( clicked() ),
- this, SLOT ( OnReverbSelRClicked() ) );
-
- // line edits
- QObject::connect ( edtFaderTag, SIGNAL ( textChanged ( const QString& ) ),
- this, SLOT ( OnFaderTagTextChanged ( const QString& ) ) );
-
- // other
- QObject::connect ( pClient,
- SIGNAL ( ConClientListMesReceived ( CVector ) ),
- this, SLOT ( OnConClientListMesReceived ( CVector ) ) );
-
- QObject::connect ( pClient,
- SIGNAL ( Disconnected() ),
- this, SLOT ( OnDisconnected() ) );
-
- QObject::connect ( pClient,
- SIGNAL ( ChatTextReceived ( QString ) ),
- this, SLOT ( OnChatTextReceived ( QString ) ) );
-
- QObject::connect ( pClient, SIGNAL ( PingTimeReceived ( int ) ),
- this, SLOT ( OnPingTimeResult ( int ) ) );
-
- QObject::connect ( pClient,
- SIGNAL ( CLServerListReceived ( CHostAddress, CVector ) ),
- this, SLOT ( OnCLServerListReceived ( CHostAddress, CVector ) ) );
-
- QObject::connect ( pClient,
- SIGNAL ( CLPingTimeWithNumClientsReceived ( CHostAddress, int, int ) ),
- this, SLOT ( OnCLPingTimeWithNumClientsReceived ( CHostAddress, int, int ) ) );
-
- QObject::connect ( &ClientSettingsDlg, SIGNAL ( GUIDesignChanged() ),
- this, SLOT ( OnGUIDesignChanged() ) );
-
- QObject::connect ( &ClientSettingsDlg, SIGNAL ( StereoCheckBoxChanged() ),
- this, SLOT ( OnStereoCheckBoxChanged() ) );
-
- QObject::connect ( MainMixerBoard, SIGNAL ( ChangeChanGain ( int, double ) ),
- this, SLOT ( OnChangeChanGain ( int, double ) ) );
-
- QObject::connect ( MainMixerBoard, SIGNAL ( NumClientsChanged ( int ) ),
- this, SLOT ( OnNumClientsChanged ( int ) ) );
-
- QObject::connect ( &ChatDlg, SIGNAL ( NewLocalInputText ( QString ) ),
- this, SLOT ( OnNewLocalInputText ( QString ) ) );
-
- QObject::connect ( &ConnectDlg, SIGNAL ( ReqServerListQuery ( CHostAddress ) ),
- this, SLOT ( OnReqServerListQuery ( CHostAddress ) ) );
-
- QObject::connect ( &ConnectDlg, SIGNAL ( CreateCLPingMes ( CHostAddress ) ),
- this, SLOT ( OnCreateCLPingMes ( CHostAddress ) ) );
-
-
- // Timers ------------------------------------------------------------------
- // start timer for status bar
- TimerStatus.start ( LED_BAR_UPDATE_TIME_MS );
-}
-
-void CLlconClientDlg::closeEvent ( QCloseEvent* Event )
-{
- // if settings/connect dialog or chat dialog is open, close it
- ClientSettingsDlg.close();
- ConnectDlg.close();
- ChatDlg.close();
-
- // if connected, terminate connection
- if ( pClient->IsRunning() )
- {
- pClient->Stop();
- }
-
- // store fader tag
- pClient->strName = edtFaderTag->text();
-
- // default implementation of this event handler routine
- Event->accept();
-}
-
-void CLlconClientDlg::UpdateAudioFaderSlider()
-{
- // update slider and label of audio fader
- const int iCurAudInFader = pClient->GetAudioInFader();
- sldAudioPan->setValue ( iCurAudInFader );
-
- // show in label the center position and what channel is
- // attenuated
- if ( iCurAudInFader == AUD_FADER_IN_MIDDLE )
- {
- lblAudioPanValue->setText ( "Center" );
- }
- else
- {
- if ( iCurAudInFader > AUD_FADER_IN_MIDDLE )
- {
- // attenuation on right channel
- lblAudioPanValue->setText ( "R -" +
- QString().setNum ( iCurAudInFader - AUD_FADER_IN_MIDDLE ) );
- }
- else
- {
- // attenuation on left channel
- lblAudioPanValue->setText ( "L -" +
- QString().setNum ( AUD_FADER_IN_MIDDLE - iCurAudInFader ) );
- }
- }
-}
-
-void CLlconClientDlg::UpdateRevSelection()
-{
- if ( pClient->GetUseStereo() )
- {
- // for stereo make channel selection invisible since
- // reverberation effect is always applied to both channels
- rbtReverbSelL->setVisible ( false );
- rbtReverbSelR->setVisible ( false );
- }
- else
- {
- // make radio buttons visible
- rbtReverbSelL->setVisible ( true );
- rbtReverbSelR->setVisible ( true );
-
- // update value
- if ( pClient->IsReverbOnLeftChan() )
- {
- rbtReverbSelL->setChecked ( true );
- }
- else
- {
- rbtReverbSelR->setChecked ( true );
- }
- }
-}
-
-void CLlconClientDlg::OnAudioPanValueChanged ( int value )
-{
- pClient->SetAudioInFader ( value );
- UpdateAudioFaderSlider();
-}
-
-void CLlconClientDlg::OnConnectDisconBut()
-{
- // the connect/disconnect button implements a toggle functionality
- // -> apply inverted running state
- ConnectDisconnect ( !pClient->IsRunning() );
-}
-
-void CLlconClientDlg::OnOpenGeneralSettings()
-{
- // open general settings dialog
- ClientSettingsDlg.show();
-
- // make sure dialog is upfront and has focus
- ClientSettingsDlg.raise();
- ClientSettingsDlg.activateWindow();
-}
-
-void CLlconClientDlg::OnChatTextReceived ( QString strChatText )
-{
- // init flag (will maybe overwritten later in this function)
- bUnreadChatMessage = false;
-
- ChatDlg.AddChatText ( strChatText );
-
- // if requested, open window
- if ( pClient->GetOpenChatOnNewMessage() )
- {
- ShowChatWindow();
- }
- else
- {
- if ( !ChatDlg.isVisible() )
- {
- bUnreadChatMessage = true;
- }
- }
-
- UpdateDisplay();
-}
-
-void CLlconClientDlg::OnDisconnected()
-{
- // channel is now disconnected, clear mixer board (remove all faders)
- MainMixerBoard->HideAll();
-
- UpdateDisplay();
-}
-
-void CLlconClientDlg::OnConClientListMesReceived ( CVector vecChanInfo )
-{
- // update mixer board
- MainMixerBoard->ApplyNewConClientList ( vecChanInfo );
-}
-
-void CLlconClientDlg::OnNumClientsChanged ( int iNewNumClients )
-{
- // update window title
- SetMyWindowTitle ( iNewNumClients );
-}
-
-void CLlconClientDlg::SetMyWindowTitle ( const int iNumClients )
-{
- // show number of connected clients in window title (and therefore also in
- // the task bar of the OS)
- if ( iNumClients == 0 )
- {
- // only application name
- setWindowTitle ( APP_NAME );
- }
- else
- {
- if ( iNumClients == 1 )
- {
- setWindowTitle ( QString ( APP_NAME ) + " (1 user)" );
- }
- else
- {
- setWindowTitle ( QString ( APP_NAME ) +
- QString ( " (%1 users)" ).arg ( iNumClients ) );
- }
- }
-}
-
-void CLlconClientDlg::ShowChatWindow()
-{
- // open chat dialog
- ChatDlg.show();
-
- // make sure dialog is upfront and has focus
- ChatDlg.raise();
- ChatDlg.activateWindow();
-
- // chat dialog is opened, reset unread message flag
- bUnreadChatMessage = false;
-
- UpdateDisplay();
-}
-
-void CLlconClientDlg::OnFaderTagTextChanged ( const QString& strNewName )
-{
- // check length
- if ( strNewName.length() <= MAX_LEN_FADER_TAG )
- {
- // refresh internal name parameter
- pClient->strName = strNewName;
-
- // update name at server
- pClient->SetRemoteName();
- }
- else
- {
- // text is too long, update control with shortend text
- edtFaderTag->setText ( strNewName.left ( MAX_LEN_FADER_TAG ) );
- }
-}
-
-void CLlconClientDlg::OnTimerSigMet()
-{
- // get current input levels
- double dCurSigLevelL = pClient->MicLevelL();
- double dCurSigLevelR = pClient->MicLevelR();
-
- // linear transformation of the input level range to the progress-bar
- // range
- dCurSigLevelL -= LOW_BOUND_SIG_METER;
- dCurSigLevelL *= NUM_STEPS_INP_LEV_METER /
- ( UPPER_BOUND_SIG_METER - LOW_BOUND_SIG_METER );
-
- // lower bound the signal
- if ( dCurSigLevelL < 0 )
- {
- dCurSigLevelL = 0;
- }
-
- dCurSigLevelR -= LOW_BOUND_SIG_METER;
- dCurSigLevelR *= NUM_STEPS_INP_LEV_METER /
- ( UPPER_BOUND_SIG_METER - LOW_BOUND_SIG_METER );
-
- // lower bound the signal
- if ( dCurSigLevelR < 0 )
- {
- dCurSigLevelR = 0;
- }
-
- // show current level
- lbrInputLevelL->setValue ( (int) ceil ( dCurSigLevelL ) );
- lbrInputLevelR->setValue ( (int) ceil ( dCurSigLevelR ) );
-}
-
-void CLlconClientDlg::OnTimerPing()
-{
- // send ping message to server
- pClient->CreatePingMes();
-}
-
-void CLlconClientDlg::OnPingTimeResult ( int iPingTime )
-{
- // calculate overall delay
- const int iOverallDelayMs = pClient->EstimatedOverallDelay ( iPingTime );
-
- // color definition: <= 40 ms green, <= 65 ms yellow, otherwise red
- int iOverallDelayLEDColor;
- if ( iOverallDelayMs <= 40 )
- {
- iOverallDelayLEDColor = MUL_COL_LED_GREEN;
- }
- else
- {
- if ( iOverallDelayMs <= 65 )
- {
- iOverallDelayLEDColor = MUL_COL_LED_YELLOW;
- }
- else
- {
- iOverallDelayLEDColor = MUL_COL_LED_RED;
- }
- }
-
- // only update delay information on settings dialog if it is visible to
- // avoid CPU load on working thread if not necessary
- if ( ClientSettingsDlg.isVisible() )
- {
- // set ping time result to general settings dialog
- ClientSettingsDlg.SetPingTimeResult ( iPingTime,
- iOverallDelayMs,
- iOverallDelayLEDColor );
- }
-
- // update delay LED on the main window
- ledDelay->SetLight ( iOverallDelayLEDColor );
-}
-
-void CLlconClientDlg::OnCLPingTimeWithNumClientsReceived ( CHostAddress InetAddr,
- int iPingTime,
- int iNumClients )
-{
- // color definition: <= 25 ms green, <= 50 ms yellow, otherwise red
- int iPingTimeLEDColor;
- if ( iPingTime <= 25 )
- {
- iPingTimeLEDColor = MUL_COL_LED_GREEN;
- }
- else
- {
- if ( iPingTime <= 50 )
- {
- iPingTimeLEDColor = MUL_COL_LED_YELLOW;
- }
- else
- {
- iPingTimeLEDColor = MUL_COL_LED_RED;
- }
- }
-
- // update connection dialog server list
- ConnectDlg.SetPingTimeAndNumClientsResult ( InetAddr,
- iPingTime,
- iPingTimeLEDColor,
- iNumClients );
-}
-
-void CLlconClientDlg::ConnectDisconnect ( const bool bDoStart )
-{
- // start/stop client, set button text
- if ( bDoStart )
- {
- // get the central server address string
+/******************************************************************************\
+ * 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
+ *
+\******************************************************************************/
+
+#include "llconclientdlg.h"
+
+
+/* Implementation *************************************************************/
+CLlconClientDlg::CLlconClientDlg ( CClient* pNCliP,
+ const bool bNewConnectOnStartup,
+ const bool bNewDisalbeLEDs,
+ QWidget* parent,
+ Qt::WindowFlags f ) :
+ QDialog ( parent, f ),
+ pClient ( pNCliP ),
+ bUnreadChatMessage ( false ),
+ ClientSettingsDlg ( pNCliP, parent, Qt::Window ),
+ ChatDlg ( parent, Qt::Window ),
+ ConnectDlg ( parent, Qt::Dialog )
+{
+ setupUi ( this );
+
+
+ // Add help text to controls -----------------------------------------------
+ // input level meter
+ QString strInpLevH = tr ( "Input Level Meter: The input level "
+ "indicators show the current input level of the two stereo channels "
+ "of the current selected audio input. The upper level display belongs "
+ "to the left channel and the lower level display to the right channel "
+ "of the audio input.
"
+ "Make sure not to clip the input signal to avoid distortions of the "
+ "audio signal." );
+
+ QString strInpLevHTT = tr ( "If the llcon software is connected and "
+ "you play your instrument/sing in the microphone, the LED level "
+ "meter should flicker. If this is not the case, you have "
+ "probably selected the wrong input channel (e.g. line in instead "
+ "of the microphone input) or set the input gain too low in the "
+ "(Windows) audio mixer.
For a proper usage of the llcon software, "
+ "you should not hear your singing/instrument in the loudspeaker or "
+ "your headphone when the llcon software is not connected. This can "
+ "be achieved by muting your input audio channel in the Playback "
+ "mixer (not the Recording mixer!)." ) + TOOLTIP_COM_END_TEXT;
+
+ QString strInpLevHAccText = tr ( "Input level meter" );
+ QString strInpLevHAccDescr = tr ( "Simulates an analog LED level meter." );
+
+ lblInputLEDMeter->setWhatsThis ( strInpLevH );
+ lblLevelMeterLeft->setWhatsThis ( strInpLevH );
+ lblLevelMeterRight->setWhatsThis ( strInpLevH );
+ lbrInputLevelL->setWhatsThis ( strInpLevH );
+ lbrInputLevelL->setAccessibleName ( strInpLevHAccText );
+ lbrInputLevelL->setAccessibleDescription ( strInpLevHAccDescr );
+ lbrInputLevelL->setToolTip ( strInpLevHTT );
+ lbrInputLevelR->setWhatsThis ( strInpLevH );
+ lbrInputLevelR->setAccessibleName ( strInpLevHAccText );
+ lbrInputLevelR->setAccessibleDescription ( strInpLevHAccDescr );
+ lbrInputLevelR->setToolTip ( strInpLevHTT );
+
+ // connect/disconnect button
+ butConnect->setWhatsThis ( tr ( "Connect / Disconnect Button:"
+ " Push this button to connect the server. A valid IP address has "
+ "to be specified before. If the client is connected, pressing this "
+ "button will disconnect the connection." ) );
+
+ butConnect->setAccessibleName (
+ tr ( "Connect and disconnect toggle button" ) );
+
+ butConnect->setAccessibleDescription ( tr ( "Clicking on this "
+ "button changes the caption of the button from Connect to "
+ "Disconnect, i.e., it implements a toggle functionality for connecting "
+ "and disconnecting the llcon software." ) );
+
+ // fader tag
+ QString strFaderTag = tr ( "Fader Tag: The fader tag of the local "
+ "client is set in the fader tag edit box. This tag will appear "
+ "at your fader on the mixer board when you are connected to a llcon "
+ "server. This tag will also show up at each client which is connected "
+ "to the same server as the local client. If the fader tag is empty, "
+ "the IP address of the client is displayed instead." );
+
+ QString strFaderTagTT = tr ( "Set your name and/or instrument and/or "
+ "pseoudonym here so that the other musicians can identify you." ) +
+ TOOLTIP_COM_END_TEXT;
+
+ lblServerTag->setWhatsThis ( strFaderTag );
+ lblServerTag->setToolTip ( strFaderTagTT );
+ edtFaderTag->setWhatsThis ( strFaderTag );
+ edtFaderTag->setToolTip ( strFaderTagTT );
+
+ edtFaderTag->setAccessibleName ( tr ( "Fader tag edit box" ) );
+
+ // local audio input fader
+ QString strAudFader = tr ( "Local Audio Input Fader: With the "
+ "audio fader, the relative levels of the left and right local audio "
+ "channels can be changed. 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 in "
+ "a direction where the label above the fader shows L -x, where "
+ "x is the current attenuation indication. " );
+
+ lblAudioPan->setWhatsThis ( strAudFader );
+ lblAudioPanValue->setWhatsThis ( strAudFader );
+ sldAudioPan->setWhatsThis ( strAudFader );
+
+ sldAudioPan->setAccessibleName ( tr ( "Local audio input fader (left/right)" ) );
+
+ // reverberation level
+ QString strAudReverb = tr ( "Reverberation Level: A reverberation "
+ "effect can be applied to one local audio channel. The channel "
+ "selection and the reverberation level can be modified. If, e.g., "
+ "the microphone signal is fed into the right audio channel of the "
+ "sound card and a reverberation effect shall be applied, set the "
+ "channel selector to right and move the fader upwards until the "
+ "desired reverberation level is reached.
"
+ "The reverberation effect requires significant CPU so that it should "
+ "only be used on fast PCs. If the reverberation 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." );
+
+ lblAudioReverb->setWhatsThis ( strAudReverb );
+ sldAudioReverb->setWhatsThis ( strAudReverb );
+
+ sldAudioReverb->setAccessibleName ( tr ( "Reverberation effect level setting" ) );
+
+ // reverberation channel selection
+ QString strRevChanSel = tr ( "Reverberation Channel Selection: "
+ "With these radio buttons the audio input channel on which the "
+ "reverberation effect is applied can be chosen. Either the left "
+ "or right input channel can be selected." );
+
+ rbtReverbSelL->setWhatsThis ( strRevChanSel );
+ rbtReverbSelL->setAccessibleName ( tr ( "Left channel selection for reverberation" ) );
+ rbtReverbSelR->setWhatsThis ( strRevChanSel );
+ rbtReverbSelR->setAccessibleName ( tr ( "Right channel selection for reverberation" ) );
+
+ // connection LED
+ QString strLEDConnection = tr ( "Connection Status LED: "
+ "The connection status LED indicator shows the current connection "
+ "status. If the light is green, a successful connection to the "
+ "server is established. If the light blinks red right after "
+ "pressing the connect button, the server address is invalid. "
+ "If the light turns red and stays red, the connection to the "
+ "server is lost." );
+
+ lblConnection->setWhatsThis ( strLEDConnection );
+ ledConnection->setWhatsThis ( strLEDConnection );
+
+ ledConnection->setAccessibleName ( tr ( "Connection status LED indicator" ) );
+
+ // delay LED
+ QString strLEDDelay = tr ( "Delay Status LED: "
+ "The delay status LED indicator shows the current audio delay "
+ "status. If the light is green, the delay is perfect for a jam "
+ "session. If the ligth is yellow, a session is still possible but "
+ "it may be harder to play. If the light is red, the delay is too "
+ "large for jamming." );
+
+ lblDelay->setWhatsThis ( strLEDDelay );
+ ledDelay->setWhatsThis ( strLEDDelay );
+ ledDelay->setToolTip ( tr ( "If this LED indicator turns red, "
+ "you will not have much fun using the llcon software." ) +
+ TOOLTIP_COM_END_TEXT );
+
+ ledDelay->setAccessibleName ( tr ( "Delay status LED indicator" ) );
+
+ // buffers LED
+ QString strLEDBuffers = tr ( "Buffers Status LED: "
+ "The buffers status LED indicator shows the current audio/streaming "
+ "status. If the light is green, there are no buffer overruns/underruns "
+ "and the audio stream is not interrupted. If the light is red, the "
+ "audio stream is interrupted caused by one of the following problems:"
+ ""
+ "- The network jitter buffer is not large enough for the current "
+ "network/audio interface jitter.
"
+ "- The sound card buffer delay (buffer size) is set to a too small "
+ "value.
"
+ "- The upload or download stream rate is too high for the current "
+ "available internet bandwidth.
"
+ "- The CPU of the client or server is at 100%.
"
+ "
" );
+
+ lblBuffers->setWhatsThis ( strLEDBuffers );
+ ledBuffers->setWhatsThis ( strLEDBuffers );
+
+ ledBuffers->setAccessibleName ( tr ( "Buffers status LED indicator" ) );
+
+ // chat LED
+ QString strLEDChat = tr ( "Chat Status LED: "
+ "If the option Open Chat on New Message is not activated, this "
+ "status LED will turn green on a new received chat message." );
+
+ lblChat->setWhatsThis ( strLEDChat );
+ ledChat->setWhatsThis ( strLEDChat );
+
+ ledBuffers->setAccessibleName ( tr ( "Chat status LED indicator" ) );
+
+
+ // init GUI design
+ SetGUIDesign ( pClient->GetGUIDesign() );
+
+ // reset mixer board
+ MainMixerBoard->HideAll();
+
+ // init fader tag line edit
+ edtFaderTag->setText ( pClient->strName );
+
+ // init status label
+ OnTimerStatus();
+
+ // init connection button text
+ butConnect->setText ( CON_BUT_CONNECTTEXT );
+
+ // init input level meter bars
+ lbrInputLevelL->setValue ( 0 );
+ lbrInputLevelR->setValue ( 0 );
+
+ // init status LEDs
+ ledConnection->SetUpdateTime ( 2 * LED_BAR_UPDATE_TIME_MS );
+ ledChat->SetUpdateTime ( 2 * LED_BAR_UPDATE_TIME_MS );
+ ledDelay->SetUpdateTime ( 2 * PING_UPDATE_TIME_MS );
+ ledDelay->Reset();
+
+
+ // init slider controls ---
+ // audio in fader
+ sldAudioPan->setRange ( AUD_FADER_IN_MIN, AUD_FADER_IN_MAX );
+ sldAudioPan->setTickInterval ( AUD_FADER_IN_MAX / 5 );
+ UpdateAudioFaderSlider();
+
+ // audio reverberation
+ sldAudioReverb->setRange ( 0, AUD_REVERB_MAX );
+ const int iCurAudReverb = pClient->GetReverbLevel();
+ sldAudioReverb->setValue ( iCurAudReverb );
+ sldAudioReverb->setTickInterval ( AUD_REVERB_MAX / 5 );
+
+ // init reverb channel
+ UpdateRevSelection();
+
+
+ // connect on startup ---
+ if ( bNewConnectOnStartup )
+ {
+ // since the software starts up right now, the previous state was
+ // "not connected" so that a call to "OnConnectDisconBut()" will
+ // start the connection
+ OnConnectDisconBut();
+ }
+
+
+ // disable controls on request ---
+ // disable LEDs in main window if requested
+ if ( bNewDisalbeLEDs )
+ {
+ lbrInputLevelL->setEnabled ( false );
+ lbrInputLevelR->setEnabled ( false );
+ ledConnection->setEnabled ( false );
+ ledBuffers->setEnabled ( false );
+ ledDelay->setEnabled ( false );
+ ledChat->setEnabled ( false );
+ butConnect->setFocus();
+ }
+
+
+ // Mac Workaround:
+ // If the connect button is the default button, on Mac it is highlighted
+ // by fading in and out a blue backgroud color. This operation consumes so
+ // much CPU that we get audio interruptions.
+ // Better solution: increase thread priority of worker thread (since the
+ // user can always highlight the button manually, too) -> TODO
+#if defined ( __APPLE__ ) || defined ( __MACOSX )
+ butConnect->setDefault ( false );
+#endif
+
+
+ // View menu --------------------------------------------------------------
+ pViewMenu = new QMenu ( "&View", this );
+
+ pViewMenu->addAction ( tr ( "&Chat..." ), this,
+ SLOT ( OnOpenChatDialog() ) );
+
+ pViewMenu->addAction ( tr ( "&General Settings..." ), this,
+ SLOT ( OnOpenGeneralSettings() ) );
+
+ pViewMenu->addSeparator();
+
+ pViewMenu->addAction ( tr ( "E&xit" ), this,
+ SLOT ( close() ), QKeySequence ( Qt::CTRL + Qt::Key_Q ) );
+
+
+ // Main menu bar -----------------------------------------------------------
+ pMenu = new QMenuBar ( this );
+
+ pMenu->addMenu ( pViewMenu );
+ pMenu->addMenu ( new CLlconHelpMenu ( this ) );
+
+ // Now tell the layout about the menu
+ layout()->setMenuBar ( pMenu );
+
+
+ // Connections -------------------------------------------------------------
+ // push-buttons
+ QObject::connect ( butConnect, SIGNAL ( clicked() ),
+ this, SLOT ( OnConnectDisconBut() ) );
+
+ // timers
+ QObject::connect ( &TimerSigMet, SIGNAL ( timeout() ),
+ this, SLOT ( OnTimerSigMet() ) );
+
+ QObject::connect ( &TimerStatus, SIGNAL ( timeout() ),
+ this, SLOT ( OnTimerStatus() ) );
+
+ QObject::connect ( &TimerPing, SIGNAL ( timeout() ),
+ this, SLOT ( OnTimerPing() ) );
+
+ // sliders
+ QObject::connect ( sldAudioPan, SIGNAL ( valueChanged ( int ) ),
+ this, SLOT ( OnAudioPanValueChanged ( int ) ) );
+
+ QObject::connect ( sldAudioReverb, SIGNAL ( valueChanged ( int ) ),
+ this, SLOT ( OnAudioReverbValueChanged ( int ) ) );
+
+ // radio buttons
+ QObject::connect ( rbtReverbSelL, SIGNAL ( clicked() ),
+ this, SLOT ( OnReverbSelLClicked() ) );
+
+ QObject::connect ( rbtReverbSelR, SIGNAL ( clicked() ),
+ this, SLOT ( OnReverbSelRClicked() ) );
+
+ // line edits
+ QObject::connect ( edtFaderTag, SIGNAL ( textChanged ( const QString& ) ),
+ this, SLOT ( OnFaderTagTextChanged ( const QString& ) ) );
+
+ // other
+ QObject::connect ( pClient,
+ SIGNAL ( ConClientListMesReceived ( CVector ) ),
+ this, SLOT ( OnConClientListMesReceived ( CVector ) ) );
+
+ QObject::connect ( pClient,
+ SIGNAL ( Disconnected() ),
+ this, SLOT ( OnDisconnected() ) );
+
+ QObject::connect ( pClient,
+ SIGNAL ( ChatTextReceived ( QString ) ),
+ this, SLOT ( OnChatTextReceived ( QString ) ) );
+
+ QObject::connect ( pClient, SIGNAL ( PingTimeReceived ( int ) ),
+ this, SLOT ( OnPingTimeResult ( int ) ) );
+
+ QObject::connect ( pClient,
+ SIGNAL ( CLServerListReceived ( CHostAddress, CVector ) ),
+ this, SLOT ( OnCLServerListReceived ( CHostAddress, CVector ) ) );
+
+ QObject::connect ( pClient,
+ SIGNAL ( CLPingTimeWithNumClientsReceived ( CHostAddress, int, int ) ),
+ this, SLOT ( OnCLPingTimeWithNumClientsReceived ( CHostAddress, int, int ) ) );
+
+ QObject::connect ( &ClientSettingsDlg, SIGNAL ( GUIDesignChanged() ),
+ this, SLOT ( OnGUIDesignChanged() ) );
+
+ QObject::connect ( &ClientSettingsDlg, SIGNAL ( StereoCheckBoxChanged() ),
+ this, SLOT ( OnStereoCheckBoxChanged() ) );
+
+ QObject::connect ( MainMixerBoard, SIGNAL ( ChangeChanGain ( int, double ) ),
+ this, SLOT ( OnChangeChanGain ( int, double ) ) );
+
+ QObject::connect ( MainMixerBoard, SIGNAL ( NumClientsChanged ( int ) ),
+ this, SLOT ( OnNumClientsChanged ( int ) ) );
+
+ QObject::connect ( &ChatDlg, SIGNAL ( NewLocalInputText ( QString ) ),
+ this, SLOT ( OnNewLocalInputText ( QString ) ) );
+
+ QObject::connect ( &ConnectDlg, SIGNAL ( ReqServerListQuery ( CHostAddress ) ),
+ this, SLOT ( OnReqServerListQuery ( CHostAddress ) ) );
+
+ QObject::connect ( &ConnectDlg, SIGNAL ( CreateCLPingMes ( CHostAddress ) ),
+ this, SLOT ( OnCreateCLPingMes ( CHostAddress ) ) );
+
+
+ // Timers ------------------------------------------------------------------
+ // start timer for status bar
+ TimerStatus.start ( LED_BAR_UPDATE_TIME_MS );
+}
+
+void CLlconClientDlg::closeEvent ( QCloseEvent* Event )
+{
+ // if settings/connect dialog or chat dialog is open, close it
+ ClientSettingsDlg.close();
+ ConnectDlg.close();
+ ChatDlg.close();
+
+ // if connected, terminate connection
+ if ( pClient->IsRunning() )
+ {
+ pClient->Stop();
+ }
+
+ // store fader tag
+ pClient->strName = edtFaderTag->text();
+
+ // default implementation of this event handler routine
+ Event->accept();
+}
+
+void CLlconClientDlg::UpdateAudioFaderSlider()
+{
+ // update slider and label of audio fader
+ const int iCurAudInFader = pClient->GetAudioInFader();
+ sldAudioPan->setValue ( iCurAudInFader );
+
+ // show in label the center position and what channel is
+ // attenuated
+ if ( iCurAudInFader == AUD_FADER_IN_MIDDLE )
+ {
+ lblAudioPanValue->setText ( "Center" );
+ }
+ else
+ {
+ if ( iCurAudInFader > AUD_FADER_IN_MIDDLE )
+ {
+ // attenuation on right channel
+ lblAudioPanValue->setText ( "R -" +
+ QString().setNum ( iCurAudInFader - AUD_FADER_IN_MIDDLE ) );
+ }
+ else
+ {
+ // attenuation on left channel
+ lblAudioPanValue->setText ( "L -" +
+ QString().setNum ( AUD_FADER_IN_MIDDLE - iCurAudInFader ) );
+ }
+ }
+}
+
+void CLlconClientDlg::UpdateRevSelection()
+{
+ if ( pClient->GetUseStereo() )
+ {
+ // for stereo make channel selection invisible since
+ // reverberation effect is always applied to both channels
+ rbtReverbSelL->setVisible ( false );
+ rbtReverbSelR->setVisible ( false );
+ }
+ else
+ {
+ // make radio buttons visible
+ rbtReverbSelL->setVisible ( true );
+ rbtReverbSelR->setVisible ( true );
+
+ // update value
+ if ( pClient->IsReverbOnLeftChan() )
+ {
+ rbtReverbSelL->setChecked ( true );
+ }
+ else
+ {
+ rbtReverbSelR->setChecked ( true );
+ }
+ }
+}
+
+void CLlconClientDlg::OnAudioPanValueChanged ( int value )
+{
+ pClient->SetAudioInFader ( value );
+ UpdateAudioFaderSlider();
+}
+
+void CLlconClientDlg::OnConnectDisconBut()
+{
+ // the connect/disconnect button implements a toggle functionality
+ // -> apply inverted running state
+ ConnectDisconnect ( !pClient->IsRunning() );
+}
+
+void CLlconClientDlg::OnOpenGeneralSettings()
+{
+ // open general settings dialog
+ ClientSettingsDlg.show();
+
+ // make sure dialog is upfront and has focus
+ ClientSettingsDlg.raise();
+ ClientSettingsDlg.activateWindow();
+}
+
+void CLlconClientDlg::OnChatTextReceived ( QString strChatText )
+{
+ // init flag (will maybe overwritten later in this function)
+ bUnreadChatMessage = false;
+
+ ChatDlg.AddChatText ( strChatText );
+
+ // if requested, open window
+ if ( pClient->GetOpenChatOnNewMessage() )
+ {
+ ShowChatWindow();
+ }
+ else
+ {
+ if ( !ChatDlg.isVisible() )
+ {
+ bUnreadChatMessage = true;
+ }
+ }
+
+ UpdateDisplay();
+}
+
+void CLlconClientDlg::OnDisconnected()
+{
+ // channel is now disconnected, clear mixer board (remove all faders)
+ MainMixerBoard->HideAll();
+
+ UpdateDisplay();
+}
+
+void CLlconClientDlg::OnConClientListMesReceived ( CVector vecChanInfo )
+{
+ // update mixer board
+ MainMixerBoard->ApplyNewConClientList ( vecChanInfo );
+}
+
+void CLlconClientDlg::OnNumClientsChanged ( int iNewNumClients )
+{
+ // update window title
+ SetMyWindowTitle ( iNewNumClients );
+}
+
+void CLlconClientDlg::SetMyWindowTitle ( const int iNumClients )
+{
+ // show number of connected clients in window title (and therefore also in
+ // the task bar of the OS)
+ if ( iNumClients == 0 )
+ {
+ // only application name
+ setWindowTitle ( APP_NAME );
+ }
+ else
+ {
+ if ( iNumClients == 1 )
+ {
+ setWindowTitle ( QString ( APP_NAME ) + " (1 user)" );
+ }
+ else
+ {
+ setWindowTitle ( QString ( APP_NAME ) +
+ QString ( " (%1 users)" ).arg ( iNumClients ) );
+ }
+ }
+}
+
+void CLlconClientDlg::ShowChatWindow()
+{
+ // open chat dialog
+ ChatDlg.show();
+
+ // make sure dialog is upfront and has focus
+ ChatDlg.raise();
+ ChatDlg.activateWindow();
+
+ // chat dialog is opened, reset unread message flag
+ bUnreadChatMessage = false;
+
+ UpdateDisplay();
+}
+
+void CLlconClientDlg::OnFaderTagTextChanged ( const QString& strNewName )
+{
+ // check length
+ if ( strNewName.length() <= MAX_LEN_FADER_TAG )
+ {
+ // refresh internal name parameter
+ pClient->strName = strNewName;
+
+ // update name at server
+ pClient->SetRemoteName();
+ }
+ else
+ {
+ // text is too long, update control with shortend text
+ edtFaderTag->setText ( strNewName.left ( MAX_LEN_FADER_TAG ) );
+ }
+}
+
+void CLlconClientDlg::OnTimerSigMet()
+{
+ // get current input levels
+ double dCurSigLevelL = pClient->MicLevelL();
+ double dCurSigLevelR = pClient->MicLevelR();
+
+ // linear transformation of the input level range to the progress-bar
+ // range
+ dCurSigLevelL -= LOW_BOUND_SIG_METER;
+ dCurSigLevelL *= NUM_STEPS_INP_LEV_METER /
+ ( UPPER_BOUND_SIG_METER - LOW_BOUND_SIG_METER );
+
+ // lower bound the signal
+ if ( dCurSigLevelL < 0 )
+ {
+ dCurSigLevelL = 0;
+ }
+
+ dCurSigLevelR -= LOW_BOUND_SIG_METER;
+ dCurSigLevelR *= NUM_STEPS_INP_LEV_METER /
+ ( UPPER_BOUND_SIG_METER - LOW_BOUND_SIG_METER );
+
+ // lower bound the signal
+ if ( dCurSigLevelR < 0 )
+ {
+ dCurSigLevelR = 0;
+ }
+
+ // show current level
+ lbrInputLevelL->setValue ( (int) ceil ( dCurSigLevelL ) );
+ lbrInputLevelR->setValue ( (int) ceil ( dCurSigLevelR ) );
+}
+
+void CLlconClientDlg::OnTimerPing()
+{
+ // send ping message to server
+ pClient->CreatePingMes();
+}
+
+void CLlconClientDlg::OnPingTimeResult ( int iPingTime )
+{
+ // calculate overall delay
+ const int iOverallDelayMs = pClient->EstimatedOverallDelay ( iPingTime );
+
+ // color definition: <= 40 ms green, <= 65 ms yellow, otherwise red
+ int iOverallDelayLEDColor;
+ if ( iOverallDelayMs <= 40 )
+ {
+ iOverallDelayLEDColor = MUL_COL_LED_GREEN;
+ }
+ else
+ {
+ if ( iOverallDelayMs <= 65 )
+ {
+ iOverallDelayLEDColor = MUL_COL_LED_YELLOW;
+ }
+ else
+ {
+ iOverallDelayLEDColor = MUL_COL_LED_RED;
+ }
+ }
+
+ // only update delay information on settings dialog if it is visible to
+ // avoid CPU load on working thread if not necessary
+ if ( ClientSettingsDlg.isVisible() )
+ {
+ // set ping time result to general settings dialog
+ ClientSettingsDlg.SetPingTimeResult ( iPingTime,
+ iOverallDelayMs,
+ iOverallDelayLEDColor );
+ }
+
+ // update delay LED on the main window
+ ledDelay->SetLight ( iOverallDelayLEDColor );
+}
+
+void CLlconClientDlg::OnCLPingTimeWithNumClientsReceived ( CHostAddress InetAddr,
+ int iPingTime,
+ int iNumClients )
+{
+ // color definition: <= 25 ms green, <= 50 ms yellow, otherwise red
+ int iPingTimeLEDColor;
+ if ( iPingTime <= 25 )
+ {
+ iPingTimeLEDColor = MUL_COL_LED_GREEN;
+ }
+ else
+ {
+ if ( iPingTime <= 50 )
+ {
+ iPingTimeLEDColor = MUL_COL_LED_YELLOW;
+ }
+ else
+ {
+ iPingTimeLEDColor = MUL_COL_LED_RED;
+ }
+ }
+
+ // update connection dialog server list
+ ConnectDlg.SetPingTimeAndNumClientsResult ( InetAddr,
+ iPingTime,
+ iPingTimeLEDColor,
+ iNumClients );
+}
+
+void CLlconClientDlg::ConnectDisconnect ( const bool bDoStart )
+{
+ // start/stop client, set button text
+ if ( bDoStart )
+ {
+ // get the central server address string
const QString strCurCentServAddr =
SELECT_SERVER_ADDRESS ( pClient->GetUseDefaultCentralServerAddress(),
pClient->GetServerListCentralServerAddress() );
-
- // init the connect dialog and execute it (modal dialog)
- ConnectDlg.Init ( strCurCentServAddr, pClient->vstrIPAddress );
- ConnectDlg.exec();
-
- // check if state is OK (e.g., no Cancel was pressed)
- if ( ConnectDlg.GetStateOK() )
- {
- const QString strSelectedAddress = ConnectDlg.GetSelectedAddress();
-
- // only store new host address in our data base if the address is
- // not empty and it was not a server list item (only the addresses
- // typed in manually are stored by definition)
- if ( !strSelectedAddress.isEmpty() &&
- !ConnectDlg.GetServerListItemWasChosen() )
- {
- CVector vstrTempList ( MAX_NUM_SERVER_ADDR_ITEMS, "" );
-
- // store the new address in the current server storage list at
- // the top, make sure we do not have more than allowed stored
- // servers
- vstrTempList[0] = strSelectedAddress;
- int iTempListCnt = 1;
-
- for ( int iIdx = 0; iIdx < MAX_NUM_SERVER_ADDR_ITEMS; iIdx++ )
- {
- // only add old server address if it is not the same as the
- // selected one
- if ( ( pClient->vstrIPAddress[iIdx].compare ( strSelectedAddress ) ) &&
- ( iTempListCnt < MAX_NUM_SERVER_ADDR_ITEMS ) )
- {
- vstrTempList[iTempListCnt] =
- pClient->vstrIPAddress[iIdx];
-
- iTempListCnt++;
- }
- }
-
- // copy new generated list to client
- pClient->vstrIPAddress = vstrTempList;
- }
-
- // set address and check if address is valid
- if ( pClient->SetServerAddr ( strSelectedAddress ) )
- {
- bool bStartOk = true;
-
- // try to start client, if error occurred, do not go in
- // running state but show error message
- try
- {
- pClient->Start();
- }
-
- catch ( CGenErr generr )
- {
- QMessageBox::critical (
- this, APP_NAME, generr.GetErrorText(), "Close", 0 );
-
- bStartOk = false;
- }
-
- if ( bStartOk )
- {
- // change connect button text to "disconnect"
- butConnect->setText ( CON_BUT_DISCONNECTTEXT );
-
- // set server name in audio mixer group box title
- if ( ConnectDlg.GetServerListItemWasChosen() )
- {
- // in case a server in the server list was chosen,
- // display the server name of the server list
- MainMixerBoard->SetServerName (
- ConnectDlg.GetSelectedServerName() );
- }
- else
- {
- // an item of the server address combo box was chosen,
- // just show the address string as it was entered by the
- // user
- MainMixerBoard->SetServerName ( strSelectedAddress );
- }
-
- // start timer for level meter bar and ping time measurement
- TimerSigMet.start ( LEVELMETER_UPDATE_TIME_MS );
- TimerPing.start ( PING_UPDATE_TIME_MS );
- }
- }
- else
- {
- // show the error as red light
- ledConnection->SetLight ( MUL_COL_LED_RED );
- }
-
- }
- }
- else
- {
- // only stop client if currently running, in case we received
- // the stopped message, the client is already stopped but the
- // connect/disconnect button and other GUI controls must be
- // updated
- if ( pClient->IsRunning() )
- {
- pClient->Stop();
- }
-
- // change connect button text to "connect"
- butConnect->setText ( CON_BUT_CONNECTTEXT );
-
- // reset server name in audio mixer group box title
- MainMixerBoard->SetServerName ( "" );
-
- // stop timer for level meter bars and reset them
- TimerSigMet.stop();
- lbrInputLevelL->setValue ( 0 );
- lbrInputLevelR->setValue ( 0 );
-
- // stop ping time measurement timer
- TimerPing.stop();
-
-
-// TODO is this still required???
-// immediately update status bar
-OnTimerStatus();
-
-// TODO this seems not to work, LEDs are still updated afterwards...
-// reset LEDs
-ledConnection->Reset();
-ledBuffers->Reset();
-ledDelay->Reset();
-ledChat->Reset();
-
-
- // clear mixer board (remove all faders)
- MainMixerBoard->HideAll();
- }
-}
-
-void CLlconClientDlg::UpdateDisplay()
-{
- // update status LEDs
- if ( pClient->IsRunning() )
- {
- if ( pClient->IsConnected() )
- {
- // chat LED
- if ( bUnreadChatMessage )
- {
- ledChat->SetLight ( MUL_COL_LED_GREEN );
- }
- else
- {
- ledChat->Reset();
- }
-
- // connection LED
- ledConnection->SetLight ( MUL_COL_LED_GREEN );
- }
- else
- {
- // connection LED
- ledConnection->SetLight ( MUL_COL_LED_RED );
- }
- }
-}
-
-void CLlconClientDlg::SetGUIDesign ( const EGUIDesign eNewDesign )
-{
- // apply GUI design to current window
- switch ( eNewDesign )
- {
- case GD_ORIGINAL:
- backgroundFrame->setStyleSheet (
- "QFrame#backgroundFrame { border-image: url(:/png/fader/res/mixerboardbackground.png) 34px 30px 40px 40px;"
- " border-top: 34px transparent;"
- " border-bottom: 40px transparent;"
- " border-left: 30px transparent;"
- " border-right: 40px transparent;"
- " padding: -5px;"
- " margin: -5px, -5px, 0px, 0px; }"
- "QLabel { color: rgb(148, 148, 148);"
- " font: bold; }"
- "QRadioButton { color: rgb(148, 148, 148);"
- " font: bold; }"
- "QGroupBox::title { color: rgb(148, 148, 148); }" );
-
-#ifdef _WIN32
-// Workaround QT-Windows problem: This should not be necessary since in the
-// background frame the style sheet for QRadioButton was already set. But it
-// seems that it is only applied if the style was set to default and then back
-// to GD_ORIGINAL. This seems to be a QT related issue...
-rbtReverbSelL->setStyleSheet ( "color: rgb(148, 148, 148);"
- "font: bold;" );
-rbtReverbSelR->setStyleSheet ( "color: rgb(148, 148, 148);"
- "font: bold;" );
-#endif
-
- break;
-
- default:
- // reset style sheet and set original paramters
- backgroundFrame->setStyleSheet ( "" );
-
-#ifdef _WIN32
-// Workaround QT-Windows problem: See above description
-rbtReverbSelL->setStyleSheet ( "" );
-rbtReverbSelR->setStyleSheet ( "" );
-#endif
-
- break;
- }
-
- // also apply GUI design to child GUI controls
- MainMixerBoard->SetGUIDesign ( eNewDesign );
-}
-
-void CLlconClientDlg::customEvent ( QEvent* Event )
-{
- if ( Event->type() == QEvent::User + 11 )
- {
- const int iMessType = ( (CLlconEvent*) Event )->iMessType;
- const int iStatus = ( (CLlconEvent*) Event )->iStatus;
-
- switch ( iMessType )
- {
- case MS_SOUND_IN:
- case MS_SOUND_OUT:
- case MS_JIT_BUF_PUT:
- case MS_JIT_BUF_GET:
- // buffer status -> if any buffer goes red, this LED will go red
- ledBuffers->SetLight ( iStatus );
- break;
-
- case MS_RESET_ALL:
- ledConnection->Reset();
- ledBuffers->Reset();
- ledDelay->Reset();
- ledChat->Reset();
- break;
-
- case MS_SET_JIT_BUF_SIZE:
- pClient->SetSockBufNumFrames ( iStatus );
- break;
- }
-
- // update general settings dialog, too
- ClientSettingsDlg.SetStatus ( iMessType, iStatus );
- }
-}
+
+ // init the connect dialog and execute it (modal dialog)
+ ConnectDlg.Init ( strCurCentServAddr, pClient->vstrIPAddress );
+ ConnectDlg.exec();
+
+ // check if state is OK (e.g., no Cancel was pressed)
+ if ( ConnectDlg.GetStateOK() )
+ {
+ const QString strSelectedAddress = ConnectDlg.GetSelectedAddress();
+
+ // only store new host address in our data base if the address is
+ // not empty and it was not a server list item (only the addresses
+ // typed in manually are stored by definition)
+ if ( !strSelectedAddress.isEmpty() &&
+ !ConnectDlg.GetServerListItemWasChosen() )
+ {
+ CVector vstrTempList ( MAX_NUM_SERVER_ADDR_ITEMS, "" );
+
+ // store the new address in the current server storage list at
+ // the top, make sure we do not have more than allowed stored
+ // servers
+ vstrTempList[0] = strSelectedAddress;
+ int iTempListCnt = 1;
+
+ for ( int iIdx = 0; iIdx < MAX_NUM_SERVER_ADDR_ITEMS; iIdx++ )
+ {
+ // only add old server address if it is not the same as the
+ // selected one
+ if ( ( pClient->vstrIPAddress[iIdx].compare ( strSelectedAddress ) ) &&
+ ( iTempListCnt < MAX_NUM_SERVER_ADDR_ITEMS ) )
+ {
+ vstrTempList[iTempListCnt] =
+ pClient->vstrIPAddress[iIdx];
+
+ iTempListCnt++;
+ }
+ }
+
+ // copy new generated list to client
+ pClient->vstrIPAddress = vstrTempList;
+ }
+
+ // set address and check if address is valid
+ if ( pClient->SetServerAddr ( strSelectedAddress ) )
+ {
+ bool bStartOk = true;
+
+ // try to start client, if error occurred, do not go in
+ // running state but show error message
+ try
+ {
+ pClient->Start();
+ }
+
+ catch ( CGenErr generr )
+ {
+ QMessageBox::critical (
+ this, APP_NAME, generr.GetErrorText(), "Close", 0 );
+
+ bStartOk = false;
+ }
+
+ if ( bStartOk )
+ {
+ // change connect button text to "disconnect"
+ butConnect->setText ( CON_BUT_DISCONNECTTEXT );
+
+ // set server name in audio mixer group box title
+ if ( ConnectDlg.GetServerListItemWasChosen() )
+ {
+ // in case a server in the server list was chosen,
+ // display the server name of the server list
+ MainMixerBoard->SetServerName (
+ ConnectDlg.GetSelectedServerName() );
+ }
+ else
+ {
+ // an item of the server address combo box was chosen,
+ // just show the address string as it was entered by the
+ // user
+ MainMixerBoard->SetServerName ( strSelectedAddress );
+ }
+
+ // start timer for level meter bar and ping time measurement
+ TimerSigMet.start ( LEVELMETER_UPDATE_TIME_MS );
+ TimerPing.start ( PING_UPDATE_TIME_MS );
+ }
+ }
+ else
+ {
+ // show the error as red light
+ ledConnection->SetLight ( MUL_COL_LED_RED );
+ }
+
+ }
+ }
+ else
+ {
+ // only stop client if currently running, in case we received
+ // the stopped message, the client is already stopped but the
+ // connect/disconnect button and other GUI controls must be
+ // updated
+ if ( pClient->IsRunning() )
+ {
+ pClient->Stop();
+ }
+
+ // change connect button text to "connect"
+ butConnect->setText ( CON_BUT_CONNECTTEXT );
+
+ // reset server name in audio mixer group box title
+ MainMixerBoard->SetServerName ( "" );
+
+ // stop timer for level meter bars and reset them
+ TimerSigMet.stop();
+ lbrInputLevelL->setValue ( 0 );
+ lbrInputLevelR->setValue ( 0 );
+
+ // stop ping time measurement timer
+ TimerPing.stop();
+
+
+// TODO is this still required???
+// immediately update status bar
+OnTimerStatus();
+
+// TODO this seems not to work, LEDs are still updated afterwards...
+// reset LEDs
+ledConnection->Reset();
+ledBuffers->Reset();
+ledDelay->Reset();
+ledChat->Reset();
+
+
+ // clear mixer board (remove all faders)
+ MainMixerBoard->HideAll();
+ }
+}
+
+void CLlconClientDlg::UpdateDisplay()
+{
+ // update status LEDs
+ if ( pClient->IsRunning() )
+ {
+ if ( pClient->IsConnected() )
+ {
+ // chat LED
+ if ( bUnreadChatMessage )
+ {
+ ledChat->SetLight ( MUL_COL_LED_GREEN );
+ }
+ else
+ {
+ ledChat->Reset();
+ }
+
+ // connection LED
+ ledConnection->SetLight ( MUL_COL_LED_GREEN );
+ }
+ else
+ {
+ // connection LED
+ ledConnection->SetLight ( MUL_COL_LED_RED );
+ }
+ }
+}
+
+void CLlconClientDlg::SetGUIDesign ( const EGUIDesign eNewDesign )
+{
+ // apply GUI design to current window
+ switch ( eNewDesign )
+ {
+ case GD_ORIGINAL:
+ backgroundFrame->setStyleSheet (
+ "QFrame#backgroundFrame { border-image: url(:/png/fader/res/mixerboardbackground.png) 34px 30px 40px 40px;"
+ " border-top: 34px transparent;"
+ " border-bottom: 40px transparent;"
+ " border-left: 30px transparent;"
+ " border-right: 40px transparent;"
+ " padding: -5px;"
+ " margin: -5px, -5px, 0px, 0px; }"
+ "QLabel { color: rgb(148, 148, 148);"
+ " font: bold; }"
+ "QRadioButton { color: rgb(148, 148, 148);"
+ " font: bold; }"
+ "QGroupBox::title { color: rgb(148, 148, 148); }" );
+
+#ifdef _WIN32
+// Workaround QT-Windows problem: This should not be necessary since in the
+// background frame the style sheet for QRadioButton was already set. But it
+// seems that it is only applied if the style was set to default and then back
+// to GD_ORIGINAL. This seems to be a QT related issue...
+rbtReverbSelL->setStyleSheet ( "color: rgb(148, 148, 148);"
+ "font: bold;" );
+rbtReverbSelR->setStyleSheet ( "color: rgb(148, 148, 148);"
+ "font: bold;" );
+#endif
+
+ break;
+
+ default:
+ // reset style sheet and set original paramters
+ backgroundFrame->setStyleSheet ( "" );
+
+#ifdef _WIN32
+// Workaround QT-Windows problem: See above description
+rbtReverbSelL->setStyleSheet ( "" );
+rbtReverbSelR->setStyleSheet ( "" );
+#endif
+
+ break;
+ }
+
+ // also apply GUI design to child GUI controls
+ MainMixerBoard->SetGUIDesign ( eNewDesign );
+}
+
+void CLlconClientDlg::customEvent ( QEvent* Event )
+{
+ if ( Event->type() == QEvent::User + 11 )
+ {
+ const int iMessType = ( (CLlconEvent*) Event )->iMessType;
+ const int iStatus = ( (CLlconEvent*) Event )->iStatus;
+
+ switch ( iMessType )
+ {
+ case MS_SOUND_IN:
+ case MS_SOUND_OUT:
+ case MS_JIT_BUF_PUT:
+ case MS_JIT_BUF_GET:
+ // buffer status -> if any buffer goes red, this LED will go red
+ ledBuffers->SetLight ( iStatus );
+ break;
+
+ case MS_RESET_ALL:
+ ledConnection->Reset();
+ ledBuffers->Reset();
+ ledDelay->Reset();
+ ledChat->Reset();
+ break;
+
+ case MS_SET_JIT_BUF_SIZE:
+ pClient->SetSockBufNumFrames ( iStatus );
+ break;
+ }
+
+ // update general settings dialog, too
+ ClientSettingsDlg.SetStatus ( iMessType, iStatus );
+ }
+}
diff --git a/src/llconserverdlg.cpp b/src/llconserverdlg.cpp
index ff5acec7..1b7d0f1c 100755
--- a/src/llconserverdlg.cpp
+++ b/src/llconserverdlg.cpp
@@ -47,6 +47,13 @@ CLlconServerDlg::CLlconServerDlg ( CServer* pNServP,
lvwClients->setAccessibleName ( tr ( "Connected clients list view" ) );
+ // start minimized on operating system start
+ chbStartOnOSStart->setWhatsThis ( tr ( "Start Minimized on Operating "
+ "System Start: If the start minimized on operating system start "
+ "check box is checked, the " ) + APP_NAME + tr ( " server will be "
+ "started when the operating system starts up and is automatically "
+ "minimized to a system task bar icon." ) );
+
// register server flag
chbRegisterServer->setWhatsThis ( tr ( "Register Server Status: If "
"the register server check box is checked, this server registers "