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;
+}