Files
renato97 014e636889 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.
2026-05-03 23:54:29 -03:00

107 lines
4.1 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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.01.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