Skip to content

Commit

Permalink
Implemented MidiGraph
Browse files Browse the repository at this point in the history
  • Loading branch information
mfep committed Mar 28, 2024
1 parent 825dc2e commit 19a7f1c
Show file tree
Hide file tree
Showing 4 changed files with 174 additions and 6 deletions.
9 changes: 3 additions & 6 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ add_subdirectory(external/libspng EXCLUDE_FROM_ALL)
set(RTMIDI_API_JACK OFF)
set(RTMIDI_BUILD_STATIC_LIBS ON)
add_subdirectory(external/rtmidi EXCLUDE_FROM_ALL)
add_subdirectory(src/midi)

set(sources
${g_font_cpp_path}
Expand Down Expand Up @@ -66,10 +67,6 @@ set(sources
src/ResourceLoader.cpp
src/Theme.cpp
src/Version.cpp
src/midi/InputObserver.cpp
src/midi/MidiEngine.cpp
src/midi/MidiProbe.cpp
src/midi/OutputObserver.cpp
)

if(WIN32)
Expand Down Expand Up @@ -105,15 +102,15 @@ target_link_libraries(midiconn PRIVATE
SDL2::SDL2
fmt::fmt
freetype
resources)
resources
midi)
if(NOT WIN32 AND MC_CHECK_FOR_UPDATES)
target_link_libraries(midiconn PRIVATE curl)
endif()
target_compile_definitions(midiconn PRIVATE
SPDLOG_ACTIVE_LEVEL=SPDLOG_LEVEL_DEBUG
IMGUI_ENABLE_FREETYPE
)
target_compile_features(midiconn PRIVATE cxx_std_20)

set(CPACK_PACKAGE_NAME "midiconn")
set(CPACK_PACKAGE_VENDOR "safeworlds")
Expand Down
10 changes: 10 additions & 0 deletions src/midi/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
add_library(midi
InputObserver.cpp
MidiEngine.cpp
MidiGraph.cpp
MidiProbe.cpp
OutputObserver.cpp
)

target_compile_features(midi PUBLIC cxx_std_20)
target_link_libraries(midi PRIVATE fmt::fmt rtmidi spdlog::spdlog)
101 changes: 101 additions & 0 deletions src/midi/MidiGraph.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
#include "MidiGraph.hpp"

namespace mc::midi
{

Node::~Node()
{
for (auto& conn : m_sender_connections)
{
Connection::destroy(conn);
}
for (auto& conn : m_receiver_connections)
{
Connection::destroy(conn);
}
}

void Node::process(data_span data)
{
}

void Node::broadcast_data(data_span data)
{
size_t idx = 0;
for (auto it = m_sender_connections.begin(), end = m_sender_connections.end(); it != end;
++it, ++idx)
{
if (idx == 0)
{
(*it)->receiver()->receive_data(data);
}
else
{
data_vec data_copy(data.size());
std::copy(data.begin(), data.end(), data_copy.begin());
(*it)->receiver()->receive_data(data_copy);
}
}
}

void Node::connect_as_sender(connection_ptr connection)
{
m_sender_connections.emplace(connection);
}

void Node::connect_as_receiver(connection_ptr connection)
{
m_receiver_connections.emplace(connection);
}

void Node::remove_connection(connection_ptr connection)
{
remove_connection_impl(m_sender_connections, connection);
remove_connection_impl(m_receiver_connections, connection);
}

void Node::remove_connection_impl(std::set<connection_ptr>& set, connection_ptr connection)
{
set.erase(connection);
}

void Node::receive_data(data_span data)
{
process(data);
broadcast_data(data);
}

weak_connection_ptr Connection::create(Node& sender, Node& receiver)
{
if (is_loop(sender, receiver))
{
return weak_connection_ptr();
}
const auto conn = std::shared_ptr<Connection>(new Connection());
conn->m_sender = &sender;
conn->m_receiver = &receiver;
sender.connect_as_sender(conn);
receiver.connect_as_receiver(conn);
return conn;
}

void Connection::destroy(weak_connection_ptr connection)
{
auto connection_shared = connection.lock();
if (connection_shared)
{
connection_shared->m_sender->remove_connection(connection_shared);
connection_shared->m_receiver->remove_connection(connection_shared);
}
}

bool Connection::is_loop(Node& sender, Node& receiver)
{
return &sender == &receiver || std::any_of(receiver.m_sender_connections.begin(),
receiver.m_sender_connections.end(),
[&sender](const connection_ptr& connection) {
return is_loop(sender, *connection->m_receiver);
});
}

} // namespace mc::midi
60 changes: 60 additions & 0 deletions src/midi/MidiGraph.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
#pragma once

#include <algorithm>
#include <memory>
#include <set>
#include <span>
#include <vector>

namespace mc::midi
{

class Connection;

using connection_ptr = std::shared_ptr<Connection>;
using weak_connection_ptr = std::weak_ptr<Connection>;
using data_vec = std::vector<unsigned char>;
using data_span = std::span<unsigned char>;

class Node
{
public:
virtual ~Node();

protected:
virtual void process(data_span data);
void broadcast_data(data_span data);

private:
friend class Connection;

void connect_as_sender(connection_ptr connection);
void connect_as_receiver(connection_ptr connection);
void remove_connection(connection_ptr connection);
void remove_connection_impl(std::set<connection_ptr>& set, connection_ptr connection);

void receive_data(data_span data);

std::set<connection_ptr> m_sender_connections;
std::set<connection_ptr> m_receiver_connections;
};

class Connection final
{
private:
Connection() = default;

public:
static weak_connection_ptr create(Node& sender, Node& receiver);
static void destroy(weak_connection_ptr connection);

Node* receiver() const { return m_receiver; }

private:
static bool is_loop(Node& sender, Node& receiver);

Node* m_sender;
Node* m_receiver;
};

} // namespace mc::midi

0 comments on commit 19a7f1c

Please sign in to comment.