# DeepPluck V0.5.0 Second Oscillator Engine — Implementation Report

## 1. Executive Summary

DeepPluck V0.5.0 adds one focused second PolyBLEP saw per voice. The new source has a click-free bypass, level, octave, semitone, and fine-tune controls and is summed before the existing per-voice filter. It deliberately shares the existing Filter Envelope, Amp Envelope, velocity, lifecycle, and sixteen-voice stealing policy. A later V0.5.0 acceptance follow-up adds bounded, smoothed resonance-dependent gain compensation at the output of that filter so high resonance does not cause an excessive perceived-level loss.

The automatable Definition of Done is complete. A fresh Visual Studio 2026 x64 configuration, Debug build, Release build, all 13 Debug CTest suites, all 13 Release CTest suites, artifact checks, metadata checks, and both process-level Standalone smoke tests passed. No compiler warning was emitted by either final build. On 2026-08-30 the user manually confirmed the accepted V0.5-plus-resonance build with: `0.5.1 ist ok und läuft`. This closes the human listening/resonance acceptance gate without inventing test details that were not supplied. Full Cubase validation remains separately pending.

## 2. Milestone Scope

Implemented:

- one second anti-aliased PolyBLEP saw in every preallocated voice;
- independent On/Off, Level, Octave, Semitone, and Fine Tune parameters;
- deterministic start phase and continuous bypassed phase;
- source summing before the existing filter;
- shared Filter and Amp Envelopes;
- realtime-safe live smoothing;
- legacy-state migration through V0.4.0;
- four complete 29-value factory presets;
- compact development-editor controls;
- bounded resonance-dependent filter-output compensation;
- Debug/Release automated regression coverage, artifacts, and smoke tests.

Not implemented: waveform selection, FM, oscillator sync, unison, modulation matrix, effects, randomization, global phase modes, per-oscillator envelopes, or final GUI redesign.

## 3. Normative Sound-Manifest Decisions

`Docs/Sound/DeepPluck_Sound_Manifest_v1.0.md` was read before implementation and treated as normative. The design remains a focused emotional Deep House pluck rather than a general synthesizer: one fixed companion saw, conservative preset levels, no extra oscillator modes, and no hidden dynamics processing. Existing twenty-four preset values were retained. Because no real listening endpoint was available, the specified five new values were not changed speculatively.

## 4. Verified V0.4.0 Baseline and Starting Commit

- Branch: `master`
- Starting commit: `8fcc7aba31bace3c556aef3e982436d6d0be09ac`
- V0.4.0 was already manually accepted by the user: Transient and Noise worked, behavior matched expectations, and no conspicuous errors were found.
- Before V0.5 source changes, the existing Debug and Release matrices each passed 11/11 CTest suites.
- Verified baseline contracts: 16 preallocated voices, one sound, stable identity, no-input/stereo-output instrument, existing PolyBLEP/filter/envelope/transient/noise architecture, and project-local artifacts only.

## 5. Repository/User-File Protection

The following start-side untracked user files remained unmodified and untracked and were not staged:

- `CubaseTest/`
- `Docs/DeepPluck_V0.2.0a_Master_Prompt_Rev1.txt`
- `Docs/DeepPluck_V0.2.0b_MasterPrompt_Rev1.txt`
- `Docs/DeepPluck_V0.5.0_Second_Oscillator_MasterPrompt_Rev1.txt`

No file below `JUCE/` was changed. `build/` and `Artifacts/` remained ignored. No cleanup command touched user data, and nothing was copied to a system plugin folder.

## 6. Plugin Identity and Version

The numeric version is 0.5.0. These persistent identities are unchanged:

- company/vendor: `ToneTrax`
- manufacturer code: `Tntx`
- plugin code: `DpV1`
- bundle identifier: `de.tonetrax.deeppluck`
- plugin/product name: `DeepPluck`
- component CID: `ABCDEF019182FAEB546E747844705631`
- controller CID: `ABCDEF011234ABCD546E747844705631`
- formats: VST3 and Standalone
- contract: instrument, MIDI input, no MIDI output, no audio input, stereo output

