MayaFlux 1.0.0
Digital-First Multimedia Processing Framework
Loading...
Searching...
No Matches
MIDINode.hpp
Go to the documentation of this file.
1#pragma once
2
3#include "InputNode.hpp"
4
6
7/**
8 * @brief MIDI input node configuration
9 */
11 std::optional<uint8_t> channel; ///< MIDI channel filter (0-15)
12 std::optional<uint8_t> note_number; ///< Note number filter (0-127)
13 std::optional<uint8_t> cc_number; ///< CC number filter (0-127)
14 std::optional<uint8_t> message_type; ///< Message type filter (0x80-0xF0)
15
16 bool note_on_only {}; ///< Only respond to Note On
17 bool note_off_only {}; ///< Only respond to Note Off
18
19 std::function<double(uint8_t)> velocity_curve; ///< Custom velocity mapping
20 bool invert_cc { false }; ///< Flip CC 127→0
21
22 /**
23 * @brief Note velocity node (responds to any note)
24 */
25 static MIDIConfig note() { return {}; }
26
27 /**
28 * @brief Specific note velocity
29 */
30 static MIDIConfig note(uint8_t note_num)
31 {
32 MIDIConfig cfg;
33 cfg.note_number = note_num;
34 return cfg;
35 }
36
37 /**
38 * @brief Control Change node
39 */
40 static MIDIConfig cc(uint8_t cc_num)
41 {
42 MIDIConfig cfg;
43 cfg.cc_number = cc_num;
44 cfg.message_type = 0xB0;
45 return cfg;
46 }
47
48 /**
49 * @brief Pitch bend node
50 */
52 {
53 MIDIConfig cfg;
54 cfg.message_type = 0xE0;
55 return cfg;
56 }
57
58 /**
59 * @brief Aftertouch node
60 */
62 {
63 MIDIConfig cfg;
64 cfg.message_type = 0xD0;
65 return cfg;
66 }
67
68 /**
69 * @brief Program change node
70 */
72 {
73 MIDIConfig cfg;
74 cfg.message_type = 0xC0;
75 return cfg;
76 }
77
78 /**
79 * @brief Apply velocity curve transformation
80 */
81 template <typename F>
83 {
84 velocity_curve = std::forward<F>(curve);
85 return *this;
86 }
87
89 {
90 channel = ch;
91 return *this;
92 }
93
95 {
96 note_on_only = true;
97 return *this;
98 }
99
101 {
102 note_off_only = true;
103 return *this;
104 }
105
107 {
108 invert_cc = true;
109 return *this;
110 }
111};
112
113/**
114 * @class MIDINode
115 * @brief Specialized InputNode for MIDI messages
116 *
117 * Extracts and processes MIDI data with convenient filtering:
118 * - Note numbers and velocities
119 * - Control Change values
120 * - Pitch bend (normalized to [-1, 1])
121 * - Channel-specific filtering
122 * - Message type filtering
123 *
124 * Example usage:
125 * @code
126 * // Any note velocity
127 * auto note_vel = std::make_shared<MIDINode>(MIDIConfig::note());
128 *
129 * // Specific note on channel 1
130 * auto middle_c = std::make_shared<MIDINode>(
131 * MIDIConfig::note(60).on_channel(0));
132 *
133 * // Mod wheel (CC 1)
134 * auto mod_wheel = std::make_shared<MIDINode>(MIDIConfig::cc(1));
135 *
136 * // Pitch bend on channel 2
137 * auto pitch = std::make_shared<MIDINode>(
138 * MIDIConfig::pitch_bend().on_channel(1));
139 * @endcode
140 */
141class MAYAFLUX_API MIDINode : public InputNode {
142public:
143 using NoteCallback = std::function<void(uint8_t note, uint8_t velocity, bool is_on)>;
144 using CC_Callback = std::function<void(uint8_t cc_num, uint8_t value)>;
145 using PitchBendCallback = std::function<void(int16_t bend)>;
146
147 explicit MIDINode(MIDIConfig config = {});
148
149 void save_state() override { }
150 void restore_state() override { }
151
152 /**
153 * @brief Callback for note events with note number and velocity
154 * @param callback Function receiving (note_number, velocity, is_note_on)
155 */
156 HookId on_note(std::function<void(uint8_t note, uint8_t velocity, bool is_on)> callback)
157 {
158 return m_note_callbacks.add(
159 [this, callback](NodeContext&) {
160 if (!m_last_midi_message) {
161 return;
162 }
163 const auto& midi = *m_last_midi_message;
164 if (midi.type() == 0x90) {
165 callback(midi.data1, midi.data2, midi.data2 > 0);
166 } else {
167 callback(midi.data1, 0, false);
168 }
169 },
170 callback.target_type());
171 }
172
173 /**
174 * @brief Callback for CC events with controller number and value
175 */
176 HookId on_cc(std::function<void(uint8_t cc_num, uint8_t value)> callback)
177 {
178 return m_cc_callbacks.add(
179 [this, callback](NodeContext&) {
180 if (m_last_midi_message) {
181 callback(m_last_midi_message->data1, m_last_midi_message->data2);
182 }
183 },
184 callback.target_type());
185 }
186
187 /**
188 * @brief Callback for pitch bend with 14-bit value
189 */
190 HookId on_pitch_bend(std::function<void(int16_t bend)> callback)
191 {
192 return m_pitch_bend_callbacks.add(
193 [this, callback](NodeContext&) {
194 if (m_last_midi_message) {
195 callback(static_cast<int16_t>(((m_last_midi_message->data2 << 7) | m_last_midi_message->data1) - 8192));
196 }
197 },
198 callback.target_type());
199 }
200
201protected:
202 double extract_value(const Core::InputValue& value) override;
203
204 void notify_tick(double value) override;
205
206private:
208 std::optional<Core::InputValue::MIDIMessage> m_last_midi_message;
209
210 HookList m_note_callbacks { *this };
211 HookList m_cc_callbacks { *this };
212 HookList m_pitch_bend_callbacks { *this };
213
214 void fire_midi_callbacks(const Core::InputValue::MIDIMessage& midi);
215 [[nodiscard]] bool matches_filters(const Core::InputValue& value) const;
216};
217
218} // namespace MayaFlux::Nodes::Input
PickCallback callback
Definition Picker.cpp:22
glm::vec3 value
Stores, fires and clears the hooks of one node channel.
Definition NodeUtils.hpp:93
Abstract base class for nodes that receive external input.
HookId on_cc(std::function< void(uint8_t cc_num, uint8_t value)> callback)
Callback for CC events with controller number and value.
Definition MIDINode.hpp:176
std::function< void(uint8_t cc_num, uint8_t value)> CC_Callback
Definition MIDINode.hpp:144
HookId on_pitch_bend(std::function< void(int16_t bend)> callback)
Callback for pitch bend with 14-bit value.
Definition MIDINode.hpp:190
std::function< void(int16_t bend)> PitchBendCallback
Definition MIDINode.hpp:145
void restore_state() override
Restores the node's state from the last save Recursively cascades through all connected modulator nod...
Definition MIDINode.hpp:150
std::optional< Core::InputValue::MIDIMessage > m_last_midi_message
Definition MIDINode.hpp:208
HookId on_note(std::function< void(uint8_t note, uint8_t velocity, bool is_on)> callback)
Callback for note events with note number and velocity.
Definition MIDINode.hpp:156
std::function< void(uint8_t note, uint8_t velocity, bool is_on)> NoteCallback
Definition MIDINode.hpp:143
void save_state() override
Saves the node's current state for later restoration Recursively cascades through all connected modul...
Definition MIDINode.hpp:149
Specialized InputNode for MIDI messages.
Definition MIDINode.hpp:141
Base context class for node callbacks.
Definition Node.hpp:53
uint64_t HookId
Identifies one registration inside a HookList.
Definition NodeUtils.hpp:60
Generic input value container.
Configuration for InputNode behavior.
Definition InputNode.hpp:67
std::optional< uint8_t > channel
MIDI channel filter (0-15)
Definition MIDINode.hpp:11
std::function< double(uint8_t)> velocity_curve
Custom velocity mapping.
Definition MIDINode.hpp:19
static MIDIConfig program_change()
Program change node.
Definition MIDINode.hpp:71
bool invert_cc
Flip CC 127→0.
Definition MIDINode.hpp:20
std::optional< uint8_t > cc_number
CC number filter (0-127)
Definition MIDINode.hpp:13
std::optional< uint8_t > message_type
Message type filter (0x80-0xF0)
Definition MIDINode.hpp:14
static MIDIConfig aftertouch()
Aftertouch node.
Definition MIDINode.hpp:61
MIDIConfig & with_velocity_curve(F &&curve)
Apply velocity curve transformation.
Definition MIDINode.hpp:82
bool note_on_only
Only respond to Note On.
Definition MIDINode.hpp:16
static MIDIConfig note(uint8_t note_num)
Specific note velocity.
Definition MIDINode.hpp:30
std::optional< uint8_t > note_number
Note number filter (0-127)
Definition MIDINode.hpp:12
static MIDIConfig pitch_bend()
Pitch bend node.
Definition MIDINode.hpp:51
bool note_off_only
Only respond to Note Off.
Definition MIDINode.hpp:17
static MIDIConfig cc(uint8_t cc_num)
Control Change node.
Definition MIDINode.hpp:40
MIDIConfig & on_channel(uint8_t ch)
Definition MIDINode.hpp:88
static MIDIConfig note()
Note velocity node (responds to any note)
Definition MIDINode.hpp:25
MIDI input node configuration.
Definition MIDINode.hpp:10