MayaFlux 0.5.0
Digital-First Multimedia Processing Framework
Loading...
Searching...
No Matches
InputBinding.hpp
Go to the documentation of this file.
1#pragma once
2
3namespace MayaFlux::Core {
4
5/**
6 * @brief Input backend type enumeration
7 */
8enum class InputType : uint8_t {
9 HID, ///< Generic HID devices (game controllers, custom hardware)
10 MIDI, ///< MIDI controllers and instruments
11 OSC, ///< Open Sound Control (network)
12 SERIAL, ///< Serial port communication (Arduino, etc.)
13 TABLET, ///< Digitizers and styluses (pressure, tilt, rotation)
14 CUSTOM ///< User-defined input backends
15};
16
17// ────────────────────────────────────────────────────────────────────────────
18// Input Binding (Subscription Filter)
19// ────────────────────────────────────────────────────────────────────────────
20
21/**
22 * @struct InputBinding
23 * @brief Specifies what input an InputNode wants to receive
24 *
25 * Used when registering nodes to filter which input events they receive.
26 * Can match by backend type, specific device, or additional filters like
27 * MIDI channel or OSC address pattern.
28 */
29struct MAYAFLUX_API InputBinding {
30 InputType backend; ///< Which backend type
31 uint32_t device_id { 0 }; ///< Specific device (0 = any device)
32
33 std::optional<uint8_t> midi_channel; ///< Match specific MIDI channel (1-16)
34 std::optional<uint8_t> midi_message_type; ///< Match message type (0xB0=CC, 0x90=NoteOn, etc.)
35 std::optional<uint8_t> midi_cc_number; ///< Match specific CC number
36
37 std::optional<std::string> osc_address_pattern; ///< Match OSC address prefix
38
39 std::optional<uint16_t> hid_vendor_id; ///< Match HID vendor ID
40 std::optional<uint16_t> hid_product_id; ///< Match HID product ID
41
42 // ────────────────────────────────────────────────────────────────────────
43 // Factory Methods: Simple Bindings
44 // ────────────────────────────────────────────────────────────────────────
45
46 /**
47 * @brief Bind to HID device (any or specific)
48 * @param device_id Device ID (0 = any HID device)
49 */
50 static InputBinding hid(uint32_t device_id = 0);
51
52 /**
53 * @brief Bind to MIDI device
54 * @param device_id Device ID (0 = any MIDI device)
55 * @param channel MIDI channel filter (1-16, nullopt = any)
56 */
57 static InputBinding midi(uint32_t device_id = 0, std::optional<uint8_t> channel = {});
58
59 /**
60 * @brief Bind to OSC messages
61 * @param pattern OSC address pattern to match (empty = all)
62 */
63 static InputBinding osc(const std::string& pattern = "");
64
65 /**
66 * @brief Bind to Serial device
67 * @param device_id Device ID (0 = any Serial device)
68 */
69 static InputBinding serial(uint32_t device_id = 0);
70
71 /**
72 * @brief Bind to a tablet tool
73 * @param device_id Tool ID (0 = any tool, pen and eraser alike)
74 */
75 static InputBinding tablet(uint32_t device_id = 0);
76
77 // ────────────────────────────────────────────────────────────────────────
78 // Factory Methods: Advanced HID Bindings
79 // ────────────────────────────────────────────────────────────────────────
80
81 /**
82 * @brief Bind to HID device by vendor/product ID
83 * @param vid USB Vendor ID
84 * @param pid USB Product ID
85 *
86 * Matches any device with this VID/PID, regardless of enumeration order.
87 * Useful for binding to specific controller models.
88 */
89 static InputBinding hid_by_vid_pid(uint16_t vid, uint16_t pid);
90
91 // ────────────────────────────────────────────────────────────────────────
92 // Factory Methods: Advanced MIDI Bindings
93 // ────────────────────────────────────────────────────────────────────────
94
95 /**
96 * @brief Bind to MIDI Control Change messages
97 * @param cc_number CC number (0-127, nullopt = any CC)
98 * @param channel MIDI channel (1-16, nullopt = any channel)
99 * @param device_id Device ID (0 = any device)
100 */
101 static InputBinding midi_cc(
102 std::optional<uint8_t> cc_number = {},
103 std::optional<uint8_t> channel = {},
104 uint32_t device_id = 0);
105
106 /**
107 * @brief Bind to MIDI Note On messages
108 * @param channel MIDI channel (1-16, nullopt = any channel)
109 * @param device_id Device ID (0 = any device)
110 */
111 static InputBinding midi_note_on(
112 std::optional<uint8_t> channel = {},
113 uint32_t device_id = 0);
114
115 /**
116 * @brief Bind to MIDI Note Off messages
117 * @param channel MIDI channel (1-16, nullopt = any channel)
118 * @param device_id Device ID (0 = any device)
119 */
120 static InputBinding midi_note_off(
121 std::optional<uint8_t> channel = {},
122 uint32_t device_id = 0);
123
124 /**
125 * @brief Bind to MIDI Pitch Bend messages
126 * @param channel MIDI channel (1-16, nullopt = any channel)
127 * @param device_id Device ID (0 = any device)
128 */
129 static InputBinding midi_pitch_bend(
130 std::optional<uint8_t> channel = {},
131 uint32_t device_id = 0);
132
133 // ────────────────────────────────────────────────────────────────────────
134 // Chaining Methods (Builder Pattern)
135 // ────────────────────────────────────────────────────────────────────────
136
137 /**
138 * @brief Add MIDI channel filter
139 */
140 InputBinding& with_midi_channel(uint8_t channel);
141
142 /**
143 * @brief Add MIDI CC number filter
144 */
145 InputBinding& with_midi_cc(uint8_t cc);
146
147 /**
148 * @brief Add OSC address pattern filter
149 */
150 InputBinding& with_osc_pattern(const std::string& pattern);
151};
152
153// ────────────────────────────────────────────────────────────────────────────
154// Input Device Information
155// ────────────────────────────────────────────────────────────────────────────
156
157/**
158 * @struct InputDeviceInfo
159 * @brief Information about a connected input device
160 *
161 * Returned by device enumeration. Contains both universal fields
162 * and backend-specific fields (only populated when relevant).
163 */
164struct MAYAFLUX_API InputDeviceInfo {
165 // ─── Universal Fields ───
166 uint32_t id; ///< Unique device identifier within backend
167 std::string name; ///< Human-readable device name
168 std::string manufacturer; ///< Device manufacturer (if available)
169 InputType backend_type; ///< Which backend manages this device
170 bool is_connected; ///< Current connection state
171
172 // ─── HID-Specific ───
173 uint16_t vendor_id {}; ///< USB Vendor ID
174 uint16_t product_id {}; ///< USB Product ID
175 std::string serial_number; ///< Device serial (if available)
176
177 // ─── MIDI-Specific ───
178 bool is_input {}; ///< Can receive MIDI
179 bool is_output {}; ///< Can send MIDI
180 uint8_t port_number {}; ///< MIDI port index
181
182 // ─── OSC-Specific ───
183 std::string address; ///< IP address or hostname
184 uint16_t port {}; ///< UDP/TCP port
185
186 // ─── Serial-Specific ───
187 std::string port_name; ///< e.g., "/dev/ttyUSB0" or "COM3"
188 uint32_t baud_rate {}; ///< Serial baud rate
189
190 // ────────────────────────────────────────────────────────────────────────
191 // Convenience: Create InputBinding from this device
192 // ────────────────────────────────────────────────────────────────────────
193
194 /**
195 * @brief Create a binding to this specific device
196 * @return InputBinding configured for this device
197 */
198 [[nodiscard]] InputBinding to_binding() const;
199
200 /**
201 * @brief Create a binding to this device with additional filters
202 */
203 [[nodiscard]] InputBinding to_binding_midi(std::optional<uint8_t> channel) const;
204 [[nodiscard]] InputBinding to_binding_osc(const std::string& pattern) const;
205};
206
207/**
208 * @brief Generic input value container
209 *
210 * Represents a single input event from any backend type.
211 * Uses variant to handle different data formats efficiently.
212 */
213struct MAYAFLUX_API InputValue {
214 /**
215 * @brief Type of input data
216 */
217 enum class Type : uint8_t {
218 SCALAR, ///< Single normalized float [-1.0, 1.0] or [0.0, 1.0]
219 VECTOR, ///< Multiple float values (e.g., accelerometer xyz)
220 BYTES, ///< Raw byte data (HID reports, sysex)
221 MIDI, ///< Structured MIDI message
222 OSC ///< Structured OSC message
223 };
224
225 /**
226 * @brief MIDI message structure
227 */
228 struct MIDIMessage {
229 uint8_t status; ///< Status byte (channel + message type)
230 uint8_t data1; ///< First data byte
231 uint8_t data2; ///< Second data byte (may be unused)
232 [[nodiscard]] uint8_t channel() const { return status & 0x0F; }
233 [[nodiscard]] uint8_t type() const { return status & 0xF0; }
234 };
235
236 /**
237 * @brief OSC argument types
238 */
239 using OSCArg = std::variant<int32_t, float, std::string, std::vector<uint8_t>>;
240
241 /**
242 * @brief OSC message structure
243 */
244 struct MAYAFLUX_API OSCMessage {
245 std::string address; ///< OSC address pattern
246 std::vector<OSCArg> arguments; ///< Typed arguments
247
248 /**
249 * @brief Extract a float argument by index.
250 *
251 * int32_t arguments are widened to float.
252 *
253 * @param index Argument index (0-based).
254 * @return Float value, or std::nullopt if out of range or wrong type.
255 */
256 [[nodiscard]] std::optional<float> get_float(size_t index = 0) const noexcept;
257
258 /**
259 * @brief Extract an int32 argument by index.
260 *
261 * float arguments are truncated to int32_t.
262 *
263 * @param index Argument index (0-based).
264 * @return Int value, or std::nullopt if out of range or wrong type.
265 */
266 [[nodiscard]] std::optional<int32_t> get_int(size_t index = 0) const noexcept;
267
268 /**
269 * @brief Extract a string argument by index.
270 * @param index Argument index (0-based).
271 * @return String value, or std::nullopt if out of range or wrong type.
272 */
273 [[nodiscard]] std::optional<std::string> get_string(size_t index = 0) const noexcept;
274
275 /**
276 * @brief Extract a blob argument by index.
277 * @param index Argument index (0-based).
278 * @return Raw bytes, or std::nullopt if out of range or wrong type.
279 */
280 [[nodiscard]] std::optional<std::vector<uint8_t>> get_blob(size_t index = 0) const noexcept;
281 };
282
284 std::variant<
285 double, ///< SCALAR
286 std::vector<double>, ///< VECTOR
287 std::vector<uint8_t>, ///< BYTES
288 MIDIMessage, ///< MIDI
289 OSCMessage ///< OSC
290 >
291 data;
292
293 uint64_t timestamp_ns; ///< Nanoseconds since epoch (or backend start)
294 uint32_t device_id; ///< Source device identifier
295 InputType source_type; ///< Backend that generated this value
296
297 [[nodiscard]] double as_scalar() const { return std::get<double>(data); }
298 [[nodiscard]] const std::vector<double>& as_vector() const { return std::get<std::vector<double>>(data); }
299 [[nodiscard]] const std::vector<uint8_t>& as_bytes() const { return std::get<std::vector<uint8_t>>(data); }
300 [[nodiscard]] const MIDIMessage& as_midi() const { return std::get<MIDIMessage>(data); }
301 [[nodiscard]] const OSCMessage& as_osc() const { return std::get<OSCMessage>(data); }
302
303 static InputValue make_scalar(double v, uint32_t dev_id, InputType src);
304
305 static InputValue make_vector(std::vector<double> v, uint32_t dev_id, InputType src);
306
307 static InputValue make_bytes(std::vector<uint8_t> v, uint32_t dev_id, InputType src);
308
309 static InputValue make_midi(uint8_t status, uint8_t d1, uint8_t d2, uint32_t dev_id);
310
311 static InputValue make_osc(std::string addr, std::vector<OSCArg> args, uint32_t dev_id);
312
313 /**
314 * @brief Safe scalar extraction.
315 * @return Value, or std::nullopt if this is not a SCALAR.
316 */
317 [[nodiscard]] std::optional<double> try_scalar() const noexcept;
318
319 /**
320 * @brief Safe vector extraction.
321 * @return Pointer to vector, or nullptr if this is not a VECTOR.
322 */
323 [[nodiscard]] const std::vector<double>* try_vector() const noexcept;
324
325 /**
326 * @brief Safe bytes extraction.
327 * @return Pointer to bytes, or nullptr if this is not BYTES.
328 */
329 [[nodiscard]] const std::vector<uint8_t>* try_bytes() const noexcept;
330
331 /**
332 * @brief Safe MIDI extraction.
333 * @return Pointer to MIDIMessage, or nullptr if this is not MIDI.
334 */
335 [[nodiscard]] const MIDIMessage* try_midi() const noexcept;
336
337 /**
338 * @brief Safe OSC extraction.
339 * @return Pointer to OSCMessage, or nullptr if this is not OSC.
340 */
341 [[nodiscard]] const OSCMessage* try_osc() const noexcept;
342};
343
344} // namespace MayaFlux::Core
vk::PhysicalDeviceType type
Definition VKDevice.cpp:146
uint32_t index
Definition VKDevice.cpp:142
InputType
Input backend type enumeration.
@ OSC
Open Sound Control (network)
@ TABLET
Digitizers and styluses (pressure, tilt, rotation)
@ HID
Generic HID devices (game controllers, custom hardware)
@ MIDI
MIDI controllers and instruments.
@ SERIAL
Serial port communication (Arduino, etc.)
std::optional< uint8_t > midi_cc_number
Match specific CC number.
InputType backend
Which backend type.
std::optional< std::string > osc_address_pattern
Match OSC address prefix.
std::optional< uint16_t > hid_vendor_id
Match HID vendor ID.
std::optional< uint8_t > midi_channel
Match specific MIDI channel (1-16)
std::optional< uint8_t > midi_message_type
Match message type (0xB0=CC, 0x90=NoteOn, etc.)
std::optional< uint16_t > hid_product_id
Match HID product ID.
Specifies what input an InputNode wants to receive.
std::string address
IP address or hostname.
bool is_connected
Current connection state.
std::string name
Human-readable device name.
std::string manufacturer
Device manufacturer (if available)
uint32_t id
Unique device identifier within backend.
std::string serial_number
Device serial (if available)
InputType backend_type
Which backend manages this device.
std::string port_name
e.g., "/dev/ttyUSB0" or "COM3"
Information about a connected input device.
uint8_t status
Status byte (channel + message type)
uint8_t data2
Second data byte (may be unused)
std::vector< OSCArg > arguments
Typed arguments.
std::string address
OSC address pattern.
const std::vector< uint8_t > & as_bytes() const
const std::vector< double > & as_vector() const
const OSCMessage & as_osc() const
std::variant< int32_t, float, std::string, std::vector< uint8_t > > OSCArg
OSC argument types.
const MIDIMessage & as_midi() const
Generic input value container.