jamulus/src/audiomixerboard.cpp

439 lines
17 KiB
C++
Raw Normal View History

/******************************************************************************\
* Copyright (c) 2004-2009
*
* Author(s):
2009-05-01 12:25:32 +02:00
* 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"
2009-05-08 23:14:33 +02:00
/******************************************************************************\
* CChanneFader *
\******************************************************************************/
2006-12-09 16:00:24 +01:00
CChannelFader::CChannelFader ( QWidget* pNW,
QHBoxLayout* pParentLayout )
2006-12-09 16:00:24 +01:00
{
// create new GUI control objects and store pointers to them
pMainGrid = new QVBoxLayout();
pFader = new QSlider ( Qt::Vertical, pNW );
pcbMute = new QCheckBox ( "Mute", pNW );
pcbSolo = new QCheckBox ( "Solo", pNW );
pLabel = new QLabel ( "", pNW );
// setup layout
pMainGrid->setSpacing ( 2 );
2006-12-09 16:00:24 +01:00
// setup slider
pFader->setPageStep ( 1 );
pFader->setTickPosition ( QSlider::TicksBothSides );
2006-12-09 16:00:24 +01:00
pFader->setRange ( 0, AUD_MIX_FADER_MAX );
pFader->setTickInterval ( AUD_MIX_FADER_MAX / 9 );
2009-05-08 06:34:06 +02:00
// setup fader tag label (use white background of label)
2009-09-19 19:06:04 +02:00
pLabel->setTextFormat ( Qt::PlainText );
pLabel->setAlignment ( Qt::AlignHCenter );
2009-09-19 10:28:24 +02:00
pLabel->setStyleSheet (
"QLabel { border: 2px solid black;"
" border-radius: 4px;"
2009-09-19 19:06:04 +02:00
" padding: 4px;"
2009-09-19 10:28:24 +02:00
" background-color: white;"
" font: bold; }" );
// add user controls to grid
pMainGrid->addWidget( pFader, 0, Qt::AlignHCenter );
pMainGrid->addWidget( pcbMute, 0, Qt::AlignLeft );
pMainGrid->addWidget( pcbSolo, 0, Qt::AlignLeft );
pMainGrid->addWidget( pLabel, 0, Qt::AlignHCenter );
2006-12-09 16:00:24 +01:00
// add fader layout to audio mixer board layout
pParentLayout->addLayout ( pMainGrid );
// reset current fader
Reset();
2006-12-09 19:37:40 +01:00
// add help text to controls
pFader->setWhatsThis ( "<b>Mixer Fader:</b> Adjusts the audio level of "
"this channel. All connected clients at the server will be assigned "
"an audio fader at each client." );
pcbMute->setWhatsThis ( "<b>Mute:</b> With the Mute checkbox, the current "
"audio channel can be muted." );
pcbSolo->setWhatsThis ( "<b>Solo:</b> With the Solo checkbox, the current "
"audio channel can be set to solo which means that all other channels "
"except of the current channel are muted.<br/>"
"Only one channel at a time can be set to solo." );
pLabel->setWhatsThis ( "<b>Mixer Fader Label:</b> Label (fader tag) "
"identifying the connected client. The tag name can be set in the "
"clients main window." );
2006-12-09 19:37:40 +01:00
// connections -------------------------------------------------------------
QObject::connect ( pFader, SIGNAL ( valueChanged ( int ) ),
2009-05-08 23:14:33 +02:00
this, SLOT ( OnGainValueChanged ( int ) ) );
QObject::connect ( pcbMute, SIGNAL ( stateChanged ( int ) ),
this, SLOT ( OnMuteStateChanged ( int ) ) );
2009-05-08 23:14:33 +02:00
QObject::connect ( pcbSolo, SIGNAL ( stateChanged ( int ) ),
this, SIGNAL ( soloStateChanged ( int ) ) );
2006-12-09 19:37:40 +01:00
}
2009-09-19 10:28:24 +02:00
void CChannelFader::SetGUIDesign ( const EGUIDesign eNewDesign )
{
switch ( eNewDesign )
{
case GD_ORIGINAL:
// fader
pFader->setStyleSheet (
2009-09-19 19:06:04 +02:00
"QSlider { width: 30px;"
" border-image: url(:/png/fader/res/faderbackground.png) 10px 0px 10px 0px repeat;"
" border-top: 10px transparent;"
" border-bottom: 10px transparent;"
" border-left: 0px transparent;"
" border-right: 0px transparent; }"
2009-09-19 19:06:04 +02:00
"QSlider::groove { image: url();"
" padding-top: -10px;"
" padding-bottom: -15px; }"
2009-09-19 10:28:24 +02:00
"QSlider::handle { image: url(:/png/fader/res/faderhandle.png); }" );
// mute button
pcbMute->setStyleSheet (
"QCheckBox::indicator { width: 43px;"
" height: 24px; }"
"QCheckBox::indicator:unchecked {"
" image: url(:/png/fader/res/ledbuttonnotpressed.png); }"
"QCheckBox::indicator:checked {"
" image: url(:/png/fader/res/ledbuttonpressed.png); }"
"QCheckBox { color: rgb(148, 148, 148);"
" font: bold; }" );
pcbMute->setText ( "MUTE" );
// solo button
pcbSolo->setStyleSheet (
"QCheckBox::indicator { width: 43px;"
" height: 24px; }"
"QCheckBox::indicator:unchecked {"
" image: url(:/png/fader/res/ledbuttonnotpressed.png); }"
"QCheckBox::indicator:checked {"
" image: url(:/png/fader/res/ledbuttonpressed.png); }"
"QCheckBox { color: rgb(148, 148, 148);"
" font: bold; }" );
pcbSolo->setText ( "SOLO" );
break;
default:
// reset style sheet and set original paramters
pFader->setStyleSheet ( "" );
pcbMute->setStyleSheet ( "" );
pcbSolo->setStyleSheet ( "" );
pcbMute->setText ( "Mute" );
pcbSolo->setText ( "Solo" );
break;
}
}
void CChannelFader::Reset()
2006-12-09 19:37:40 +01:00
{
// init gain value -> maximum value as definition according to server
pFader->setValue ( AUD_MIX_FADER_MAX );
// reset mute/solo check boxes
pcbMute->setChecked ( false );
pcbSolo->setChecked ( false );
// clear label
pLabel->setText ( "" );
2009-05-08 23:14:33 +02:00
bOtherChannelIsSolo = false;
}
2006-12-09 19:37:40 +01:00
2009-05-08 23:14:33 +02:00
void CChannelFader::OnGainValueChanged ( int value )
{
// if mute flag is set, do not apply the new fader value
if ( pcbMute->checkState() == Qt::Unchecked )
{
// emit signal for new fader gain value
2009-05-08 23:14:33 +02:00
emit gainValueChanged ( CalcFaderGain ( value ) );
}
}
void CChannelFader::OnMuteStateChanged ( int value )
{
2009-05-08 23:14:33 +02:00
// call muting function
SetMute ( static_cast<Qt::CheckState> ( value ) == Qt::Checked );
}
void CChannelFader::SetMute ( const bool bState )
{
if ( bState )
{
// mute channel -> send gain of 0
2009-05-08 23:14:33 +02:00
emit gainValueChanged ( 0 );
}
else
{
2009-05-08 23:14:33 +02:00
// only unmute if no other channel is on solo
if ( !bOtherChannelIsSolo )
{
// mute was unchecked, get current fader value and apply
emit gainValueChanged ( CalcFaderGain ( pFader->value() ) );
}
}
}
void CChannelFader::ResetSoloState()
{
// reset solo state -> since solo state means that this channel is not
// muted but all others, we simply have to uncheck the check box
pcbSolo->setChecked ( false );
}
void CChannelFader::SetOtherSoloState ( const bool bState )
{
// store state (must be done before the SetMute() call!)
bOtherChannelIsSolo = bState;
// check if we are in solo on state, in that case we first have to disable
// our solo state since only one channel can be set to solo
if ( bState && pcbSolo->isChecked() )
{
pcbSolo->setChecked ( false );
}
// if other channel is solo, mute this channel, else enable channel gain
// (only enable channel gain if local mute switch is not set to on)
if ( !pcbMute->isChecked() )
{
SetMute ( bState );
}
2006-12-09 16:00:24 +01:00
}
2008-01-22 22:15:04 +01:00
void CChannelFader::SetText ( const QString sText )
2006-12-09 16:00:24 +01:00
{
const int iBreakPos = 8;
2006-12-09 16:00:24 +01:00
2006-12-10 13:36:43 +01:00
// break text at predefined position, if text is too short, break anyway to
// make sure we have two lines for fader tag
2008-01-22 22:15:04 +01:00
QString sModText = sText;
2006-12-09 16:00:24 +01:00
if ( sModText.length() > iBreakPos )
{
sModText.insert ( iBreakPos, QString ( "\n" ) );
2006-12-09 16:00:24 +01:00
}
2006-12-10 13:36:43 +01:00
else
{
// insert line break at the beginning of the string -> make sure
// if we only have one line that the text appears at the bottom line
sModText.prepend ( QString ( "\n" ) );
2006-12-10 13:36:43 +01:00
}
2006-12-09 16:00:24 +01:00
pLabel->setText ( sModText );
}
double CChannelFader::CalcFaderGain ( const int value )
{
// convert actual slider range in gain values
// and normalize so that maximum gain is 1
return static_cast<double> ( value ) / AUD_MIX_FADER_MAX;
}
2009-05-08 23:14:33 +02:00
/******************************************************************************\
* CAudioMixerBoard *
\******************************************************************************/
2009-05-08 06:34:06 +02:00
CAudioMixerBoard::CAudioMixerBoard ( QWidget* parent, Qt::WindowFlags f ) :
QGroupBox ( parent )
2006-12-09 16:00:24 +01:00
{
2009-05-08 06:34:06 +02:00
// set title text and title properties
2009-05-09 11:26:27 +02:00
setTitle ( "Server" );
2006-12-09 16:00:24 +01:00
2009-05-08 06:34:06 +02:00
// add hboxlayout
pMainLayout = new QHBoxLayout ( this );
2006-12-09 16:00:24 +01:00
// 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 );
2006-12-09 16:00:24 +01:00
vecpChanFader[i]->Hide();
}
2009-05-08 23:14:33 +02:00
// insert horizontal spacer
pMainLayout->addItem ( new QSpacerItem ( 0, 0, QSizePolicy::Expanding ) );
2006-12-09 16:00:24 +01:00
2006-12-09 19:37:40 +01:00
// connections -------------------------------------------------------------
// CODE TAG: MAX_NUM_CHANNELS_TAG
// make sure we have MAX_NUM_CHANNELS connections!!!
2009-05-08 23:14:33 +02:00
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[0], SIGNAL ( soloStateChanged ( int ) ), this, SLOT ( OnChSoloStateChangedCh0 ( int ) ) );
QObject::connect ( vecpChanFader[1], SIGNAL ( soloStateChanged ( int ) ), this, SLOT ( OnChSoloStateChangedCh1 ( int ) ) );
QObject::connect ( vecpChanFader[2], SIGNAL ( soloStateChanged ( int ) ), this, SLOT ( OnChSoloStateChangedCh2 ( int ) ) );
QObject::connect ( vecpChanFader[3], SIGNAL ( soloStateChanged ( int ) ), this, SLOT ( OnChSoloStateChangedCh3 ( int ) ) );
QObject::connect ( vecpChanFader[4], SIGNAL ( soloStateChanged ( int ) ), this, SLOT ( OnChSoloStateChangedCh4 ( int ) ) );
QObject::connect ( vecpChanFader[5], SIGNAL ( soloStateChanged ( int ) ), this, SLOT ( OnChSoloStateChangedCh5 ( int ) ) );
QObject::connect ( vecpChanFader[6], SIGNAL ( soloStateChanged ( int ) ), this, SLOT ( OnChSoloStateChangedCh6 ( int ) ) );
QObject::connect ( vecpChanFader[7], SIGNAL ( soloStateChanged ( int ) ), this, SLOT ( OnChSoloStateChangedCh7 ( int ) ) );
QObject::connect ( vecpChanFader[8], SIGNAL ( soloStateChanged ( int ) ), this, SLOT ( OnChSoloStateChangedCh8 ( int ) ) );
QObject::connect ( vecpChanFader[9], SIGNAL ( soloStateChanged ( int ) ), this, SLOT ( OnChSoloStateChangedCh9 ( int ) ) );
2006-12-09 16:00:24 +01:00
}
2009-09-19 10:28:24 +02:00
void CAudioMixerBoard::SetGUIDesign ( const EGUIDesign eNewDesign )
{
// apply GUI design to current window
switch ( eNewDesign )
{
case GD_ORIGINAL:
// group box
setStyleSheet (
"QGroupBox { border-image: url(:/png/fader/res/mixerboardbackground.png) 34px 30px 40px 40px;"
" border-top: 34px transparent;"
" border-bottom: 40px transparent;"
" border-left: 30px transparent;"
" border-right: 40px transparent;"
" padding: -5px;"
" margin: -5px, -5px, 0px, 0px; }"
"QGroupBox::title { margin-top: 13px;"
" margin-left: 35px;"
" background-color: transparent;"
" color: rgb(148, 148, 148); }" );
layout()->setMargin ( 3 );
break;
default:
// reset style sheet and set original paramters
setStyleSheet ( "" );
layout()->setMargin ( 9 );
break;
}
// also apply GUI design to child GUI controls
for ( int i = 0; i < USED_NUM_CHANNELS; i++ )
{
vecpChanFader[i]->SetGUIDesign ( eNewDesign );
}
}
2006-12-09 19:37:40 +01:00
void CAudioMixerBoard::HideAll()
2006-12-09 16:00:24 +01:00
{
// make old controls invisible
for ( int i = 0; i < USED_NUM_CHANNELS; i++ )
2006-12-09 16:00:24 +01:00
{
vecpChanFader[i]->Hide();
}
}
void CAudioMixerBoard::ApplyNewConClientList ( CVector<CChannelShortInfo>& vecChanInfo )
{
2006-12-09 19:37:40 +01:00
// search for channels with are already present and preserver their gain
// setting, for all other channels, reset gain
for ( int i = 0; i < USED_NUM_CHANNELS; i++ )
2006-12-09 19:37:40 +01:00
{
bool bFaderIsUsed = false;
for ( int j = 0; j < vecChanInfo.Size(); j++ )
{
2009-05-08 23:14:33 +02:00
// check if current fader is used
2006-12-09 19:37:40 +01:00
if ( vecChanInfo[j].iChanID == i )
{
// check if fader was already in use -> preserve gain value
if ( !vecpChanFader[i]->IsVisible() )
{
vecpChanFader[i]->Reset();
2006-12-09 19:37:40 +01:00
// show fader
vecpChanFader[i]->Show();
}
2009-05-08 23:14:33 +02:00
else
{
// by definition disable all Solo switches if the number of
// channels at the server has changed
vecpChanFader[i]->SetOtherSoloState ( false );
vecpChanFader[i]->ResetSoloState();
}
2006-12-09 19:37:40 +01:00
// update text
vecpChanFader[i]->SetText ( GenFaderText ( vecChanInfo[j] ) );
bFaderIsUsed = true;
}
}
// if current fader is not used, hide it
if ( !bFaderIsUsed )
{
vecpChanFader[i]->Hide();
}
}
2006-12-09 16:00:24 +01:00
}
2009-05-08 23:14:33 +02:00
void CAudioMixerBoard::OnChSoloStateChanged ( const int iChannelIdx, const int iValue )
{
// if channel iChannelIdx has just activated the solo switch, mute all
// other channels, else enable them again
const bool bSetOtherSoloState =
( static_cast<Qt::CheckState> ( iValue ) == Qt::Checked );
// apply "other solo state" for all other channels
for ( int i = 0; i < USED_NUM_CHANNELS; i++ )
{
if ( i != iChannelIdx )
{
// check if fader is in use
if ( vecpChanFader[i]->IsVisible() )
{
vecpChanFader[i]->SetOtherSoloState ( bSetOtherSoloState );
}
}
}
}
2008-01-22 22:15:04 +01:00
QString CAudioMixerBoard::GenFaderText ( CChannelShortInfo& ChanInfo )
2006-12-09 19:37:40 +01:00
{
// if text is empty, show IP address instead
2008-01-22 22:15:04 +01:00
if ( ChanInfo.strName.isEmpty() )
2006-12-09 19:37:40 +01:00
{
// convert IP address to text and show it (use dummy port number
// since it is not used here)
const CHostAddress TempAddr =
CHostAddress ( QHostAddress ( ChanInfo.iIpAddr ), 0 );
return TempAddr.GetIpAddressStringNoLastByte();
2006-12-09 19:37:40 +01:00
}
else
{
// show name of channel
return ChanInfo.strName;
}
2006-12-09 16:00:24 +01:00
}