The Smart Grid One relies entirely on a software-defined parameter system. All “knob” state lives in software, allowing for complete recall, deep modulation, macro control (gestures), and A/B scene morphing.
The core implementation spans private/src/Encoder.hpp, private/src/EncoderBank.hpp, and private/src/EncoderBankBank.hpp.
Ownership now lives in EncoderBankBank: it owns a flat array of BankedEncoderCell instances indexed by SmartGridOneEncoders::Param. Each EncoderBankInternal starts with null base cells and receives raw pointers through PlaceEncoder(...). This makes encoder swapping explicit and keeps base cells empty until they are placed.
Serialization follows ownership: EncoderBankBank::ToJSON() iterates the full encoder array and writes each named parameter, and FromJSON() does the inverse by looking up each name and updating the encoder state.
To accommodate polyphony and quadraphonic effects, the parameter system is structured hierarchically.
Crucially, the base value of a knob is identical for all voices within a track. However, modulation and gestures can apply different offsets to each voice within that track.
StateEncoderCell: The base class that holds the actual numerical state. It stores a value in the normalized range [0, 1].BankedEncoderCell: Extends the state cell to support deep, polyphonic modulation and macro gestures.Every BankedEncoderCell can act as a modulation destination.
BankedEncoderCell. This means you can modulate the modulation depth (e.g., using an LFO to slowly fade in an envelope’s effect on the filter cutoff).1.0 means the parameter is 100% controlled by the modulator, completely overriding the base knob value.Gestures are macro controls mapped to physical analog inputs (Like sliders and joysticks).
0.0, the parameter sits at its base knob value.1.0, the parameter moves to the Target State.BankedEncoderCell (though hidden from the normal UI) and is polyphonic.The entire state of all encoders (base values, modulation depths, and gesture targets) is duplicated across two Scenes (SceneManager.hpp).
m_blendFactor crossfades between the two scenes.EncoderBankUIState: Manages the communication between the deep software state and the physical hardware/screen UI. It handles the rendering of LED rings and the processing of delta increments from physical endless encoders.ParamSlew or FixedSlew) to the final, post-modulation parameter values before using them in audio calculations. During oversampled blocks, this slew rate is adjusted automatically.Each parameter in the Voice banks can specify which source and filter machines it applies to via bit vectors (MachineFlags). Parameters are defined in ForEachSmartGridOneParam.hpp with sourceMachines and filterMachines arguments (e.g. MachineFlags::x_dualWaveShapingVCOOnly for parameters that only affect the Dual Wave Shaping VCO source).
When the user selects a different source machine (e.g. Thru) or filter machine, UpdateEncodersForMachine() runs and swaps the actual encoder pointers in the grid. Parameters that do not apply are removed by placing nullptr in those positions, which leaves the cell empty and disconnected. This keeps the encoder grid relevant to the active machine while preserving encoder state in the owner array. The update is triggered on machine change (config page) and track change (since each track can have different machines).