Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft MIDI device names check #1059

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions data/locale/en-US.ini
Original file line number Diff line number Diff line change
Expand Up @@ -592,7 +592,15 @@ AdvSceneSwitcher.condition.run="Run"
AdvSceneSwitcher.condition.run.entry="Process exits before timeout of{{timeout}}seconds"
AdvSceneSwitcher.condition.run.entry.exit="{{checkExitCode}}Check for exit code{{exitCode}}"
AdvSceneSwitcher.condition.midi="MIDI"
<<<<<<< HEAD
AdvSceneSwitcher.condition.midi.entry="Message was received from{{device}}which matches:"
=======
AdvSceneSwitcher.condition.midi.condition.message="MIDI message was received"
AdvSceneSwitcher.condition.midi.condition.deviceName="MIDI device is connected"
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."
AdvSceneSwitcher.condition.midi.entry.message="{{conditions}}from{{device}}which matches:"
AdvSceneSwitcher.condition.midi.entry.deviceName="{{conditions}}{{deviceNames}}{{regex}}{{deviceListInfo}}"
>>>>>>> c4e35d1a (Add MIDI device name check)
AdvSceneSwitcher.condition.midi.entry.listen="Set MIDI message selection to messages incoming on selected device:{{listenButton}}"
AdvSceneSwitcher.condition.display="Display"
AdvSceneSwitcher.condition.display.type.displayName="Name of connected displays matches"
Expand Down
1 change: 0 additions & 1 deletion data/locale/fr-FR.ini
Original file line number Diff line number Diff line change
Expand Up @@ -446,7 +446,6 @@ AdvSceneSwitcher.condition.run="Exécution"
AdvSceneSwitcher.condition.run.entry="Le processus se termine avant le délai de{{timeout}}secondes"
AdvSceneSwitcher.condition.run.entry.exit="{{checkExitCode}}Vérifier le code de sortie{{exitCode}}
AdvSceneSwitcher.condition.midi="MIDI"
AdvSceneSwitcher.condition.midi.entry="Message reçu depuis{{device}}qui correspond à :"
AdvSceneSwitcher.condition.midi.entry.listen="Définir la sélection des messages MIDI pour les messages entrants sur l'appareil sélectionné :{{listenButton}}"
AdvSceneSwitcher.condition.display="Affichage"
AdvSceneSwitcher.condition.display.type.displayName="Le nom des écrans connectés correspond à"
Expand Down
1 change: 0 additions & 1 deletion data/locale/zh-CN.ini
Original file line number Diff line number Diff line change
Expand Up @@ -434,7 +434,6 @@ AdvSceneSwitcher.condition.run="运行"
AdvSceneSwitcher.condition.run.entry="进程在超时 {{timeout}} 秒之前退出"
AdvSceneSwitcher.condition.run.entry.exit="{{checkExitCode}}检查退出代码{{exitCode}}"
AdvSceneSwitcher.condition.midi="MIDI"
AdvSceneSwitcher.condition.midi.entry="从{{device}} 收到的信息,符合:(从不咕咕的阿坤:这个好像是声卡工作是录音相关的功能,英文太抽象了,我就硬译过来了,如有相关设备,音乐好的,可以根据英文翻译好发给我!)"
AdvSceneSwitcher.condition.midi.entry.listen="将MIDI信息选择设置为从选定设备上接收的信息: {{listenButton}}"
AdvSceneSwitcher.condition.display="显示器"
AdvSceneSwitcher.condition.display.type.displayName="连接的显示器的名称匹配"
Expand Down
237 changes: 202 additions & 35 deletions plugins/midi/macro-condition-midi.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,39 +12,35 @@ bool MacroConditionMidi::_registered = MacroConditionFactory::Register(
{MacroConditionMidi::Create, MacroConditionMidiEdit::Create,
"AdvSceneSwitcher.condition.midi"});

static const std::map<MacroConditionMidi::Condition, std::string>
conditionTypes = {
{MacroConditionMidi::Condition::MIDI_MESSAGE,
"AdvSceneSwitcher.condition.midi.condition.message"},
{MacroConditionMidi::Condition::MIDI_CONNECTED_DEVICE_NAMES,
"AdvSceneSwitcher.condition.midi.condition.deviceName"},
};

