Skip to content

Commit c7afdd8

Browse files
committed
Add MIDI device name check
1 parent efaf9a2 commit c7afdd8

File tree

7 files changed

+336
-53
lines changed

7 files changed

+336
-53
lines changed

data/locale/en-US.ini

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -592,7 +592,15 @@ AdvSceneSwitcher.condition.run="Run"
592592
AdvSceneSwitcher.condition.run.entry="Process exits before timeout of{{timeout}}seconds"
593593
AdvSceneSwitcher.condition.run.entry.exit="{{checkExitCode}}Check for exit code{{exitCode}}"
594594
AdvSceneSwitcher.condition.midi="MIDI"
595+
<<<<<<< HEAD
595596
AdvSceneSwitcher.condition.midi.entry="Message was received from{{device}}which matches:"
597+
=======
598+
AdvSceneSwitcher.condition.midi.condition.message="MIDI message was received"
599+
AdvSceneSwitcher.condition.midi.condition.deviceName="MIDI device is connected"
600+
AdvSceneSwitcher.condition.midi.condition.deviceName.info="On some platforms with certain APIs dynamic MIDI device detection might not function.\nSo this type of check might not be 100% reliable in all circumstances."
601+
AdvSceneSwitcher.condition.midi.entry.message="{{conditions}}from{{device}}which matches:"
602+
AdvSceneSwitcher.condition.midi.entry.deviceName="{{conditions}}{{deviceNames}}{{regex}}{{deviceListInfo}}"
603+
>>>>>>> c4e35d1a (Add MIDI device name check)
596604
AdvSceneSwitcher.condition.midi.entry.listen="Set MIDI message selection to messages incoming on selected device:{{listenButton}}"
597605
AdvSceneSwitcher.condition.display="Display"
598606
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
@@ -446,7 +446,6 @@ AdvSceneSwitcher.condition.run="Exécution"
446446
AdvSceneSwitcher.condition.run.entry="Le processus se termine avant le délai de{{timeout}}secondes"
447447
AdvSceneSwitcher.condition.run.entry.exit="{{checkExitCode}}Vérifier le code de sortie{{exitCode}}
448448
AdvSceneSwitcher.condition.midi="MIDI"
449-
AdvSceneSwitcher.condition.midi.entry="Message reçu depuis{{device}}qui correspond à :"
450449
AdvSceneSwitcher.condition.midi.entry.listen="Définir la sélection des messages MIDI pour les messages entrants sur l'appareil sélectionné :{{listenButton}}"
451450
AdvSceneSwitcher.condition.display="Affichage"
452451
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
@@ -434,7 +434,6 @@ AdvSceneSwitcher.condition.run="运行"
434434
AdvSceneSwitcher.condition.run.entry="进程在超时 {{timeout}} 秒之前退出"
435435
AdvSceneSwitcher.condition.run.entry.exit="{{checkExitCode}}检查退出代码{{exitCode}}"
436436
AdvSceneSwitcher.condition.midi="MIDI"
437-
AdvSceneSwitcher.condition.midi.entry="从{{device}} 收到的信息,符合:(从不咕咕的阿坤:这个好像是声卡工作是录音相关的功能,英文太抽象了,我就硬译过来了,如有相关设备,音乐好的,可以根据英文翻译好发给我!)"
438437
AdvSceneSwitcher.condition.midi.entry.listen="将MIDI信息选择设置为从选定设备上接收的信息: {{listenButton}}"
439438
AdvSceneSwitcher.condition.display="显示器"
440439
AdvSceneSwitcher.condition.display.type.displayName="连接的显示器的名称匹配"

plugins/midi/macro-condition-midi.cpp

Lines changed: 202 additions & 35 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,13 +49,18 @@ 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

6059
std::string MacroConditionMidi::GetShortDesc() const
6160
{
62-
return _device.Name();
61+
return _condition == MacroConditionMidi::Condition::MIDI_MESSAGE
62+
? _device.Name()
63+
: "";
6364
}
6465

