diff --git a/data/locale/de-DE.ini b/data/locale/de-DE.ini index f945907a..04a4a8ca 100644 --- a/data/locale/de-DE.ini +++ b/data/locale/de-DE.ini @@ -186,6 +186,8 @@ AdvSceneSwitcher.audioTab.title="Audio" AdvSceneSwitcher.audioTab.condition.above="über" AdvSceneSwitcher.audioTab.condition.below="unter" AdvSceneSwitcher.audioTab.entry="Wenn die Lautstärke von {{audioSources}} {{condition}} {{volumeWidget}} ist für {{duration}} wechsle zu {{scenes}} mit {{transitions}}" +AdvSceneSwitcher.audioTab.multiMatchfallbackCondition="Wenn mehrere Einträge zutreffen ..." +AdvSceneSwitcher.audioTab.multiMatchfallback="... für {{duration}} wechsle zu {{scenes}} mit {{transitions}}" ; Hotkey AdvSceneSwitcher.hotkey.startSwitcherHotkey="Starte den Erweiteren Szenenwechsler" diff --git a/data/locale/en-US.ini b/data/locale/en-US.ini index 3c4cd5a2..cfce04c7 100644 --- a/data/locale/en-US.ini +++ b/data/locale/en-US.ini @@ -186,6 +186,8 @@ AdvSceneSwitcher.audioTab.title="Audio" AdvSceneSwitcher.audioTab.condition.above="above" AdvSceneSwitcher.audioTab.condition.below="below" AdvSceneSwitcher.audioTab.entry="When the volume of {{audioSources}} is {{condition}} {{volumeWidget}} for {{duration}} switch to {{scenes}} using {{transitions}}" +AdvSceneSwitcher.audioTab.multiMatchfallbackCondition="If multiple entries match ..." +AdvSceneSwitcher.audioTab.multiMatchfallback="... for {{duration}} switch to {{scenes}} using {{transitions}}" ; Hotkey AdvSceneSwitcher.hotkey.startSwitcherHotkey="Start the Advanced Scene Switcher" diff --git a/forms/advanced-scene-switcher.ui b/forms/advanced-scene-switcher.ui index 420c4714..b5fe4989 100644 --- a/forms/advanced-scene-switcher.ui +++ b/forms/advanced-scene-switcher.ui @@ -2861,151 +2861,178 @@ - - - - 0 - 0 - - - - false + + + + + + + + + 0 + 0 + + + + false + + + + + + + + + + 22 + 22 + + + + true + + + addIconSmall + + + + + + + + 22 + 22 + + + + true + + + removeIconSmall + + + + + + + Qt::Horizontal + + + QSizePolicy::Fixed + + + + 5 + 20 + + + + + + + + Qt::Vertical + + + + + + + Qt::Horizontal + + + QSizePolicy::Fixed + + + + 5 + 20 + + + + + + + + + 22 + 22 + + + + + + + + ../../../forms/images/up.svg../../../forms/images/up.svg + + + true + + + upArrowIconSmall + + + + + + + + 22 + 22 + + + + + + + + ../../../forms/images/down.svg../../../forms/images/down.svg + + + true + + + downArrowIconSmall + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + - - - - - - 22 - 22 - - - - true - - - addIconSmall - - - - - - - - 22 - 22 - - - - true - - - removeIconSmall - - - - - - - Qt::Horizontal - - - QSizePolicy::Fixed - - - - 5 - 20 - - - - - - - - Qt::Vertical - - - - - - - Qt::Horizontal - - - QSizePolicy::Fixed - - - - 5 - 20 - - - - - - - - - 22 - 22 - - - - - - - - ../../../forms/images/up.svg../../../forms/images/up.svg - - - true - - - upArrowIconSmall - - - - - - - - 22 - 22 - - - - - - - - ../../../forms/images/down.svg../../../forms/images/down.svg - - - true - - - downArrowIconSmall - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - + + + AdvSceneSwitcher.audioTab.multiMatchfallbackCondition + + + false + + + true + + + + + + + diff --git a/src/headers/advanced-scene-switcher.hpp b/src/headers/advanced-scene-switcher.hpp index e0a4be8c..1b710cba 100644 --- a/src/headers/advanced-scene-switcher.hpp +++ b/src/headers/advanced-scene-switcher.hpp @@ -184,6 +184,7 @@ public slots: void on_audioRemove_clicked(); void on_audioUp_clicked(); void on_audioDown_clicked(); + void on_audioFallback_toggled(bool on); void on_priorityUp_clicked(); void on_priorityDown_clicked(); diff --git a/src/headers/switch-audio.hpp b/src/headers/switch-audio.hpp index 26d94060..89797dee 100644 --- a/src/headers/switch-audio.hpp +++ b/src/headers/switch-audio.hpp @@ -44,6 +44,13 @@ struct AudioSwitch : virtual SceneSwitcherEntry { friend void swap(AudioSwitch &first, AudioSwitch &second); }; +struct AudioSwitchFallback : virtual SceneSwitcherEntry { + const char *getType() { return "audio_fallback"; } + bool enable = false; + double duration = 0; + unsigned int matchCount = 0; +}; + class AudioSwitchWidget : public SwitchWidget { Q_OBJECT @@ -71,3 +78,18 @@ private: AudioSwitch *switchData; }; + +class AudioSwitchFallbackWidget : public SwitchWidget { + Q_OBJECT + +public: + AudioSwitchFallbackWidget(AudioSwitchFallback *s); + +private slots: + void DurationChanged(double dur); + +private: + QDoubleSpinBox *duration; + + AudioSwitchFallback *switchData; +}; diff --git a/src/headers/switcher-data-structs.hpp b/src/headers/switcher-data-structs.hpp index 6ea4c538..c06281b5 100644 --- a/src/headers/switcher-data-structs.hpp +++ b/src/headers/switcher-data-structs.hpp @@ -111,6 +111,7 @@ struct SwitcherData { QDateTime liveTime; std::deque audioSwitches; + AudioSwitchFallback audioFallback; std::vector functionNamesByPriority = std::vector{ default_priority_0, default_priority_1, default_priority_2, @@ -188,6 +189,8 @@ struct SwitcherData { OBSWeakSource &transition); void checkAudioSwitch(bool &match, OBSWeakSource &scene, OBSWeakSource &transition); + void checkAudioSwitchFallback(OBSWeakSource &scene, + OBSWeakSource &transition); void checkNoMatchSwitch(bool &match, OBSWeakSource &scene, OBSWeakSource &transition, int &sleep); void checkSwitchCooldown(bool &match); diff --git a/src/switch-audio.cpp b/src/switch-audio.cpp index 4529aa6d..98b51220 100644 --- a/src/switch-audio.cpp +++ b/src/switch-audio.cpp @@ -72,12 +72,43 @@ void AdvSceneSwitcher::on_audioDown_clicked() switcher->audioSwitches[index + 1]); } +void AdvSceneSwitcher::on_audioFallback_toggled(bool on) +{ + if (loading || !switcher) + return; + std::lock_guard lock(switcher->m); + switcher->audioFallback.enable = on; +} + +void SwitcherData::checkAudioSwitchFallback(OBSWeakSource &scene, + OBSWeakSource &transition) +{ + bool durationReached = + ((unsigned long long)audioFallback.matchCount * interval) / + 1000.0 >= + audioFallback.duration; + + if (durationReached) { + + scene = (audioFallback.usePreviousScene) ? previousScene + : audioFallback.scene; + transition = audioFallback.transition; + + if (verbose) + audioFallback.logMatch(); + } + + audioFallback.matchCount++; +} + void SwitcherData::checkAudioSwitch(bool &match, OBSWeakSource &scene, OBSWeakSource &transition) { if (AudioSwitch::pause) return; + bool fallbackChecked = false; // false if one or no match + for (AudioSwitch &s : audioSwitches) { if (!s.initialized()) continue; @@ -103,19 +134,56 @@ void SwitcherData::checkAudioSwitch(bool &match, OBSWeakSource &scene, } bool durationReached = - (s.matchCount * (unsigned int)interval) / 1000.0 >= + ((unsigned long long)s.matchCount * interval) / + 1000.0 >= s.duration; if (volumeThresholdreached && durationReached && audioActive) { + if (match) { + checkAudioSwitchFallback(scene, transition); + fallbackChecked = true; + break; + } + scene = (s.usePreviousScene) ? previousScene : s.scene; transition = s.transition; match = true; if (verbose) s.logMatch(); - break; + + if (!audioFallback.enable) + break; } } + + if (!fallbackChecked) + audioFallback.matchCount = 0; +} + +void saveAudioFallback(obs_data_t *obj, AudioSwitchFallback &audioFallback) +{ + obs_source_t *fallbackSceneSource = + obs_weak_source_get_source(audioFallback.scene); + obs_source_t *fallbackTransition = + obs_weak_source_get_source(audioFallback.transition); + + const char *fallbackSceneName = + obs_source_get_name(fallbackSceneSource); + const char *fallbackTransitionName = + obs_source_get_name(fallbackTransition); + + obs_data_set_bool(obj, "audioFallbackEnable", audioFallback.enable); + obs_data_set_string(obj, "audioFallbackScene", + audioFallback.usePreviousScene ? previous_scene_name + : fallbackSceneName); + obs_data_set_string(obj, "audioFallbackTransition", + fallbackTransitionName); + obs_data_set_double(obj, "audioFallbackDuration", + audioFallback.duration); + + obs_source_release(fallbackSceneSource); + obs_source_release(fallbackTransition); } void SwitcherData::saveAudioSwitches(obs_data_t *obj) @@ -159,6 +227,25 @@ void SwitcherData::saveAudioSwitches(obs_data_t *obj) } obs_data_set_array(obj, "audioSwitches", audioArray); obs_data_array_release(audioArray); + + saveAudioFallback(obj, audioFallback); +} + +void loadAudioFallback(obs_data_t *obj, AudioSwitchFallback &audioFallback) +{ + const char *fallbackSceneName = + obs_data_get_string(obj, "audioFallbackScene"); + const char *fallbackTransitionName = + obs_data_get_string(obj, "audioFallbackTransition"); + + audioFallback.enable = obs_data_get_bool(obj, "audioFallbackEnable"); + audioFallback.duration = + obs_data_get_double(obj, "audioFallbackDuration"); + audioFallback.scene = GetWeakSourceByName(fallbackSceneName); + audioFallback.transition = + GetWeakTransitionByName(fallbackTransitionName); + audioFallback.usePreviousScene = + strcmp(fallbackSceneName, previous_scene_name) == 0; } void SwitcherData::loadAudioSwitches(obs_data_t *obj) @@ -190,6 +277,8 @@ void SwitcherData::loadAudioSwitches(obs_data_t *obj) obs_data_release(array_obj); } obs_data_array_release(audioArray); + + loadAudioFallback(obj, audioFallback); } void AdvSceneSwitcher::setupAudioTab() @@ -205,6 +294,11 @@ void AdvSceneSwitcher::setupAudioTab() if (switcher->audioSwitches.size() == 0) addPulse = PulseWidget(ui->audioAdd, QColor(Qt::green)); + + AudioSwitchFallbackWidget *fb = + new AudioSwitchFallbackWidget(&switcher->audioFallback); + ui->audioFallbackLayout->addWidget(fb); + ui->audioFallback->setChecked(switcher->audioFallback.enable); } void AudioSwitch::setVolumeLevel(void *data, @@ -494,3 +588,42 @@ void AudioSwitchWidget::DurationChanged(double dur) std::lock_guard lock(switcher->m); switchData->duration = dur; } + +AudioSwitchFallbackWidget::AudioSwitchFallbackWidget(AudioSwitchFallback *s) + : SwitchWidget(s) +{ + duration = new QDoubleSpinBox(); + + duration->setMinimum(0.0); + duration->setMaximum(99.000000); + duration->setSuffix("s"); + + QWidget::connect(duration, SIGNAL(valueChanged(double)), this, + SLOT(DurationChanged(double))); + + if (s) { + duration->setValue(s->duration); + } + + QHBoxLayout *mainLayout = new QHBoxLayout; + std::unordered_map widgetPlaceholders = { + {"{{scenes}}", scenes}, + {"{{duration}}", duration}, + {"{{transitions}}", transitions}}; + placeWidgets( + obs_module_text("AdvSceneSwitcher.audioTab.multiMatchfallback"), + mainLayout, widgetPlaceholders); + setLayout(mainLayout); + + switchData = s; + + loading = false; +} + +void AudioSwitchFallbackWidget::DurationChanged(double dur) +{ + if (loading || !switchData) + return; + std::lock_guard lock(switcher->m); + switchData->duration = dur; +}