Implemented panning for channels.
This commit is contained in:
parent
5c4ba499f6
commit
764ed82ccb
11 changed files with 213 additions and 16 deletions
66
src/audiomixerboard.cpp
Executable file → Normal file
66
src/audiomixerboard.cpp
Executable file → Normal file
|
@ -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 ( "<b>Panning:</b> 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 ( "<b>Mute:</b> 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<double> ( 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<int>( vecpChanFader.size() ); i++) {
|
||||
QObject::connect ( vecpChanFader[i], SIGNAL ( panValueChanged ( double ) ),
|
||||
this, SLOT ( OnPanValueChanged ( double ) ) );
|
||||
}
|
||||
|
||||
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)
|
||||
connectFaderSignalsToMixerBoardSlots<MAX_NUM_CHANNELS>();
|
||||
|
||||
|
@ -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<CChannelFader * >(sender());
|
||||
if (!channelFader) {
|
||||
return;
|
||||
}
|
||||
// a clumsy way to find the index. Why not to use QList or QVector<ChannelFader * > and indexOf?
|
||||
CVector<CChannelFader *>::iterator it = std::find(vecpChanFader.begin(), vecpChanFader.end(), channelFader);
|
||||
int iChannelIdx = static_cast<int>( std::distance(vecpChanFader.begin(), it) ); //static_cast<int>(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
|
||||
|
|
14
src/audiomixerboard.h
Executable file → Normal file
14
src/audiomixerboard.h
Executable file → Normal file
|
@ -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<CChannelFader*> 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 );
|
||||
};
|
||||
|
|
|
@ -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> ( "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 );
|
||||
|
|
|
@ -110,9 +110,15 @@ public:
|
|||
double GetGain ( const int iChanID );
|
||||
double GetFadeInGain() { return static_cast<double> ( 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<double> vecdGains;
|
||||
|
||||
CVector<double> vecdPannings;
|
||||
|
||||
// network jitter-buffer
|
||||
CNetBufWithStats SockBuf;
|
||||
int iCurSockBufNumFrames;
|
||||
|
@ -228,6 +236,7 @@ public slots:
|
|||
void OnSendProtMessage ( CVector<uint8_t> 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();
|
||||
|
|
|
@ -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 )
|
||||
|
|
|
@ -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 ) ) );
|
||||
|
||||
|
|
|
@ -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 ); }
|
||||
|
||||
|
|
|
@ -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<uint8_t> vecData ( 3 ); // 3 bytes of data
|
||||
int iPos = 0; // init position pointer
|
||||
|
||||
// build data vector
|
||||
// channel ID
|
||||
PutValOnStream ( vecData, iPos, static_cast<uint32_t> ( iChanID ), 1 );
|
||||
|
||||
// actual gain, we convert from double with range 0..1 to integer
|
||||
const int iCurPan = static_cast<int> ( dPan * ( 1 << 15 ) );
|
||||
|
||||
PutValOnStream ( vecData, iPos, static_cast<uint32_t> ( iCurPan ), 2 );
|
||||
|
||||
CreateAndSendMessage ( PROTMESSID_CHANNEL_PAN, vecData );
|
||||
}
|
||||
|
||||
bool CProtocol::EvaluateChanGainMes ( const CVector<uint8_t>& vecData )
|
||||
{
|
||||
int iPos = 0; // init position pointer
|
||||
|
@ -810,6 +831,33 @@ bool CProtocol::EvaluateChanGainMes ( const CVector<uint8_t>& vecData )
|
|||
return false; // no error
|
||||
}
|
||||
|
||||
bool CProtocol::EvaluateChanPanMes(const CVector<uint8_t> &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<int> ( GetValFromStream ( vecData, iPos, 1 ) );
|
||||
|
||||
// pan (read integer value)
|
||||
const int iData =
|
||||
static_cast<int> ( GetValFromStream ( vecData, iPos, 2 ) );
|
||||
|
||||
// we convert the gain from integer to double with range 0..1
|
||||
const double dNewPan = static_cast<double> ( iData ) / ( 1 << 15 );
|
||||
|
||||
// invoke message action
|
||||
emit ChangeChanPan ( iCurID, dNewPan );
|
||||
|
||||
return false; // no error
|
||||
}
|
||||
|
||||
void CProtocol::CreateConClientListMes ( const CVector<CChannelInfo>& vecChanInfo )
|
||||
{
|
||||
const int iNumClients = vecChanInfo.Size();
|
||||
|
|
|
@ -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<CChannelInfo>& vecChanInfo );
|
||||
void CreateChanPanMes ( const int iChanID, const double dPan );
|
||||
void CreateConClientListMes ( const CVector<CChannelInfo>& vecChanInfo );
|
||||
void CreateReqConnClientsList();
|
||||
void CreateChanInfoMes ( const CChannelCoreInfo ChanInfo );
|
||||
void CreateReqChanInfoMes();
|
||||
|
@ -218,6 +220,7 @@ protected:
|
|||
bool EvaluateJitBufMes ( const CVector<uint8_t>& vecData );
|
||||
bool EvaluateReqJitBufMes();
|
||||
bool EvaluateChanGainMes ( const CVector<uint8_t>& vecData );
|
||||
bool EvaluateChanPanMes ( const CVector<uint8_t>& vecData );
|
||||
bool EvaluateConClientListMes ( const CVector<uint8_t>& vecData );
|
||||
bool EvaluateReqConnClientsList();
|
||||
bool EvaluateChanInfoMes ( const CVector<uint8_t>& 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<CChannelInfo> vecChanInfo );
|
||||
void ServerFullMesReceived();
|
||||
void ReqConnClientsList();
|
||||
|
|
|
@ -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<CVector<int16_t> >& vecvecsData,
|
||||
const CVector<double>& vecdGains,
|
||||
const CVector<int>& vecNumAudioChannels,
|
||||
CVector<int16_t>& vecsOutData,
|
||||
const int iCurNumAudChan,
|
||||
const int iNumClients )
|
||||
void CServer::ProcessData (const CVector<CVector<int16_t> >& vecvecsData,
|
||||
const CVector<double>& vecdGains,
|
||||
const CVector<double>& vecdPannings,
|
||||
const CVector<int>& vecNumAudioChannels,
|
||||
CVector<int16_t>& vecsOutData,
|
||||
const int iCurNumAudChan,
|
||||
const int iNumClients )
|
||||
{
|
||||
int i, j, k;
|
||||
|
||||
|
@ -1352,6 +1358,10 @@ void CServer::ProcessData ( const CVector<CVector<int16_t> >& vecvecsData,
|
|||
// get a reference to the audio data and gain of the current client
|
||||
const CVector<int16_t>& 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<double> ( 1.0 ) )
|
||||
|
@ -1363,11 +1373,11 @@ void CServer::ProcessData ( const CVector<CVector<int16_t> >& vecvecsData,
|
|||
{
|
||||
// left channel
|
||||
vecsOutData[k] = Double2Short (
|
||||
static_cast<double> ( vecsOutData[k] ) + vecsData[i] );
|
||||
static_cast<double> ( vecsOutData[k] ) + vecsData[i] * dPanCoefL);
|
||||
|
||||
// right channel
|
||||
vecsOutData[k + 1] = Double2Short (
|
||||
static_cast<double> ( vecsOutData[k + 1] ) + vecsData[i] );
|
||||
static_cast<double> ( vecsOutData[k + 1] ) + vecsData[i] * dPanCoefR);
|
||||
}
|
||||
}
|
||||
else
|
||||
|
@ -1375,8 +1385,9 @@ void CServer::ProcessData ( const CVector<CVector<int16_t> >& vecvecsData,
|
|||
// stereo
|
||||
for ( i = 0; i < ( 2 * iServerFrameSizeSamples ); i++ )
|
||||
{
|
||||
double pan = (i%2==0) ? dPanCoefL : dPanCoefR;
|
||||
vecsOutData[i] = Double2Short (
|
||||
static_cast<double> ( vecsOutData[i] ) + vecsData[i] );
|
||||
static_cast<double> ( vecsOutData[i] ) + vecsData[i] * pan );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1389,11 +1400,11 @@ void CServer::ProcessData ( const CVector<CVector<int16_t> >& 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<CVector<int16_t> >& 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 );
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -287,6 +287,7 @@ protected:
|
|||
|
||||
void ProcessData ( const CVector<CVector<int16_t> >& vecvecsData,
|
||||
const CVector<double>& vecdGains,
|
||||
const CVector<double>& vecdPannings,
|
||||
const CVector<int>& vecNumAudioChannels,
|
||||
CVector<int16_t>& vecsOutData,
|
||||
const int iCurNumAudChan,
|
||||
|
@ -328,6 +329,7 @@ protected:
|
|||
CVector<int> vecChanIDsCurConChan;
|
||||
|
||||
CVector<CVector<double> > vecvecdGains;
|
||||
CVector<CVector<double> > vecvecdPannings;
|
||||
CVector<CVector<int16_t> > vecvecsData;
|
||||
CVector<int> vecNumAudioChannels;
|
||||
CVector<int> vecNumFrameSizeConvBlocks;
|
||||
|
|
Loading…
Reference in a new issue