Add decibel selection to audio condition

This commit is contained in:
WarmUpTill
2024-02-15 19:56:30 +01:00
committed by WarmUpTill
parent 583b559c78
commit c3f207f93c
10 changed files with 191 additions and 67 deletions

View File

@@ -122,7 +122,7 @@ AdvSceneSwitcher.condition.audio.type.volume="Konfigurierter Lautstärkepegel"
AdvSceneSwitcher.condition.audio.type.syncOffset="Sync-Offset"
AdvSceneSwitcher.condition.audio.type.monitor="Audio-Monitoring"
AdvSceneSwitcher.condition.audio.type.balance="Audio-Balance"
AdvSceneSwitcher.condition.audio.entry="{{checkType}} von {{audioSources}} ist {{condition}}{{volume}}{{syncOffset}}{{monitorTypes}}"
AdvSceneSwitcher.condition.audio.entry="{{checkType}}von{{audioSources}}ist{{condition}}{{volume}}{{volumeDB}}{{percentDBToggle}}{{syncOffset}}{{monitorTypes}}"
AdvSceneSwitcher.condition.cursor="Cursor"
AdvSceneSwitcher.condition.cursor.type.region="ist in der Region"
AdvSceneSwitcher.condition.cursor.type.moving="bewegt sich"

View File

@@ -198,7 +198,7 @@ AdvSceneSwitcher.condition.audio.type.volume="Configured volume level"
AdvSceneSwitcher.condition.audio.type.syncOffset="Sync offset"
AdvSceneSwitcher.condition.audio.type.monitor="Audio monitoring"
AdvSceneSwitcher.condition.audio.type.balance="Audio balance"
AdvSceneSwitcher.condition.audio.entry="{{checkType}}of{{audioSources}}is{{condition}}{{volume}}{{syncOffset}}{{monitorTypes}}"
AdvSceneSwitcher.condition.audio.entry="{{checkType}}of{{audioSources}}is{{condition}}{{volume}}{{volumeDB}}{{percentDBToggle}}{{syncOffset}}{{monitorTypes}}"
AdvSceneSwitcher.condition.cursor="Cursor"
AdvSceneSwitcher.condition.cursor.type.region="is in region"
AdvSceneSwitcher.condition.cursor.type.moving="is moving"

View File

@@ -104,7 +104,7 @@ AdvSceneSwitcher.condition.audio.state.mute="silenciado"
AdvSceneSwitcher.condition.audio.state.unmute="no silenciado"
AdvSceneSwitcher.condition.audio.type.output="Volumen de salida"
AdvSceneSwitcher.condition.audio.type.volume="Nivel de volumen configurado"
AdvSceneSwitcher.condition.audio.entry="{{checkType}} de {{audioSources}} es {{condition}}{{volume}}{{syncOffset}}{{monitorTypes}}"
AdvSceneSwitcher.condition.audio.entry="{{checkType}}de{{audioSources}}es{{condition}}{{volume}}{{volumeDB}}{{percentDBToggle}}{{syncOffset}}{{monitorTypes}}"
AdvSceneSwitcher.condition.cursor="Cursor"
AdvSceneSwitcher.condition.cursor.type.region="está en la región"
AdvSceneSwitcher.condition.cursor.type.moving="se está moviendo"

View File

@@ -155,7 +155,7 @@ AdvSceneSwitcher.condition.audio.type.volume="Niveau de volume configuré"
AdvSceneSwitcher.condition.audio.type.syncOffset="Décalage de synchronisation"
AdvSceneSwitcher.condition.audio.type.monitor="Surveillance audio"
AdvSceneSwitcher.condition.audio.type.balance="Équilibre audio"
AdvSceneSwitcher.condition.audio.entry="{{checkType}}de{{audioSources}}est{{condition}}{{volume}}{{syncOffset}}{{monitorTypes}}"
AdvSceneSwitcher.condition.audio.entry="{{checkType}}de{{audioSources}}est{{condition}}{{volume}}{{volumeDB}}{{percentDBToggle}}{{syncOffset}}{{monitorTypes}}"
AdvSceneSwitcher.condition.cursor="Curseur"
AdvSceneSwitcher.condition.cursor.type.region="est dans la région"
AdvSceneSwitcher.condition.cursor.type.moving="est en mouvement"

