chore: land janitor round 1 and graft integration
Round 1 findings and fixes, all previously uncommitted: - FXProcessor per-slot DSP history repair (HEAD does not compile without it) - SynthVoice::getModulationValue, editor control-lock guard - ExactCompare.h naming the deliberate exact float comparisons - KnobLookAndFeel replacing the never-installed SerumLookAndFeel - 55 first-party compiler warnings to 0 - AGENT.md renamed to AGENTS.md across Source/ - graft repository context graph and its hooks - JANITOR_TASKS.md and UI_UX_AUDIT.md records
This commit is contained in:
1 parent
5c942cad0c
commit
e4cea300db
63 files changed
+2360
-805
No files matched your search
@@ -1,70 +1,76 @@
|
||||
# SerumAlt
|
||||
|
||||
A modern, commercial-quality wavetable synthesiser plugin (VST3 / AU / Standalone)
|
||||
built with **JUCE 7**, **CMake** and **C++17**. SerumAlt is a self-contained synth
|
||||
inspired by the workflow of Serum/Vital: two morphing wavetable oscillators, a full
|
||||
filter section, four envelopes and LFOs, a modulation matrix, a reorderable FX rack,
|
||||
four macros and a one-click **RAVE** button.
|
||||
A wavetable synthesiser experiment built with JUCE 7, CMake and C++17. It targets
|
||||
VST3, AU and Standalone formats, with a workflow inspired by Serum and Vital.
|
||||
This is a fun proof of concept, not a commercial release. Development favors
|
||||
working builds and hands-on listening over elaborate test infrastructure.
|
||||
|
||||

