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:
106
.sdd/changes/mix-calibration/spec.md
Normal file
106
.sdd/changes/mix-calibration/spec.md
Normal file
@@ -0,0 +1,106 @@
|
||||
# mix-calibration Specification
|
||||
|
||||
## Purpose
|
||||
|
||||
Post-processing calibrator that applies role-aware volume, EQ, stereo width, sends, and mastering chain to a `SongDefinition` before `.rpp` generation.
|
||||
|
||||
## Requirements
|
||||
|
||||
### Requirement: Calibrator Post-Processing
|
||||
|
||||
The system MUST provide a `Calibrator.apply(song: SongDefinition) -> SongDefinition` method that mutates and returns the song with calibrated mix settings. Calibration MUST run as a distinct step between track construction and `RPPBuilder.build()`.
|
||||
|
||||
#### Scenario: Happy path — full calibration
|
||||
|
||||
- GIVEN a complete `SongDefinition` with 7 tracks (Drumloop, Perc, 808 Bass, Chords, Lead, Clap, Pad) and 2 return tracks
|
||||
- WHEN `Calibrator.apply(song)` is called
|
||||
- THEN `song.tracks[].volume` matches role-based LUFS targets
|
||||
- AND each non-return track has a ReaEQ plugin prepended to its `plugins` list
|
||||
- AND `song.tracks[].pan` follows stereo-width rules
|
||||
- AND `song.tracks[].send_level` contains calibrated reverb/delay values
|
||||
- AND `song.master_plugins` contains Ozone 12 Equalizer, Dynamics, Maximizer
|
||||
|
||||
### Requirement: Role-Based Volumes
|
||||
|
||||
The system SHALL set track volumes from a preset table keyed by track role (name → role mapping). Volumes MUST be in the REAPER-compatible 0.0–1.0 range.
|
||||
|
||||
| Role | Volume | Target |
|
||||
|------|--------|--------|
|
||||
| drumloop | 0.85 | kick prominence |
|
||||
| bass | 0.72 | sub-presence |
|
||||
| chords | 0.78 | harmonic support |
|
||||
| lead | 0.78 | melody clarity |
|
||||
| clap | 0.75 | transient punch |
|
||||
| pad | 0.68 | ambient depth |
|
||||
| perc | 0.72 | groove feel |
|
||||
|
||||
#### Scenario: Unknown track role
|
||||
|
||||
- GIVEN a track with name not matching any preset role
|
||||
- WHEN calibrated
|
||||
- THEN the track's volume and pan remain unchanged (preserved as-is)
|
||||
|
||||
### Requirement: HPF/LPF EQ per Role
|
||||
|
||||
The system SHALL prepend a ReaEQ `PluginDef` to each non-return track's `plugins` list with appropriate HPF or LPF parameters. Bass tracks (808 Bass) SHALL receive LPF. All other tracks SHALL receive HPF.
|
||||
|
||||
#### Scenario: HPF on lead/chords/pad tracks
|
||||
|
||||
- GIVEN a track named "Chords", "Lead", "Pad", "Clap", "Perc", or "Drumloop"
|
||||
- WHEN calibrated
|
||||
- THEN a ReaEQ plugin is inserted at `plugins[0]` with param `0=1` (band enabled), `1=1` (HPF type), `2=200.0` (frequency for melodic) or `2=60.0` (drums)
|
||||
|
||||
#### Scenario: LPF on bass track
|
||||
|
||||
- GIVEN a track named "808 Bass"
|
||||
- WHEN calibrated
|
||||
- THEN a ReaEQ plugin is inserted at `plugins[0]` with param `0=1`, `1=0` (LPF type), `2=300.0` (frequency)
|
||||
|
||||
#### Scenario: Return tracks excluded
|
||||
|
||||
- GIVEN tracks named "Reverb" or "Delay"
|
||||
- WHEN calibrated
|
||||
- THEN no ReaEQ plugin is added (return tracks are skipped)
|
||||
|
||||
### Requirement: Stereo Width per Role
|
||||
|
||||
The system SHALL set track pan values to role-specific defaults.
|
||||
|
||||
| Role | Pan | Rationale |
|
||||
|------|-----|-----------|
|
||||
| drumloop | 0.0 | mono center |
|
||||
| bass | 0.0 | mono sub |
|
||||
| chords | +0.5 | wide right |
|
||||
| lead | +0.3 | right-leaning |
|
||||
| clap | -0.15 | off-center left |
|
||||
| pad | -0.5 | wide left |
|
||||
| perc | +0.12 | slight right |
|
||||
|
||||
### Requirement: Send Calibration
|
||||
|
||||
The system SHALL set `send_level` dict entries for reverb (index=return_track_count) and delay (index=return_track_count+1) on each non-return track.
|
||||
|
||||
| Role | Reverb | Delay |
|
||||
|------|--------|-------|
|
||||
| drumloop | 0.10 | 0.00 |
|
||||
| bass | 0.05 | 0.02 |
|
||||
| chords | 0.30 | 0.10 |
|
||||
| lead | 0.25 | 0.15 |
|
||||
| clap | 0.10 | 0.00 |
|
||||
| pad | 0.40 | 0.20 |
|
||||
| perc | 0.10 | 0.00 |
|
||||
|
||||
### Requirement: Master Chain Upgrade
|
||||
|
||||
The system SHALL replace `master_plugins` with `["Ozone_12_Equalizer","Ozone_12_Dynamics","Ozone_12_Maximizer"]`. If registry lookup for any Ozone plugin fails, the system MUST fall back to `["Pro-Q_3","Pro-C_2","Pro-L_2"]`.
|
||||
|
||||
### Requirement: Calibration Toggle
|
||||
|
||||
The system SHALL support a `--no-calibrate` CLI flag. When passed, `Calibrator.apply()` MUST NOT be called. When omitted (default), calibration MUST run. `SongMeta` MAY include an optional `calibrate: bool` field defaulting to `True`.
|
||||
|
||||
#### Scenario: --no-calibrate preserves existing behavior
|
||||
|
||||
- GIVEN `compose.py --no-calibrate -o out.rpp`
|
||||
- WHEN the song is built
|
||||
- THEN `Calibrator.apply()` is never invoked
|
||||
- AND the generated `.rpp` matches the pre-calibration baseline
|
||||
Reference in New Issue
Block a user