mirror of
https://github.com/WarmUpTill/SceneSwitcher.git
synced 2026-07-02 00:22:10 -05:00
Switch to message buffer / dispatcher for MIDI messages
This commit is contained in:
parent
97983d5ac5
commit
04631964d3
|
|
@ -156,10 +156,11 @@ void MacroActionMidiEdit::EnableListening(bool enable)
|
|||
if (_currentlyListening == enable) {
|
||||
return;
|
||||
}
|
||||
_listenDevice.UseForMessageSelection(enable);
|
||||
if (enable) {
|
||||
_messageBuffer = _entryData->_device.RegisterForMidiMessages();
|
||||
_listenTimer.start();
|
||||
} else {
|
||||
_messageBuffer.reset();
|
||||
_listenTimer.stop();
|
||||
}
|
||||
}
|
||||
|
|
@ -176,12 +177,6 @@ void MacroActionMidiEdit::ToggleListen()
|
|||
return;
|
||||
}
|
||||
|
||||
if (!_currentlyListening && _listenDevice.IsUsedForMessageSelection()) {
|
||||
DisplayMessage(obs_module_text(
|
||||
"AdvSceneSwitcher.midi.startListenFail"));
|
||||
return;
|
||||
}
|
||||
|
||||
_listen->setText(
|
||||
_currentlyListening
|
||||
? obs_module_text("AdvSceneSwitcher.midi.startListen")
|
||||
|
|
@ -194,14 +189,24 @@ void MacroActionMidiEdit::ToggleListen()
|
|||
void MacroActionMidiEdit::SetMessageSelectionToLastReceived()
|
||||
{
|
||||
auto lock = LockContext();
|
||||
auto messages = _listenDevice.GetMessages(true);
|
||||
if (!_entryData || !messages || messages->empty()) {
|
||||
if (!_entryData || !_messageBuffer || _messageBuffer->Empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
_message->SetMessage(messages->back());
|
||||
_entryData->_message = messages->back();
|
||||
_listenDevice.ClearMessageBuffer();
|
||||
std::optional<MidiMessage> message;
|
||||
while (!_messageBuffer->Empty()) {
|
||||
message = _messageBuffer->ConsumeMessage();
|
||||
if (!message) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (!message) {
|
||||
return;
|
||||
}
|
||||
|
||||
_message->SetMessage(*message);
|
||||
_entryData->_message = *message;
|
||||
}
|
||||
|
||||
} // namespace advss
|
||||
|
|
|
|||
|
|
@ -68,6 +68,7 @@ private:
|
|||
QPushButton *_listen;
|
||||
MidiDevice _listenDevice;
|
||||
QTimer _listenTimer;
|
||||
MidiMessageBuffer _messageBuffer;
|
||||
bool _currentlyListening = false;
|
||||
bool _loading = true;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -13,14 +13,17 @@ bool MacroConditionMidi::_registered = MacroConditionFactory::Register(
|
|||
|
||||
bool MacroConditionMidi::CheckCondition()
|
||||
{
|
||||
auto messages = _device.GetMessages();
|
||||
if (!messages) {
|
||||
if (!_messageBuffer) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (const auto &m : *messages) {
|
||||
if (m.Matches(_message)) {
|
||||
SetVariableValues(m);
|
||||
while (!_messageBuffer->Empty()) {
|
||||
auto message = _messageBuffer->ConsumeMessage();
|
||||
if (!message) {
|
||||
continue;
|
||||
}
|
||||
if (message->Matches(_message)) {
|
||||
SetVariableValues(*message);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
@ -41,6 +44,7 @@ bool MacroConditionMidi::Load(obs_data_t *obj)
|
|||
MacroCondition::Load(obj);
|
||||
_message.Load(obj);
|
||||
_device.Load(obj);
|
||||
_messageBuffer = _device.RegisterForMidiMessages();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -49,6 +53,12 @@ std::string MacroConditionMidi::GetShortDesc() const
|
|||
return _device.Name();
|
||||
}
|
||||
|
||||
void MacroConditionMidi::SetDevice(const MidiDevice &dev)
|
||||
{
|
||||
_device = dev;
|
||||
_messageBuffer = dev.RegisterForMidiMessages();
|
||||
}
|
||||
|
||||
void MacroConditionMidi::SetupTempVars()
|
||||
{
|
||||
MacroCondition::SetupTempVars();
|
||||
|
|
@ -137,7 +147,7 @@ void MacroConditionMidiEdit::UpdateEntryData()
|
|||
}
|
||||
|
||||
_message->SetMessage(_entryData->_message);
|
||||
_devices->SetDevice(_entryData->_device);
|
||||
_devices->SetDevice(_entryData->GetDevice());
|
||||
|
||||
adjustSize();
|
||||
updateGeometry();
|
||||
|
|
@ -155,7 +165,7 @@ void MacroConditionMidiEdit::DeviceSelectionChanged(const MidiDevice &device)
|
|||
|
||||
{
|
||||
auto lock = LockContext();
|
||||
_entryData->_device = device;
|
||||
_entryData->SetDevice(device);
|
||||
}
|
||||
emit HeaderInfoChanged(
|
||||
QString::fromStdString(_entryData->GetShortDesc()));
|
||||
|
|
@ -182,10 +192,12 @@ void MacroConditionMidiEdit::EnableListening(bool enable)
|
|||
if (_currentlyListening == enable) {
|
||||
return;
|
||||
}
|
||||
_entryData->_device.UseForMessageSelection(enable);
|
||||
if (enable) {
|
||||
_messageBuffer =
|
||||
_entryData->GetDevice().RegisterForMidiMessages();
|
||||
_listenTimer.start();
|
||||
} else {
|
||||
_messageBuffer.reset();
|
||||
_listenTimer.stop();
|
||||
}
|
||||
}
|
||||
|
|
@ -196,13 +208,6 @@ void MacroConditionMidiEdit::ToggleListen()
|
|||
return;
|
||||
}
|
||||
|
||||
if (!_currentlyListening &&
|
||||
_entryData->_device.IsUsedForMessageSelection()) {
|
||||
DisplayMessage(obs_module_text(
|
||||
"AdvSceneSwitcher.midi.startListenFail"));
|
||||
return;
|
||||
}
|
||||
|
||||
_listen->setText(
|
||||
_currentlyListening
|
||||
? obs_module_text("AdvSceneSwitcher.midi.startListen")
|
||||
|
|
@ -215,14 +220,24 @@ void MacroConditionMidiEdit::ToggleListen()
|
|||
void MacroConditionMidiEdit::SetMessageSelectionToLastReceived()
|
||||
{
|
||||
auto lock = LockContext();
|
||||
auto messages = _entryData->_device.GetMessages(true);
|
||||
if (!_entryData || !messages || messages->empty()) {
|
||||
if (!_entryData || !_messageBuffer || _messageBuffer->Empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
_message->SetMessage(messages->back());
|
||||
_entryData->_message = messages->back();
|
||||
_entryData->_device.ClearMessageBuffer();
|
||||
std::optional<MidiMessage> message;
|
||||
while (!_messageBuffer->Empty()) {
|
||||
message = _messageBuffer->ConsumeMessage();
|
||||
if (!message) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (!message) {
|
||||
return;
|
||||
}
|
||||
|
||||
_message->SetMessage(*message);
|
||||
_entryData->_message = *message;
|
||||
}
|
||||
|
||||
} // namespace advss
|
||||
|
|
|
|||
|
|
@ -20,13 +20,16 @@ public:
|
|||
return std::make_shared<MacroConditionMidi>(m);
|
||||
}
|
||||
|
||||
MidiDevice _device;
|
||||
void SetDevice(const MidiDevice &dev);
|
||||
const MidiDevice &GetDevice() const { return _device; }
|
||||
MidiMessage _message;
|
||||
|
||||
private:
|
||||
void SetupTempVars();
|
||||
void SetVariableValues(const MidiMessage &);
|
||||
|
||||
MidiDevice _device;
|
||||
MidiMessageBuffer _messageBuffer;
|
||||
static bool _registered;
|
||||
static const std::string id;
|
||||
};
|
||||
|
|
@ -67,6 +70,7 @@ private:
|
|||
QPushButton *_resetMidiDevices;
|
||||
QPushButton *_listen;
|
||||
QTimer _listenTimer;
|
||||
MidiMessageBuffer _messageBuffer;
|
||||
bool _currentlyListening = false;
|
||||
bool _loading = true;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -10,48 +10,21 @@
|
|||
#include <ui-helpers.hpp>
|
||||
#include <utility.hpp>
|
||||
|
||||
#undef DispatchMessage
|
||||
|
||||
namespace advss {
|
||||
|
||||
std::map<std::pair<MidiDeviceType, std::string>, MidiDeviceInstance *>
|
||||
MidiDeviceInstance::devices = {};
|
||||
|
||||
static bool registerClearMessageBufferStep()
|
||||
{
|
||||
AddIntervalResetStep(
|
||||
MidiDeviceInstance::ClearMessageBuffersOfAllDevices);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool registerClearMessageBufferStepDone =
|
||||
registerClearMessageBufferStep();
|
||||
|
||||
void MidiDeviceInstance::ClearMessageBuffersOfAllDevices()
|
||||
{
|
||||
for (auto const &[_, device] : MidiDeviceInstance::devices) {
|
||||
if (device->_skipBufferClear) {
|
||||
continue;
|
||||
}
|
||||
device->ClearMessageBuffer();
|
||||
}
|
||||
}
|
||||
|
||||
void MidiDeviceInstance::ResetAllDevices()
|
||||
{
|
||||
for (auto const &[_, device] : MidiDeviceInstance::devices) {
|
||||
if (device->_skipBufferClear) {
|
||||
continue;
|
||||
}
|
||||
device->ClosePort();
|
||||
device->ClearMessageBuffer();
|
||||
device->OpenPort();
|
||||
}
|
||||
}
|
||||
|
||||
void MidiDeviceInstance::ClearMessageBuffer()
|
||||
{
|
||||
_messages.clear();
|
||||
}
|
||||
|
||||
MidiMessage::MidiMessage(const libremidi::message &message)
|
||||
{
|
||||
_typeIsOptional = false;
|
||||
|
|
@ -357,7 +330,7 @@ void MidiDevice::Load(obs_data_t *obj)
|
|||
}
|
||||
}
|
||||
|
||||
bool MidiDevice::SendMessge(const MidiMessage &m)
|
||||
bool MidiDevice::SendMessge(const MidiMessage &m) const
|
||||
{
|
||||
if (_type == MidiDeviceType::INPUT || _name.empty() || !_dev) {
|
||||
return false;
|
||||
|
|
@ -392,8 +365,8 @@ getInPortFromName(const std::string &name)
|
|||
|
||||
bool MidiDeviceInstance::OpenPort()
|
||||
{
|
||||
if ((_type == MidiDeviceType::INPUT && in.is_port_open()) ||
|
||||
(_type == MidiDeviceType::OUTPUT && out.is_port_open())) {
|
||||
if ((_type == MidiDeviceType::INPUT && _in.is_port_open()) ||
|
||||
(_type == MidiDeviceType::OUTPUT && _out.is_port_open())) {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -406,7 +379,7 @@ bool MidiDeviceInstance::OpenPort()
|
|||
return false;
|
||||
}
|
||||
try {
|
||||
out.open_port(*port);
|
||||
_out.open_port(*port);
|
||||
blog(LOG_INFO, "Opened output midi port '%s'",
|
||||
_name.c_str());
|
||||
return true;
|
||||
|
|
@ -430,7 +403,7 @@ bool MidiDeviceInstance::OpenPort()
|
|||
ReceiveMidiMessage(std::move(m));
|
||||
};
|
||||
|
||||
in = libremidi::midi_in{
|
||||
_in = libremidi::midi_in{
|
||||
libremidi::input_configuration{.on_message = cb}};
|
||||
|
||||
auto port = getInPortFromName(_name);
|
||||
|
|
@ -441,7 +414,7 @@ bool MidiDeviceInstance::OpenPort()
|
|||
}
|
||||
|
||||
try {
|
||||
in.open_port(*port);
|
||||
_in.open_port(*port);
|
||||
blog(LOG_INFO, "Opened input midi port '%s'", _name.c_str());
|
||||
return true;
|
||||
} catch (const libremidi::driver_error &error) {
|
||||
|
|
@ -459,14 +432,14 @@ bool MidiDeviceInstance::OpenPort()
|
|||
|
||||
void MidiDeviceInstance::ClosePort()
|
||||
{
|
||||
if ((_type == MidiDeviceType::INPUT && !in.is_port_open()) ||
|
||||
(_type == MidiDeviceType::OUTPUT && !out.is_port_open())) {
|
||||
if ((_type == MidiDeviceType::INPUT && !_in.is_port_open()) ||
|
||||
(_type == MidiDeviceType::OUTPUT && !_out.is_port_open())) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (_type == MidiDeviceType::OUTPUT) {
|
||||
try {
|
||||
out.close_port();
|
||||
_out.close_port();
|
||||
blog(LOG_INFO, "Closed output midi port '%s'",
|
||||
_name.c_str());
|
||||
} catch (const libremidi::driver_error &error) {
|
||||
|
|
@ -486,7 +459,7 @@ void MidiDeviceInstance::ClosePort()
|
|||
}
|
||||
|
||||
try {
|
||||
in.close_port();
|
||||
_in.close_port();
|
||||
blog(LOG_INFO, "Closed input midi port '%s'", _name.c_str());
|
||||
} catch (const libremidi::driver_error &error) {
|
||||
blog(LOG_WARNING, "Failed to close input midi port '%s': %s",
|
||||
|
|
@ -546,7 +519,7 @@ bool MidiDeviceInstance::SendMessge(const MidiMessage &m)
|
|||
}
|
||||
|
||||
try {
|
||||
out.send_message(message);
|
||||
_out.send_message(message);
|
||||
return true;
|
||||
} catch (const libremidi::driver_error &err) {
|
||||
blog(LOG_WARNING, "%s", err.what());
|
||||
|
|
@ -555,54 +528,26 @@ bool MidiDeviceInstance::SendMessge(const MidiMessage &m)
|
|||
return false;
|
||||
}
|
||||
|
||||
const std::vector<MidiMessage> &MidiDeviceInstance::GetMessages()
|
||||
MidiMessageBuffer MidiDeviceInstance::RegisterForMidiMessages()
|
||||
{
|
||||
return _messages;
|
||||
return _dispatcher.RegisterClient();
|
||||
}
|
||||
|
||||
void MidiDeviceInstance::ReceiveMidiMessage(libremidi::message &&msg)
|
||||
{
|
||||
auto lock = LockContext();
|
||||
_messages.emplace_back(msg);
|
||||
_dispatcher.DispatchMessage(msg);
|
||||
vblog(LOG_INFO, "received midi: %s",
|
||||
MidiMessage::ToString(msg).c_str());
|
||||
}
|
||||
|
||||
void MidiDevice::UseForMessageSelection(bool skipBufferClear)
|
||||
[[nodiscard]] MidiMessageBuffer MidiDevice::RegisterForMidiMessages() const
|
||||
{
|
||||
if (!_dev) {
|
||||
return;
|
||||
if (_type == MidiDeviceType::OUTPUT || _name.empty() || !_dev) {
|
||||
return {};
|
||||
}
|
||||
|
||||
blog(LOG_INFO, "%s \"listen\" mode for midi input device \"%s\"! %s",
|
||||
skipBufferClear ? "Enable" : "Disable", Name().c_str(),
|
||||
skipBufferClear
|
||||
? "This will block incoming messages from being processed!"
|
||||
: "");
|
||||
ClearMessageBuffer();
|
||||
_dev->_skipBufferClear = skipBufferClear;
|
||||
}
|
||||
|
||||
bool MidiDevice::IsUsedForMessageSelection()
|
||||
{
|
||||
return _dev && _dev->_skipBufferClear;
|
||||
}
|
||||
|
||||
void MidiDevice::ClearMessageBuffer()
|
||||
{
|
||||
if (_dev) {
|
||||
_dev->ClearMessageBuffer();
|
||||
}
|
||||
}
|
||||
|
||||
const std::vector<MidiMessage> *MidiDevice::GetMessages(bool ignoreSkip)
|
||||
{
|
||||
if (_type == MidiDeviceType::OUTPUT || _name.empty() || !_dev ||
|
||||
(_dev->_skipBufferClear && !ignoreSkip)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return &_dev->GetMessages();
|
||||
return _dev->RegisterForMidiMessages();
|
||||
}
|
||||
|
||||
std::string MidiDevice::Name() const
|
||||
|
|
|
|||
|
|
@ -1,15 +1,20 @@
|
|||
#pragma once
|
||||
#include <variable-spinbox.hpp>
|
||||
#include <variable-number.hpp>
|
||||
#include <variable-string.hpp>
|
||||
#include <QComboBox>
|
||||
#include <message-dispatcher.hpp>
|
||||
#include <obs-data.h>
|
||||
#include <variable-number.hpp>
|
||||
#include <variable-spinbox.hpp>
|
||||
#include <variable-string.hpp>
|
||||
|
||||
#define LIBREMIDI_HEADER_ONLY 1
|
||||
#include <libremidi/libremidi.hpp>
|
||||
|
||||
namespace advss {
|
||||
|
||||
class MidiMessage;
|
||||
using MidiMessageBuffer = std::shared_ptr<MessageBuffer<MidiMessage>>;
|
||||
using MidiMessageDispatcher = MessageDispatcher<MidiMessage>;
|
||||
|
||||
// Based on https://github.com/nhielost/obs-midi-mg MMGMessage
|
||||
class MidiMessage {
|
||||
public:
|
||||
|
|
@ -60,7 +65,6 @@ public:
|
|||
static MidiDeviceInstance *GetDevice(MidiDeviceType type,
|
||||
const std::string &);
|
||||
static MidiDeviceInstance *GetDevice(MidiDeviceType type, int port);
|
||||
static void ClearMessageBuffersOfAllDevices();
|
||||
static void ResetAllDevices();
|
||||
|
||||
private:
|
||||
|
|
@ -69,26 +73,23 @@ private:
|
|||
bool OpenPort();
|
||||
void ClosePort();
|
||||
bool SendMessge(const MidiMessage &);
|
||||
const std::vector<MidiMessage> &GetMessages();
|
||||
[[nodiscard]] MidiMessageBuffer RegisterForMidiMessages();
|
||||
void ReceiveMidiMessage(libremidi::message &&);
|
||||
void ClearMessageBuffer();
|
||||
|
||||
static std::map<std::pair<MidiDeviceType, std::string>,
|
||||
MidiDeviceInstance *>
|
||||
devices;
|
||||
|
||||
bool _skipBufferClear = false;
|
||||
|
||||
MidiDeviceType _type = MidiDeviceType::INPUT;
|
||||
std::string _name;
|
||||
libremidi::midi_in in =
|
||||
libremidi::midi_in _in =
|
||||
libremidi::midi_in(libremidi::input_configuration{
|
||||
[this](libremidi::message &&message) {
|
||||
ReceiveMidiMessage(std::move(message));
|
||||
}});
|
||||
libremidi::midi_out out =
|
||||
libremidi::midi_out _out =
|
||||
libremidi::midi_out(libremidi::output_configuration());
|
||||
std::vector<MidiMessage> _messages;
|
||||
MidiMessageDispatcher _dispatcher;
|
||||
|
||||
friend class MidiDevice;
|
||||
};
|
||||
|
|
@ -100,19 +101,12 @@ public:
|
|||
void Save(obs_data_t *obj) const;
|
||||
void Load(obs_data_t *obj);
|
||||
|
||||
bool SendMessge(const MidiMessage &);
|
||||
bool SendMessge(const MidiMessage &) const;
|
||||
[[nodiscard]] MidiMessageBuffer RegisterForMidiMessages() const;
|
||||
|
||||
const std::vector<MidiMessage> * // Might resize! Only call
|
||||
GetMessages(bool ignoreListenMode = false); // while holding switcher
|
||||
// lock!
|
||||
std::string Name() const;
|
||||
|
||||
// Used for "listen" mode of message selection
|
||||
// Listen mode disables automatic clearing of buffers
|
||||
void UseForMessageSelection(bool);
|
||||
bool IsUsedForMessageSelection();
|
||||
void ClearMessageBuffer();
|
||||
bool DeviceSelected() { return !!_dev; }
|
||||
bool DeviceSelected() const { return !!_dev; }
|
||||
|
||||
private:
|
||||
MidiDeviceType _type = MidiDeviceType::INPUT;
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user