From f287a1041db102f8b88d406eb3afce21110a8c30 Mon Sep 17 00:00:00 2001 From: WarmUpTill Date: Sat, 22 Jan 2022 18:52:30 +0100 Subject: [PATCH] Add option to also check for configured volume level --- data/locale/en-US.ini | 5 +- src/headers/macro-condition-audio.hpp | 27 +++- src/macro-condition-audio.cpp | 220 ++++++++++++++++++++++---- 3 files changed, 222 insertions(+), 30 deletions(-) diff --git a/data/locale/en-US.ini b/data/locale/en-US.ini index c8a44aaf..d558c2f6 100644 --- a/data/locale/en-US.ini +++ b/data/locale/en-US.ini @@ -89,10 +89,13 @@ AdvSceneSwitcher.logic.not="If not" ; Macro Conditions AdvSceneSwitcher.condition.audio="Audio" AdvSceneSwitcher.condition.audio.state.below="below" +AdvSceneSwitcher.condition.audio.state.exact="exactly" AdvSceneSwitcher.condition.audio.state.above="above" AdvSceneSwitcher.condition.audio.state.mute="muted" AdvSceneSwitcher.condition.audio.state.unmute="unmuted" -AdvSceneSwitcher.condition.audio.entry="Volume of {{audioSources}} is {{condition}} {{volume}}" +AdvSceneSwitcher.condition.audio.type.output="Output volume" +AdvSceneSwitcher.condition.audio.type.volume="Configured volume level" +AdvSceneSwitcher.condition.audio.entry="{{checkType}} of {{audioSources}} is {{condition}} {{volume}}" AdvSceneSwitcher.condition.cursor="Cursor" AdvSceneSwitcher.condition.cursor.type.region="is in region" AdvSceneSwitcher.condition.cursor.type.moving="is moving" diff --git a/src/headers/macro-condition-audio.hpp b/src/headers/macro-condition-audio.hpp index c28d9122..48e66172 100644 --- a/src/headers/macro-condition-audio.hpp +++ b/src/headers/macro-condition-audio.hpp @@ -6,9 +6,23 @@ #include #include -enum class AudioCondition { +enum class AudioConditionCheckType { + OUTPUT_VOLUME, + CONFIGURED_VOLUME, +}; + +enum class AudioOutputCondition { ABOVE, BELOW, + // TODO: To be removed + MUTE, + UNMUTE, +}; + +enum class AudioVolumeCondition { + ABOVE, + EXACT, + BELOW, MUTE, UNMUTE, }; @@ -34,10 +48,16 @@ public: OBSWeakSource _audioSource; int _volume = 0; - AudioCondition _condition = AudioCondition::ABOVE; + AudioConditionCheckType _checkType = + AudioConditionCheckType::OUTPUT_VOLUME; + AudioOutputCondition _outputCondition = AudioOutputCondition::ABOVE; + AudioVolumeCondition _volumeCondition = AudioVolumeCondition::ABOVE; obs_volmeter_t *_volmeter = nullptr; private: + bool CheckOutputCondition(); + bool CheckVolumeCondition(); + float _peak = -std::numeric_limits::infinity(); static bool _registered; static const std::string id; @@ -64,10 +84,13 @@ private slots: void SourceChanged(const QString &text); void VolumeThresholdChanged(int vol); void ConditionChanged(int cond); + void CheckTypeChanged(int cond); + signals: void HeaderInfoChanged(const QString &); protected: + QComboBox *_checkTypes; QComboBox *_audioSources; QComboBox *_condition; QSpinBox *_volume; diff --git a/src/macro-condition-audio.cpp b/src/macro-condition-audio.cpp index f1df7c1c..effbae80 100644 --- a/src/macro-condition-audio.cpp +++ b/src/macro-condition-audio.cpp @@ -10,11 +10,23 @@ bool MacroConditionAudio::_registered = MacroConditionFactory::Register( {MacroConditionAudio::Create, MacroConditionAudioEdit::Create, "AdvSceneSwitcher.condition.audio"}); -static std::map audioConditionTypes = { - {AudioCondition::ABOVE, "AdvSceneSwitcher.condition.audio.state.above"}, - {AudioCondition::BELOW, "AdvSceneSwitcher.condition.audio.state.below"}, - {AudioCondition::MUTE, "AdvSceneSwitcher.condition.audio.state.mute"}, - {AudioCondition::UNMUTE, +static std::map audioOutputConditionTypes = { + {AudioOutputCondition::ABOVE, + "AdvSceneSwitcher.condition.audio.state.above"}, + {AudioOutputCondition::BELOW, + "AdvSceneSwitcher.condition.audio.state.below"}, +}; + +static std::map audioVolumeConditionTypes = { + {AudioVolumeCondition::ABOVE, + "AdvSceneSwitcher.condition.audio.state.above"}, + {AudioVolumeCondition::EXACT, + "AdvSceneSwitcher.condition.audio.state.exact"}, + {AudioVolumeCondition::BELOW, + "AdvSceneSwitcher.condition.audio.state.below"}, + {AudioVolumeCondition::MUTE, + "AdvSceneSwitcher.condition.audio.state.mute"}, + {AudioVolumeCondition::UNMUTE, "AdvSceneSwitcher.condition.audio.state.unmute"}, }; @@ -24,43 +36,85 @@ MacroConditionAudio::~MacroConditionAudio() obs_volmeter_destroy(_volmeter); } -bool MacroConditionAudio::CheckCondition() +bool MacroConditionAudio::CheckOutputCondition() { bool ret = false; auto s = obs_weak_source_get_source(_audioSource); - switch (_condition) { - case AudioCondition::ABOVE: + + switch (_outputCondition) { + case AudioOutputCondition::ABOVE: // peak will have a value from -60 db to 0 db ret = ((double)_peak + 60) * 1.7 > _volume; break; - case AudioCondition::BELOW: + case AudioOutputCondition::BELOW: // peak will have a value from -60 db to 0 db ret = ((double)_peak + 60) * 1.7 < _volume; break; - case AudioCondition::MUTE: - ret = obs_source_muted(s); - break; - case AudioCondition::UNMUTE: - ret = !obs_source_muted(s); - break; default: break; } // Reset for next check _peak = -std::numeric_limits::infinity(); + obs_source_release(s); + + return ret; +} + +bool MacroConditionAudio::CheckVolumeCondition() +{ + + bool ret = false; + auto s = obs_weak_source_get_source(_audioSource); + + switch (_volumeCondition) { + case AudioVolumeCondition::ABOVE: + ret = obs_source_get_volume(s) > _volume / 100.f; + break; + case AudioVolumeCondition::EXACT: + ret = obs_source_get_volume(s) == _volume / 100.f; + break; + case AudioVolumeCondition::BELOW: + ret = obs_source_get_volume(s) < _volume / 100.f; + break; + case AudioVolumeCondition::MUTE: + ret = obs_source_muted(s); + break; + case AudioVolumeCondition::UNMUTE: + ret = !obs_source_muted(s); + break; + default: + break; + } obs_source_release(s); return ret; } +bool MacroConditionAudio::CheckCondition() +{ + switch (_checkType) { + case AudioConditionCheckType::OUTPUT_VOLUME: + return CheckOutputCondition(); + case AudioConditionCheckType::CONFIGURED_VOLUME: + return CheckVolumeCondition(); + default: + break; + } + return false; +} + bool MacroConditionAudio::Save(obs_data_t *obj) { MacroCondition::Save(obj); obs_data_set_string(obj, "audioSource", GetWeakSourceName(_audioSource).c_str()); obs_data_set_int(obj, "volume", _volume); - obs_data_set_int(obj, "condition", static_cast(_condition)); + obs_data_set_int(obj, "checkType", static_cast(_checkType)); + obs_data_set_int(obj, "outputCondition", + static_cast(_outputCondition)); + obs_data_set_int(obj, "volumeCondition", + static_cast(_volumeCondition)); return true; } @@ -81,14 +135,66 @@ obs_volmeter_t *AddVolmeterToSource(MacroConditionAudio *entry, return volmeter; } +// TODO: Remove in future version +static void convertOldSettingsFormat(obs_data_t *obj) +{ + auto oldCond = static_cast( + obs_data_get_int(obj, "condition")); + switch (oldCond) { + case AudioOutputCondition::ABOVE: + obs_data_set_int( + obj, "checkType", + static_cast( + AudioConditionCheckType::OUTPUT_VOLUME)); + obs_data_set_int(obj, "outputCondition", + static_cast(AudioOutputCondition::ABOVE)); + break; + case AudioOutputCondition::BELOW: + obs_data_set_int( + obj, "checkType", + static_cast( + AudioConditionCheckType::OUTPUT_VOLUME)); + obs_data_set_int(obj, "outputCondition", + static_cast(AudioOutputCondition::BELOW)); + break; + case AudioOutputCondition::MUTE: + obs_data_set_int( + obj, "checkType", + static_cast( + AudioConditionCheckType::CONFIGURED_VOLUME)); + obs_data_set_int(obj, "volumeCondition", + static_cast(AudioVolumeCondition::MUTE)); + break; + case AudioOutputCondition::UNMUTE: + obs_data_set_int( + obj, "checkType", + static_cast( + AudioConditionCheckType::CONFIGURED_VOLUME)); + obs_data_set_int( + obj, "volumeCondition", + static_cast(AudioVolumeCondition::UNMUTE)); + break; + default: + break; + } +} + bool MacroConditionAudio::Load(obs_data_t *obj) { + if (!obs_data_has_user_value(obj, "checkType")) { + convertOldSettingsFormat(obj); + } + MacroCondition::Load(obj); const char *audioSourceName = obs_data_get_string(obj, "audioSource"); _audioSource = GetWeakSourceByName(audioSourceName); _volume = obs_data_get_int(obj, "volume"); - _condition = - static_cast(obs_data_get_int(obj, "condition")); + _checkType = static_cast( + obs_data_get_int(obj, "checkType")); + _outputCondition = static_cast( + obs_data_get_int(obj, "outputCondition")); + _volumeCondition = static_cast( + obs_data_get_int(obj, "volumeCondition")); _volmeter = AddVolmeterToSource(this, _audioSource); return true; } @@ -122,9 +228,26 @@ void MacroConditionAudio::ResetVolmeter() _volmeter = AddVolmeterToSource(this, _audioSource); } -static inline void populateConditionSelection(QComboBox *list) +static inline void populateCheckTypes(QComboBox *list) { - for (auto entry : audioConditionTypes) { + list->addItem(obs_module_text( + "AdvSceneSwitcher.condition.audio.type.output")); + list->addItem(obs_module_text( + "AdvSceneSwitcher.condition.audio.type.volume")); +} + +static inline void populateOutputConditionSelection(QComboBox *list) +{ + list->clear(); + for (auto entry : audioOutputConditionTypes) { + list->addItem(obs_module_text(entry.second.c_str())); + } +} + +static inline void populateVolumeConditionSelection(QComboBox *list) +{ + list->clear(); + for (auto entry : audioVolumeConditionTypes) { list->addItem(obs_module_text(entry.second.c_str())); } } @@ -133,6 +256,7 @@ MacroConditionAudioEdit::MacroConditionAudioEdit( QWidget *parent, std::shared_ptr entryData) : QWidget(parent) { + _checkTypes = new QComboBox(); _audioSources = new QComboBox(); _condition = new QComboBox(); _volume = new QSpinBox(); @@ -141,6 +265,8 @@ MacroConditionAudioEdit::MacroConditionAudioEdit( _volume->setMaximum(100); _volume->setMinimum(0); + QWidget::connect(_checkTypes, SIGNAL(currentIndexChanged(int)), this, + SLOT(CheckTypeChanged(int))); QWidget::connect(_volume, SIGNAL(valueChanged(int)), this, SLOT(VolumeThresholdChanged(int))); QWidget::connect(_condition, SIGNAL(currentIndexChanged(int)), this, @@ -149,11 +275,12 @@ MacroConditionAudioEdit::MacroConditionAudioEdit( SIGNAL(currentTextChanged(const QString &)), this, SLOT(SourceChanged(const QString &))); + populateCheckTypes(_checkTypes); populateAudioSelection(_audioSources); - populateConditionSelection(_condition); QHBoxLayout *switchLayout = new QHBoxLayout; std::unordered_map widgetPlaceholders = { + {"{{checkType}}", _checkTypes}, {"{{audioSources}}", _audioSources}, {"{{volume}}", _volume}, {"{{condition}}", _condition}, @@ -224,7 +351,31 @@ void MacroConditionAudioEdit::ConditionChanged(int cond) } std::lock_guard lock(switcher->m); - _entryData->_condition = static_cast(cond); + if (_entryData->_checkType == AudioConditionCheckType::OUTPUT_VOLUME) { + _entryData->_outputCondition = + static_cast(cond); + } else { + _entryData->_volumeCondition = + static_cast(cond); + } + SetWidgetVisibility(); +} + +void MacroConditionAudioEdit::CheckTypeChanged(int cond) +{ + if (_loading || !_entryData) { + return; + } + + std::lock_guard lock(switcher->m); + _entryData->_checkType = static_cast(cond); + + const QSignalBlocker b(_condition); + if (_entryData->_checkType == AudioConditionCheckType::OUTPUT_VOLUME) { + populateOutputConditionSelection(_condition); + } else { + populateVolumeConditionSelection(_condition); + } SetWidgetVisibility(); } @@ -237,7 +388,16 @@ void MacroConditionAudioEdit::UpdateEntryData() _audioSources->setCurrentText( GetWeakSourceName(_entryData->_audioSource).c_str()); _volume->setValue(_entryData->_volume); - _condition->setCurrentIndex(static_cast(_entryData->_condition)); + _checkTypes->setCurrentIndex(static_cast(_entryData->_checkType)); + if (_entryData->_checkType == AudioConditionCheckType::OUTPUT_VOLUME) { + populateOutputConditionSelection(_condition); + _condition->setCurrentIndex( + static_cast(_entryData->_outputCondition)); + } else { + populateVolumeConditionSelection(_condition); + _condition->setCurrentIndex( + static_cast(_entryData->_volumeCondition)); + } UpdateVolmeterSource(); SetWidgetVisibility(); } @@ -248,9 +408,15 @@ void MacroConditionAudioEdit::SetWidgetVisibility() return; } - _volume->setVisible(_entryData->_condition == AudioCondition::ABOVE || - _entryData->_condition == AudioCondition::BELOW); - _volMeter->setVisible(_entryData->_condition == AudioCondition::ABOVE || - _entryData->_condition == AudioCondition::BELOW); + _volume->setVisible( + _entryData->_checkType == + AudioConditionCheckType::OUTPUT_VOLUME || + (_entryData->_checkType == + AudioConditionCheckType::CONFIGURED_VOLUME && + (_entryData->_volumeCondition == AudioVolumeCondition::ABOVE || + _entryData->_volumeCondition == AudioVolumeCondition::EXACT || + _entryData->_volumeCondition == AudioVolumeCondition::BELOW))); + _volMeter->setVisible(_entryData->_checkType == + AudioConditionCheckType::OUTPUT_VOLUME); adjustSize(); }