bool MacroConditionMidi::CheckCondition()
{
if (!_messageBuffer) {
return false;
}

const bool macroWasPausedSinceLastCheck =
MacroWasPausedSince(GetMacro(), _lastCheck);
_lastCheck = std::chrono::high_resolution_clock::now();
if (macroWasPausedSinceLastCheck) {
_messageBuffer->Clear();
return false;
switch (_condition) {
case Condition::MIDI_MESSAGE:
return CheckMessage();
case Condition::MIDI_CONNECTED_DEVICE_NAMES:
return CheckConnectedDevcieNames();
default:
break;
}

while (!_messageBuffer->Empty()) {
auto message = _messageBuffer->ConsumeMessage();
if (!message) {
continue;
}
if (message->Matches(_message)) {
SetVariableValues(*message);
return true;
}
}

return false;
}

bool MacroConditionMidi::Save(obs_data_t *obj) const
{
MacroCondition::Save(obj);
obs_data_set_int(obj, "condition", static_cast<int>(_condition));
_message.Save(obj);
_device.Save(obj);
_deviceName.Save(obj, "deviceName");
_regex.Save(obj);
return true;
}

Expand All @@ -53,13 +49,18 @@ bool MacroConditionMidi::Load(obs_data_t *obj)
MacroCondition::Load(obj);
_message.Load(obj);
_device.Load(obj);
_messageBuffer = _device.RegisterForMidiMessages();
_deviceName.Load(obj, "deviceName");
_regex.Load(obj);
SetCondition(
static_cast<Condition>(obs_data_get_int(obj, "condition")));
return true;
}

std::string MacroConditionMidi::GetShortDesc() const
{
return _device.Name();
return _condition == MacroConditionMidi::Condition::MIDI_MESSAGE
? _device.Name()
: "";
}

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

void MacroConditionMidi::SetCondition(Condition condition)
{
_condition = condition;
if (_condition == Condition::MIDI_MESSAGE) {
_messageBuffer = _device.RegisterForMidiMessages();
}
SetupTempVars();
}

bool MacroConditionMidi::CheckMessage()
{
if (!_messageBuffer) {
return false;
}

const bool macroWasPausedSinceLastCheck =
MacroWasPausedSince(GetMacro(), _lastCheck);
_lastCheck = std::chrono::high_resolution_clock::now();
if (macroWasPausedSinceLastCheck) {
_messageBuffer->Clear();
return false;
}

while (!_messageBuffer->Empty()) {
auto message = _messageBuffer->ConsumeMessage();
if (!message) {
continue;
}
if (message->Matches(_message)) {
SetVariableValues(*message);
return true;
}
}

return false;
}

bool MacroConditionMidi::CheckConnectedDevcieNames()
{
auto deviceNames = GetDeviceNames();
if (!_regex.Enabled()) {
return std::find(deviceNames.begin(), deviceNames.end(),
std::string(_deviceName)) != deviceNames.end();
}
for (const auto &deviceName : deviceNames) {
if (_regex.Matches(deviceName, _deviceName)) {
return true;
}
}
return false;
}

void MacroConditionMidi::SetupTempVars()
{
MacroCondition::SetupTempVars();
if (_condition == Condition::MIDI_CONNECTED_DEVICE_NAMES) {
return;
}
AddTempvar("type",
obs_module_text("AdvSceneSwitcher.tempVar.midi.type"));
AddTempvar("channel",
Expand Down Expand Up @@ -98,16 +154,45 @@ void MacroConditionMidi::SetVariableValues(const MidiMessage &m)
SetTempVarValue("value2", std::to_string(m.Value()));
}

static void populateConditionSelection(QComboBox *list)
{
for (const auto &[_, name] : conditionTypes) {
list->addItem(obs_module_text(name.c_str()));
}
}

MacroConditionMidiEdit::MacroConditionMidiEdit(
QWidget *parent, std::shared_ptr<MacroConditionMidi> entryData)
: QWidget(parent),
_conditions(new QComboBox()),
_devices(new MidiDeviceSelection(this, MidiDeviceType::INPUT)),
_message(new MidiMessageSelection(this)),
_resetMidiDevices(new QPushButton(
obs_module_text("AdvSceneSwitcher.midi.resetDevices"))),
_listen(new QPushButton(
obs_module_text("AdvSceneSwitcher.midi.startListen")))
obs_module_text("AdvSceneSwitcher.midi.startListen"))),
_deviceNames(new QComboBox()),
_regex(new RegexConfigWidget()),
_deviceListInfo(new QLabel()),
_listenLayout(new QHBoxLayout()),
_entryLayout(new QHBoxLayout())
{
_deviceNames->addItems(GetDeviceNamesAsQStringList());
_deviceNames->setEditable(true);

QString path = GetThemeTypeName() == "Light"
? ":/res/images/help.svg"
: ":/res/images/help_light.svg";
QIcon icon(path);
QPixmap pixmap = icon.pixmap(QSize(16, 16));
_deviceListInfo->setPixmap(pixmap);
_deviceListInfo->setToolTip(obs_module_text(
"AdvSceneSwitcher.condition.midi.condition.deviceName.info"));

populateConditionSelection(_conditions);

QWidget::connect(_conditions, SIGNAL(currentIndexChanged(int)), this,
SLOT(ConditionChanged(int)));
QWidget::connect(_devices,
SIGNAL(DeviceSelectionChanged(const MidiDevice &)),
this,
Expand All @@ -121,19 +206,21 @@ MacroConditionMidiEdit::MacroConditionMidiEdit(
SLOT(ToggleListen()));
QWidget::connect(&_listenTimer, SIGNAL(timeout()), this,
SLOT(SetMessageSelectionToLastReceived()));
QWidget::connect(_deviceNames,
SIGNAL(currentTextChanged(const QString &)), this,
SLOT(DeviceNameChanged(const QString &)));
QWidget::connect(_regex,
SIGNAL(RegexConfigChanged(const RegexConfig &)), this,
SLOT(RegexChanged(const RegexConfig &)));

auto entryLayout = new QHBoxLayout;
PlaceWidgets(obs_module_text("AdvSceneSwitcher.condition.midi.entry"),
entryLayout, {{"{{device}}", _devices}});
auto listenLayout = new QHBoxLayout;
PlaceWidgets(
obs_module_text("AdvSceneSwitcher.condition.midi.entry.listen"),
listenLayout, {{"{{listenButton}}", _listen}});
_listenLayout, {{"{{listenButton}}", _listen}});

auto mainLayout = new QVBoxLayout;
mainLayout->addLayout(entryLayout);
mainLayout->addLayout(_entryLayout);
mainLayout->addWidget(_message);
mainLayout->addLayout(listenLayout);
mainLayout->addLayout(_listenLayout);
mainLayout->addWidget(_resetMidiDevices);
setLayout(mainLayout);

Expand All @@ -155,11 +242,14 @@ void MacroConditionMidiEdit::UpdateEntryData()
return;
}

