feat: professional reggaeton production engine — 7 SDD changes, 302 tests
- section-energy: track activity matrix + volume/velocity multipliers per section - smart-chords: ChordEngine with voice leading, inversions, 4 emotion modes - hook-melody: melody engine with hook/stabs/smooth styles, call-and-response - mix-calibration: Calibrator module (LUFS volumes, HPF/LPF, stereo, sends, master) - transitions-fx: FX track with risers/impacts/sweeps at section boundaries - sidechain: MIDI CC11 bass ducking on kick hits via DrumLoopAnalyzer - presets-pack: role-aware plugin presets (Serum/Decapitator/Omnisphere per role) Full SDD pipeline (propose→spec→design→tasks→apply→verify) for all 7 changes. 302/302 tests passing.
This commit is contained in:
87
.sdd/changes/mix-calibration/proposal.md
Normal file
87
.sdd/changes/mix-calibration/proposal.md
Normal file
@@ -0,0 +1,87 @@
|
||||
# Proposal: Automated Mix Calibration
|
||||
|
||||
## Intent
|
||||
|
||||
All track volumes, pans, and sends are hardcoded constants. No frequency balancing. Master chain uses Pro-Q_3/Pro-C_2/Pro-L_2 with DEFAULT presets. Result: flat, amateur sound with bass-drum masking and no stereo width.
|
||||
|
||||
Add a post-processing calibrator that sets role-based LUFS volumes, HPF/LPF EQ, stereo panning, calibrated sends, and a proper mastering chain.
|
||||
|
||||
## Scope
|
||||
|
||||
### In Scope
|
||||
- `src/calibrator/` module — calibrates a `SongDefinition` with role-aware mix settings
|
||||
- LUFS-targeted volumes per role (kick -8 → drumloop 0.85, bass -10 → 0.72, lead -12 → 0.78, etc.)
|
||||
- HPF/LPF via ReaEQ plugins prepended to each track (HPF on non-bass, LPF on bass)
|
||||
- Stereo width management: bass/kick mono, lead wide (±0.3), chords wider (±0.5), clap off-center
|
||||
- Calibrated send levels: lead 25% verb / 15% delay, chords 30% / 10%, pad 40% / 20%, drums 10% / 0%
|
||||
- Master chain swap: Pro-Q_3 → Ozone 12 Equalizer, Pro-C_2 → Ozone 12 Dynamics, Pro-L_2 → Ozone 12 Maximizer
|
||||
- `--no-calibrate` flag on compose.py to skip calibration
|
||||
|
||||
### Out of Scope
|
||||
- True LUFS measurement (requires REAPER rendering — Phase 2 via ReaScript)
|
||||
- ReaEQ parameter automation (parametric curves, dynamic EQ)
|
||||
- Reference-track matching
|
||||
- Multi-genre calibration profiles (reggaeton only for now)
|
||||
|
||||
## Capabilities
|
||||
|
||||
### New Capabilities
|
||||
- `mix-calibration`: Role-based volume/pan/send/EQ calibration applied as post-processing step on `SongDefinition`
|
||||
|
||||
### Modified Capabilities
|
||||
<!-- None — existing compose pipeline is unchanged; calibration is additive -->
|
||||
|
||||
None
|
||||
|
||||
## Approach
|
||||
|
||||
**Separate calibrator module** (`src/calibrator/`), NOT inline in compose.py. Rationale:
|
||||
- compose.py is 612 lines — adding 200+ calibration lines would bloat it
|
||||
- Calibration is a separate concern (mixing vs. composition)
|
||||
- Independently testable, skippable via `--no-calibrate`
|
||||
- Follows existing module pattern (selector/, builder/, validator/)
|
||||
|
||||
**Data flow**: `compose.main()` → `SongDefinition` → `Calibrator.apply(song)` → calibrated `SongDefinition` → `RPPBuilder.build()`
|
||||
|
||||
**HPF/LPF strategy**: Add ReaEQ plugin to each track's plugin list. Extend `_build_plugin()` to serialize `PluginDef.params` into VST parameter slots (currently ignored). ReaEQ uses 19 fixed param slots; we populate band 0 (type=1 HPF or type=0 LPF) with frequency values.
|
||||
|
||||
**Master chain**: Replace `master_plugins=["Pro-Q_3","Pro-C_2","Pro-L_2"]` with `["Ozone_12_Equalizer","Ozone_12_Dynamics","Ozone_12_Maximizer"]` using default presets already in registry.
|
||||
|
||||
## Affected Areas
|
||||
|
||||
| Area | Impact | Description |
|
||||
|------|--------|-------------|
|
||||
| `src/calibrator/__init__.py` | New | `Calibrator` class with `apply(song)` method |
|
||||
| `src/calibrator/presets.py` | New | Calibration presets (LUFS targets, HPF/LPF freqs, pans, sends) |
|
||||
| `src/reaper_builder/__init__.py` | Modified | `_build_plugin()` — serialize `PluginDef.params` to VST slots |
|
||||
| `scripts/compose.py` | Modified | Import Calibrator, call after track build, add `--no-calibrate` flag |
|
||||
| `tests/test_calibrator.py` | New | Unit tests for calibrator output |
|
||||
| `src/core/schema.py` | Modified | Add `calibrate: bool` flag to `SongMeta` (optional) |
|
||||
|
||||
## Risks
|
||||
|
||||
| Risk | Likelihood | Mitigation |
|
||||
|------|------------|------------|
|
||||
| ReaEQ param serialization breaks existing .rpp | Low | Feature-gated: only when `PluginDef.params` is non-empty; zero backcompat impact |
|
||||
| Ozone 12 plugins missing on some machines | Med | Fallback to Pro-Q_3/Pro-C_2/Pro-L_2 if Ozone registry lookup fails |
|
||||
| Too-aggressive HPF cuts thin out full sections | Low | Conservative cutoffs: HPF 60Hz for drums, 200Hz for lead/chords; tunable via presets |
|
||||
|
||||
## Rollback Plan
|
||||
|
||||
1. Revert compose.py: remove `--no-calibrate` flag, remove calibrator import
|
||||
2. Revert builder: remove params serialization in `_build_plugin()`
|
||||
3. Delete `src/calibrator/`
|
||||
4. Restore original `VOLUME_LEVELS`, `SEND_LEVELS`, `MASTER_VOLUME`, `master_plugins` constants
|
||||
|
||||
## Dependencies
|
||||
|
||||
- `PLUGIN_REGISTRY` entries for `ReaEQ`, `Ozone_12_Equalizer`, `Ozone_12_Dynamics`, `Ozone_12_Maximizer` (all exist)
|
||||
- No new Python dependencies required
|
||||
|
||||
## Success Criteria
|
||||
|
||||
- [ ] `Calibrator.apply(song)` returns a `SongDefinition` with volume/pan/send values matching role-based presets
|
||||
- [ ] Each non-return track has at least one ReaEQ plugin with HPF or LPF params set
|
||||
- [ ] `--no-calibrate` flag preserves existing behavior (no calibration applied)
|
||||
- [ ] Generated .rpp with calibration produces audibly cleaner mix (verified by ear)
|
||||
- [ ] All 110 existing tests still pass (calibration is additive, not breaking)
|
||||
Reference in New Issue
Block a user