Skip to content

[minor] Add SpectrumAnalyzer widget - #516

Merged
matt-edmondson merged 3 commits into
mainfrom
claude/project-thread-tp7qwq
Sep 29, 2026
Merged

matt-edmondson merged 3 commits into
mainfrom
claude/project-thread-tp7qwq

Conversation

@matt-edmondson

Copy link
Copy Markdown
Contributor

Requested by Matt · project thread

Before: ktsu.ImGui.Widgets could show an audio level (DbMeter) and a waveform (Scope), but not a spectrum. A host with FFT output had to draw one itself.

After: ImGuiWidgets.SpectrumAnalyzer draws caller-supplied FFT magnitudes as log-frequency bars, or as a line, with a peak-hold marker per band. It uses DbMeter's zone colours and Scope's frame layout, with gridlines at each frequency decade and every 12 dB. It marks itself with ImGuiProbes.MarkItem.

The FFT stays with the host. The widget takes the N/2+1 bin magnitudes of a real FFT in dB.

How: SpectrumAnalyzerState is a public, caller-owned class with no ImGui dependency. It groups the bins into log-spaced bands, and each band shows its loudest bin, so a pure tone reads at its true level. Bands too narrow to hold a bin are interpolated at their centre rather than shown as silent, and bands above Nyquist read silence. Bars rise at once and fall at BarFallRate. Peaks hold for PeakHoldSeconds, then fall at PeakFallRate, never below their bar, and the fall is the same however the frame time is sliced. One overload updates and draws using io.DeltaTime; the other only draws, so one state can be shown twice without advancing twice.

The state is owned by the caller, like ImageCanvasState, rather than kept under the widget's ImGui id as #501 suggested. That way nothing accumulates inside the library.

Also includes:

  • 17 unit tests for the state, run without an ImGui context.
  • A 6-test isolation suite in tests/ImGui.Widgets.UITests/.
  • A "Spectrum Analyzer" demo section, a sweeping tone over pink noise, which is added to the demo suite's expand-every-section test.
  • README and CLAUDE.md widget list entries.

Tested locally in Release. The widget unit tests (344), the widget UI suite (388) and the widgets demo suite (30) all pass. The demo suite ran against a stand-in ktsu.png in the build output, because this checkout has the LFS pointer instead of the image.

Closes #501

🤖 Generated with Claude Code

https://claude.ai/code/session_01KwPRukimexyvu84zFn7oEP


Generated by Claude Code

Log-frequency bars or a line over caller-supplied FFT magnitudes, with
peak hold, in DbMeter's zone colours and Scope's frame layout. Band
folding, bar ballistics and peak hold live in SpectrumAnalyzerState,
tested without an ImGui context. Adds an isolation UI suite, a demo
section and README/CLAUDE.md entries.

Closes #501

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KwPRukimexyvu84zFn7oEP
@matt-edmondson matt-edmondson self-assigned this Sep 29, 2026
Comment thread ImGui.Widgets/SpectrumAnalyzerState.cs Fixed
Comment thread ImGui.Widgets/SpectrumAnalyzerState.cs Fixed
Comment thread ImGui.Widgets/SpectrumAnalyzerState.cs Fixed
Comment thread ImGui.Widgets/SpectrumAnalyzerState.cs Fixed
Comment thread ImGui.Widgets/SpectrumAnalyzerState.cs Fixed
Replaces the negated comparisons code quality flagged with direct ones,
naming NaN and infinity explicitly so the guards reject the same inputs.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KwPRukimexyvu84zFn7oEP
Keeps both Waveform and SpectrumAnalyzer in the docs, demo and demo
suite. The two signal demo sections go through a small SignalDemos
class, because referencing both from ImGuiWidgetsDemo pushed it over
the CA1506 class-coupling limit.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KwPRukimexyvu84zFn7oEP
@sonarqubecloud

Copy link
Copy Markdown

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Domain widgets Tier 1: add SpectrumAnalyzer (log-frequency bars/line with peak hold)

2 participants