MayaFlux 0.4.0
Digital-First Multimedia Processing Framework
Loading...
Searching...
No Matches
CoreMidiBackend.hpp
Go to the documentation of this file.
1#pragma once
2
3#ifdef MAYAFLUX_PLATFORM_MACOS
4
5#include "InputBackend.hpp"
6
7#include <CoreMIDI/CoreMIDI.h>
8
9namespace MayaFlux::Core {
10
11/**
12 * @class CoreMidiBackend
13 * @brief CoreMIDI-native MIDI backend for macOS
14 *
15 * Wraps Apple's CoreMIDI framework directly with no third-party
16 * dependencies.
17 *
18 * Intended feature parity:
19 * - Multiple simultaneous MIDI input ports
20 * - Port filtering by name
21 * - Virtual MIDI port creation
22 * - Device hotplug detection
23 * - SysEx support
24 * - MIDI output support
25 *
26 * Threading model:
27 * - CoreMIDI invokes MIDIReadProc on CoreMIDI-managed threads
28 * - Callbacks push InputValue to InputManager's queue (thread-safe)
29 * - No polling thread required
30 * - Device notifications arrive through MIDINotifyProc
31 */
32class MAYAFLUX_API CoreMidiBackend : public IInputBackend {
33public:
34 struct Config {
35 std::vector<std::string> input_port_filters;
36 std::vector<std::string> output_port_filters;
37 bool auto_open_inputs { true };
38 bool auto_open_outputs { false };
39 bool enable_virtual_port { false };
40 bool enable_sysex { true };
41 std::string virtual_port_name { "MayaFlux" };
42 };
43
44 CoreMidiBackend();
45 explicit CoreMidiBackend(Config config);
46 ~CoreMidiBackend() override;
47
48 CoreMidiBackend(const CoreMidiBackend&) = delete;
49 CoreMidiBackend& operator=(const CoreMidiBackend&) = delete;
50 CoreMidiBackend(CoreMidiBackend&&) = delete;
51 CoreMidiBackend& operator=(CoreMidiBackend&&) = delete;
52
53 // ===================================================================================
54 // IInputBackend Implementation
55 // ===================================================================================
56
57 bool initialize() override;
58 void start() override;
59 void stop() override;
60 void shutdown() override;
61
62 [[nodiscard]] bool is_initialized() const override { return m_initialized.load(); }
63 [[nodiscard]] bool is_running() const override { return m_running.load(); }
64
65 [[nodiscard]] std::vector<InputDeviceInfo> get_devices() const override;
66 size_t refresh_devices() override;
67
68 bool open_device(uint32_t device_id) override;
69 void close_device(uint32_t device_id) override;
70
71 [[nodiscard]] bool is_device_open(uint32_t device_id) const override;
72 [[nodiscard]] std::vector<uint32_t> get_open_devices() const override;
73
74 void set_input_callback(InputCallback callback) override;
75 void set_device_callback(DeviceCallback callback) override;
76
77 [[nodiscard]] InputType get_type() const override { return InputType::MIDI; }
78 [[nodiscard]] std::string get_name() const override { return "MIDI (CoreMIDI)"; }
79 [[nodiscard]] std::string get_version() const override;
80
81private:
82 struct MIDIPortInfo : InputDeviceInfo {
83 MIDIUniqueID unique_id { 0 };
84 MIDIEndpointRef endpoint { 0 };
85 };
86
87 struct MIDIPortState {
88 MIDIPortInfo info;
89 uint32_t device_id { 0 };
90
91 MIDIPortRef input_port { 0 };
92
93 std::atomic<bool> active { false };
94
95 std::function<void(const InputValue&)> input_callback;
96 };
97
98 Config m_config;
99
100 std::atomic<bool> m_initialized { false };
101 std::atomic<bool> m_running { false };
102
103 MIDIClientRef m_client { 0 };
104 MIDIEndpointRef m_virtual_destination { 0 };
105
106 mutable std::mutex m_devices_mutex;
107 std::unordered_map<uint32_t, MIDIPortInfo> m_enumerated_devices;
108 std::unordered_map<uint32_t, std::shared_ptr<MIDIPortState>> m_open_devices;
109 uint32_t m_next_device_id { 1 };
110
111 InputCallback m_input_callback;
112 DeviceCallback m_device_callback;
113 mutable std::mutex m_callback_mutex;
114
115 bool port_matches_filter(const std::string& port_name) const;
116 uint32_t find_or_assign_device_id(MIDIUniqueID unique_id);
117
118 void create_virtual_port_if_enabled();
119 void notify_device_change(const InputDeviceInfo& info, bool connected);
120
121 static void virtual_destination_callback(
122 const MIDIPacketList* packet_list,
123 void* read_proc_ref_con,
124 void* src_conn_ref_con);
125
126 static void midi_read_callback(
127 const MIDIPacketList* packet_list,
128 void* read_proc_ref_con,
129 void* src_conn_ref_con);
130
131 static void midi_notify_callback(
132 const MIDINotification* notification,
133 void* ref_con);
134
135 void destroy_open_port(MIDIPortState& state);
136};
137
138} // namespace MayaFlux::Core
139
140#endif // MAYAFLUX_PLATFORM_MACOS
void initialize()
Definition main.cpp:11
InputType
Input backend type enumeration.
std::function< void(const InputValue &)> InputCallback
Callback signature for input events.
std::function< void(const InputDeviceInfo &, bool connected)> DeviceCallback
Callback signature for device connection/disconnection events.
void shutdown()
Release stored references.
Definition Forma.cpp:168
void stop()
Stop all Portal::Graphics operations.
Definition Graphics.cpp:69
bool is_initialized()
Checks if the default engine has been initialized.
Definition Core.cpp:52