chore: move build output under build/ and scripts into scripts/
Layout: - scripts/ holds the four build scripts plus the new clean.sh - cmake/ holds mingw64-toolchain.cmake - the scripts default to build/linux, build/macos, build/windows, build/harness - docs/ holds the audit documents, with the round 1 task list archived Cleanup: - scripts/clean.sh removes generated output, with --dry-run, --staging, --legacy and --all, and refuses tracked, protected or outside paths - the Windows VST3 manifest now comes from cmake/moduleinfo.json.in, so its version, vendor and class IDs follow cmake/Plugin.cmake instead of a hand-written heredoc that could drift - deleted the unused Source/GUI/Slider, which no code constructed - fixed the hidden double processBlock overload: three warning lines to zero - unslopped the build scripts, the two .cjs helpers and the CMake comments - .gitignore covers the upstream JUCE Projucer and DemoRunner binaries Verified: five scripts pass bash -n; the harness passes CTest with zero warning lines; the Linux VST3 and Standalone link; the Windows cross-build passes its x86-64, runtime-import and entry-point checks; each configure exposes only its own targets; and a full build leaves Source/ and third_party/JUCE unchanged. The generated manifest is identical to the previous hand-written one.
This commit is contained in:
1 parent
e4cea300db
commit
facd5c5b5e
25 files changed
+438
-313
No files matched your search
@@ -0,0 +1,412 @@
|
||||
# SerumAlt UI and UX audit
|
||||
|
||||
Written from the working tree on branch `main`. The user report was "much of
|
||||
features arent correctly described and UI is bearly functional". That bundles
|
||||
two problems, and this audit keeps them apart:
|
||||
|
||||
1. Description. Controls lack names, units and plain descriptions.
|
||||
2. Function. Some controls do not reach the DSP they claim to drive.
|
||||
|
||||
The single largest finding explains the "barely functional" complaint on its
|
||||
own. No knob ever painted its name. `Knob` is a `juce::Slider` with
|
||||
`NoTextBox`, and JUCE does not draw a slider's component name, so every one of
|
||||
the roughly fifty knobs was an unlabelled arc whose only identification was a
|
||||
tooltip hover. The label strings passed to `makeKnob` were correct but
|
||||
invisible, and the runtime FX rename table in `updateVisuals` never reached a
|
||||
user's eyes.
|
||||
|
||||
---
|
||||
|
||||
## How this was produced
|
||||
|
||||
Reconnaissance read `Source/PluginEditor.{h,cpp}`, `Source/Params.{h,cpp}`,
|
||||
`Source/Resources.{h,cpp}`, `Source/PluginProcessor.cpp`, `Source/Engine.cpp`,
|
||||
the nine effects in `Source/EffectUnits/`, and every file in `Source/GUI/`.
|
||||
Four specialist passes then covered naming and descriptions, dead controls,
|
||||
interaction state, and layout plus accessibility. Findings were checked against
|
||||
`AUDIT_REPORT.md` (a codebase structure audit, no UI text coverage) and
|
||||
`JANITOR_TASKS.md` (fourteen tasks, all reported done; JT-01 removed the unused
|
||||
look-and-feel, JT-06 built the FX type list from `FXProcessor::fxTypeName`).
|
||||
Nothing in either file duplicates the findings below.
|
||||
|
||||
The two prior documents also correct the task brief in one respect.
|
||||
`Source/GUI/SerumLookAndFeel.h` no longer exists; JT-01 deleted it because it was
|
||||
never installed. The GUI has no custom look-and-feel, so "draw all controls
|
||||
through `SerumLookAndFeel`" resolves to "use `theme::` colours", which this work
|
||||
does.
|
||||
|
||||
Verification used `BUILD_DIR=/tmp/... ./build_harness.sh --run`.
|
||||
`UI_UX_AUDIT.md` is the deliverable that survives; the fixes listed as applied
|
||||
are already in the tree.
|
||||
|
||||
---
|
||||
|
||||
## Status vocabulary
|
||||
|
||||
- Functioning. The parameter is read by the DSP and changes what you hear.
|
||||
- Dead. Nothing reads it, or the thing that reads it throws the value away.
|
||||
- Conditional. Read and audible only in some modes or for some effect types.
|
||||
- Design decision. Fixing it needs a choice about behaviour or layout, so it was
|
||||
left alone and recorded for the user.
|
||||
|
||||
---
|
||||
|
||||
## Control inventory
|
||||
|
||||
Every user-visible control, by tab. "Readout" is what the knob shows while you
|
||||
drag it.
|
||||
|
||||
### Top bar
|
||||
|
||||
| Control | Parameter | Current label | Current tooltip | What it does and its unit | Recommended label | Recommended tooltip | Status |
|
||||
|---|---|---|---|---|---|---|---|
|
||||
| Preset combo | n/a | (preset name) | Select a factory preset | Loads one of the factory presets and replaces the whole patch | Preset | Loads a factory preset and replaces the current patch | Functioning |
|
||||
| RAVE toggle | `rave` | RAVE | RAVE one-click boost (unison, width, drive, OTT, reverb) | Render-time override: unison to 8, spread and detune to full, both filter drives to 60 %, Hyper intensity to 100 %, reverb mix +0.4 | Rave | Adds unison, width, drive, OTT and reverb to the current patch | Functioning, description was accurate, label case fixed |
|
||||
| Scale combo | `uiScale` | 75%..200% | Interface scale (75% - 200%) | Window scale, 75 % to 200 %. Index maps to a five-entry scale table | Scale | Interface scale, 75 % to 200 % | Functioning |
|
||||
| Master knob | `master` | (invisible) | Master output volume (0-100%) | Master output gain, 0 to 100 % of full scale | Master | Master output level, 0 % to 100 % | Functioning. Percent is not the engineering unit for a gain, see deferred D-8 |
|
||||
| Master readout | `master` | MASTER | none | Painted numeric readout of the same parameter | Master | none needed | Functioning |
|
||||
| Tabs | n/a | OSC, FILTER, MOD, FX, MACRO | Oscillators (Tab cycles sections) etc. | Switches the visible section. Plain Tab also cycles sections | Osc, Filter, Mod, FX, Macro | Oscillators. Tab cycles sections. | Functioning, label case fixed |
|
||||
|
||||
### Oscillator tab
|
||||
|
||||
Oscillator A and Oscillator B have identical control sets. Rows 1 and 2 are
|
||||
listed once.
|
||||
|
||||
| Control | Parameter | Current label | Current tooltip | What it does and its unit | Recommended label | Recommended tooltip | Status |
|
||||
|---|---|---|---|---|---|---|---|
|
||||
| On | `oscAOn` / `oscBOn` | On | Enable oscillator A | Gates the oscillator in `Oscillator::render` | On | Turns oscillator A on or off | Functioning |
|
||||
| Wavetable | `oscAWave` / `oscBWave` | (combo, no visible label) | Oscillator A wavetable | Selects one of 10 factory wavetables | Table | Selects the wavetable, 10 factory tables | Functioning, combo shows its own item text |
|
||||
| Warp mode | `oscAWarp` / `oscBWarp` | (combo) | Oscillator A warp mode | Selects one of 8 warp modes | Warp | Selects the wavetable warp mode | Functioning |
|
||||
| Wavetable position | `oscAWtPos` / `oscBWtPos` | Wavetable Position | Wavetable position (0-100%) | Frame position in the table, 0 to 100 % | Wt position | Wavetable frame position, 0 % to 100 % | Functioning |
|
||||
| Warp amount | `oscAWarpAmt` / `oscBWarpAmt` | Warp Amount | Warp amount (0-100%) | Warp depth, 0 to 100 % | Warp amount | Warp depth, 0 % to 100 % | Functioning |
|
||||
| Coarse | `oscACoarse` / `oscBCoarse` | Coarse | Pitch coarse (-24 to +24 semitones) | Coarse pitch, -24 to +24 semitones | Coarse | Coarse pitch, -24 to +24 semitones | Functioning |
|
||||
| Fine | `oscAFine` / `oscBFine` | Fine | Pitch fine (-100 to +100 cents) | Fine pitch, -100 to +100 cents | Fine | Fine pitch, -100 to +100 cents | Functioning |
|
||||
| Level | `oscALevel` / `oscBLevel` | Level | Oscillator A level (0-100%) | Linear amplitude gain, 0 to 1 | Level | Oscillator A level, 0 % to 100 % | Functioning |
|
||||
| Pan | `oscAPan` / `oscBPan` | Pan | Oscillator A pan (L100-R100) | Stereo position, hard left to hard right | Pan | Oscillator A pan, hard left to hard right | Functioning |
|
||||
| Unison | `oscAUnison` / `oscBUnison` | Unison | Unison voices (1-16) | Voice count, 1 to 16. Now detented so the dial rests on whole voices | Unison | Unison voices, 1 to 16 | Functioning |
|
||||
| Detune | `oscADetune` / `oscBDetune` | Detune | Unison detune (0-100%) | Per-voice detune spread, -50 to +50 cents | Detune | Unison detune spread, -50 to +50 cents | Functioning. Readout used to say "50 %" for 25 cents |
|
||||
| Spread | `oscASpread` / `oscBSpread` | Spread | Unison spread (0-100%) | Stereo spread of the unison voices, 0 to 100 % | Spread | Unison stereo spread, 0 % to 100 % | Functioning |
|
||||
| Phase | `oscAPhase` / `oscBPhase` | Phase | Phase (0-100%) | Start phase at note on, 0 to 360 degrees | Phase | Start phase at note on, 0 to 360 degrees | Functioning. Readout used to say a percentage |
|
||||
| Random phase | `oscARandPh` / `oscBRandPh` | Random Phase | Random phase (0-100%) | Random start phase per voice, up to 360 degrees | Rand phase | Random start phase per voice, 0 to 360 degrees | Functioning. Readout used to say a percentage |
|
||||
| Sub On | `subOn` | On | Enable sub oscillator | Gates the sub oscillator | On | Turns the sub oscillator on or off | Functioning |
|
||||
| Sub shape | `subShape` | (combo) | Sub oscillator waveform | Sine or triangle | Shape | Sub oscillator waveform, sine or triangle | Functioning |
|
||||
| Sub octave | `subOct` | (combo) | Sub oscillator octave | -2, -1 or 0 octaves, engine reads `value - 2` | Octave | Sub oscillator octave, 2 below to unison | Functioning |
|
||||
| Sub level | `subLevel` | Level | Sub oscillator level (0-100%) | Linear amplitude gain | Level | Sub oscillator level, 0 % to 100 % | Functioning |
|
||||
| Noise On | `noiseOn` | On | Enable noise | Gates the noise source | On | Turns noise on or off | Functioning |
|
||||
| Noise type | `noiseType` | (combo) | Noise type | White or pink | Type | Noise colour, white or pink | Functioning |
|
||||
| Noise level | `noiseLevel` | Level | Noise level (0-100%) | Linear amplitude gain | Level | Noise level, 0 % to 100 % | Functioning |
|
||||
|
||||
### Filter tab
|
||||
|
||||
| Control | Parameter | Current label | Current tooltip | What it does and its unit | Recommended label | Recommended tooltip | Status |
|
||||
|---|---|---|---|---|---|---|---|
|
||||
| On | `f1On` / `f2On` | On | Enable filter 1 | Gates the filter in `FilterBank` | On | Turns filter 1 on or off | Functioning |
|
||||
| Type | `f1Type` / `f2Type` | (combo) | Filter 1 type | One of 7 models: Ladder LP, Ladder HP, Ladder BP, Diode, Comb, Formant, Screamer | Type | Selects the filter 1 model | Functioning |
|
||||
| Slope | `f1Slope` / `f2Slope` | (combo) 6 dB, 12 dB, 24 dB | Filter 1 slope | One, two or four one-pole stages on the ladder and diode models. Comb, Formant and Screamer ignore it | Slope | Slope, 6, 12 or 24 dB per octave on the ladder and diode models | Conditional, see D-2 |
|
||||
| Cutoff | `f1Cutoff` / `f2Cutoff` | Cutoff | Filter 1 cutoff (20 Hz - 20 kHz) | Cutoff, 20 Hz to 20 kHz before key tracking, clamped to 18 kHz after it | Cutoff | Filter 1 cutoff, 20 Hz to 18 kHz | Functioning. Tooltip overstated the reachable top |
|
||||
| Resonance | `f1Res` / `f2Res` | Resonance | Filter 1 resonance (0-100%) | Resonance feedback, 0 to 98 % | Resonance | Filter 1 resonance, 0 % to 100 % | Functioning |
|
||||
| Drive | `f1Drive` / `f2Drive` | Drive | Filter 1 drive (0-100%) | Per-sample drive. Damps the comb model. Formant ignores it | Drive | Filter 1 drive, 0 % to 100 %. Damps the comb model. | Conditional, see D-3 |
|
||||
| Keytrack | `f1Key` / `f2Key` | Keytrack | Filter 1 keytrack (0-100%) | Cutoff follows note pitch, 100 % is full tracking | Keytrack | Filter 1 key tracking, 0 % to 100 % | Functioning |
|
||||
| Routing | `fRoute` | (combo) | Filter routing (serial / parallel / split) | Serial, parallel or split | Routing | Filter routing, serial, parallel or split | Functioning |
|
||||
| Mix | `fMix` | Mix | Filter mix (0-100%) | Crossfades filter 1 into filter 2. Read only in parallel routing | Mix | Blends filter 2 over filter 1 in parallel routing, 0 % to 100 % | Conditional, see D-1 |
|
||||
| Output | `fOut` | Output | Filter output (0-100%) | Output gain, engine multiplies by 1.5, so the 0.667 default is unity | Output | Filter output gain, 0 % to 150 % | Functioning. The old readout understated the range: 67 % is unity |
|
||||
|
||||
### Modulation tab
|
||||
|
||||
| Control | Parameter | Current label | Current tooltip | What it does and its unit | Recommended label | Recommended tooltip | Status |
|
||||
|---|---|---|---|---|---|---|---|
|
||||
| Attack | `env1A`..`env4A` | Attack | Attack time (0.5 ms - 12 s) | Attack time, 0.5 ms to 12 s, cubic taper | Attack | Attack time, 0.5 ms to 12 s | Functioning |
|
||||
| Decay | `env1D`..`env4D` | Decay | Decay time (0.5 ms - 12 s) | Decay time, 0.5 ms to 12 s | Decay | Decay time, 0.5 ms to 12 s | Functioning |
|
||||
| Sustain | `env1S`..`env4S` | Sustain | Sustain level (0-100%) | Sustain level, 0 to 100 % | Sustain | Sustain level, 0 % to 100 % | Functioning |
|
||||
| Release | `env1R`..`env4R` | Release | Release time (0.5 ms - 12 s) | Release time, 0.5 ms to 12 s | Release | Release time, 0.5 ms to 12 s | Functioning |
|
||||
| Curve | `env1Curve`..`env4Curve` | Curve | Envelope curve (0-100%) | Shape exponent, mapped to 0.3 to 3.0 | Curve | Curve shape. Low is a fast attack and slow decay, high is the reverse. | Functioning. The readout is still a percentage of an exponent, see D-9 |
|
||||
| Envelope graph | n/a | n/a | none | ADSR curve preview, drawn from the same shape functions as the DSP | n/a | Add a tooltip naming the envelope | Functioning |
|
||||
| Shape | `lfo1Shape`..`lfo4Shape` | (combo) | LFO shape | Sine, Triangle, Saw, Square, S&H, Step, Freehand | Shape | Selects the LFO waveform | Functioning |
|
||||
| Sync | `lfo1Sync`..`lfo4Sync` | Sync | Tempo-sync LFO | Locks the rate to host tempo and uses Beat instead of Rate | Sync | Locks the LFO to host tempo and uses the Beat knob | Functioning |
|
||||
| Rate | `lfo1Rate`..`lfo4Rate` | Rate | LFO rate (0.02 Hz - 30 Hz) | Rate, 0.02 Hz to 30 Hz, log taper | Rate | LFO rate, 0.02 Hz to 30 Hz | Functioning. Readout used to say "50 %" for about 0.77 Hz |
|
||||
| Beat | `lfo1Beat`..`lfo4Beat` | Beat | Beat division (1/32 - 4 bars) | Period of one cycle, one of 16 divisions from 1/32 beat to 16 beats | Beat | Cycle length, 1/32 beat to 16 beats | Functioning. Readout used to say a percentage, and the old tooltip was wrong at the fast end |
|
||||
| Phase | `lfo1Phase`..`lfo4Phase` | Phase | Phase (0-100%) | Start phase offset, 0 to 360 degrees | Phase | Start phase, 0 to 360 degrees | Functioning. Readout used to say a percentage |
|
||||
| Fade | `lfo1Fade`..`lfo4Fade` | Fade | Fade in (0-100%) | Fade in time, 0 to 8 seconds | Fade | Fade in time, 0 s to 8 s | Functioning. Readout and tooltip both said percent for seconds |
|
||||
| Delay | `lfo1Delay`..`lfo4Delay` | Delay | Start delay (0-100%) | Start delay, 0 to 4 seconds | Delay | Start delay, 0 s to 4 s | Functioning. Readout and tooltip both said percent for seconds |
|
||||
| LFO graph | n/a | n/a | none | Shape preview. Step and Freehand are drag-editable | n/a | Describe the drag gesture | Functioning, discoverability is D-11 |
|
||||
| Source | n/a | (combo) | Modulation source | One of 17 sources | Source | Selects the modulation source | Functioning |
|
||||
| Target | n/a | (combo) | Modulation destination | One of 35 destinations | Target | Selects the modulation destination | Functioning |
|
||||
| Depth | n/a | (invisible) | Modulation depth (-1 to +1) | Amount applied to the next Add, -100 % to +100 % of the target range. Negative inverts | Depth | Modulation amount for the next Add, -100 % to +100 % of the target range | Functioning. Readout and tooltip rewritten |
|
||||
| Bipolar | n/a | Bipolar | Bipolar modulation depth | Recentres a one-sided source for the next Add | Bipolar | Recentres a one-sided source so the modulation swings both ways, for the next Add | Functioning |
|
||||
| Add | n/a | Add | Add modulation connection | Appends a connection, capped at 32 | Add | Adds the selected source and destination to the matrix | Functioning |
|
||||
| Remove last | n/a | Remove Last | Remove last modulation connection | Removes the newest row only | Remove last | Removes the newest matrix row, older rows stay | Functioning |
|
||||
| Clear | n/a | Clear | Clear all modulation connections | Removes every connection | Clear all | Removes every modulation connection | Functioning |
|
||||
| Connection list | n/a | (read-only text) | none | Source, target, depth and polarity per row | n/a | Every modulation connection, newest last | Functioning |
|
||||
|
||||
### Effects tab
|
||||
|
||||
Each of the eight slots has the same shape: a type combo, up and down arrows,
|
||||
and five knobs. The knob names, tooltips and readout units follow the selected
|
||||
effect, and that table was rebuilt from the DSP each effect actually runs.
|
||||
|
||||
| Control | Parameter | Current label | What it does and its unit | Readout unit | Status |
|
||||
|---|---|---|---|---|---|
|
||||
| Type | `fx1Type`..`fx8Type` | (combo) | Off, Hyper, Chorus, Flanger, Phaser, Distortion, EQ, Compressor, Delay, Reverb | n/a | Functioning |
|
||||
| Up / Down | n/a | arrow glyphs | Swaps this slot's six parameters with the neighbour | n/a | Functioning. The end arrows are now disabled instead of doing nothing |
|
||||
| Mix | `fx1Mix`..`fx8Mix` | Mix | Dry and wet mix, 0 to 100 % | percent | Functioning |
|
||||
| Off P1..P4 | `fx*P1`..`fx*P4` | Unused | The rack skips an Off slot, so all four do nothing | n/a | Dead by design, now labelled and greyed |
|
||||
| Hyper | | Intensity, Low Amount, High Amount, Output | 0-100 %, 40-100 %, 40-100 %, 0.5x-1.5x | percent, percent, percent, x | Functioning |
|
||||
| Chorus | | Rate, Depth, Width, Unused | 0.1-5 Hz, 0.5-6 ms, 0-100 %, nothing | Hz, ms, percent | Rate and Depth used to read as percent; P4 is genuinely dead |
|
||||
| Flanger | | Rate, Depth, Feedback, Unused | 0.05-2.05 Hz, 0.3-5 ms, 0-90 %, nothing | Hz, ms, percent | Rate and Depth used to read as percent; P4 is genuinely dead |
|
||||
| Phaser | | Rate, Depth, Feedback, Stages | 0.05-2.05 Hz, 30-90 %, 0-70 %, 2-6 | Hz, percent, percent, count | Rate used to read as percent; Stages used to read "50 %" |
|
||||
| Distortion | | Drive, Shape, Tone, Output | 1x-25x, 0-100 %, 800 Hz-16 kHz, 0.4x-1.6x | x, percent, Hz, x | All four used to read as percent |
|
||||
| EQ | | Low Gain, Mid Gain, High Gain, Mid Freq | +/-15 dB, +/-12 dB, +/-15 dB, 200 Hz-5 kHz | dB, dB, dB, Hz | All four used to read as percent |
|
||||
| Compressor | | Threshold, Ratio, Attack, Release | -40-0 dB, 2:1-20:1, 2-100 ms, 30-500 ms | dB, ratio, ms, ms | All four used to read as percent, and two of them share a name with a different unit on the Modulation tab |
|
||||
| Delay | | Time, Feedback, Damping, Ping-Pong | 1-2000 ms, 0-92 %, 0-95 %, on or off | ms, percent, percent, on/off | Time used to read as percent; Ping-Pong used to read "50 %" |
|
||||
| Reverb | | Size, Damping, Width, Predelay | 20-99 %, 0-100 %, 0-100 %, 0-150 ms | percent, percent, percent, ms | Predelay used to read as percent |
|
||||
|
||||
The old tooltips were worse than the readouts. They were only rewritten when a
|
||||
knob's name changed, so two effects sharing a name (Rate, Damping, Feedback,
|
||||
Output) left the previous effect's tooltip on screen, and every one of them
|
||||
claimed "normalised 0-100%".
|
||||
|
||||
### Macro tab
|
||||
|
||||
| Control | Parameter | Current label | Current tooltip | What it does and its unit | Recommended label | Recommended tooltip | Status |
|
||||
|---|---|---|---|---|---|---|---|
|
||||
| Macro knobs | `macro1`..`macro4` | Energy, Width, Drive, Atmosphere | (name) macro (0-100%) | Macro amount, 0 to 100 %, drives its assigned destinations | Energy / Width / Drive / Atmosphere | Energy macro, 0 % to 100 %, drives its assigned destinations | Functioning. Names come from `MacroControls::macroName`; the macro panels have no title of their own, so the knob label is the only identifier |
|
||||
| Macro | n/a | (combo) | Macro to assign | Selects which of the four macros to edit | Macro | Selects the macro to edit | Functioning |
|
||||
| Target | n/a | (combo) | Destination parameter | One of 35 destinations | Target | Selects the destination parameter | Functioning |
|
||||
| Depth | n/a | (invisible) | Macro assignment depth (0 to 1) | Amount applied to the next Assign, 0 to 100 % of the target range | Depth | Macro amount for the next Assign, 0 % to 100 % of the target range | Functioning. Started at zero, so a default Assign was silent; now starts at half |
|
||||
| Assign | n/a | Assign | Assign destination to the selected macro | Appends an assignment, capped at 8 per macro | Assign | Adds this destination to the selected macro | Functioning |
|
||||
| Clear all | n/a | Clear All | Clear all macro assignments | Empties all four macros | Clear all | Removes every macro assignment from all four macros | Functioning |
|
||||
| Assignment list | n/a | (read-only text) | none | Target and depth per macro | n/a | Every macro assignment, grouped by macro | Functioning |
|
||||
|
||||
---
|
||||
|
||||
## Applied mechanical fixes
|
||||
|
||||
Every item below was applied, compiles, and passes the harness.
|
||||
|
||||
### Description fixes
|
||||
|
||||
- A1. Knobs now paint their name. New `Source/GUI/KnobLookAndFeel.{h,cpp}` draws
|
||||
the dial from `theme::` colours and reserves a 16 px strip at the foot of the
|
||||
knob for the label, which `Knob::paint` fills. This is the change that makes
|
||||
every other label in the editor visible for the first time.
|
||||
- A2. All eight FX parameter knobs are named, tooltipped and unit-formatted per
|
||||
effect type from one table (`kFxParamDisplay` in `PluginEditor.cpp`), replacing
|
||||
the two tables that disagreed with each other.
|
||||
- A3. Unit formatters added: LFO rate in Hz, LFO beat as a cycle length, LFO fade
|
||||
and delay in seconds, oscillator detune and both phases in cents and degrees,
|
||||
filter output as a percentage of its real 0-150 % range, modulation depth as
|
||||
-100 % to +100 %, macro depth as 0-100 %, compressor threshold and ratio,
|
||||
filter and EQ gains in dB, chorus and flanger rate in Hz and depth in ms,
|
||||
distortion drive and output as multiples, phaser stage count, ping-pong as on
|
||||
or off, reverb predelay in ms.
|
||||
- A4. Tooltips rewritten for every control that had a vague one: all eight
|
||||
effect types, both filters (cutoff now says 18 kHz, which is the real ceiling),
|
||||
all four envelopes, all four LFOs, the modulation matrix buttons, the macro
|
||||
buttons, the filters' drive and slope, both lists, the preset and scale combos,
|
||||
and the RAVE toggle.
|
||||
- A5. Labels corrected where the name was wrong or abbreviated: tab labels are
|
||||
now Osc/Filter/Mod/FX/Macro, "Random Phase" is "Rand phase" to fit its 76 px
|
||||
knob, and the RAVE toggle reads "Rave".
|
||||
|
||||
### Function fixes that were one line each
|
||||
|
||||
- B1. Double click restored a hardcoded 0.5 for every knob. Forty-nine knob
|
||||
parameters have a different default, so the gesture silently wrote the wrong
|
||||
value. `makeKnob` now reads the parameter's own default through
|
||||
`AudioProcessorParameter::convertFrom0to1`. The modulation depth knob double
|
||||
clicks to its neutral zero, and the macro depth knob to its new half.
|
||||
- B2. The macro depth knob started at zero, so an Assign made without touching
|
||||
it created an inaudible assignment. It now starts at half.
|
||||
- B3. Unison had no detent, so the dial rested between voices. Both unison knobs
|
||||
now step in whole voices.
|
||||
- B4. The first FX slot's up arrow and the last slot's down arrow were enabled
|
||||
but did nothing. They are now disabled.
|
||||
- B5. An FX parameter the selected effect ignores stayed live and editable. Those
|
||||
knobs are now disabled and labelled Unused.
|
||||
- B6. The knob value popup was never clamped to the window, so it was cut off for
|
||||
knobs near an edge. It is now clamped on both axes.
|
||||
- B7. The popup is parented to the editor while the interface scale is applied to
|
||||
a child, so it ignored the 75-200 % scale. It now measures the scale from its
|
||||
own transform and sizes itself to match.
|
||||
- B8. Switching section mid-drag could strand the popup on screen, because it is
|
||||
not a child of the hidden view. `Knob::visibilityChanged` now takes it down.
|
||||
|
||||
### Interaction and accessibility fixes
|
||||
|
||||
- C1. Toggle buttons repainted on mouse activity but never read the hover state,
|
||||
so every On, Sync and Bipolar LED looked identical under the cursor. `paint`
|
||||
now brightens the LED and the name on hover and dims both when disabled.
|
||||
- C2. `ToggleButton::paint` ignored `isEnabled()`. It no longer does.
|
||||
- C3. Knobs now take keyboard focus. `juce::Slider` disables focus in its own
|
||||
constructor, which left every knob unreachable without a mouse and cut off the
|
||||
accessible value interface.
|
||||
|
||||
### Layout constant fixes
|
||||
|
||||
`Source/GUI/AGENTS.md` requires every position to be derived from the `layout`
|
||||
namespace. Each tab declared its own private `colW`, `colGap` and panel heights,
|
||||
and the tab-bar height was the bare literal `60` in six places. Those metrics now
|
||||
live in `layout`, and the per-tab locals alias them, so the value has one home:
|
||||
|
||||
- L1. Named the tab-bar height as `layout::tabBarHeight` and used it in all five
|
||||
tab views plus the matrix and macro panel height calculations.
|
||||
- L2. Hoisted the panel grids: `twoColW`, `threeColW`, `fourColW`, `fourColGap`,
|
||||
and the panel heights `oscPanelH`, `smallPanelH`, `filterPanelH`, `envPanelH`,
|
||||
`lfoPanelH`, `macroPanelH`.
|
||||
- L3. Named `depthKnobHeight` for the matrix and macro depth knob, which was the
|
||||
literal `60` in two `setBounds` calls and again inside both list tops.
|
||||
- L4. Named `toggleWide` for the Bipolar toggle width, which was the literal `60`
|
||||
in its `setBounds` and again in the `addX` offset that had to stay in step
|
||||
with it.
|
||||
- L5. Named `headerCentreY` for the header row centre line, which was
|
||||
`titleHeight + 30` in two places with the `30` unexplained.
|
||||
|
||||
The first attempt at L5 derived the centre from `headerHeight`, which is the
|
||||
36 px toggle, and produced 40 instead of 52. That would have shifted the whole
|
||||
matrix and macro header row by 12 px. It is derived from `depthKnobHeight` now,
|
||||
and a separate check compiles the namespace and asserts all fourteen new
|
||||
constants equal the literals they replaced.
|
||||
|
||||
Two layout reports were left in place rather than acted on. The top bar still
|
||||
positions its controls with literals (`presetCombo` at 200, 16, 220, 24;
|
||||
`masterKnob` at 906, 0, 64, 60; the tab pitch of 92, and so on), because naming
|
||||
those means deciding what the top bar's own grid is, which is a design choice
|
||||
rather than a rename. The `layout::labelHeight` constant was deleted: it was
|
||||
declared and never read.
|
||||
|
||||
---
|
||||
|
||||
## Deferred items needing a design decision
|
||||
|
||||
None of these were applied. Each changes behaviour, layout or sound, and each
|
||||
needs the user's call.
|
||||
|
||||
- D-1. Filter Mix does nothing in serial and split routing. `FilterBank` reads
|
||||
`p.mix` only in the parallel branch. Either define a crossfade for the other
|
||||
two routes or disable the knob in them. Real DSP work.
|
||||
- D-2. Filter Slope does nothing for Comb, Formant and Screamer, and on
|
||||
Ladder BP the 6 dB and 12 dB settings produce the same two-stage filter.
|
||||
Making the label honest needs DSP work; the tooltip now at least names the
|
||||
models it affects.
|
||||
- D-3. Filter Drive does nothing for Formant. `Filter::formant` is called
|
||||
without the drive argument.
|
||||
- D-4. The Modulation and Macro depth knobs and the Bipolar toggle only affect
|
||||
the next Add or Assign. They look like live controls for an existing
|
||||
connection. Relabel them as defaults, or make them edit the selected row.
|
||||
- D-5. The first FX slot's down arrow moves an effect earlier in the chain while
|
||||
pointing down. In the two-column grid the reading order wraps right to left
|
||||
between rows, so slot 2 sits to the right of slot 3. Number the slots, or
|
||||
relabel the arrows for a two-column grid.
|
||||
- D-6. The Filter tab leaves about 370 px of empty space below three 300 px
|
||||
panels. Nothing breaks, but the tab looks unfinished.
|
||||
- D-7. The OSC tab puts Sub and Noise in a second row beneath both oscillators.
|
||||
The reading order is fine; the geometry suggests Sub belongs to Osc A and
|
||||
Noise to Osc B without saying so.
|
||||
- D-8. Master and the oscillator, sub and noise Level knobs show a percentage
|
||||
for a linear gain. dB is the engineering unit. Changing it changes what every
|
||||
readout says, so it was left as percent.
|
||||
- D-9. Envelope Curve shows a percentage of a shape exponent that runs 0.3 to
|
||||
3.0. "Amount" or a named curve would be better than a percentage.
|
||||
- D-10. No control marks itself as changed from its default. Nothing reads
|
||||
`getDefaultValue()`.
|
||||
- D-11. Step and Freehand LFO shapes are drag-editable, but nothing says so: no
|
||||
tooltip on an editable graph, no cursor change, no hover state, no undo, and a
|
||||
preset load silently discards the drawn shape. `LFODisplay` is not a
|
||||
`SettableTooltipClient` today.
|
||||
- D-12. Plain Tab switches section, which means JUCE's focus traversal never
|
||||
runs and a keyboard-only user cannot reach any control except a combo box or a
|
||||
text editor. This is a convention choice: keep Tab for sections and move it to
|
||||
Ctrl+Tab, or keep Tab for controls and use function keys for sections.
|
||||
- D-13. `ToggleButton` derives from `juce::Component`, so it has no accessible
|
||||
role, name or state, and cannot be activated from the keyboard. Deriving from
|
||||
`juce::Button` would fix all of that at once but changes the class contract.
|
||||
- D-14. The waveform, filter, envelope and LFO graphs have no text or numeric
|
||||
equivalent, so a screen reader announces nothing for any of them. Each needs a
|
||||
description string.
|
||||
- D-15. Knobs have no focus outline. `hasKeyboardFocus` is read nowhere.
|
||||
- D-16. No group is marked, so a group that the selected shape ignores keeps its
|
||||
old values.
|
||||
|
||||
---
|
||||
|
||||
## Verified as functioning, with evidence
|
||||
|
||||
The following were suspected dead and are not. Recorded so the check is not
|
||||
repeated.
|
||||
|
||||
- Modulation depth and polarity reach `SynthVoice` and `Engine`, and the bipolar
|
||||
flag changes the modulation math.
|
||||
- Macro depth reaches both the global and per-voice modulation sums.
|
||||
- Remove Last removes the newest matrix row, matching its label, with no hidden
|
||||
ordering rule.
|
||||
- The master readout and the master knob drive the same parameter the output
|
||||
stage uses.
|
||||
- The filter type and LFO shape combo indices agree between the combo, the
|
||||
stored value, the DSP and the display, for all 7 and all 7 values.
|
||||
- The UI scale combo's five items map exactly onto the five-entry scale table.
|
||||
- All six On toggles gate their DSP. All eight warps, all four sub and noise
|
||||
controls, all four envelopes, all four LFOs, and the matrix and macro editors
|
||||
are live.
|
||||
- RAVE's tooltip matched its implementation exactly.
|
||||
- No knob can write outside its parameter range, and the Unison readout and the
|
||||
DSP round identically.
|
||||
|
||||
---
|
||||
|
||||
## Janitor cleanups made beyond UI text
|
||||
|
||||
Kept separate from the fixes above.
|
||||
|
||||
- J-1. Deleted the now-dead formatter `fmtDepth`, which the modulation and macro
|
||||
depth knobs were the only users of.
|
||||
- J-2. Deleted `layout::labelHeight`, which was declared and never read. Toggle
|
||||
and readout label sizes are hardcoded, so the constant described nothing.
|
||||
- J-3. Replaced the duplicated per-effect label table with the single
|
||||
`kFxParamDisplay` table, which removes the latent stale-tooltip bug rather than
|
||||
only fixing its symptoms.
|
||||
- J-4. `Source/GUI/Slider.h` and `Slider.cpp` define a horizontal slider that no
|
||||
code constructs. Reported only: deleting it means editing `CMakeLists.txt` and
|
||||
the GUI module's owned-file list, which is wider than this change. Recommend
|
||||
it as a follow-up.
|
||||
- J-5. `MacroControls::removeAssignment` is defined and never called. The Macro
|
||||
tab has no control that would call it, so a single macro assignment cannot be
|
||||
deleted. Reported only: adding the control is a new feature.
|
||||
|
||||
---
|
||||
|
||||
## What could not be verified
|
||||
|
||||
There is no headless way to check a visual change in this repository. The
|
||||
harness drives `SerumAltAudioProcessor` and never constructs the editor, so it
|
||||
proves the code compiles and the audio path still renders every preset, and it
|
||||
proves nothing about the pixels. The knob label, the toggle hover state, the
|
||||
disabled FX arrows and the popup clamping were reasoned from the JUCE 7.0.12
|
||||
sources in `third_party/JUCE` and checked against them line by line, but they
|
||||
have not been seen on screen. Do not treat a passing harness run as visual
|
||||
proof.
|
||||
|
||||
One consequence worth stating plainly: the new knob look-and-feel replaces
|
||||
`LookAndFeel_V4::drawRotarySlider` for knobs only. Every other control still uses
|
||||
the shared default look-and-feel, exactly as before.
|
||||
|
||||
---
|
||||
|
||||
## Verification
|
||||
|
||||
- `BUILD_DIR=/tmp/sa-verify ./build_harness.sh --run` reaches `100% tests passed`
|
||||
with zero first-party warnings.
|
||||
- The parameter surface is unchanged, checked at runtime rather than by reading
|
||||
the source. A temporary build printed every parameter of the live processor as
|
||||
`id | name | default`. It reported 155 parameters (the 96 declared in
|
||||
`createParameterLayout` plus the 59 generated entries), and the sorted list had
|
||||
fingerprint `62b4556078a261a5b1aaa8ba34081f44` both before and after the UI
|
||||
edits. No ID, name, range or default moved. The only parameter interaction the
|
||||
fix added is a read of `getDefaultValue()` and `convertFrom0to1()`.
|
||||
- Nothing under `Source/Params.h`, `Source/Params.cpp` or
|
||||
`createParameterLayout` in `Source/PluginProcessor.cpp` was edited.
|
||||
- `third_party/JUCE` is untouched. The untracked `third_party/JUCE/DemoRunner`
|
||||
and `third_party/JUCE/Projucer` files are upstream binaries dated 2024-04-15,
|
||||
not build products of this work.
|
||||
- No checked-in `build_*` directory was written to. Every build used a directory
|
||||
under `/tmp`.
|
||||
- The pre-existing uncommitted work in the tree was preserved.
|
||||
Reference in new issue
Block a user