The generated Release `moduleinfo.json` reports DeepPluck 0.5.0, ToneTrax, Instrument/Synth, and the unchanged class identities.

## 7. Final Signal Flow

```text
Primary PolyBLEP Saw ------------------------------------+
Oscillator 2 PolyBLEP Saw -> pitch/level/bypass ---------+
Transient wavelet -> one-shot/level/tone/bypass ---------+ source sum
Decorrelated Noise -> DC block/tone/one-shot/level -------+
    -> dry branch ----------------------------------------+
    -> Drive -> 24 dB Low-Pass -> Filter Envelope
             -> bounded resonance compensation -----------+ filter crossfade
    -> shared Amp Envelope -> Velocity -> 0.08 Voice Gain
16-voice stereo sum -> 20 ms Output Gain -> stereo output
```

There is no hidden cross-source normalization, primary-oscillator attenuation, limiter, or clipper. The only automatic gain term is the documented filter-local resonance compensation `1 + 1.5 * resonance^2`, bounded to 1.0..2.5 (0..+7.96 dB) and smoothed over 20 ms.

## 8. Oscillator-2 DSP Design

Every `DeepPluckVoice` owns a second `DeepPluckOscillator`. It reuses the production PolyBLEP rising-saw core and therefore remains table-free, allocation-free, and non-oversampled. Oscillator 1 code and gain remain unchanged. Oscillator 2 always advances while a voice is active, even when its contribution is bypassed.

## 9. Pitch Formula and Parameter Ranges

```text
offsetSemitones = 12 * octave + semitone + fineTuneCents / 100
frequency2 = primaryNoteFrequency * 2^(offsetSemitones / 12)
```

Octave and Semitone are integer parameters. Snapshot reads round and clamp them. Fine Tune and Level are bounded continuous parameters. The existing oscillator clamps the applied frequency to its sample-rate-safe internal range.

## 10. Phase and Determinism Contract

- real Note-On: primary phase 0.0, Oscillator 2 phase 0.25;
- parameter change: no phase reset;
- bypass: internal phase continues;
- re-enable: reveals the advanced phase through the 5 ms crossfade;
- hard stop: Oscillator 2 returns to known phase 0.25;
- stolen/new note: starts at phase 0.25 with current target pitch;
- deterministic source and noise sequences remain independent of Oscillator-2 parameter values.

## 11. Smoothing and Live Automation

- `osc2Enabled`: 5 ms linear crossfade;
- `osc2Level`: dB converted to gain per rendered segment, then 20 ms linear-gain ramp;
- Octave/Semitone/Fine Tune and Master Tune contribution: 20 ms multiplicative frequency ramp;
- Note-On: current and target values synchronize immediately;
- repeated target updates continue from current smoother state and never reset oscillator phase.

## 12. Realtime-Safety Review

The five raw APVTS pointers are bound in `DeepPluckParameterCache` outside the audio hot path. Each atomic is read, validated, bounded, and copied once per block into the existing trivially-copyable snapshot. Voices read only that snapshot. The new audio path performs no allocation, collection growth, locking, file/network access, logging, GUI work, APVTS string lookup, ValueTree operation, or entropy acquisition. Transcendental pitch/gain target calculations occur per rendered segment, not per sample; the sample loop contains bounded smoothers, oscillators, mixing, and existing filter/envelope work. Resonance compensation uses a preallocated JUCE linear smoother and one multiply per filter sample.

## 13. Filter/Amp/Transient/Noise Integration

Oscillator 2 is summed with Oscillator 1, Transient, and Noise before the existing filter dry/wet split. The resonance compensation is applied after the ladder stages, so it cannot alter resonance feedback or pre-filter drive behavior. It depends only on the bounded resonance value, has no signal-level detector, and therefore cannot act as a limiter or conceal clipping/instability. Tests cover every on/off combination of Oscillator 2, Transient, Noise, and Filter; common filter-envelope movement; common Amp-Envelope shaping; velocity; exact Oscillator-2-off identity; and complete lifecycle silence. Transient/Noise start logic, one-shot ownership, and deterministic seeds were not changed.

