SceneSwitcher/plugins/midi/macro-action-midi.cpp

228 lines
5.3 KiB
C++

#include "macro-action-midi.hpp"
#include "layout-helpers.hpp"
#include "ui-helpers.hpp"
namespace advss {
const std::string MacroActionMidi::id = "midi";
bool MacroActionMidi::_registered = MacroActionFactory::Register(
MacroActionMidi::id,
{MacroActionMidi::Create, MacroActionMidiEdit::Create,
"AdvSceneSwitcher.action.midi"});
bool MacroActionMidi::PerformAction()
{
if (!_device.SendMessge(_message)) {
blog(LOG_WARNING,
"failed to send midi message \"%s\" to \"%s\"",
_message.ToString().c_str(), _device.Name().c_str());
}
return true;
}
void MacroActionMidi::LogAction() const
{
vblog(LOG_INFO, "send midi message \"%s\" to \"%s\"",
_message.ToString().c_str(), _device.Name().c_str());
}
bool MacroActionMidi::Save(obs_data_t *obj) const
{
MacroAction::Save(obj);
_message.Save(obj);
_device.Save(obj);
return true;
}
bool MacroActionMidi::Load(obs_data_t *obj)
{
MacroAction::Load(obj);
_message.Load(obj);
_device.Load(obj);
return true;
}
std::string MacroActionMidi::GetShortDesc() const
{
return _device.Name();
}
void MacroActionMidi::ResolveVariablesToFixedValues()
{
_message.ResolveVariables();
}
std::shared_ptr<MacroAction> MacroActionMidi::Create(Macro *m)
{
return std::make_shared<MacroActionMidi>(m);
}
std::shared_ptr<MacroAction> MacroActionMidi::Copy() const
{
return std::make_shared<MacroActionMidi>(*this);
}
MacroActionMidiEdit::MacroActionMidiEdit(
QWidget *parent, std::shared_ptr<MacroActionMidi> entryData)
: QWidget(parent),
_devices(new MidiDeviceSelection(this, MidiDeviceType::OUTPUT)),
_message(new MidiMessageSelection(this)),
_resetMidiDevices(new QPushButton(
obs_module_text("AdvSceneSwitcher.midi.resetDevices"))),
_listenDevices(new MidiDeviceSelection(this, MidiDeviceType::INPUT)),
_listen(new QPushButton(
obs_module_text("AdvSceneSwitcher.midi.startListen")))
{
QWidget::connect(_devices,
SIGNAL(DeviceSelectionChanged(const MidiDevice &)),
this,
SLOT(DeviceSelectionChanged(const MidiDevice &)));
QWidget::connect(_message,
SIGNAL(MidiMessageChanged(const MidiMessage &)), this,
SLOT(MidiMessageChanged(const MidiMessage &)));
QWidget::connect(_resetMidiDevices, SIGNAL(clicked()), this,
SLOT(ResetMidiDevices()));
QWidget::connect(_listen, SIGNAL(clicked()), this,
SLOT(ToggleListen()));
QWidget::connect(
_listenDevices,
SIGNAL(DeviceSelectionChanged(const MidiDevice &)), this,
SLOT(ListenDeviceSelectionChanged(const MidiDevice &)));
QWidget::connect(&_listenTimer, SIGNAL(timeout()), this,
SLOT(SetMessageSelectionToLastReceived()));
auto entryLayout = new QHBoxLayout;
PlaceWidgets(obs_module_text("AdvSceneSwitcher.action.midi.entry"),
entryLayout, {{"{{device}}", _devices}});
auto listenLayout = new QHBoxLayout;
PlaceWidgets(
obs_module_text("AdvSceneSwitcher.action.midi.entry.listen"),
listenLayout,
{{"{{listenButton}}", _listen},
{"{{listenDevices}}", _listenDevices}});
auto mainLayout = new QVBoxLayout;
mainLayout->addLayout(entryLayout);
mainLayout->addWidget(_message);
mainLayout->addLayout(listenLayout);
mainLayout->addWidget(_resetMidiDevices);
setLayout(mainLayout);
_listenTimer.setInterval(100);
_entryData = entryData;
UpdateEntryData();
_loading = false;
}
MacroActionMidiEdit::~MacroActionMidiEdit()
{
EnableListening(false);
}
void MacroActionMidiEdit::UpdateEntryData()
{
if (!_entryData) {
return;
}
_message->SetMessage(_entryData->_message);
_devices->SetDevice(_entryData->_device);
adjustSize();
updateGeometry();
}
void MacroActionMidiEdit::DeviceSelectionChanged(const MidiDevice &device)
{
if (_loading || !_entryData) {
return;
}
{
auto lock = LockContext();
_entryData->_device = device;
}
emit HeaderInfoChanged(
QString::fromStdString(_entryData->GetShortDesc()));
}
void MacroActionMidiEdit::ListenDeviceSelectionChanged(const MidiDevice &dev)
{
if (_currentlyListening) {
ToggleListen();
}
_listenDevice = dev;
}
void MacroActionMidiEdit::MidiMessageChanged(const MidiMessage &message)
{
if (_loading || !_entryData) {
return;
}
auto lock = LockContext();
_entryData->_message = message;
}
void MacroActionMidiEdit::EnableListening(bool enable)
{
if (_currentlyListening == enable) {
return;
}
if (enable) {
_messageBuffer = _entryData->_device.RegisterForMidiMessages();
_listenTimer.start();
} else {
_messageBuffer.reset();
_listenTimer.stop();
}
}
void MacroActionMidiEdit::ResetMidiDevices()
{
auto lock = LockContext();
MidiDeviceInstance::ResetAllDevices();
}
void MacroActionMidiEdit::ToggleListen()
{
if (!_entryData || !_listenDevice.DeviceSelected()) {
return;
}
_listen->setText(
_currentlyListening
? obs_module_text("AdvSceneSwitcher.midi.startListen")
: obs_module_text("AdvSceneSwitcher.midi.stopListen"));
EnableListening(!_currentlyListening);
_currentlyListening = !_currentlyListening;
_message->setDisabled(_currentlyListening);
}
void MacroActionMidiEdit::SetMessageSelectionToLastReceived()
{
auto lock = LockContext();
if (!_entryData || !_messageBuffer || _messageBuffer->Empty()) {
return;
}
std::optional<MidiMessage> message;
while (!_messageBuffer->Empty()) {
message = _messageBuffer->ConsumeMessage();
if (!message) {
continue;
}
}
if (!message) {
return;
}
_message->SetMessage(*message);
_entryData->_message = *message;
}
} // namespace advss