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:
renato97
2026-05-03 23:54:29 -03:00
parent 48bc271afc
commit 014e636889
51 changed files with 11394 additions and 113 deletions

View File

@@ -33,6 +33,152 @@ class TestSectionDef:
assert section.vol_mult == 0.6
class TestBuildSectionStructureMultipliers:
"""Verify build_section_structure() populates velocity_mult and vol_mult."""
@staticmethod
def _get_sections():
from scripts.compose import build_section_structure
sections, _offsets = build_section_structure()
return {s.name: s for s in sections}
def test_intro_has_low_multipliers(self):
sections = self._get_sections()
assert sections["intro"].velocity_mult == 0.6
assert sections["intro"].vol_mult == 0.70
def test_verse_has_mid_multipliers(self):
sections = self._get_sections()
assert sections["verse"].velocity_mult == 0.7
assert sections["verse"].vol_mult == 0.85
def test_pre_chorus_has_high_multipliers(self):
sections = self._get_sections()
assert sections["pre-chorus"].velocity_mult == 0.85
assert sections["pre-chorus"].vol_mult == 0.95
def test_chorus_has_full_multipliers(self):
sections = self._get_sections()
assert sections["chorus"].velocity_mult == 1.0
assert sections["chorus"].vol_mult == 1.0
def test_verse2_same_as_verse(self):
sections = self._get_sections()
assert sections["verse2"].velocity_mult == 0.7
assert sections["verse2"].vol_mult == 0.85
def test_chorus2_same_as_chorus(self):
sections = self._get_sections()
assert sections["chorus2"].velocity_mult == 1.0
assert sections["chorus2"].vol_mult == 1.0
def test_bridge_has_low_multipliers(self):
sections = self._get_sections()
assert sections["bridge"].velocity_mult == 0.6
assert sections["bridge"].vol_mult == 0.75
def test_final_has_full_multipliers(self):
sections = self._get_sections()
assert sections["final"].velocity_mult == 1.0
assert sections["final"].vol_mult == 1.0
def test_outro_has_lowest_multipliers(self):
sections = self._get_sections()
assert sections["outro"].velocity_mult == 0.4
assert sections["outro"].vol_mult == 0.60
def test_all_sections_have_multipliers(self):
"""Every section name in SECTIONS has a corresponding entry in multipliers."""
sections = self._get_sections()
from scripts.compose import SECTIONS
expected_names = {name for name, _, _, _ in SECTIONS}
assert set(sections.keys()) == expected_names
class TestSectionActiveHelper:
"""Tests for _section_active() centralized activity helper."""
@staticmethod
def _get_activity():
from scripts.compose import TRACK_ACTIVITY
return TRACK_ACTIVITY
def test_intro_drumloop_active(self):
from scripts.compose import _section_active
assert _section_active("intro", "drumloop", self._get_activity()) is True
def test_intro_bass_inactive(self):
from scripts.compose import _section_active
assert _section_active("intro", "bass", self._get_activity()) is False
def test_intro_chords_inactive(self):
from scripts.compose import _section_active
assert _section_active("intro", "chords", self._get_activity()) is False
def test_intro_lead_inactive(self):
from scripts.compose import _section_active
assert _section_active("intro", "lead", self._get_activity()) is False
def test_chorus_all_active(self):
from scripts.compose import _section_active
activity = self._get_activity()
for role in ("drumloop", "perc", "bass", "chords", "lead", "clap", "pad"):
assert _section_active("chorus", role, activity) is True, f"chorus.{role} should be active"
def test_verse_only_drumloop_bass_chords_active(self):
from scripts.compose import _section_active
activity = self._get_activity()
assert _section_active("verse", "drumloop", activity) is True
assert _section_active("verse", "bass", activity) is True
assert _section_active("verse", "chords", activity) is True
assert _section_active("verse", "lead", activity) is False
assert _section_active("verse", "perc", activity) is False
assert _section_active("verse", "clap", activity) is False
def test_pre_chorus_section_name(self):
"""The section is named pre-chorus, not build."""
from scripts.compose import _section_active
activity = self._get_activity()
assert "pre-chorus" in activity, "pre-chorus must be a key in TRACK_ACTIVITY"
assert "build" not in activity, "build must NOT be a key in TRACK_ACTIVITY"
assert _section_active("pre-chorus", "bass", activity) is True
def test_unknown_section_returns_false(self):
from scripts.compose import _section_active
assert _section_active("xyz", "bass", self._get_activity()) is False
def test_unknown_role_returns_false(self):
from scripts.compose import _section_active
assert _section_active("chorus", "banjo", self._get_activity()) is False
def test_outro_has_drumloop_and_pad(self):
from scripts.compose import _section_active
activity = self._get_activity()
assert _section_active("outro", "drumloop", activity) is True
assert _section_active("outro", "pad", activity) is True
assert _section_active("outro", "bass", activity) is False
def test_bridge_has_drumloop_pad_lead(self):
from scripts.compose import _section_active
activity = self._get_activity()
assert _section_active("bridge", "drumloop", activity) is True
assert _section_active("bridge", "pad", activity) is True
assert _section_active("bridge", "lead", activity) is True
assert _section_active("bridge", "bass", activity) is False
assert _section_active("bridge", "chords", activity) is False
def test_final_has_perc_bass_chords_lead_clap_pad(self):
from scripts.compose import _section_active
activity = self._get_activity()
assert _section_active("final", "drumloop", activity) is True
assert _section_active("final", "perc", activity) is True
assert _section_active("final", "bass", activity) is True
assert _section_active("final", "chords", activity) is True
assert _section_active("final", "lead", activity) is True
assert _section_active("final", "clap", activity) is True
assert _section_active("final", "pad", activity) is True
class TestPluginRegistry:
def test_plugins_in_registry(self):
from src.reaper_builder import PLUGIN_REGISTRY