Adds two foundational pieces shared by every concrete mode:
- `base.hpp`: defines `nisps::ParamSchema` (the aggregate type the
`Mode` concept's `param_schema()` returns by const-reference),
`nisps::ControlEvent`, and `ModeBase<Derived, EngineT, MLPType,
NInputs>` — a CRTP scaffold absorbing input forwarding, ML
inference + voice space mapping, engine.set_params() routing, and
a per-mode ControlEvent ring buffer for MIDI/I2C events.
`ModeRoutesOutputsToEngine<Derived>` lets a derived mode (e.g.
SoundAnalysisMIDI) opt out of routing ML outputs to engine
params when its outputs become MIDI CCs instead.
- `voice_space.hpp`: `VoiceSpaceEntry` + `make_voice_space_entries()`
+ `find_voice_space()` helpers. Voice-space *mapping code* lives
inside engines (mirroring firmware); mode layer just selects
which voice space the engine uses by index/name.
No heap, no virtuals, no Pico/Arduino dependencies; satisfies stream
4 of architecture.md.
54 lines
1.9 KiB
C++
54 lines
1.9 KiB
C++
// nisps/modes/voice_space.hpp — Voice-space binding helpers.
|
|
//
|
|
// In this codebase the *voice-space code* (the lambda that maps NN outputs
|
|
// to engine state fields) lives INSIDE each engine — see e.g.
|
|
// `PAFSynthEngine::apply_quad_detune` etc. Engines expose a
|
|
// `set_voice_space(EngineT::VoiceSpace)` method to switch which mapping is
|
|
// active; the next `set_params(span<float>)` call routes through the
|
|
// selected voice space.
|
|
//
|
|
// The mode layer therefore only needs to:
|
|
// 1. Tell the engine which voice space is active.
|
|
// 2. Surface the voice-space NAMES (for UI dropdowns / schema parity).
|
|
//
|
|
// `VoiceSpaceEntry` is a thin value used by `ParamSchema::voice_spaces` and
|
|
// for static introspection (e.g. matching schema names against
|
|
// `EngineT::kVoiceSpaceNames`). We keep it constexpr-friendly.
|
|
|
|
#pragma once
|
|
|
|
#include <array>
|
|
#include <cstddef>
|
|
#include <span>
|
|
#include <string_view>
|
|
|
|
namespace nisps {
|
|
|
|
struct VoiceSpaceEntry {
|
|
std::string_view name;
|
|
std::size_t index;
|
|
};
|
|
|
|
// Build a constexpr list of {name, index} from the engine's static name table.
|
|
template <typename EngineT>
|
|
constexpr auto make_voice_space_entries() noexcept {
|
|
constexpr std::size_t N = EngineT::kVoiceSpaceCount;
|
|
std::array<VoiceSpaceEntry, N> entries{};
|
|
for (std::size_t i = 0u; i < N; ++i) {
|
|
entries[i] = VoiceSpaceEntry{EngineT::kVoiceSpaceNames[i], i};
|
|
}
|
|
return entries;
|
|
}
|
|
|
|
// Look up a voice-space index by name on an engine. Returns SIZE_MAX if not
|
|
// found. Modes use this to translate schema voice-space strings to the
|
|
// engine's enum index when loading a default.
|
|
template <typename EngineT>
|
|
constexpr std::size_t find_voice_space(std::string_view name) noexcept {
|
|
for (std::size_t i = 0u; i < EngineT::kVoiceSpaceCount; ++i) {
|
|
if (EngineT::kVoiceSpaceNames[i] == name) return i;
|
|
}
|
|
return static_cast<std::size_t>(-1);
|
|
}
|
|
|
|
} // namespace nisps
|