/******************************************************************************\ * Copyright (c) 2004-2020 * * Author(s): * Volker Fischer * ****************************************************************************** * * This program is free software; you can redistribute it and/or modify it under * the terms of the GNU General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) any later * version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License along with * this program; if not, write to the Free Software Foundation, Inc., * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * \******************************************************************************/ #include "audiomixerboard.h" /******************************************************************************\ * CChanneFader * \******************************************************************************/ CChannelFader::CChannelFader(QWidget *pNW, QHBoxLayout *pParentLayout) { // create new GUI control objects and store pointers to them (note that // QWidget takes the ownership of the pMainGrid so that this only has // to be created locally in this constructor) pFrame = new QFrame(pNW); //pFrame->setStyleSheet("border: 5px solid white;"); pLevelsBox = new QWidget(pFrame); plbrChannelLevel = new CMultiColorLEDBar(pLevelsBox); pFader = new QSlider(Qt::Vertical, pLevelsBox); pMuteSoloBox = new QWidget(pFrame); pcbMute = new QCheckBox("Mute", pMuteSoloBox); pcbSolo = new QCheckBox("Solo", pMuteSoloBox); pLabelInstBox = new QGroupBox(pFrame); plblLabel = new QLabel("", pFrame); plblInstrument = new QLabel(pFrame); plblCountryFlag = new QLabel(pFrame); QVBoxLayout *pMainGrid = new QVBoxLayout(pFrame); QHBoxLayout *pLevelsGrid = new QHBoxLayout(pLevelsBox); QVBoxLayout *pMuteSoloGrid = new QVBoxLayout(pMuteSoloBox); QHBoxLayout *pLabelGrid = new QHBoxLayout(pLabelInstBox); QVBoxLayout *pLabelPictGrid = new QVBoxLayout(); // setup channel level plbrChannelLevel->setContentsMargins(0, 3, 2, 3); // setup slider pFader->setPageStep(1); pFader->setTickPosition(QSlider::TicksBothSides); pFader->setRange(0, AUD_MIX_FADER_MAX); pFader->setTickInterval(AUD_MIX_FADER_MAX / 9); // setup fader tag label (black bold text which is centered) plblLabel->setTextFormat(Qt::PlainText); plblLabel->setAlignment(Qt::AlignHCenter | Qt::AlignVCenter); plblLabel->setMinimumHeight(35); // maximum height of the instrument+flag pictures plblLabel->setStyleSheet( "QLabel { color: white;" " font: bold; }"); // set margins of the layouts to zero to get maximum space for the controls pMainGrid->setContentsMargins(0, 0, 0, 0); pLevelsGrid->setContentsMargins(0, 0, 0, 0); pLevelsGrid->setSpacing(0); // only minimal space pMuteSoloGrid->setContentsMargins(0, 0, 0, 0); pLabelGrid->setContentsMargins(0, 0, 0, 0); pLabelGrid->setSpacing(2); // only minimal space between picture and text // add user controls to the grids pLabelPictGrid->addWidget(plblCountryFlag, 200, Qt::AlignHCenter); pLabelPictGrid->addWidget(plblInstrument, 200, Qt::AlignHCenter); pLabelGrid->addLayout(pLabelPictGrid); pLabelGrid->addWidget(plblLabel, 0, Qt::AlignVCenter); pLevelsGrid->addWidget(plbrChannelLevel, 0, Qt::AlignRight); pLevelsGrid->addWidget(pFader, 0, Qt::AlignLeft); pMuteSoloGrid->addWidget(pcbMute, 0, Qt::AlignLeft); pMuteSoloGrid->addWidget(pcbSolo, 0, Qt::AlignLeft); pMainGrid->addWidget(pLevelsBox, 0, Qt::AlignHCenter); pMainGrid->addWidget(pMuteSoloBox, 0, Qt::AlignHCenter); pMainGrid->addWidget(pLabelInstBox); // add fader frame to audio mixer board layout pParentLayout->addWidget(pFrame); // reset current fader Reset(); // add help text to controls plbrChannelLevel->setWhatsThis(tr("Channel Level: Displays the " "pre-fader audio level of this channel. All connected clients at the " "server will be assigned an audio level, the same value for each client.")); plbrChannelLevel->setAccessibleName(tr("Input level of the current audio " "channel at the server")); pFader->setWhatsThis(tr("Mixer Fader: Adjusts the audio level of " "this channel. All connected clients at the server will be assigned " "an audio fader at each client, adjusting the local mix.")); pFader->setAccessibleName(tr("Local mix level setting 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")); pcbSolo->setWhatsThis(tr("Solo: With the Solo checkbox, the " "audio channel can be set to solo which means that all other channels " "except of the current channel are muted. It is possible to set more than " "one channel to solo.")); pcbSolo->setAccessibleName(tr("Solo button")); QString strFaderText = tr("Fader Tag: The fader tag " "identifies the connected client. The tag name, the picture of your " "instrument and a flag of your country can be set in the main window."); plblInstrument->setWhatsThis(strFaderText); plblInstrument->setAccessibleName(tr("Mixer channel instrument picture")); plblLabel->setWhatsThis(strFaderText); plblLabel->setAccessibleName(tr("Mixer channel label (fader tag)")); plblCountryFlag->setWhatsThis(strFaderText); plblCountryFlag->setAccessibleName(tr("Mixer channel country flag")); // Connections ------------------------------------------------------------- QObject::connect(pFader, SIGNAL(valueChanged(int)), this, SLOT(OnLevelValueChanged(int))); QObject::connect(pcbMute, SIGNAL(stateChanged(int)), this, SLOT(OnMuteStateChanged(int))); QObject::connect(pcbSolo, SIGNAL(stateChanged(int)), SIGNAL(soloStateChanged(int))); } void CChannelFader::SetGUIDesign(const EGUIDesign eNewDesign) { switch (eNewDesign) { case GD_ORIGINAL: // fader pFader->setStyleSheet( "QSlider { width: 45px;" " border-image: url(:/png/main/res/ui-2021/clientdialog/raya_fader_azul.png) repeat;" " border-top: 10px transparent;" " border-bottom: 10px transparent;" " border-left: 20px transparent;" " border-right: -25px transparent; }" "QSlider::groove { image: url();" " padding-left: -38px;" " padding-top: -10px;" " padding-bottom: -7px; }" "QSlider::handle { image: url(:/png/main/res/ui-2021/clientdialog/fader_sala_blanco.png); }"); pcbMute->setText(tr("MUTE")); pcbMute->setStyleSheet( "QCheckBox::pcbMute {" " width: 24px;" " height: 24px;" " }" " QCheckBox::pcbMute:checked" " {" " image: url(:/png/main/res/ui/btn_power_clicked.png);" " }" " QCheckBox::pcbMute:unchecked" " {" " image: url(:/png/main/res/ui/btn_minipower.png);" " }" "" " QCheckBox::pcbMute:checked:hover" " {" " image: url(:/png/main/res/ui/btn_power_clicked.png);" " }" " QCheckBox::pcbMute:unchecked:hover" " {" " image: url(:/png/main/res/ui/btn_minipower_hover.png);" " }" " QCheckBox::pcbMute:checked:pressed" " {" " image: url(:/png/main/res/ui/btn_power_click.png);" " }" " QCheckBox::pcbMute:unchecked:pressed" " {" " image: url(:/png/main/res/ui/btn_power_click.png);" " }" ); pcbSolo->setText(tr("SOLO")); pcbSolo->setStyleSheet( "QCheckBox::pcbSolo {" " width: 24px;" " height: 24px;" " }" " QCheckBox::pcbSolo:checked" " {" " image: url(:/png/main/res/ui/btn_power_clicked.png);" " }" " QCheckBox::pcbSolo:unchecked" " {" " image: url(:/png/main/res/ui/btn_minipower.png);" " }" "" " QCheckBox::pcbSolo:checked:hover" " {" " image: url(:/png/main/res/ui/btn_power_clicked.png);" " }" " QCheckBox::pcbSolo:unchecked:hover" " {" " image: url(:/png/main/res/ui/btn_minipower_hover.png);" " }" " QCheckBox::pcbSolo:checked:pressed" " {" " image: url(:/png/main/res/ui/btn_power_click.png);" " }" " QCheckBox::pcbSolo:unchecked:pressed" " {" " image: url(:/png/main/res/ui/btn_power_click.png);" " }" ); plbrChannelLevel->SetLevelMeterType(CMultiColorLEDBar::MT_LED); break; default: // reset style sheet and set original paramters pFader->setStyleSheet(""); pcbMute->setText(tr("Mute")); pcbSolo->setText(tr("Solo")); plbrChannelLevel->SetLevelMeterType(CMultiColorLEDBar::MT_LED); break; } } void CChannelFader::SetDisplayChannelLevel(const bool eNDCL) { plbrChannelLevel->setHidden(!eNDCL); } bool CChannelFader::GetDisplayChannelLevel() { return !plbrChannelLevel->isHidden(); } void CChannelFader::SetupFaderTag(const ESkillLevel eSkillLevel) { // setup group box for label/instrument picture: set a thick black border // with nice round edges QString strStile = "QGroupBox { border: 1px solid white;" " border-radius: 4px;" " padding: 10px;}"; // the background color depends on the skill level /* switch (eSkillLevel) { case SL_BEGINNER: strStile += QString("background-color: rgb(%1, %2, %3); }"). arg(RGBCOL_R_SL_BEGINNER). arg(RGBCOL_G_SL_BEGINNER). arg(RGBCOL_B_SL_BEGINNER); break; case SL_INTERMEDIATE: strStile += QString("background-color: rgb(%1, %2, %3); }"). arg(RGBCOL_R_SL_INTERMEDIATE). arg(RGBCOL_G_SL_INTERMEDIATE). arg(RGBCOL_B_SL_INTERMEDIATE); break; case SL_PROFESSIONAL: strStile += QString("background-color: rgb(%1, %2, %3); }"). arg(RGBCOL_R_SL_SL_PROFESSIONAL). arg(RGBCOL_G_SL_SL_PROFESSIONAL). arg(RGBCOL_B_SL_SL_PROFESSIONAL); break; default: strStile += QString("background-color: rgb(%1, %2, %3); }"). arg(RGBCOL_R_SL_NOT_SET). arg(RGBCOL_G_SL_NOT_SET). arg(RGBCOL_B_SL_NOT_SET); break; } */ pLabelInstBox->setStyleSheet(strStile); } void CChannelFader::Reset() { // init gain value -> maximum value as definition according to server pFader->setValue(AUD_MIX_FADER_MAX); // reset mute/solo check boxes and level meter pcbMute->setChecked(true); //Muteo el canal para evitar feedback al principio CChannelFader::SetMute(true); pcbSolo->setChecked(false); plbrChannelLevel->setValue(0); // clear instrument picture, country flag, tool tips and label text plblLabel->setText(""); plblLabel->setToolTip(""); plblInstrument->setVisible(false); plblInstrument->setToolTip(""); plblCountryFlag->setVisible(false); plblCountryFlag->setToolTip(""); strReceivedName = ""; SetupFaderTag(SL_NOT_SET); // set a defined tool tip time out (only available in Qt5) #if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0) const int iToolTipDurMs = 30000; plblLabel->setToolTipDuration ( iToolTipDurMs ); plblInstrument->setToolTipDuration ( iToolTipDurMs ); plblCountryFlag->setToolTipDuration ( iToolTipDurMs ); #endif bOtherChannelIsSolo = false; } void CChannelFader::SetFaderLevel(const int iLevel) { // first make a range check if ((iLevel >= 0) && (iLevel <= AUD_MIX_FADER_MAX)) { // we set the new fader level in the GUI (slider control) and also tell the // server about the change pFader->setValue(iLevel); SendFaderLevelToServer(iLevel); } } void CChannelFader::SetFaderIsSolo(const bool bIsSolo) { // changing the state automatically emits the signal, too pcbSolo->setChecked(bIsSolo); } void CChannelFader::SetFaderIsMute(const bool bIsMute) { // changing the state automatically emits the signal, too pcbMute->setChecked(bIsMute); } void CChannelFader::SendFaderLevelToServer(const int iLevel) { // if mute flag is set or other channel is on solo, do not apply the new // fader value (exception: we are on solo, in that case we ignore the // "other channel is on solo" flag) if ((pcbMute->checkState() == Qt::Unchecked) && (!bOtherChannelIsSolo || IsSolo())) { // emit signal for new fader gain value emit gainValueChanged(CalcFaderGain(iLevel)); } } void CChannelFader::OnMuteStateChanged(int value) { // call muting function SetMute(static_cast ( value ) == Qt::Checked); } void CChannelFader::SetMute(const bool bState) { if (bState) { // mute channel -> send gain of 0 emit gainValueChanged(0); } else { // only unmute if we are not solot but an other channel is on solo if (!bOtherChannelIsSolo || IsSolo()) { // mute was unchecked, get current fader value and apply emit gainValueChanged(CalcFaderGain(GetFaderLevel())); } } } void CChannelFader::UpdateSoloState(const bool bNewOtherSoloState) { // store state (must be done before the SetMute() call!) bOtherChannelIsSolo = bNewOtherSoloState; // mute overwrites solo -> if mute is active, do not change anything if (!pcbMute->isChecked()) { // mute channel if we are not solo but another channel is solo SetMute(bOtherChannelIsSolo && !IsSolo()); } } void CChannelFader::SetChannelLevel(const uint16_t iLevel) { plbrChannelLevel->setValue(iLevel); } void CChannelFader::SetText(const CChannelInfo &ChanInfo) { // store original received name strReceivedName = ChanInfo.strName; // break text at predefined position const int iBreakPos = MAX_LEN_FADER_TAG / 2; QString strModText = ChanInfo.GenNameForDisplay(); if (strModText.length() > iBreakPos) { strModText.insert(iBreakPos, QString("\n")); } plblLabel->setText(strModText); } void CChannelFader::SetChannelInfos(const CChannelInfo &cChanInfo) { // init properties for the tool tip int iTTInstrument = CInstPictures::GetNotUsedInstrument(); QLocale::Country eTTCountry = QLocale::AnyCountry; // Instrument picture ------------------------------------------------------ // get the resource reference string for this instrument const QString strCurResourceRef = CInstPictures::GetResourceReference(cChanInfo.iInstrument); // first check if instrument picture is used or not and if it is valid if (CInstPictures::IsNotUsedInstrument(cChanInfo.iInstrument) || strCurResourceRef.isEmpty()) { // disable instrument picture plblInstrument->setVisible(false); } else { // set correct picture plblInstrument->setPixmap(QPixmap(strCurResourceRef)); iTTInstrument = cChanInfo.iInstrument; // enable instrument picture plblInstrument->setVisible(true); } // Country flag icon ------------------------------------------------------- if (cChanInfo.eCountry != QLocale::AnyCountry) { // try to load the country flag icon QPixmap CountryFlagPixmap(CLocale::GetCountryFlagIconsResourceReference(cChanInfo.eCountry)); // first check if resource reference was valid if (CountryFlagPixmap.isNull()) { // disable country flag plblCountryFlag->setVisible(false); } else { // set correct picture plblCountryFlag->setPixmap(CountryFlagPixmap); eTTCountry = cChanInfo.eCountry; // enable country flag plblCountryFlag->setVisible(true); } } else { // disable country flag plblCountryFlag->setVisible(false); } // Skill level background color -------------------------------------------- SetupFaderTag(cChanInfo.eSkillLevel); // Tool tip ---------------------------------------------------------------- // complete musician profile in the tool tip QString strToolTip = ""; // alias/name if (!strReceivedName.isEmpty()) { strToolTip += "

