Pulp 1.88.0
Cross-platform audio plugin framework
Loading...
Searching...
No Matches
midi_parameter_map.hpp
Go to the documentation of this file.
1#pragma once
2
35
36#include <algorithm>
37#include <array>
38#include <cmath>
39#include <cstddef>
40#include <cstdint>
42#include <pulp/state/store.hpp>
43
44namespace pulp::state {
45
49 float min = 0.0f;
50 float max = 1.0f;
51
54 float apply(uint8_t value) const {
55 return min + (value / 127.0f) * (max - min);
56 }
57};
58
60 public:
62 static constexpr uint8_t kOmni = 0xFF;
63
64 // ── UI thread ──
65
67 void set_mapping(uint8_t channel, uint8_t cc, ParamID id) {
68 set_mapping(channel, cc, id, MidiMapScale{});
69 }
70
72 void set_mapping(uint8_t channel, uint8_t cc, ParamID id, MidiMapScale scale) {
73 commands_.try_push({Command::Set, channel, cc, id, clamp_scale(scale)});
74 }
75
77 void arm_learn(ParamID id) {
79 }
80
82 void arm_learn(ParamID id, MidiMapScale scale) {
83 commands_.try_push({Command::Arm, kOmni, 0, id, clamp_scale(scale)});
84 }
85
87 void clear(ParamID id) {
88 commands_.try_push({Command::Clear, kOmni, 0, id, MidiMapScale{}});
89 }
90
91 // ── audio thread ──
92
94 void pump() {
95 while (auto cmd = commands_.try_pop()) {
96 switch (cmd->type) {
97 case Command::Set:
98 insert(cmd->channel, cmd->cc, cmd->id, cmd->scale);
99 break;
100 case Command::Arm:
101 learn_armed_ = true;
102 learn_target_ = cmd->id;
103 learn_scale_ = cmd->scale;
104 break;
105 case Command::Clear:
106 remove_target(cmd->id);
107 break;
108 }
109 }
110 }
111
114 void handle_cc(StateStore& store, uint8_t channel, uint8_t cc, uint8_t value) {
115 if (learn_armed_) {
116 insert(channel, cc, learn_target_, learn_scale_);
117 learn_armed_ = false;
118 }
119 for (std::size_t i = 0; i < count_; ++i) {
120 const auto& m = map_[i];
121 if (m.cc == cc && (m.channel == kOmni || m.channel == channel))
122 store.set_normalized_rt(m.id, m.scale.apply(value));
123 }
124 }
125
126 bool learn_armed() const {
127 return learn_armed_;
128 }
129
130 private:
131 struct Command {
132 enum Type { Set, Arm, Clear } type;
133 uint8_t channel;
134 uint8_t cc;
135 ParamID id;
136 MidiMapScale scale;
137 };
138 struct Mapping {
139 uint8_t channel;
140 uint8_t cc;
141 ParamID id;
142 MidiMapScale scale;
143 };
144
145 static MidiMapScale clamp_scale(MidiMapScale scale) {
146 scale.min = std::isfinite(scale.min) ? std::clamp(scale.min, 0.0f, 1.0f) : 0.0f;
147 scale.max = std::isfinite(scale.max) ? std::clamp(scale.max, 0.0f, 1.0f) : 1.0f;
148 return scale;
149 }
150
151 void insert(uint8_t channel, uint8_t cc, ParamID id, MidiMapScale scale) {
152 for (std::size_t i = 0; i < count_; ++i) {
153 if (map_[i].channel == channel && map_[i].cc == cc) {
154 map_[i].id = id;
155 map_[i].scale = scale;
156 return;
157 }
158 }
159 if (count_ < kMaxMappings)
160 map_[count_++] = {channel, cc, id, scale};
161 }
162
163 void remove_target(ParamID id) {
164 std::size_t w = 0;
165 for (std::size_t i = 0; i < count_; ++i)
166 if (map_[i].id != id)
167 map_[w++] = map_[i];
168 count_ = w;
169 }
170
171 static constexpr std::size_t kMaxMappings = 64;
172 std::array<Mapping, kMaxMappings> map_{};
173 std::size_t count_ = 0;
174 bool learn_armed_ = false;
175 ParamID learn_target_ = 0;
176 MidiMapScale learn_scale_{};
177 pulp::runtime::SpscQueue<Command, 64> commands_;
178};
179
180} // namespace pulp::state
Definition midi_parameter_map.hpp:59
bool learn_armed() const
Definition midi_parameter_map.hpp:126
void handle_cc(StateStore &store, uint8_t channel, uint8_t cc, uint8_t value)
Route one incoming CC.
Definition midi_parameter_map.hpp:114
void arm_learn(ParamID id, MidiMapScale scale)
Arm learn: the next incoming CC binds to id with scale's window.
Definition midi_parameter_map.hpp:82
void pump()
Drain queued UI commands. Call once at the top of process().
Definition midi_parameter_map.hpp:94
void clear(ParamID id)
Remove any mapping that targets id.
Definition midi_parameter_map.hpp:87
void set_mapping(uint8_t channel, uint8_t cc, ParamID id)
Map (channel, cc) → parameter across the full range. channel may be kOmni.
Definition midi_parameter_map.hpp:67
void set_mapping(uint8_t channel, uint8_t cc, ParamID id, MidiMapScale scale)
Map (channel, cc) → parameter, sweeping only scale's normalized window.
Definition midi_parameter_map.hpp:72
static constexpr uint8_t kOmni
Match any MIDI channel.
Definition midi_parameter_map.hpp:62
void arm_learn(ParamID id)
Arm learn: the next incoming CC binds to id across the full range.
Definition midi_parameter_map.hpp:77
Centralized parameter storage with lock-free value access.
Definition store.hpp:164
void set_normalized_rt(ParamID id, float normalized)
Real-time-safe normalized-value write.
@ i
Definition formant_filter_bank.hpp:20
void scale(const float *a, float scalar, float *dst, std::size_t count) noexcept
SequencerStateChannel is the audio-safe transport for a plugin's structured NON-parameter state: the ...
Definition audio_device_manager.hpp:48
uint32_t ParamID
Unique parameter identifier, stable across plugin versions.
Definition parameter.hpp:55
@ w
Definition input_events.hpp:41
Normalized [0, 1] output window a CC sweep is mapped onto.
Definition midi_parameter_map.hpp:48
float min
Definition midi_parameter_map.hpp:49
float max
Definition midi_parameter_map.hpp:50
float apply(uint8_t value) const
Map a raw 7-bit CC value onto this window.
Definition midi_parameter_map.hpp:54