Skip to content

feat: v0.2.0 deep-dive 2-band -> 3-band rebuild + M2 preset system#66

Merged
yves-vogl merged 1 commit into
mainfrom
feat/v0.2.0-deep-dive-and-presets
Jul 16, 2026
Merged

feat: v0.2.0 deep-dive 2-band -> 3-band rebuild + M2 preset system#66
yves-vogl merged 1 commit into
mainfrom
feat/v0.2.0-deep-dive-and-presets

Conversation

@yves-vogl

Copy link
Copy Markdown
Collaborator

Summary

Research-driven v0.2.0 rebuild (docs/design-brief.md, docs/research-notes.md) restructuring Crypta's signal path from a 2-band (low/high) split to a genuine 3-band (low/mid/high) split matching the reference plugin class's own defining architecture, plus the suite-wide M2 preset system.

Topology (headline change)

  • Two cascaded LR4 crossovers replace the single split: Split Low (60–400 Hz, default 120 Hz, was Crossover Frequency) peels off the Low band; Split High (300–2000 Hz, default 600 Hz, NEW) splits the remainder into Mid and High. The two are clamped ≥1/3 octave apart (src/dsp/SplitGap.h) to prevent a degenerate near-zero-width Mid band.
  • New Mid band (src/dsp/MidBand.h/.cpp): staged/cascaded drive-only saturation (0–100%, default 30%) + Level, no filter/tone/blend — matching the reference class's own Mid band exactly.
  • High band's pre-drive highpass (Tight, 20–500 Hz, default 100 Hz) promoted from a Razor-only fixed 200 Hz constant to a first-class, voicing-independent control.
  • Low-band compressor ballistics re-sourced to the reference class's fixed "glue" values: ratio 4:1→2:1, attack 10→3 ms, release 120→6 ms (range floor lowered 10→5 ms). Retires the "New York style" framing.
  • IR loader relocated to process only the Mid+High post-sum signal, never the Low band — structurally enforced and directly tested (tests/LowBandIsolationTests.cpp).
  • EQ default corner frequencies re-anchored (80/500/2800/5000 Hz, sourced bass tone-stack anchors).
  • src/dsp/PhaseAlignFilter.h (unplanned engineering necessity, discovered during this rebuild): a naive cascade of two independent LR4 crossovers does not flat-sum on its own — up to −10 dB deviation was measured at close split ratios. Fixed with an allpass compensation filter on the Low band; the fix is proven algebraically (not just empirically) in docs/architecture.md's "Cascaded 3-band flat-sum and phase alignment" section.
  • Lossy v0.1.x state migration: the old crossoverFreq value maps to the new splitHighHz, clamped into 300–2000 Hz. v0.1.x's shipped default (250 Hz) lands exactly at the 300 Hz floor — dedicated regression test in tests/StateMigrationTests.cpp.

