From c3f207f93c66477e08e0adb90cc09e7142189f0b Mon Sep 17 00:00:00 2001 From: WarmUpTill Date: Thu, 15 Feb 2024 19:56:30 +0100 Subject: [PATCH] Add decibel selection to audio condition --- data/locale/de-DE.ini | 2 +- data/locale/en-US.ini | 2 +- data/locale/es-ES.ini | 2 +- data/locale/fr-FR.ini | 2 +- data/locale/zh-CN.ini | 2 +- plugins/base/macro-action-audio.cpp | 11 +- plugins/base/macro-condition-audio.cpp | 201 +++++++++++++++++++------ plugins/base/macro-condition-audio.hpp | 23 ++- plugins/base/utils/audio-helpers.cpp | 11 ++ plugins/base/utils/audio-helpers.hpp | 2 + 10 files changed, 191 insertions(+), 67 deletions(-) diff --git a/data/locale/de-DE.ini b/data/locale/de-DE.ini index d913a81a..7787172b 100644 --- a/data/locale/de-DE.ini +++ b/data/locale/de-DE.ini @@ -122,7 +122,7 @@ AdvSceneSwitcher.condition.audio.type.volume="Konfigurierter Lautstärkepegel" AdvSceneSwitcher.condition.audio.type.syncOffset="Sync-Offset" AdvSceneSwitcher.condition.audio.type.monitor="Audio-Monitoring" AdvSceneSwitcher.condition.audio.type.balance="Audio-Balance" -AdvSceneSwitcher.condition.audio.entry="{{checkType}} von {{audioSources}} ist {{condition}}{{volume}}{{syncOffset}}{{monitorTypes}}" +AdvSceneSwitcher.condition.audio.entry="{{checkType}}von{{audioSources}}ist{{condition}}{{volume}}{{volumeDB}}{{percentDBToggle}}{{syncOffset}}{{monitorTypes}}" AdvSceneSwitcher.condition.cursor="Cursor" AdvSceneSwitcher.condition.cursor.type.region="ist in der Region" AdvSceneSwitcher.condition.cursor.type.moving="bewegt sich" diff --git a/data/locale/en-US.ini b/data/locale/en-US.ini index 383f165c..073c0473 100644 --- a/data/locale/en-US.ini +++ b/data/locale/en-US.ini @@ -198,7 +198,7 @@ AdvSceneSwitcher.condition.audio.type.volume="Configured volume level" AdvSceneSwitcher.condition.audio.type.syncOffset="Sync offset" AdvSceneSwitcher.condition.audio.type.monitor="Audio monitoring" AdvSceneSwitcher.condition.audio.type.balance="Audio balance" -AdvSceneSwitcher.condition.audio.entry="{{checkType}}of{{audioSources}}is{{condition}}{{volume}}{{syncOffset}}{{monitorTypes}}" +AdvSceneSwitcher.condition.audio.entry="{{checkType}}of{{audioSources}}is{{condition}}{{volume}}{{volumeDB}}{{percentDBToggle}}{{syncOffset}}{{monitorTypes}}" AdvSceneSwitcher.condition.cursor="Cursor" AdvSceneSwitcher.condition.cursor.type.region="is in region" AdvSceneSwitcher.condition.cursor.type.moving="is moving" diff --git a/data/locale/es-ES.ini b/data/locale/es-ES.ini index 32e041bd..51a56276 100644 --- a/data/locale/es-ES.ini +++ b/data/locale/es-ES.ini @@ -104,7 +104,7 @@ AdvSceneSwitcher.condition.audio.state.mute="silenciado" AdvSceneSwitcher.condition.audio.state.unmute="no silenciado" AdvSceneSwitcher.condition.audio.type.output="Volumen de salida" AdvSceneSwitcher.condition.audio.type.volume="Nivel de volumen configurado" -AdvSceneSwitcher.condition.audio.entry="{{checkType}} de {{audioSources}} es {{condition}}{{volume}}{{syncOffset}}{{monitorTypes}}" +AdvSceneSwitcher.condition.audio.entry="{{checkType}}de{{audioSources}}es{{condition}}{{volume}}{{volumeDB}}{{percentDBToggle}}{{syncOffset}}{{monitorTypes}}" AdvSceneSwitcher.condition.cursor="Cursor" AdvSceneSwitcher.condition.cursor.type.region="está en la región" AdvSceneSwitcher.condition.cursor.type.moving="se está moviendo" diff --git a/data/locale/fr-FR.ini b/data/locale/fr-FR.ini index 01efc250..a8b15589 100644 --- a/data/locale/fr-FR.ini +++ b/data/locale/fr-FR.ini @@ -155,7 +155,7 @@ AdvSceneSwitcher.condition.audio.type.volume="Niveau de volume configuré" AdvSceneSwitcher.condition.audio.type.syncOffset="Décalage de synchronisation" AdvSceneSwitcher.condition.audio.type.monitor="Surveillance audio" AdvSceneSwitcher.condition.audio.type.balance="Équilibre audio" -AdvSceneSwitcher.condition.audio.entry="{{checkType}}de{{audioSources}}est{{condition}}{{volume}}{{syncOffset}}{{monitorTypes}}" +AdvSceneSwitcher.condition.audio.entry="{{checkType}}de{{audioSources}}est{{condition}}{{volume}}{{volumeDB}}{{percentDBToggle}}{{syncOffset}}{{monitorTypes}}" AdvSceneSwitcher.condition.cursor="Curseur" AdvSceneSwitcher.condition.cursor.type.region="est dans la région" AdvSceneSwitcher.condition.cursor.type.moving="est en mouvement" diff --git a/data/locale/zh-CN.ini b/data/locale/zh-CN.ini index 8ee7cd0d..ff2666f0 100644 --- a/data/locale/zh-CN.ini +++ b/data/locale/zh-CN.ini @@ -140,7 +140,7 @@ AdvSceneSwitcher.condition.audio.type.volume="配置音量级别" AdvSceneSwitcher.condition.audio.type.syncOffset="同步偏移" AdvSceneSwitcher.condition.audio.type.monitor="音频监控" AdvSceneSwitcher.condition.audio.type.balance="音频平衡" -AdvSceneSwitcher.condition.audio.entry="{{checkType}} 的 {{audioSources}} 是 {{condition}}{{volume}}{{syncOffset}}{{monitorTypes}}" +AdvSceneSwitcher.condition.audio.entry="{{checkType}}的{{audioSources}}是{{condition}}{{volume}}{{volumeDB}}{{percentDBToggle}}{{syncOffset}}{{monitorTypes}}" AdvSceneSwitcher.condition.cursor="屏幕区域" AdvSceneSwitcher.condition.cursor.type.region="当前位置" AdvSceneSwitcher.condition.cursor.type.moving="正在移动" diff --git a/plugins/base/macro-action-audio.cpp b/plugins/base/macro-action-audio.cpp index dc40d0ef..6108b34e 100644 --- a/plugins/base/macro-action-audio.cpp +++ b/plugins/base/macro-action-audio.cpp @@ -4,8 +4,6 @@ #include "macro-helpers.hpp" #include "selection-helpers.hpp" -#include - namespace advss { constexpr int64_t nsPerMs = 1000000; @@ -45,7 +43,7 @@ struct FadeInfo { std::atomic_bool active = {false}; std::atomic_int id = {0}; }; -} +} // namespace static FadeInfo masterAudioFade; static std::unordered_map audioFades; @@ -53,11 +51,6 @@ static std::unordered_map audioFades; constexpr auto fadeInterval = std::chrono::milliseconds(100); constexpr float minFade = 0.000001f; -static float decibelToPercent(float db) -{ - return pow(10, (db / 20)); -} - // For backwards compatibility #if LIBOBS_API_VER >= MAKE_SEMANTIC_VERSION(29, 0, 0) static float get_master_volume() @@ -114,7 +107,7 @@ std::atomic_int *MacroActionAudio::GetFadeIdPtr() const float MacroActionAudio::GetVolume() const { - return _useDb ? decibelToPercent(_volumeDB) : (float)_volume / 100.0f; + return _useDb ? DecibelToPercent(_volumeDB) : (float)_volume / 100.0f; } void MacroActionAudio::SetVolume(float vol) const diff --git a/plugins/base/macro-condition-audio.cpp b/plugins/base/macro-condition-audio.cpp index 511321c1..f1bdfd41 100644 --- a/plugins/base/macro-condition-audio.cpp +++ b/plugins/base/macro-condition-audio.cpp @@ -67,15 +67,22 @@ bool MacroConditionAudio::CheckOutputCondition() OBSSourceAutoRelease source = obs_weak_source_get_source(_audioSource.GetSource()); - // peak will have a value from -60 db to 0 db so we need to scale it - double curVolume = ((double)_peak + 60) * 1.7; + double curVolume = _useDb ? _peak : DecibelToPercent(_peak); switch (_outputCondition) { case OutputCondition::ABOVE: - ret = curVolume > _volume; + if (_useDb) { + ret = curVolume > _volumeDB; + } else { + ret = curVolume > _volumePercent; + } break; case OutputCondition::BELOW: - ret = curVolume < _volume; + if (_useDb) { + ret = curVolume < _volumeDB; + } else { + ret = curVolume < _volumePercent; + } break; default: break; @@ -99,20 +106,34 @@ bool MacroConditionAudio::CheckVolumeCondition() OBSSourceAutoRelease source = obs_weak_source_get_source(_audioSource.GetSource()); - float curVolume = obs_source_get_volume(source); + float curVolume = + _useDb ? PercentToDecibel(obs_source_get_volume(source)) + : obs_source_get_volume(source); bool muted = obs_source_muted(source); switch (_volumeCondition) { case VolumeCondition::ABOVE: - ret = curVolume > _volume / 100.f; + if (_useDb) { + ret = curVolume > _volumeDB; + } else { + ret = curVolume > _volumePercent / 100.f; + } SetVariableValue(std::to_string(curVolume)); break; case VolumeCondition::EXACT: - ret = curVolume == _volume / 100.f; + if (_useDb) { + ret = curVolume == _volumeDB; + } else { + ret = curVolume == _volumePercent / 100.f; + } SetVariableValue(std::to_string(curVolume)); break; case VolumeCondition::BELOW: - ret = curVolume < _volume / 100.f; + if (_useDb) { + ret = curVolume < _volumeDB; + } else { + ret = curVolume < _volumePercent / 100.f; + } SetVariableValue(std::to_string(curVolume)); break; case VolumeCondition::MUTE: @@ -222,7 +243,7 @@ bool MacroConditionAudio::Save(obs_data_t *obj) const MacroCondition::Save(obj); _audioSource.Save(obj, "audioSource"); obs_data_set_int(obj, "monitor", _monitorType); - _volume.Save(obj, "volume"); + _volumePercent.Save(obj, "volume"); _syncOffset.Save(obj, "syncOffset"); _balance.Save(obj, "balance"); obs_data_set_int(obj, "checkType", static_cast(_checkType)); @@ -230,7 +251,9 @@ bool MacroConditionAudio::Save(obs_data_t *obj) const static_cast(_outputCondition)); obs_data_set_int(obj, "volumeCondition", static_cast(_volumeCondition)); - obs_data_set_int(obj, "version", 1); + obs_data_set_bool(obj, "useDb", _useDb); + _volumeDB.Save(obj, "volumeDB"); + obs_data_set_int(obj, "version", 2); return true; } @@ -257,11 +280,11 @@ bool MacroConditionAudio::Load(obs_data_t *obj) _monitorType = static_cast( obs_data_get_int(obj, "monitor")); if (!obs_data_has_user_value(obj, "version")) { - _volume = obs_data_get_int(obj, "volume"); + _volumePercent = obs_data_get_int(obj, "volume"); _syncOffset = obs_data_get_int(obj, "syncOffset"); _balance = obs_data_get_double(obj, "balance"); } else { - _volume.Load(obj, "volume"); + _volumePercent.Load(obj, "volume"); _syncOffset.Load(obj, "syncOffset"); _balance.Load(obj, "balance"); } @@ -271,6 +294,13 @@ bool MacroConditionAudio::Load(obs_data_t *obj) _volumeCondition = static_cast( obs_data_get_int(obj, "volumeCondition")); _volmeter = AddVolmeterToSource(this, _audioSource.GetSource()); + if (obs_data_get_int(obj, "version") != 2) { + _useDb = false; + _volumeDB = 0.0; + } else { + _useDb = obs_data_get_bool(obj, "useDb"); + _volumeDB.Load(obj, "volumeDB"); + } return true; } @@ -367,16 +397,16 @@ static inline void populateCheckTypes(QComboBox *list) static inline void populateOutputConditionSelection(QComboBox *list) { list->clear(); - for (auto entry : audioOutputConditionTypes) { - list->addItem(obs_module_text(entry.second.c_str())); + for (const auto &[_, name] : audioOutputConditionTypes) { + list->addItem(obs_module_text(name.c_str())); } } static inline void populateVolumeConditionSelection(QComboBox *list) { list->clear(); - for (auto entry : audioVolumeConditionTypes) { - list->addItem(obs_module_text(entry.second.c_str())); + for (const auto &[_, name] : audioVolumeConditionTypes) { + list->addItem(obs_module_text(name.c_str())); } } @@ -386,14 +416,21 @@ MacroConditionAudioEdit::MacroConditionAudioEdit( _checkTypes(new QComboBox()), _sources(new SourceSelectionWidget(this, QStringList(), true)), _condition(new QComboBox()), - _volume(new VariableSpinBox()), + _volumePercent(new VariableSpinBox()), + _volumeDB(new VariableDoubleSpinBox), + _percentDBToggle(new QPushButton), _syncOffset(new VariableSpinBox()), _monitorTypes(new QComboBox), _balance(new SliderSpinBox(0., 1., "")) { - _volume->setSuffix("%"); - _volume->setMaximum(100); - _volume->setMinimum(0); + _volumePercent->setSuffix("%"); + _volumePercent->setMaximum(100); + _volumePercent->setMinimum(0); + + _volumeDB->setMinimum(-100); + _volumeDB->setMaximum(0); + _volumeDB->setSuffix("dB"); + _volumeDB->specialValueText("-inf"); _syncOffset->setMinimum(-950); _syncOffset->setMaximum(20000); @@ -406,10 +443,9 @@ MacroConditionAudioEdit::MacroConditionAudioEdit( QWidget::connect(_checkTypes, SIGNAL(currentIndexChanged(int)), this, SLOT(CheckTypeChanged(int))); QWidget::connect( - _volume, + _volumePercent, SIGNAL(NumberVariableChanged(const NumberVariable &)), - this, - SLOT(VolumeThresholdChanged(const NumberVariable &))); + this, SLOT(VolumePercentChanged(const NumberVariable &))); QWidget::connect( _syncOffset, SIGNAL(NumberVariableChanged(const NumberVariable &)), @@ -425,6 +461,12 @@ MacroConditionAudioEdit::MacroConditionAudioEdit( QWidget::connect(_sources, SIGNAL(SourceChanged(const SourceSelection &)), this, SLOT(SourceChanged(const SourceSelection &))); + QWidget::connect( + _volumeDB, + SIGNAL(NumberVariableChanged(const NumberVariable &)), + this, SLOT(VolumeDBChanged(const NumberVariable &))); + QWidget::connect(_percentDBToggle, SIGNAL(clicked()), this, + SLOT(PercentDBClicked())); populateCheckTypes(_checkTypes); PopulateMonitorTypeSelection(_monitorTypes); @@ -433,11 +475,13 @@ MacroConditionAudioEdit::MacroConditionAudioEdit( std::unordered_map widgetPlaceholders = { {"{{checkType}}", _checkTypes}, {"{{audioSources}}", _sources}, - {"{{volume}}", _volume}, + {"{{volume}}", _volumePercent}, {"{{syncOffset}}", _syncOffset}, {"{{monitorTypes}}", _monitorTypes}, {"{{balance}}", _balance}, {"{{condition}}", _condition}, + {"{{volumeDB}}", _volumeDB}, + {"{{percentDBToggle}}", _percentDBToggle}, }; PlaceWidgets(obs_module_text("AdvSceneSwitcher.condition.audio.entry"), switchLayout, widgetPlaceholders); @@ -459,16 +503,14 @@ void MacroConditionAudioEdit::UpdateVolmeterSource() _entryData->_audioSource.GetSource()); _volMeter = new VolControl(soruce.Get()); - QLayout *layout = this->layout(); + auto layout = this->layout(); layout->addWidget(_volMeter); - QWidget::connect(_volMeter->GetSlider(), SIGNAL(valueChanged(int)), - _volume, SLOT(SetFixedValue(int))); - QWidget::connect(_volume, SIGNAL(FixedValueChanged(int)), - _volMeter->GetSlider(), SLOT(setValue(int))); + QWidget::connect(_volMeter->GetSlider(), &QSlider::valueChanged, + [=](int) { SyncSliderAndValueSelection(true); }); // Slider will default to 0 so set it manually once - _volMeter->GetSlider()->setValue(_entryData->_volume); + _volMeter->GetSlider()->setValue(_entryData->_volumePercent); } void MacroConditionAudioEdit::SourceChanged(const SourceSelection &source) @@ -488,15 +530,18 @@ void MacroConditionAudioEdit::SourceChanged(const SourceSelection &source) QString::fromStdString(_entryData->GetShortDesc())); } -void MacroConditionAudioEdit::VolumeThresholdChanged( +void MacroConditionAudioEdit::VolumePercentChanged( const NumberVariable &vol) { if (_loading || !_entryData) { return; } + { + auto lock = LockContext(); + _entryData->_volumePercent = vol; + } - auto lock = LockContext(); - _entryData->_volume = vol; + SyncSliderAndValueSelection(false); } void MacroConditionAudioEdit::SyncOffsetChanged(const NumberVariable &value) @@ -529,6 +574,64 @@ void MacroConditionAudioEdit::BalanceChanged(const NumberVariable &value _entryData->_balance = value; } +void MacroConditionAudioEdit::VolumeDBChanged( + const NumberVariable &value) +{ + if (_loading || !_entryData) { + return; + } + { + auto lock = LockContext(); + _entryData->_volumeDB = value; + } + SyncSliderAndValueSelection(false); +} + +void MacroConditionAudioEdit::PercentDBClicked() +{ + if (_loading || !_entryData) { + return; + } + + auto lock = LockContext(); + _entryData->_useDb = !_entryData->_useDb; + SetWidgetVisibility(); +} + +void MacroConditionAudioEdit::SyncSliderAndValueSelection(bool sliderMoved) +{ + if (_loading || !_entryData) { + return; + } + + if (sliderMoved) { + if (_entryData->_useDb) { + _volumeDB->SetFixedValue(PercentToDecibel( + (float)_volMeter->GetSlider()->value() / + 100.0)); + const QSignalBlocker blocker(this); + _volumePercent->SetFixedValue( + _volMeter->GetSlider()->value()); + } else { + _volumePercent->SetFixedValue( + _volMeter->GetSlider()->value()); + const QSignalBlocker blocker(this); + _volumeDB->SetFixedValue(PercentToDecibel( + (float)_volMeter->GetSlider()->value() / + 100.0)); + } + } else { + const QSignalBlocker blocker(this); + if (_entryData->_useDb) { + _volMeter->GetSlider()->setValue( + DecibelToPercent(_entryData->_volumeDB) * 100); + } else { + _volMeter->GetSlider()->setValue( + _entryData->_volumePercent); + } + } +} + void MacroConditionAudioEdit::ConditionChanged(int cond) { if (_loading || !_entryData) { @@ -577,7 +680,8 @@ void MacroConditionAudioEdit::UpdateEntryData() } _sources->SetSource(_entryData->_audioSource); - _volume->SetValue(_entryData->_volume); + _volumePercent->SetValue(_entryData->_volumePercent); + _volumeDB->SetValue(_entryData->_volumeDB); _syncOffset->SetValue(_entryData->_syncOffset); _monitorTypes->setCurrentIndex(_entryData->_monitorType); _balance->SetDoubleValue(_entryData->_balance); @@ -601,23 +705,26 @@ void MacroConditionAudioEdit::UpdateEntryData() SetWidgetVisibility(); } +bool MacroConditionAudioEdit::HasVolumeControl() const +{ + return _entryData->GetType() == + MacroConditionAudio::Type::OUTPUT_VOLUME || + (_entryData->GetType() == + MacroConditionAudio::Type::CONFIGURED_VOLUME && + (_entryData->_volumeCondition == + MacroConditionAudio::VolumeCondition::ABOVE || + _entryData->_volumeCondition == + MacroConditionAudio::VolumeCondition::EXACT || + _entryData->_volumeCondition == + MacroConditionAudio::VolumeCondition::BELOW)); +} + void MacroConditionAudioEdit::SetWidgetVisibility() { if (!_entryData) { return; } - _volume->setVisible( - _entryData->GetType() == - MacroConditionAudio::Type::OUTPUT_VOLUME || - (_entryData->GetType() == - MacroConditionAudio::Type::CONFIGURED_VOLUME && - (_entryData->_volumeCondition == - MacroConditionAudio::VolumeCondition::ABOVE || - _entryData->_volumeCondition == - MacroConditionAudio::VolumeCondition::EXACT || - _entryData->_volumeCondition == - MacroConditionAudio::VolumeCondition::BELOW))); _condition->setVisible( _entryData->GetType() == MacroConditionAudio::Type::OUTPUT_VOLUME || @@ -634,6 +741,10 @@ void MacroConditionAudioEdit::SetWidgetVisibility() MacroConditionAudio::Type::BALANCE); _volMeter->setVisible(_entryData->GetType() == MacroConditionAudio::Type::OUTPUT_VOLUME); + _volumePercent->setVisible(HasVolumeControl() && !_entryData->_useDb); + _volumeDB->setVisible(HasVolumeControl() && _entryData->_useDb); + _percentDBToggle->setText(_entryData->_useDb ? "dB" : "%"); + _percentDBToggle->setVisible(HasVolumeControl()); adjustSize(); } diff --git a/plugins/base/macro-condition-audio.hpp b/plugins/base/macro-condition-audio.hpp index 261b9981..2ffd3b41 100644 --- a/plugins/base/macro-condition-audio.hpp +++ b/plugins/base/macro-condition-audio.hpp @@ -54,7 +54,9 @@ public: }; SourceSelection _audioSource; - NumberVariable _volume = 0; + bool _useDb = false; + NumberVariable _volumePercent = 0; + NumberVariable _volumeDB = 0.0; NumberVariable _syncOffset = 0; obs_monitoring_type _monitorType = OBS_MONITORING_TYPE_NONE; NumberVariable _balance = 0.5; @@ -95,30 +97,35 @@ public: private slots: void SourceChanged(const SourceSelection &); - void VolumeThresholdChanged(const NumberVariable &vol); + void VolumePercentChanged(const NumberVariable &vol); void ConditionChanged(int cond); void CheckTypeChanged(int cond); void SyncOffsetChanged(const NumberVariable &value); void MonitorTypeChanged(int value); void BalanceChanged(const NumberVariable &value); + void VolumeDBChanged(const NumberVariable &value); + void PercentDBClicked(); + void SyncSliderAndValueSelection(bool sliderMoved); signals: void HeaderInfoChanged(const QString &); -protected: +private: + void SetWidgetVisibility(); + bool HasVolumeControl() const; + QComboBox *_checkTypes; SourceSelectionWidget *_sources; QComboBox *_condition; - VariableSpinBox *_volume; + VariableSpinBox *_volumePercent; + VariableDoubleSpinBox *_volumeDB; + QPushButton *_percentDBToggle; VariableSpinBox *_syncOffset; QComboBox *_monitorTypes; SliderSpinBox *_balance; VolControl *_volMeter = nullptr; + std::shared_ptr _entryData; - -private: - void SetWidgetVisibility(); - bool _loading = true; }; diff --git a/plugins/base/utils/audio-helpers.cpp b/plugins/base/utils/audio-helpers.cpp index 9869c53c..4fe3abee 100644 --- a/plugins/base/utils/audio-helpers.cpp +++ b/plugins/base/utils/audio-helpers.cpp @@ -1,6 +1,7 @@ #include "audio-helpers.hpp" #include "obs-module-helper.hpp" +#include #include namespace advss { @@ -13,4 +14,14 @@ void PopulateMonitorTypeSelection(QComboBox *list) list->addItem(obs_module_text("AdvSceneSwitcher.audio.monitor.both")); } +float DecibelToPercent(float db) +{ + return isfinite((double)db) ? powf(10.0f, db / 20.0f) : 0.0f; +} + +float PercentToDecibel(float percent) +{ + return (percent == 0.0f) ? -INFINITY : (20.0f * log10f(percent)); +} + } // namespace advss diff --git a/plugins/base/utils/audio-helpers.hpp b/plugins/base/utils/audio-helpers.hpp index 20684dd9..b32713c2 100644 --- a/plugins/base/utils/audio-helpers.hpp +++ b/plugins/base/utils/audio-helpers.hpp @@ -4,5 +4,7 @@ namespace advss { void PopulateMonitorTypeSelection(QComboBox *list); +float DecibelToPercent(float db); +float PercentToDecibel(float percent); } // namespace advss