Merge pull request #1 from corrados/master

update
This commit is contained in:
ignotus 2020-06-14 22:50:50 +02:00 committed by GitHub
commit 2310832894
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
32 changed files with 2294 additions and 1853 deletions

View file

@ -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

View file

@ -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,20 +768,28 @@ 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++ )
{
PairList << QPair<QString, int> ( vecpChanFader[i]->GetReceivedName().toLower(), 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

View file

@ -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

View file

@ -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] );
}
}
else
{
for ( i = 0, j = 0; i < iMonoBlockSizeSam; i++, j += 2 )
{
// attenuation on left channel
vecsStereoSndCrd[j] = Double2Short ( dAttFactStereo * vecsStereoSndCrd[j] );
}
// 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
{
// 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;
// for mono implement a cross-fade between channels and mix them
const double dGainL = 1 - dPan;
const double dGainR = dPan;
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 )
{
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] );
}
vecsStereoSndCrd[i] = Double2Short (
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 )
{

View file

@ -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;

View file

@ -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 );

View file

@ -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 );

View file

@ -331,9 +331,9 @@ CClientSettingsDlg::CClientSettingsDlg ( CClient* pNCliP, QWidget* parent,
// GUI design (skin) combo box
cbxSkin->clear();
cbxSkin->addItem ( tr ( "Normal" ) ); // GD_STANDARD
cbxSkin->addItem ( tr ( "Fancy" ) ); // GD_ORIGINAL
cbxSkin->addItem ( tr ( "Slim Channel" ) ); // GD_SLIMFADER
cbxSkin->addItem ( tr ( "Normal" ) ); // GD_STANDARD
cbxSkin->addItem ( tr ( "Fancy" ) ); // GD_ORIGINAL
cbxSkin->addItem ( tr ( "Compact" ) ); // GD_SLIMFADER
cbxSkin->setCurrentIndex ( static_cast<int> ( pClient->GetGUIDesign() ) );
// custom central server address

View file

@ -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
View 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 );

View file

@ -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.

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -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();

View file

@ -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 )

View file

@ -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 );

View file

@ -58,6 +58,7 @@ public:
protected:
virtual void changeEvent ( QEvent* pEvent );
virtual void closeEvent ( QCloseEvent* Event );
void UpdateGUIDependencies();
void UpdateSystemTrayIcon ( const bool bIsActive );
@ -65,20 +66,20 @@ protected:
void ModifyAutoStartEntry ( const bool bDoAutoStart );
void UpdateRecorderStatus( QString sessionDir );
QTimer Timer;
CServer* pServer;
CSettings* pSettings;
QTimer Timer;
CServer* pServer;
CSettings* pSettings;
CVector<QTreeWidgetItem*> vecpListViewItems;
QMutex ListViewMutex;
CVector<QTreeWidgetItem*> vecpListViewItems;
QMutex ListViewMutex;
QMenuBar* pMenu;
QMenuBar* pMenu;
bool bSystemTrayIconAvaialbe;
QSystemTrayIcon SystemTrayIcon;
QPixmap BitmapSystemTrayInactive;
QPixmap BitmapSystemTrayActive;
QMenu* pSystemTrayIconMenu;
bool bSystemTrayIconAvaialbe;
QSystemTrayIcon SystemTrayIcon;
QPixmap BitmapSystemTrayInactive;
QPixmap BitmapSystemTrayActive;
QMenu* pSystemTrayIconMenu;
public slots:
void OnAboutToQuit() { pSettings->Save(); }

View file

@ -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>

View file

@ -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

View file

