-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
4 changed files
with
174 additions
and
6 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |