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:
121
.sdd/changes/hook-melody/spec.md
Normal file
121
.sdd/changes/hook-melody/spec.md
Normal file
@@ -0,0 +1,121 @@
|
||||
# Delta for melody-engine
|
||||
|
||||
## ADDED Requirements
|
||||
|
||||
| # | Requirement | RFC |
|
||||
|---|------------|-----|
|
||||
| R1 | Motif generation with 3 reggaeton styles | MUST |
|
||||
| R2 | Deterministic output from seed | MUST |
|
||||
| R3 | Call-and-response phrase structure | MUST |
|
||||
| R4 | Chord-aware note selection | MUST |
|
||||
| R5 | Motif variation via transpose/rhythmic shift | SHOULD |
|
||||
| R6 | build_lead_track() delegation | MUST |
|
||||
|
||||
### Requirement: Motif Generation (R1)
|
||||
|
||||
`build_motif(key_root, key_minor, style, bars, seed)` MUST generate a 2–4 bar repeating motif using scale-aware note selection. Three styles:
|
||||
|
||||
- **hook**: Arch contour (ascend then descend), chord tones on beats 0, 2, 4..., 4–8 notes
|
||||
- **stabs**: Short 16th-duration hits on dembow grid positions [1.0, 2.5, 3.0, 3.5] per bar
|
||||
- **smooth**: Stepwise scalar motion at eighth-note density, ≤2 semitones between consecutive notes
|
||||
|
||||
MUST accept `bars` parameter (2–8) defaulting to 4. MUST return `list[MidiNote]`.
|
||||
|
||||
#### Scenario: hook style generates arch contour with chord tones
|
||||
|
||||
- GIVEN key Am, style "hook", bars=4, seed=42
|
||||
- WHEN `build_motif("A", True, "hook", 4, 42)` is called
|
||||
- THEN returns 4–12 MidiNote objects
|
||||
- AND notes on quarter-beat positions (0, 2, 4, …) are within the i-VI-III-VII chord tones ≥70% of the time
|
||||
|
||||
#### Scenario: stabs style generates dembow-positioned hits
|
||||
|
||||
- GIVEN key Am, style "stabs", bars=2, seed=1
|
||||
- WHEN `build_motif("A", True, "stabs", 2, 1)` is called
|
||||
- THEN all note start times are within {1.0, 2.5, 3.0, 3.5} per bar
|
||||
- AND each note duration ≤ 0.25 beats (16th note)
|
||||
|
||||
#### Scenario: smooth style generates stepwise motion
|
||||
|
||||
- GIVEN key Am, style "smooth", bars=4, seed=7
|
||||
- WHEN `build_motif("A", True, "smooth", 4, 7)` is called
|
||||
- THEN pitch difference between consecutive notes ≤ 2 semitones
|
||||
|
||||
#### Scenario: invalid style raises ValueError
|
||||
|
||||
- GIVEN an unrecognized style string
|
||||
- WHEN `build_motif("A", True, "invalid", 4, 42)` is called
|
||||
- THEN raises ValueError with message containing valid styles
|
||||
|
||||
### Requirement: Deterministic Output (R2)
|
||||
|
||||
`build_motif()` and `apply_variation()` MUST produce identical output for identical input parameters (key, style, bars, seed). MUST NOT rely on global RNG state.
|
||||
|
||||
#### Scenario: same seed produces identical output
|
||||
|
||||
- GIVEN fixed parameters
|
||||
- WHEN `build_motif("A", True, "hook", 4, 42)` is called twice
|
||||
- THEN both calls return identical lists of MidiNote objects
|
||||
|
||||
#### Scenario: different seeds produce different output
|
||||
|
||||
- GIVEN same key and style but different seeds
|
||||
- WHEN `build_motif("A", True, "hook", 4, 42)` and `build_motif("A", True, "hook", 4, 99)` are called
|
||||
- THEN the returned note lists differ
|
||||
|
||||
### Requirement: Call-and-Response Structure (R3)
|
||||
|
||||
`build_call_response(motif, bars, key_root, key_minor, seed)` MUST generate two halves: **call** (motif + variation, ending on V or VII degree) and **response** (motif, resolving to tonic i). Total length MUST equal `bars` parameter. SHALL repeat motif to fill section length.
|
||||
|
||||
#### Scenario: call ends on tension, response resolves
|
||||
|
||||
- GIVEN an Am hook motif, bars=8, seed=42
|
||||
- WHEN `build_call_response(motif, 8, "A", True, 42)` is called
|
||||
- THEN the last note of the first 4 bars has pitch in {E, G} (V or VII of Am)
|
||||
- AND the last note of the final bar (bar 8) has pitch in {A} (tonic)
|
||||
|
||||
#### Scenario: fills section with motif repetition
|
||||
|
||||
- GIVEN a 2-bar motif and bars=8
|
||||
- WHEN `build_call_response(motif, 8, "A", True, 42)` is called
|
||||
- THEN returns notes spanning 8 bars total
|
||||
- AND motif content repeats at least 2 times within the 8 bars
|
||||
|
||||
### Requirement: Chord-Aware Notes (R4)
|
||||
|
||||
Note selection on strong beats (quarter note positions 0, 4, 8, 12 per bar in 16th-note grid) MUST favor chord tones from `CHORD_PROGRESSION`. Weak beats (all other positions) MAY use any scale degree.
|
||||
|
||||
#### Scenario: strong beats favor chord tones
|
||||
|
||||
- GIVEN key Am (CHORD_PROGRESSION = i-VI-III-VII), style "hook", bars=8
|
||||
- WHEN a motif is generated
|
||||
- THEN ≥70% of notes starting on quarter-beat boundaries belong to active chord tones
|
||||
|
||||
### Requirement: Motif Variation (R5)
|
||||
|
||||
`apply_variation(motif, shift_beats, transpose_semitones)` SHOULD produce a recognizable variant of the input motif. `shift_beats` offsets all start times within the loop. `transpose_semitones` shifts pitches within the scale. MUST return `list[MidiNote]`.
|
||||
|
||||
#### Scenario: rhythmic shift preserves note count and structure
|
||||
|
||||
- GIVEN a 4-bar hook motif
|
||||
- WHEN `apply_variation(motif, shift_beats=0.25)` is called
|
||||
- THEN note count equals original
|
||||
- AND all note durations equal original
|
||||
- AND inter-onset intervals are preserved
|
||||
|
||||
#### Scenario: transpose within scale preserves motif contour
|
||||
|
||||
- GIVEN a 4-bar hook motif in Am
|
||||
- WHEN `apply_variation(motif, transpose_semitones=3)` is called
|
||||
- THEN all pitches are offset by ±3 semitones (within pentatonic scale)
|
||||
|
||||
### Requirement: build_lead_track() Delegation (R6)
|
||||
|
||||
`build_lead_track()` in `compose.py` MUST delegate to `melody_engine.build_call_response()` instead of generating random pentatonic notes directly. MUST keep identical function signature. MUST pass existing tests after adjusting expected note counts.
|
||||
|
||||
#### Scenario: build_lead_track uses call-response structure
|
||||
|
||||
- GIVEN seed=42, key Am, sections containing "chorus" and "final"
|
||||
- WHEN `build_lead_track(sections, offsets, "A", True, 42)` is called
|
||||
- THEN returned TrackDef clips contain notes organized as call-response phrases
|
||||
- AND at least one clip has notes ending on tonic pitch
|
||||
Reference in New Issue
Block a user