## 14. Voice-Stealing and MIDI Timing

Polyphony remains exactly 16. No allocator or stealing priority changed. The 17th note still prefers the quietest released voice, the two-millisecond retained-sample fade remains in place, and a stolen note initializes Oscillator 2 at phase 0.25. Automated coverage includes sample-offset Note-On and existing sample-offset Note-Off, same-note retrigger, chords, release, hard All Notes Off, block-size variation, and repeated stealing/lifecycle stress.

## 15. Gain Staging and Headroom Measurements

Measurements use deterministic in-memory stereo renders. Unless identified as a single-voice A/B case, the headroom sequence starts sixteen full-velocity notes MIDI 48..63 at sample zero in a 512-sample block and measures the initial block plus following blocks. The multi-rate fresh-default stress sets Amp Attack/Decay to 1 ms and Sustain to 1 to expose the sustained 16-voice sum. Debug and Release values matched.

| Measurement | Peak |
|---|---:|
| Oscillator 2 level-0 difference signal, one voice, 48 kHz/1024 | 0.0783639 |
| both oscillators, Oscillator 2 at 0 dB, one voice, 48 kHz/1024 | 0.122351 |
| both oscillators + Transient + Noise, one voice, 48 kHz/512 | 0.0956953 |
| 16-voice steal render, 48 kHz/64 | 0.309855 |
| fresh-default stress, 44.1 kHz/512 | 0.499816 |
| fresh-default stress, 48 kHz/512 | 0.499483 |
| fresh-default stress, 96 kHz/512 | 0.499510 |
| Deep Pluck preset, 48 kHz/512 | 0.268460 |
| Soft Pluck preset, 48 kHz/512 | 0.159664 |
| Tight Pluck preset, 48 kHz/512 | 0.472162 |
| Long Pluck preset, 48 kHz/512 | 0.174707 |
| maximum V0.5 oscillator/layer/filter stress, 96 kHz/127 | 0.870790 |
| minimum compensated high-resonance passband RMS ratio | 0.542022 (-5.31966 dB) |
| isolated maximum-resonance/maximum-drive filter stress | 3.08514 |

The resonance matrix covers 44.1, 48, and 96 kHz; cutoffs 100, 500, 2000, and 10000 Hz; and pre-filter drive 0, 9, and 18 dB. Its high-resonance probe never falls below 0.542022 of the matching zero-resonance RMS value, meeting the automated no-more-than-6 dB loss criterion. The isolated filter peak is intentionally not clipped or normalized and remains visible to the stress test. The complete sixteen-voice maximum stress remains below the stricter automated 0.95 headroom threshold. No NaN or infinity occurred.

The PolyBLEP/non-harmonic-energy ratios versus a naive saw were 0.0232196 at coherent bin 79 and 0.0481054 at bin 173 for 44.1, 48, and 96 kHz, well below the test limit of 0.80.

## 16. Parameter Table with All 29 IDs