Alias/Name

" + strReceivedName; } // instrument if (!CInstPictures::IsNotUsedInstrument(iTTInstrument)) { strToolTip += "

Instrument

" + CInstPictures::GetName(iTTInstrument); } // location if ((eTTCountry != QLocale::AnyCountry) || (!cChanInfo.strCity.isEmpty())) { strToolTip += "

Location

"; if (!cChanInfo.strCity.isEmpty()) { strToolTip += cChanInfo.strCity; if (eTTCountry != QLocale::AnyCountry) { strToolTip += ", "; } } if (eTTCountry != QLocale::AnyCountry) { strToolTip += QLocale::countryToString(eTTCountry); } } // skill level switch (cChanInfo.eSkillLevel) { case SL_BEGINNER: strToolTip += "

Skill Level

Beginner"; break; case SL_INTERMEDIATE: strToolTip += "

Skill Level

Intermediate"; break; case SL_PROFESSIONAL: strToolTip += "

Skill Level

Expert"; break; case SL_NOT_SET: // skill level not set, do not add this entry break; } // if no information is given, leave the tool tip empty, otherwise add header if (!strToolTip.isEmpty()) { strToolTip.prepend("

Musician Profile

"); } plblCountryFlag->setToolTip(strToolTip); plblInstrument->setToolTip(strToolTip); plblLabel->setToolTip(strToolTip); } double CChannelFader::CalcFaderGain(const int value) { // convert actual slider range in gain values // and normalize so that maximum gain is 1 const double dInValueRange0_1 = static_cast ( value ) / AUD_MIX_FADER_MAX; // map range from 0..1 to range -35..0 dB and calculate linear gain if (value == 0) { return 0; // -infinity } else { return pow(10, (dInValueRange0_1 * 35 - 35) / 20); } } /******************************************************************************\ * CAudioMixerBoard * \******************************************************************************/ CAudioMixerBoard::CAudioMixerBoard(QWidget *parent, Qt::WindowFlags) : QScrollArea(parent), vecStoredFaderTags(MAX_NUM_STORED_FADER_SETTINGS, ""), vecStoredFaderLevels(MAX_NUM_STORED_FADER_SETTINGS, AUD_MIX_FADER_MAX), vecStoredFaderIsSolo(MAX_NUM_STORED_FADER_SETTINGS, false), vecStoredFaderIsMute(MAX_NUM_STORED_FADER_SETTINGS, false), iNewClientFaderLevel(100), bNoFaderVisible(true), strServerName("") { // add group box and hboxlayout pGroupBox = new QGroupBox(); // will be added to the scroll area which is then the parent pGroupBox->setStyleSheet("border: 1px solid rgb(0,0,0,0.2);"); pMainLayout = new QHBoxLayout(pGroupBox); // set title text (default: no server given) SetServerName(""); // create all mixer controls and make them invisible vecpChanFader.Init(MAX_NUM_CHANNELS); for (int i = 0; i < MAX_NUM_CHANNELS; i++) { vecpChanFader[i] = new CChannelFader(this, pMainLayout); vecpChanFader[i]->Hide(); } // insert horizontal spacer pMainLayout->addItem(new QSpacerItem(0, 0, QSizePolicy::Expanding)); // add the group box to the scroll area setMinimumWidth(400); // at least two faders shall be visible setWidget(pGroupBox); setWidgetResizable(true); // make sure it fills the entire scroll area setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); setHorizontalScrollBarPolicy(Qt::ScrollBarAsNeeded); setFrameShape(QFrame::NoFrame); // Connections ------------------------------------------------------------- #if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0) connectFaderSignalsToMixerBoardSlots(); #else // CODE TAG: MAX_NUM_CHANNELS_TAG // make sure we have MAX_NUM_CHANNELS connections!!! QObject::connect(vecpChanFader[0], SIGNAL(gainValueChanged(double)), this, SLOT(OnGainValueChangedCh0(double))); QObject::connect(vecpChanFader[1], SIGNAL(gainValueChanged(double)), this, SLOT(OnGainValueChangedCh1(double))); QObject::connect(vecpChanFader[2], SIGNAL(gainValueChanged(double)), this, SLOT(OnGainValueChangedCh2(double))); QObject::connect(vecpChanFader[3], SIGNAL(gainValueChanged(double)), this, SLOT(OnGainValueChangedCh3(double))); QObject::connect(vecpChanFader[4], SIGNAL(gainValueChanged(double)), this, SLOT(OnGainValueChangedCh4(double))); QObject::connect(vecpChanFader[5], SIGNAL(gainValueChanged(double)), this, SLOT(OnGainValueChangedCh5(double))); QObject::connect(vecpChanFader[6], SIGNAL(gainValueChanged(double)), this, SLOT(OnGainValueChangedCh6(double))); QObject::connect(vecpChanFader[7], SIGNAL(gainValueChanged(double)), this, SLOT(OnGainValueChangedCh7(double))); QObject::connect(vecpChanFader[8], SIGNAL(gainValueChanged(double)), this, SLOT(OnGainValueChangedCh8(double))); QObject::connect(vecpChanFader[9], SIGNAL(gainValueChanged(double)), this, SLOT(OnGainValueChangedCh9(double))); QObject::connect(vecpChanFader[10], SIGNAL(gainValueChanged(double)), this, SLOT(OnGainValueChangedCh10(double))); QObject::connect(vecpChanFader[11], SIGNAL(gainValueChanged(double)), this, SLOT(OnGainValueChangedCh11(double))); QObject::connect(vecpChanFader[12], SIGNAL(gainValueChanged(double)), this, SLOT(OnGainValueChangedCh12(double))); QObject::connect(vecpChanFader[13], SIGNAL(gainValueChanged(double)), this, SLOT(OnGainValueChangedCh13(double))); QObject::connect(vecpChanFader[14], SIGNAL(gainValueChanged(double)), this, SLOT(OnGainValueChangedCh14(double))); QObject::connect(vecpChanFader[15], SIGNAL(gainValueChanged(double)), this, SLOT(OnGainValueChangedCh15(double))); QObject::connect(vecpChanFader[16], SIGNAL(gainValueChanged(double)), this, SLOT(OnGainValueChangedCh16(double))); QObject::connect(vecpChanFader[17], SIGNAL(gainValueChanged(double)), this, SLOT(OnGainValueChangedCh17(double))); QObject::connect(vecpChanFader[18], SIGNAL(gainValueChanged(double)), this, SLOT(OnGainValueChangedCh18(double))); QObject::connect(vecpChanFader[19], SIGNAL(gainValueChanged(double)), this, SLOT(OnGainValueChangedCh19(double))); QObject::connect(vecpChanFader[20], SIGNAL(gainValueChanged(double)), this, SLOT(OnGainValueChangedCh20(double))); QObject::connect(vecpChanFader[21], SIGNAL(gainValueChanged(double)), this, SLOT(OnGainValueChangedCh21(double))); QObject::connect(vecpChanFader[22], SIGNAL(gainValueChanged(double)), this, SLOT(OnGainValueChangedCh22(double))); QObject::connect(vecpChanFader[23], SIGNAL(gainValueChanged(double)), this, SLOT(OnGainValueChangedCh23(double))); QObject::connect(vecpChanFader[24], SIGNAL(gainValueChanged(double)), this, SLOT(OnGainValueChangedCh24(double))); QObject::connect(vecpChanFader[25], SIGNAL(gainValueChanged(double)), this, SLOT(OnGainValueChangedCh25(double))); QObject::connect(vecpChanFader[26], SIGNAL(gainValueChanged(double)), this, SLOT(OnGainValueChangedCh26(double))); QObject::connect(vecpChanFader[27], SIGNAL(gainValueChanged(double)), this, SLOT(OnGainValueChangedCh27(double))); QObject::connect(vecpChanFader[28], SIGNAL(gainValueChanged(double)), this, SLOT(OnGainValueChangedCh28(double))); QObject::connect(vecpChanFader[29], SIGNAL(gainValueChanged(double)), this, SLOT(OnGainValueChangedCh29(double))); QObject::connect(vecpChanFader[30], SIGNAL(gainValueChanged(double)), this, SLOT(OnGainValueChangedCh30(double))); QObject::connect(vecpChanFader[31], SIGNAL(gainValueChanged(double)), this, SLOT(OnGainValueChangedCh31(double))); QObject::connect(vecpChanFader[32], SIGNAL(gainValueChanged(double)), this, SLOT(OnGainValueChangedCh32(double))); QObject::connect(vecpChanFader[33], SIGNAL(gainValueChanged(double)), this, SLOT(OnGainValueChangedCh33(double))); QObject::connect(vecpChanFader[34], SIGNAL(gainValueChanged(double)), this, SLOT(OnGainValueChangedCh34(double))); QObject::connect(vecpChanFader[35], SIGNAL(gainValueChanged(double)), this, SLOT(OnGainValueChangedCh35(double))); QObject::connect(vecpChanFader[36], SIGNAL(gainValueChanged(double)), this, SLOT(OnGainValueChangedCh36(double))); QObject::connect(vecpChanFader[37], SIGNAL(gainValueChanged(double)), this, SLOT(OnGainValueChangedCh37(double))); QObject::connect(vecpChanFader[38], SIGNAL(gainValueChanged(double)), this, SLOT(OnGainValueChangedCh38(double))); QObject::connect(vecpChanFader[39], SIGNAL(gainValueChanged(double)), this, SLOT(OnGainValueChangedCh39(double))); QObject::connect(vecpChanFader[40], SIGNAL(gainValueChanged(double)), this, SLOT(OnGainValueChangedCh40(double))); QObject::connect(vecpChanFader[41], SIGNAL(gainValueChanged(double)), this, SLOT(OnGainValueChangedCh41(double))); QObject::connect(vecpChanFader[42], SIGNAL(gainValueChanged(double)), this, SLOT(OnGainValueChangedCh42(double))); QObject::connect(vecpChanFader[43], SIGNAL(gainValueChanged(double)), this, SLOT(OnGainValueChangedCh43(double))); QObject::connect(vecpChanFader[44], SIGNAL(gainValueChanged(double)), this, SLOT(OnGainValueChangedCh44(double))); QObject::connect(vecpChanFader[45], SIGNAL(gainValueChanged(double)), this, SLOT(OnGainValueChangedCh45(double))); QObject::connect(vecpChanFader[46], SIGNAL(gainValueChanged(double)), this, SLOT(OnGainValueChangedCh46(double))); QObject::connect(vecpChanFader[47], SIGNAL(gainValueChanged(double)), this, SLOT(OnGainValueChangedCh47(double))); QObject::connect(vecpChanFader[48], SIGNAL(gainValueChanged(double)), this, SLOT(OnGainValueChangedCh48(double))); QObject::connect(vecpChanFader[49], SIGNAL(gainValueChanged(double)), this, SLOT(OnGainValueChangedCh49(double))); QObject::connect(vecpChanFader[0], SIGNAL(soloStateChanged(int)), this, SLOT(OnChSoloStateChanged())); QObject::connect(vecpChanFader[1], SIGNAL(soloStateChanged(int)), this, SLOT(OnChSoloStateChanged())); QObject::connect(vecpChanFader[2], SIGNAL(soloStateChanged(int)), this, SLOT(OnChSoloStateChanged())); QObject::connect(vecpChanFader[3], SIGNAL(soloStateChanged(int)), this, SLOT(OnChSoloStateChanged())); QObject::connect(vecpChanFader[4], SIGNAL(soloStateChanged(int)), this, SLOT(OnChSoloStateChanged())); QObject::connect(vecpChanFader[5], SIGNAL(soloStateChanged(int)), this, SLOT(OnChSoloStateChanged())); QObject::connect(vecpChanFader[6], SIGNAL(soloStateChanged(int)), this, SLOT(OnChSoloStateChanged())); QObject::connect(vecpChanFader[7], SIGNAL(soloStateChanged(int)), this, SLOT(OnChSoloStateChanged())); QObject::connect(vecpChanFader[8], SIGNAL(soloStateChanged(int)), this, SLOT(OnChSoloStateChanged())); QObject::connect(vecpChanFader[9], SIGNAL(soloStateChanged(int)), this, SLOT(OnChSoloStateChanged())); QObject::connect(vecpChanFader[10], SIGNAL(soloStateChanged(int)), this, SLOT(OnChSoloStateChanged())); QObject::connect(vecpChanFader[11], SIGNAL(soloStateChanged(int)), this, SLOT(OnChSoloStateChanged())); QObject::connect(vecpChanFader[12], SIGNAL(soloStateChanged(int)), this, SLOT(OnChSoloStateChanged())); QObject::connect(vecpChanFader[13], SIGNAL(soloStateChanged(int)), this, SLOT(OnChSoloStateChanged())); QObject::connect(vecpChanFader[14], SIGNAL(soloStateChanged(int)), this, SLOT(OnChSoloStateChanged())); QObject::connect(vecpChanFader[15], SIGNAL(soloStateChanged(int)), this, SLOT(OnChSoloStateChanged())); QObject::connect(vecpChanFader[16], SIGNAL(soloStateChanged(int)), this, SLOT(OnChSoloStateChanged())); QObject::connect(vecpChanFader[17], SIGNAL(soloStateChanged(int)), this, SLOT(OnChSoloStateChanged())); QObject::connect(vecpChanFader[18], SIGNAL(soloStateChanged(int)), this, SLOT(OnChSoloStateChanged())); QObject::connect(vecpChanFader[19], SIGNAL(soloStateChanged(int)), this, SLOT(OnChSoloStateChanged())); QObject::connect(vecpChanFader[20], SIGNAL(soloStateChanged(int)), this, SLOT(OnChSoloStateChanged())); QObject::connect(vecpChanFader[21], SIGNAL(soloStateChanged(int)), this, SLOT(OnChSoloStateChanged())); QObject::connect(vecpChanFader[22], SIGNAL(soloStateChanged(int)), this, SLOT(OnChSoloStateChanged())); QObject::connect(vecpChanFader[23], SIGNAL(soloStateChanged(int)), this, SLOT(OnChSoloStateChanged())); QObject::connect(vecpChanFader[24], SIGNAL(soloStateChanged(int)), this, SLOT(OnChSoloStateChanged())); QObject::connect(vecpChanFader[25], SIGNAL(soloStateChanged(int)), this, SLOT(OnChSoloStateChanged())); QObject::connect(vecpChanFader[26], SIGNAL(soloStateChanged(int)), this, SLOT(OnChSoloStateChanged())); QObject::connect(vecpChanFader[27], SIGNAL(soloStateChanged(int)), this, SLOT(OnChSoloStateChanged())); QObject::connect(vecpChanFader[28], SIGNAL(soloStateChanged(int)), this, SLOT(OnChSoloStateChanged())); QObject::connect(vecpChanFader[29], SIGNAL(soloStateChanged(int)), this, SLOT(OnChSoloStateChanged())); QObject::connect(vecpChanFader[30], SIGNAL(soloStateChanged(int)), this, SLOT(OnChSoloStateChanged())); QObject::connect(vecpChanFader[31], SIGNAL(soloStateChanged(int)), this, SLOT(OnChSoloStateChanged())); QObject::connect(vecpChanFader[32], SIGNAL(soloStateChanged(int)), this, SLOT(OnChSoloStateChanged())); QObject::connect(vecpChanFader[33], SIGNAL(soloStateChanged(int)), this, SLOT(OnChSoloStateChanged())); QObject::connect(vecpChanFader[34], SIGNAL(soloStateChanged(int)), this, SLOT(OnChSoloStateChanged())); QObject::connect(vecpChanFader[35], SIGNAL(soloStateChanged(int)), this, SLOT(OnChSoloStateChanged())); QObject::connect(vecpChanFader[36], SIGNAL(soloStateChanged(int)), this, SLOT(OnChSoloStateChanged())); QObject::connect(vecpChanFader[37], SIGNAL(soloStateChanged(int)), this, SLOT(OnChSoloStateChanged())); QObject::connect(vecpChanFader[38], SIGNAL(soloStateChanged(int)), this, SLOT(OnChSoloStateChanged())); QObject::connect(vecpChanFader[39], SIGNAL(soloStateChanged(int)), this, SLOT(OnChSoloStateChanged())); QObject::connect(vecpChanFader[40], SIGNAL(soloStateChanged(int)), this, SLOT(OnChSoloStateChanged())); QObject::connect(vecpChanFader[41], SIGNAL(soloStateChanged(int)), this, SLOT(OnChSoloStateChanged())); QObject::connect(vecpChanFader[42], SIGNAL(soloStateChanged(int)), this, SLOT(OnChSoloStateChanged())); QObject::connect(vecpChanFader[43], SIGNAL(soloStateChanged(int)), this, SLOT(OnChSoloStateChanged())); QObject::connect(vecpChanFader[44], SIGNAL(soloStateChanged(int)), this, SLOT(OnChSoloStateChanged())); QObject::connect(vecpChanFader[45], SIGNAL(soloStateChanged(int)), this, SLOT(OnChSoloStateChanged())); QObject::connect(vecpChanFader[46], SIGNAL(soloStateChanged(int)), this, SLOT(OnChSoloStateChanged())); QObject::connect(vecpChanFader[47], SIGNAL(soloStateChanged(int)), this, SLOT(OnChSoloStateChanged())); QObject::connect(vecpChanFader[48], SIGNAL(soloStateChanged(int)), this, SLOT(OnChSoloStateChanged())); QObject::connect(vecpChanFader[49], SIGNAL(soloStateChanged(int)), this, SLOT(OnChSoloStateChanged())); #endif } #if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0) template inline void CAudioMixerBoard::connectFaderSignalsToMixerBoardSlots() { int iCurChanID = slotId - 1; void ( CAudioMixerBoard::* pGainValueChanged )( double ) = &CAudioMixerBoardSlots::OnChGainValueChanged; QObject::connect ( vecpChanFader[iCurChanID], &CChannelFader::soloStateChanged, this, &CAudioMixerBoard::UpdateSoloStates ); QObject::connect ( vecpChanFader[iCurChanID], &CChannelFader::gainValueChanged, this, pGainValueChanged ); connectFaderSignalsToMixerBoardSlots(); }; template<> inline void CAudioMixerBoard::connectFaderSignalsToMixerBoardSlots<0>() {}; #endif void CAudioMixerBoard::SetServerName(const QString &strNewServerName) { // store the current server name strServerName = strNewServerName; if (strServerName.isEmpty()) { // no connection or connection was reset: show default title pGroupBox->setTitle(""); } else { // Do not set the server name directly but first show a label which indicates // that we are trying to connect the server. First if a connected client // list was received, the connection was successful and the title is updated // with the correct server name. Make sure to choose a "try to connect" title // which is most striking (we use filled blocks and upper case letters). pGroupBox->setTitle( u8"\u2588\u2588\u2588\u2588\u2588 T R Y I N G T O C O N N E C T \u2588\u2588\u2588\u2588\u2588"); } } void CAudioMixerBoard::SetGUIDesign(const EGUIDesign eNewDesign) { // apply GUI design to child GUI controls for (int i = 0; i < MAX_NUM_CHANNELS; i++) { vecpChanFader[i]->SetGUIDesign(eNewDesign); } } void CAudioMixerBoard::SetDisplayChannelLevels(const bool eNDCL) { bDisplayChannelLevels = eNDCL; // only update hiding the levels immediately, showing the levels // is only applied if the server actually transmits levels if (!bDisplayChannelLevels) { // hide all level meters for (int i = 0; i < MAX_NUM_CHANNELS; i++) { vecpChanFader[i]->SetDisplayChannelLevel(false); } } } void CAudioMixerBoard::HideAll() { // make all controls invisible for (int i = 0; i < MAX_NUM_CHANNELS; i++) { // before hiding the fader, store its level (if some conditions are fullfilled) StoreFaderSettings(vecpChanFader[i]); vecpChanFader[i]->SetChannelLevel(0); vecpChanFader[i]->SetDisplayChannelLevel(false); vecpChanFader[i]->Hide(); } // set flag bNoFaderVisible = true; // emit status of connected clients emit NumClientsChanged(0); // -> no clients connected } void CAudioMixerBoard::ApplyNewConClientList(CVector &vecChanInfo) { // we want to set the server name only if the very first faders appear // in the audio mixer board to show a "try to connect" before if (pGroupBox->title().compare(strServerName)) { //pGroupBox->setTitle(strServerName); pGroupBox->setTitle(""); } // get number of connected clients const int iNumConnectedClients = vecChanInfo.Size(); // search for channels with are already present and preserve their gain // setting, for all other channels reset gain for (int i = 0; i < MAX_NUM_CHANNELS; i++) { bool bFaderIsUsed = false; for (int j = 0; j < iNumConnectedClients; j++) { // check if current fader is used if (vecChanInfo[j].iChanID == i) { // check if fader was already in use -> preserve gain value if (!vecpChanFader[i]->IsVisible()) { // the fader was not in use, reset everything for new client vecpChanFader[i]->Reset(); // show fader vecpChanFader[i]->Show(); // Set the default initial fader level. Check first that // this is not the initialization (i.e. previously there // were no faders visible) to avoid that our own level is // adjusted. The fader level of 100 % is the default in the // server, in that case we do not have to do anything here. if (!bNoFaderVisible && (iNewClientFaderLevel != 100)) { // the value is in percent -> convert range vecpChanFader[i]->SetFaderLevel(static_cast ( iNewClientFaderLevel / 100.0 * AUD_MIX_FADER_MAX )); } } // restore gain (if new name is different from the current one) if (vecpChanFader[i]->GetReceivedName().compare(vecChanInfo[j].strName)) { // the text has actually changed, search in the list of // stored settings if we have a matching entry int iStoredFaderLevel; bool bStoredFaderIsSolo; bool bStoredFaderIsMute; if (GetStoredFaderSettings(vecChanInfo[j], iStoredFaderLevel, bStoredFaderIsSolo, bStoredFaderIsMute)) { vecpChanFader[i]->SetFaderLevel(iStoredFaderLevel); vecpChanFader[i]->SetFaderIsSolo(bStoredFaderIsSolo); vecpChanFader[i]->SetFaderIsMute(bStoredFaderIsMute); } } // set the text in the fader vecpChanFader[i]->SetText(vecChanInfo[j]); // update other channel infos vecpChanFader[i]->SetChannelInfos(vecChanInfo[j]); bFaderIsUsed = true; } } // if current fader is not used, hide it if (!bFaderIsUsed) { // before hiding the fader, store its level (if some conditions are fullfilled) StoreFaderSettings(vecpChanFader[i]); vecpChanFader[i]->Hide(); } } // update the solo states since if any channel was on solo and a new client // has just connected, the new channel must be muted UpdateSoloStates(); // update flag for "all faders are invisible" bNoFaderVisible = (iNumConnectedClients == 0); // emit status of connected clients emit NumClientsChanged(iNumConnectedClients); } void CAudioMixerBoard::SetFaderLevel(const int iChannelIdx, const int iValue) { // only apply new fader level if channel index is valid and the fader is visible if ((iChannelIdx >= 0) && (iChannelIdx < MAX_NUM_CHANNELS)) { if (vecpChanFader[iChannelIdx]->IsVisible()) { vecpChanFader[iChannelIdx]->SetFaderLevel(iValue); } } } void CAudioMixerBoard::UpdateSoloStates() { // first check if any channel has a solo state active bool bAnyChannelIsSolo = false; for (int i = 0; i < MAX_NUM_CHANNELS; i++) { // check if fader is in use and has solo state active if (vecpChanFader[i]->IsVisible() && vecpChanFader[i]->IsSolo()) { bAnyChannelIsSolo = true; continue; } } // now update the solo state of all active faders for (int i = 0; i < MAX_NUM_CHANNELS; i++) { if (vecpChanFader[i]->IsVisible()) { vecpChanFader[i]->UpdateSoloState(bAnyChannelIsSolo); } } } void CAudioMixerBoard::UpdateGainValue(const int iChannelIdx, const double dValue) { emit ChangeChanGain(iChannelIdx, dValue); } void CAudioMixerBoard::StoreFaderSettings(CChannelFader *pChanFader) { // if the fader was visible and the name is not empty, we store the old gain if (pChanFader->IsVisible() && !pChanFader->GetReceivedName().isEmpty()) { CVector viOldStoredFaderLevels(vecStoredFaderLevels); CVector vbOldStoredFaderIsSolo(vecStoredFaderIsSolo); CVector vbOldStoredFaderIsMute(vecStoredFaderIsMute); // init temporary list count (may be overwritten later on) int iTempListCnt = 0; // put new value on the top of the list const int iOldIdx = vecStoredFaderTags.StringFiFoWithCompare(pChanFader->GetReceivedName(), true); // current fader level and solo state is at the top of the list vecStoredFaderLevels[0] = pChanFader->GetFaderLevel(); vecStoredFaderIsSolo[0] = pChanFader->IsSolo(); vecStoredFaderIsMute[0] = pChanFader->IsMute(); iTempListCnt = 1; for (int iIdx = 0; iIdx < MAX_NUM_STORED_FADER_SETTINGS; iIdx++) { // first check if we still have space in our data storage if (iTempListCnt < MAX_NUM_STORED_FADER_SETTINGS) { // check for the old index of the current entry (this has to be // skipped), note that per definition: the old index is an illegal // index in case the entry was not present in the vector before if (iIdx != iOldIdx) { vecStoredFaderLevels[iTempListCnt] = viOldStoredFaderLevels[iIdx]; vecStoredFaderIsSolo[iTempListCnt] = vbOldStoredFaderIsSolo[iIdx]; vecStoredFaderIsMute[iTempListCnt] = vbOldStoredFaderIsMute[iIdx]; iTempListCnt++; } } } } } bool CAudioMixerBoard::GetStoredFaderSettings(const CChannelInfo &ChanInfo, int &iStoredFaderLevel, bool &bStoredFaderIsSolo, bool &bStoredFaderIsMute) { // only do the check if the name string is not empty if (!ChanInfo.strName.isEmpty()) { for (int iIdx = 0; iIdx < MAX_NUM_STORED_FADER_SETTINGS; iIdx++) { // check if fader text is already known in the list if (!vecStoredFaderTags[iIdx].compare(ChanInfo.strName)) { // copy stored settings values iStoredFaderLevel = vecStoredFaderLevels[iIdx]; bStoredFaderIsSolo = vecStoredFaderIsSolo[iIdx] != 0; bStoredFaderIsMute = vecStoredFaderIsMute[iIdx] != 0; // values found and copied, return OK return true; } } } // return "not OK" since we did not find matching fader settings return false; } void CAudioMixerBoard::SetChannelLevels(const CVector &vecChannelLevel) { const int iNumChannelLevels = vecChannelLevel.Size(); int i = 0; for (int iChId = 0; iChId < MAX_NUM_CHANNELS; iChId++) { if (vecpChanFader[iChId]->IsVisible() && i < iNumChannelLevels) { vecpChanFader[iChId]->SetChannelLevel(vecChannelLevel[i++]); // show level only if we successfully received levels from the // server (if server does not support levels, do not show levels) if (bDisplayChannelLevels && !vecpChanFader[iChId]->GetDisplayChannelLevel()) { vecpChanFader[iChId]->SetDisplayChannelLevel(true); } } } }