diff options
author | Eddy Pedroni <epedroni@pm.me> | 2025-07-22 22:00:00 +0200 |
---|---|---|
committer | Eddy Pedroni <epedroni@pm.me> | 2025-07-22 22:00:00 +0200 |
commit | 6da14e1590935710055ebc81ba55017b457ca1ad (patch) | |
tree | 799daf6f75331183ea48ece00d62ec92f0fc7a51 | |
parent | f0835be9ffcae8e5c74c8fc6a0da2f7bc49343ac (diff) |
Initial daemon implementation, no routing yet
-rw-r--r-- | daemon/src/configuration.h | 17 | ||||
-rw-r--r-- | daemon/src/connection_manager.cpp | 74 | ||||
-rw-r--r-- | daemon/src/connection_manager.h | 34 | ||||
-rw-r--r-- | daemon/src/main.cpp | 24 | ||||
-rw-r--r-- | daemon/src/message.h | 42 | ||||
-rw-r--r-- | daemon/src/routing.cpp | 24 | ||||
-rw-r--r-- | daemon/src/routing.h | 24 | ||||
-rw-r--r-- | daemon/src/types.h | 15 |
8 files changed, 251 insertions, 3 deletions
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 <map> + +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 <iostream> +#include <rtmidi/RtMidi.h> + +namespace midi_router +{ + +struct Device_Connection +{ + Device_Id source_id; + std::function<void(Message const &)> const & submit; + RtMidiIn midi_in {}; + RtMidiOut midi_out {}; +}; + +static void +callback(double time_stamp, std::vector<unsigned char> *raw, void *user_data) +{ + Device_Connection* device = static_cast<Device_Connection*>(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<void(Message const &)> 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<Device_Connection>(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 <functional> +#include <string> +#include <map> +#include <memory> + +class RtMidi; + +namespace midi_router +{ + +struct Device_Connection; + +class Connection_Manager +{ +public: + Connection_Manager(Device_Map const & device_map, std::function<void(Message const &)> const & submit); + + ~Connection_Manager(); + +private: + static bool + open_port(RtMidi* const midi, std::string const & name); + + Device_Map const & m_device_map; + std::function<void(Message const &)> m_submit; + std::map<std::string, std::unique_ptr<Device_Connection>> 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 <iostream> -#include <rtmidi/RtMidi.h> -#include "concurrentqueue/blockingconcurrentqueue.h" +#include <thread> +#include <chrono> + +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 <string> +#include <cstdint> +#include <array> + +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<std::uint8_t, 3> const bytes; + + Type + type() const + { + if (bytes[0] & 0xF0 == 0xF0) return static_cast<Type>(bytes[0]); + else return static_cast<Type>(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 <iostream> + +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<Message> 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 <string> +#include <map> +#include <vector> + +namespace midi_router +{ + +using Device_Id = std::string; +using Device_Map = std::map<std::string, Device_Id>; +using Target_List = std::vector<Device_Id>; +using Route_Map = std::map<Device_Id, Target_List>; + +} // namespace midi_router |