From 0be5131935db5a6a12126a1d35bad37204312937 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C5=91rinc=20Serf=C5=91z=C5=91?= Date: Fri, 17 May 2024 18:24:17 +0200 Subject: [PATCH] refactor: Simplified handling of disconnect/reconnect of MIDI devices --- CMakeLists.txt | 3 - src/DisconnectedMidiInNode.cpp | 28 ----- src/DisconnectedMidiInNode.hpp | 23 ---- src/DisconnectedMidiOutNode.cpp | 29 ----- src/DisconnectedMidiOutNode.hpp | 24 ----- src/MidiInNode.cpp | 95 ++++++++++++----- src/MidiInNode.hpp | 8 +- src/MidiOutNode.cpp | 58 ++++++++-- src/MidiOutNode.hpp | 7 +- src/MidiPortWatchdog.cpp | 182 -------------------------------- src/MidiPortWatchdog.hpp | 19 ---- src/Node.hpp | 3 +- src/NodeEditor.cpp | 4 +- src/NodeFactory.cpp | 43 +++++--- src/NodeFactory.hpp | 14 +-- src/NodeSerializer.cpp | 54 ++-------- src/NodeSerializer.hpp | 4 - src/PortNameDisplay.cpp | 37 ++----- src/PortNameDisplay.hpp | 6 +- src/midi/MessageTypeMask.hpp | 2 + src/midi/MidiProbe.cpp | 6 +- src/midi/MidiProbe.hpp | 6 +- 22 files changed, 193 insertions(+), 462 deletions(-) delete mode 100644 src/DisconnectedMidiInNode.cpp delete mode 100644 src/DisconnectedMidiInNode.hpp delete mode 100644 src/DisconnectedMidiOutNode.cpp delete mode 100644 src/DisconnectedMidiOutNode.hpp delete mode 100644 src/MidiPortWatchdog.cpp delete mode 100644 src/MidiPortWatchdog.hpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 055c839..60e19f0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -49,15 +49,12 @@ set(sources src/ActivityIndicator.cpp src/Application.cpp src/ConfigFile.cpp - src/DisconnectedMidiInNode.cpp - src/DisconnectedMidiOutNode.cpp src/KeyboardShortcutAggregator.cpp src/Licenses.cpp src/LogNode.cpp src/MidiChannelNode.cpp src/MidiInNode.cpp src/MidiOutNode.cpp - src/MidiPortWatchdog.cpp src/Node.cpp src/NodeEditor.cpp src/NodeFactory.cpp diff --git a/src/DisconnectedMidiInNode.cpp b/src/DisconnectedMidiInNode.cpp deleted file mode 100644 index c765565..0000000 --- a/src/DisconnectedMidiInNode.cpp +++ /dev/null @@ -1,28 +0,0 @@ -#include "DisconnectedMidiInNode.hpp" - -#include "imgui.h" -#include "imnodes.h" - -#include "PortNameDisplay.hpp" - -namespace mc -{ - -DisconnectedMidiInNode::DisconnectedMidiInNode(const std::string& input_name, - const PortNameDisplay& port_name_display) - : m_input_name(input_name), m_port_name_display(&port_name_display) -{ -} - -void DisconnectedMidiInNode::render_internal() -{ - ImNodes::BeginNodeTitleBar(); - const auto display_name = m_port_name_display->get_port_name(midi::InputInfo{0, m_input_name}); - ImGui::TextUnformatted(display_name.c_str()); - ImNodes::EndNodeTitleBar(); - ImNodes::BeginOutputAttribute(out_id()); - ImGui::TextUnformatted("disconnected"); - ImNodes::EndOutputAttribute(); -} - -} // namespace mc diff --git a/src/DisconnectedMidiInNode.hpp b/src/DisconnectedMidiInNode.hpp deleted file mode 100644 index d532cdf..0000000 --- a/src/DisconnectedMidiInNode.hpp +++ /dev/null @@ -1,23 +0,0 @@ -#pragma once -#include "DisconnectedNode.hpp" - -namespace mc -{ - -class PortNameDisplay; - -class DisconnectedMidiInNode final : public DisconnectedNode -{ -public: - DisconnectedMidiInNode(const std::string& input_name, const PortNameDisplay& port_name_display); - const std::string& get_name() const { return m_input_name; } - -private: - void render_internal() override; - - std::string m_input_name; - const PortNameDisplay* m_port_name_display; - friend class NodeSerializer; -}; - -} // namespace mc diff --git a/src/DisconnectedMidiOutNode.cpp b/src/DisconnectedMidiOutNode.cpp deleted file mode 100644 index aab7ac0..0000000 --- a/src/DisconnectedMidiOutNode.cpp +++ /dev/null @@ -1,29 +0,0 @@ -#include "DisconnectedMidiOutNode.hpp" - -#include "imgui.h" -#include "imnodes.h" - -#include "PortNameDisplay.hpp" - -namespace mc -{ - -DisconnectedMidiOutNode::DisconnectedMidiOutNode(const std::string& output_name, - const PortNameDisplay& port_name_display) - : m_output_name(output_name), m_port_name_display(&port_name_display) -{ -} - -void DisconnectedMidiOutNode::render_internal() -{ - ImNodes::BeginNodeTitleBar(); - const auto display_name = - m_port_name_display->get_port_name(midi::OutputInfo{0, m_output_name}); - ImGui::TextUnformatted(display_name.c_str()); - ImNodes::EndNodeTitleBar(); - ImNodes::BeginInputAttribute(in_id()); - ImGui::TextUnformatted("disconnected"); - ImNodes::EndInputAttribute(); -} - -} // namespace mc diff --git a/src/DisconnectedMidiOutNode.hpp b/src/DisconnectedMidiOutNode.hpp deleted file mode 100644 index 90e319b..0000000 --- a/src/DisconnectedMidiOutNode.hpp +++ /dev/null @@ -1,24 +0,0 @@ -#pragma once -#include "DisconnectedNode.hpp" - -namespace mc -{ - -class PortNameDisplay; - -class DisconnectedMidiOutNode final : public DisconnectedNode -{ -public: - DisconnectedMidiOutNode(const std::string& output_name, - const PortNameDisplay& port_name_display); - const std::string& get_name() const { return m_output_name; } - -private: - void render_internal() override; - - std::string m_output_name; - const PortNameDisplay* m_port_name_display; - friend class NodeSerializer; -}; - -} // namespace mc diff --git a/src/MidiInNode.cpp b/src/MidiInNode.cpp index 838a292..8e7dd43 100644 --- a/src/MidiInNode.cpp +++ b/src/MidiInNode.cpp @@ -13,19 +13,25 @@ namespace mc { -MidiInNode::MidiInNode(const midi::InputInfo& input_info, +MidiInNode::MidiInNode(std::string_view input_name, std::shared_ptr midi_input_node, const PortNameDisplay& port_name_display) - : m_input_info(input_info), m_midi_input_node(midi_input_node), + : m_input_name(input_name), m_midi_input_node(midi_input_node), m_port_name_display(&port_name_display) { - m_midi_input_node->enable_message_types(m_message_type_mask); - m_midi_input_node->add_observer(this); + if (m_midi_input_node) + { + m_midi_input_node->enable_message_types(m_message_type_mask); + m_midi_input_node->add_observer(this); + } } MidiInNode::~MidiInNode() { - m_midi_input_node->remove_observer(this); + if (m_midi_input_node) + { + m_midi_input_node->remove_observer(this); + } } void MidiInNode::accept_serializer(nlohmann::json& j, const NodeSerializer& serializer) const @@ -40,37 +46,39 @@ midi::Node* MidiInNode::get_midi_node() void MidiInNode::render_internal() { + check_midi_node_connected(); + ImNodes::BeginNodeTitleBar(); - const std::string node_title = m_port_name_display->get_port_name(m_input_info); + const std::string node_title = m_port_name_display->get_port_name(m_input_name); ImGui::TextUnformatted(node_title.c_str()); ImNodes::EndNodeTitleBar(); ImNodes::BeginOutputAttribute(out_id()); - m_midi_activity.render(); - ImGui::SameLine(); - ImGui::TextUnformatted("all channels"); + if (m_midi_input_node) + { + m_midi_activity.render(); + ImGui::SameLine(); + ImGui::TextUnformatted("all channels"); + } + else + { + ImGui::TextUnformatted("disconnected"); + } ImNodes::EndOutputAttribute(); + if (m_midi_input_node == nullptr) + { + return; + } + ImGui::PushStyleColor(ImGuiCol_HeaderHovered, ImVec4{}); ImGui::PushStyleColor(ImGuiCol_HeaderActive, ImVec4{}); if (ImGui::TreeNode("Advanced")) { - bool message_type_mask_changed = false; - if (ImGui::Checkbox("Receive SysEx", &m_message_type_mask.m_sysex_enabled)) - { - message_type_mask_changed = true; - } - if (ImGui::Checkbox("Receive MIDI Clock", &m_message_type_mask.m_time_enabled)) - { - message_type_mask_changed = true; - } - if (ImGui::Checkbox("Receive Active Sensing", &m_message_type_mask.m_sensing_enabled)) - { - message_type_mask_changed = true; - } - if (message_type_mask_changed) - { - m_midi_input_node->enable_message_types(m_message_type_mask); - } + midi::MessageTypeMask new_message_type_mask; + ImGui::Checkbox("Receive SysEx", &new_message_type_mask.m_sysex_enabled); + ImGui::Checkbox("Receive MIDI Clock", &new_message_type_mask.m_time_enabled); + ImGui::Checkbox("Receive Active Sensing", &new_message_type_mask.m_sensing_enabled); + set_message_type_mask(new_message_type_mask); ImGui::TreePop(); } ImGui::PopStyleColor(2); @@ -81,10 +89,43 @@ void MidiInNode::message_processed(std::span /*message_byte m_midi_activity.trigger(); } +void MidiInNode::check_midi_node_connected() +{ + const auto input_opt = midi::MidiProbe::get_valid_input(m_input_name); + if (input_opt && m_midi_input_node == nullptr) + { + m_midi_input_node = std::make_shared(*input_opt); + m_midi_input_node->enable_message_types(m_message_type_mask); + m_midi_input_node->add_observer(this); + for (auto output_connected_node : get_output_connections()) + { + if (auto node = output_connected_node.lock(); node != nullptr) + { + if (auto* midi_node = node->get_midi_node(); midi_node != nullptr) + { + midi::Connection::create(*m_midi_input_node, *midi_node); + } + } + } + } + else if (!input_opt && m_midi_input_node != nullptr) + { + m_midi_input_node->remove_observer(this); + m_midi_input_node = nullptr; + } +} + void MidiInNode::set_message_type_mask(midi::MessageTypeMask new_value) { + if (m_message_type_mask == new_value) + { + return; + } m_message_type_mask = new_value; - m_midi_input_node->enable_message_types(new_value); + if (m_midi_input_node) + { + m_midi_input_node->enable_message_types(new_value); + } } } // namespace mc diff --git a/src/MidiInNode.hpp b/src/MidiInNode.hpp index e263b4f..77bb9eb 100644 --- a/src/MidiInNode.hpp +++ b/src/MidiInNode.hpp @@ -6,6 +6,8 @@ #include "midi/MessageTypeMask.hpp" #include "midi/MidiInfo.hpp" +#include + namespace mc { namespace midi @@ -18,14 +20,13 @@ class PortNameDisplay; class MidiInNode final : public Node, private midi::GraphObserver { public: - MidiInNode(const midi::InputInfo& input_info, + MidiInNode(std::string_view input_name, std::shared_ptr midi_input_node, const PortNameDisplay& port_name_display); ~MidiInNode(); void accept_serializer(nlohmann::json& j, const NodeSerializer& serializer) const override; - const midi::InputInfo& get_info() const { return m_input_info; } protected: midi::Node* get_midi_node() override; @@ -34,9 +35,10 @@ class MidiInNode final : public Node, private midi::GraphObserver void render_internal() override; void message_processed(std::span message_bytes) override; + void check_midi_node_connected(); void set_message_type_mask(midi::MessageTypeMask new_value); - midi::InputInfo m_input_info; + std::string m_input_name; std::shared_ptr m_midi_input_node; ActivityIndicator m_midi_activity; const PortNameDisplay* m_port_name_display; diff --git a/src/MidiOutNode.cpp b/src/MidiOutNode.cpp index a48c5b8..b20138e 100644 --- a/src/MidiOutNode.cpp +++ b/src/MidiOutNode.cpp @@ -5,23 +5,30 @@ #include "NodeSerializer.hpp" #include "PortNameDisplay.hpp" +#include "midi/MidiProbe.hpp" #include "midi/OutputNode.hpp" namespace mc { -MidiOutNode::MidiOutNode(const midi::OutputInfo& output_info, +MidiOutNode::MidiOutNode(std::string_view output_name, std::shared_ptr midi_output_node, const PortNameDisplay& port_name_display) - : m_output_info(output_info), m_midi_output_node(midi_output_node), + : m_output_name(output_name), m_midi_output_node(midi_output_node), m_port_name_display(&port_name_display) { - m_midi_output_node->add_observer(this); + if (m_midi_output_node) + { + m_midi_output_node->add_observer(this); + } } MidiOutNode::~MidiOutNode() { - m_midi_output_node->remove_observer(this); + if (m_midi_output_node) + { + m_midi_output_node->remove_observer(this); + } } void MidiOutNode::accept_serializer(nlohmann::json& j, const NodeSerializer& serializer) const @@ -36,14 +43,24 @@ midi::Node* MidiOutNode::get_midi_node() void MidiOutNode::render_internal() { + check_midi_node_connected(); + ImNodes::BeginNodeTitleBar(); - const std::string node_title = m_port_name_display->get_port_name(m_output_info); + const std::string node_title = m_port_name_display->get_port_name(m_output_name); ImGui::TextUnformatted(node_title.c_str()); ImNodes::EndNodeTitleBar(); ImNodes::BeginInputAttribute(in_id()); - m_midi_activity.render(); - ImGui::SameLine(); - ImGui::TextUnformatted("all channels"); + + if (m_midi_output_node) + { + m_midi_activity.render(); + ImGui::SameLine(); + ImGui::TextUnformatted("all channels"); + } + else + { + ImGui::TextUnformatted("disconnected"); + } ImNodes::EndInputAttribute(); } @@ -53,4 +70,29 @@ void MidiOutNode::message_received(std::span /*message_byte m_midi_activity.trigger(); } +void MidiOutNode::check_midi_node_connected() +{ + const auto output_opt = midi::MidiProbe::get_valid_output(m_output_name); + if (output_opt && m_midi_output_node == nullptr) + { + m_midi_output_node = std::make_shared(*output_opt); + m_midi_output_node->add_observer(this); + for (auto input_connected_node : get_input_connections()) + { + if (auto node = input_connected_node.lock(); node != nullptr) + { + if (auto* midi_node = node->get_midi_node(); midi_node != nullptr) + { + midi::Connection::create(*midi_node, *m_midi_output_node); + } + } + } + } + else if (!output_opt && m_midi_output_node != nullptr) + { + m_midi_output_node->remove_observer(this); + m_midi_output_node = nullptr; + } +} + } // namespace mc diff --git a/src/MidiOutNode.hpp b/src/MidiOutNode.hpp index 2c289f4..27a3e5f 100644 --- a/src/MidiOutNode.hpp +++ b/src/MidiOutNode.hpp @@ -16,14 +16,13 @@ class PortNameDisplay; class MidiOutNode final : public Node, private midi::GraphObserver { public: - MidiOutNode(const midi::OutputInfo& output_info, + MidiOutNode(std::string_view output_name, std::shared_ptr midi_output_node, const PortNameDisplay& port_name_display); ~MidiOutNode(); void accept_serializer(nlohmann::json& j, const NodeSerializer& serializer) const override; - const midi::OutputInfo& get_info() const { return m_output_info; } protected: midi::Node* get_midi_node() override; @@ -32,7 +31,9 @@ class MidiOutNode final : public Node, private midi::GraphObserver void render_internal() override; void message_received(std::span message_bytes) override; - midi::OutputInfo m_output_info; + void check_midi_node_connected(); + + std::string m_output_name; std::shared_ptr m_midi_output_node; ActivityIndicator m_midi_activity; const PortNameDisplay* m_port_name_display; diff --git a/src/MidiPortWatchdog.cpp b/src/MidiPortWatchdog.cpp deleted file mode 100644 index 92cf846..0000000 --- a/src/MidiPortWatchdog.cpp +++ /dev/null @@ -1,182 +0,0 @@ -#include "MidiPortWatchdog.hpp" - -#include "spdlog/spdlog.h" - -#include "DisconnectedMidiInNode.hpp" -#include "DisconnectedMidiOutNode.hpp" -#include "MidiInNode.hpp" -#include "MidiOutNode.hpp" -#include "NodeFactory.hpp" -#include "midi/MidiProbe.hpp" - -namespace mc -{ -namespace -{ - -template -struct MidiNodeTraits; - -template <> -struct MidiNodeTraits -{ - static constexpr bool is_disconnected = false; -}; - -template <> -struct MidiNodeTraits -{ - static constexpr bool is_disconnected = false; -}; - -template <> -struct MidiNodeTraits -{ - static constexpr bool is_disconnected = true; -}; - -template <> -struct MidiNodeTraits -{ - static constexpr bool is_disconnected = true; -}; - -template -struct NodeBuilder -{ - NodeFactory* m_node_factory{}; -}; - -std::shared_ptr build_node(const NodeBuilder& builder, - const midi::InputInfo& input_info) -{ - return builder.m_node_factory->build_midi_node(input_info); -} - -std::shared_ptr build_node(const NodeBuilder& builder, - const std::string& input_name) -{ - return builder.m_node_factory->build_disconnected_midi_in_node(input_name); -} - -std::shared_ptr build_node(const NodeBuilder& builder, - const midi::OutputInfo& output_info) -{ - return builder.m_node_factory->build_midi_node(output_info); -} - -std::shared_ptr build_node(const NodeBuilder& builder, - const std::string& output_name) -{ - return builder.m_node_factory->build_disconnected_midi_out_node(output_name); -} - -template -bool update_node(std::shared_ptr& node_ptr, - ValidGetterFun valid_getter_fun, - const NodeBuilder& builder) -{ - if (auto* midi_ptr = dynamic_cast(node_ptr.get()); midi_ptr != nullptr) - { - std::string midi_port_name; - if constexpr (MidiNodeTraits::is_disconnected) - { - midi_port_name = midi_ptr->get_name(); - } - else - { - midi_port_name = midi_ptr->get_info().m_name; - } - - const auto get_memo = [](std::shared_ptr& old_node) { - return std::tuple{old_node->get_input_connections(), - old_node->get_output_connections(), - ImNodes::GetNodeGridSpacePos(old_node->id())}; - }; - const auto set_memo = [](std::shared_ptr& new_node, const auto& memo) { - for (const auto& outputting_node : std::get<0>(memo)) - { - auto outputting_node_ptr = outputting_node.lock(); - if (outputting_node_ptr != nullptr) - { - outputting_node_ptr->connect_output(new_node, outputting_node); - } - } - for (const auto& connected_node : std::get<1>(memo)) - { - new_node->connect_output(connected_node, new_node); - } - ImNodes::SetNodeGridSpacePos(new_node->id(), std::get<2>(memo)); - }; - - const auto valid_info = valid_getter_fun(midi_port_name); - - if constexpr (MidiNodeTraits::is_disconnected) - { - if (valid_info.has_value()) - { - spdlog::info("Re-activating node for connected device \"{}\"", midi_port_name); - const auto memo = get_memo(node_ptr); - node_ptr = build_node(builder, valid_info.value()); - set_memo(node_ptr, memo); - } - } - else - { - if (!valid_info.has_value() || valid_info.value().m_id != midi_ptr->get_info().m_id) - { - spdlog::info("Deactivating node for disconnected device \"{}\"", midi_port_name); - const auto memo = get_memo(node_ptr); - node_ptr = build_node(builder, midi_port_name); - set_memo(node_ptr, memo); - } - } - return true; - } - else - { - return false; - } -} - -} // namespace - -void MidiPortWatchdog::check_nodes(std::vector>& nodes, - NodeFactory& node_factory) -{ - - for (auto& node_ptr : nodes) - { - const auto get_valid_input = [](const auto& name) { - return midi::MidiProbe::get_valid_input(name); - }; - const auto get_valid_output = [](const auto& name) { - return midi::MidiProbe::get_valid_output(name); - }; - - if (update_node( - node_ptr, get_valid_input, NodeBuilder{&node_factory})) - { - // do nothing, update done in side effect - } - else if (update_node( - node_ptr, - get_valid_output, - NodeBuilder{&node_factory})) - { - // do nothing, update done in side effect - } - else if (update_node( - node_ptr, get_valid_input, NodeBuilder{&node_factory})) - { - // do nothing, update done in side effect - } - else if (update_node( - node_ptr, get_valid_output, NodeBuilder{&node_factory})) - { - // do nothing, update done in side effect - } - } -} - -} // namespace mc \ No newline at end of file diff --git a/src/MidiPortWatchdog.hpp b/src/MidiPortWatchdog.hpp deleted file mode 100644 index 82794f5..0000000 --- a/src/MidiPortWatchdog.hpp +++ /dev/null @@ -1,19 +0,0 @@ -#pragma once -#include -#include - -#include "Node.hpp" - -namespace mc -{ -class NodeFactory; - -class MidiPortWatchdog final -{ -public: - MidiPortWatchdog() = delete; - - static void check_nodes(std::vector>& nodes, NodeFactory& node_factory); -}; - -} // namespace mc diff --git a/src/Node.hpp b/src/Node.hpp index 9d38da9..312e6e6 100644 --- a/src/Node.hpp +++ b/src/Node.hpp @@ -39,8 +39,9 @@ class Node static bool is_in_id(int id) { return id % 2 == 0; } static bool is_out_id(int id) { return !is_in_id(id); } -protected: virtual midi::Node* get_midi_node() = 0; + +protected: virtual void render_internal() = 0; virtual void push_style() const {} virtual void pop_style() const {} diff --git a/src/NodeEditor.cpp b/src/NodeEditor.cpp index 6f1cf75..fb1b9cb 100644 --- a/src/NodeEditor.cpp +++ b/src/NodeEditor.cpp @@ -11,7 +11,6 @@ #include "MidiChannelNode.hpp" #include "MidiInNode.hpp" #include "MidiOutNode.hpp" -#include "MidiPortWatchdog.hpp" #include "NodeFactory.hpp" #include "NodeSerializer.hpp" #include "PortNameDisplay.hpp" @@ -167,7 +166,7 @@ std::shared_ptr NodeEditor::renderContextMenu(bool show_outputting_nodes, auto render_midi_inout_list = [this, render_add_node](auto& infos) -> std::shared_ptr { for (const auto& info : infos) { - const std::string port_name = m_port_name_display->get_port_name(info); + const std::string port_name = m_port_name_display->get_port_name(info.m_name); if (auto node = render_add_node( [this, &info] { return m_node_factory->build_midi_node(info); @@ -235,7 +234,6 @@ std::shared_ptr NodeEditor::renderContextMenu(bool show_outputting_nodes, void NodeEditor::renderNodes() { - MidiPortWatchdog::check_nodes(m_nodes, *m_node_factory); for (const auto& node : m_nodes) { node->render(); diff --git a/src/NodeFactory.cpp b/src/NodeFactory.cpp index 04316a7..893c3df 100644 --- a/src/NodeFactory.cpp +++ b/src/NodeFactory.cpp @@ -1,13 +1,12 @@ #include "NodeFactory.hpp" -#include "DisconnectedMidiInNode.hpp" -#include "DisconnectedMidiOutNode.hpp" #include "LogNode.hpp" #include "MidiChannelNode.hpp" #include "MidiInNode.hpp" #include "MidiOutNode.hpp" #include "Theme.hpp" #include "midi/InputNode.hpp" +#include "midi/MidiProbe.hpp" #include "midi/OutputNode.hpp" namespace mc @@ -62,26 +61,46 @@ NodeFactory::NodeFactory(const ThemeControl& theme_control, std::shared_ptr NodeFactory::build_midi_node(const midi::InputInfo& input_info) { - return std::make_shared( - input_info, make_cached_midi_node(m_input_nodes, input_info), *m_port_name_display); + return build_midi_in_node(input_info.m_name); } std::shared_ptr NodeFactory::build_midi_node(const midi::OutputInfo& output_info) { - return std::make_shared( - output_info, make_cached_midi_node(m_output_nodes, output_info), *m_port_name_display); + return build_midi_out_node(output_info.m_name); } -std::shared_ptr NodeFactory::build_disconnected_midi_in_node( - const std::string& input_name) +std::shared_ptr NodeFactory::build_midi_in_node(std::string_view input_name) { - return std::make_shared(input_name, *m_port_name_display); + const auto input_info_opt = midi::MidiProbe::get_valid_input(input_name); + auto midi_node = [&]() -> std::shared_ptr { + if (input_info_opt) + { + return make_cached_midi_node(m_input_nodes, *input_info_opt); + } + else + { + return nullptr; + } + }(); + + return std::make_shared(input_name, std::move(midi_node), *m_port_name_display); } -std::shared_ptr NodeFactory::build_disconnected_midi_out_node( - const std::string& output_name) +std::shared_ptr NodeFactory::build_midi_out_node(std::string_view output_name) { - return std::make_shared(output_name, *m_port_name_display); + const auto output_info_opt = midi::MidiProbe::get_valid_output(output_name); + auto midi_node = [&]() -> std::shared_ptr { + if (output_info_opt) + { + return make_cached_midi_node(m_output_nodes, *output_info_opt); + } + else + { + return nullptr; + } + }(); + + return std::make_shared(output_name, std::move(midi_node), *m_port_name_display); } std::shared_ptr NodeFactory::build_midi_channel_node() diff --git a/src/NodeFactory.hpp b/src/NodeFactory.hpp index ccf7c2e..02ad5d9 100644 --- a/src/NodeFactory.hpp +++ b/src/NodeFactory.hpp @@ -2,7 +2,7 @@ #include #include -#include +#include namespace mc { @@ -15,8 +15,6 @@ struct OutputInfo; class OutputNode; } // namespace midi -class DisconnectedMidiInNode; -class DisconnectedMidiOutNode; class LogNode; class MidiChannelNode; class MidiInNode; @@ -34,12 +32,10 @@ class NodeFactory final NodeFactory& operator=(const NodeFactory&) = delete; NodeFactory& operator=(NodeFactory&&) = delete; - std::shared_ptr build_midi_node(const midi::InputInfo& input_info); - std::shared_ptr build_midi_node(const midi::OutputInfo& output_info); - std::shared_ptr build_disconnected_midi_in_node( - const std::string& input_name); - std::shared_ptr build_disconnected_midi_out_node( - const std::string& output_name); + std::shared_ptr build_midi_node(const midi::InputInfo& input_info); + std::shared_ptr build_midi_node(const midi::OutputInfo& output_info); + std::shared_ptr build_midi_in_node(std::string_view input_name); + std::shared_ptr build_midi_out_node(std::string_view output_name); std::shared_ptr build_midi_channel_node(); std::shared_ptr build_log_node(); diff --git a/src/NodeSerializer.cpp b/src/NodeSerializer.cpp index 91dc307..2c047af 100644 --- a/src/NodeSerializer.cpp +++ b/src/NodeSerializer.cpp @@ -5,16 +5,12 @@ #include "imnodes.h" #include "nlohmann/json.hpp" -#include "DisconnectedMidiInNode.hpp" -#include "DisconnectedMidiOutNode.hpp" #include "LogNode.hpp" #include "MidiChannelNode.hpp" #include "MidiInNode.hpp" #include "MidiOutNode.hpp" #include "NodeFactory.hpp" #include "midi/MessageTypeMask.hpp" -#include "midi/MidiInfo.hpp" -#include "midi/MidiProbe.hpp" NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(ImVec2, x, y); @@ -53,28 +49,12 @@ void NodeSerializer::serialize_node(json& j, const MidiInNode& node) const { j = json{ {"type", "midi_in" }, - {"input_name", node.m_input_info.m_name}, + {"input_name", node.m_input_name }, {"message_type_mask", node.m_message_type_mask}, }; } -void NodeSerializer::serialize_node(json& j, const DisconnectedMidiInNode& node) const -{ - j = json{ - {"type", "midi_in" }, - {"input_name", node.m_input_name} - }; -} - void NodeSerializer::serialize_node(json& j, const MidiOutNode& node) const -{ - j = json{ - {"type", "midi_out" }, - {"output_name", node.m_output_info.m_name} - }; -} - -void NodeSerializer::serialize_node(json& j, const DisconnectedMidiOutNode& node) const { j = json{ {"type", "midi_out" }, @@ -104,35 +84,19 @@ std::shared_ptr NodeSerializer::deserialize_node(const json& j) const std::shared_ptr node; if (node_type == "midi_in") { - const auto input_name = j.at("input_name").get(); - const auto input_info_opt = midi::MidiProbe::get_valid_input(input_name); - if (input_info_opt.has_value()) - { - auto midi_in_node = m_node_factory->build_midi_node(input_info_opt.value()); - if (j.contains("message_type_mask")) - { - midi_in_node->set_message_type_mask( - j.at("message_type_mask").get()); - } - node = midi_in_node; - } - else + const auto input_name = j.at("input_name").get(); + auto midi_in_node = m_node_factory->build_midi_in_node(input_name); + if (j.contains("message_type_mask")) { - node = m_node_factory->build_disconnected_midi_in_node(input_name); + midi_in_node->set_message_type_mask( + j.at("message_type_mask").get()); } + node = midi_in_node; } else if (node_type == "midi_out") { - const auto output_name = j.at("output_name").get(); - const auto output_info_opt = midi::MidiProbe::get_valid_output(output_name); - if (output_info_opt.has_value()) - { - node = m_node_factory->build_midi_node(output_info_opt.value()); - } - else - { - node = m_node_factory->build_disconnected_midi_out_node(output_name); - } + const auto output_name = j.at("output_name").get(); + node = m_node_factory->build_midi_out_node(output_name); } else if (node_type == "midi_channel") { diff --git a/src/NodeSerializer.hpp b/src/NodeSerializer.hpp index 3b6c19a..48abf63 100644 --- a/src/NodeSerializer.hpp +++ b/src/NodeSerializer.hpp @@ -6,8 +6,6 @@ namespace mc { -class DisconnectedMidiInNode; -class DisconnectedMidiOutNode; class LogNode; class MidiChannelNode; class MidiInNode; @@ -22,8 +20,6 @@ class NodeSerializer final void serialize_node(nlohmann::json& j, const Node& node) const; - void serialize_node(nlohmann::json& j, const DisconnectedMidiInNode& node) const; - void serialize_node(nlohmann::json& j, const DisconnectedMidiOutNode& node) const; void serialize_node(nlohmann::json& j, const LogNode& node) const; void serialize_node(nlohmann::json& j, const MidiChannelNode& node) const; void serialize_node(nlohmann::json& j, const MidiInNode& node) const; diff --git a/src/PortNameDisplay.cpp b/src/PortNameDisplay.cpp index efddf4a..697a8dd 100644 --- a/src/PortNameDisplay.cpp +++ b/src/PortNameDisplay.cpp @@ -4,46 +4,25 @@ namespace mc { -namespace -{ - -std::string abbreviate_port_name(const std::string& port_name) -{ - const std::regex re(R"(^(.+):(\1.*) \d+:\d+$)"); - std::smatch results; - if (std::regex_match(port_name, results, re)) - { - return results[2].str(); - } - else - { - return port_name; - } -} - -} // namespace PortNameDisplay::PortNameDisplay(const bool initial_show_full_port_names) : m_show_full_port_names(initial_show_full_port_names) { } -std::string PortNameDisplay::get_port_name(const midi::InputInfo& input_info) const +std::string PortNameDisplay::get_port_name(std::string_view full_name) const { - if (m_show_full_port_names) + const std::regex re(R"(^(.+):(\1.*) \d+:\d+$)"); + std::smatch results; + std::string full_name_copy(full_name); + if (!m_show_full_port_names && std::regex_match(full_name_copy, results, re)) { - return input_info.m_name; + return results[2].str(); } - return abbreviate_port_name(input_info.m_name); -} - -std::string PortNameDisplay::get_port_name(const midi::OutputInfo& output_info) const -{ - if (m_show_full_port_names) + else { - return output_info.m_name; + return full_name_copy; } - return abbreviate_port_name(output_info.m_name); } } // namespace mc diff --git a/src/PortNameDisplay.hpp b/src/PortNameDisplay.hpp index ca3a0fb..2eec209 100644 --- a/src/PortNameDisplay.hpp +++ b/src/PortNameDisplay.hpp @@ -1,7 +1,6 @@ #pragma once #include - -#include "midi/MidiInfo.hpp" +#include namespace mc { @@ -14,8 +13,7 @@ class PortNameDisplay final const bool& get_show_full_port_names() const { return m_show_full_port_names; } void set_show_full_port_names(const bool value) { m_show_full_port_names = value; } - std::string get_port_name(const midi::InputInfo& input_info) const; - std::string get_port_name(const midi::OutputInfo& output_info) const; + std::string get_port_name(std::string_view full_name) const; private: bool m_show_full_port_names; diff --git a/src/midi/MessageTypeMask.hpp b/src/midi/MessageTypeMask.hpp index 869aee3..f04bcf5 100644 --- a/src/midi/MessageTypeMask.hpp +++ b/src/midi/MessageTypeMask.hpp @@ -8,6 +8,8 @@ struct MessageTypeMask bool m_sysex_enabled{true}; bool m_time_enabled{true}; bool m_sensing_enabled{true}; + + constexpr bool operator==(const MessageTypeMask&) const = default; }; diff --git a/src/midi/MidiProbe.cpp b/src/midi/MidiProbe.cpp index f0558c1..e6235c9 100644 --- a/src/midi/MidiProbe.cpp +++ b/src/midi/MidiProbe.cpp @@ -36,7 +36,7 @@ std::vector get_connections() } template -std::optional get_valid_info(const std::string& name, const std::vector& infos) +std::optional get_valid_info(std::string_view name, const std::vector& infos) { auto found_it = std::find_if(infos.begin(), infos.end(), [&](const auto& info) { return info.m_name == name; @@ -80,12 +80,12 @@ std::vector MidiProbe::get_outputs() return get_connections(); } -std::optional MidiProbe::get_valid_input(const std::string& input_name) +std::optional MidiProbe::get_valid_input(std::string_view input_name) { return get_valid_info(input_name, get_inputs()); } -std::optional MidiProbe::get_valid_output(const std::string& output_name) +std::optional MidiProbe::get_valid_output(std::string_view output_name) { return get_valid_info(output_name, get_outputs()); } diff --git a/src/midi/MidiProbe.hpp b/src/midi/MidiProbe.hpp index 23d0c05..2d8a567 100644 --- a/src/midi/MidiProbe.hpp +++ b/src/midi/MidiProbe.hpp @@ -1,6 +1,6 @@ #pragma once #include -#include +#include #include #include "MidiInfo.hpp" @@ -18,8 +18,8 @@ class MidiProbe final static std::vector get_inputs(); static std::vector get_outputs(); - static std::optional get_valid_input(const std::string& input_name); - static std::optional get_valid_output(const std::string& output_name); + static std::optional get_valid_input(std::string_view input_name); + static std::optional get_valid_output(std::string_view output_name); static std::optional get_valid_input_port_name(unsigned id); static std::optional get_valid_output_port_name(unsigned id);