diff --git a/src/audiomixerboard.cpp b/src/audiomixerboard.cpp
old mode 100755
new mode 100644
index c1ca9713..af367bb1
--- a/src/audiomixerboard.cpp
+++ b/src/audiomixerboard.cpp
@@ -40,6 +40,8 @@ CChannelFader::CChannelFader ( QWidget* pNW,
plbrChannelLevel = new CMultiColorLEDBar ( pLevelsBox );
pFader = new QSlider ( Qt::Vertical, pLevelsBox );
+ pPan = new QSlider (Qt::Horizontal, pLevelsBox);
+
pMuteSoloBox = new QWidget ( pFrame );
pcbMute = new QCheckBox ( "Mute", pMuteSoloBox );
pcbSolo = new QCheckBox ( "Solo", pMuteSoloBox );
@@ -64,6 +66,11 @@ CChannelFader::CChannelFader ( QWidget* pNW,
pFader->setRange ( 0, AUD_MIX_FADER_MAX );
pFader->setTickInterval ( AUD_MIX_FADER_MAX / 9 );
+ // setup panning slider
+ pPan->setRange( 0, AUD_MIX_FADER_MAX);
+ pPan->setValue(AUD_MIX_FADER_MAX/2);
+
+
// setup fader tag label (black bold text which is centered)
plblLabel->setTextFormat ( Qt::PlainText );
plblLabel->setAlignment ( Qt::AlignHCenter | Qt::AlignVCenter );
@@ -96,6 +103,8 @@ CChannelFader::CChannelFader ( QWidget* pNW,
pMuteSoloGrid->addWidget ( pcbMute, 0, Qt::AlignLeft );
pMuteSoloGrid->addWidget ( pcbSolo, 0, Qt::AlignLeft );
+ //TODO: Pan row: "L" slider "R"
+ pMainGrid->addWidget ( pPan, 0, Qt::AlignCenter );
pMainGrid->addWidget ( pLevelsBox, 0, Qt::AlignHCenter );
pMainGrid->addWidget ( pMuteSoloBox, 0, Qt::AlignHCenter );
pMainGrid->addWidget ( pLabelInstBox );
@@ -119,6 +128,10 @@ CChannelFader::CChannelFader ( QWidget* pNW,
pFader->setAccessibleName ( tr ( "Local mix level setting of the current audio "
"channel at the server" ) );
+ pPan->setWhatsThis ( tr ( "Panning: Sets the panning position from Left to Right of the channel. "
+ " Works only in stero or preferably mono in/stereo out mode." ) );
+ pPan->setAccessibleName ( tr ( "Local panning position of the current audio channel at the server" ) );
+
pcbMute->setWhatsThis ( tr ( "Mute: With the Mute checkbox, the "
"audio channel can be muted." ) );
pcbMute->setAccessibleName ( tr ( "Mute button" ) );
@@ -145,6 +158,9 @@ CChannelFader::CChannelFader ( QWidget* pNW,
QObject::connect ( pFader, SIGNAL ( valueChanged ( int ) ),
this, SLOT ( OnLevelValueChanged ( int ) ) );
+ QObject::connect ( pPan, SIGNAL ( valueChanged ( int ) ),
+ this, SLOT ( OnPanValueChanged ( int ) ) );
+
QObject::connect ( pcbMute, SIGNAL ( stateChanged ( int ) ),
this, SLOT ( OnMuteStateChanged ( int ) ) );
@@ -243,8 +259,9 @@ void CChannelFader::SetupFaderTag ( const ESkillLevel eSkillLevel )
void CChannelFader::Reset()
{
- // init gain value -> maximum value as definition according to server
+ // init gain and pan value -> maximum value as definition according to server
pFader->setValue ( AUD_MIX_FADER_MAX );
+ pPan->setValue ( AUD_MIX_FADER_MAX/2 );
// reset mute/solo check boxes and level meter
pcbMute->setChecked ( false );
@@ -281,6 +298,18 @@ void CChannelFader::SetFaderLevel ( const int iLevel )
// server about the change
pFader->setValue ( iLevel );
SendFaderLevelToServer ( iLevel );
+ }
+}
+
+void CChannelFader::SetPanValue(const int iPan)
+{
+ // first make a range check
+ if ( ( iPan >= 0 ) && ( iPan <= AUD_MIX_FADER_MAX ) )
+ {
+ // we set the new fader level in the GUI (slider control) and also tell the
+ // server about the change
+ pPan->setValue ( iPan );
+ SendPanValueToServer( iPan );
}
}
@@ -309,6 +338,20 @@ void CChannelFader::SendFaderLevelToServer ( const int iLevel )
}
}
+void CChannelFader::SendPanValueToServer ( const int iPan )
+{
+
+ // if mute flag is set or other channel is on solo, do not apply the pan
+ if ( ( pcbMute->checkState() == Qt::Unchecked ) &&
+ ( !bOtherChannelIsSolo || IsSolo() ) )
+ {
+ // emit signal for new pan value
+ double dPan = static_cast ( iPan ) / AUD_MIX_FADER_MAX;
+ emit panValueChanged ( dPan );
+ }
+
+}
+
void CChannelFader::OnMuteStateChanged ( int value )
{
// call muting function
@@ -562,6 +605,13 @@ CAudioMixerBoard::CAudioMixerBoard ( QWidget* parent, Qt::WindowFlags ) :
// Connections -------------------------------------------------------------
+
+ for (int i=0; i< static_cast( vecpChanFader.size() ); i++) {
+ QObject::connect ( vecpChanFader[i], SIGNAL ( panValueChanged ( double ) ),
+ this, SLOT ( OnPanValueChanged ( double ) ) );
+ }
+
+
#if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)
connectFaderSignalsToMixerBoardSlots();
@@ -908,6 +958,20 @@ void CAudioMixerBoard::UpdateGainValue ( const int iChannelIdx,
emit ChangeChanGain ( iChannelIdx, dValue );
}
+void CAudioMixerBoard::OnPanValueChanged ( const double dValue )
+{
+
+ // get channel index from sender according t, this SHOULD coincide with the chanID.
+ CChannelFader * channelFader = qobject_cast(sender());
+ if (!channelFader) {
+ return;
+ }
+ // a clumsy way to find the index. Why not to use QList or QVector and indexOf?
+ CVector::iterator it = std::find(vecpChanFader.begin(), vecpChanFader.end(), channelFader);
+ int iChannelIdx = static_cast( std::distance(vecpChanFader.begin(), it) ); //static_cast(it);
+ emit ChangeChanPan ( iChannelIdx, dValue );
+}
+
void CAudioMixerBoard::StoreFaderSettings ( CChannelFader* pChanFader )
{
// if the fader was visible and the name is not empty, we store the old gain
diff --git a/src/audiomixerboard.h b/src/audiomixerboard.h
old mode 100755
new mode 100644
index f5d04393..b73fbbaa
--- a/src/audiomixerboard.h
+++ b/src/audiomixerboard.h
@@ -61,9 +61,11 @@ public:
void UpdateSoloState ( const bool bNewOtherSoloState );
void SetFaderLevel ( const int iLevel );
+ void SetPanValue ( const int iPan );
void SetFaderIsSolo ( const bool bIsSolo );
void SetFaderIsMute ( const bool bIsMute );
int GetFaderLevel() { return pFader->value(); }
+ int GetPanValue() {return pPan->value(); }
void Reset();
void SetChannelLevel ( const uint16_t iLevel );
@@ -71,6 +73,7 @@ protected:
double CalcFaderGain ( const int value );
void SetMute ( const bool bState );
void SendFaderLevelToServer ( const int iLevel );
+ void SendPanValueToServer ( const int iPan );
void SetupFaderTag ( const ESkillLevel eSkillLevel );
QFrame* pFrame;
@@ -79,6 +82,7 @@ protected:
QWidget* pMuteSoloBox;
CMultiColorLEDBar* plbrChannelLevel;
QSlider* pFader;
+ QSlider* pPan;
QCheckBox* pcbMute;
QCheckBox* pcbSolo;
@@ -94,10 +98,12 @@ protected:
public slots:
void OnLevelValueChanged ( int value ) { SendFaderLevelToServer ( value ); }
+ void OnPanValueChanged ( int value ) {SendPanValueToServer ( value ); }
void OnMuteStateChanged ( int value );
signals:
void gainValueChanged ( double value );
+ void panValueChanged (double value );
void soloStateChanged ( int value );
};
@@ -160,6 +166,9 @@ protected:
void StoreFaderSettings ( CChannelFader* pChanFader );
void UpdateSoloStates();
+ void OnGainValueChanged ( const int iChannelIdx,
+ const double dValue );
+
CVector vecpChanFader;
QGroupBox* pGroupBox;
QHBoxLayout* pMainLayout;
@@ -180,8 +189,10 @@ protected:
#endif
-#if QT_VERSION < 0x50000 // MOC does not expand macros in Qt 4, so we cannot use QT_VERSION_CHECK(5, 0, 0)
public slots:
+ void OnPanValueChanged ( const double dValue );
+
+#if QT_VERSION < 0x50000 // MOC does not expand macros in Qt 4, so we cannot use QT_VERSION_CHECK(5, 0, 0)
// CODE TAG: MAX_NUM_CHANNELS_TAG
// make sure we have MAX_NUM_CHANNELS connections!!!
void OnGainValueChangedCh0 ( double dValue ) { UpdateGainValue ( 0, dValue ); }
@@ -241,5 +252,6 @@ public slots:
signals:
void ChangeChanGain ( int iId, double dGain );
+ void ChangeChanPan ( int iId, double dPan );
void NumClientsChanged ( int iNewNumClients );
};
diff --git a/src/channel.cpp b/src/channel.cpp
index de629a82..19142925 100755
--- a/src/channel.cpp
+++ b/src/channel.cpp
@@ -28,6 +28,7 @@
// CChannel implementation *****************************************************
CChannel::CChannel ( const bool bNIsServer ) :
vecdGains ( MAX_NUM_CHANNELS, 1.0 ),
+ vecdPannings ( MAX_NUM_CHANNELS, 0.5),
bDoAutoSockBufSize ( true ),
iFadeInCnt ( 0 ),
iFadeInCntMax ( FADE_IN_NUM_FRAMES_DBLE_FRAMESIZE ),
@@ -86,6 +87,9 @@ qRegisterMetaType ( "CHostAddress" );
QObject::connect( &Protocol, SIGNAL ( ChangeChanGain ( int, double ) ),
this, SLOT ( OnChangeChanGain ( int, double ) ) );
+ QObject::connect( &Protocol, SIGNAL ( ChangeChanPan ( int, double ) ),
+ this, SLOT ( OnChangeChanPan ( int, double ) ) );
+
QObject::connect( &Protocol, SIGNAL ( ChangeChanInfo ( CChannelCoreInfo ) ),
this, SLOT ( OnChangeChanInfo ( CChannelCoreInfo ) ) );
@@ -269,6 +273,32 @@ double CChannel::GetGain ( const int iChanID )
}
}
+void CChannel::SetPan(const int iChanID, const double dNewPan)
+{
+ QMutexLocker locker ( &Mutex );
+
+ // set value (make sure channel ID is in range)
+ if ( ( iChanID >= 0 ) && ( iChanID < MAX_NUM_CHANNELS ) )
+ {
+ vecdPannings[iChanID] = dNewPan;
+ }
+}
+
+double CChannel::GetPan(const int iChanID)
+{
+ QMutexLocker locker ( &Mutex );
+
+ // get value (make sure channel ID is in range)
+ if ( ( iChanID >= 0 ) && ( iChanID < MAX_NUM_CHANNELS ) )
+ {
+ return vecdPannings[iChanID];
+ }
+ else
+ {
+ return 0;
+ }
+}
+
void CChannel::SetChanInfo ( const CChannelCoreInfo& NChanInf )
{
// apply value (if different from previous one)
@@ -335,6 +365,12 @@ void CChannel::OnChangeChanGain ( int iChanID,
SetGain ( iChanID, dNewGain );
}
+void CChannel::OnChangeChanPan ( int iChanID,
+ double dNewPan )
+{
+ SetPan( iChanID, dNewPan );
+}
+
void CChannel::OnChangeChanInfo ( CChannelCoreInfo ChanInfo )
{
SetChanInfo ( ChanInfo );
diff --git a/src/channel.h b/src/channel.h
index 3369b535..9c34ef01 100755
--- a/src/channel.h
+++ b/src/channel.h
@@ -110,9 +110,15 @@ public:
double GetGain ( const int iChanID );
double GetFadeInGain() { return static_cast ( iFadeInCnt ) / iFadeInCntMax; }
+ void SetPan ( const int iChanID, const double dNewPan );
+ double GetPan ( const int iChanID );
+
void SetRemoteChanGain ( const int iId, const double dGain )
{ Protocol.CreateChanGainMes ( iId, dGain ); }
+ void SetRemoteChanPan ( const int iId, const double dPan )
+ { Protocol.CreateChanPanMes ( iId, dPan ); }
+
bool SetSockBufNumFrames ( const int iNewNumFrames,
const bool bPreserve = false );
int GetSockBufNumFrames() const { return iCurSockBufNumFrames; }
@@ -191,6 +197,8 @@ protected:
// mixer and effect settings
CVector vecdGains;
+ CVector vecdPannings;
+
// network jitter-buffer
CNetBufWithStats SockBuf;
int iCurSockBufNumFrames;
@@ -228,6 +236,7 @@ public slots:
void OnSendProtMessage ( CVector vecMessage );
void OnJittBufSizeChange ( int iNewJitBufSize );
void OnChangeChanGain ( int iChanID, double dNewGain );
+ void OnChangeChanPan ( int iChanID, double dNewPan );
void OnChangeChanInfo ( CChannelCoreInfo ChanInfo );
void OnNetTranspPropsReceived ( CNetworkTransportProps NetworkTransportProps );
void OnReqNetTranspProps();
diff --git a/src/client.h b/src/client.h
index 15837f00..3dbbd0b6 100755
--- a/src/client.h
+++ b/src/client.h
@@ -244,6 +244,9 @@ public:
void SetRemoteChanGain ( const int iId, const double dGain )
{ Channel.SetRemoteChanGain ( iId, dGain ); }
+ void SetRemoteChanPan ( const int iId, const double dPan )
+ { Channel.SetRemoteChanPan ( iId, dPan ); }
+
void SetRemoteInfo() { Channel.SetRemoteInfo ( ChannelInfo ); }
void CreateChatTextMes ( const QString& strChatText )
diff --git a/src/clientdlg.cpp b/src/clientdlg.cpp
index fb138d3e..1a5dc9f1 100755
--- a/src/clientdlg.cpp
+++ b/src/clientdlg.cpp
@@ -520,6 +520,9 @@ CClientDlg::CClientDlg ( CClient* pNCliP,
QObject::connect ( MainMixerBoard, SIGNAL ( ChangeChanGain ( int, double ) ),
this, SLOT ( OnChangeChanGain ( int, double ) ) );
+ QObject::connect ( MainMixerBoard, SIGNAL ( ChangeChanPan ( int, double ) ),
+ this, SLOT ( OnChangeChanPan ( int, double ) ) );
+
QObject::connect ( MainMixerBoard, SIGNAL ( NumClientsChanged ( int ) ),
this, SLOT ( OnNumClientsChanged ( int ) ) );
diff --git a/src/clientdlg.h b/src/clientdlg.h
index 5d265574..8c870878 100755
--- a/src/clientdlg.h
+++ b/src/clientdlg.h
@@ -170,6 +170,9 @@ public slots:
void OnChangeChanGain ( int iId, double dGain )
{ pClient->SetRemoteChanGain ( iId, dGain ); }
+ void OnChangeChanPan ( int iId, double dPan )
+ { pClient->SetRemoteChanPan ( iId, dPan ); }
+
void OnNewLocalInputText ( QString strChatText )
{ pClient->CreateChatTextMes ( strChatText ); }
diff --git a/src/protocol.cpp b/src/protocol.cpp
index ed54bf2c..6c915b6e 100755
--- a/src/protocol.cpp
+++ b/src/protocol.cpp
@@ -572,6 +572,10 @@ if ( rand() < ( RAND_MAX / 2 ) ) return false;
bRet = EvaluateChanGainMes ( vecbyMesBodyData );
break;
+ case PROTMESSID_CHANNEL_PAN:
+ bRet = EvaluateChanPanMes ( vecbyMesBodyData );
+ break;
+
case PROTMESSID_CONN_CLIENTS_LIST:
bRet = EvaluateConClientListMes ( vecbyMesBodyData );
break;
@@ -783,6 +787,23 @@ void CProtocol::CreateChanGainMes ( const int iChanID, const double dGain )
CreateAndSendMessage ( PROTMESSID_CHANNEL_GAIN, vecData );
}
+void CProtocol::CreateChanPanMes(const int iChanID, const double dPan)
+{
+ CVector vecData ( 3 ); // 3 bytes of data
+ int iPos = 0; // init position pointer
+
+ // build data vector
+ // channel ID
+ PutValOnStream ( vecData, iPos, static_cast ( iChanID ), 1 );
+
+ // actual gain, we convert from double with range 0..1 to integer
+ const int iCurPan = static_cast ( dPan * ( 1 << 15 ) );
+
+ PutValOnStream ( vecData, iPos, static_cast ( iCurPan ), 2 );
+
+ CreateAndSendMessage ( PROTMESSID_CHANNEL_PAN, vecData );
+}
+
bool CProtocol::EvaluateChanGainMes ( const CVector& vecData )
{
int iPos = 0; // init position pointer
@@ -810,6 +831,33 @@ bool CProtocol::EvaluateChanGainMes ( const CVector& vecData )
return false; // no error
}
+bool CProtocol::EvaluateChanPanMes(const CVector &vecData)
+{
+ int iPos = 0; // init position pointer
+
+ // check size
+ if ( vecData.Size() != 3 )
+ {
+ return true; // return error code
+ }
+
+ // channel ID
+ const int iCurID =
+ static_cast ( GetValFromStream ( vecData, iPos, 1 ) );
+
+ // pan (read integer value)
+ const int iData =
+ static_cast ( GetValFromStream ( vecData, iPos, 2 ) );
+
+ // we convert the gain from integer to double with range 0..1
+ const double dNewPan = static_cast ( iData ) / ( 1 << 15 );
+
+ // invoke message action
+ emit ChangeChanPan ( iCurID, dNewPan );
+
+ return false; // no error
+}
+
void CProtocol::CreateConClientListMes ( const CVector& vecChanInfo )
{
const int iNumClients = vecChanInfo.Size();
diff --git a/src/protocol.h b/src/protocol.h
index 027c4284..542cf700 100755
--- a/src/protocol.h
+++ b/src/protocol.h
@@ -55,6 +55,7 @@
#define PROTMESSID_OPUS_SUPPORTED 26 // tells that OPUS codec is supported
#define PROTMESSID_LICENCE_REQUIRED 27 // licence required
#define PROTMESSID_REQ_CHANNEL_LEVEL_LIST 28 // request the channel level list
+#define PROTMESSID_CHANNEL_PAN 29 // set channel gain for mix
// message IDs of connection less messages (CLM)
// DEFINITION -> start at 1000, end at 1999, see IsConnectionLessMessageID
@@ -96,7 +97,8 @@ public:
void CreateJitBufMes ( const int iJitBufSize );
void CreateReqJitBufMes();
void CreateChanGainMes ( const int iChanID, const double dGain );
- void CreateConClientListMes ( const CVector& vecChanInfo );
+ void CreateChanPanMes ( const int iChanID, const double dPan );
+ void CreateConClientListMes ( const CVector& vecChanInfo );
void CreateReqConnClientsList();
void CreateChanInfoMes ( const CChannelCoreInfo ChanInfo );
void CreateReqChanInfoMes();
@@ -218,6 +220,7 @@ protected:
bool EvaluateJitBufMes ( const CVector& vecData );
bool EvaluateReqJitBufMes();
bool EvaluateChanGainMes ( const CVector& vecData );
+ bool EvaluateChanPanMes ( const CVector& vecData );
bool EvaluateConClientListMes ( const CVector& vecData );
bool EvaluateReqConnClientsList();
bool EvaluateChanInfoMes ( const CVector& vecData );
@@ -276,6 +279,7 @@ signals:
void ReqJittBufSize();
void ChangeNetwBlSiFact ( int iNewNetwBlSiFact );
void ChangeChanGain ( int iChanID, double dNewGain );
+ void ChangeChanPan ( int iChanID, double dNewPan );
void ConClientListMesReceived ( CVector vecChanInfo );
void ServerFullMesReceived();
void ReqConnClientsList();
diff --git a/src/server.cpp b/src/server.cpp
index d3658c0c..69288057 100755
--- a/src/server.cpp
+++ b/src/server.cpp
@@ -339,6 +339,7 @@ CServer::CServer ( const int iNewMaxNumChan,
// allocate worst case memory for the temporary vectors
vecChanIDsCurConChan.Init ( iMaxNumChannels );
vecvecdGains.Init ( iMaxNumChannels );
+ vecvecdPannings.Init ( iMaxNumChannels );
vecvecsData.Init ( iMaxNumChannels );
vecNumAudioChannels.Init ( iMaxNumChannels );
vecNumFrameSizeConvBlocks.Init ( iMaxNumChannels );
@@ -349,6 +350,7 @@ CServer::CServer ( const int iNewMaxNumChan,
{
// init vectors storing information of all channels
vecvecdGains[i].Init ( iMaxNumChannels );
+ vecvecdPannings[i].Init ( iMaxNumChannels );
// we always use stereo audio buffers (see "vecsSendData")
vecvecsData[i].Init ( 2 /* stereo */ * DOUBLE_SYSTEM_FRAME_SIZE_SAMPLES /* worst case buffer size */ );
@@ -1047,9 +1049,11 @@ JitterMeas.Measure();
// "vecChanIDsCurConChan" to query the IDs of the currently
// connected channels
vecvecdGains[i][j] = vecChannels[iCurChanID].GetGain ( vecChanIDsCurConChan[j] );
-
// consider audio fade-in
vecvecdGains[i][j] *= vecChannels[vecChanIDsCurConChan[j]].GetFadeInGain();
+
+ //panning
+ vecvecdPannings[i][j] = vecChannels[iCurChanID].GetPan( vecChanIDsCurConChan[j] ); //((double)rand() / (double)(RAND_MAX)); //vecChannels[iCurChanID].GetGain ( vecChanIDsCurConChan[j] ); //TODO: GetPanning
}
// If the server frame size is smaller than the received OPUS frame size, we need a conversion
@@ -1177,6 +1181,7 @@ JitterMeas.Measure();
// actual processing of audio data -> mix
ProcessData ( vecvecsData,
vecvecdGains[i],
+ vecvecdPannings[i],
vecNumAudioChannels,
vecsSendData,
iCurNumAudChan,
@@ -1275,12 +1280,13 @@ opus_custom_encoder_ctl ( CurOpusEncoder,
}
/// @brief Mix all audio data from all clients together.
-void CServer::ProcessData ( const CVector >& vecvecsData,
- const CVector& vecdGains,
- const CVector& vecNumAudioChannels,
- CVector& vecsOutData,
- const int iCurNumAudChan,
- const int iNumClients )
+void CServer::ProcessData (const CVector >& vecvecsData,
+ const CVector& vecdGains,
+ const CVector& vecdPannings,
+ const CVector& vecNumAudioChannels,
+ CVector& vecsOutData,
+ const int iCurNumAudChan,
+ const int iNumClients )
{
int i, j, k;
@@ -1352,6 +1358,10 @@ void CServer::ProcessData ( const CVector >& vecvecsData,
// get a reference to the audio data and gain of the current client
const CVector& vecsData = vecvecsData[j];
const double dGain = vecdGains[j];
+ const double dPan = vecdPannings[j];
+ const double dPanCoefL = sqrt(1-dPan); // faster: (1-dPan)
+ const double dPanCoefR = sqrt(dPan); // (dPan)
+ // see http://write.flossmanuals.net/csound/b-panning-and-spatialization/ for better formula, if needed
// if channel gain is 1, avoid multiplication for speed optimization
if ( dGain == static_cast ( 1.0 ) )
@@ -1363,11 +1373,11 @@ void CServer::ProcessData ( const CVector >& vecvecsData,
{
// left channel
vecsOutData[k] = Double2Short (
- static_cast ( vecsOutData[k] ) + vecsData[i] );
+ static_cast ( vecsOutData[k] ) + vecsData[i] * dPanCoefL);
// right channel
vecsOutData[k + 1] = Double2Short (
- static_cast ( vecsOutData[k + 1] ) + vecsData[i] );
+ static_cast ( vecsOutData[k + 1] ) + vecsData[i] * dPanCoefR);
}
}
else
@@ -1375,8 +1385,9 @@ void CServer::ProcessData ( const CVector >& vecvecsData,
// stereo
for ( i = 0; i < ( 2 * iServerFrameSizeSamples ); i++ )
{
+ double pan = (i%2==0) ? dPanCoefL : dPanCoefR;
vecsOutData[i] = Double2Short (
- static_cast ( vecsOutData[i] ) + vecsData[i] );
+ static_cast ( vecsOutData[i] ) + vecsData[i] * pan );
}
}
}
@@ -1389,11 +1400,11 @@ void CServer::ProcessData ( const CVector >& vecvecsData,
{
// left channel
vecsOutData[k] = Double2Short (
- vecsOutData[k] + vecsData[i] * dGain );
+ vecsOutData[k] + vecsData[i] * dGain * dPanCoefL);
// right channel
vecsOutData[k + 1] = Double2Short (
- vecsOutData[k + 1] + vecsData[i] * dGain );
+ vecsOutData[k + 1] + vecsData[i] * dGain * dPanCoefR);
}
}
else
@@ -1401,8 +1412,10 @@ void CServer::ProcessData ( const CVector >& vecvecsData,
// stereo
for ( i = 0; i < ( 2 * iServerFrameSizeSamples ); i++ )
{
+ double pan = (i%2==0) ? dPanCoefL : dPanCoefR;
vecsOutData[i] = Double2Short (
- vecsOutData[i] + vecsData[i] * dGain );
+ vecsOutData[i] + vecsData[i] * dGain * pan );
+
}
}
}
diff --git a/src/server.h b/src/server.h
index d56a42c8..6060dd07 100755
--- a/src/server.h
+++ b/src/server.h
@@ -287,6 +287,7 @@ protected:
void ProcessData ( const CVector >& vecvecsData,
const CVector& vecdGains,
+ const CVector& vecdPannings,
const CVector& vecNumAudioChannels,
CVector& vecsOutData,
const int iCurNumAudChan,
@@ -328,6 +329,7 @@ protected:
CVector vecChanIDsCurConChan;
CVector > vecvecdGains;
+ CVector > vecvecdPannings;
CVector > vecvecsData;
CVector vecNumAudioChannels;
CVector vecNumFrameSizeConvBlocks;