Skip to content

Commit 5e5e574

Browse files
committed
Draft MIDI device names check
1 parent b17a6cc commit 5e5e574

File tree

7 files changed

+305
-62
lines changed

7 files changed

+305
-62
lines changed

data/locale/en-US.ini

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -542,7 +542,10 @@ AdvSceneSwitcher.condition.run="Run"
542542
AdvSceneSwitcher.condition.run.entry="Process exits before timeout of{{timeout}}seconds"
543543
AdvSceneSwitcher.condition.run.entry.exit="{{checkExitCode}}Check for exit code{{exitCode}}"
544544
AdvSceneSwitcher.condition.midi="MIDI"
545-
AdvSceneSwitcher.condition.midi.entry="Mesasge was received from{{device}}which matches:"
545+
AdvSceneSwitcher.condition.midi.condition.message="MIDI message was received"
546+
AdvSceneSwitcher.condition.midi.condition.deviceName="MIDI device is connected"
547+
AdvSceneSwitcher.condition.midi.entry.message="{{conditions}} from{{device}}which matches:"
548+
AdvSceneSwitcher.condition.midi.entry.deviceName="{{conditions}}{{deviceNames}}{{regex}}"
546549
AdvSceneSwitcher.condition.midi.entry.listen="Set MIDI message selection to messages incoming on selected device:{{listenButton}}"
547550
AdvSceneSwitcher.condition.display="Display"
548551
AdvSceneSwitcher.condition.display.type.displayName="Name of connected displays matches"

data/locale/fr-FR.ini

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -448,7 +448,6 @@ AdvSceneSwitcher.condition.run="Exécution"
448448
AdvSceneSwitcher.condition.run.entry="Le processus se termine avant le délai de{{timeout}}secondes"
449449
AdvSceneSwitcher.condition.run.entry.exit="{{checkExitCode}}Vérifier le code de sortie{{exitCode}}
450450
AdvSceneSwitcher.condition.midi="MIDI"
451-
AdvSceneSwitcher.condition.midi.entry="Message reçu depuis{{device}}qui correspond à :"
452451
AdvSceneSwitcher.condition.midi.entry.listen="Définir la sélection des messages MIDI pour les messages entrants sur l'appareil sélectionné :{{listenButton}}"
453452
AdvSceneSwitcher.condition.display="Affichage"
454453
AdvSceneSwitcher.condition.display.type.displayName="Le nom des écrans connectés correspond à"

data/locale/zh-CN.ini

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -436,7 +436,6 @@ AdvSceneSwitcher.condition.run="运行"
436436
AdvSceneSwitcher.condition.run.entry="进程在超时 {{timeout}} 秒之前退出"
437437
AdvSceneSwitcher.condition.run.entry.exit="{{checkExitCode}}检查退出代码{{exitCode}}"
438438
AdvSceneSwitcher.condition.midi="MIDI"
439-
AdvSceneSwitcher.condition.midi.entry="从{{device}} 收到的信息,符合:(从不咕咕的阿坤:这个好像是声卡工作是录音相关的功能,英文太抽象了,我就硬译过来了,如有相关设备,音乐好的,可以根据英文翻译好发给我!)"
440439
AdvSceneSwitcher.condition.midi.entry.listen="将MIDI信息选择设置为从选定设备上接收的信息: {{listenButton}}"
441440
AdvSceneSwitcher.condition.display="显示器"
442441
AdvSceneSwitcher.condition.display.type.displayName="连接的显示器的名称匹配"

plugins/midi/macro-condition-midi.cpp

Lines changed: 184 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -12,39 +12,35 @@ bool MacroConditionMidi::_registered = MacroConditionFactory::Register(
1212
{MacroConditionMidi::Create, MacroConditionMidiEdit::Create,
1313
"AdvSceneSwitcher.condition.midi"});
1414