View File

@@ -140,7 +140,7 @@ AdvSceneSwitcher.condition.audio.type.volume="配置音量级别"
AdvSceneSwitcher.condition.audio.type.syncOffset="同步偏移"
AdvSceneSwitcher.condition.audio.type.monitor="音频监控"
AdvSceneSwitcher.condition.audio.type.balance="音频平衡"
AdvSceneSwitcher.condition.audio.entry="{{checkType}}{{audioSources}}{{condition}}{{volume}}{{syncOffset}}{{monitorTypes}}"
AdvSceneSwitcher.condition.audio.entry="{{checkType}}{{audioSources}}{{condition}}{{volume}}{{volumeDB}}{{percentDBToggle}}{{syncOffset}}{{monitorTypes}}"
AdvSceneSwitcher.condition.cursor="屏幕区域"
AdvSceneSwitcher.condition.cursor.type.region="当前位置"
AdvSceneSwitcher.condition.cursor.type.moving="正在移动"

View File

@@ -4,8 +4,6 @@
#include "macro-helpers.hpp"
#include "selection-helpers.hpp"
#include <cmath>
namespace advss {
constexpr int64_t nsPerMs = 1000000;
@@ -45,7 +43,7 @@ struct FadeInfo {
std::atomic_bool active = {false};
std::atomic_int id = {0};
};
}
} // namespace
static FadeInfo masterAudioFade;
static std::unordered_map<std::string, FadeInfo> audioFades;
@@ -53,11 +51,6 @@ static std::unordered_map<std::string, FadeInfo> audioFades;
constexpr auto fadeInterval = std::chrono::milliseconds(100);
constexpr float minFade = 0.000001f;
static float decibelToPercent(float db)
{
return pow(10, (db / 20));
}
// For backwards compatibility
#if LIBOBS_API_VER >= MAKE_SEMANTIC_VERSION(29, 0, 0)
static float get_master_volume()
@@ -114,7 +107,7 @@ std::atomic_int *MacroActionAudio::GetFadeIdPtr() const
float MacroActionAudio::GetVolume() const
{
return _useDb ? decibelToPercent(_volumeDB) : (float)_volume / 100.0f;
return _useDb ? DecibelToPercent(_volumeDB) : (float)_volume / 100.0f;
}
void MacroActionAudio::SetVolume(float vol) const

View File

