M1: multiband width, Auto Mono Safety, Haas Mode, correlation meter, broadened tests, manual#8
Merged
Merged
Conversation
…and Haas Mode Completes the M1 "Complete and refine the DSP" milestone: - Multiband width: an independent Low Width (0-200%, default 0%) control scales the Side signal's low band (below Bass Mono Freq) separately from Width, which now governs the high band whenever the crossover is engaged. Low Width's default reproduces the v0.1 "bass mono" behaviour exactly. - Auto Mono Safety: an optional, correlation-driven Side attenuation that reins in the stereo image whenever the input goes strongly out-of-phase. Only ever scales Side, so the mono-sum invariant holds regardless. - Correlation/phase meter (DSP): a running, leaky-integrated input- correlation estimate, exposed via FirmamentEngine::getCorrelationValue() and FirmamentAudioProcessor::getCorrelationMeterValue(). Drives Auto Mono Safety internally; not yet wired to a GUI meter widget (M3 scope). - Haas Mode: an optional post-decode Right-channel delay (0-40 ms) via juce::dsp::DelayLine, trading the exact mono-sum guarantee for a precedence-effect widening technique. Off by default. - PluginEditor: extended with knobs/toggles for every new parameter, matching the existing plain v0.1-style editor. All four features are gated off/at-default by default, so the existing v0.1 signal path and its tests are unchanged. Verified during implementation that juce::dsp::LinkwitzRileyFilter's dual-output low+high sum is a flat- magnitude allpass, not an exact reconstruction of the input (per JUCE 8.0.14's own class documentation) - this only affects multiband width's design/docs, not the original bass-mono behaviour, which never relied on summing bands.
Grows the suite from 24 to 49 test cases (issue "Broaden test coverage"): - Dedicated coverage for every M1 addition: MultibandWidthTests.cpp, AutoMonoSafetyTests.cpp, CorrelationMeterTests.cpp, HaasModeTests.cpp. - SampleRateSweepTests.cpp: unity round-trip, latency, and finiteness checks across the full 44.1-192 kHz range, plus a mid-session sample- rate-change (re-prepare) test. - BusConfigTests.cpp: direct coverage of isBusesLayoutSupported()'s accepted (mono/stereo in, stereo out) and rejected (mono out, surround, disabled bus) configurations, plus full-signal-path smoke tests for both accepted layouts with every M1 stage engaged. - LongRunStabilityTests.cpp: ~1000-block randomised-automation and ~500-block sustained-worst-case NaN/Inf stability sweeps. - Extended the existing extreme-parameter-value and rapid-automation tests in RobustnessTests.cpp to exercise every new parameter. - ParameterTests.cpp/StateTests.cpp: updated parameter count/defaults and added state round-trip coverage for the four new parameters. All test cases run in well under a second each locally (Debug, macOS); the full suite completes in ~8s.
- docs/manual.md: full user manual - what Firmament is, where it sits in a symphonic-metal chain, signal-flow description, complete parameter reference (range/default/unit/musical description) for all 7 parameters, and mixing tips. - docs/architecture.md: updated Mermaid diagram and per-stage sections for multiband width, Auto Mono Safety, the correlation/phase meter, and Haas Mode; corrected the pre-existing "sum reconstructs the input exactly" claim about LinkwitzRileyFilter's dual-output bands to match JUCE 8.0.14's own documented behaviour (flat-magnitude allpass, not identity). - README.md: expanded feature list, added a parameter table, corrected the roadmap table to match the actual GitHub milestones (M1 DSP completion, M2 presets/state, M3 GUI & accessibility, M4 release). - CLAUDE.md: updated Status/DSP sections to reflect the M1 signal path and test count.
Documents everything added in this M1 DSP-completion pass under a new [0.1.0] - 2026-07-14 section, Keep-a-Changelog style.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Completes the M1 — DSP completion & test coverage milestone and prepares Firmament for a v0.1.0 tag.
DSP (issue #1, "Complete and refine the DSP")
Low Width(0-200%, default 0%) scales the Side signal's low band (belowBass Mono Freq), whileWidthnow governs the high band whenever the crossover is engaged.Low Width's default reproduces the v0.1 "bass mono forces the low band to silence" behaviour exactly (verified intests/MultibandWidthTests.cpp).L + R == 2 * Midmono-sum invariant.FirmamentEngine::getCorrelationValue()/FirmamentAudioProcessor::getCorrelationMeterValue(). Drives Auto Mono Safety internally.juce::dsp::DelayLine), off by default - a deliberate, clearly-documented exception to the mono-sum invariant, since delaying one channel relative to the other is fundamentally incompatible with an exact sum guarantee.PluginEditorextended with knobs/toggles for every new parameter (still the plain v0.1-style editor - custom LookAndFeel is M3).Notable finding, corrected in docs:
juce::dsp::LinkwitzRileyFilter's dual-output low+high bands sum to a flat-magnitude allpass, not an exact reconstruction of the input - this is JUCE 8.0.14's own documented behaviour, confirmed empirically during development. The original v0.1 "Bass Mono" feature was never affected (it only ever discards the low band rather than re-summing), but a pre-existing doc comment overclaimed exact reconstruction; corrected indocs/architecture.mdandFirmamentEngine.h/.cppbefore it could mislead future multiband work.Deferred / explicitly out of scope
getCorrelationMeterValue()), but the visual meter component itself belongs to the M3 "Custom GUI / LookAndFeel" issue ("Add metering where relevant to the plugin"), not M1. Not closing that issue.Tests (issue #2, "Broaden test coverage")
Grew the suite from 24 to 49 Catch2 test cases:
SampleRateSweepTests.cpp- unity round-trip, latency, and finiteness across the full 44.1-192 kHz range, plus a mid-session sample-rate-change test.BusConfigTests.cpp- directisBusesLayoutSupported()accepted/rejected coverage (mono/stereo in, stereo out, surround/mono-out/disabled rejections) plus full-signal-path smoke tests with every M1 stage engaged.LongRunStabilityTests.cpp- ~1000-block randomised-automation and ~500-block sustained-worst-case NaN/Inf stability sweeps.RobustnessTests.cpp's extreme-value and rapid-automation tests to cover every new parameter.MultibandWidthTests.cpp,AutoMonoSafetyTests.cpp,CorrelationMeterTests.cpp,HaasModeTests.cpp.ParameterTests.cpp/StateTests.cppupdated for the 4 new parameters (count, defaults, ranges, state round-trip).All existing v0.1 null/reference/mono-collapse/latency tests remain green and unmodified in intent (only extended with new parameters at their v0.1-equivalent defaults).
Documentation
docs/manual.md- full user manual (what Firmament is, where it sits in a symphonic-metal chain, signal flow, complete 7-parameter reference, mixing tips).docs/architecture.md- updated diagram/sections for the new signal path, plus the LinkwitzRileyFilter documentation correction above.README.md- expanded feature list, added a parameter table, corrected the roadmap table to match the actual GitHub milestones.CLAUDE.md- updated Status/DSP sections.CHANGELOG.md- moved Unreleased content into a new[0.1.0] - 2026-07-14section.Test evidence (local, Debug, macOS arm64)
TestsandFirmament_Standalonebuild cleanly (no warnings from new code).ctest: 100% tests passed, 49/49, ~8s total.CMake project VERSION is already
0.1.0(project(Firmament VERSION 0.1.0 ...), JUCE 8.0.14'sjuce_add_plugininheritsPROJECT_VERSIONwhen no explicitVERSIONis passed - confirmed viaJUCEUtils.cmake), so no version bump was needed.Closes #1
Closes #2