# Proposal: transitions-fx ## Intent 9 sections play back-to-back with zero transition — the song feels like disjointed loops. Add transition FX (risers, impacts, sweeps) at section boundaries to glue sections into a coherent arrangement. ## Scope ### In Scope - Place transition FX clips (audio samples) on a dedicated "Transition FX" track at section boundaries - Riser/wash FX: 2–4 beats before section changes (e.g., build → chorus drop) - Impact/hit FX: on the downbeat of CHORUS, FINAL, VERSE2 entries - Filter sweep simulation via fade-in/fade-out on adjacent clips - Transition plan: which boundary gets which FX type + duration - Reuse existing FX-role samples from library (impacts, risers, transition FX, wash) ### Out of Scope - Synthesized FX generation (numpy waveform synthesis) — deferred to future - MIDI CC filter automation in RPP (no CC support in builder today) - Per-track volume automation curves - Reverse cymbal (no suitable samples in library) ## Capabilities ### New Capabilities - `transition-fx`: Placement of audio FX clips at section boundaries for arrangement glue ### Modified Capabilities None — existing section/track structure unchanged. ## Approach **Audio samples from library** — the library has 57 FX-role samples including: - Impacts: `fx_C2_126_boomy` (2.5s, from `impact.wav`) - Risers: `fx_C#5_123_aggressive` (30s), `fx_G3_143_boomy` (6.6s, "RISER 3") - Transition FX: 4 "transicion fx" variants (1.0–1.7s) - Wash/noise: `fx_G#6_136_aggressive` (3.3s) - Short shots/gates: "CAMTAZO 1–2" (1.5–2.0s), "PUERTA" (0.2s) Place audio clips on a new "FX" track at section boundaries: - **Riser/wash**: starts 2–4 beats BEFORE boundary, ends on boundary downbeat - **Impact**: starts on boundary downbeat, short duration (1–2 beats) - Use existing `fade_in`/`fade_out` on ClipDef for filter-like sweeps - Use SampleSelector with `role="fx"` to pick compatible samples ## Affected Areas | Area | Impact | Description | |------|--------|-------------| | `scripts/compose.py` | Modified | Add `build_fx_track()` — places FX clips between sections | | `src/core/schema.py` | Unchanged | `ClipDef` already has `position`, `length`, `audio_path`, `fade_in`, `fade_out` | | `src/reaper_builder/__init__.py` | Unchanged | Audio clip building already works | ## Risks | Risk | Likelihood | Mitigation | |------|------------|------------| | FX samples may not match project key | Low | FX role is ATONAL_ROLES — key scoring skipped by selector | | Long riser samples exceed needed duration | Low | Clip length sets playback window; sample trimmed automatically | | No suitable riser for specific boundary | Med | Fall back to fade_in on next section clip | ## Rollback Plan Remove `build_fx_track()` call from `main()`. Existing tracks untouched. ## Dependencies - `data/sample_index.json` (already exists) - `SampleSelector` with `role="fx"` (already works) ## Success Criteria - [ ] `python scripts/compose.py --bpm 99 --key Am` produces .rpp with FX clips at section boundaries - [ ] At least one FX clip between: build→chorus, chorus→verse2, bridge→final, outro end - [ ] FX clips have appropriate fade_in/fade_out curves - [ ] 110 existing tests continue to pass - [ ] Song renders without gaps — FX clips overlap/bridge sections