@@ -67,15 +67,22 @@ bool MacroConditionAudio::CheckOutputCondition()
OBSSourceAutoRelease source =
obs_weak_source_get_source(_audioSource.GetSource());
// peak will have a value from -60 db to 0 db so we need to scale it
double curVolume = ((double)_peak + 60) * 1.7;
double curVolume = _useDb ? _peak : DecibelToPercent(_peak);
switch (_outputCondition) {
case OutputCondition::ABOVE:
ret = curVolume > _volume;
if (_useDb) {
ret = curVolume > _volumeDB;
} else {
ret = curVolume > _volumePercent;
}
break;
case OutputCondition::BELOW:
ret = curVolume < _volume;
if (_useDb) {
ret = curVolume < _volumeDB;
} else {
ret = curVolume < _volumePercent;
}
break;
default:
break;
@@ -99,20 +106,34 @@ bool MacroConditionAudio::CheckVolumeCondition()
OBSSourceAutoRelease source =
obs_weak_source_get_source(_audioSource.GetSource());
float curVolume = obs_source_get_volume(source);
float curVolume =
_useDb ? PercentToDecibel(obs_source_get_volume(source))
: obs_source_get_volume(source);
bool muted = obs_source_muted(source);
switch (_volumeCondition) {
case VolumeCondition::ABOVE:
ret = curVolume > _volume / 100.f;
if (_useDb) {
ret = curVolume > _volumeDB;
} else {
ret = curVolume > _volumePercent / 100.f;
}
SetVariableValue(std::to_string(curVolume));
break;
case VolumeCondition::EXACT:
ret = curVolume == _volume / 100.f;
if (_useDb) {
ret = curVolume == _volumeDB;
} else {
ret = curVolume == _volumePercent / 100.f;
}
SetVariableValue(std::to_string(curVolume));
break;
case VolumeCondition::BELOW:
ret = curVolume < _volume / 100.f;
if (_useDb) {
ret = curVolume < _volumeDB;
} else {
ret = curVolume < _volumePercent / 100.f;
}
SetVariableValue(std::to_string(curVolume));
break;
case VolumeCondition::MUTE:
@@ -222,7 +243,7 @@ bool MacroConditionAudio::Save(obs_data_t *obj) const
MacroCondition::Save(obj);
_audioSource.Save(obj, "audioSource");
obs_data_set_int(obj, "monitor", _monitorType);
_volume.Save(obj, "volume");
_volumePercent.Save(obj, "volume");
_syncOffset.Save(obj, "syncOffset");
_balance.Save(obj, "balance");
obs_data_set_int(obj, "checkType", static_cast<int>(_checkType));
@@ -230,7 +251,9 @@ bool MacroConditionAudio::Save(obs_data_t *obj) const
static_cast<int>(_outputCondition));
obs_data_set_int(obj, "volumeCondition",
static_cast<int>(_volumeCondition));
obs_data_set_int(obj, "version", 1);
obs_data_set_bool(obj, "useDb", _useDb);
_volumeDB.Save(obj, "volumeDB");
obs_data_set_int(obj, "version", 2);
return true;
}
@@ -257,11 +280,11 @@ bool MacroConditionAudio::Load(obs_data_t *obj)
_monitorType = static_cast<obs_monitoring_type>(
obs_data_get_int(obj, "monitor"));
if (!obs_data_has_user_value(obj, "version")) {
_volume = obs_data_get_int(obj, "volume");
_volumePercent = obs_data_get_int(obj, "volume");
_syncOffset = obs_data_get_int(obj, "syncOffset");
_balance = obs_data_get_double(obj, "balance");
} else {
_volume.Load(obj, "volume");
_volumePercent.Load(obj, "volume");
_syncOffset.Load(obj, "syncOffset");
_balance.Load(obj, "balance");
}
@@ -271,6 +294,13 @@ bool MacroConditionAudio::Load(obs_data_t *obj)
_volumeCondition = static_cast<VolumeCondition>(
obs_data_get_int(obj, "volumeCondition"));
_volmeter = AddVolmeterToSource(this, _audioSource.GetSource());
if (obs_data_get_int(obj, "version") != 2) {
_useDb = false;
_volumeDB = 0.0;
} else {
_useDb = obs_data_get_bool(obj, "useDb");
_volumeDB.Load(obj, "volumeDB");
}
return true;
}
@@ -367,16 +397,16 @@ static inline void populateCheckTypes(QComboBox *list)
static inline void populateOutputConditionSelection(QComboBox *list)
{
list->clear();
for (auto entry : audioOutputConditionTypes) {
list->addItem(obs_module_text(entry.second.c_str()));
for (const auto &[_, name] : audioOutputConditionTypes) {
list->addItem(obs_module_text(name.c_str()));
}
}
static inline void populateVolumeConditionSelection(QComboBox *list)
{
list->clear();
for (auto entry : audioVolumeConditionTypes) {
list->addItem(obs_module_text(entry.second.c_str()));
for (const auto &[_, name] : audioVolumeConditionTypes) {
list->addItem(obs_module_text(name.c_str()));
}
}
@@ -386,14 +416,21 @@ MacroConditionAudioEdit::MacroConditionAudioEdit(
_checkTypes(new QComboBox()),
_sources(new SourceSelectionWidget(this, QStringList(), true)),
_condition(new QComboBox()),
_volume(new VariableSpinBox()),
_volumePercent(new VariableSpinBox()),
_volumeDB(new VariableDoubleSpinBox),
_percentDBToggle(new QPushButton),
_syncOffset(new VariableSpinBox()),
_monitorTypes(new QComboBox),
_balance(new SliderSpinBox(0., 1., ""))
{
_volume->setSuffix("%");
_volume->setMaximum(100);
_volume->setMinimum(0);
_volumePercent->setSuffix("%");
_volumePercent->setMaximum(100);
_volumePercent->setMinimum(0);
_volumeDB->setMinimum(-100);
_volumeDB->setMaximum(0);
_volumeDB->setSuffix("dB");
_volumeDB->specialValueText("-inf");
_syncOffset->setMinimum(-950);
_syncOffset->setMaximum(20000);
@@ -406,10 +443,9 @@ MacroConditionAudioEdit::MacroConditionAudioEdit(
QWidget::connect(_checkTypes, SIGNAL(currentIndexChanged(int)), this,
SLOT(CheckTypeChanged(int)));
QWidget::connect(
_volume,
_volumePercent,
SIGNAL(NumberVariableChanged(const NumberVariable<int> &)),
this,
SLOT(VolumeThresholdChanged(const NumberVariable<int> &)));
this, SLOT(VolumePercentChanged(const NumberVariable<int> &)));
QWidget::connect(
_syncOffset,
SIGNAL(NumberVariableChanged(const NumberVariable<int> &)),
@@ -425,6 +461,12 @@ MacroConditionAudioEdit::MacroConditionAudioEdit(
QWidget::connect(_sources,
SIGNAL(SourceChanged(const SourceSelection &)), this,
SLOT(SourceChanged(const SourceSelection &)));
QWidget::connect(
_volumeDB,
SIGNAL(NumberVariableChanged(const NumberVariable<double> &)),
this, SLOT(VolumeDBChanged(const NumberVariable<double> &)));
QWidget::connect(_percentDBToggle, SIGNAL(clicked()), this,
SLOT(PercentDBClicked()));
populateCheckTypes(_checkTypes);
PopulateMonitorTypeSelection(_monitorTypes);
@@ -433,11 +475,13 @@ MacroConditionAudioEdit::MacroConditionAudioEdit(
std::unordered_map<std::string, QWidget *> widgetPlaceholders = {
{"{{checkType}}", _checkTypes},
{"{{audioSources}}", _sources},
{"{{volume}}", _volume},
{"{{volume}}", _volumePercent},
{"{{syncOffset}}", _syncOffset},
{"{{monitorTypes}}", _monitorTypes},
{"{{balance}}", _balance},
{"{{condition}}", _condition},
{"{{volumeDB}}", _volumeDB},
{"{{percentDBToggle}}", _percentDBToggle},
};
PlaceWidgets(obs_module_text("AdvSceneSwitcher.condition.audio.entry"),
switchLayout, widgetPlaceholders);
@@ -459,16 +503,14 @@ void MacroConditionAudioEdit::UpdateVolmeterSource()
_entryData->_audioSource.GetSource());
_volMeter = new VolControl(soruce.Get());
QLayout *layout = this->layout();
auto layout = this->layout();
layout->addWidget(_volMeter);
QWidget::connect(_volMeter->GetSlider(), SIGNAL(valueChanged(int)),
_volume, SLOT(SetFixedValue(int)));
QWidget::connect(_volume, SIGNAL(FixedValueChanged(int)),
_volMeter->GetSlider(), SLOT(setValue(int)));
QWidget::connect(_volMeter->GetSlider(), &QSlider::valueChanged,
[=](int) { SyncSliderAndValueSelection(true); });
// Slider will default to 0 so set it manually once
_volMeter->GetSlider()->setValue(_entryData->_volume);
_volMeter->GetSlider()->setValue(_entryData->_volumePercent);
}
void MacroConditionAudioEdit::SourceChanged(const SourceSelection &source)
@@ -488,15 +530,18 @@ void MacroConditionAudioEdit::SourceChanged(const SourceSelection &source)
QString::fromStdString(_entryData->GetShortDesc()));
}
void MacroConditionAudioEdit::VolumeThresholdChanged(
void MacroConditionAudioEdit::VolumePercentChanged(
const NumberVariable<int> &vol)
{
if (_loading || !_entryData) {
return;
}
{
auto lock = LockContext();
_entryData->_volumePercent = vol;
}
auto lock = LockContext();
_entryData->_volume = vol;
SyncSliderAndValueSelection(false);
}
void MacroConditionAudioEdit::SyncOffsetChanged(const NumberVariable<int> &value)
@@ -529,6 +574,64 @@ void MacroConditionAudioEdit::BalanceChanged(const NumberVariable<double> &value
_entryData->_balance = value;
}
void MacroConditionAudioEdit::VolumeDBChanged(
const NumberVariable<double> &value)
{
if (_loading || !_entryData) {
return;
}
{
auto lock = LockContext();
_entryData->_volumeDB = value;
}
SyncSliderAndValueSelection(false);
}
void MacroConditionAudioEdit::PercentDBClicked()
{
if (_loading || !_entryData) {
return;
}
auto lock = LockContext();
_entryData->_useDb = !_entryData->_useDb;
SetWidgetVisibility();
}
void MacroConditionAudioEdit::SyncSliderAndValueSelection(bool sliderMoved)
{
if (_loading || !_entryData) {
return;
}
if (sliderMoved) {
if (_entryData->_useDb) {
_volumeDB->SetFixedValue(PercentToDecibel(
(float)_volMeter->GetSlider()->value() /
100.0));
const QSignalBlocker blocker(this);
_volumePercent->SetFixedValue(
_volMeter->GetSlider()->value());
} else {
_volumePercent->SetFixedValue(
_volMeter->GetSlider()->value());
const QSignalBlocker blocker(this);
_volumeDB->SetFixedValue(PercentToDecibel(
(float)_volMeter->GetSlider()->value() /
100.0));
}
} else {
const QSignalBlocker blocker(this);
if (_entryData->_useDb) {
_volMeter->GetSlider()->setValue(
DecibelToPercent(_entryData->_volumeDB) * 100);
} else {
_volMeter->GetSlider()->setValue(
_entryData->_volumePercent);
}
}
}
void MacroConditionAudioEdit::ConditionChanged(int cond)
{
if (_loading || !_entryData) {
@@ -577,7 +680,8 @@ void MacroConditionAudioEdit::UpdateEntryData()
}
_sources->SetSource(_entryData->_audioSource);
_volume->SetValue(_entryData->_volume);
_volumePercent->SetValue(_entryData->_volumePercent);
_volumeDB->SetValue(_entryData->_volumeDB);
_syncOffset->SetValue(_entryData->_syncOffset);
_monitorTypes->setCurrentIndex(_entryData->_monitorType);
_balance->SetDoubleValue(_entryData->_balance);
@@ -601,23 +705,26 @@ void MacroConditionAudioEdit::UpdateEntryData()
SetWidgetVisibility();
}
bool MacroConditionAudioEdit::HasVolumeControl() const
{
return _entryData->GetType() ==
MacroConditionAudio::Type::OUTPUT_VOLUME ||
(_entryData->GetType() ==
MacroConditionAudio::Type::CONFIGURED_VOLUME &&
(_entryData->_volumeCondition ==
MacroConditionAudio::VolumeCondition::ABOVE ||
_entryData->_volumeCondition ==
MacroConditionAudio::VolumeCondition::EXACT ||
_entryData->_volumeCondition ==
MacroConditionAudio::VolumeCondition::BELOW));
}
void MacroConditionAudioEdit::SetWidgetVisibility()
{
if (!_entryData) {
return;
}
_volume->setVisible(
_entryData->GetType() ==
MacroConditionAudio::Type::OUTPUT_VOLUME ||
(_entryData->GetType() ==
MacroConditionAudio::Type::CONFIGURED_VOLUME &&
(_entryData->_volumeCondition ==
MacroConditionAudio::VolumeCondition::ABOVE ||
_entryData->_volumeCondition ==
MacroConditionAudio::VolumeCondition::EXACT ||
_entryData->_volumeCondition ==
MacroConditionAudio::VolumeCondition::BELOW)));
_condition->setVisible(
_entryData->GetType() ==
MacroConditionAudio::Type::OUTPUT_VOLUME ||
@@ -634,6 +741,10 @@ void MacroConditionAudioEdit::SetWidgetVisibility()
MacroConditionAudio::Type::BALANCE);
_volMeter->setVisible(_entryData->GetType() ==
MacroConditionAudio::Type::OUTPUT_VOLUME);
_volumePercent->setVisible(HasVolumeControl() && !_entryData->_useDb);
_volumeDB->setVisible(HasVolumeControl() && _entryData->_useDb);
_percentDBToggle->setText(_entryData->_useDb ? "dB" : "%");
_percentDBToggle->setVisible(HasVolumeControl());
adjustSize();
}

View File

@@ -54,7 +54,9 @@ public:
};
SourceSelection _audioSource;
NumberVariable<int> _volume = 0;
bool _useDb = false;
NumberVariable<int> _volumePercent = 0;
NumberVariable<double> _volumeDB = 0.0;
NumberVariable<int> _syncOffset = 0;
obs_monitoring_type _monitorType = OBS_MONITORING_TYPE_NONE;
NumberVariable<double> _balance = 0.5;
@@ -95,30 +97,35 @@ public:
private slots:
void SourceChanged(const SourceSelection &);
void VolumeThresholdChanged(const NumberVariable<int> &vol);
void VolumePercentChanged(const NumberVariable<int> &vol);
void ConditionChanged(int cond);
void CheckTypeChanged(int cond);
void SyncOffsetChanged(const NumberVariable<int> &value);
void MonitorTypeChanged(int value);
void BalanceChanged(const NumberVariable<double> &value);
void VolumeDBChanged(const NumberVariable<double> &value);
void PercentDBClicked();
void SyncSliderAndValueSelection(bool sliderMoved);
signals:
void HeaderInfoChanged(const QString &);
protected:
private:
void SetWidgetVisibility();
bool HasVolumeControl() const;
QComboBox *_checkTypes;
SourceSelectionWidget *_sources;
QComboBox *_condition;
VariableSpinBox *_volume;
VariableSpinBox *_volumePercent;
VariableDoubleSpinBox *_volumeDB;
QPushButton *_percentDBToggle;
VariableSpinBox *_syncOffset;
QComboBox *_monitorTypes;
SliderSpinBox *_balance;
VolControl *_volMeter = nullptr;
std::shared_ptr<MacroConditionAudio> _entryData;
private:
void SetWidgetVisibility();
bool _loading = true;
};

View File

@@ -1,6 +1,7 @@
#include "audio-helpers.hpp"
#include "obs-module-helper.hpp"
#include <cmath>
#include <obs.hpp>
namespace advss {
@@ -13,4 +14,14 @@ void PopulateMonitorTypeSelection(QComboBox *list)
list->addItem(obs_module_text("AdvSceneSwitcher.audio.monitor.both"));
}
float DecibelToPercent(float db)
{
return isfinite((double)db) ? powf(10.0f, db / 20.0f) : 0.0f;
}
float PercentToDecibel(float percent)
{
return (percent == 0.0f) ? -INFINITY : (20.0f * log10f(percent));
}
} // namespace advss

View File

@@ -4,5 +4,7 @@
namespace advss {
void PopulateMonitorTypeSelection(QComboBox *list);
float DecibelToPercent(float db);
float PercentToDecibel(float percent);
} // namespace advss