# Transition FX Specification ## Purpose Glue sections together by placing audio FX clips at arrangement boundaries using existing `role="fx"` library samples. ## Requirements ### Requirement: FX Track Existence The system MUST create a dedicated "Transition FX" audio track with clips at 7 section boundaries. #### Scenario: FX track present in arrangement - GIVEN a 9-section song - WHEN `compose.py` runs - THEN a track named "Transition FX" exists with 7+ audio clips at boundary positions ### Requirement: Riser Before Climax A riser/wash FX MUST start 2–4 beats before build→chorus and bridge→final boundaries, ending ON the boundary downbeat. #### Scenario: Riser before chorus - GIVEN build ends at beat 64 (bar 16) - WHEN FX is built - THEN a riser at position 60 (beat 60), length 4, `fade_in` ≥ 1.0s #### Scenario: Riser before final - GIVEN bridge ends at beat 176 (bar 44) - WHEN FX is built - THEN a riser at position 172, length 4, `fade_in` ≥ 1.0s #### Scenario: Riser before chorus2 - GIVEN verse2 ends at beat 128 (bar 32) - WHEN FX is built - THEN a riser at position 124, length 4, `fade_in` ≥ 1.0s ### Requirement: Impact on Section Downbeat An impact/stab FX MUST start on beat 1 of CHORUS (beat 64) and FINAL (beat 176). #### Scenario: Impact on chorus beat 1 - GIVEN chorus starts at beat 64 - WHEN FX is built - THEN an impact clip at position 64, length 1–2 beats, `fade_out` ≥ 0.2s #### Scenario: Impact on final beat 1 - GIVEN final starts at beat 176 - WHEN FX is built - THEN an impact clip at position 176, length 1–2 beats ### Requirement: Transition Sweeps Between Verses Short transition FX MUST bridge chorus→verse2 (beat 96) and chorus2→bridge (beat 160). #### Scenario: Sweep bridges chorus to verse2 - GIVEN chorus ends at beat 96 - WHEN FX is built - THEN a transition clip at position 94, length 2 beats, `fade_in` and `fade_out` > 0 ### Requirement: FX Sample Selection The system SHALL select FX samples via `SampleSelector.select_one(role="fx")`, favoring short samples for impacts, long for risers. #### Scenario: FX role returns candidates - GIVEN 57 FX samples in library with ATONAL_ROLES including "fx" - WHEN `select(role="fx")` is called - THEN non-empty result returned; key scoring skipped (neutral 0.5) ### Requirement: Fade Curves FX clips MUST use `fade_in`/`fade_out`. Risers: `fade_in` ≥ 0.3s. Impacts: `fade_out` ≥ 0.2s. #### Scenario: Riser fades in, impact fades out - GIVEN riser and impact clips defined - WHEN ClipDef is created - THEN riser.fade_in > 0 AND impact.fade_out > 0 ### Requirement: FX Track Mixing The FX track SHALL have volume ≤ 0.80 and send to Reverb/Delay returns. #### Scenario: FX track has moderate volume and sends - GIVEN "Transition FX" track created - WHEN track is defined - THEN volume = 0.72, send_level includes reverb (0.08) and delay (0.05)