M2 preset system (ported from basilica-audio/nave's pilot)

  • src/presets/PresetManager.{h,cpp}, PresetBar.{h,cpp}, Localisation.{h,cpp} — copied verbatim per the replication recipe.
  • Nine factory presets (presets/factory/*.json, documented in docs/presets.md): Default, Glue & Grind, Sub Lock, Throat, Fuzz Wall, Cut Through, Definition Only, Clean Low/Loud Top, Cab-Colored Grind.
  • German localisation of the preset UI frame (resources/i18n/de.txt); core/DSP terminology is never translated.
  • CMakeLists.txt: juce_add_binary_data(CryptaBinaryData ...), links juce_gui_basics + CryptaBinaryData into SharedCode.
  • PluginEditor now docks a PresetBar above the existing generic editor.

Version

Bumped to 0.2.0.

Test plan

  • ctest --test-dir build --output-on-failure96/96 Catch2 tests green locally (Debug, native arm64), up from 53 pre-rebuild. All v0.1.1 regression coverage (reset(), midFilter reset, tail length, oversized-block chunking) stays green.
  • New coverage: SplitGapTests, MidBandTests, ThreeBandFlatSumTests (3-band flat-sum incl. the minimum-gap clamp boundary), StateMigrationTests (incl. the untouched-v1-default → exactly-300Hz test), LowBandIsolationTests (IR-routing guarantee), TopologyRobustnessTests (NaN/Inf sweep of every new/changed control), PresetManagerTests (17 cases, ported from nave).
  • cmake --build build --target Tests Crypta_Standalone — both build clean (Debug, Ninja, native arm64).
  • CI (macOS + Windows, pluginval strictness 10, auval) — pending, watching after this PR opens.

🤖 Generated with Claude Code

Research-driven rebuild (docs/design-brief.md, docs/research-notes.md),
restructuring the signal path from a 2-band (low/high) split to a genuine
3-band (low/mid/high) split matching the reference class's own defining
architecture, plus the suite-wide M2 preset system.

Topology:
- Two cascaded LR4 crossovers replace the single split: Split Low
  (60-400 Hz, default 120 Hz, was Crossover Frequency) peels off the Low
  band; Split High (300-2000 Hz, default 600 Hz, NEW) splits the remainder
  into Mid and High. Clamped >=1/3 octave apart (src/dsp/SplitGap.h).
- New Mid band (src/dsp/MidBand.h/.cpp): staged/cascaded drive-only
  saturation (0-100%, default 30%) + Level, no filter/tone/blend, its own
  4x-oversampled shaping stage.
- High band's pre-drive highpass ("Tight", 20-500 Hz, default 100 Hz) is
  promoted from a Razor-only fixed 200 Hz constant to a first-class,
  voicing-independent control applied ahead of all three voicings.
- Low-band compressor ballistics re-sourced to the reference class's fixed
  "glue" values: ratio 4:1->2:1, attack 10->3ms, release 120->6ms (range
  floor 10->5ms). Retires the "New York style" framing.
- IR loader relocated to process only the Mid+High post-sum signal, never
  the Low band - structurally enforced and tested
  (tests/LowBandIsolationTests.cpp).
- EQ default corner frequencies re-anchored: 100->80Hz, 2500->2800Hz,
  8000->5000Hz (dormant unless EQ is enabled).
- Added src/dsp/PhaseAlignFilter.h: a naive cascade of two independent LR4
  crossovers does not flat-sum on its own (up to -10dB deviation measured
  at close split ratios) - fixed with an allpass compensation filter on the
  Low band, proven algebraically in docs/architecture.md, not just
  empirically.
- Lossy v0.1.x state migration: the old crossoverFreq value maps to the new
  Split High parameter, clamped into its 300-2000Hz range (v0.1.x's 250Hz
  default lands exactly at the 300Hz floor - dedicated regression test).

M2 preset system (ported from basilica-audio/nave's pilot):
- src/presets/PresetManager.{h,cpp}, src/presets/PresetBar.{h,cpp},
  src/presets/Localisation.{h,cpp} (copied verbatim per the replication
  recipe).
- Nine factory presets (presets/factory/*.json, docs/presets.md).
- German localisation of the preset UI frame (resources/i18n/de.txt).
- CMakeLists.txt: juce_add_binary_data(CryptaBinaryData ...), links
  juce_gui_basics + CryptaBinaryData into SharedCode.
- PluginEditor now docks a PresetBar above the existing generic editor.

Tests: 53 -> 96 Catch2 cases (all v0.1.1 regression coverage kept green;
new: SplitGapTests, MidBandTests, ThreeBandFlatSumTests,
StateMigrationTests, LowBandIsolationTests, TopologyRobustnessTests,
PresetManagerTests, plus Voicing/GainStaging/Latency/Parameter/State test
updates for the new topology).

Docs rewritten: docs/manual.md, docs/architecture.md, README.md,
CHANGELOG.md (v0.2.0 entry). docs/design-brief.md and
docs/research-notes.md added as the binding brief for this rebuild.

Version bumped to 0.2.0.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@yves-vogl
yves-vogl merged commit f301d1c into main Jul 16, 2026
2 checks passed
@yves-vogl
yves-vogl deleted the feat/v0.2.0-deep-dive-and-presets branch July 16, 2026 06:02
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.

1 participant