28#ifndef SBL_CONTROL_CC_MAPPER_HPP_
29#define SBL_CONTROL_CC_MAPPER_HPP_
54template<
typename Target>
63template<
typename Target>
67 using Sink = void (*)(
void* context, Target target,
float value_su);
71 : table_(table), count_(N), sink_(sink), context_(context) {}
80 template<
typename Store>
81 uint8_t
on_cc(uint8_t channel, uint8_t cc, uint8_t value,
const Store& store)
const {
83 for (
size_t i = 0; i < count_; ++i) {
89 const uint8_t lsb_cc =
static_cast<uint8_t
>(e.
cc + 32);
90 if (cc != e.
cc && cc != lsb_cc)
continue;
91 const uint8_t msb = (cc == e.
cc) ? value : to7(store.cc(e.
cc));
92 const uint8_t lsb = (cc == lsb_cc) ? value : to7(store.cc(lsb_cc));
93 t =
static_cast<float>((
static_cast<uint16_t
>(msb) << 7) | lsb) *
96 if (cc != e.
cc)
continue;
97 t =
static_cast<float>(value) * (1.0f / 127.0f);
101 sink_(context_, e.
target, v);
107 size_t size()
const {
return count_; }
110 static uint8_t to7(
float su) {
111 const float c = su * 127.0f + 0.5f;
112 return c <= 0.0f ? 0 : (c >= 127.0f ? 127 :
static_cast<uint8_t
>(c));
115 const CcEntry<Target>* table_;
CcMapper(const CcEntry< Target >(&table)[N], Sink sink, void *context)
void(*)(void *context, Target target, float value_su) Sink
The app's write into the merge layer. value_su is the curve output.
uint8_t on_cc(uint8_t channel, uint8_t cc, uint8_t value, const Store &store) const
Route one ControlChange event.
Control Stack v2: scheduler, event queue, merge, CC mapping, calibration, presets.
constexpr CcCurve kCcLinear
float cam_evaluate(const float *table, uint16_t size, float input)
constexpr uint8_t kAnyChannel
Row channel that matches every channel.
@ Paired14
14-bit: cc is the MSB (0–31), cc + 32 the LSB
A LUTE cam table (size + 1 entries, guard point included), or linear when table is null.
uint8_t channel
0–15, or kAnyChannel
uint8_t cc
controller number (the MSB for Paired14)