6566
void MacroConditionMidi::SetDevice(const MidiDevice &dev)
@@ -68,9 +69,64 @@ void MacroConditionMidi::SetDevice(const MidiDevice &dev)
6869
_messageBuffer = dev.RegisterForMidiMessages();
6970
}
7071

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

157+
static void populateConditionSelection(QComboBox *list)
158+
{
159+
for (const auto &[_, name] : conditionTypes) {
160+
list->addItem(obs_module_text(name.c_str()));
161+
}
162+
}
163+
101164
MacroConditionMidiEdit::MacroConditionMidiEdit(
102165
QWidget *parent, std::shared_ptr<MacroConditionMidi> entryData)
103166
: QWidget(parent),
167+
_conditions(new QComboBox()),
104168
_devices(new MidiDeviceSelection(this, MidiDeviceType::INPUT)),
105169
_message(new MidiMessageSelection(this)),
106170
_resetMidiDevices(new QPushButton(
107171
obs_module_text("AdvSceneSwitcher.midi.resetDevices"))),
108172
_listen(new QPushButton(
109-
obs_module_text("AdvSceneSwitcher.midi.startListen")))
173+
obs_module_text("AdvSceneSwitcher.midi.startListen"))),
174+
_deviceNames(new QComboBox()),
175+
_regex(new RegexConfigWidget()),
176+
_deviceListInfo(new QLabel()),
177+
_listenLayout(new QHBoxLayout()),
178+
_entryLayout(new QHBoxLayout())
110179
{
180+
_deviceNames->addItems(GetDeviceNamesAsQStringList());
181+
_deviceNames->setEditable(true);
182+
183+
QString path = GetThemeTypeName() == "Light"
184+
? ":/res/images/help.svg"
185+
: ":/res/images/help_light.svg";
186+
QIcon icon(path);
187+
QPixmap pixmap = icon.pixmap(QSize(16, 16));
188+
_deviceListInfo->setPixmap(pixmap);
189+
_deviceListInfo->setToolTip(obs_module_text(
190+
"AdvSceneSwitcher.condition.midi.condition.deviceName.info"));
191+
192+
populateConditionSelection(_conditions);
193+
194+
QWidget::connect(_conditions, SIGNAL(currentIndexChanged(int)), this,
195+
SLOT(ConditionChanged(int)));
111196
QWidget::connect(_devices,
112197
SIGNAL(DeviceSelectionChanged(const MidiDevice &)),
113198
this,
@@ -121,19 +206,21 @@ MacroConditionMidiEdit::MacroConditionMidiEdit(
121206
SLOT(ToggleListen()));
122207
QWidget::connect(&_listenTimer, SIGNAL(timeout()), this,
123208
SLOT(SetMessageSelectionToLastReceived()));
209+
QWidget::connect(_deviceNames,
210+
SIGNAL(currentTextChanged(const QString &)), this,
211+
SLOT(DeviceNameChanged(const QString &)));
212+
QWidget::connect(_regex,
213+
SIGNAL(RegexConfigChanged(const RegexConfig &)), this,
214+
SLOT(RegexChanged(const RegexConfig &)));
124215

125-
auto entryLayout = new QHBoxLayout;
126-
PlaceWidgets(obs_module_text("AdvSceneSwitcher.condition.midi.entry"),
127-
entryLayout, {{"{{device}}", _devices}});
128-
auto listenLayout = new QHBoxLayout;
129216
PlaceWidgets(
130217
obs_module_text("AdvSceneSwitcher.condition.midi.entry.listen"),
131-
listenLayout, {{"{{listenButton}}", _listen}});
218+
_listenLayout, {{"{{listenButton}}", _listen}});
132219

133220
auto mainLayout = new QVBoxLayout;
134-
mainLayout->addLayout(entryLayout);
221+
mainLayout->addLayout(_entryLayout);
135222
mainLayout->addWidget(_message);
136-
mainLayout->addLayout(listenLayout);
223+
mainLayout->addLayout(_listenLayout);
137224
mainLayout->addWidget(_resetMidiDevices);
138225
setLayout(mainLayout);
139226

@@ -155,11 +242,14 @@ void MacroConditionMidiEdit::UpdateEntryData()
155242
return;
156243
}
157244

