mirror of
https://github.com/WarmUpTill/SceneSwitcher.git
synced 2026-09-07 00:56:00 -05:00
Compare commits
6 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
70dad8ebb4 | ||
|
|
497b3b3e04 | ||
|
|
891811aa47 | ||
|
|
be9ddaa4c9 | ||
|
|
03494c2915 | ||
|
|
bcf7c247bf |
@@ -151,6 +151,8 @@ target_sources(
|
|||||||
lib/utils/backup.hpp
|
lib/utils/backup.hpp
|
||||||
lib/utils/curl-helper.cpp
|
lib/utils/curl-helper.cpp
|
||||||
lib/utils/curl-helper.hpp
|
lib/utils/curl-helper.hpp
|
||||||
|
lib/utils/double-slider.cpp
|
||||||
|
lib/utils/double-slider.hpp
|
||||||
lib/utils/duration-control.cpp
|
lib/utils/duration-control.cpp
|
||||||
lib/utils/duration-control.hpp
|
lib/utils/duration-control.hpp
|
||||||
lib/utils/duration.cpp
|
lib/utils/duration.cpp
|
||||||
|
|||||||
@@ -437,10 +437,8 @@ AudioSwitchWidget::AudioSwitchWidget(QWidget *parent, AudioSwitch *s)
|
|||||||
audioVolumeThreshold->setMaximum(100);
|
audioVolumeThreshold->setMaximum(100);
|
||||||
audioVolumeThreshold->setMinimum(0);
|
audioVolumeThreshold->setMinimum(0);
|
||||||
|
|
||||||
QWidget::connect(volMeter->GetSlider(), SIGNAL(valueChanged(int)),
|
QWidget::connect(volMeter->GetSlider(), &DoubleSlider::DoubleValChanged,
|
||||||
audioVolumeThreshold, SLOT(setValue(int)));
|
[=](double) { SyncSliderAndValueSelection(true); });
|
||||||
QWidget::connect(audioVolumeThreshold, SIGNAL(valueChanged(int)),
|
|
||||||
volMeter->GetSlider(), SLOT(setValue(int)));
|
|
||||||
QWidget::connect(audioVolumeThreshold, SIGNAL(valueChanged(int)), this,
|
QWidget::connect(audioVolumeThreshold, SIGNAL(valueChanged(int)), this,
|
||||||
SLOT(VolumeThresholdChanged(int)));
|
SLOT(VolumeThresholdChanged(int)));
|
||||||
QWidget::connect(condition, SIGNAL(currentIndexChanged(int)), this,
|
QWidget::connect(condition, SIGNAL(currentIndexChanged(int)), this,
|
||||||
@@ -487,6 +485,7 @@ AudioSwitchWidget::AudioSwitchWidget(QWidget *parent, AudioSwitch *s)
|
|||||||
switchData = s;
|
switchData = s;
|
||||||
|
|
||||||
loading = false;
|
loading = false;
|
||||||
|
SyncSliderAndValueSelection(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
AudioSwitch *AudioSwitchWidget::getSwitchData()
|
AudioSwitch *AudioSwitchWidget::getSwitchData()
|
||||||
@@ -509,6 +508,21 @@ void AudioSwitchWidget::swapSwitchData(AudioSwitchWidget *s1,
|
|||||||
s2->setSwitchData(t);
|
s2->setSwitchData(t);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AudioSwitchWidget::SyncSliderAndValueSelection(bool sliderMoved)
|
||||||
|
{
|
||||||
|
if (loading || !switchData) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sliderMoved) {
|
||||||
|
auto sliderPosition = volMeter->GetSlider()->DoubleValue();
|
||||||
|
audioVolumeThreshold->setValue(sliderPosition);
|
||||||
|
} else {
|
||||||
|
volMeter->GetSlider()->SetDoubleVal(
|
||||||
|
switchData->volumeThreshold);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void AudioSwitchWidget::UpdateVolmeterSource()
|
void AudioSwitchWidget::UpdateVolmeterSource()
|
||||||
{
|
{
|
||||||
delete volMeter;
|
delete volMeter;
|
||||||
@@ -520,10 +534,8 @@ void AudioSwitchWidget::UpdateVolmeterSource()
|
|||||||
QLayout *layout = this->layout();
|
QLayout *layout = this->layout();
|
||||||
layout->addWidget(volMeter);
|
layout->addWidget(volMeter);
|
||||||
|
|
||||||
QWidget::connect(volMeter->GetSlider(), SIGNAL(valueChanged(int)),
|
QWidget::connect(volMeter->GetSlider(), &DoubleSlider::DoubleValChanged,
|
||||||
audioVolumeThreshold, SLOT(setValue(int)));
|
[=](double) { SyncSliderAndValueSelection(true); });
|
||||||
QWidget::connect(audioVolumeThreshold, SIGNAL(valueChanged(int)),
|
|
||||||
volMeter->GetSlider(), SLOT(setValue(int)));
|
|
||||||
|
|
||||||
// Slider will default to 0 so set it manually once
|
// Slider will default to 0 so set it manually once
|
||||||
volMeter->GetSlider()->setValue(switchData->volumeThreshold);
|
volMeter->GetSlider()->setValue(switchData->volumeThreshold);
|
||||||
@@ -547,8 +559,11 @@ void AudioSwitchWidget::VolumeThresholdChanged(int vol)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::lock_guard<std::mutex> lock(switcher->m);
|
{
|
||||||
switchData->volumeThreshold = vol;
|
std::lock_guard<std::mutex> lock(switcher->m);
|
||||||
|
switchData->volumeThreshold = vol;
|
||||||
|
}
|
||||||
|
SyncSliderAndValueSelection(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AudioSwitchWidget::ConditionChanged(int cond)
|
void AudioSwitchWidget::ConditionChanged(int cond)
|
||||||
|
|||||||
@@ -79,6 +79,7 @@ private slots:
|
|||||||
void ConditionChanged(int cond);
|
void ConditionChanged(int cond);
|
||||||
void DurationChanged(const Duration &);
|
void DurationChanged(const Duration &);
|
||||||
void IgnoreInactiveChanged(int state);
|
void IgnoreInactiveChanged(int state);
|
||||||
|
void SyncSliderAndValueSelection(bool sliderMoved);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QComboBox *audioSources;
|
QComboBox *audioSources;
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
#include "advanced-scene-switcher.hpp"
|
#include "advanced-scene-switcher.hpp"
|
||||||
|
#include "action-queue.hpp"
|
||||||
#include "macro-action-edit.hpp"
|
#include "macro-action-edit.hpp"
|
||||||
#include "macro-condition-edit.hpp"
|
#include "macro-condition-edit.hpp"
|
||||||
#include "macro-export-import-dialog.hpp"
|
#include "macro-export-import-dialog.hpp"
|
||||||
@@ -248,6 +249,7 @@ void AdvSceneSwitcher::ExportMacros()
|
|||||||
}
|
}
|
||||||
obs_data_set_array(data, "macros", macroArray);
|
obs_data_set_array(data, "macros", macroArray);
|
||||||
SaveVariables(data);
|
SaveVariables(data);
|
||||||
|
SaveActionQueues(data);
|
||||||
obs_data_set_string(data, "version", g_GIT_TAG);
|
obs_data_set_string(data, "version", g_GIT_TAG);
|
||||||
auto json = obs_data_get_json(data);
|
auto json = obs_data_get_json(data);
|
||||||
QString exportString(json);
|
QString exportString(json);
|
||||||
@@ -370,26 +372,6 @@ bool AdvSceneSwitcher::ResolveMacroImportNameConflict(
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool variableWithNameExists(const std::string &name)
|
|
||||||
{
|
|
||||||
return !!GetVariableByName(name);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void importVariables(obs_data_t *obj)
|
|
||||||
{
|
|
||||||
OBSDataArrayAutoRelease array = obs_data_get_array(obj, "variables");
|
|
||||||
size_t count = obs_data_array_count(array);
|
|
||||||
for (size_t i = 0; i < count; i++) {
|
|
||||||
OBSDataAutoRelease data = obs_data_array_item(array, i);
|
|
||||||
auto var = Variable::Create();
|
|
||||||
var->Load(data);
|
|
||||||
if (variableWithNameExists(var->Name())) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
GetVariables().emplace_back(var);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void AdvSceneSwitcher::ImportMacros()
|
void AdvSceneSwitcher::ImportMacros()
|
||||||
{
|
{
|
||||||
QString json;
|
QString json;
|
||||||
@@ -404,7 +386,8 @@ void AdvSceneSwitcher::ImportMacros()
|
|||||||
ImportMacros();
|
ImportMacros();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
importVariables(data);
|
ImportVariables(data);
|
||||||
|
ImportQueues(data);
|
||||||
|
|
||||||
auto version = obs_data_get_string(data, "version");
|
auto version = obs_data_get_string(data, "version");
|
||||||
if (strcmp(version, g_GIT_TAG) != 0) {
|
if (strcmp(version, g_GIT_TAG) != 0) {
|
||||||
@@ -425,6 +408,7 @@ void AdvSceneSwitcher::ImportMacros()
|
|||||||
OBSDataAutoRelease array_obj = obs_data_array_item(array, i);
|
OBSDataAutoRelease array_obj = obs_data_array_item(array, i);
|
||||||
auto macro = std::make_shared<Macro>();
|
auto macro = std::make_shared<Macro>();
|
||||||
macro->Load(array_obj);
|
macro->Load(array_obj);
|
||||||
|
RunPostLoadSteps();
|
||||||
|
|
||||||
if (macroNameExists(macro->Name()) &&
|
if (macroNameExists(macro->Name()) &&
|
||||||
!ResolveMacroImportNameConflict(macro)) {
|
!ResolveMacroImportNameConflict(macro)) {
|
||||||
|
|||||||
@@ -358,6 +358,27 @@ void LoadActionQueues(obs_data_t *obj)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool queueWithNameExists(const std::string &name)
|
||||||
|
{
|
||||||
|
return !GetWeakActionQueueByName(name).expired();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImportQueues(obs_data_t *data)
|
||||||
|
{
|
||||||
|
OBSDataArrayAutoRelease array =
|
||||||
|
obs_data_get_array(data, "actionQueues");
|
||||||
|
size_t count = obs_data_array_count(array);
|
||||||
|
for (size_t i = 0; i < count; i++) {
|
||||||
|
OBSDataAutoRelease arrayElement = obs_data_array_item(array, i);
|
||||||
|
auto queue = ActionQueue::Create();
|
||||||
|
queue->Load(arrayElement);
|
||||||
|
if (queueWithNameExists(queue->Name())) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
queues.emplace_back(queue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
std::weak_ptr<ActionQueue> GetWeakActionQueueByName(const std::string &name)
|
std::weak_ptr<ActionQueue> GetWeakActionQueueByName(const std::string &name)
|
||||||
{
|
{
|
||||||
for (const auto &queue : queues) {
|
for (const auto &queue : queues) {
|
||||||
|
|||||||
@@ -98,6 +98,7 @@ signals:
|
|||||||
void SetupActionQueues();
|
void SetupActionQueues();
|
||||||
void SaveActionQueues(obs_data_t *);
|
void SaveActionQueues(obs_data_t *);
|
||||||
void LoadActionQueues(obs_data_t *);
|
void LoadActionQueues(obs_data_t *);
|
||||||
|
void ImportQueues(obs_data_t *);
|
||||||
std::weak_ptr<ActionQueue> GetWeakActionQueueByName(const std::string &name);
|
std::weak_ptr<ActionQueue> GetWeakActionQueueByName(const std::string &name);
|
||||||
std::weak_ptr<ActionQueue> GetWeakActionQueueByQString(const QString &name);
|
std::weak_ptr<ActionQueue> GetWeakActionQueueByQString(const QString &name);
|
||||||
std::string GetActionQueueName(const std::weak_ptr<ActionQueue> &);
|
std::string GetActionQueueName(const std::weak_ptr<ActionQueue> &);
|
||||||
|
|||||||
63
lib/utils/double-slider.cpp
Normal file
63
lib/utils/double-slider.cpp
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
#include "double-slider.hpp"
|
||||||
|
#include <QWheelEvent>
|
||||||
|
|
||||||
|
#include <cmath>
|
||||||
|
|
||||||
|
namespace advss {
|
||||||
|
|
||||||
|
SliderIgnoreScroll::SliderIgnoreScroll(QWidget *parent) : QSlider(parent)
|
||||||
|
{
|
||||||
|
setFocusPolicy(Qt::StrongFocus);
|
||||||
|
}
|
||||||
|
|
||||||
|
SliderIgnoreScroll::SliderIgnoreScroll(Qt::Orientation orientation,
|
||||||
|
QWidget *parent)
|
||||||
|
: QSlider(parent)
|
||||||
|
{
|
||||||
|
setFocusPolicy(Qt::StrongFocus);
|
||||||
|
setOrientation(orientation);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SliderIgnoreScroll::wheelEvent(QWheelEvent *event)
|
||||||
|
{
|
||||||
|
if (!hasFocus()) {
|
||||||
|
event->ignore();
|
||||||
|
} else {
|
||||||
|
QSlider::wheelEvent(event);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DoubleSlider::DoubleSlider(QWidget *parent) : SliderIgnoreScroll(parent)
|
||||||
|
{
|
||||||
|
connect(this, &DoubleSlider::valueChanged, [this](int val) {
|
||||||
|
emit DoubleValChanged((minVal / minStep + val) * minStep);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void DoubleSlider::SetDoubleConstraints(double newMin, double newMax,
|
||||||
|
double newStep, double val)
|
||||||
|
{
|
||||||
|
minVal = newMin;
|
||||||
|
maxVal = newMax;
|
||||||
|
minStep = newStep;
|
||||||
|
|
||||||
|
double total = maxVal - minVal;
|
||||||
|
int intMax = int(total / minStep);
|
||||||
|
|
||||||
|
setMinimum(0);
|
||||||
|
setMaximum(intMax);
|
||||||
|
setSingleStep(1);
|
||||||
|
SetDoubleVal(val);
|
||||||
|
}
|
||||||
|
|
||||||
|
double DoubleSlider::DoubleValue()
|
||||||
|
{
|
||||||
|
return (minVal / minStep + value()) * minStep;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DoubleSlider::SetDoubleVal(double val)
|
||||||
|
{
|
||||||
|
setValue(lround((val - minVal) / minStep));
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace advss
|
||||||
40
lib/utils/double-slider.hpp
Normal file
40
lib/utils/double-slider.hpp
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
// Based on OBS DoubleSlider and SliderIgnoreScroll implementation
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#include "export-symbol-helper.hpp"
|
||||||
|
|
||||||
|
#include <QSlider>
|
||||||
|
|
||||||
|
namespace advss {
|
||||||
|
|
||||||
|
class SliderIgnoreScroll : public QSlider {
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
SliderIgnoreScroll(QWidget *parent = nullptr);
|
||||||
|
SliderIgnoreScroll(Qt::Orientation orientation,
|
||||||
|
QWidget *parent = nullptr);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
virtual void wheelEvent(QWheelEvent *event) override;
|
||||||
|
};
|
||||||
|
|
||||||
|
class ADVSS_EXPORT DoubleSlider : public SliderIgnoreScroll {
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
double minVal = 0, maxVal = 100, minStep = 1;
|
||||||
|
|
||||||
|
public:
|
||||||
|
DoubleSlider(QWidget *parent = nullptr);
|
||||||
|
|
||||||
|
void SetDoubleConstraints(double newMin, double newMax, double newStep,
|
||||||
|
double val);
|
||||||
|
double DoubleValue();
|
||||||
|
signals:
|
||||||
|
void DoubleValChanged(double val);
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
void SetDoubleVal(double val);
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace advss
|
||||||
@@ -90,15 +90,17 @@ void VolControl::setPeakMeterType(enum obs_peak_meter_type peakMeterType)
|
|||||||
}
|
}
|
||||||
|
|
||||||
VolumeSlider::VolumeSlider(obs_fader_t *fader, QWidget *parent)
|
VolumeSlider::VolumeSlider(obs_fader_t *fader, QWidget *parent)
|
||||||
: QSlider(parent)
|
: DoubleSlider(parent)
|
||||||
{
|
{
|
||||||
fad = fader;
|
fad = fader;
|
||||||
}
|
}
|
||||||
|
|
||||||
VolumeSlider::VolumeSlider(obs_fader_t *fader, Qt::Orientation orientation,
|
VolumeSlider::VolumeSlider(obs_fader_t *fader, Qt::Orientation orientation,
|
||||||
QWidget *parent)
|
QWidget *parent)
|
||||||
: QSlider(orientation, parent)
|
: DoubleSlider(parent)
|
||||||
{
|
{
|
||||||
|
SetDoubleConstraints(0, 100, 0.01, 0);
|
||||||
|
setOrientation(orientation);
|
||||||
fad = fader;
|
fad = fader;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -219,7 +221,6 @@ VolControl::VolControl(OBSSource source_, bool showConfig, bool vertical)
|
|||||||
nameLabel->setText(sourceName);
|
nameLabel->setText(sourceName);
|
||||||
|
|
||||||
slider->setMinimum(0);
|
slider->setMinimum(0);
|
||||||
slider->setMaximum(int(FADER_PRECISION));
|
|
||||||
|
|
||||||
obs_fader_add_callback(obs_fader, OBSVolumeChanged, this);
|
obs_fader_add_callback(obs_fader, OBSVolumeChanged, this);
|
||||||
obs_volmeter_add_callback(obs_volmeter, OBSVolumeLevel, this);
|
obs_volmeter_add_callback(obs_volmeter, OBSVolumeLevel, this);
|
||||||
@@ -592,7 +593,9 @@ void VolumeMeter::mousePressEvent(QMouseEvent *event)
|
|||||||
|
|
||||||
VolumeMeter::VolumeMeter(QWidget *parent, obs_volmeter_t *obs_volmeter,
|
VolumeMeter::VolumeMeter(QWidget *parent, obs_volmeter_t *obs_volmeter,
|
||||||
bool vertical)
|
bool vertical)
|
||||||
: QWidget(parent), obs_volmeter(obs_volmeter), vertical(vertical)
|
: QWidget(parent),
|
||||||
|
obs_volmeter(obs_volmeter),
|
||||||
|
vertical(vertical)
|
||||||
{
|
{
|
||||||
setAttribute(Qt::WA_OpaquePaintEvent, true);
|
setAttribute(Qt::WA_OpaquePaintEvent, true);
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
#include "double-slider.hpp"
|
||||||
|
|
||||||
#include <obs.hpp>
|
#include <obs.hpp>
|
||||||
#include <QWidget>
|
#include <QWidget>
|
||||||
@@ -284,7 +285,7 @@ private:
|
|||||||
QLabel *nameLabel;
|
QLabel *nameLabel;
|
||||||
QLabel *volLabel;
|
QLabel *volLabel;
|
||||||
VolumeMeter *volMeter;
|
VolumeMeter *volMeter;
|
||||||
QSlider *slider;
|
DoubleSlider *slider;
|
||||||
QPushButton *config = nullptr;
|
QPushButton *config = nullptr;
|
||||||
float levelTotal;
|
float levelTotal;
|
||||||
float levelCount;
|
float levelCount;
|
||||||
@@ -327,10 +328,10 @@ public:
|
|||||||
inline void SetContextMenu(QMenu *cm) { contextMenu = cm; }
|
inline void SetContextMenu(QMenu *cm) { contextMenu = cm; }
|
||||||
|
|
||||||
void refreshColors();
|
void refreshColors();
|
||||||
QSlider *GetSlider() const { return slider; }
|
DoubleSlider *GetSlider() const { return slider; }
|
||||||
};
|
};
|
||||||
|
|
||||||
class VolumeSlider : public QSlider {
|
class VolumeSlider : public DoubleSlider {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|||||||
@@ -187,6 +187,28 @@ void LoadVariables(obs_data_t *obj)
|
|||||||
obs_data_array_release(variablesArray);
|
obs_data_array_release(variablesArray);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool variableWithNameExists(const std::string &name)
|
||||||
|
{
|
||||||
|
return !!GetVariableByName(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImportVariables(obs_data_t *data)
|
||||||
|
{
|
||||||
|
obs_data_array_t *array = obs_data_get_array(data, "variables");
|
||||||
|
size_t count = obs_data_array_count(array);
|
||||||
|
for (size_t i = 0; i < count; i++) {
|
||||||
|
obs_data_t *arrayElement = obs_data_array_item(array, i);
|
||||||
|
auto var = Variable::Create();
|
||||||
|
var->Load(arrayElement);
|
||||||
|
obs_data_release(arrayElement);
|
||||||
|
if (variableWithNameExists(var->Name())) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
GetVariables().emplace_back(var);
|
||||||
|
}
|
||||||
|
obs_data_array_release(array);
|
||||||
|
}
|
||||||
|
|
||||||
static void populateSaveActionSelection(QComboBox *list)
|
static void populateSaveActionSelection(QComboBox *list)
|
||||||
{
|
{
|
||||||
list->addItem(
|
list->addItem(
|
||||||
|
|||||||
@@ -88,6 +88,7 @@ signals:
|
|||||||
|
|
||||||
void SaveVariables(obs_data_t *obj);
|
void SaveVariables(obs_data_t *obj);
|
||||||
void LoadVariables(obs_data_t *obj);
|
void LoadVariables(obs_data_t *obj);
|
||||||
|
void ImportVariables(obs_data_t *obj);
|
||||||
|
|
||||||
std::deque<std::shared_ptr<Item>> &GetVariables();
|
std::deque<std::shared_ptr<Item>> &GetVariables();
|
||||||
|
|
||||||
|
|||||||
@@ -253,7 +253,7 @@ bool MacroConditionAudio::Save(obs_data_t *obj) const
|
|||||||
static_cast<int>(_volumeCondition));
|
static_cast<int>(_volumeCondition));
|
||||||
obs_data_set_bool(obj, "useDb", _useDb);
|
obs_data_set_bool(obj, "useDb", _useDb);
|
||||||
_volumeDB.Save(obj, "volumeDB");
|
_volumeDB.Save(obj, "volumeDB");
|
||||||
obs_data_set_int(obj, "version", 2);
|
obs_data_set_int(obj, "version", 3);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -294,9 +294,19 @@ bool MacroConditionAudio::Load(obs_data_t *obj)
|
|||||||
_volumeCondition = static_cast<VolumeCondition>(
|
_volumeCondition = static_cast<VolumeCondition>(
|
||||||
obs_data_get_int(obj, "volumeCondition"));
|
obs_data_get_int(obj, "volumeCondition"));
|
||||||
_volmeter = AddVolmeterToSource(this, _audioSource.GetSource());
|
_volmeter = AddVolmeterToSource(this, _audioSource.GetSource());
|
||||||
if (obs_data_get_int(obj, "version") != 2) {
|
|
||||||
|
if (obs_data_get_int(obj, "version") < 2) {
|
||||||
|
// Set default values for dB handling
|
||||||
_useDb = false;
|
_useDb = false;
|
||||||
_volumeDB = 0.0;
|
_volumeDB = 0.0;
|
||||||
|
|
||||||
|
// In previous versions the scaling happened in CheckCondition()
|
||||||
|
// so these values must now be converted to enable compatibility
|
||||||
|
// with the decibel value based checks.
|
||||||
|
OBSDataAutoRelease data = obs_data_get_obj(obj, "volume");
|
||||||
|
auto oldFixedValue = obs_data_get_int(data, "value");
|
||||||
|
_volumeDB = ((double)oldFixedValue / 1.7) - 60;
|
||||||
|
_volumePercent = DecibelToPercent(_volumeDB) * 100;
|
||||||
} else {
|
} else {
|
||||||
_useDb = obs_data_get_bool(obj, "useDb");
|
_useDb = obs_data_get_bool(obj, "useDb");
|
||||||
_volumeDB.Load(obj, "volumeDB");
|
_volumeDB.Load(obj, "volumeDB");
|
||||||
@@ -416,7 +426,7 @@ MacroConditionAudioEdit::MacroConditionAudioEdit(
|
|||||||
_checkTypes(new QComboBox()),
|
_checkTypes(new QComboBox()),
|
||||||
_sources(new SourceSelectionWidget(this, QStringList(), true)),
|
_sources(new SourceSelectionWidget(this, QStringList(), true)),
|
||||||
_condition(new QComboBox()),
|
_condition(new QComboBox()),
|
||||||
_volumePercent(new VariableSpinBox()),
|
_volumePercent(new VariableDoubleSpinBox()),
|
||||||
_volumeDB(new VariableDoubleSpinBox),
|
_volumeDB(new VariableDoubleSpinBox),
|
||||||
_percentDBToggle(new QPushButton),
|
_percentDBToggle(new QPushButton),
|
||||||
_syncOffset(new VariableSpinBox()),
|
_syncOffset(new VariableSpinBox()),
|
||||||
@@ -444,8 +454,9 @@ MacroConditionAudioEdit::MacroConditionAudioEdit(
|
|||||||
SLOT(CheckTypeChanged(int)));
|
SLOT(CheckTypeChanged(int)));
|
||||||
QWidget::connect(
|
QWidget::connect(
|
||||||
_volumePercent,
|
_volumePercent,
|
||||||
SIGNAL(NumberVariableChanged(const NumberVariable<int> &)),
|
SIGNAL(NumberVariableChanged(const NumberVariable<double> &)),
|
||||||
this, SLOT(VolumePercentChanged(const NumberVariable<int> &)));
|
this,
|
||||||
|
SLOT(VolumePercentChanged(const NumberVariable<double> &)));
|
||||||
QWidget::connect(
|
QWidget::connect(
|
||||||
_syncOffset,
|
_syncOffset,
|
||||||
SIGNAL(NumberVariableChanged(const NumberVariable<int> &)),
|
SIGNAL(NumberVariableChanged(const NumberVariable<int> &)),
|
||||||
@@ -506,11 +517,12 @@ void MacroConditionAudioEdit::UpdateVolmeterSource()
|
|||||||
auto layout = this->layout();
|
auto layout = this->layout();
|
||||||
layout->addWidget(_volMeter);
|
layout->addWidget(_volMeter);
|
||||||
|
|
||||||
QWidget::connect(_volMeter->GetSlider(), &QSlider::valueChanged,
|
QWidget::connect(_volMeter->GetSlider(),
|
||||||
[=](int) { SyncSliderAndValueSelection(true); });
|
&DoubleSlider::DoubleValChanged,
|
||||||
|
[=](double) { SyncSliderAndValueSelection(true); });
|
||||||
|
|
||||||
// Slider will default to 0 so set it manually once
|
// Slider will default to 0 so set it manually once
|
||||||
_volMeter->GetSlider()->setValue(_entryData->_volumePercent);
|
SyncSliderAndValueSelection(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
void MacroConditionAudioEdit::SourceChanged(const SourceSelection &source)
|
void MacroConditionAudioEdit::SourceChanged(const SourceSelection &source)
|
||||||
@@ -531,7 +543,7 @@ void MacroConditionAudioEdit::SourceChanged(const SourceSelection &source)
|
|||||||
}
|
}
|
||||||
|
|
||||||
void MacroConditionAudioEdit::VolumePercentChanged(
|
void MacroConditionAudioEdit::VolumePercentChanged(
|
||||||
const NumberVariable<int> &vol)
|
const NumberVariable<double> &vol)
|
||||||
{
|
{
|
||||||
if (_loading || !_entryData) {
|
if (_loading || !_entryData) {
|
||||||
return;
|
return;
|
||||||
@@ -600,35 +612,35 @@ void MacroConditionAudioEdit::PercentDBClicked()
|
|||||||
|
|
||||||
void MacroConditionAudioEdit::SyncSliderAndValueSelection(bool sliderMoved)
|
void MacroConditionAudioEdit::SyncSliderAndValueSelection(bool sliderMoved)
|
||||||
{
|
{
|
||||||
if (_loading || !_entryData) {
|
if (!_entryData) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sliderMoved) {
|
if (sliderMoved) {
|
||||||
|
auto sliderPosition = _volMeter->GetSlider()->DoubleValue();
|
||||||
|
// Adjust to the dB scale on the volume meter widget
|
||||||
|
auto dBScaleValue = ((sliderPosition * 3.0) / 5.0) - 60.0;
|
||||||
|
|
||||||
if (_entryData->_useDb) {
|
if (_entryData->_useDb) {
|
||||||
_volumeDB->SetFixedValue(PercentToDecibel(
|
_volumeDB->SetFixedValue(dBScaleValue);
|
||||||
(float)_volMeter->GetSlider()->value() /
|
|
||||||
100.0));
|
|
||||||
const QSignalBlocker blocker(this);
|
const QSignalBlocker blocker(this);
|
||||||
_volumePercent->SetFixedValue(
|
_volumePercent->SetFixedValue(
|
||||||
_volMeter->GetSlider()->value());
|
DecibelToPercent(dBScaleValue) * 100);
|
||||||
} else {
|
} else {
|
||||||
_volumePercent->SetFixedValue(
|
_volumePercent->SetFixedValue(
|
||||||
_volMeter->GetSlider()->value());
|
DecibelToPercent(dBScaleValue) * 100);
|
||||||
const QSignalBlocker blocker(this);
|
const QSignalBlocker blocker(this);
|
||||||
_volumeDB->SetFixedValue(PercentToDecibel(
|
_volumeDB->SetFixedValue(dBScaleValue);
|
||||||
(float)_volMeter->GetSlider()->value() /
|
|
||||||
100.0));
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
const QSignalBlocker blocker(this);
|
const QSignalBlocker blocker(this);
|
||||||
if (_entryData->_useDb) {
|
double dBValue =
|
||||||
_volMeter->GetSlider()->setValue(
|
_entryData->_useDb
|
||||||
DecibelToPercent(_entryData->_volumeDB) * 100);
|
? _entryData->_volumeDB.GetFixedValue()
|
||||||
} else {
|
: PercentToDecibel(_entryData->_volumePercent /
|
||||||
_volMeter->GetSlider()->setValue(
|
100.0);
|
||||||
_entryData->_volumePercent);
|
auto sliderPosition = (dBValue + 60.0) * 5 / 3.0;
|
||||||
}
|
_volMeter->GetSlider()->SetDoubleVal(sliderPosition);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -55,11 +55,11 @@ public:
|
|||||||
|
|
||||||
SourceSelection _audioSource;
|
SourceSelection _audioSource;
|
||||||
bool _useDb = false;
|
bool _useDb = false;
|
||||||
NumberVariable<int> _volumePercent = 0;
|
DoubleVariable _volumePercent = 0;
|
||||||
NumberVariable<double> _volumeDB = 0.0;
|
DoubleVariable _volumeDB = 0.0;
|
||||||
NumberVariable<int> _syncOffset = 0;
|
IntVariable _syncOffset = 0;
|
||||||
obs_monitoring_type _monitorType = OBS_MONITORING_TYPE_NONE;
|
obs_monitoring_type _monitorType = OBS_MONITORING_TYPE_NONE;
|
||||||
NumberVariable<double> _balance = 0.5;
|
DoubleVariable _balance = 0.5;
|
||||||
OutputCondition _outputCondition = OutputCondition::ABOVE;
|
OutputCondition _outputCondition = OutputCondition::ABOVE;
|
||||||
VolumeCondition _volumeCondition = VolumeCondition::ABOVE;
|
VolumeCondition _volumeCondition = VolumeCondition::ABOVE;
|
||||||
obs_volmeter_t *_volmeter = nullptr;
|
obs_volmeter_t *_volmeter = nullptr;
|
||||||
@@ -97,7 +97,7 @@ public:
|
|||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void SourceChanged(const SourceSelection &);
|
void SourceChanged(const SourceSelection &);
|
||||||
void VolumePercentChanged(const NumberVariable<int> &vol);
|
void VolumePercentChanged(const NumberVariable<double> &vol);
|
||||||
void ConditionChanged(int cond);
|
void ConditionChanged(int cond);
|
||||||
void CheckTypeChanged(int cond);
|
void CheckTypeChanged(int cond);
|
||||||
void SyncOffsetChanged(const NumberVariable<int> &value);
|
void SyncOffsetChanged(const NumberVariable<int> &value);
|
||||||
@@ -117,7 +117,7 @@ private:
|
|||||||
QComboBox *_checkTypes;
|
QComboBox *_checkTypes;
|
||||||
SourceSelectionWidget *_sources;
|
SourceSelectionWidget *_sources;
|
||||||
QComboBox *_condition;
|
QComboBox *_condition;
|
||||||
VariableSpinBox *_volumePercent;
|
VariableDoubleSpinBox *_volumePercent;
|
||||||
VariableDoubleSpinBox *_volumeDB;
|
VariableDoubleSpinBox *_volumeDB;
|
||||||
QPushButton *_percentDBToggle;
|
QPushButton *_percentDBToggle;
|
||||||
VariableSpinBox *_syncOffset;
|
VariableSpinBox *_syncOffset;
|
||||||
|
|||||||
@@ -17,6 +17,55 @@ namespace advss {
|
|||||||
std::map<std::pair<MidiDeviceType, std::string>, MidiDeviceInstance *>
|
std::map<std::pair<MidiDeviceType, std::string>, MidiDeviceInstance *>
|
||||||
MidiDeviceInstance::devices = {};
|
MidiDeviceInstance::devices = {};
|
||||||
|
|
||||||
|
static bool setupDeviceObservers()
|
||||||
|
{
|
||||||
|
static std::vector<libremidi::observer> observers;
|
||||||
|
for (auto api : libremidi::available_apis()) {
|
||||||
|
libremidi::observer_configuration cbs;
|
||||||
|
cbs.input_added = [=](const libremidi::input_port &p) {
|
||||||
|
auto dev = MidiDeviceInstance::GetDevice(p);
|
||||||
|
if (!dev) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
blog(LOG_INFO, "MIDI input connected: %s",
|
||||||
|
p.port_name.c_str());
|
||||||
|
dev->ClosePort();
|
||||||
|
dev->OpenPort();
|
||||||
|
};
|
||||||
|
cbs.input_removed = [=](const libremidi::input_port &p) {
|
||||||
|
auto dev = MidiDeviceInstance::GetDevice(p);
|
||||||
|
if (!dev) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
blog(LOG_INFO, "MIDI input removed: %s",
|
||||||
|
p.port_name.c_str());
|
||||||
|
};
|
||||||
|
cbs.output_added = [=](const libremidi::output_port &p) {
|
||||||
|
auto dev = MidiDeviceInstance::GetDevice(p);
|
||||||
|
if (!dev) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
blog(LOG_INFO, "MIDI output connected: %s",
|
||||||
|
p.port_name.c_str());
|
||||||
|
dev->ClosePort();
|
||||||
|
dev->OpenPort();
|
||||||
|
};
|
||||||
|
cbs.output_removed = [=](const libremidi::output_port &p) {
|
||||||
|
auto dev = MidiDeviceInstance::GetDevice(p);
|
||||||
|
if (!dev) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
blog(LOG_INFO, "MIDI output removed: %s",
|
||||||
|
p.port_name.c_str());
|
||||||
|
};
|
||||||
|
observers.emplace_back(
|
||||||
|
cbs, libremidi::observer_configuration_for(api));
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool deviceObserversAreSetup = setupDeviceObservers();
|
||||||
|
|
||||||
void MidiDeviceInstance::ResetAllDevices()
|
void MidiDeviceInstance::ResetAllDevices()
|
||||||
{
|
{
|
||||||
for (auto const &[_, device] : MidiDeviceInstance::devices) {
|
for (auto const &[_, device] : MidiDeviceInstance::devices) {
|
||||||
@@ -212,8 +261,9 @@ bool MidiMessage::Matches(const MidiMessage &m) const
|
|||||||
return channelMatch && noteMatch && valueMatch && typeMatch;
|
return channelMatch && noteMatch && valueMatch && typeMatch;
|
||||||
}
|
}
|
||||||
|
|
||||||
MidiDeviceInstance *MidiDeviceInstance::GetDevice(MidiDeviceType type,
|
MidiDeviceInstance *
|
||||||
const std::string &name)
|
MidiDeviceInstance::GetDeviceAndOpen(MidiDeviceType type,
|
||||||
|
const std::string &name)
|
||||||
{
|
{
|
||||||
if (name.empty()) {
|
if (name.empty()) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
@@ -252,6 +302,30 @@ getNameFromPortInformation(const libremidi::port_information &info)
|
|||||||
return "[" + name;
|
return "[" + name;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MidiDeviceInstance *
|
||||||
|
advss::MidiDeviceInstance::GetDevice(const libremidi::input_port &p)
|
||||||
|
{
|
||||||
|
auto key = std::make_pair(MidiDeviceType::INPUT,
|
||||||
|
getNameFromPortInformation(p));
|
||||||
|
auto it = MidiDeviceInstance::devices.find(key);
|
||||||
|
if (it == devices.end()) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
return it->second;
|
||||||
|
}
|
||||||
|
|
||||||
|
MidiDeviceInstance *
|
||||||
|
advss::MidiDeviceInstance::GetDevice(const libremidi::output_port &p)
|
||||||
|
{
|
||||||
|
auto key = std::make_pair(MidiDeviceType::OUTPUT,
|
||||||
|
getNameFromPortInformation(p));
|
||||||
|
auto it = MidiDeviceInstance::devices.find(key);
|
||||||
|
if (it == devices.end()) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
return it->second;
|
||||||
|
}
|
||||||
|
|
||||||
static inline QStringList getInputDeviceNames()
|
static inline QStringList getInputDeviceNames()
|
||||||
{
|
{
|
||||||
QStringList devices;
|
QStringList devices;
|
||||||
@@ -305,10 +379,11 @@ static std::string getPortNameFromNumber(MidiDeviceType type, int port)
|
|||||||
return devices.at(port).toStdString();
|
return devices.at(port).toStdString();
|
||||||
}
|
}
|
||||||
|
|
||||||
MidiDeviceInstance *MidiDeviceInstance::GetDevice(MidiDeviceType type, int port)
|
MidiDeviceInstance *MidiDeviceInstance::GetDeviceAndOpen(MidiDeviceType type,
|
||||||
|
int port)
|
||||||
{
|
{
|
||||||
std::string name = getPortNameFromNumber(type, port);
|
std::string name = getPortNameFromNumber(type, port);
|
||||||
return GetDevice(type, name);
|
return GetDeviceAndOpen(type, name);
|
||||||
}
|
}
|
||||||
|
|
||||||
void MidiDevice::Save(obs_data_t *obj) const
|
void MidiDevice::Save(obs_data_t *obj) const
|
||||||
@@ -327,13 +402,13 @@ void MidiDevice::Load(obs_data_t *obj)
|
|||||||
// TODO: Remove this fallback at some point
|
// TODO: Remove this fallback at some point
|
||||||
if (obs_data_has_user_value(data, "port")) {
|
if (obs_data_has_user_value(data, "port")) {
|
||||||
auto port = obs_data_get_int(data, "port");
|
auto port = obs_data_get_int(data, "port");
|
||||||
_dev = MidiDeviceInstance::GetDevice(_type, port);
|
_dev = MidiDeviceInstance::GetDeviceAndOpen(_type, port);
|
||||||
if (_dev) {
|
if (_dev) {
|
||||||
_name = _dev->_name;
|
_name = _dev->_name;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
_name = obs_data_get_string(data, "portName");
|
_name = obs_data_get_string(data, "portName");
|
||||||
_dev = MidiDeviceInstance::GetDevice(_type, _name);
|
_dev = MidiDeviceInstance::GetDeviceAndOpen(_type, _name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -372,8 +447,7 @@ getInPortFromName(const std::string &name)
|
|||||||
|
|
||||||
bool MidiDeviceInstance::OpenPort()
|
bool MidiDeviceInstance::OpenPort()
|
||||||
{
|
{
|
||||||
if ((_type == MidiDeviceType::INPUT && _in.is_port_open()) ||
|
if (IsOpened()) {
|
||||||
(_type == MidiDeviceType::OUTPUT && _out.is_port_open())) {
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -437,10 +511,15 @@ bool MidiDeviceInstance::OpenPort()
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool MidiDeviceInstance::IsOpened() const
|
||||||
|
{
|
||||||
|
return (_type == MidiDeviceType::INPUT && _in.is_port_open()) ||
|
||||||
|
(_type == MidiDeviceType::OUTPUT && _out.is_port_open());
|
||||||
|
}
|
||||||
|
|
||||||
void MidiDeviceInstance::ClosePort()
|
void MidiDeviceInstance::ClosePort()
|
||||||
{
|
{
|
||||||
if ((_type == MidiDeviceType::INPUT && !_in.is_port_open()) ||
|
if (!IsOpened()) {
|
||||||
(_type == MidiDeviceType::OUTPUT && !_out.is_port_open())) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -542,7 +621,6 @@ MidiMessageBuffer MidiDeviceInstance::RegisterForMidiMessages()
|
|||||||
|
|
||||||
void MidiDeviceInstance::ReceiveMidiMessage(libremidi::message &&msg)
|
void MidiDeviceInstance::ReceiveMidiMessage(libremidi::message &&msg)
|
||||||
{
|
{
|
||||||
auto lock = LockContext();
|
|
||||||
_dispatcher.DispatchMessage(msg);
|
_dispatcher.DispatchMessage(msg);
|
||||||
vblog(LOG_INFO, "received midi: %s",
|
vblog(LOG_INFO, "received midi: %s",
|
||||||
MidiMessage::ToString(msg).c_str());
|
MidiMessage::ToString(msg).c_str());
|
||||||
@@ -590,7 +668,7 @@ void MidiDeviceSelection::IdxChangedHelper(int idx)
|
|||||||
}
|
}
|
||||||
|
|
||||||
auto name = currentText().toStdString();
|
auto name = currentText().toStdString();
|
||||||
auto devInstance = MidiDeviceInstance::GetDevice(_type, name);
|
auto devInstance = MidiDeviceInstance::GetDeviceAndOpen(_type, name);
|
||||||
if (!devInstance) {
|
if (!devInstance) {
|
||||||
DisplayMessage(obs_module_text(
|
DisplayMessage(obs_module_text(
|
||||||
"AdvSceneSwitcher.midi.deviceOpenFail"));
|
"AdvSceneSwitcher.midi.deviceOpenFail"));
|
||||||
|
|||||||
@@ -64,16 +64,22 @@ enum class MidiDeviceType {
|
|||||||
|
|
||||||
class MidiDeviceInstance {
|
class MidiDeviceInstance {
|
||||||
public:
|
public:
|
||||||
static MidiDeviceInstance *GetDevice(MidiDeviceType type,
|
static MidiDeviceInstance *GetDeviceAndOpen(MidiDeviceType type,
|
||||||
const std::string &);
|
const std::string &);
|
||||||
static MidiDeviceInstance *GetDevice(MidiDeviceType type, int port);
|
static MidiDeviceInstance *GetDeviceAndOpen(MidiDeviceType type,
|
||||||
|
int port);
|
||||||
|
static MidiDeviceInstance *GetDevice(const libremidi::input_port &p);
|
||||||
|
static MidiDeviceInstance *GetDevice(const libremidi::output_port &p);
|
||||||
|
|
||||||
static void ResetAllDevices();
|
static void ResetAllDevices();
|
||||||
|
|
||||||
|
bool OpenPort();
|
||||||
|
void ClosePort();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
MidiDeviceInstance() = default;
|
MidiDeviceInstance() = default;
|
||||||
~MidiDeviceInstance() = default;
|
~MidiDeviceInstance() = default;
|
||||||
bool OpenPort();
|
bool IsOpened() const;
|
||||||
void ClosePort();
|
|
||||||
bool SendMessge(const MidiMessage &);
|
bool SendMessge(const MidiMessage &);
|
||||||
[[nodiscard]] MidiMessageBuffer RegisterForMidiMessages();
|
[[nodiscard]] MidiMessageBuffer RegisterForMidiMessages();
|
||||||
void ReceiveMidiMessage(libremidi::message &&);
|
void ReceiveMidiMessage(libremidi::message &&);
|
||||||
|
|||||||
Reference in New Issue
Block a user