| Position | ID | Type/range | Fresh default | Smoothing |
|---:|---|---|---:|---|
| 1 | `outputGain` | float -60..+6 dB | -3 dB | 20 ms |
| 2 | `masterTune` | float 420..460 Hz | 440 Hz | 20 ms pitch |
| 3 | `ampAttack` | float 0.001..5 s | 0.003 s | live envelope |
| 4 | `ampDecay` | float 0.001..5 s | 0.320 s | live envelope |
| 5 | `ampSustain` | float 0..1 | 0 | live envelope |
| 6 | `ampRelease` | float 0.001..10 s | 0.180 s | live envelope |
| 7 | `filterEnabled` | bool | on | 10 ms |
| 8 | `filterCutoff` | float 20..20000 Hz | 1800 Hz | 20 ms log |
| 9 | `filterResonance` | float 0..1 | 0.18 | 20 ms |
| 10 | `filterDrive` | float 0..18 dB | 3 dB | 20 ms |
| 11 | `filterKeyTracking` | float 0..1 | 0.35 | 20 ms |
| 12 | `filterEnvAmount` | float -5..+5 oct | +2.50 oct | 20 ms |
| 13 | `filterAttack` | float 0.001..5 s | 0.002 s | live envelope |
| 14 | `filterDecay` | float 0.001..5 s | 0.280 s | live envelope |
| 15 | `filterSustain` | float 0..1 | 0 | live envelope |
| 16 | `filterRelease` | float 0.001..10 s | 0.180 s | live envelope |
| 17 | `transientEnabled` | bool | on | 5 ms |
| 18 | `transientLevel` | float -60..0 dB | -18 dB | 20 ms |
| 19 | `transientDecay` | float 0.001..0.100 s | 0.012 s | live one-shot |
| 20 | `transientTone` | float 0..1 | 0.55 | 10 ms |
| 21 | `noiseEnabled` | bool | on | 5 ms |
| 22 | `noiseLevel` | float -60..0 dB | -27 dB | 20 ms |
| 23 | `noiseDecay` | float 0.005..1.500 s | 0.120 s | live one-shot |
| 24 | `noiseTone` | float 0..1 | 0.35 | 20 ms coefficient |
| 25 | `osc2Enabled` | bool | on | 5 ms |
| 26 | `osc2Level` | float -60..0 dB, 0.1 | -15 dB | 20 ms gain |
| 27 | `osc2Octave` | int -1..+1 | 0 | 20 ms pitch |
| 28 | `osc2Semitone` | int -12..+12 | 0 | 20 ms pitch |
| 29 | `osc2FineTune` | float -50..+50 ct, 0.1 | -7 ct | 20 ms pitch |

Positions 1..24, their IDs, ranges, defaults, and semantics are unchanged. New IDs are appended only at positions 25..29.

## 17. State Migration Matrix V0.1.0–V0.5.0

| Incoming state | Existing rules | Oscillator-2 result |
|---|---|---|
| V0.1 | V0.2/V0.3/V0.4 legacy behavior retained | disabled; numeric V0.5 defaults |
| V0.2 | V0.3/V0.4 legacy behavior retained | disabled; numeric V0.5 defaults |
| V0.3 | V0.4 legacy behavior retained | disabled; numeric V0.5 defaults |
| full/partial V0.4 with no V0.5 ID | all supplied V0.4 values retained | disabled; numeric V0.5 defaults |
| partial V0.5 with any new ID | supplied new values retained | missing new values receive fresh defaults, including Enabled on when missing |
| full V0.5 | all 29 recognized values overlaid | deterministic 29-value roundtrip |
| invalid root/data | rejected/validated as before | current state remains safe |

This prevents an old session from unexpectedly hearing Oscillator 2 while allowing a fresh V0.5 instance to use it musically.

## 18. Factory Presets and Musical Rationale

Existing twenty-four values and preset order are unchanged. Only the specified new values were appended:

| Preset | Enabled | Level | Octave | Semitone | Fine Tune |
|---|---:|---:|---:|---:|---:|
| Deep Pluck | on | -15 dB | 0 | 0 | -7 ct |
| Soft Pluck | on | -21 dB | -1 | 0 | +5 ct |
| Tight Pluck | on | -21 dB | +1 | 0 | 0 ct |
| Long Pluck | on | -18 dB | 0 | 0 | -11 ct |

Deep Pluck exactly equals all fresh defaults. The other values keep the companion layer deliberately subordinate: low and quiet for Soft, high and quiet for Tight, and modest slow beating for Long. No listening-based claim is made until manual verification occurs.

## 19. GUI Changes

The existing fixed 1180 × 930 development editor now shows `Development Build V0.5.0` and a compact `OSCILLATOR 2` row with On/Off, Level, Octave, Semitone, and Fine Tune. The row uses the existing visual language and disabled controls dim to 45%. The other sections were compacted within the same window; no final redesign was introduced. The automated parameter suite constructs the production editor at 1180 × 930 and verifies that construction changes none of the 29 parameter values.

## 20. Automated Test Coverage

The CTest target contains 13 suites:

1. `parameters`
2. `oscillator`
3. `envelope`
4. `filter`
5. `filter_envelope`
6. `transient_noise`
7. `transient_noise_integration`
8. `oscillator2`
9. `oscillator2_integration`
10. `synthesiser`
11. `sample_accuracy`
12. `matrix`
13. `smoothing_stability`

