commit
2310832894
32 changed files with 2294 additions and 1853 deletions
|
@ -7,8 +7,12 @@
|
|||
|
||||
- add new "slim channel" skin, intended for large ensembles (#339)
|
||||
|
||||
- support sorting faders by channel instrument, coded by Alberstein8 (#356)
|
||||
|
||||
- support for storing/recovering the server window positions (#357)
|
||||
|
||||
TODO Mac audio interface -> crackling
|
||||
TODO try to reproduce: Quitting client when server window minimized not handled cleanly #355
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -207,7 +207,7 @@ void CChannelFader::SetGUIDesign ( const EGUIDesign eNewDesign )
|
|||
|
||||
case GD_SLIMFADER:
|
||||
pLabelPictGrid->addWidget ( plblLabel, 0, Qt::AlignHCenter ); // label below icons
|
||||
pLabelInstBox->setMinimumHeight ( 80 ); // maximum hight of the instrument+flag+label
|
||||
pLabelInstBox->setMinimumHeight ( 84 ); // maximum hight of the instrument+flag+label
|
||||
pPan->setFixedSize ( 28, 28 );
|
||||
pFader->setTickPosition ( QSlider::NoTicks );
|
||||
pFader->setStyleSheet ( "" );
|
||||
|
@ -314,7 +314,7 @@ void CChannelFader::Reset()
|
|||
plblInstrument->setToolTip ( "" );
|
||||
plblCountryFlag->setVisible ( false );
|
||||
plblCountryFlag->setToolTip ( "" );
|
||||
strReceivedName = "";
|
||||
cReceivedChanInfo = CChannelInfo();
|
||||
SetupFaderTag ( SL_NOT_SET );
|
||||
|
||||
// set a defined tool tip time out
|
||||
|
@ -438,15 +438,15 @@ void CChannelFader::SetChannelLevel ( const uint16_t iLevel )
|
|||
|
||||
void CChannelFader::SetChannelInfos ( const CChannelInfo& cChanInfo )
|
||||
{
|
||||
// store received channel info
|
||||
cReceivedChanInfo = cChanInfo;
|
||||
|
||||
// init properties for the tool tip
|
||||
int iTTInstrument = CInstPictures::GetNotUsedInstrument();
|
||||
QLocale::Country eTTCountry = QLocale::AnyCountry;
|
||||
|
||||
|
||||
// Label text --------------------------------------------------------------
|
||||
// store original received name
|
||||
strReceivedName = cChanInfo.strName;
|
||||
|
||||
// break text at predefined position
|
||||
const int iBreakPos = MAX_LEN_FADER_TAG / 2;
|
||||
|
||||
|
@ -521,9 +521,9 @@ void CChannelFader::SetChannelInfos ( const CChannelInfo& cChanInfo )
|
|||
QString strToolTip = "";
|
||||
|
||||
// alias/name
|
||||
if ( !strReceivedName.isEmpty() )
|
||||
if ( !cChanInfo.strName.isEmpty() )
|
||||
{
|
||||
strToolTip += "<h4>" + tr ( "Alias/Name" ) + "</h4>" + strReceivedName;
|
||||
strToolTip += "<h4>" + tr ( "Alias/Name" ) + "</h4>" + cChanInfo.strName;
|
||||
}
|
||||
|
||||
// instrument
|
||||
|
@ -768,21 +768,29 @@ void CAudioMixerBoard::HideAll()
|
|||
iMyChannelID = INVALID_INDEX;
|
||||
|
||||
// use original order of channel (by server ID)
|
||||
ChangeFaderOrder ( false );
|
||||
ChangeFaderOrder ( false, ST_BY_NAME );
|
||||
|
||||
// emit status of connected clients
|
||||
emit NumClientsChanged ( 0 ); // -> no clients connected
|
||||
}
|
||||
|
||||
void CAudioMixerBoard::ChangeFaderOrder ( const bool bDoSort )
|
||||
void CAudioMixerBoard::ChangeFaderOrder ( const bool bDoSort,
|
||||
const EChSortType eChSortType )
|
||||
{
|
||||
// create a pair list of lower strings and fader ID for each channel
|
||||
QList<QPair<QString, int> > PairList;
|
||||
|
||||
for ( int i = 0; i < MAX_NUM_CHANNELS; i++ )
|
||||
{
|
||||
if ( eChSortType == ST_BY_NAME )
|
||||
{
|
||||
PairList << QPair<QString, int> ( vecpChanFader[i]->GetReceivedName().toLower(), i );
|
||||
}
|
||||
else // ST_BY_INSTRUMENT
|
||||
{
|
||||
PairList << QPair<QString, int> ( CInstPictures::GetName ( vecpChanFader[i]->GetReceivedInstrument() ), i );
|
||||
}
|
||||
}
|
||||
|
||||
// if requested, sort the channels
|
||||
if ( bDoSort )
|
||||
|
|
|
@ -49,7 +49,8 @@ class CChannelFader : public QObject
|
|||
public:
|
||||
CChannelFader ( QWidget* pNW );
|
||||
|
||||
QString GetReceivedName() { return strReceivedName; }
|
||||
QString GetReceivedName() { return cReceivedChanInfo.strName; }
|
||||
int GetReceivedInstrument() { return cReceivedChanInfo.iInstrument; }
|
||||
void SetChannelInfos ( const CChannelInfo& cChanInfo );
|
||||
void Show() { pFrame->show(); }
|
||||
void Hide() { pFrame->hide(); }
|
||||
|
@ -101,7 +102,7 @@ protected:
|
|||
QLabel* plblInstrument;
|
||||
QLabel* plblCountryFlag;
|
||||
|
||||
QString strReceivedName;
|
||||
CChannelInfo cReceivedChanInfo;
|
||||
|
||||
bool bOtherChannelIsSolo;
|
||||
bool bIsMyOwnFader;
|
||||
|
@ -146,7 +147,6 @@ public:
|
|||
CAudioMixerBoard ( QWidget* parent = nullptr, Qt::WindowFlags f = nullptr );
|
||||
|
||||
void HideAll();
|
||||
void ChangeFaderOrder ( const bool bDoSort );
|
||||
void ApplyNewConClientList ( CVector<CChannelInfo>& vecChanInfo );
|
||||
void SetServerName ( const QString& strNewServerName );
|
||||
void SetGUIDesign ( const EGUIDesign eNewDesign );
|
||||
|
@ -159,6 +159,9 @@ public:
|
|||
void SetFaderLevel ( const int iChannelIdx,
|
||||
const int iValue );
|
||||
|
||||
void ChangeFaderOrder ( const bool bDoSort,
|
||||
const EChSortType eChSortType );
|
||||
|
||||
void SetChannelLevels ( const CVector<uint16_t>& vecChannelLevel );
|
||||
|
||||
// settings
|
||||
|
|
140
src/client.cpp
140
src/client.cpp
|
@ -889,8 +889,9 @@ void CClient::Init()
|
|||
iNumAudioChannels );
|
||||
|
||||
// init reverberation
|
||||
AudioReverbL.Init ( SYSTEM_SAMPLE_RATE_HZ );
|
||||
AudioReverbR.Init ( SYSTEM_SAMPLE_RATE_HZ );
|
||||
AudioReverb.Init ( eAudioChannelConf,
|
||||
iStereoBlockSizeSam,
|
||||
SYSTEM_SAMPLE_RATE_HZ );
|
||||
|
||||
// init the sound card conversion buffers
|
||||
if ( bSndCrdConversionBufferRequired )
|
||||
|
@ -973,118 +974,41 @@ void CClient::ProcessAudioDataIntern ( CVector<int16_t>& vecsStereoSndCrd )
|
|||
// add reverberation effect if activated
|
||||
if ( iReverbLevel != 0 )
|
||||
{
|
||||
// calculate attenuation amplification factor
|
||||
const double dRevLev = static_cast<double> ( iReverbLevel ) / AUD_REVERB_MAX / 4;
|
||||
AudioReverb.Process ( vecsStereoSndCrd,
|
||||
bReverbOnLeftChan,
|
||||
static_cast<double> ( iReverbLevel ) / AUD_REVERB_MAX / 4 );
|
||||
}
|
||||
|
||||
// apply pan (audio fader) and mix mono signals
|
||||
if ( !( ( iAudioInFader == AUD_FADER_IN_MIDDLE ) && ( eAudioChannelConf == CC_STEREO ) ) )
|
||||
{
|
||||
// calculate pan gain in the range 0 to 1, where 0.5 is the middle position
|
||||
const double dPan = static_cast<double> ( iAudioInFader ) / AUD_FADER_IN_MAX;
|
||||
|
||||
if ( eAudioChannelConf == CC_STEREO )
|
||||
{
|
||||
// for stereo always apply reverberation effect on both channels
|
||||
for ( i = 0; i < iStereoBlockSizeSam; i += 2 )
|
||||
{
|
||||
// both channels (stereo)
|
||||
AudioReverbL.ProcessSample ( vecsStereoSndCrd[i], vecsStereoSndCrd[i + 1], dRevLev );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// mono and mono-in/stereo out mode
|
||||
if ( bReverbOnLeftChan )
|
||||
{
|
||||
for ( i = 0; i < iStereoBlockSizeSam; i += 2 )
|
||||
{
|
||||
// left channel
|
||||
int16_t sRightDummy = 0; // has to be 0 for mono reverb
|
||||
AudioReverbL.ProcessSample ( vecsStereoSndCrd[i], sRightDummy, dRevLev );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for ( i = 1; i < iStereoBlockSizeSam; i += 2 )
|
||||
{
|
||||
// right channel
|
||||
int16_t sRightDummy = 0; // has to be 0 for mono reverb
|
||||
AudioReverbR.ProcessSample ( vecsStereoSndCrd[i], sRightDummy, dRevLev );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// for stereo only apply pan attenuation on one channel (same as pan in the server)
|
||||
const double dGainL = std::min ( 0.5, 1 - dPan ) * 2;
|
||||
const double dGainR = std::min ( 0.5, dPan ) * 2;
|
||||
|
||||
// mix both signals depending on the fading setting, convert
|
||||
// from double to short
|
||||
if ( iAudioInFader == AUD_FADER_IN_MIDDLE )
|
||||
{
|
||||
// no action require if fader is in the middle and stereo is used
|
||||
if ( eAudioChannelConf != CC_STEREO )
|
||||
{
|
||||
// mix channels together (store result in first half of the vector)
|
||||
for ( i = 0, j = 0; i < iMonoBlockSizeSam; i++, j += 2 )
|
||||
{
|
||||
// for the sum make sure we have more bits available (cast to
|
||||
// int32), after the normalization by 2, the result will fit
|
||||
// into the old size so that cast to int16 is safe
|
||||
vecsStereoSndCrd[i] = static_cast<int16_t> (
|
||||
( static_cast<int32_t> ( vecsStereoSndCrd[j] ) + vecsStereoSndCrd[j + 1] ) / 2 );
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( eAudioChannelConf == CC_STEREO )
|
||||
{
|
||||
// stereo
|
||||
const double dAttFactStereo = static_cast<double> (
|
||||
AUD_FADER_IN_MIDDLE - abs ( AUD_FADER_IN_MIDDLE - iAudioInFader ) ) / AUD_FADER_IN_MIDDLE;
|
||||
|
||||
if ( iAudioInFader > AUD_FADER_IN_MIDDLE )
|
||||
{
|
||||
for ( i = 0, j = 0; i < iMonoBlockSizeSam; i++, j += 2 )
|
||||
{
|
||||
// attenuation on right channel
|
||||
vecsStereoSndCrd[j + 1] = Double2Short ( dAttFactStereo * vecsStereoSndCrd[j + 1] );
|
||||
// note that the gain is always <= 1, therefore a simple cast is
|
||||
// ok since we never can get an overload
|
||||
vecsStereoSndCrd[j + 1] = static_cast<int16_t> ( dGainR * vecsStereoSndCrd[j + 1] );
|
||||
vecsStereoSndCrd[j] = static_cast<int16_t> ( dGainL * vecsStereoSndCrd[j] );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// for mono implement a cross-fade between channels and mix them
|
||||
const double dGainL = 1 - dPan;
|
||||
const double dGainR = dPan;
|
||||
|
||||
for ( i = 0, j = 0; i < iMonoBlockSizeSam; i++, j += 2 )
|
||||
{
|
||||
// attenuation on left channel
|
||||
vecsStereoSndCrd[j] = Double2Short ( dAttFactStereo * vecsStereoSndCrd[j] );
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// mono and mono-in/stereo out mode
|
||||
// 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<double> (
|
||||
AUD_FADER_IN_MIDDLE - abs ( AUD_FADER_IN_MIDDLE - iAudioInFader ) ) / AUD_FADER_IN_MIDDLE / 2;
|
||||
|
||||
const double dAmplFactMono = 0.5 + static_cast<double> (
|
||||
abs ( AUD_FADER_IN_MIDDLE - iAudioInFader ) ) / AUD_FADER_IN_MIDDLE / 2;
|
||||
|
||||
if ( iAudioInFader > AUD_FADER_IN_MIDDLE )
|
||||
{
|
||||
for ( i = 0, j = 0; i < iMonoBlockSizeSam; i++, j += 2 )
|
||||
{
|
||||
// attenuation on right channel (store result in first half
|
||||
// of the vector)
|
||||
vecsStereoSndCrd[i] = Double2Short (
|
||||
dAmplFactMono * vecsStereoSndCrd[j] +
|
||||
dAttFactMono * vecsStereoSndCrd[j + 1] );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for ( i = 0, j = 0; i < iMonoBlockSizeSam; i++, j += 2 )
|
||||
{
|
||||
// attenuation on left channel (store result in first half
|
||||
// of the vector)
|
||||
vecsStereoSndCrd[i] = Double2Short (
|
||||
dAmplFactMono * vecsStereoSndCrd[j + 1] +
|
||||
dAttFactMono * vecsStereoSndCrd[j] );
|
||||
}
|
||||
dGainL * vecsStereoSndCrd[j] + dGainR * vecsStereoSndCrd[j + 1] );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1175,20 +1099,6 @@ void CClient::ProcessAudioDataIntern ( CVector<int16_t>& vecsStereoSndCrd )
|
|||
}
|
||||
}
|
||||
|
||||
/*
|
||||
// TEST
|
||||
// fid=fopen('c:\\temp\test2.dat','r');x=fread(fid,'int16');fclose(fid);
|
||||
static FILE* pFileDelay = fopen("c:\\temp\\test2.dat", "wb");
|
||||
short sData[2];
|
||||
for (i = 0; i < iMonoBlockSizeSam; i++)
|
||||
{
|
||||
sData[0] = (short) vecsStereoSndCrd[i];
|
||||
fwrite(&sData, size_t(2), size_t(1), pFileDelay);
|
||||
}
|
||||
fflush(pFileDelay);
|
||||
*/
|
||||
|
||||
|
||||
// for muted stream we have to add our local data here
|
||||
if ( bMuteOutStream )
|
||||
{
|
||||
|
|
|
@ -151,8 +151,7 @@ public:
|
|||
void SetReverbOnLeftChan ( const bool bIL )
|
||||
{
|
||||
bReverbOnLeftChan = bIL;
|
||||
AudioReverbL.Clear();
|
||||
AudioReverbR.Clear();
|
||||
AudioReverb.Clear();
|
||||
}
|
||||
|
||||
void SetDoAutoSockBufSize ( const bool bValue );
|
||||
|
@ -354,8 +353,7 @@ protected:
|
|||
int iAudioInFader;
|
||||
bool bReverbOnLeftChan;
|
||||
int iReverbLevel;
|
||||
CAudioReverb AudioReverbL;
|
||||
CAudioReverb AudioReverbR;
|
||||
CAudioReverb AudioReverb;
|
||||
|
||||
int iSndCrdPrefFrameSizeFactor;
|
||||
int iSndCrdFrameSizeFactor;
|
||||
|
|
|
@ -282,9 +282,12 @@ CClientDlg::CClientDlg ( CClient* pNCliP,
|
|||
// Edit menu --------------------------------------------------------------
|
||||
pEditMenu = new QMenu ( tr ( "&Edit" ), this );
|
||||
|
||||
pEditMenu->addAction ( tr ( "&Sort Channel Users by Name" ), this,
|
||||
pEditMenu->addAction ( tr ( "Sort Channel Users by &Name" ), this,
|
||||
SLOT ( OnSortChannelsByName() ), QKeySequence ( Qt::CTRL + Qt::Key_N ) );
|
||||
|
||||
pEditMenu->addAction ( tr ( "Sort Channel Users by &Instrument" ), this,
|
||||
SLOT ( OnSortChannelsByInstrument() ), QKeySequence ( Qt::CTRL + Qt::Key_I ) );
|
||||
|
||||
|
||||
// Main menu bar -----------------------------------------------------------
|
||||
pMenu = new QMenuBar ( this );
|
||||
|
|
|
@ -152,7 +152,8 @@ public slots:
|
|||
void OnOpenGeneralSettings() { ShowGeneralSettings(); }
|
||||
void OnOpenChatDialog() { ShowChatWindow(); }
|
||||
void OnOpenAnalyzerConsole() { ShowAnalyzerConsole(); }
|
||||
void OnSortChannelsByName() { MainMixerBoard->ChangeFaderOrder ( true ); }
|
||||
void OnSortChannelsByName() { MainMixerBoard->ChangeFaderOrder ( true, ST_BY_NAME ); }
|
||||
void OnSortChannelsByInstrument() { MainMixerBoard->ChangeFaderOrder ( true, ST_BY_INSTRUMENT ); }
|
||||
|
||||
void OnSettingsStateChanged ( int value );
|
||||
void OnChatStateChanged ( int value );
|
||||
|
|
|
@ -333,7 +333,7 @@ CClientSettingsDlg::CClientSettingsDlg ( CClient* pNCliP, QWidget* parent,
|
|||
cbxSkin->clear();
|
||||
cbxSkin->addItem ( tr ( "Normal" ) ); // GD_STANDARD
|
||||
cbxSkin->addItem ( tr ( "Fancy" ) ); // GD_ORIGINAL
|
||||
cbxSkin->addItem ( tr ( "Slim Channel" ) ); // GD_SLIMFADER
|
||||
cbxSkin->addItem ( tr ( "Compact" ) ); // GD_SLIMFADER
|
||||
cbxSkin->setCurrentIndex ( static_cast<int> ( pClient->GetGUIDesign() ) );
|
||||
|
||||
// custom central server address
|
||||
|
|
|
@ -216,6 +216,17 @@ MESSAGES (with connection)
|
|||
note: does not have any data -> n = 0
|
||||
|
||||
|
||||
- PROTMESSID_RECORDER_STATE: notifies of changes in the server jam recorder state
|
||||
|
||||
+--------------+
|
||||
| 1 byte state |
|
||||
+--------------+
|
||||
|
||||
state is a value from the enum ERecorderState:
|
||||
- 0 undefined (not used by protocol messages)
|
||||
- tbc
|
||||
|
||||
|
||||
CONNECTION LESS MESSAGES
|
||||
------------------------
|
||||
|
||||
|
@ -659,6 +670,10 @@ if ( rand() < ( RAND_MAX / 2 ) ) return false;
|
|||
case PROTMESSID_VERSION_AND_OS:
|
||||
bRet = EvaluateVersionAndOSMes ( vecbyMesBodyData );
|
||||
break;
|
||||
|
||||
case PROTMESSID_RECORDER_STATE:
|
||||
bRet = EvaluateRecorderStateMes ( vecbyMesBodyData );
|
||||
break;
|
||||
}
|
||||
|
||||
// immediately send acknowledge message
|
||||
|
@ -1544,6 +1559,43 @@ bool CProtocol::EvaluateVersionAndOSMes ( const CVector<uint8_t>& vecData )
|
|||
return false; // no error
|
||||
}
|
||||
|
||||
void CProtocol::CreateRecorderStateMes ( const ERecorderState eRecorderState )
|
||||
{
|
||||
CVector<uint8_t> vecData ( 1 ); // 1 byte of data
|
||||
int iPos = 0; // init position pointer
|
||||
|
||||
// build data vector
|
||||
// server jam recorder state (1 byte)
|
||||
PutValOnStream ( vecData, iPos, static_cast<uint32_t> ( eRecorderState ), 1 );
|
||||
|
||||
CreateAndSendMessage ( PROTMESSID_RECORDER_STATE, vecData );
|
||||
}
|
||||
|
||||
bool CProtocol::EvaluateRecorderStateMes(const CVector<uint8_t>& vecData)
|
||||
{
|
||||
int iPos = 0; // init position pointer
|
||||
|
||||
// check size
|
||||
if ( vecData.Size() != 1 )
|
||||
{
|
||||
return true; // return error code
|
||||
}
|
||||
|
||||
// server jam recorder state (1 byte)
|
||||
const int iRecorderState =
|
||||
static_cast<int> ( GetValFromStream ( vecData, iPos, 1 ) );
|
||||
|
||||
if ( iRecorderState != RS_UNDEFINED ) // ... to be defined ...
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
// invoke message action
|
||||
emit RecorderStateReceived ( static_cast<ERecorderState> ( iRecorderState ) );
|
||||
|
||||
return false; // no error
|
||||
}
|
||||
|
||||
|
||||
// Connection less messages ----------------------------------------------------
|
||||
void CProtocol::CreateCLPingMes ( const CHostAddress& InetAddr, const int iMs )
|
||||
|
|
4
src/protocol.h
Normal file → Executable file
4
src/protocol.h
Normal file → Executable file
|
@ -59,6 +59,7 @@
|
|||
#define PROTMESSID_CHANNEL_PAN 30 // set channel pan for mix
|
||||
#define PROTMESSID_MUTE_STATE_CHANGED 31 // mute state of your signal at another client has changed
|
||||
#define PROTMESSID_CLIENT_ID 32 // current user ID and server status
|
||||
#define PROTMESSID_RECORDER_STATE 33 // contains the state of the jam recorder (ERecorderState)
|
||||
|
||||
// message IDs of connection less messages (CLM)
|
||||
// DEFINITION -> start at 1000, end at 1999, see IsConnectionLessMessageID
|
||||
|
@ -114,6 +115,7 @@ public:
|
|||
void CreateOpusSupportedMes();
|
||||
void CreateReqChannelLevelListMes ( const bool bRCL );
|
||||
void CreateVersionAndOSMes();
|
||||
void CreateRecorderStateMes ( const ERecorderState eRecorderState );
|
||||
|
||||
void CreateCLPingMes ( const CHostAddress& InetAddr, const int iMs );
|
||||
void CreateCLPingWithNumClientsMes ( const CHostAddress& InetAddr,
|
||||
|
@ -239,6 +241,7 @@ protected:
|
|||
bool EvaluateLicenceRequiredMes ( const CVector<uint8_t>& vecData );
|
||||
bool EvaluateReqChannelLevelListMes ( const CVector<uint8_t>& vecData );
|
||||
bool EvaluateVersionAndOSMes ( const CVector<uint8_t>& vecData );
|
||||
bool EvaluateRecorderStateMes ( const CVector<uint8_t>& vecData );
|
||||
|
||||
bool EvaluateCLPingMes ( const CHostAddress& InetAddr,
|
||||
const CVector<uint8_t>& vecData );
|
||||
|
@ -302,6 +305,7 @@ signals:
|
|||
void LicenceRequired ( ELicenceType eLicenceType );
|
||||
void ReqChannelLevelList ( bool bOptIn );
|
||||
void VersionAndOSReceived ( COSUtil::EOpSystemType eOSType, QString strVersion );
|
||||
void RecorderStateReceived ( ERecorderState eRecorderState );
|
||||
|
||||
void CLPingReceived ( CHostAddress InetAddr,
|
||||
int iMs );
|
||||
|
|
|
@ -93,7 +93,7 @@ in a direction where the label above the fader shows L -x, where x is the curren
|
|||
In the audio mixer frame, a fader is shown for each connected client at the server (including yourself).
|
||||
The faders allow you to adjust the level of what you hear without affecting what others hear.
|
||||
|
||||
The VU meter shows the input level at the server - that is, the sound you are sending.
|
||||
The VU meter shows the input level at the server - that is, the sound being sent.
|
||||
|
||||
If you have set your Audio Channel to Stereo or Stereo Out in your Settings, you will also see a pan control.
|
||||
|
||||
|
@ -103,6 +103,7 @@ Using the **Mute button** prevents the indicated channel being heard in your loc
|
|||
|
||||
The **Solo button** allows you to hear one or more musicians on their own. Those not soloed will be muted. Note also that those musicians who are not soloed will see a "muted" icon above your fader.
|
||||
|
||||
Channels are listed left to right in the order that clients connect until they leave, at which point their "slot" is filled by the next new arrival. You can change the sort order using the Edit option in the application menu.
|
||||
|
||||
|
||||
|
||||
|
|
Binary file not shown.
File diff suppressed because it is too large
Load diff
Binary file not shown.
File diff suppressed because it is too large
Load diff
Binary file not shown.
File diff suppressed because it is too large
Load diff
Binary file not shown.
File diff suppressed because it is too large
Load diff
Binary file not shown.
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
Binary file not shown.
File diff suppressed because it is too large
Load diff
|
@ -234,12 +234,14 @@ CServer::CServer ( const int iNewMaxNumChan,
|
|||
const bool bNDisconnectAllClientsOnQuit,
|
||||
const bool bNUseDoubleSystemFrameSize,
|
||||
const ELicenceType eNLicenceType ) :
|
||||
vecWindowPosMain (), // empty array
|
||||
bUseDoubleSystemFrameSize ( bNUseDoubleSystemFrameSize ),
|
||||
iMaxNumChannels ( iNewMaxNumChan ),
|
||||
Socket ( this, iPortNumber ),
|
||||
Logging ( iMaxDaysHistory ),
|
||||
iFrameCount ( 0 ),
|
||||
JamRecorder ( strRecordingDirName ),
|
||||
bEnableRecording ( false ),
|
||||
bWriteStatusHTMLFile ( false ),
|
||||
HighPrecisionTimer ( bNUseDoubleSystemFrameSize ),
|
||||
ServerListManager ( iPortNumber,
|
||||
|
@ -249,7 +251,6 @@ CServer::CServer ( const int iNewMaxNumChan,
|
|||
bNCentServPingServerInList,
|
||||
&ConnLessProtocol ),
|
||||
bAutoRunMinimized ( false ),
|
||||
strWelcomeMessage ( strNewWelcomeMessage ),
|
||||
eLicenceType ( eNLicenceType ),
|
||||
bDisconnectAllClientsOnQuit ( bNDisconnectAllClientsOnQuit ),
|
||||
pSignalHandler ( CSignalHandler::getSingletonP() )
|
||||
|
@ -401,11 +402,28 @@ CServer::CServer ( const int iNewMaxNumChan,
|
|||
QString().number( static_cast<int> ( iPortNumber ) ) );
|
||||
}
|
||||
|
||||
// manage welcome message: if the welcome message is a valid link to a local
|
||||
// file, the content of that file is used as the welcome message (#361)
|
||||
strWelcomeMessage = strNewWelcomeMessage; // first copy text, may be overwritten
|
||||
if ( QFileInfo ( strNewWelcomeMessage ).exists() )
|
||||
{
|
||||
QFile file ( strNewWelcomeMessage );
|
||||
|
||||
if ( file.open ( QIODevice::ReadOnly | QIODevice::Text ) )
|
||||
{
|
||||
// use entrie file content for the welcome message
|
||||
strWelcomeMessage = file.readAll();
|
||||
}
|
||||
}
|
||||
|
||||
// restrict welcome message to maximum allowed length
|
||||
strWelcomeMessage = strWelcomeMessage.left ( MAX_LEN_CHAT_TEXT );
|
||||
|
||||
// enable jam recording (if requested) - kicks off the thread
|
||||
if ( !strRecordingDirName.isEmpty() )
|
||||
{
|
||||
bRecorderInitialised = JamRecorder.Init ( this, iServerFrameSizeSamples );
|
||||
bEnableRecording = bRecorderInitialised;
|
||||
SetEnableRecording ( bRecorderInitialised );
|
||||
}
|
||||
|
||||
// enable all channels (for the server all channel must be enabled the
|
||||
|
@ -665,6 +683,10 @@ void CServer::OnAboutToQuit()
|
|||
|
||||
void CServer::OnHandledSignal ( int sigNum )
|
||||
{
|
||||
// show the signal number on the command line (note that this does not work for the Windows command line)
|
||||
// TODO we should use the ConsoleWriterFactory() instead of qDebug()
|
||||
qDebug() << "OnHandledSignal: " << sigNum;
|
||||
|
||||
#ifdef _WIN32
|
||||
// Windows does not actually get OnHandledSignal triggered
|
||||
QCoreApplication::instance()->exit();
|
||||
|
@ -705,8 +727,16 @@ void CServer::SetEnableRecording ( bool bNewEnableRecording )
|
|||
{
|
||||
if ( bRecorderInitialised )
|
||||
{
|
||||
// note that this block executes regardless of whether
|
||||
// what appears to be a change is being applied, to ensure
|
||||
// the requested state is the result
|
||||
bEnableRecording = bNewEnableRecording;
|
||||
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(5, 5, 0)
|
||||
// TODO we should use the ConsoleWriterFactory() instead of qInfo()
|
||||
qInfo() << "Recording state " << ( bEnableRecording ? "enabled" : "disabled" );
|
||||
#endif
|
||||
|
||||
if ( !bEnableRecording )
|
||||
{
|
||||
emit StopRecorder();
|
||||
|
|
|
@ -28,6 +28,7 @@
|
|||
#include <QTimer>
|
||||
#include <QDateTime>
|
||||
#include <QHostAddress>
|
||||
#include <QFileInfo>
|
||||
#include <algorithm>
|
||||
#ifdef USE_OPUS_SHARED_LIB
|
||||
# include "opus/opus_custom.h"
|
||||
|
@ -250,6 +251,9 @@ public:
|
|||
void SetLicenceType ( const ELicenceType NLiType ) { eLicenceType = NLiType; }
|
||||
ELicenceType GetLicenceType() { return eLicenceType; }
|
||||
|
||||
// window position/state settings
|
||||
QByteArray vecWindowPosMain;
|
||||
|
||||
protected:
|
||||
// access functions for actual channels
|
||||
bool IsConnected ( const int iChanNum )
|
||||
|
|
|
@ -332,6 +332,14 @@ lvwClients->setMinimumHeight ( 140 );
|
|||
layout()->setMenuBar ( pMenu );
|
||||
|
||||
|
||||
// Window positions --------------------------------------------------------
|
||||
// main window
|
||||
if ( !pServer->vecWindowPosMain.isEmpty() && !pServer->vecWindowPosMain.isNull() )
|
||||
{
|
||||
restoreGeometry ( pServer->vecWindowPosMain );
|
||||
}
|
||||
|
||||
|
||||
// Connections -------------------------------------------------------------
|
||||
// check boxes
|
||||
QObject::connect ( chbRegisterServer, &QCheckBox::stateChanged,
|
||||
|
@ -399,6 +407,15 @@ lvwClients->setMinimumHeight ( 140 );
|
|||
Timer.start ( GUI_CONTRL_UPDATE_TIME );
|
||||
}
|
||||
|
||||
void CServerDlg::closeEvent ( QCloseEvent* Event )
|
||||
{
|
||||
// store window positions
|
||||
pServer->vecWindowPosMain = saveGeometry();
|
||||
|
||||
// default implementation of this event handler routine
|
||||
Event->accept();
|
||||
}
|
||||
|
||||
void CServerDlg::OnStartOnOSStartStateChanged ( int value )
|
||||
{
|
||||
const bool bCurAutoStartMinState = ( value == Qt::Checked );
|
||||
|
|
|
@ -58,6 +58,7 @@ public:
|
|||
|
||||
protected:
|
||||
virtual void changeEvent ( QEvent* pEvent );
|
||||
virtual void closeEvent ( QCloseEvent* Event );
|
||||
|
||||
void UpdateGUIDependencies();
|
||||
void UpdateSystemTrayIcon ( const bool bIsActive );
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>588</width>
|
||||
<height>415</height>
|
||||
<height>419</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
|
@ -69,9 +69,27 @@
|
|||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout">
|
||||
<item>
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>Genre</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QComboBox" name="cbxCentServAddrType"/>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="lblRegSvrStatus">
|
||||
<property name="text">
|
||||
<string>STATUS</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer>
|
||||
<property name="orientation">
|
||||
|
@ -88,13 +106,6 @@
|
|||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="lblRegSvrStatus">
|
||||
<property name="text">
|
||||
<string>STATUS</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
|
|
|
@ -427,6 +427,10 @@ if ( GetFlagIniSet ( IniXMLDocument, "server", "defcentservaddr", bValue ) )
|
|||
{
|
||||
pServer->SetLicenceType ( static_cast<ELicenceType> ( iValue ) );
|
||||
}
|
||||
|
||||
// window position of the main window
|
||||
pServer->vecWindowPosMain = FromBase64ToByteArray (
|
||||
GetIniSetting ( IniXMLDocument, "server", "winposmain_base64" ) );
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -666,6 +670,10 @@ void CSettings::Save()
|
|||
// licence type
|
||||
SetNumericIniSet ( IniXMLDocument, "server", "licencetype",
|
||||
static_cast<int> ( pServer->GetLicenceType() ) );
|
||||
|
||||
// window position of the main window
|
||||
PutIniSetting ( IniXMLDocument, "server", "winposmain_base64",
|
||||
ToBase64 ( pServer->vecWindowPosMain ) );
|
||||
}
|
||||
|
||||
// prepare file name for storing initialization data in XML file and store
|
||||
|
|
60
src/util.cpp
60
src/util.cpp
|
@ -165,10 +165,14 @@ uint32_t CCRC::GetCRC()
|
|||
three series allpass units, followed by four parallel comb filters, and two
|
||||
decorrelation delay lines in parallel at the output.
|
||||
*/
|
||||
void CAudioReverb::Init ( const int iSampleRate,
|
||||
void CAudioReverb::Init ( const EAudChanConf eNAudioChannelConf,
|
||||
const int iNStereoBlockSizeSam,
|
||||
const int iSampleRate,
|
||||
const double rT60 )
|
||||
{
|
||||
int delay, i;
|
||||
// store paramters
|
||||
eAudioChannelConf = eNAudioChannelConf;
|
||||
iStereoBlockSizeSam = iNStereoBlockSizeSam;
|
||||
|
||||
// delay lengths for 44100 Hz sample rate
|
||||
int lengths[9] = { 1116, 1356, 1422, 1617, 225, 341, 441, 211, 179 };
|
||||
|
@ -176,9 +180,9 @@ void CAudioReverb::Init ( const int iSampleRate,
|
|||
|
||||
if ( scaler != 1.0 )
|
||||
{
|
||||
for ( i = 0; i < 9; i++ )
|
||||
for ( int i = 0; i < 9; i++ )
|
||||
{
|
||||
delay = static_cast<int> ( floor ( scaler * lengths[i] ) );
|
||||
int delay = static_cast<int> ( floor ( scaler * lengths[i] ) );
|
||||
|
||||
if ( ( delay & 1 ) == 0 )
|
||||
{
|
||||
|
@ -194,12 +198,12 @@ void CAudioReverb::Init ( const int iSampleRate,
|
|||
}
|
||||
}
|
||||
|
||||
for ( i = 0; i < 3; i++ )
|
||||
for ( int i = 0; i < 3; i++ )
|
||||
{
|
||||
allpassDelays[i].Init ( lengths[i + 4] );
|
||||
}
|
||||
|
||||
for ( i = 0; i < 4; i++ )
|
||||
for ( int i = 0; i < 4; i++ )
|
||||
{
|
||||
combDelays[i].Init ( lengths[i] );
|
||||
combFilters[i].setPole ( 0.2 );
|
||||
|
@ -285,16 +289,31 @@ double CAudioReverb::COnePole::Calc ( const double dIn )
|
|||
return dLastSample;
|
||||
}
|
||||
|
||||
void CAudioReverb::ProcessSample ( int16_t& iInputOutputLeft,
|
||||
int16_t& iInputOutputRight,
|
||||
void CAudioReverb::Process ( CVector<int16_t>& vecsStereoInOut,
|
||||
const bool bReverbOnLeftChan,
|
||||
const double dAttenuation )
|
||||
{
|
||||
// compute one output sample
|
||||
double temp, temp0, temp1, temp2;
|
||||
double dMixedInput, temp, temp0, temp1, temp2;
|
||||
|
||||
for ( int i = 0; i < iStereoBlockSizeSam; i += 2 )
|
||||
{
|
||||
// we sum up the stereo input channels (in case mono input is used, a zero
|
||||
// shall be input for the right channel)
|
||||
const double dMixedInput = 0.5 * ( iInputOutputLeft + iInputOutputRight );
|
||||
if ( eAudioChannelConf == CC_STEREO )
|
||||
{
|
||||
dMixedInput = 0.5 * ( vecsStereoInOut[i] + vecsStereoInOut[i + 1] );
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( bReverbOnLeftChan )
|
||||
{
|
||||
dMixedInput = vecsStereoInOut[i];
|
||||
}
|
||||
else
|
||||
{
|
||||
dMixedInput = vecsStereoInOut[i + 1];
|
||||
}
|
||||
}
|
||||
|
||||
temp = allpassDelays[0].Get();
|
||||
temp0 = allpassCoefficient * temp;
|
||||
|
@ -329,14 +348,22 @@ void CAudioReverb::ProcessSample ( int16_t& iInputOutputLeft,
|
|||
outLeftDelay.Add ( filtout );
|
||||
outRightDelay.Add ( filtout );
|
||||
|
||||
// inplace apply the attenuated reverb signal
|
||||
iInputOutputLeft = Double2Short (
|
||||
( 1.0 - dAttenuation ) * iInputOutputLeft +
|
||||
// inplace apply the attenuated reverb signal (for stereo always apply
|
||||
// reverberation effect on both channels)
|
||||
if ( ( eAudioChannelConf == CC_STEREO ) || bReverbOnLeftChan )
|
||||
{
|
||||
vecsStereoInOut[i] = Double2Short (
|
||||
( 1.0 - dAttenuation ) * vecsStereoInOut[i] +
|
||||
0.5 * dAttenuation * outLeftDelay.Get() );
|
||||
}
|
||||
|
||||
iInputOutputRight = Double2Short (
|
||||
( 1.0 - dAttenuation ) * iInputOutputRight +
|
||||
if ( ( eAudioChannelConf == CC_STEREO ) || !bReverbOnLeftChan )
|
||||
{
|
||||
vecsStereoInOut[i + 1] = Double2Short (
|
||||
( 1.0 - dAttenuation ) * vecsStereoInOut[i + 1] +
|
||||
0.5 * dAttenuation * outRightDelay.Get() );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -398,6 +425,7 @@ CAboutDlg::CAboutDlg ( QWidget* parent ) : QDialog ( parent )
|
|||
"<p>Emlyn Bolton (<a href=""https://github.com/emlynmac"">emlynmac</a>)</p>"
|
||||
"<p>Jos van den Oever (<a href=""https://github.com/vandenoever"">vandenoever</a>)</p>"
|
||||
"<p>Tormod Volden (<a href=""https://github.com/tormodvolden"">tormodvolden</a>)</p>"
|
||||
"<p>Alberstein8 (<a href=""https://github.com/Alberstein8"">Alberstein8</a>)</p>"
|
||||
"<p>Gauthier Fleutot Östervall (<a href=""https://github.com/fleutot"">fleutot</a>)</p>"
|
||||
"<p>Stanislas Michalak (<a href=""https://github.com/stanislas-m"">stanislas-m</a>)</p>"
|
||||
"<p>JP Cimalando (<a href=""https://github.com/jpcima"">jpcima</a>)</p>"
|
||||
|
|
28
src/util.h
28
src/util.h
|
@ -563,6 +563,22 @@ enum ELicenceType
|
|||
};
|
||||
|
||||
|
||||
// Server jam recorder state enum ----------------------------------------------
|
||||
enum ERecorderState
|
||||
{
|
||||
RS_UNDEFINED = 0
|
||||
// ... to be defined ...
|
||||
};
|
||||
|
||||
|
||||
// Channel sort type -----------------------------------------------------------
|
||||
enum EChSortType
|
||||
{
|
||||
ST_BY_NAME = 0,
|
||||
ST_BY_INSTRUMENT = 1
|
||||
};
|
||||
|
||||
|
||||
// Central server address type -------------------------------------------------
|
||||
enum ECSAddType
|
||||
{
|
||||
|
@ -1098,10 +1114,14 @@ class CAudioReverb
|
|||
public:
|
||||
CAudioReverb() {}
|
||||
|
||||
void Init ( const int iSampleRate, const double rT60 = 1.1 );
|
||||
void Init ( const EAudChanConf eNAudioChannelConf,
|
||||
const int iNStereoBlockSizeSam,
|
||||
const int iSampleRate,
|
||||
const double rT60 = 1.1 );
|
||||
|
||||
void Clear();
|
||||
void ProcessSample ( int16_t& iInputOutputLeft,
|
||||
int16_t& iInputOutputRight,
|
||||
void Process ( CVector<int16_t>& vecsStereoInOut,
|
||||
const bool bReverbOnLeftChan,
|
||||
const double dAttenuation );
|
||||
|
||||
protected:
|
||||
|
@ -1122,6 +1142,8 @@ protected:
|
|||
double dLastSample;
|
||||
};
|
||||
|
||||
EAudChanConf eAudioChannelConf;
|
||||
int iStereoBlockSizeSam;
|
||||
CFIFO<double> allpassDelays[3];
|
||||
CFIFO<double> combDelays[4];
|
||||
COnePole combFilters[4];
|
||||
|
|
Loading…
Reference in a new issue