15+
static const std::map<MacroConditionMidi::Condition, std::string>
16+
conditionTypes = {
17+
{MacroConditionMidi::Condition::MIDI_MESSAGE,
18+
"AdvSceneSwitcher.condition.midi.condition.message"},
19+
{MacroConditionMidi::Condition::MIDI_CONNECTED_DEVICE_NAMES,
20+
"AdvSceneSwitcher.condition.midi.condition.deviceName"},
21+
};
22+
1523
bool MacroConditionMidi::CheckCondition()
1624
{
17-
if (!_messageBuffer) {
18-
return false;
19-
}
20-
21-
const bool macroWasPausedSinceLastCheck =
22-
MacroWasPausedSince(GetMacro(), _lastCheck);
23-
_lastCheck = std::chrono::high_resolution_clock::now();
24-
if (macroWasPausedSinceLastCheck) {
25-
_messageBuffer->Clear();
26-
return false;
25+
switch (_condition) {
26+
case Condition::MIDI_MESSAGE:
27+
return CheckMessage();
28+
case Condition::MIDI_CONNECTED_DEVICE_NAMES:
29+
return CheckConnectedDevcieNames();
30+
default:
31+
break;
2732
}
28-
29-
while (!_messageBuffer->Empty()) {
30-
auto message = _messageBuffer->ConsumeMessage();
31-
if (!message) {
32-
continue;
33-
}
34-
if (message->Matches(_message)) {
35-
SetVariableValues(*message);
36-
return true;
37-
}
38-
}
39-
4033
return false;
4134
}
4235

4336
bool MacroConditionMidi::Save(obs_data_t *obj) const
4437
{
4538
MacroCondition::Save(obj);
39+
obs_data_set_int(obj, "condition", static_cast<int>(_condition));
4640
_message.Save(obj);
4741
_device.Save(obj);
42+
_deviceName.Save(obj, "deviceName");
43+
_regex.Save(obj);
4844
return true;
4945
}
5046

@@ -53,7 +49,10 @@ bool MacroConditionMidi::Load(obs_data_t *obj)
5349
MacroCondition::Load(obj);
5450
_message.Load(obj);
5551
_device.Load(obj);
56-
_messageBuffer = _device.RegisterForMidiMessages();
52+
_deviceName.Load(obj, "deviceName");
53+
_regex.Load(obj);
54+
SetCondition(
55+
static_cast<Condition>(obs_data_get_int(obj, "condition")));
5756
return true;
5857
}
5958

@@ -68,9 +67,64 @@ void MacroConditionMidi::SetDevice(const MidiDevice &dev)
6867
_messageBuffer = dev.RegisterForMidiMessages();
6968
}
7069

