Skip to content

Commit 19fc52f

Browse files
committed
Add MIDI device name check
1 parent e74b531 commit 19fc52f

7 files changed

Lines changed: 324 additions & 63 deletions

File tree

data/locale/en-US.ini

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -545,7 +545,11 @@ AdvSceneSwitcher.condition.run="Run"
545545
AdvSceneSwitcher.condition.run.entry="Process exits before timeout of{{timeout}}seconds"
546546
AdvSceneSwitcher.condition.run.entry.exit="{{checkExitCode}}Check for exit code{{exitCode}}"
547547
AdvSceneSwitcher.condition.midi="MIDI"
548-
AdvSceneSwitcher.condition.midi.entry="Mesasge was received from{{device}}which matches:"
548+
AdvSceneSwitcher.condition.midi.condition.message="MIDI message was received"
549+
AdvSceneSwitcher.condition.midi.condition.deviceName="MIDI device is connected"
550+
AdvSceneSwitcher.condition.midi.condition.deviceName.info="On some platforms with certain APIs MIDI devices which were already disconnected might still be reported as connected.\nSo this type of check might not be 100% reliable in all circumstances."
551+
AdvSceneSwitcher.condition.midi.entry.message="{{conditions}}from{{device}}which matches:"
552+
AdvSceneSwitcher.condition.midi.entry.deviceName="{{conditions}}{{deviceNames}}{{regex}}{{deviceListInfo}}"
549553
AdvSceneSwitcher.condition.midi.entry.listen="Set MIDI message selection to messages incoming on selected device:{{listenButton}}"
550554
AdvSceneSwitcher.condition.display="Display"
551555
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
@@ -447,7 +447,6 @@ AdvSceneSwitcher.condition.run="Exécution"
447447
AdvSceneSwitcher.condition.run.entry="Le processus se termine avant le délai de{{timeout}}secondes"
448448
AdvSceneSwitcher.condition.run.entry.exit="{{checkExitCode}}Vérifier le code de sortie{{exitCode}}
449449
AdvSceneSwitcher.condition.midi="MIDI"
450-
AdvSceneSwitcher.condition.midi.entry="Message reçu depuis{{device}}qui correspond à :"
451450
AdvSceneSwitcher.condition.midi.entry.listen="Définir la sélection des messages MIDI pour les messages entrants sur l'appareil sélectionné :{{listenButton}}"
452451
AdvSceneSwitcher.condition.display="Affichage"
453452
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
@@ -435,7 +435,6 @@ AdvSceneSwitcher.condition.run="运行"
435435
AdvSceneSwitcher.condition.run.entry="进程在超时 {{timeout}} 秒之前退出"
436436
AdvSceneSwitcher.condition.run.entry.exit="{{checkExitCode}}检查退出代码{{exitCode}}"
437437
AdvSceneSwitcher.condition.midi="MIDI"
438-
AdvSceneSwitcher.condition.midi.entry="从{{device}} 收到的信息,符合:(从不咕咕的阿坤:这个好像是声卡工作是录音相关的功能,英文太抽象了,我就硬译过来了,如有相关设备,音乐好的,可以根据英文翻译好发给我!)"
439438
AdvSceneSwitcher.condition.midi.entry.listen="将MIDI信息选择设置为从选定设备上接收的信息: {{listenButton}}"
440439
AdvSceneSwitcher.condition.display="显示器"
441440
AdvSceneSwitcher.condition.display.type.displayName="连接的显示器的名称匹配"

plugins/midi/macro-condition-midi.cpp

Lines changed: 197 additions & 34 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;
27-
}
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-
}
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;
3832
}
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,45 @@ 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+
_deviceListInfo(new QLabel()),
175+
_listenLayout(new QHBoxLayout()),
176+
_entryLayout(new QHBoxLayout())
110177
{
178+
_deviceNames->addItems(GetDeviceNamesAsQStringList());
179+
_deviceNames->setEditable(true);
180+
181+
QString path = GetThemeTypeName() == "Light"
182+
? ":/res/images/help.svg"
183+
: ":/res/images/help_light.svg";
184+
QIcon icon(path);
185+
QPixmap pixmap = icon.pixmap(QSize(16, 16));
186+
_deviceListInfo->setPixmap(pixmap);
187+
_deviceListInfo->setToolTip(obs_module_text(
188+
"AdvSceneSwitcher.condition.midi.condition.deviceName.info"));
189+
190+
populateConditionSelection(_conditions);
191+
192+
QWidget::connect(_conditions, SIGNAL(currentIndexChanged(int)), this,
193+
SLOT(ConditionChanged(int)));
111194
QWidget::connect(_devices,
112195
SIGNAL(DeviceSelectionChanged(const MidiDevice &)),
113196
this,
@@ -121,19 +204,21 @@ MacroConditionMidiEdit::MacroConditionMidiEdit(
121204
SLOT(ToggleListen()));
122205
QWidget::connect(&_listenTimer, SIGNAL(timeout()), this,
123206
SLOT(SetMessageSelectionToLastReceived()));
207+
QWidget::connect(_deviceNames,
208+
SIGNAL(currentTextChanged(const QString &)), this,
209+
SLOT(DeviceNameChanged(const QString &)));
210+
QWidget::connect(_regex,
211+
SIGNAL(RegexConfigChanged(const RegexConfig &)), this,
212+
SLOT(RegexChanged(const RegexConfig &)));
124213

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

133218
auto mainLayout = new QVBoxLayout;
134-
mainLayout->addLayout(entryLayout);
219+
mainLayout->addLayout(_entryLayout);
135220
mainLayout->addWidget(_message);
136-
mainLayout->addLayout(listenLayout);
221+
mainLayout->addLayout(_listenLayout);
137222
mainLayout->addWidget(_resetMidiDevices);
138223
setLayout(mainLayout);
139224

@@ -155,11 +240,14 @@ void MacroConditionMidiEdit::UpdateEntryData()
155240
return;
156241
}
157242

243+
_conditions->setCurrentIndex(
244+
static_cast<int>(_entryData->GetCondition()));
158245
_message->SetMessage(_entryData->_message);
159246
_devices->SetDevice(_entryData->GetDevice());
160-
161-
adjustSize();
162-
updateGeometry();
247+
_deviceNames->setCurrentText(QString::fromStdString(
248+
_entryData->_deviceName.UnresolvedValue()));
249+
_regex->SetRegexConfig(_entryData->_regex);
250+
SetWidgetVisibility();
163251
}
164252

165253
void MacroConditionMidiEdit::DeviceSelectionChanged(const MidiDevice &device)
@@ -211,6 +299,46 @@ void MacroConditionMidiEdit::EnableListening(bool enable)
211299
}
212300
}
213301

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

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

0 commit comments

Comments
 (0)