add option to allow scene sequence to be interrupted (#93)

This commit is contained in:
WarmUpTill 2021-01-02 14:32:18 +01:00 committed by GitHub
parent 2f0b900745
commit 4e971f59a9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 101 additions and 32 deletions

View File

@ -175,7 +175,9 @@ AdvSceneSwitcher.sceneSequenceTab.loadTitle="Wähle eine Datei aus von der Szene
AdvSceneSwitcher.sceneSequenceTab.loadFail="Laden der Einstellungen ist fehlgeschlagen!"
AdvSceneSwitcher.sceneSequenceTab.loadSuccess="Laden der Einstellungen war erfolgreich!"
AdvSceneSwitcher.sceneSequenceTab.fileType="Text Dateien (*.txt)"
AdvSceneSwitcher.sceneSequenceTab.entry="Wenn {{startScenes}} aktiv ist wechsle zu {{scenes}} nach {{delay}} {{delayUnits}} mit {{transitions}}"
AdvSceneSwitcher.sceneSequenceTab.interruptible="kann unterbrochen werden"
AdvSceneSwitcher.sceneSequenceTab.interruptibleHint="Andere Szenenwechselmethoden können diese Sequenz unterbrechen"
AdvSceneSwitcher.sceneSequenceTab.entry="Wenn {{startScenes}} aktiv ist wechsle zu {{scenes}} nach {{delay}} {{delayUnits}} mit {{transitions}} {{interruptible}}"
; Audio Tab
AdvSceneSwitcher.audioTab.title="Audio"

View File

@ -175,7 +175,9 @@ AdvSceneSwitcher.sceneSequenceTab.loadTitle="Select a file to read Scene Sequenc
AdvSceneSwitcher.sceneSequenceTab.loadFail="Advanced Scene Switcher failed to import settings!"
AdvSceneSwitcher.sceneSequenceTab.loadSuccess="Advanced Scene Switcher settings imported successfully!"
AdvSceneSwitcher.sceneSequenceTab.fileType="Text files (*.txt)"
AdvSceneSwitcher.sceneSequenceTab.entry="When {{startScenes}} is active switch to {{scenes}} after {{delay}} {{delayUnits}} using {{transitions}}"
AdvSceneSwitcher.sceneSequenceTab.interruptible="interruptible"
AdvSceneSwitcher.sceneSequenceTab.interruptibleHint="Other switching methods are allowed to interrupt this scene sequence"
AdvSceneSwitcher.sceneSequenceTab.entry="When {{startScenes}} is active switch to {{scenes}} after {{delay}} {{delayUnits}} using {{transitions}} {{interruptible}}"
; Audio Tab
AdvSceneSwitcher.audioTab.title="Audio"

View File

@ -171,7 +171,7 @@ AdvSceneSwitcher.sceneSequenceTab.loadTitle="从文件加载序列 ..."
AdvSceneSwitcher.sceneSequenceTab.loadFail="导入失败"
AdvSceneSwitcher.sceneSequenceTab.loadSuccess="导入失败成功"
AdvSceneSwitcher.sceneSequenceTab.fileType="文本文件 (*.txt)"
AdvSceneSwitcher.sceneSequenceTab.entry="当场景 {{startScenes}} 被激活 {{delay}} {{delayUnits}}后使用转场特效 {{transitions}} 切换到场景 {{scenes}}"
AdvSceneSwitcher.sceneSequenceTab.entry="当场景 {{startScenes}} 被激活 {{delay}} {{delayUnits}}后使用转场特效 {{transitions}} 切换到场景 {{scenes}} {{interruptible}}"
; Audio Tab
AdvSceneSwitcher.audioTab.title="音频"

View File

@ -15,6 +15,8 @@ struct SceneSequenceSwitch : SceneSwitcherEntry {
OBSWeakSource startScene = nullptr;
double delay = 0;
int delayMultiplier = 1;
bool interruptible = false;
unsigned int matchCount = 0;
const char *getType() { return "sequence"; }
bool initialized();
@ -25,11 +27,13 @@ struct SceneSequenceSwitch : SceneSwitcherEntry {
inline SceneSequenceSwitch(OBSWeakSource startScene_,
OBSWeakSource scene_,
OBSWeakSource transition_, double delay_,
int delayMultiplier_, bool usePreviousScene_)
int delayMultiplier_, bool interruptible_,
bool usePreviousScene_)
: SceneSwitcherEntry(scene_, transition_, usePreviousScene_),
startScene(startScene_),
delay(delay_),
delayMultiplier(delayMultiplier_)
delayMultiplier(delayMultiplier_),
interruptible(interruptible_)
{
}
};
@ -50,11 +54,13 @@ private slots:
void DelayChanged(double delay);
void DelayUnitsChanged(int idx);
void StartSceneChanged(const QString &text);
void InterruptibleChanged(int state);
private:
QDoubleSpinBox *delay;
QComboBox *delayUnits;
QComboBox *startScenes;
QCheckBox *interruptible;
SceneSequenceSwitch *switchData;
};