70+
void MacroConditionMidi::SetCondition(Condition condition)
71+
{
72+
_condition = condition;
73+
if (_condition == Condition::MIDI_MESSAGE) {
74+
_messageBuffer = _device.RegisterForMidiMessages();
75+
}
76+
SetupTempVars();
77+
}
78+
79+
bool MacroConditionMidi::CheckMessage()
80+
{
81+
if (!_messageBuffer) {
82+
return false;
83+
}
84+
85+
const bool macroWasPausedSinceLastCheck =
86+
MacroWasPausedSince(GetMacro(), _lastCheck);
87+
_lastCheck = std::chrono::high_resolution_clock::now();
88+
if (macroWasPausedSinceLastCheck) {
89+
_messageBuffer->Clear();
90+
return false;
91+
}
92+
93+
while (!_messageBuffer->Empty()) {
94+
auto message = _messageBuffer->ConsumeMessage();
95+
if (!message) {
96+
continue;
97+
}
98+
if (message->Matches(_message)) {
99+
SetVariableValues(*message);
100+
return true;
101+
}
102+
}
103+
104+
return false;
105+
}
106+
107+
bool MacroConditionMidi::CheckConnectedDevcieNames()
108+
{
109+
auto deviceNames = GetDeviceNames();
110+
if (!_regex.Enabled()) {
111+
return std::find(deviceNames.begin(), deviceNames.end(),
112+
std::string(_deviceName)) != deviceNames.end();
113+
}
114+
for (const auto &deviceName : deviceNames) {
115+
if (_regex.Matches(deviceName, _deviceName)) {
116+
return true;
117+
}
118+
}
119+
return false;
120+
}
121+
71122
void MacroConditionMidi::SetupTempVars()
72123
{
73124
MacroCondition::SetupTempVars();
125+
if (_condition == Condition::MIDI_CONNECTED_DEVICE_NAMES) {
126+
return;
127+
}
74128
AddTempvar("type",
75129
obs_module_text("AdvSceneSwitcher.tempVar.midi.type"));
76130
AddTempvar("channel",
@@ -98,16 +152,35 @@ void MacroConditionMidi::SetVariableValues(const MidiMessage &m)
98152
SetTempVarValue("value2", std::to_string(m.Value()));
99153
}
100154

155+
static void populateConditionSelection(QComboBox *list)
156+
{
157+
for (const auto &[_, name] : conditionTypes) {
158+
list->addItem(obs_module_text(name.c_str()));
159+
}
160+
}
161+
101162
MacroConditionMidiEdit::MacroConditionMidiEdit(
102163
QWidget *parent, std::shared_ptr<MacroConditionMidi> entryData)
103164
: QWidget(parent),
165+
_conditions(new QComboBox()),
104166
_devices(new MidiDeviceSelection(this, MidiDeviceType::INPUT)),
105167
_message(new MidiMessageSelection(this)),
106168
_resetMidiDevices(new QPushButton(
107169
obs_module_text("AdvSceneSwitcher.midi.resetDevices"))),
108170
_listen(new QPushButton(
109-
obs_module_text("AdvSceneSwitcher.midi.startListen")))
171+
obs_module_text("AdvSceneSwitcher.midi.startListen"))),
172+
_deviceNames(new QComboBox()),
173+
_regex(new RegexConfigWidget()),
174+
_listenLayout(new QHBoxLayout()),
175+
_entryLayout(new QHBoxLayout())
110176
{
177+
_deviceNames->addItems(GetDeviceNamesAsQStringList());
178+
_deviceNames->setEditable(true);
179+
180+
populateConditionSelection(_conditions);
181+
182+
QWidget::connect(_conditions, SIGNAL(currentIndexChanged(int)), this,
183+
SLOT(ConditionChanged(int)));
111184
QWidget::connect(_devices,
112185
SIGNAL(DeviceSelectionChanged(const MidiDevice &)),
113186
this,
@@ -121,19 +194,17 @@ MacroConditionMidiEdit::MacroConditionMidiEdit(
121194
SLOT(ToggleListen()));
122195
QWidget::connect(&_listenTimer, SIGNAL(timeout()), this,
123196
SLOT(SetMessageSelectionToLastReceived()));
124-
125-
auto entryLayout = new QHBoxLayout;
126-
PlaceWidgets(obs_module_text("AdvSceneSwitcher.condition.midi.entry"),
127-
entryLayout, {{"{{device}}", _devices}});
128-
auto listenLayout = new QHBoxLayout;
129-
PlaceWidgets(
130-
obs_module_text("AdvSceneSwitcher.condition.midi.entry.listen"),
131-
listenLayout, {{"{{listenButton}}", _listen}});
197+
QWidget::connect(_deviceNames,
198+
SIGNAL(currentTextChanged(const QString &)), this,
199+
SLOT(DeviceNameChanged(const QString &)));
200+
QWidget::connect(_regex,
201+
SIGNAL(RegexConfigChanged(const RegexConfig &)), this,
202+
SLOT(RegexChanged(const RegexConfig &)));
132203

133204
auto mainLayout = new QVBoxLayout;
134-
mainLayout->addLayout(entryLayout);
205+
mainLayout->addLayout(_entryLayout);
135206
mainLayout->addWidget(_message);
136-
mainLayout->addLayout(listenLayout);
207+
mainLayout->addLayout(_listenLayout);
137208
mainLayout->addWidget(_resetMidiDevices);
138209
setLayout(mainLayout);
139210

@@ -155,11 +226,14 @@ void MacroConditionMidiEdit::UpdateEntryData()
155226
return;
156227
}
157228

229+
_conditions->setCurrentIndex(
230+
static_cast<int>(_entryData->GetCondition()));
158231
_message->SetMessage(_entryData->_message);
159232
_devices->SetDevice(_entryData->GetDevice());
160-
161-
adjustSize();
162-
updateGeometry();
233+
_deviceNames->setCurrentText(QString::fromStdString(
234+
_entryData->_deviceName.UnresolvedValue()));
235+
_regex->SetRegexConfig(_entryData->_regex);
236+
SetWidgetVisibility();
163237
}
164238

165239
void MacroConditionMidiEdit::DeviceSelectionChanged(const MidiDevice &device)
@@ -211,6 +285,44 @@ void MacroConditionMidiEdit::EnableListening(bool enable)
211285
}
212286
}
213287