The suites cover parameter order/type/ranges/defaults, state/preset behavior, production-core pitch and PolyBLEP metrics, phase, multi-rate safety, smoothing durations, live pitch continuity, exact bypass identity, shared filter/envelopes, velocity, source combinations, deterministic block partitioning, lifecycle, MIDI offsets, hard stop, stealing, and headroom. Filter coverage additionally verifies unity compensation at zero resonance, the exact 2.5 upper bound, the 20 ms transition, the cutoff/sample-rate/drive RMS matrix, finite output, and an uncompromised peak-stress observation. Existing tolerances were not weakened.

## 21. Debug Build and CTest Result

Confirmed environment: Windows 11 x64, Visual Studio 2026, MSVC 19.51.36256.0, Windows SDK 10.0.26100.0, CMake 4.4.3, JUCE 9.0.1, C++20, generator `Visual Studio 18 2026`, platform x64.

Final acceptance commands included:

```powershell
cmake --fresh -S . -B build -G "Visual Studio 18 2026" -A x64
cmake --build build --config Debug --parallel
ctest --test-dir build -C Debug --output-on-failure
```

Result: build successful, 13/13 tests passed, 0 failed, no compiler warning emitted. A subsequent clean Debug rebuild also compiled every project source and JUCE translation unit successfully before the final 13/13 run.

## 22. Release Build and CTest Result

```powershell
cmake --build build --config Release --parallel
ctest --test-dir build -C Release --output-on-failure
```

Result: build successful, 13/13 tests passed, 0 failed, no compiler warning emitted. Debug and Release numerical metrics were identical at the recorded precision.

## 23. Produced Local Artifacts

All UTC times are from 2026-08-30. Build outputs:

| Configuration | Artifact | Size | Last write UTC |
|---|---|---:|---|
| Debug | `build/DeepPluck_artefacts/Debug/VST3/DeepPluck.vst3` (binary in `Contents/x86_64-win`) | 24,794,624 B | 12:05:03 |
| Debug | `build/DeepPluck_artefacts/Debug/Standalone/DeepPluck.exe` | 27,181,568 B | 12:05:03 |
| Release | `build/DeepPluck_artefacts/Release/VST3/DeepPluck.vst3` (binary in `Contents/x86_64-win`) | 7,793,664 B | 12:07:13 |
| Release | `build/DeepPluck_artefacts/Release/Standalone/DeepPluck.exe` | 8,975,360 B | 12:07:13 |

Project-local copies:

- `Artifacts/Debug/DeepPluck.vst3`
- `Artifacts/Debug/DeepPluck.exe`
- `Artifacts/Release/DeepPluck.vst3`
- `Artifacts/Release/DeepPluck.exe`

Each copied binary had the same SHA-256 as its corresponding build output. `COPY_PLUGIN_AFTER_BUILD` is `FALSE`. `C:\Program Files\Common Files\VST3\DeepPluck.vst3` was absent after verification, confirming that no system installation occurred.

## 24. Standalone Smoke Tests

Both project-local executables were actually started after the builds. Debug and Release each remained alive and responsive for three seconds, created a native window titled `DeepPluck`, accepted a normal close request, exited within five seconds, and left zero `DeepPluck` processes behind. No `%APPDATA%\DeepPluck.settings` file existed before or after the smoke run, so no user settings file required cleanup.

This is a process/window smoke test, not an audio listening claim. Editor construction, V0.5 size, and state non-mutation are automated; visual polish, hands-on control interaction, and audio-device behavior remain part of manual verification.

## 25. Listening-Test Results

**MANUALLY ACCEPTED BY THE USER**

On 2026-08-30 the user stated: `0.5.1 ist ok und läuft`. In the conversation this was explicitly understood as confirmation of the V0.5 sound and the Resonance Loudness Compensation. The user did not provide device, sample-rate, buffer-size, note, chord, or loudness-meter details, so this report records the acceptance but does not invent a more granular listening protocol or measurements.

## 26. Cubase Validation Results

