diff --git a/data/locale/en-US.ini b/data/locale/en-US.ini index 11e09518..d609f9c2 100644 --- a/data/locale/en-US.ini +++ b/data/locale/en-US.ini @@ -327,8 +327,10 @@ AdvSceneSwitcher.action.audio.type.sourceVolume="Set source volume" AdvSceneSwitcher.action.audio.type.masterVolume="Set master volume" AdvSceneSwitcher.action.audio.fade.type.duration="over a duration of" AdvSceneSwitcher.action.audio.fade.type.rate="at a rate of" -AdvSceneSwitcher.action.audio.fade.duration="{{fade}}Fade {{fadeTypes}} {{duration}} seconds. {{wait}} Wait for fade to complete." -AdvSceneSwitcher.action.audio.fade.rate="{{fade}}Fade {{fadeTypes}} {{rate}}per second. {{wait}} Wait for fade to complete." +AdvSceneSwitcher.action.audio.fade.duration="{{fade}}Fade {{fadeTypes}} {{duration}} seconds." +AdvSceneSwitcher.action.audio.fade.rate="{{fade}}Fade {{fadeTypes}} {{rate}}per second." +AdvSceneSwitcher.action.audio.fade.wait="Wait for fade to complete." +AdvSceneSwitcher.action.audio.fade.abort="Abort already active fade." AdvSceneSwitcher.action.audio.entry="{{actions}} {{audioSources}} {{volume}}" AdvSceneSwitcher.action.recording="Recording" AdvSceneSwitcher.action.recording.type.stop="Stop recording" diff --git a/src/headers/macro-action-audio.hpp b/src/headers/macro-action-audio.hpp index 4ac7b1b6..fe59a713 100644 --- a/src/headers/macro-action-audio.hpp +++ b/src/headers/macro-action-audio.hpp @@ -41,6 +41,7 @@ public: Duration _duration; double _rate = 100.; bool _wait = false; + bool _abortActiveFade = false; private: void StartFade(); @@ -49,6 +50,7 @@ private: float GetVolume(); void SetFadeActive(bool value); bool FadeActive(); + std::atomic_int *GetFadeIdPtr(); static bool _registered; static const std::string id; @@ -61,7 +63,6 @@ public: MacroActionAudioEdit( QWidget *parent, std::shared_ptr entryData = nullptr); - void SetWidgetVisibility(); void UpdateEntryData(); static QWidget *Create(QWidget *parent, std::shared_ptr action) @@ -79,6 +80,7 @@ private slots: void DurationChanged(double seconds); void RateChanged(double value); void WaitChanged(int value); + void AbortActiveFadeChanged(int value); void FadeTypeChanged(int value); signals: void HeaderInfoChanged(const QString &); @@ -92,9 +94,13 @@ protected: DurationSelection *_duration; QDoubleSpinBox *_rate; QCheckBox *_wait; - QHBoxLayout *_fadeLayout; + QCheckBox *_abortActiveFade; + QHBoxLayout *_fadeTypeLayout; + QVBoxLayout *_fadeOptionsLayout; std::shared_ptr _entryData; private: + void SetWidgetVisibility(); + bool _loading = true; }; diff --git a/src/headers/switcher-data-structs.hpp b/src/headers/switcher-data-structs.hpp index 859ae012..a67db717 100644 --- a/src/headers/switcher-data-structs.hpp +++ b/src/headers/switcher-data-structs.hpp @@ -113,6 +113,7 @@ struct SwitcherData { struct AudioFadeInfo { std::atomic_bool active = {false}; + std::atomic_int id = {0}; }; AudioFadeInfo masterAudioFade; std::unordered_map activeAudioFades; diff --git a/src/macro-action-audio.cpp b/src/macro-action-audio.cpp index c6308f83..16b7ec10 100644 --- a/src/macro-action-audio.cpp +++ b/src/macro-action-audio.cpp @@ -54,6 +54,20 @@ bool MacroActionAudio::FadeActive() return active; } +std::atomic_int *MacroActionAudio::GetFadeIdPtr() +{ + + if (_action == AudioAction::SOURCE_VOLUME) { + auto it = switcher->activeAudioFades.find( + GetWeakSourceName(_audioSource)); + if (it == switcher->activeAudioFades.end()) { + return nullptr; + } + return &it->second.id; + } + return &switcher->masterAudioFade.id; +} + void MacroActionAudio::SetVolume(float vol) { if (_action == AudioAction::SOURCE_VOLUME) { @@ -105,7 +119,10 @@ void MacroActionAudio::FadeVolume() auto macro = GetMacro(); int step = 0; - for (; step < nrSteps && !macro->GetStop(); ++step) { + auto fadeId = GetFadeIdPtr(); + int expectedFadeId = ++(*fadeId); + for (; step < nrSteps && !macro->GetStop() && expectedFadeId == *fadeId; + ++step) { curVol = (volIncrease) ? curVol + volStep : curVol - volStep; SetVolume(curVol); std::this_thread::sleep_for(fadeInterval); @@ -126,7 +143,7 @@ void MacroActionAudio::StartFade() return; } - if (FadeActive()) { + if (FadeActive() && !_abortActiveFade) { blog(LOG_WARNING, "Audio fade for volume of %s already active! New fade request will be ignored!", (_action == AudioAction::SOURCE_VOLUME) @@ -196,6 +213,7 @@ bool MacroActionAudio::Save(obs_data_t *obj) obs_data_set_bool(obj, "fade", _fade); obs_data_set_int(obj, "fadeType", static_cast(_fadeType)); obs_data_set_bool(obj, "wait", _wait); + obs_data_set_bool(obj, "abortActiveFade", _abortActiveFade); return true; } @@ -220,6 +238,11 @@ bool MacroActionAudio::Load(obs_data_t *obj) } else { _fadeType = FadeType::DURATION; } + if (obs_data_has_user_value(obj, "abortActiveFade")) { + _abortActiveFade = obs_data_get_bool(obj, "abortActiveFade"); + } else { + _abortActiveFade = false; + } return true; } @@ -252,10 +275,15 @@ MacroActionAudioEdit::MacroActionAudioEdit( _actions(new QComboBox), _volumePercent(new QSpinBox), _fade(new QCheckBox), - _wait(new QCheckBox), + _wait(new QCheckBox( + obs_module_text("AdvSceneSwitcher.action.audio.fade.wait"))), + _abortActiveFade(new QCheckBox( + obs_module_text("AdvSceneSwitcher.action.audio.fade.abort"))), _duration(new DurationSelection(parent, false)), _rate(new QDoubleSpinBox), - _fadeTypes(new QComboBox) + _fadeTypes(new QComboBox), + _fadeTypeLayout(new QHBoxLayout), + _fadeOptionsLayout(new QVBoxLayout) { _volumePercent->setMinimum(0); _volumePercent->setMaximum(2000); @@ -284,6 +312,8 @@ MacroActionAudioEdit::MacroActionAudioEdit( SLOT(RateChanged(double))); QWidget::connect(_wait, SIGNAL(stateChanged(int)), this, SLOT(WaitChanged(int))); + QWidget::connect(_abortActiveFade, SIGNAL(stateChanged(int)), this, + SLOT(AbortActiveFadeChanged(int))); QWidget::connect(_fadeTypes, SIGNAL(currentIndexChanged(int)), this, SLOT(FadeTypeChanged(int))); @@ -295,18 +325,24 @@ MacroActionAudioEdit::MacroActionAudioEdit( {"{{duration}}", _duration}, {"{{rate}}", _rate}, {"{{wait}}", _wait}, + {"{{abortActiveFade}}", _abortActiveFade}, {"{{fadeTypes}}", _fadeTypes}, }; QHBoxLayout *entryLayout = new QHBoxLayout; placeWidgets(obs_module_text("AdvSceneSwitcher.action.audio.entry"), entryLayout, widgetPlaceholders); - _fadeLayout = new QHBoxLayout; + _fadeTypeLayout = new QHBoxLayout; placeWidgets( obs_module_text("AdvSceneSwitcher.action.audio.fade.duration"), - _fadeLayout, widgetPlaceholders); + _fadeTypeLayout, widgetPlaceholders); + + _fadeOptionsLayout->addLayout(_fadeTypeLayout); + _fadeOptionsLayout->addWidget(_abortActiveFade); + _fadeOptionsLayout->addWidget(_wait); + QVBoxLayout *mainLayout = new QVBoxLayout; mainLayout->addLayout(entryLayout); - mainLayout->addLayout(_fadeLayout); + mainLayout->addLayout(_fadeOptionsLayout); setLayout(mainLayout); _entryData = entryData; @@ -330,32 +366,41 @@ void MacroActionAudioEdit::SetWidgetVisibility() _volumePercent->setVisible(hasVolumeControl(_entryData->_action)); _audioSources->setVisible(hasSourceControl(_entryData->_action)); - _fadeLayout->removeWidget(_fade); - _fadeLayout->removeWidget(_fadeTypes); - _fadeLayout->removeWidget(_duration); - _fadeLayout->removeWidget(_rate); - _fadeLayout->removeWidget(_wait); - clearLayout(_fadeLayout); + _fadeTypes->setDisabled(!_entryData->_fade); + _wait->setDisabled(!_entryData->_fade); + _abortActiveFade->setDisabled(!_entryData->_fade); + _duration->setDisabled(!_entryData->_fade); + _rate->setDisabled(!_entryData->_fade); + + _fadeTypeLayout->removeWidget(_fade); + _fadeTypeLayout->removeWidget(_fadeTypes); + _fadeTypeLayout->removeWidget(_duration); + _fadeTypeLayout->removeWidget(_rate); + clearLayout(_fadeTypeLayout); std::unordered_map widgetPlaceholders = { - {"{{fade}}", _fade}, {"{{duration}}", _duration}, - {"{{rate}}", _rate}, {"{{wait}}", _wait}, + {"{{fade}}", _fade}, + {"{{duration}}", _duration}, + {"{{rate}}", _rate}, {"{{fadeTypes}}", _fadeTypes}, }; if (_entryData->_fadeType == FadeType::DURATION) { placeWidgets( obs_module_text( "AdvSceneSwitcher.action.audio.fade.duration"), - _fadeLayout, widgetPlaceholders); + _fadeTypeLayout, widgetPlaceholders); } else { placeWidgets(obs_module_text( "AdvSceneSwitcher.action.audio.fade.rate"), - _fadeLayout, widgetPlaceholders); + _fadeTypeLayout, widgetPlaceholders); } _duration->setVisible(_entryData->_fadeType == FadeType::DURATION); _rate->setVisible(_entryData->_fadeType == FadeType::RATE); - setLayoutVisible(_fadeLayout, hasVolumeControl(_entryData->_action)); + setLayoutVisible(_fadeTypeLayout, + hasVolumeControl(_entryData->_action)); + setLayoutVisible(_fadeOptionsLayout, + hasVolumeControl(_entryData->_action)); adjustSize(); } @@ -373,6 +418,7 @@ void MacroActionAudioEdit::UpdateEntryData() _duration->SetDuration(_entryData->_duration); _rate->setValue(_entryData->_rate); _wait->setChecked(_entryData->_wait); + _abortActiveFade->setChecked(_entryData->_abortActiveFade); _fadeTypes->setCurrentIndex(static_cast(_entryData->_fadeType)); SetWidgetVisibility(); } @@ -418,6 +464,7 @@ void MacroActionAudioEdit::FadeChanged(int value) std::lock_guard lock(switcher->m); _entryData->_fade = value; + SetWidgetVisibility(); } void MacroActionAudioEdit::DurationChanged(double seconds) @@ -450,6 +497,16 @@ void MacroActionAudioEdit::WaitChanged(int value) _entryData->_wait = value; } +void MacroActionAudioEdit::AbortActiveFadeChanged(int value) +{ + if (_loading || !_entryData) { + return; + } + + std::lock_guard lock(switcher->m); + _entryData->_abortActiveFade = value; +} + void MacroActionAudioEdit::FadeTypeChanged(int value) { if (_loading || !_entryData) {