mirror of
https://github.com/WarmUpTill/SceneSwitcher.git
synced 2026-08-29 12:45:28 -05:00
Compare commits
7 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
70dad8ebb4 | ||
|
|
497b3b3e04 | ||
|
|
891811aa47 | ||
|
|
be9ddaa4c9 | ||
|
|
03494c2915 | ||
|
|
bcf7c247bf | ||
|
|
132d89b350 |
@@ -151,6 +151,8 @@ target_sources(
|
||||
lib/utils/backup.hpp
|
||||
lib/utils/curl-helper.cpp
|
||||
lib/utils/curl-helper.hpp
|
||||
lib/utils/double-slider.cpp
|
||||
lib/utils/double-slider.hpp
|
||||
lib/utils/duration-control.cpp
|
||||
lib/utils/duration-control.hpp
|
||||
lib/utils/duration.cpp
|
||||
|
||||
@@ -437,10 +437,8 @@ AudioSwitchWidget::AudioSwitchWidget(QWidget *parent, AudioSwitch *s)
|
||||
audioVolumeThreshold->setMaximum(100);
|
||||
audioVolumeThreshold->setMinimum(0);
|
||||
|
||||
QWidget::connect(volMeter->GetSlider(), SIGNAL(valueChanged(int)),
|
||||
audioVolumeThreshold, SLOT(setValue(int)));
|
||||
QWidget::connect(audioVolumeThreshold, SIGNAL(valueChanged(int)),
|
||||
volMeter->GetSlider(), SLOT(setValue(int)));
|
||||
QWidget::connect(volMeter->GetSlider(), &DoubleSlider::DoubleValChanged,
|
||||
[=](double) { SyncSliderAndValueSelection(true); });
|
||||
QWidget::connect(audioVolumeThreshold, SIGNAL(valueChanged(int)), this,
|
||||
SLOT(VolumeThresholdChanged(int)));
|
||||
QWidget::connect(condition, SIGNAL(currentIndexChanged(int)), this,
|
||||
@@ -487,6 +485,7 @@ AudioSwitchWidget::AudioSwitchWidget(QWidget *parent, AudioSwitch *s)
|
||||
switchData = s;
|
||||
|
||||
loading = false;
|
||||
SyncSliderAndValueSelection(false);
|
||||
}
|
||||
|
||||
AudioSwitch *AudioSwitchWidget::getSwitchData()
|
||||
@@ -509,6 +508,21 @@ void AudioSwitchWidget::swapSwitchData(AudioSwitchWidget *s1,
|
||||
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()
|
||||
{
|
||||
delete volMeter;
|
||||
@@ -520,10 +534,8 @@ void AudioSwitchWidget::UpdateVolmeterSource()
|
||||
QLayout *layout = this->layout();
|
||||
layout->addWidget(volMeter);
|
||||
|
||||
QWidget::connect(volMeter->GetSlider(), SIGNAL(valueChanged(int)),
|
||||
audioVolumeThreshold, SLOT(setValue(int)));
|
||||
QWidget::connect(audioVolumeThreshold, SIGNAL(valueChanged(int)),
|
||||
volMeter->GetSlider(), SLOT(setValue(int)));
|
||||
QWidget::connect(volMeter->GetSlider(), &DoubleSlider::DoubleValChanged,
|
||||
[=](double) { SyncSliderAndValueSelection(true); });
|
||||
|
||||
// Slider will default to 0 so set it manually once
|
||||
volMeter->GetSlider()->setValue(switchData->volumeThreshold);
|
||||
@@ -547,8 +559,11 @@ void AudioSwitchWidget::VolumeThresholdChanged(int vol)
|
||||
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)
|
||||
|
||||
@@ -79,6 +79,7 @@ private slots:
|
||||
void ConditionChanged(int cond);
|
||||
void DurationChanged(const Duration &);
|
||||
void IgnoreInactiveChanged(int state);
|
||||
void SyncSliderAndValueSelection(bool sliderMoved);
|
||||
|
||||
private:
|
||||
QComboBox *audioSources;
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
#include "advanced-scene-switcher.hpp"
|
||||
#include "action-queue.hpp"
|
||||
#include "macro-action-edit.hpp"
|
||||
#include "macro-condition-edit.hpp"
|
||||
#include "macro-export-import-dialog.hpp"
|
||||
@@ -248,6 +249,7 @@ void AdvSceneSwitcher::ExportMacros()
|
||||
}
|
||||
obs_data_set_array(data, "macros", macroArray);
|
||||
SaveVariables(data);
|
||||
SaveActionQueues(data);
|
||||
obs_data_set_string(data, "version", g_GIT_TAG);
|
||||
auto json = obs_data_get_json(data);
|
||||
QString exportString(json);
|
||||
@@ -370,26 +372,6 @@ bool AdvSceneSwitcher::ResolveMacroImportNameConflict(
|
||||
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()
|
||||
{
|
||||
QString json;
|
||||
@@ -404,7 +386,8 @@ void AdvSceneSwitcher::ImportMacros()
|
||||
ImportMacros();
|
||||
return;
|
||||
}
|
||||
importVariables(data);
|
||||
ImportVariables(data);
|
||||
ImportQueues(data);
|
||||
|
||||
auto version = obs_data_get_string(data, "version");
|
||||
if (strcmp(version, g_GIT_TAG) != 0) {
|
||||
@@ -425,6 +408,7 @@ void AdvSceneSwitcher::ImportMacros()
|
||||
OBSDataAutoRelease array_obj = obs_data_array_item(array, i);
|
||||
auto macro = std::make_shared<Macro>();
|
||||
macro->Load(array_obj);
|
||||
RunPostLoadSteps();
|
||||
|
||||
if (macroNameExists(macro->Name()) &&
|
||||
!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)
|
||||
{
|
||||
for (const auto &queue : queues) {
|
||||
|
||||
@@ -98,6 +98,7 @@ signals:
|
||||
void SetupActionQueues();
|
||||
void SaveActionQueues(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> GetWeakActionQueueByQString(const QString &name);
|
||||
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)
|
||||
: QSlider(parent)
|
||||
: DoubleSlider(parent)
|
||||
{
|
||||
fad = fader;
|
||||
}
|
||||
|
||||
VolumeSlider::VolumeSlider(obs_fader_t *fader, Qt::Orientation orientation,
|
||||
QWidget *parent)
|
||||
: QSlider(orientation, parent)
|
||||
: DoubleSlider(parent)
|
||||
{
|
||||
SetDoubleConstraints(0, 100, 0.01, 0);
|
||||
setOrientation(orientation);
|
||||
fad = fader;
|
||||
}
|
||||
|
||||
@@ -219,7 +221,6 @@ VolControl::VolControl(OBSSource source_, bool showConfig, bool vertical)
|
||||
nameLabel->setText(sourceName);
|
||||
|
||||
slider->setMinimum(0);
|
||||
slider->setMaximum(int(FADER_PRECISION));
|
||||
|
||||
obs_fader_add_callback(obs_fader, OBSVolumeChanged, 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,
|
||||
bool vertical)
|
||||
: QWidget(parent), obs_volmeter(obs_volmeter), vertical(vertical)
|
||||
: QWidget(parent),
|
||||
obs_volmeter(obs_volmeter),
|
||||
vertical(vertical)
|
||||
{
|
||||
setAttribute(Qt::WA_OpaquePaintEvent, true);
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
#pragma once
|
||||
#include "double-slider.hpp"
|
||||
|
||||
#include <obs.hpp>
|
||||
#include <QWidget>
|
||||
@@ -284,7 +285,7 @@ private:
|
||||
QLabel *nameLabel;
|
||||
QLabel *volLabel;
|
||||
VolumeMeter *volMeter;
|
||||
QSlider *slider;
|
||||
DoubleSlider *slider;
|
||||
QPushButton *config = nullptr;
|
||||
float levelTotal;
|
||||
float levelCount;
|
||||
@@ -327,10 +328,10 @@ public:
|
||||
inline void SetContextMenu(QMenu *cm) { contextMenu = cm; }
|
||||
|
||||
void refreshColors();
|
||||
QSlider *GetSlider() const { return slider; }
|
||||
DoubleSlider *GetSlider() const { return slider; }
|
||||
};
|
||||
|
||||
class VolumeSlider : public QSlider {
|
||||
class VolumeSlider : public DoubleSlider {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
@@ -187,6 +187,28 @@ void LoadVariables(obs_data_t *obj)
|
||||
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)
|
||||
{
|
||||
list->addItem(
|
||||
|
||||
@@ -88,6 +88,7 @@ signals:
|
||||
|
||||
void SaveVariables(obs_data_t *obj);
|
||||
void LoadVariables(obs_data_t *obj);
|
||||
void ImportVariables(obs_data_t *obj);
|
||||
|
||||
std::deque<std::shared_ptr<Item>> &GetVariables();
|
||||
|
||||
|
||||
@@ -67,12 +67,12 @@ bool MacroActionVCam::Load(obs_data_t *obj)
|
||||
|
||||
std::shared_ptr<MacroAction> MacroActionVCam::Create(Macro *m)
|
||||
{
|
||||
return std::shared_ptr<MacroAction>();
|
||||
return std::make_shared<MacroActionVCam>(m);
|
||||
}
|
||||
|
||||
std::shared_ptr<MacroAction> MacroActionVCam::Copy() const
|
||||
{
|
||||
return std::shared_ptr<MacroAction>();
|
||||
return std::make_shared<MacroActionVCam>(*this);
|
||||
}
|
||||
|
||||
static inline void populateActionSelection(QComboBox *list)
|
||||
|
||||
@@ -253,7 +253,7 @@ bool MacroConditionAudio::Save(obs_data_t *obj) const
|
||||
static_cast<int>(_volumeCondition));
|
||||
obs_data_set_bool(obj, "useDb", _useDb);
|
||||
_volumeDB.Save(obj, "volumeDB");
|
||||
obs_data_set_int(obj, "version", 2);
|
||||
obs_data_set_int(obj, "version", 3);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -294,9 +294,19 @@ 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) {
|
||||
|
||||
if (obs_data_get_int(obj, "version") < 2) {
|
||||
// Set default values for dB handling
|
||||
_useDb = false;
|
||||
_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 {
|
||||
_useDb = obs_data_get_bool(obj, "useDb");
|
||||
_volumeDB.Load(obj, "volumeDB");
|
||||
@@ -416,7 +426,7 @@ MacroConditionAudioEdit::MacroConditionAudioEdit(
|
||||
_checkTypes(new QComboBox()),
|
||||
_sources(new SourceSelectionWidget(this, QStringList(), true)),
|
||||
_condition(new QComboBox()),
|
||||
_volumePercent(new VariableSpinBox()),
|
||||
_volumePercent(new VariableDoubleSpinBox()),
|
||||
_volumeDB(new VariableDoubleSpinBox),
|
||||
_percentDBToggle(new QPushButton),
|
||||
_syncOffset(new VariableSpinBox()),
|
||||
@@ -444,8 +454,9 @@ MacroConditionAudioEdit::MacroConditionAudioEdit(
|
||||
SLOT(CheckTypeChanged(int)));
|
||||
QWidget::connect(
|
||||
_volumePercent,
|
||||
SIGNAL(NumberVariableChanged(const NumberVariable<int> &)),
|
||||
this, SLOT(VolumePercentChanged(const NumberVariable<int> &)));
|
||||
SIGNAL(NumberVariableChanged(const NumberVariable<double> &)),
|
||||
this,
|
||||
SLOT(VolumePercentChanged(const NumberVariable<double> &)));
|
||||
QWidget::connect(
|
||||
_syncOffset,
|
||||
SIGNAL(NumberVariableChanged(const NumberVariable<int> &)),
|
||||
@@ -506,11 +517,12 @@ void MacroConditionAudioEdit::UpdateVolmeterSource()
|
||||
auto layout = this->layout();
|
||||
layout->addWidget(_volMeter);
|
||||
|
||||
QWidget::connect(_volMeter->GetSlider(), &QSlider::valueChanged,
|
||||
[=](int) { SyncSliderAndValueSelection(true); });
|
||||
QWidget::connect(_volMeter->GetSlider(),
|
||||
&DoubleSlider::DoubleValChanged,
|
||||
[=](double) { SyncSliderAndValueSelection(true); });
|
||||
|
||||
// Slider will default to 0 so set it manually once
|
||||
_volMeter->GetSlider()->setValue(_entryData->_volumePercent);
|
||||
SyncSliderAndValueSelection(false);
|
||||
}
|
||||
|
||||
void MacroConditionAudioEdit::SourceChanged(const SourceSelection &source)
|
||||
@@ -531,7 +543,7 @@ void MacroConditionAudioEdit::SourceChanged(const SourceSelection &source)
|
||||
}
|
||||
|
||||
void MacroConditionAudioEdit::VolumePercentChanged(
|
||||
const NumberVariable<int> &vol)
|
||||
const NumberVariable<double> &vol)
|
||||
{
|
||||
if (_loading || !_entryData) {
|
||||
return;
|
||||
@@ -600,35 +612,35 @@ void MacroConditionAudioEdit::PercentDBClicked()
|
||||
|
||||
void MacroConditionAudioEdit::SyncSliderAndValueSelection(bool sliderMoved)
|
||||
{
|
||||
if (_loading || !_entryData) {
|
||||
if (!_entryData) {
|
||||
return;
|
||||
}
|
||||
|
||||
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) {
|
||||
_volumeDB->SetFixedValue(PercentToDecibel(
|
||||
(float)_volMeter->GetSlider()->value() /
|
||||
100.0));
|
||||
_volumeDB->SetFixedValue(dBScaleValue);
|
||||
const QSignalBlocker blocker(this);
|
||||
_volumePercent->SetFixedValue(
|
||||
_volMeter->GetSlider()->value());
|
||||
DecibelToPercent(dBScaleValue) * 100);
|
||||
} else {
|
||||
_volumePercent->SetFixedValue(
|
||||
_volMeter->GetSlider()->value());
|
||||
DecibelToPercent(dBScaleValue) * 100);
|
||||
const QSignalBlocker blocker(this);
|
||||
_volumeDB->SetFixedValue(PercentToDecibel(
|
||||
(float)_volMeter->GetSlider()->value() /
|
||||
100.0));
|
||||
_volumeDB->SetFixedValue(dBScaleValue);
|
||||
}
|
||||
} else {
|
||||
const QSignalBlocker blocker(this);
|
||||
if (_entryData->_useDb) {
|
||||
_volMeter->GetSlider()->setValue(
|
||||
DecibelToPercent(_entryData->_volumeDB) * 100);
|
||||
} else {
|
||||
_volMeter->GetSlider()->setValue(
|
||||
_entryData->_volumePercent);
|
||||
}
|
||||
double dBValue =
|
||||
_entryData->_useDb
|
||||
? _entryData->_volumeDB.GetFixedValue()
|
||||
: PercentToDecibel(_entryData->_volumePercent /
|
||||
100.0);
|
||||
auto sliderPosition = (dBValue + 60.0) * 5 / 3.0;
|
||||
_volMeter->GetSlider()->SetDoubleVal(sliderPosition);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -55,11 +55,11 @@ public:
|
||||
|
||||
SourceSelection _audioSource;
|
||||
bool _useDb = false;
|
||||
NumberVariable<int> _volumePercent = 0;
|
||||
NumberVariable<double> _volumeDB = 0.0;
|
||||
NumberVariable<int> _syncOffset = 0;
|
||||
DoubleVariable _volumePercent = 0;
|
||||
DoubleVariable _volumeDB = 0.0;
|
||||
IntVariable _syncOffset = 0;
|
||||
obs_monitoring_type _monitorType = OBS_MONITORING_TYPE_NONE;
|
||||
NumberVariable<double> _balance = 0.5;
|
||||
DoubleVariable _balance = 0.5;
|
||||
OutputCondition _outputCondition = OutputCondition::ABOVE;
|
||||
VolumeCondition _volumeCondition = VolumeCondition::ABOVE;
|
||||
obs_volmeter_t *_volmeter = nullptr;
|
||||
@@ -97,7 +97,7 @@ public:
|
||||
|
||||
private slots:
|
||||
void SourceChanged(const SourceSelection &);
|
||||
void VolumePercentChanged(const NumberVariable<int> &vol);
|
||||
void VolumePercentChanged(const NumberVariable<double> &vol);
|
||||
void ConditionChanged(int cond);
|
||||
void CheckTypeChanged(int cond);
|
||||
void SyncOffsetChanged(const NumberVariable<int> &value);
|
||||
@@ -117,7 +117,7 @@ private:
|
||||
QComboBox *_checkTypes;
|
||||
SourceSelectionWidget *_sources;
|
||||
QComboBox *_condition;
|
||||
VariableSpinBox *_volumePercent;
|
||||
VariableDoubleSpinBox *_volumePercent;
|
||||
VariableDoubleSpinBox *_volumeDB;
|
||||
QPushButton *_percentDBToggle;
|
||||
VariableSpinBox *_syncOffset;
|
||||
|
||||
@@ -17,6 +17,55 @@ namespace advss {
|
||||
std::map<std::pair<MidiDeviceType, std::string>, MidiDeviceInstance *>
|
||||
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()
|
||||
{
|
||||
for (auto const &[_, device] : MidiDeviceInstance::devices) {
|
||||
@@ -212,8 +261,9 @@ bool MidiMessage::Matches(const MidiMessage &m) const
|
||||
return channelMatch && noteMatch && valueMatch && typeMatch;
|
||||
}
|
||||
|
||||
MidiDeviceInstance *MidiDeviceInstance::GetDevice(MidiDeviceType type,
|
||||
const std::string &name)
|
||||
MidiDeviceInstance *
|
||||
MidiDeviceInstance::GetDeviceAndOpen(MidiDeviceType type,
|
||||
const std::string &name)
|
||||
{
|
||||
if (name.empty()) {
|
||||
return nullptr;
|
||||
@@ -252,6 +302,30 @@ getNameFromPortInformation(const libremidi::port_information &info)
|
||||
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()
|
||||
{
|
||||
QStringList devices;
|
||||
@@ -305,10 +379,11 @@ static std::string getPortNameFromNumber(MidiDeviceType type, int port)
|
||||
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);
|
||||
return GetDevice(type, name);
|
||||
return GetDeviceAndOpen(type, name);
|
||||
}
|
||||
|
||||
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
|
||||
if (obs_data_has_user_value(data, "port")) {
|
||||
auto port = obs_data_get_int(data, "port");
|
||||
_dev = MidiDeviceInstance::GetDevice(_type, port);
|
||||
_dev = MidiDeviceInstance::GetDeviceAndOpen(_type, port);
|
||||
if (_dev) {
|
||||
_name = _dev->_name;
|
||||
}
|
||||
} else {
|
||||
_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()
|
||||
{
|
||||
if ((_type == MidiDeviceType::INPUT && _in.is_port_open()) ||
|
||||
(_type == MidiDeviceType::OUTPUT && _out.is_port_open())) {
|
||||
if (IsOpened()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -437,10 +511,15 @@ bool MidiDeviceInstance::OpenPort()
|
||||
return false;
|
||||
}
|
||||
|
||||
bool MidiDeviceInstance::IsOpened() const
|
||||
{
|
||||
return (_type == MidiDeviceType::INPUT && _in.is_port_open()) ||
|
||||
(_type == MidiDeviceType::OUTPUT && _out.is_port_open());
|
||||
}
|
||||
|
||||
void MidiDeviceInstance::ClosePort()
|
||||
{
|
||||
if ((_type == MidiDeviceType::INPUT && !_in.is_port_open()) ||
|
||||
(_type == MidiDeviceType::OUTPUT && !_out.is_port_open())) {
|
||||
if (!IsOpened()) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -542,7 +621,6 @@ MidiMessageBuffer MidiDeviceInstance::RegisterForMidiMessages()
|
||||
|
||||
void MidiDeviceInstance::ReceiveMidiMessage(libremidi::message &&msg)
|
||||
{
|
||||
auto lock = LockContext();
|
||||
_dispatcher.DispatchMessage(msg);
|
||||
vblog(LOG_INFO, "received midi: %s",
|
||||
MidiMessage::ToString(msg).c_str());
|
||||
@@ -590,7 +668,7 @@ void MidiDeviceSelection::IdxChangedHelper(int idx)
|
||||
}
|
||||
|
||||
auto name = currentText().toStdString();
|
||||
auto devInstance = MidiDeviceInstance::GetDevice(_type, name);
|
||||
auto devInstance = MidiDeviceInstance::GetDeviceAndOpen(_type, name);
|
||||
if (!devInstance) {
|
||||
DisplayMessage(obs_module_text(
|
||||
"AdvSceneSwitcher.midi.deviceOpenFail"));
|
||||
|
||||
@@ -64,16 +64,22 @@ enum class MidiDeviceType {
|
||||
|
||||
class MidiDeviceInstance {
|
||||
public:
|
||||
static MidiDeviceInstance *GetDevice(MidiDeviceType type,
|
||||
const std::string &);
|
||||
static MidiDeviceInstance *GetDevice(MidiDeviceType type, int port);
|
||||
static MidiDeviceInstance *GetDeviceAndOpen(MidiDeviceType type,
|
||||
const std::string &);
|
||||
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();
|
||||
|
||||
bool OpenPort();
|
||||
void ClosePort();
|
||||
|
||||
private:
|
||||
MidiDeviceInstance() = default;
|
||||
~MidiDeviceInstance() = default;
|
||||
bool OpenPort();
|
||||
void ClosePort();
|
||||
bool IsOpened() const;
|
||||
bool SendMessge(const MidiMessage &);
|
||||
[[nodiscard]] MidiMessageBuffer RegisterForMidiMessages();
|
||||
void ReceiveMidiMessage(libremidi::message &&);
|
||||
|
||||
Reference in New Issue
Block a user