View File

@ -153,6 +153,59 @@ void AdvSceneSwitcher::on_sceneSequenceLoad_clicked()
close();
}
void matchInterruptible(SwitcherData *switcher, SceneSequenceSwitch &s,
bool &match, OBSWeakSource &scene,
OBSWeakSource &transition)
{
bool durationReached = s.matchCount * (switcher->interval / 1000.0) >=
s.delay;
s.matchCount++;
if (durationReached) {
match = true;
scene = (s.usePreviousScene) ? switcher->previousScene
: s.scene;
transition = s.transition;
s.matchCount = 0;
if (switcher->verbose)
s.logMatch();
}
}
void matchUninterruptible(SwitcherData *switcher, SceneSequenceSwitch &s,
obs_source_t *currentSource,
std::unique_lock<std::mutex> &lock, bool &match,
OBSWeakSource &scene, OBSWeakSource &transition)
{
// scene was already active for the previous cycle so remove this time
int dur = s.delay * 1000 - switcher->interval;
if (dur > 0) {
switcher->waitScene = currentSource;
if (switcher->verbose)
s.logSleep(dur);
switcher->cv.wait_for(lock, std::chrono::milliseconds(dur));
switcher->waitScene = nullptr;
}
obs_source_t *currentSource2 = obs_frontend_get_current_scene();
// only switch if user hasn't changed scene manually
if (currentSource == currentSource2) {
match = true;
scene = (s.usePreviousScene) ? switcher->previousScene
: s.scene;
transition = s.transition;
if (switcher->verbose)
s.logMatch();
} else if (switcher->verbose) {
blog(LOG_INFO, "sequence canceled");
}
obs_source_release(currentSource2);
}
void SwitcherData::checkSceneSequence(bool &match, OBSWeakSource &scene,
OBSWeakSource &transition,
std::unique_lock<std::mutex> &lock)
@ -168,34 +221,20 @@ void SwitcherData::checkSceneSequence(bool &match, OBSWeakSource &scene,
continue;
if (s.startScene == ws) {
int dur = s.delay * 1000 - interval;
if (dur > 0) {
waitScene = currentSource;
if (verbose)
s.logSleep(dur);
cv.wait_for(lock,
std::chrono::milliseconds(dur));
waitScene = nullptr;
}
obs_source_t *currentSource2 =
obs_frontend_get_current_scene();
// only switch if user hasn't changed scene manually
if (currentSource == currentSource2) {
match = true;
scene = (s.usePreviousScene) ? previousScene
: s.scene;
transition = s.transition;
if (verbose)
s.logMatch();
} else if (verbose) {
blog(LOG_INFO, "sequence canceled");
if (s.interruptible) {
matchInterruptible(switcher, s, match, scene,
transition);
} else {
matchUninterruptible(switcher, s, currentSource,
lock, match, scene,
transition);
}
obs_source_release(currentSource2);
break;
if (match)
break;
} else {
s.matchCount = 0;
}
}
obs_source_release(currentSource);
@ -229,6 +268,8 @@ void SwitcherData::saveSceneSequenceSwitches(obs_data_t *obj)
obs_data_set_double(array_obj, "delay", s.delay);
obs_data_set_int(array_obj, "delayMultiplier",
s.delayMultiplier);
obs_data_set_bool(array_obj, "interruptible",
s.interruptible);
obs_data_array_push_back(sceneSequenceArray, array_obj);
}
@ -265,12 +306,14 @@ void SwitcherData::loadSceneSequenceSwitches(obs_data_t *obj)
if (delayMultiplier == 0 ||
(delayMultiplier != 1 && delayMultiplier % 60 != 0))
delayMultiplier = 1;
bool interruptible =
obs_data_get_bool(array_obj, "interruptible");
switcher->sceneSequenceSwitches.emplace_back(
GetWeakSourceByName(scene1),
GetWeakSourceByName(scene2),
GetWeakTransitionByName(transition), delay,
delayMultiplier,
delayMultiplier, interruptible,
(strcmp(scene2, previous_scene_name) == 0));
obs_data_release(array_obj);
@ -321,6 +364,8 @@ SequenceWidget::SequenceWidget(SceneSequenceSwitch *s) : SwitchWidget(s)
delay = new QDoubleSpinBox();
delayUnits = new QComboBox();
startScenes = new QComboBox();
interruptible = new QCheckBox(obs_module_text(
"AdvSceneSwitcher.sceneSequenceTab.interruptible"));
QWidget::connect(delay, SIGNAL(valueChanged(double)), this,
SLOT(DelayChanged(double)));
@ -329,10 +374,14 @@ SequenceWidget::SequenceWidget(SceneSequenceSwitch *s) : SwitchWidget(s)
QWidget::connect(startScenes,
SIGNAL(currentTextChanged(const QString &)), this,
SLOT(StartSceneChanged(const QString &)));
QWidget::connect(interruptible, SIGNAL(stateChanged(int)), this,
SLOT(InterruptibleChanged(int)));
delay->setMaximum(99999.000000);
AdvSceneSwitcher::populateSceneSelection(startScenes, false);
populateDelayUnits(delayUnits);
interruptible->setToolTip(obs_module_text(
"AdvSceneSwitcher.sceneSequenceTab.interruptibleHint"));
if (s) {
switch (s->delayMultiplier) {
@ -350,6 +399,7 @@ SequenceWidget::SequenceWidget(SceneSequenceSwitch *s) : SwitchWidget(s)
}
startScenes->setCurrentText(
GetWeakSourceName(s->startScene).c_str());
interruptible->setChecked(s->interruptible);
}
QHBoxLayout *mainLayout = new QHBoxLayout;
@ -358,7 +408,8 @@ SequenceWidget::SequenceWidget(SceneSequenceSwitch *s) : SwitchWidget(s)
{"{{scenes}}", scenes},
{"{{delay}}", delay},
{"{{delayUnits}}", delayUnits},
{"{{transitions}}", transitions}};
{"{{transitions}}", transitions},
{"{{interruptible}}", interruptible}};
placeWidgets(obs_module_text("AdvSceneSwitcher.sceneSequenceTab.entry"),
mainLayout, widgetPlaceholders);
setLayout(mainLayout);
@ -434,3 +485,11 @@ void SequenceWidget::StartSceneChanged(const QString &text)
std::lock_guard<std::mutex> lock(switcher->m);
switchData->startScene = GetWeakSourceByQString(text);
}
void SequenceWidget::InterruptibleChanged(int state)
{
if (loading || !switchData)
return;
std::lock_guard<std::mutex> lock(switcher->m);
switchData->interruptible = state;
}