Files
reaper-control/.sdd/changes/hook-melody/spec.md
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

5.4 KiB
Raw Blame History

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 24 bar repeating motif using scale-aware note selection. Three styles:

  • hook: Arch contour (ascend then descend), chord tones on beats 0, 2, 4..., 48 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 (28) 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 412 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