diff --git a/ChangeLog b/ChangeLog index 88487eff..70ff269b 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,7 @@ 3.1.1 +- added stereo audio channel support + - added input/output audio channel mapping for ASIO audio interface diff --git a/src/client.cpp b/src/client.cpp index a244cfa6..b73d0d10 100755 --- a/src/client.cpp +++ b/src/client.cpp @@ -51,7 +51,7 @@ CClient::CClient ( const quint16 iPortNumber ) : bFraSiFactSafeSupported ( false ), iCeltNumCodedBytes ( CELT_NUM_BYTES_MONO_NORMAL_QUALITY ), bCeltDoHighQuality ( false ), - bStereo ( false ), + bUseStereo ( false ), bSndCrdConversionBufferRequired ( false ), iSndCardMonoBlockSizeSamConvBuff ( 0 ) { @@ -234,8 +234,26 @@ void CClient::SetCELTHighQuality ( const bool bNCeltHighQualityFlag ) // set new parameter bCeltDoHighQuality = bNCeltHighQualityFlag; + Init(); - // init with new block size index parameter + if ( bWasRunning ) + { + Sound.Start(); + } +} + +void CClient::SetUseStereo ( const bool bNUseStereo ) +{ + // init with new parameter, if client was running then first + // stop it and restart again after new initialization + const bool bWasRunning = Sound.IsRunning(); + if ( bWasRunning ) + { + Sound.Stop(); + } + + // set new parameter + bUseStereo = bNUseStereo; Init(); if ( bWasRunning ) @@ -496,9 +514,8 @@ void CClient::Init() // calculate stereo (two channels) buffer size iStereoBlockSizeSam = 2 * iMonoBlockSizeSam; - vecsAudioSndCrdMono.Init ( iMonoBlockSizeSam ); - vecsAudioSndCrdStereo.Init ( iStereoBlockSizeSam ); - vecdAudioStereo.Init ( iStereoBlockSizeSam ); + vecsAudioSndCrdMono.Init ( iMonoBlockSizeSam ); + vecdAudioStereo.Init ( iStereoBlockSizeSam ); // init response time evaluation CycleTimeVariance.Init ( iMonoBlockSizeSam, @@ -512,7 +529,7 @@ void CClient::Init() // inits for CELT coding if ( bCeltDoHighQuality ) { - if ( bStereo ) + if ( bUseStereo ) { iCeltNumCodedBytes = CELT_NUM_BYTES_STEREO_HIGH_QUALITY; } @@ -523,7 +540,7 @@ void CClient::Init() } else { - if ( bStereo ) + if ( bUseStereo ) { iCeltNumCodedBytes = CELT_NUM_BYTES_STEREO_NORMAL_QUALITY; } @@ -536,7 +553,7 @@ void CClient::Init() // inits for network and channel vecbyNetwData.Init ( iCeltNumCodedBytes ); - if ( bStereo ) + if ( bUseStereo ) { vecsNetwork.Init ( iStereoBlockSizeSam ); @@ -641,7 +658,7 @@ void CClient::ProcessAudioDataIntern ( CVector& vecsStereoSndCrd ) // from double to short if ( iAudioInFader == AUD_FADER_IN_MIDDLE ) { - if ( bStereo ) + if ( bUseStereo ) { // perform type conversion for ( i = 0; i < iStereoBlockSizeSam; i++ ) @@ -662,52 +679,78 @@ void CClient::ProcessAudioDataIntern ( CVector& vecsStereoSndCrd ) } else { - - -// TODO for stereo!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -// TODO for stereo!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -// TODO for stereo!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -// TODO for stereo!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -// TODO for stereo!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -// TODO for stereo!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - - - // make sure that in the middle position the two channels are - // amplified by 1/2, if the pan is set to one channel, this - // channel should have an amplification of 1 - const double dAttFact = static_cast ( - AUD_FADER_IN_MIDDLE - abs ( AUD_FADER_IN_MIDDLE - iAudioInFader ) ) / - AUD_FADER_IN_MIDDLE / 2; - - const double dAmplFact = 0.5 + static_cast ( - abs ( AUD_FADER_IN_MIDDLE - iAudioInFader ) ) / - AUD_FADER_IN_MIDDLE / 2; - - if ( iAudioInFader > AUD_FADER_IN_MIDDLE ) + if ( bUseStereo ) { - for ( i = 0, j = 0; i < iMonoBlockSizeSam; i++, j += 2 ) + // stereo + const double dAttFactStereo = static_cast ( + AUD_FADER_IN_MIDDLE - abs ( AUD_FADER_IN_MIDDLE - iAudioInFader ) ) / + AUD_FADER_IN_MIDDLE; + + if ( iAudioInFader > AUD_FADER_IN_MIDDLE ) { - // attenuation on right channel - vecsNetwork[i] = Double2Short ( - dAmplFact * vecdAudioStereo[j] + - dAttFact * vecdAudioStereo[j + 1] ); + for ( i = 0, j = 0; i < iMonoBlockSizeSam; i++, j += 2 ) + { + // attenuation on right channel + vecsNetwork[j] = Double2Short ( + vecdAudioStereo[j] ); + + vecsNetwork[j + 1] = Double2Short ( + dAttFactStereo * vecdAudioStereo[j + 1] ); + } + } + else + { + for ( i = 0, j = 0; i < iMonoBlockSizeSam; i++, j += 2 ) + { + // attenuation on left channel + vecsNetwork[j] = Double2Short ( + dAttFactStereo * vecdAudioStereo[j] ); + + vecsNetwork[j + 1] = Double2Short ( + vecdAudioStereo[j + 1] ); + } } } else { - for ( i = 0, j = 0; i < iMonoBlockSizeSam; i++, j += 2 ) + // mono + // make sure that in the middle position the two channels are + // amplified by 1/2, if the pan is set to one channel, this + // channel should have an amplification of 1 + const double dAttFactMono = static_cast ( + AUD_FADER_IN_MIDDLE - abs ( AUD_FADER_IN_MIDDLE - iAudioInFader ) ) / + AUD_FADER_IN_MIDDLE / 2; + + const double dAmplFactMono = 0.5 + static_cast ( + abs ( AUD_FADER_IN_MIDDLE - iAudioInFader ) ) / + AUD_FADER_IN_MIDDLE / 2; + + if ( iAudioInFader > AUD_FADER_IN_MIDDLE ) { - // attenuation on left channel - vecsNetwork[i] = Double2Short ( - dAmplFact * vecdAudioStereo[j + 1] + - dAttFact * vecdAudioStereo[j] ); + for ( i = 0, j = 0; i < iMonoBlockSizeSam; i++, j += 2 ) + { + // attenuation on right channel + vecsNetwork[i] = Double2Short ( + dAmplFactMono * vecdAudioStereo[j] + + dAttFactMono * vecdAudioStereo[j + 1] ); + } + } + else + { + for ( i = 0, j = 0; i < iMonoBlockSizeSam; i++, j += 2 ) + { + // attenuation on left channel + vecsNetwork[i] = Double2Short ( + dAmplFactMono * vecdAudioStereo[j + 1] + + dAttFactMono * vecdAudioStereo[j] ); + } } } } for ( i = 0; i < iSndCrdFrameSizeFactor; i++ ) { - if ( bStereo ) + if ( bUseStereo ) { // encode current audio frame with CELT encoder celt_encode ( CeltEncoderStereo, @@ -751,12 +794,12 @@ void CClient::ProcessAudioDataIntern ( CVector& vecsStereoSndCrd ) // CELT decoding if ( bReceiveDataOk ) { - if ( bStereo ) + if ( bUseStereo ) { celt_decode ( CeltDecoderStereo, &vecbyNetwData[0], iCeltNumCodedBytes, - &vecsAudioSndCrdStereo[i * 2 * SYSTEM_FRAME_SIZE_SAMPLES] ); + &vecsStereoSndCrd[i * 2 * SYSTEM_FRAME_SIZE_SAMPLES] ); } else { @@ -769,12 +812,12 @@ void CClient::ProcessAudioDataIntern ( CVector& vecsStereoSndCrd ) else { // lost packet - if ( bStereo ) + if ( bUseStereo ) { celt_decode ( CeltDecoderStereo, NULL, 0, - &vecsAudioSndCrdStereo[i * 2 * SYSTEM_FRAME_SIZE_SAMPLES] ); + &vecsStereoSndCrd[i * 2 * SYSTEM_FRAME_SIZE_SAMPLES] ); } else { @@ -789,15 +832,7 @@ void CClient::ProcessAudioDataIntern ( CVector& vecsStereoSndCrd ) // check if channel is connected if ( Channel.IsConnected() ) { - if ( bStereo ) - { - // copy data - for ( i = 0; i < iStereoBlockSizeSam; i++ ) - { - vecsStereoSndCrd[i] = vecsAudioSndCrdStereo[i]; - } - } - else + if ( !bUseStereo ) { // copy mono data in stereo sound card buffer for ( i = 0, j = 0; i < iMonoBlockSizeSam; i++, j += 2 ) diff --git a/src/client.h b/src/client.h index 9207fbfb..1ff1cdc2 100755 --- a/src/client.h +++ b/src/client.h @@ -104,6 +104,9 @@ public: bool GetCELTHighQuality() const { return bCeltDoHighQuality; } void SetCELTHighQuality ( const bool bNCeltHighQualityFlag ); + bool GetUseStereo() const { return bUseStereo; } + void SetUseStereo ( const bool bNUseStereo ); + int GetAudioInFader() const { return iAudioInFader; } void SetAudioInFader ( const int iNV ) { iAudioInFader = iNV; } @@ -236,7 +239,7 @@ protected: CELTDecoder* CeltDecoderStereo; int iCeltNumCodedBytes; bool bCeltDoHighQuality; - bool bStereo; + bool bUseStereo; CVector vecCeltData; CSocket Socket; @@ -270,7 +273,6 @@ protected: EGUIDesign eGUIDesign; CVector vecsAudioSndCrdMono; - CVector vecsAudioSndCrdStereo; CVector vecdAudioStereo; CVector vecsNetwork; diff --git a/src/clientsettingsdlg.cpp b/src/clientsettingsdlg.cpp index d9344547..9805965a 100755 --- a/src/clientsettingsdlg.cpp +++ b/src/clientsettingsdlg.cpp @@ -182,6 +182,15 @@ CClientSettingsDlg::CClientSettingsDlg ( CClient* pNCliP, QWidget* parent, cbUseHighQualityAudio->setAccessibleName ( tr ( "Use high quality audio " "check box" ) ); + // use stereo + cbUseStereo->setWhatsThis ( tr ( "Stereo " + "Enables the stereo mode. If not checked, a mono mode is used. " + "Enabling stereo mode will increase the stream data rate. Make sure " + "that the current upload rate does not exceed the available bandwidth " + "of your internet connection." ) ); + + cbUseStereo->setAccessibleName ( tr ( "Stereo check box" ) ); + // current connection status parameter QString strConnStats = tr ( "Current Connection Status " "Parameter: The ping time is the time required for the audio " @@ -283,6 +292,16 @@ cbGUIDesignFancy->setVisible ( false ); cbUseHighQualityAudio->setCheckState ( Qt::Unchecked ); } + // "Stereo" check box + if ( pClient->GetUseStereo() ) + { + cbUseStereo->setCheckState ( Qt::Checked ); + } + else + { + cbUseStereo->setCheckState ( Qt::Unchecked ); + } + // set text for sound card buffer delay radio buttons rButBufferDelayPreferred->setText ( GenSndCrdBufferDelayString ( FRAME_SIZE_FACTOR_PREFERRED * SYSTEM_FRAME_SIZE_SAMPLES, @@ -325,6 +344,9 @@ cbGUIDesignFancy->setVisible ( false ); QObject::connect ( cbUseHighQualityAudio, SIGNAL ( stateChanged ( int ) ), this, SLOT ( OnUseHighQualityAudioStateChanged ( int ) ) ); + QObject::connect ( cbUseStereo, SIGNAL ( stateChanged ( int ) ), + this, SLOT ( OnUseStereoStateChanged ( int ) ) ); + QObject::connect ( cbAutoJitBuf, SIGNAL ( stateChanged ( int ) ), this, SLOT ( OnAutoJitBuf ( int ) ) ); @@ -572,7 +594,13 @@ void CClientSettingsDlg::OnGUIDesignFancyStateChanged ( int value ) void CClientSettingsDlg::OnUseHighQualityAudioStateChanged ( int value ) { pClient->SetCELTHighQuality ( value == Qt::Checked ); - UpdateDisplay(); + UpdateDisplay(); // upload rate will be changed +} + +void CClientSettingsDlg::OnUseStereoStateChanged ( int value ) +{ + pClient->SetUseStereo ( value == Qt::Checked ); + UpdateDisplay(); // upload rate will be changed } void CClientSettingsDlg::OnSndCrdBufferDelayButtonGroupClicked ( QAbstractButton* button ) diff --git a/src/clientsettingsdlg.h b/src/clientsettingsdlg.h index 6ecbef15..dc6c0f95 100755 --- a/src/clientsettingsdlg.h +++ b/src/clientsettingsdlg.h @@ -90,6 +90,7 @@ protected: void OnOpenChatOnNewMessageStateChanged ( int value ); void OnGUIDesignFancyStateChanged ( int value ); void OnUseHighQualityAudioStateChanged ( int value ); + void OnUseStereoStateChanged ( int value ); void OnSndCrdBufferDelayButtonGroupClicked ( QAbstractButton* button ); void OnPingTimeResult ( int iPingTime ); void OnSoundCrdSelection ( int iSndDevIdx ); diff --git a/src/clientsettingsdlgbase.ui b/src/clientsettingsdlgbase.ui index 5a215204..48e2272a 100755 --- a/src/clientsettingsdlgbase.ui +++ b/src/clientsettingsdlgbase.ui @@ -432,6 +432,16 @@ + + + + Qt::NonModal + + + Stereo + + + @@ -440,7 +450,7 @@ 201 - 71 + 81 diff --git a/src/settings.cpp b/src/settings.cpp index 0a8ab7ff..68982ec7 100755 --- a/src/settings.cpp +++ b/src/settings.cpp @@ -189,6 +189,12 @@ void CSettings::ReadIniFile ( const QString& sFileName ) { pClient->SetCELTHighQuality ( bValue ); } + + // flag whether stereo mode is used + if ( GetFlagIniSet ( IniXMLDocument, "client", "stereoaudio", bValue ) ) + { + pClient->SetUseStereo ( bValue ); + } } void CSettings::WriteIniFile ( const QString& sFileName ) @@ -266,6 +272,10 @@ void CSettings::WriteIniFile ( const QString& sFileName ) SetFlagIniSet ( IniXMLDocument, "client", "highqualityaudio", pClient->GetCELTHighQuality() ); + // flag whether stereo mode is used + SetFlagIniSet ( IniXMLDocument, "client", "stereoaudio", + pClient->GetUseStereo() ); + // prepare file name for storing initialization data in XML file QString sCurFileName = sFileName; if ( sCurFileName.isEmpty() )