Skip to content

AnalogService

Source: AnalogService.h

Row

struct Row
src/core/AnalogService.h:216

One analog input: where it is wired, the travel that matters, what it drives, and the filter state it carries between polls.

The state is per row because two pots are independent.

Public Attributes

uint32_t id = 0

int8_t pin = -1

uint16_t inMin = 0 : the raw count the travel STARTS at

uint16_t inMax = 0 : and where it ends: set to full scale when a row is added

bool invert = false : a pot wired the other way round

InputAction action {}

uint16_t raw = 0 : the last reading, unfiltered: what a user calibrates from

uint16_t smoothed = 0 : the running average, in raw counts

uint8_t mapped = 0 : what the target last received

bool primed = false : the average holds a real reading, so it can be trusted

bool sent = false : a value has been written, so mapped is a real comparison

AnalogService

class AnalogService
src/core/AnalogService.h:44

Inherits: MoonModule, ListSource

A core, domain-neutral ANALOG INPUT peripheral: a list of ADC pins, each driving a control with a value rather than an event.

The continuous twin of ButtonService, which drives the same controls from a contact.

An expression pedal is the shape this is built around, and it is why the rows carry more than a pin. A pedal's usable travel is never the full sweep: it rests at some count and tops out well below full scale, so a raw reading mapped straight through would give a control that never reaches 0 or 255 and jumps at one end. inMin / inMax name the travel that matters and invert covers a pot wired the other way round, which is the difference between a pedal that feels right and one a user has to fight.

It writes the surface, not a driver. A row names a target as Module.control and goes through Scheduler::setControl, the same primitive every other transport uses, so a pedal and an OSC message are indistinguishable to whatever they drive. Pointing a row at Control.fader1 (the recommended path) puts the pedal on the control surface where the assignment can then be changed without touching the pedal's own configuration.

Smoothed here, not in the platform. An ADC pin jitters by a few counts even at rest, and a pot adds its own noise, so an unfiltered read would rewrite its target every tick forever. The seam reports raw counts (a jitter figure is a property of what is WIRED, which only this module knows) and the smoothing is an exponential average whose weight a user can see and change. A deadband on top of it is what stops a resting pedal from writing at all.

Polled on tick20ms. A foot moves in tens of milliseconds and 50 Hz follows it comfortably, where the render tick would sample a pedal thousands of times a second to learn the same thing. It also means a busy ADC cannot stutter the lights at the frame rate.

Not auto-wired. Factory-registered like the other services: a board with a pedal jack or an on-board sense divider adds it under Services, with a row per pin.

Public Methods

virtual inline ModuleRole role() const override : Role for type identification (no RTTI needed).

virtual inline void defineControls() override : defineControls MUST be idempotent and pure: only controls_.clear() + controls_.addX().

virtual inline void tick20ms() override : Poll every configured pin at 50 Hz. Not on tick(): a foot moves in tens of milliseconds.

inline bool isEditableList() const override

inline uint8_t listRowCount() const override

inline void writeListRow(JsonSink & sink, uint8_t row) const override

inline void writeListRowDetail(JsonSink & sink, uint8_t row) const override

inline void writeListOptionSets(JsonSink & sink) const override

inline bool addListRow(uint32_t & outId) override

inline bool deleteListRow(uint32_t id) override

inline bool setListRowField(uint32_t id, const char * field, const char * valueJson) override

inline bool restoreList(const char * json, const char * key) override