245+
_conditions->setCurrentIndex(
246+
static_cast<int>(_entryData->GetCondition()));
158247
_message->SetMessage(_entryData->_message);
159248
_devices->SetDevice(_entryData->GetDevice());
160-
161-
adjustSize();
162-
updateGeometry();
249+
_deviceNames->setCurrentText(QString::fromStdString(
250+
_entryData->_deviceName.UnresolvedValue()));
251+
_regex->SetRegexConfig(_entryData->_regex);
252+
SetWidgetVisibility();
163253
}
164254

165255
void MacroConditionMidiEdit::DeviceSelectionChanged(const MidiDevice &device)
@@ -211,6 +301,46 @@ void MacroConditionMidiEdit::EnableListening(bool enable)
211301
}
212302
}
213303

304+
void MacroConditionMidiEdit::SetWidgetVisibility()
305+
{
306+
_entryLayout->removeWidget(_conditions);
307+
_entryLayout->removeWidget(_devices);
308+
_entryLayout->removeWidget(_deviceNames);
309+
_entryLayout->removeWidget(_regex);
310+
311+
ClearLayout(_entryLayout);
312+
313+
std::unordered_map<std::string, QWidget *> widgetPlaceholders = {
314+
{"{{conditions}}", _conditions},
315+
{"{{device}}", _devices},
316+
{"{{deviceNames}}", _deviceNames},
317+
{"{{regex}}", _regex},
318+
{"{{deviceListInfo}}", _deviceListInfo},
319+
};
320+
321+
const bool isMessageCheck = _entryData->GetCondition() ==
322+
MacroConditionMidi::Condition::MIDI_MESSAGE;
323+
324+
auto layoutString =
325+
isMessageCheck
326+
? "AdvSceneSwitcher.condition.midi.entry.message"
327+
: "AdvSceneSwitcher.condition.midi.entry.deviceName";
328+
329+
PlaceWidgets(obs_module_text(layoutString), _entryLayout,
330+
widgetPlaceholders);
331+
332+
SetLayoutVisible(_listenLayout, isMessageCheck);
333+
_devices->setVisible(isMessageCheck);
334+
_message->setVisible(isMessageCheck);
335+
_resetMidiDevices->setVisible(isMessageCheck);
336+
_deviceNames->setVisible(!isMessageCheck);
337+
_regex->setVisible(!isMessageCheck);
338+
_deviceListInfo->setVisible(!isMessageCheck);
339+
340+
adjustSize();
341+
updateGeometry();
342+
}
343+
214344
void MacroConditionMidiEdit::ToggleListen()
215345
{
216346
if (!_entryData) {
@@ -249,4 +379,41 @@ void MacroConditionMidiEdit::SetMessageSelectionToLastReceived()
249379
_entryData->_message = *message;
250380
}
251381

382+
void MacroConditionMidiEdit::ConditionChanged(int value)
383+
{
384+
if (_loading || !_entryData) {
385+
return;
386+
}
387+
388+
auto lock = LockContext();
389+
_entryData->SetCondition(
390+
static_cast<MacroConditionMidi::Condition>(value));
391+
SetWidgetVisibility();
392+
emit HeaderInfoChanged(
393+
QString::fromStdString(_entryData->GetShortDesc()));
394+
}
395+
396+
void MacroConditionMidiEdit::DeviceNameChanged(const QString &deviceName)
397+
{
398+
if (_loading || !_entryData) {
399+
return;
400+
}
401+
402+
auto lock = LockContext();
403+
_entryData->_deviceName = deviceName.toStdString();
404+
}
405+
406+
void MacroConditionMidiEdit::RegexChanged(const RegexConfig &conf)
407+
{
408+
if (_loading || !_entryData) {
409+
return;
410+
}
411+
412+
auto lock = LockContext();
413+
_entryData->_regex = conf;
414+
415+
adjustSize();
416+
updateGeometry();
417+
}
418+
252419
} // namespace advss

0 commit comments

Comments
 (0)