Compare commits

...

10 Commits

Author SHA1 Message Date
WarmUpTill
70dad8ebb4 Handle MIDI device disconnect and reconnect 2024-03-09 12:00:52 +01:00
WarmUpTill
497b3b3e04 Clean up macro import and add action queues 2024-03-09 12:00:52 +01:00
WarmUpTill
891811aa47 Convert audio volume thresholds to new format 2024-03-09 09:18:29 +01:00
WarmUpTill
be9ddaa4c9 Increase precision of percent based volume threshold input 2024-03-09 09:18:29 +01:00
WarmUpTill
03494c2915 Adapt to volume widget slider changes 2024-03-09 09:18:29 +01:00
WarmUpTill
bcf7c247bf Increase precision of volume widget slider 2024-03-09 09:18:29 +01:00
WarmUpTill
132d89b350 Fix virtual camera action selection causing a crash
The Create() and Copy() functions were not correctly implemented and
returned a nullptr
2024-03-06 12:53:43 +01:00
WarmUpTill
daf16357c9 Fix output volume check of audio condition not working
Only the percent based selection was not working properly since the
calculation was off by a factor of 100.
2024-03-03 20:54:15 +01:00
WarmUpTill
8080abc93c Fix crash when opening setting window 2024-03-03 20:54:15 +01:00
WarmUpTill
902715bd3e Save settings when switching to new macro
This should ensure that settings are saved more frequently and less data
is lost in case the plugin crashes with the settings dialog opened.
2024-03-03 20:54:15 +01:00
18 changed files with 341 additions and 90 deletions

View File

@@ -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

View File

@@ -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)

View File

@@ -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;

View File

@@ -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"
@@ -13,6 +14,7 @@
#include "utility.hpp"
#include "version.h"
#include <obs-frontend-api.h>
#include <QColor>
#include <QGraphicsOpacityEffect>
#include <QMenu>
@@ -247,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);
@@ -369,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;
@@ -403,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) {
@@ -424,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)) {
@@ -729,6 +714,7 @@ void AdvSceneSwitcher::MacroSelectionChanged()
return;
}
SetEditMacro(*macro);
obs_frontend_save();
}
void AdvSceneSwitcher::HighlightOnChange()

View File

@@ -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) {

View File

@@ -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> &);

View 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

View 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

View File

@@ -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);

View File

@@ -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:

View File

@@ -102,7 +102,6 @@ static void removeVariableRow(QTableWidget *table, const QString &name)
static void updateVaribleStatus(QTableWidget *table)
{
auto lock = LockContext();
for (int row = 0; row < table->rowCount(); row++) {
auto item = table->item(row, 0);
if (!item) {

View File

@@ -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(

View File

@@ -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();

View File

@@ -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)

View File

@@ -67,7 +67,7 @@ bool MacroConditionAudio::CheckOutputCondition()
OBSSourceAutoRelease source =
obs_weak_source_get_source(_audioSource.GetSource());
double curVolume = _useDb ? _peak : DecibelToPercent(_peak);
double curVolume = _useDb ? _peak : DecibelToPercent(_peak) * 100;
switch (_outputCondition) {
case OutputCondition::ABOVE:
@@ -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);
}
}

View File

@@ -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;

View File

@@ -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"));

View File

@@ -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 &&);