_conditions->setCurrentIndex(
static_cast<int>(_entryData->GetCondition()));
_message->SetMessage(_entryData->_message);
_devices->SetDevice(_entryData->GetDevice());

adjustSize();
updateGeometry();
_deviceNames->setCurrentText(QString::fromStdString(
_entryData->_deviceName.UnresolvedValue()));
_regex->SetRegexConfig(_entryData->_regex);
SetWidgetVisibility();
}

void MacroConditionMidiEdit::DeviceSelectionChanged(const MidiDevice &device)
Expand Down Expand Up @@ -211,6 +301,46 @@ void MacroConditionMidiEdit::EnableListening(bool enable)
}
}

void MacroConditionMidiEdit::SetWidgetVisibility()
{
_entryLayout->removeWidget(_conditions);
_entryLayout->removeWidget(_devices);
_entryLayout->removeWidget(_deviceNames);
_entryLayout->removeWidget(_regex);

ClearLayout(_entryLayout);

std::unordered_map<std::string, QWidget *> widgetPlaceholders = {
{"{{conditions}}", _conditions},
{"{{device}}", _devices},
{"{{deviceNames}}", _deviceNames},
{"{{regex}}", _regex},
{"{{deviceListInfo}}", _deviceListInfo},
};

const bool isMessageCheck = _entryData->GetCondition() ==
MacroConditionMidi::Condition::MIDI_MESSAGE;

auto layoutString =
isMessageCheck
? "AdvSceneSwitcher.condition.midi.entry.message"
: "AdvSceneSwitcher.condition.midi.entry.deviceName";

PlaceWidgets(obs_module_text(layoutString), _entryLayout,
widgetPlaceholders);

SetLayoutVisible(_listenLayout, isMessageCheck);
_devices->setVisible(isMessageCheck);
_message->setVisible(isMessageCheck);
_resetMidiDevices->setVisible(isMessageCheck);
_deviceNames->setVisible(!isMessageCheck);
_regex->setVisible(!isMessageCheck);
_deviceListInfo->setVisible(!isMessageCheck);

adjustSize();
updateGeometry();
}

void MacroConditionMidiEdit::ToggleListen()
{
if (!_entryData) {
Expand Down Expand Up @@ -249,4 +379,41 @@ void MacroConditionMidiEdit::SetMessageSelectionToLastReceived()
_entryData->_message = *message;
}

void MacroConditionMidiEdit::ConditionChanged(int value)
{
if (_loading || !_entryData) {
return;
}

auto lock = LockContext();
_entryData->SetCondition(
static_cast<MacroConditionMidi::Condition>(value));
SetWidgetVisibility();
emit HeaderInfoChanged(
QString::fromStdString(_entryData->GetShortDesc()));
}

void MacroConditionMidiEdit::DeviceNameChanged(const QString &deviceName)
{
if (_loading || !_entryData) {
return;
}

auto lock = LockContext();
_entryData->_deviceName = deviceName.toStdString();
}

void MacroConditionMidiEdit::RegexChanged(const RegexConfig &conf)
{
if (_loading || !_entryData) {
return;
}

auto lock = LockContext();
_entryData->_regex = conf;

adjustSize();
updateGeometry();
}

} // namespace advss
Loading
Loading