@ -165,20 +165,24 @@ 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,
const double rT60 )
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 };
const double scaler = static_cast<double> ( iSampleRate ) / 44100.0;
int lengths[9] = { 1116, 1356, 1422, 1617, 225, 341, 441, 211, 179 };
const double scaler = static_cast<double> ( iSampleRate ) / 44100.0;
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,58 +289,81 @@ double CAudioReverb::COnePole::Calc ( const double dIn )
return dLastSample;
}
void CAudioReverb::ProcessSample ( int16_t& iInputOutputLeft,
int16_t& iInputOutputRight,
const double dAttenuation )
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;
// 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 );
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)
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;
temp0 += dMixedInput;
allpassDelays[0].Add ( temp0 );
temp0 = - ( allpassCoefficient * temp0 ) + temp;
temp = allpassDelays[0].Get();
temp0 = allpassCoefficient * temp;
temp0 += dMixedInput;
allpassDelays[0].Add ( temp0 );
temp0 = - ( allpassCoefficient * temp0 ) + temp;
temp = allpassDelays[1].Get();
temp1 = allpassCoefficient * temp;
temp1 += temp0;
allpassDelays[1].Add ( temp1 );
temp1 = - ( allpassCoefficient * temp1 ) + temp;
temp = allpassDelays[1].Get();
temp1 = allpassCoefficient * temp;
temp1 += temp0;
allpassDelays[1].Add ( temp1 );
temp1 = - ( allpassCoefficient * temp1 ) + temp;
temp = allpassDelays[2].Get();
temp2 = allpassCoefficient * temp;
temp2 += temp1;
allpassDelays[2].Add ( temp2 );
temp2 = - ( allpassCoefficient * temp2 ) + temp;
temp = allpassDelays[2].Get();
temp2 = allpassCoefficient * temp;
temp2 += temp1;
allpassDelays[2].Add ( temp2 );
temp2 = - ( allpassCoefficient * temp2 ) + temp;
const double temp3 = temp2 + combFilters[0].Calc ( combCoefficient[0] * combDelays[0].Get() );
const double temp4 = temp2 + combFilters[1].Calc ( combCoefficient[1] * combDelays[1].Get() );
const double temp5 = temp2 + combFilters[2].Calc ( combCoefficient[2] * combDelays[2].Get() );
const double temp6 = temp2 + combFilters[3].Calc ( combCoefficient[3] * combDelays[3].Get() );
const double temp3 = temp2 + combFilters[0].Calc ( combCoefficient[0] * combDelays[0].Get() );
const double temp4 = temp2 + combFilters[1].Calc ( combCoefficient[1] * combDelays[1].Get() );
const double temp5 = temp2 + combFilters[2].Calc ( combCoefficient[2] * combDelays[2].Get() );
const double temp6 = temp2 + combFilters[3].Calc ( combCoefficient[3] * combDelays[3].Get() );
combDelays[0].Add ( temp3 );
combDelays[1].Add ( temp4 );
combDelays[2].Add ( temp5 );
combDelays[3].Add ( temp6 );
combDelays[0].Add ( temp3 );
combDelays[1].Add ( temp4 );
combDelays[2].Add ( temp5 );
combDelays[3].Add ( temp6 );
const double filtout = temp3 + temp4 + temp5 + temp6;
const double filtout = temp3 + temp4 + temp5 + temp6;
outLeftDelay.Add ( filtout );
outRightDelay.Add ( filtout );
outLeftDelay.Add ( filtout );
outRightDelay.Add ( filtout );
// inplace apply the attenuated reverb signal
iInputOutputLeft = Double2Short (
( 1.0 - dAttenuation ) * iInputOutputLeft +
0.5 * dAttenuation * outLeftDelay.Get() );
// 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 +
0.5 * dAttenuation * outRightDelay.Get() );
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>"

View file

@ -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
{
@ -694,8 +710,8 @@ public:
}
protected:
double UpdateCurLevel ( double dCurLevel,
const short& sMax );
double UpdateCurLevel ( double dCurLevel,
const short& sMax );
double dCurLevelL;
double dCurLevelR;
@ -1098,11 +1114,15 @@ 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,
const double dAttenuation );
void Process ( CVector<int16_t>& vecsStereoInOut,
const bool bReverbOnLeftChan,
const double dAttenuation );
protected:
void setT60 ( const double rT60, const int iSampleRate );
@ -1122,6 +1142,8 @@ protected:
double dLastSample;
};
EAudChanConf eAudioChannelConf;
int iStereoBlockSizeSam;
CFIFO<double> allpassDelays[3];
CFIFO<double> combDelays[4];
COnePole combFilters[4];