**MANUAL VERIFICATION REQUIRED - CUBASE VALIDATION**

External blocker: automatic system installation is prohibited, no authorized Cubase-visible VST3 placement was provided, and this agent cannot perform a human interactive Cubase/audio session. The untracked `CubaseTest/` user directory was intentionally not used or changed.

Remaining steps:

1. Manually copy the complete `Artifacts/Release/DeepPluck.vst3` bundle to a Cubase-visible VST3 folder and rescan.
2. Confirm one unchanged DeepPluck identity, correct vendor/classification, load/remove/reload, and no duplicate entry.
3. Open a V0.4 project: prior 24 automation lanes must stay mapped, Oscillator 2 must be off, and the known sound must remain unchanged.
4. Confirm all 29 parameters in order, save non-default new values, close/reopen, and verify state/preset recall.
5. Exercise slow/fast automation, discrete pitch jumps, Filter/Envelope/Transient/Noise combinations, realtime/offline bounce, 4/8/16/17-note behavior, several buffers/sample rates, and multiple instances.
6. Record Cubase version, binary configuration, audio device/settings, results, CPU behavior, and any reproducible defect; manually remove the test bundle afterward if desired.

## 27. Documentation Changes

- `README.md`: V0.5 behavior, 29 parameters, migration, resonance compensation, tests, editor, build paths, and manual checklist.
- `ARCHITECTURE.md`: ownership, source flow, pitch/phase/smoothing, filter-local compensation, parameter/preset/state contracts, realtime policy, tests, and deferred scope.
- `AGENTS.md`: confirmed reference environment wording updated to V0.5.0.
- `CMakeLists.txt`: project/plugin version and description plus two new CTest suites.
- this report: complete implementation and verification record.

Historical V0.4 reports and prompts were not rewritten.

## 28. Known Limitations and Explicit Out-of-Scope Items

- PolyBLEP reduces aliasing but is not brick-wall band limiting.
- Oscillator 2 is intentionally one fixed saw without waveform choice, sync, FM, or a dedicated envelope.
- Host parameters are snapshotted once per block; MIDI event dispatch remains sample-accurate.
- No unison, modulation matrix, effects, randomization, final artwork, installer, or automatic updater exists.
- No host CPU profile, human listening acceptance, or Cubase validation is claimed in this report.

## 29. Definition-of-Done Status

Complete: repository protection, Sound Manifest compliance, identity/version, 16 voices, all 29 parameter contracts, DSP and routing, phase/determinism, smoothing, migration, presets, GUI integration, realtime review, bounded resonance compensation, automated cutoff/drive/peak verification, Debug/Release builds, 13/13 tests in each configuration, headroom metrics, local artifacts, no system install, metadata, technical Standalone smoke, focused V0.5 implementation commit, and documentation.

The user has completed the human V0.5 listening and Resonance Loudness Compensation acceptance. Complete Cubase scan/legacy/automation/bounce/stability validation is still pending because this environment has no authorized host-visible installation or human Cubase session. Therefore the precise status is: **V0.5 listening/resonance acceptance complete; Cubase validation pending**.

## 30. Git Commits and Final Repository Status

- Implementation/tests/current documentation: `87f6cc32ebc14f6dbcde20f1ff5a2560ccd4cacb` — `DeepPluck V0.5.0 Second Oscillator Engine`
- Verification report: the focused commit containing this report, message `Document DeepPluck V0.5.0 verification`; its hash is reported in the final handoff because a commit cannot embed its own content-derived hash.

The manually accepted resonance-compensation follow-up is finalized in a separate focused commit with message `fix: compensate filter resonance loudness`; its hash is reported in the subsequent V0.6.0 implementation record. It contains `README.md`, `ARCHITECTURE.md`, `Source/Synth/DeepPluckFilter.cpp`, `Source/Synth/DeepPluckFilter.h`, `Tests/TestMain.cpp`, and this report, and is not mixed into a V0.6.0 feature commit. No history was rewritten and nothing was pushed. The protected start-side untracked user entries listed in section 5 remain untouched; `build/` and `Artifacts/` remain ignored and unstaged.
