This document describes the visualizer system for the Smart Grid One display. Visualizers render DSP data (scopes, spectra, meters, etc.) in the 24×18 grid layout, driven by the selected encoder bank.
| File | Purpose |
|---|---|
SmartGridOneMainVisualizerComponent.hpp |
Base class for all visualizers. Defines Draw() and optional OnClick(). |
SmartGridOneVisualizerMain.hpp |
Main container component. Owns visualizer instances, handles layout, dispatch, and metering. |
ForEachSmartGridOneVisualizer.hpp |
X-macro list mapping (name, bank, block, constructor, source-machine flags) for each visualizer. |
ForEachModulationVisualizer.hpp |
X-macro list with panel entries and encoder-only modulator entries. |
ModulatorVisualizers.hpp |
Owns encoder background instances, indexed by mode and modulator. |
EncoderModulatorComponents.hpp |
Individual Sheafy dials, Noise traces, and Spread bars for encoder backgrounds. |
GangedRandomLFOComponent.hpp |
Predictive wait/move view for one fixed-size correlated random gang. |
PartialMachineComponents.hpp |
Partial Machine input-spectrum and spatial atom views. |
Visualizers are not JUCE Components. They are lightweight structs that implement:
Draw(juce::Graphics& g, juce::Rectangle<int> bounds) — Pure virtual. Receives block-local bounds (0, 0, width, height) after the main component has set clip region and origin.OnClick(const juce::MouseEvent& event) — Optional override. Event position is in block-local coordinates.Each visualizer also carries SourceMachineFlags, and SmartGridOneVisualizerMain only draws visualizers whose flags match at least one visible voice in the active track.
The grid is 24×18 cells. Block positions:
| Block | Grid position | Description |
|---|---|---|
| 0 | (0, 0) | Top-left 8×8 |
| 1 | (0, 8) | Left 8×8 |
| 2 | (8, 8) | Center 8×8 |
| 3 | (16, 8) | Right 8×8 |
| -1 | (0, 8), 24×8 | Full-width strip (e.g. MelodyRoll) |
| slots 0-11 | (x, 16), 2×2 | Modulation panels drawn across the bottom row |
Encoder regions at (8,0), (16,0), (8,3), (16,3) are excluded from paint and click handling.
Metering occupies (8, 5), 16×2 cells.
EncoderBankUIState publishes the selected bank mode and each visible cell’s encoder type and index. Connected ModulatorAmount cells use those fields to look up their source’s background, including nested selected depths at (3,3). Base parameters show a background when exactly one affecting modulator has a visualizer; unassociated sources and gesture assignments do not count. Gesture cells do not draw a background. Depth cells always retain their own source, even when another modulator affects the depth, and depth zero still shows its source.
The modulation visualizer catalogue associates each supported panel with a VoiceModulator, QuadModulator, or GlobalModulator enum. G(name, slot, constructor, mode, color, modulator) defines a panel and its optional encoder association. The panel slot is independent of this association; std::nullopt leaves a panel unassociated (currently the combined Sheafy panel). H(modulator, constructor) defines an encoder-only view: Sheaf 1–3, Voice/Quad Spread, and Noise in all three modes. These entries add no bottom panels or panel click handling.
SmartGridOneVisualizerMain uses each associated panel constructor twice: once for the existing panel, once for the encoder background. Encoder-only constructors run once. Background instances occupy a fixed 3×15 owning table (26 populated entries). All three voice bank modes share the Voice row and follow the existing active-trio UI state. Scope buffers and random-LFO snapshots are shared, while panel voice selection is separate from background scope selection.
Each encoder draws its background inside the square dial area at 50% opacity using a JUCE transparency layer. Its arcs, indicators, name and badges retain their normal appearance. The badge strip is outside the clip, whether above or below the dial. Depths use direct lookup. Base parameters inspect only their affecting-modulator bits and stop at the second eligible source. Drawing constructs no visualizer objects; background views receive no mouse events. Ganged-random and quad LFO indicator dots use the supplied modulator color, while their path colors stay unchanged.
Individual Sheafy dials fit inside the encoder’s voice rings and share its 270-degree sweep. Spokes show the selected axis’s attainable values for the active trio’s current lens and time slice. Three concentric filled arcs show the actual held values in voice colors, read from m_nonagonUIState.m_extraTimbre; these include unison selection and may differ from the next pending pitch choices. The existing combined Sheafy panel is unchanged.
Noise draws a fresh UI-generated random trace each frame, without reading or advancing the DSP random generator. Spread draws three or four narrow bars for its fixed values from zero to one, centered inside the innermost encoder ring. Its bars use active-trio voice colors in Voice mode and fixed voice colors in Quad mode. Both follow the corresponding visual styles in Sheaf. All named modulators now have backgrounds, so combining Noise or Spread with an LFO counts as two eligible sources and hides the base parameter’s background.
The selected encoder bank (SmartGridOneEncoders::Bank) determines which visualizers are drawn. Banks:
Visualizers read from:
TheNonagonSquiggleBoyInternal::UIState — Central UI state. Access via NonagonWrapper::GetUIState().m_squiggleBoyUIState — Contains:
m_audioScopeWriter, m_controlScopeWriter, m_quadScopeWriter, m_quadControlScopeWriter, m_globalControlScopeWriter, m_sourceMixerScopeWriter, m_monoScopeWriter, m_monoAudioScopeWriter — Scope buffersm_voiceMeterReader, m_returnMeterReader, etc. — Meter readersm_activeTrack, m_xPos, m_yPos — Panning/position statem_gangedRandomLFOUIState, m_quadGangedRandomLFOUIState, m_globalGangedRandomLFOUIState — Coherent predictive random-LFO snapshotsm_voiceFilterUIState — Filter response for analyzer overlaysm_delayUIState, m_reverbUIState, m_partialMachineUIState — Effect UI state for quad analyzers and other effect-specific visualizersNonagonWrapper — Provides GetAudioScopeWriter(), GetControlScopeWriter(), GetNoteWriter(), etc.| Component | Bank(s) | Block | Data source |
|---|---|---|---|
| ScopeComponent | Source, FilterAndAmp, VoiceLFOs | 0–3 | ScopeWriter, voice offset |
| GangedRandomLFOComponent | Voice, Quad, Global modulation panels | slots 0–3 | Ganged random LFO snapshots |
| AnalyserComponent | Source, FilterAndAmp | 3 | WindowedFFT, voice filter UI state |
| PhysicalModelingFrequencyResponseComponent | Source | 0 | PhysicalModelingSource::UIState transfer function |
| SampleTrioWaveformVisualizerComponent | Source | 1 | AudioBufferBank::UIState waveform buckets plus SampleSource::UIState read-head/window data |
| VoiceMeterComponent | FilterAndAmp | 0 | m_voiceMeterReader |
| SoundStageComponent | PanningAndSequencing | 0 | m_xPos, m_yPos, m_voiceMeterReader |
| MelodyRollComponent | PanningAndSequencing | -1 | NonagonNoteWriter |
| QuadAnalyserComponent | Delay, Reverb, PartialMachine, TheoryOfTime | 0 | m_quadScopeWriter, delay/reverb/partial-machine UI state |
| QuadDelayEnvelopeVisualizerComponent | Delay, TheoryOfTime | 1 | m_delayUIState envelope snapshots plus relative read/write head positions |
| PartialMachineInputSpectrumComponent | PartialMachine | 1 | m_monoAudioScopeWriter plus m_partialMachineUIState atom snapshot |
| PartialMachineSpatialComponent | PartialMachine | 2 | m_partialMachineUIState atom snapshot and frequency-dependent spatial mapping |
| TheoryOfTimeScopeComponent | TheoryOfTime | 2 | m_monoScopeWriter |
| SourceMixerReductionComponent | Mastering, Inputs, DeepVocoder | 0–3 | m_sourceMixerScopeWriter |
| SourceMixerFrequencyComponent | Mastering, Inputs, DeepVocoder | 1–3 | m_sourceMixerScopeWriter |
| MultibandEQComponent | Mastering, Inputs, DeepVocoder | 2–3 | m_quadScopeWriter |
| MultibandGainReductionComponent | Mastering, Inputs, DeepVocoder | 3 | m_stereoMasteringChainUIState |
QuadDelayEnvelopeVisualizerComponent is a non-FFT effect view. It renders min/max envelope snapshots derived from the quad delay’s movable-writer buffer and overlays the current relative read/write tape-head positions from m_delayUIState.
GangedRandomLFOComponent reconstructs each voice’s complete current round without storing scope history. It draws elapsed wait/move motion as a solid path, the remaining predicted contour as dashed segments, and the present position as a dot on the shared longest-voice time axis.
SampleTrioWaveformVisualizerComponent is another non-FFT Source view. It renders one horizontal strip per voice in the active trio using min/max buckets published by each selected AudioBufferBank; the active SampleStart/SampleLength region is colored by voice, and the current sample read head is drawn as a white vertical line.
PartialMachineInputSpectrumComponent draws the mono input sent into the Partial Machine, then overlays the tracked atoms after frequency-dependent reduction. PartialMachineSpatialComponent draws those same atoms in the quad field using the Partial Machine’s frequency-to-radius and frequency-to-azimuth mapping.