288+
void MacroConditionMidiEdit::SetWidgetVisibility()
289+
{
290+
_entryLayout->removeWidget(_conditions);
291+
_entryLayout->removeWidget(_devices);
292+
_entryLayout->removeWidget(_deviceNames);
293+
_entryLayout->removeWidget(_regex);
294+
295+
ClearLayout(_entryLayout);
296+
297+
std::unordered_map<std::string, QWidget *> widgetPlaceholders = {
298+
{"{{conditions}}", _conditions},
299+
{"{{device}}", _devices},
300+
{"{{deviceNames}}", _deviceNames},
301+
{"{{regex}}", _regex},
302+
};
303+
304+
const bool isMessageCheck = _entryData->GetCondition() ==
305+
MacroConditionMidi::Condition::MIDI_MESSAGE;
306+
307+
auto layoutString =
308+
isMessageCheck
309+
? "AdvSceneSwitcher.condition.midi.entry.message"
310+
: "AdvSceneSwitcher.condition.midi.entry.deviceName";
311+
312+
PlaceWidgets(obs_module_text(layoutString), _entryLayout,
313+
widgetPlaceholders);
314+
315+
SetLayoutVisible(_listenLayout, isMessageCheck);
316+
_devices->setVisible(isMessageCheck);
317+
_message->setVisible(isMessageCheck);
318+
_resetMidiDevices->setVisible(isMessageCheck);
319+
_deviceNames->setVisible(!isMessageCheck);
320+
_regex->setVisible(!isMessageCheck);
321+
322+
adjustSize();
323+
updateGeometry();
324+
}
325+
214326
void MacroConditionMidiEdit::ToggleListen()
215327
{
216328
if (!_entryData) {
@@ -249,4 +361,39 @@ void MacroConditionMidiEdit::SetMessageSelectionToLastReceived()
249361
_entryData->_message = *message;
250362
}
251363

364+
void MacroConditionMidiEdit::ConditionChanged(int value)
365+
{
366+
if (_loading || !_entryData) {
367+
return;
368+
}
369+
370+
auto lock = LockContext();
371+
_entryData->SetCondition(
372+
static_cast<MacroConditionMidi::Condition>(value));
373+
SetWidgetVisibility();
374+
}
375+
376+
void MacroConditionMidiEdit::DeviceNameChanged(const QString &deviceName)
377+
{
378+
if (_loading || !_entryData) {
379+
return;
380+
}
381+
382+
auto lock = LockContext();
383+
_entryData->_deviceName = deviceName.toStdString();
384+
}
385+
386+
void MacroConditionMidiEdit::RegexChanged(const RegexConfig &conf)
387+
{
388+
if (_loading || !_entryData) {
389+
return;
390+
}
391+
392+
auto lock = LockContext();
393+
_entryData->_regex = conf;
394+
395+
adjustSize();
396+
updateGeometry();
397+
}
398+
252399
} // namespace advss

plugins/midi/macro-condition-midi.hpp

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
#pragma once
22
#include "macro-condition-edit.hpp"
33
#include "midi-helpers.hpp"
4+
#include "regex-config.hpp"
5+
#include "variable-line-edit.hpp"
46

57
#include <QPushButton>
68
#include <QTimer>
@@ -23,11 +25,23 @@ class MacroConditionMidi : public MacroCondition {
2325
void SetDevice(const MidiDevice &dev);
2426
const MidiDevice &GetDevice() const { return _device; }
2527
MidiMessage _message;
28+
StringVariable _deviceName;
29+
RegexConfig _regex;
30+
31+
enum class Condition {
32+
MIDI_MESSAGE,
33+
MIDI_CONNECTED_DEVICE_NAMES,
34+
};
35+
void SetCondition(Condition);
36+
Condition GetCondition() const { return _condition; }
2637

2738
private:
39+
bool CheckMessage();
40+
bool CheckConnectedDevcieNames();
2841
void SetupTempVars();
2942
void SetVariableValues(const MidiMessage &);
3043

44+
Condition _condition = Condition::MIDI_MESSAGE;
3145
MidiDevice _device;
3246
MidiMessageBuffer _messageBuffer;
3347
std::chrono::high_resolution_clock::time_point _lastCheck{};
@@ -58,18 +72,28 @@ private slots:
5872
void ResetMidiDevices();
5973
void ToggleListen();
6074
void SetMessageSelectionToLastReceived();
75+
void ConditionChanged(int);
76+
void DeviceNameChanged(const QString &);
77+
void RegexChanged(const RegexConfig &);
6178
signals:
6279
void HeaderInfoChanged(const QString &);
6380

6481
private:
6582
void EnableListening(bool);
83+
void SetWidgetVisibility();
6684

6785
std::shared_ptr<MacroConditionMidi> _entryData;
6886

87+
QComboBox *_conditions;
6988
MidiDeviceSelection *_devices;
7089
MidiMessageSelection *_message;
7190
QPushButton *_resetMidiDevices;
7291
QPushButton *_listen;
92+
QComboBox *_deviceNames;
93+
RegexConfigWidget *_regex;
94+
QHBoxLayout *_listenLayout;
95+
QHBoxLayout *_entryLayout;
96+
7397
QTimer _listenTimer;
7498
MidiMessageBuffer _messageBuffer;
7599
bool _currentlyListening = false;

0 commit comments

Comments
 (0)