MayaFlux 1.0.0
Digital-First Multimedia Processing Framework
Loading...
Searching...
No Matches
WinMmMidiBackend.hpp
Go to the documentation of this file.
1#pragma once
2
3#ifdef MAYAFLUX_PLATFORM_WINDOWS
4
5#include "InputBackend.hpp"
6
7#include <windows.h>
8#include <mmsystem.h>
9
10#ifdef ERROR
11#undef ERROR
12#endif
13
14namespace MayaFlux::Core {
15
16/**
17 * @class WinMmMidiBackend
18 * @brief WinMM-native MIDI input backend for Windows
19 *
20 * Wraps midiIn* API directly. Zero additional dependencies beyond winmm.lib.
21 * Compatible with Windows 10 and later. On Windows 11 24H2+ with Windows MIDI
22 * Services installed, WinMM calls are automatically routed through the new
23 * service, gaining multi-client support without any code changes.
24 *
25 * Threading model:
26 * - midiInOpen uses CALLBACK_FUNCTION; Windows calls midi_callback on a
27 * dedicated MM thread per open device
28 * - Callbacks push InputValue to InputManager's queue (thread-safe)
29 * - No polling thread needed
30 * - SysEx uses double-buffered MIDIHDR; buffers are re-queued from the callback
31 */
32class MAYAFLUX_API WinMmMidiBackend : public IInputBackend {
33public:
34 struct Config {
35 std::vector<std::string> input_port_filters;
36 bool auto_open_inputs { true };
37 bool enable_sysex { true };
38 std::string virtual_port_name { "MayaFlux" };
39 };
40
41 WinMmMidiBackend();
42 explicit WinMmMidiBackend(Config config);
43 ~WinMmMidiBackend() override;
44
45 WinMmMidiBackend(const WinMmMidiBackend&) = delete;
46 WinMmMidiBackend& operator=(const WinMmMidiBackend&) = delete;
47 WinMmMidiBackend(WinMmMidiBackend&&) = delete;
48 WinMmMidiBackend& operator=(WinMmMidiBackend&&) = delete;
49
50 bool initialize() override;
51 void start() override;
52 void stop() override;
53 void shutdown() override;
54
55 [[nodiscard]] bool is_initialized() const override { return m_initialized.load(); }
56 [[nodiscard]] bool is_running() const override { return m_running.load(); }
57
58 [[nodiscard]] std::vector<InputDeviceInfo> get_devices() const override;
59 size_t refresh_devices() override;
60
61 bool open_device(uint32_t device_id) override;
62 void close_device(uint32_t device_id) override;
63 [[nodiscard]] bool is_device_open(uint32_t device_id) const override;
64 [[nodiscard]] std::vector<uint32_t> get_open_devices() const override;
65
66 void set_input_callback(InputCallback callback) override;
67 void set_device_callback(DeviceCallback callback) override;
68
69 [[nodiscard]] InputType get_type() const override { return InputType::MIDI; }
70 [[nodiscard]] std::string get_name() const override { return "MIDI (WinMM)"; }
71 [[nodiscard]] std::string get_version() const override;
72
73private:
74 static constexpr size_t k_sysex_buf_size { 256 };
75 static constexpr size_t k_sysex_buf_count { 2 };
76
77 struct MIDIPortInfo : InputDeviceInfo {
78 UINT winmm_device_id { 0 };
79 };
80
81 struct MIDIPortState {
82 MIDIPortInfo info;
83 uint32_t device_id { 0 };
84 HMIDIIN handle { nullptr };
85 std::atomic<bool> active { false };
86 std::function<void(const InputValue&)> input_callback;
87 MIDIHDR sysex_headers[k_sysex_buf_count] {};
88 std::array<std::vector<uint8_t>, k_sysex_buf_count> sysex_bufs;
89 };
90
91 Config m_config;
92 std::atomic<bool> m_initialized { false };
93 std::atomic<bool> m_running { false };
94
95 mutable std::mutex m_devices_mutex;
96 std::unordered_map<uint32_t, MIDIPortInfo> m_enumerated_devices;
97 std::unordered_map<uint32_t, std::shared_ptr<MIDIPortState>> m_open_devices;
98 uint32_t m_next_device_id { 1 };
99
100 InputCallback m_input_callback;
101 DeviceCallback m_device_callback;
102 mutable std::mutex m_callback_mutex;
103
104 bool port_matches_filter(const std::string& name) const;
105 uint32_t find_or_assign_device_id(UINT winmm_id);
106 void queue_sysex_buffers(MIDIPortState& state);
107 void notify_device_change(const InputDeviceInfo& info, bool connected);
108
109 static void CALLBACK midi_callback(HMIDIIN handle, UINT msg,
110 DWORD_PTR user_data, DWORD_PTR param1, DWORD_PTR param2);
111};
112
113} // namespace MayaFlux::Core
114
115#endif // MAYAFLUX_PLATFORM_WINDOWS
PickCallback callback
Definition Picker.cpp:22
std::string name
Definition VKDevice.cpp:123
void initialize()
Definition main.cpp:10
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.
@ CALLBACK
Use callback for custom transition.
void shutdown()
Release stored references.
Definition Forma.cpp:58
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:85