feat(nisps/engines): port firmware audio engines to AudioEngine concept (meml-1v6)
Concept-based, no virtual dispatch, per-engine voice spaces as inline
methods. Each engine satisfies nisps::AudioEngine via static_assert.
- NoOpEngine: silent passthrough; used for sequencer-only modes and
for the SoundAnalysisMIDI mode's audio path.
- PAFSynthEngine (33 params, 7 voice spaces): 4-voice PAF synth with
detune cascade, ring-mod, sine-shaper, ADSR, feedback delay. note_on/
note_off interface for MIDI keyboard.
- ChannelStripEngine (24 params, 6 voice spaces): stereo console strip
(pre-gain/HPF/LPF/2x peak/low-shelf/high-shelf/comp/post-gain). Voice
spaces: WannabeNeve66, SSL4K, SSL9K, MaleVox, FemaleVox, Neve80
(stepped-frequency).
- XIASRIEngine (24 params, "Direct" voice space): pitch-shift + 6 allpass
+ 2 comb + 4 delays. Direct NN→param mapping per firmware semantics.
- VerbFXEngine (47 params, 12 voice spaces): 8-band SVF filterbank +
3-lane dynamic delay + 8-lpcomb/4-allpass Freeverb-style tail with
cross-fades. All 12 voice spaces ported from voicespaces/VerbFX/*.hpp.
- MEMLCeliumEngine (56 params): 2-track ratio sequencer + dual-voice
PAF synth (7+7+22+20 layout). Sequencer triggers V0/V1 ADSR.
- BreakOrEngine (56 params): 8-track ratio sequencer; emits NoteOn/
NoteOff/Clock events via pop_events(span). process() returns silence.
- ElysiamorfEngine (40 params): 8-track FM-pair sequencer; emits CC
events on CCs {1,2,3,4,5,9,11,12}. Silent audio path.
- AnalysisEngine (0 params, 6 features): port of XiasriAnalysis (pitch
via zero-crossing, aperiodicity via MAD, log-domain energy + attack
derivative + brightness ratio). Inputs to ML on SoundAnalysisMIDI mode.
All param_count() values match schemas/modes/*.json output_size.
4074 LOC total. CMake adds nisps_dsp_engine_tests target with 38
passing tests under -Wall -Wextra -Werror -Wpedantic.
2026-04-29 15:09:12 +02:00
|
|
|
// nisps/engines/base.hpp — common building blocks for AudioEngine
|
|
|
|
|
// implementations.
|
|
|
|
|
//
|
|
|
|
|
// Includes:
|
refactor(nisps): delete dead engine/mode mass
Phase 1 group 3 (L3, L9, L4, L5, L6, ST1).
- L3: nisps/modes/voice_space.hpp — entirely dead, no includes anywhere.
- L4: deleted SawOsc and SquareOsc. KEPT SineOsc — a verifier caught that the
original reviewer's grep missed its live consumer (the firmware selftest);
re-confirmed here before touching the file.
- L9: removed the no-op VoiceSpace enum/table/setter boilerplate from the five
engines with no real voice spaces; kept it on PAFSynth, VerbFX and
ChannelStrip, which have real ones. Every engine member was checked against
nisps/wasm/bindings.cpp, firmware/ and tests/ for callers first.
- L5: ModeBase::input_dirty_ was write-only state — deleted the flag rather
than making it gate inference, which would have been a behaviour change.
- L6: VerbFXEngine's delay_to_verb_ (computed 12x per block, never read),
enable_reverb_, enable_delay_to_reverb_ and the unused set_enable_* setters.
- ST1: rewrote the four engine header comment blocks that described
implementations which do not exist.
L7 (MEMLCeliumEngine's inert feedback path) is deliberately NOT done — tracing
git history showed feedbackGain went 0.1f (live) -> "0; //0.1f" (explicitly
muted, value preserved) -> dropped entirely in the port. That is a muted
feature, not dead weight, and deleting it would silently lose it. Left intact
pending an operator decision; see the phase report.
Gates: run-all-tests.sh ALL GREEN.
2026-07-21 12:48:50 +02:00
|
|
|
// - NoOpEngine: silent passthrough (engine_id() == "thru"), used directly
|
|
|
|
|
// as the mode-level EngineT wherever a mode produces no audio itself —
|
|
|
|
|
// SoundAnalysisMIDIMode (audio is analysed via a separately-composed
|
|
|
|
|
// AnalysisEngine member, not synthesised) and ExternalSynthMIDIMode
|
|
|
|
|
// (joystick -> MLP -> MIDI CC only, no audio path). BreakOrEngine and
|
|
|
|
|
// ElysiamorfEngine are sequencer-only engines that also return silence
|
|
|
|
|
// from process(), but each implements that directly — neither composes
|
|
|
|
|
// NoOpEngine.
|
feat(nisps/engines): port firmware audio engines to AudioEngine concept (meml-1v6)
Concept-based, no virtual dispatch, per-engine voice spaces as inline
methods. Each engine satisfies nisps::AudioEngine via static_assert.
- NoOpEngine: silent passthrough; used for sequencer-only modes and
for the SoundAnalysisMIDI mode's audio path.
- PAFSynthEngine (33 params, 7 voice spaces): 4-voice PAF synth with
detune cascade, ring-mod, sine-shaper, ADSR, feedback delay. note_on/
note_off interface for MIDI keyboard.
- ChannelStripEngine (24 params, 6 voice spaces): stereo console strip
(pre-gain/HPF/LPF/2x peak/low-shelf/high-shelf/comp/post-gain). Voice
spaces: WannabeNeve66, SSL4K, SSL9K, MaleVox, FemaleVox, Neve80
(stepped-frequency).
- XIASRIEngine (24 params, "Direct" voice space): pitch-shift + 6 allpass
+ 2 comb + 4 delays. Direct NN→param mapping per firmware semantics.
- VerbFXEngine (47 params, 12 voice spaces): 8-band SVF filterbank +
3-lane dynamic delay + 8-lpcomb/4-allpass Freeverb-style tail with
cross-fades. All 12 voice spaces ported from voicespaces/VerbFX/*.hpp.
- MEMLCeliumEngine (56 params): 2-track ratio sequencer + dual-voice
PAF synth (7+7+22+20 layout). Sequencer triggers V0/V1 ADSR.
- BreakOrEngine (56 params): 8-track ratio sequencer; emits NoteOn/
NoteOff/Clock events via pop_events(span). process() returns silence.
- ElysiamorfEngine (40 params): 8-track FM-pair sequencer; emits CC
events on CCs {1,2,3,4,5,9,11,12}. Silent audio path.
- AnalysisEngine (0 params, 6 features): port of XiasriAnalysis (pitch
via zero-crossing, aperiodicity via MAD, log-domain energy + attack
derivative + brightness ratio). Inputs to ML on SoundAnalysisMIDI mode.
All param_count() values match schemas/modes/*.json output_size.
4074 LOC total. CMake adds nisps_dsp_engine_tests target with 38
passing tests under -Wall -Wextra -Werror -Wpedantic.
2026-04-29 15:09:12 +02:00
|
|
|
// - Helper macros / static_asserts to verify each concrete engine satisfies
|
|
|
|
|
// `nisps::AudioEngine` at compile time.
|
|
|
|
|
|
|
|
|
|
#pragma once
|
|
|
|
|
|
|
|
|
|
#include <cstddef>
|
|
|
|
|
#include <span>
|
|
|
|
|
#include <string_view>
|
|
|
|
|
|
|
|
|
|
#include "../core/concepts.hpp"
|
|
|
|
|
#include "../core/perf.hpp"
|
|
|
|
|
#include "../core/types.hpp"
|
|
|
|
|
|
|
|
|
|
namespace nisps {
|
|
|
|
|
|
|
|
|
|
class NoOpEngine {
|
|
|
|
|
public:
|
|
|
|
|
static constexpr std::size_t param_count() noexcept { return 0u; }
|
2026-04-29 15:12:12 +02:00
|
|
|
static constexpr std::string_view engine_id() noexcept { return "thru"; }
|
feat(nisps/engines): port firmware audio engines to AudioEngine concept (meml-1v6)
Concept-based, no virtual dispatch, per-engine voice spaces as inline
methods. Each engine satisfies nisps::AudioEngine via static_assert.
- NoOpEngine: silent passthrough; used for sequencer-only modes and
for the SoundAnalysisMIDI mode's audio path.
- PAFSynthEngine (33 params, 7 voice spaces): 4-voice PAF synth with
detune cascade, ring-mod, sine-shaper, ADSR, feedback delay. note_on/
note_off interface for MIDI keyboard.
- ChannelStripEngine (24 params, 6 voice spaces): stereo console strip
(pre-gain/HPF/LPF/2x peak/low-shelf/high-shelf/comp/post-gain). Voice
spaces: WannabeNeve66, SSL4K, SSL9K, MaleVox, FemaleVox, Neve80
(stepped-frequency).
- XIASRIEngine (24 params, "Direct" voice space): pitch-shift + 6 allpass
+ 2 comb + 4 delays. Direct NN→param mapping per firmware semantics.
- VerbFXEngine (47 params, 12 voice spaces): 8-band SVF filterbank +
3-lane dynamic delay + 8-lpcomb/4-allpass Freeverb-style tail with
cross-fades. All 12 voice spaces ported from voicespaces/VerbFX/*.hpp.
- MEMLCeliumEngine (56 params): 2-track ratio sequencer + dual-voice
PAF synth (7+7+22+20 layout). Sequencer triggers V0/V1 ADSR.
- BreakOrEngine (56 params): 8-track ratio sequencer; emits NoteOn/
NoteOff/Clock events via pop_events(span). process() returns silence.
- ElysiamorfEngine (40 params): 8-track FM-pair sequencer; emits CC
events on CCs {1,2,3,4,5,9,11,12}. Silent audio path.
- AnalysisEngine (0 params, 6 features): port of XiasriAnalysis (pitch
via zero-crossing, aperiodicity via MAD, log-domain energy + attack
derivative + brightness ratio). Inputs to ML on SoundAnalysisMIDI mode.
All param_count() values match schemas/modes/*.json output_size.
4074 LOC total. CMake adds nisps_dsp_engine_tests target with 38
passing tests under -Wall -Wextra -Werror -Wpedantic.
2026-04-29 15:09:12 +02:00
|
|
|
|
|
|
|
|
void setup(float /*sample_rate*/) noexcept {}
|
|
|
|
|
void set_params(std::span<const float> /*params*/) noexcept {}
|
|
|
|
|
|
|
|
|
|
NISPS_HOT NISPS_FORCE_INLINE stereosample_t process(stereosample_t /*x*/) noexcept {
|
|
|
|
|
return {0.f, 0.f};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
DriverConfig driver_config() const noexcept { return {}; }
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static_assert(AudioEngine<NoOpEngine>, "NoOpEngine must satisfy AudioEngine");
|
|
|
|
|
|
|
|
|
|
} // namespace nisps
|