|
||||
|
||||
## Features
|
||||
|
||||
- **Two wavetable oscillators** — 256 frames × 2048 samples, bilinear morphing,
|
||||
8 warp modes (Bend+/-, Sync, PWM, Asym, Mirror, Fold), unison 1–16 with phase
|
||||
spread/detune/width.
|
||||
- **10 factory wavetables** (Basic Shapes, Saw PWM, Square Sync, Triangle Fold,
|
||||
Vowel, Organ, Warm Saw, Digital, Glass, Bass), generated lazily and RAM-resident.
|
||||
- **Sub oscillator** (sine/triangle, −2/−1/0 oct) and **noise** (white/pink).
|
||||
- **Filter section** — two slots, 7 models (Ladder LP/HP/BP, Diode, Comb, Formant,
|
||||
Screamer), 6/12/24 dB slopes, drive, keytrack, and serial/parallel/split routing.
|
||||
- **4 ADSR envelopes** with curve tension and live preview.
|
||||
- **4 LFOs** — tempo-sync, 7 shapes (sine/tri/saw/square/S&H/step/freehand),
|
||||
editable step-sequencer and freehand drawing, fade-in and start delay.
|
||||
- **Modulation matrix** — direct source→destination connections with bipolar depth.
|
||||
- **FX rack** — 9 effects (Hyper/OTT, Chorus, Flanger, Phaser, Distortion, EQ,
|
||||
Compressor, Delay, Reverb) in 8 reorderable slots.
|
||||
- **4 macros** (Energy, Width, Drive, Atmosphere) with assignable destinations.
|
||||
- **RAVE** — one-click boost (unison, width, drive, OTT, reverb) with snapshot/restore.
|
||||
- **16 factory presets** with production-quality values.
|
||||
- **Scalable GUI** (75% / 100% / 125% / 150% / 200%) — dark modern vector look,
|
||||
Path-drawn controls, SVG logo/background, real-time waveform/filter/envelope/LFO
|
||||
displays.
|
||||
- Two wavetable oscillators, each with 256 frames of 2048 samples, bilinear
|
||||
morphing, seven warp effects plus bypass, and up to 16 unison voices.
|
||||
- Ten factory wavetables, built before audio rendering and kept in memory.
|
||||
- Sine/triangle sub oscillator and white/pink noise.
|
||||
- Two filter slots with seven models, drive, key tracking and serial, parallel
|
||||
or split routing.
|
||||
- Four ADSR envelopes and four free-running or tempo-synced LFOs, including
|
||||
editable step and freehand shapes.
|
||||
- A modulation matrix and four assignable macros.
|
||||
- Nine effect types in eight reorderable slots, with independent state per slot.
|
||||
- A non-destructive RAVE boost for unison, spread, drive, Hyper and reverb.
|
||||
- Sixteen factory presets and a scalable vector GUI with waveform, envelope,
|
||||
LFO and schematic filter previews.
|
||||
|
||||
## Architecture
|
||||
|
||||
```
|
||||
Source/
|
||||
PluginProcessor.{h,cpp} APVTS, presets, state, RAVE/UI-scale glue
|
||||
PluginEditor.{h,cpp} Tabbed dark GUI, scaling, visualisations
|
||||
Params.{h,cpp} Parameter IDs, enums, mod sources/targets, mappings
|
||||
Wavetable.{h,cpp} 256×2048 tables + lazy library
|
||||
PluginEditor.{h,cpp} Tabbed GUI, owned controls, scaling, previews
|
||||
Params.{h,cpp} Parameter IDs, indexed groups, enums, mappings
|
||||
Wavetable.{h,cpp} 256×2048 tables, prebuilt by the engine
|
||||
Oscillator.{h,cpp} Morph/warp/unison oscillator
|
||||
SubOscillator.{h,cpp} Sine/triangle sub
|
||||
NoiseOscillator.{h,cpp} White/pink noise
|
||||
Filter.{h,cpp} 7 filter models
|
||||
FilterBank.{h,cpp} 2 slots + routing
|
||||
Filter.{h,cpp} Seven filter models and cached coefficients
|
||||
FilterBank.{h,cpp} Two slots and routing
|
||||
Envelope.{h,cpp} ADSR with curve
|
||||
LFO.{h,cpp} Synced LFO + shape editing
|
||||
LFO.{h,cpp} Continuous phase, sync and shape editing
|
||||
ModulationMatrix.{h,cpp} Connections
|
||||
FXProcessor.{h,cpp} Reorderable rack
|
||||
FXProcessor.{h,cpp} Independent effect state per rack slot
|
||||
EffectUnits/ Hyper, Chorus, Flanger, Phaser, Distortion, EQ,
|
||||
Compressor, Delay, Reverb
|
||||
MacroControls.{h,cpp} 4 assignable macros
|
||||
RAVEButton.{h,cpp} RAVE snapshot/boost
|
||||
SynthVoice.{h,cpp} 32-voice pool render path
|
||||
Engine.{h,cpp} Per-block DSP + MIDI + FX + limiting
|
||||
GUI/ Knob, Slider, ToggleButton, Display, Panel,
|
||||
Waveform/Filter/Envelope/LFO displays
|
||||
Presets/FactoryPresets.cpp 16 factory presets
|
||||
MacroControls.{h,cpp} Four assignable macros
|
||||
RAVEButton.{h,cpp} Render-time boost, without rewriting parameters
|
||||
SynthVoice.{h,cpp} Per-voice oscillators, filters and envelopes
|
||||
Engine.{h,cpp} 32 voices, MIDI timing, control snapshots, FX
|
||||
GUI/ Controls and previews
|
||||
Presets/FactoryPresets.cpp Factory preset definitions
|
||||
Resources/ SVG assets
|
||||
```
|
||||
|
||||
Key architectural decisions: a fixed 32-voice pool with pre-allocated unison
|
||||
sub-voices (max 16/osc), scalar processing (SIMD deferred), control-rate modulation
|
||||
(one level, no modulation-of-modulation), and a `juce::AudioProcessorValueTreeState`
|
||||
backed parameter store that survives preset save/load together with the mod matrix,
|
||||
macro assignments and LFO shape data.
|
||||
The engine splits rendering at MIDI event positions and into segments of at most
|
||||
64 samples. Buffers and effect instances are prepared ahead of time. GUI edits
|
||||
use a control-side copy; audio tries to capture that copy once per host block and
|
||||
keeps its previous settings if an edit is still in progress.
|
||||
|
||||
### Behavior notes
|
||||
|
||||
- Loading a factory preset resets sound parameters before applying its settings,
|
||||
while preserving UI scale.
|
||||
- RAVE is automatable and saved with the project. It changes the rendered sound
|
||||
without moving the underlying knobs; turning it off removes the boost.
|
||||
- Modulation of Master and FX mixes uses global sources directly. Envelope,
|
||||
velocity, note and random sources for these destinations use the newest active voice.
|
||||
- Effect types can repeat across slots. Reordering swaps settings, not running
|
||||
delay or reverb tails. Preconstructing effects uses more memory but avoids
|
||||
allocating effect instances while audio is running.
|
||||
- Filter graphs are schematic previews, not measurements of the nonlinear DSP.
|
||||
- LFO shape data is stored as JSON text inside the project's XML state. Older
|
||||
saves containing only the literal `[Array]` did not preserve the shape data
|
||||
and fall back to the default pattern.
|
||||
|
||||
## Building
|
||||
|
||||
@@ -139,7 +145,10 @@ The Windows script reuses the toolchain file without rewriting it. It injects
|
||||
`moduleinfo.json` because the cross-compiled JUCE manifest helper cannot run on
|
||||
Linux. Keep this manifest's metadata in sync with `CMakeLists.txt`,
|
||||
`cmake/Plugin.cmake`, and the vendored VST3 SDK. MinGW links its C++ and threading
|
||||
runtimes statically via `-static-libgcc -static-libstdc++ -static`.
|
||||
runtimes statically via `-static-libgcc -static-libstdc++ -static`. Before staging,
|
||||
the script verifies the linked module is x86-64, imports none of those MinGW
|
||||
runtimes, and exports the VST3 entry points, so a module that a stock Windows host
|
||||
could not load fails the build instead of being staged silently.
|
||||
|
||||
macOS builds target the host architecture by default. To request a universal binary:
|
||||
|
||||
|
||||
Reference in new issue
Block a user