From 6da14e1590935710055ebc81ba55017b457ca1ad Mon Sep 17 00:00:00 2001 From: Eddy Pedroni Date: Tue, 22 Jul 2025 22:00:00 +0200 Subject: Initial daemon implementation, no routing yet --- daemon/src/configuration.h | 17 +++++++++ daemon/src/connection_manager.cpp | 74 +++++++++++++++++++++++++++++++++++++++ daemon/src/connection_manager.h | 34 ++++++++++++++++++ daemon/src/main.cpp | 24 +++++++++++-- daemon/src/message.h | 42 ++++++++++++++++++++++ daemon/src/routing.cpp | 24 +++++++++++++ daemon/src/routing.h | 24 +++++++++++++ daemon/src/types.h | 15 ++++++++ 8 files changed, 251 insertions(+), 3 deletions(-) create mode 100644 daemon/src/configuration.h create mode 100644 daemon/src/connection_manager.cpp create mode 100644 daemon/src/connection_manager.h create mode 100644 daemon/src/message.h create mode 100644 daemon/src/routing.cpp create mode 100644 daemon/src/routing.h create mode 100644 daemon/src/types.h diff --git a/daemon/src/configuration.h b/daemon/src/configuration.h new file mode 100644 index 0000000..4189315 --- /dev/null +++ b/daemon/src/configuration.h @@ -0,0 +1,17 @@ +#pragma once + +#include "types.h" + +#include + +namespace midi_router +{ + +struct Configuration +{ + + Device_Map const devices; + Route_Map const routes; +}; + +} // namespace midi_router diff --git a/daemon/src/connection_manager.cpp b/daemon/src/connection_manager.cpp new file mode 100644 index 0000000..820f1d2 --- /dev/null +++ b/daemon/src/connection_manager.cpp @@ -0,0 +1,74 @@ +#include "connection_manager.h" + +#include +#include + +namespace midi_router +{ + +struct Device_Connection +{ + Device_Id source_id; + std::function const & submit; + RtMidiIn midi_in {}; + RtMidiOut midi_out {}; +}; + +static void +callback(double time_stamp, std::vector *raw, void *user_data) +{ + Device_Connection* device = static_cast(user_data); + + if (raw->size() != 3) + { + std::cerr << "Received message with wrong size from " << device->source_id << ", dropping\n"; + } + + Message message { device->source_id, {raw->at(0), raw->at(1), raw->at(2)} }; + device->submit(message); +} + +Connection_Manager::Connection_Manager(Device_Map const & device_map, std::function const & submit): + m_device_map(device_map), + m_submit(submit), + m_connections{} + { + for (auto const & [name, id] : device_map) + { + m_connections[id] = std::make_unique(id, submit); + auto & connection = m_connections[id]; + + connection->midi_in.setCallback(&callback, connection.get()); + connection->midi_in.ignoreTypes(true, true, true); + + if (!open_port(&connection->midi_in, name)) + { + std::cerr << "Input port not found for device " << name << "\n"; + } + + if (!open_port(&connection->midi_out, name)) + { + std::cerr << "Output port not found for device " << name << "\n"; + } + + } + } + +Connection_Manager::~Connection_Manager() = default; + +bool +Connection_Manager::open_port(RtMidi* const midi, std::string const & name) +{ + for (std::size_t i = 0; i < midi->getPortCount(); ++i) + { + if (midi->getPortName(i).contains(name)) + { + midi->openPort(i); + return true; + } + } + return false; +} + +} // namespace midi_router + diff --git a/daemon/src/connection_manager.h b/daemon/src/connection_manager.h new file mode 100644 index 0000000..240e436 --- /dev/null +++ b/daemon/src/connection_manager.h @@ -0,0 +1,34 @@ +#pragma once + +#include "types.h" +#include "message.h" + +#include +#include +#include +#include + +class RtMidi; + +namespace midi_router +{ + +struct Device_Connection; + +class Connection_Manager +{ +public: + Connection_Manager(Device_Map const & device_map, std::function const & submit); + + ~Connection_Manager(); + +private: + static bool + open_port(RtMidi* const midi, std::string const & name); + + Device_Map const & m_device_map; + std::function m_submit; + std::map> m_connections; +}; + +} // namespace midi_router diff --git a/daemon/src/main.cpp b/daemon/src/main.cpp index 68d0a96..dc72433 100644 --- a/daemon/src/main.cpp +++ b/daemon/src/main.cpp @@ -1,8 +1,26 @@ +#include "connection_manager.h" +#include "configuration.h" +#include "routing.h" + #include -#include -#include "concurrentqueue/blockingconcurrentqueue.h" +#include +#include + +using namespace midi_router; int main() { - std::cout << "Hello, world\n"; + Configuration const config {{ + {"Deluge MIDI 1", "deluge"}, + {"MPK mini Plus MIDI 1", "mpk"}, + }}; + + Router router {}; + Connection_Manager cm { config.devices, [&](Message const & m){ router.submit(m); } }; // works + //Connection_Manager cm { config.devices, std::bind(&Router::submit, &router, std::placeholders::_1) }; // why doesn't this work? + + while(true) + { + std::this_thread::sleep_for(std::chrono::seconds(1)); + } } diff --git a/daemon/src/message.h b/daemon/src/message.h new file mode 100644 index 0000000..9339118 --- /dev/null +++ b/daemon/src/message.h @@ -0,0 +1,42 @@ +#pragma once + +#include "types.h" + +#include +#include +#include + +namespace midi_router +{ + +struct Message +{ + enum class Type + { + NOTE_OFF = 0x8u, + NOTE_ON = 0x9u, + POLY_AT = 0xAu, + CONTROL_CHANGE = 0xBu, + PROGRAM_CHANGE = 0xCu, + CHANNEL_AT = 0xDu, + PITCH_WHEEL = 0xEu, + + CLOCK = 0xF8u, + MEAS_END = 0xF9u, + START = 0xFAu, + CONTINUE = 0xFBu, + STOP = 0xFCu, + }; + + Device_Id const & source_id; + std::array const bytes; + + Type + type() const + { + if (bytes[0] & 0xF0 == 0xF0) return static_cast(bytes[0]); + else return static_cast(bytes[0] >> 4); + } +}; + +} // namespace midi_router diff --git a/daemon/src/routing.cpp b/daemon/src/routing.cpp new file mode 100644 index 0000000..709d815 --- /dev/null +++ b/daemon/src/routing.cpp @@ -0,0 +1,24 @@ +#include "routing.h" + +#include + +namespace midi_router +{ + +void +Router::route(Route_Map const & config) const +{ + +} + +void +Router::submit(Message const & message) +{ + if (!m_queue.try_enqueue(message)) + { + std::cout << "Failed to enqueue message from " << message.source_id << "\n"; + } +} + +} // namespace midi_router + diff --git a/daemon/src/routing.h b/daemon/src/routing.h new file mode 100644 index 0000000..2d68391 --- /dev/null +++ b/daemon/src/routing.h @@ -0,0 +1,24 @@ +#pragma once + +#include "message.h" +#include "configuration.h" + +#include "concurrentqueue/blockingconcurrentqueue.h" + +namespace midi_router +{ + +class Router +{ +public: + void + route(Route_Map const & config) const; + + void + submit(Message const & message); + +private: + moodycamel::BlockingConcurrentQueue m_queue {}; +}; + +} // namespace midi_router diff --git a/daemon/src/types.h b/daemon/src/types.h new file mode 100644 index 0000000..f09fb88 --- /dev/null +++ b/daemon/src/types.h @@ -0,0 +1,15 @@ +#pragma once + +#include +#include +#include + +namespace midi_router +{ + +using Device_Id = std::string; +using Device_Map = std::map; +using Target_List = std::vector; +using Route_Map = std::map; + +} // namespace midi_router -- cgit v1.2.3