feat: SDD workflow — test sync, song generation + validation, ReaScript hybrid pipeline
- compose-test-sync: fix 3 failing tests (NOTE_TO_MIDI, DrumLoopAnalyzer mock, section name) - generate-song: CLI wrapper + RPP validator (6 structural checks) + 4 e2e tests - reascript-hybrid: ReaScriptGenerator + command protocol + CLI + 16 unit tests - 110/110 tests passing - Full SDD cycle (propose→spec→design→tasks→apply→verify) for all 3 changes
This commit is contained in:
112
.sdd/changes/archive/2026-05-03-reascript-hybrid/ARCHIVE.md
Normal file
112
.sdd/changes/archive/2026-05-03-reascript-hybrid/ARCHIVE.md
Normal file
@@ -0,0 +1,112 @@
|
||||
# Archive: reascript-hybrid
|
||||
|
||||
**Archived**: 2026-05-03
|
||||
**Status**: Complete — 110 tests pass (verify PASS)
|
||||
|
||||
---
|
||||
|
||||
## Summary
|
||||
|
||||
Added a Phase 2 pipeline that runs inside REAPER via ReaScript for FX verification, track calibration, audio rendering, and loudness measurement. Phase 1 (.rpp generation via RPPBuilder) is unchanged and works standalone. The two-phase architecture enables offline composition with in-DAW verification.
|
||||
|
||||
---
|
||||
|
||||
## Specs Synced
|
||||
|
||||
| Domain | Action | Details |
|
||||
|--------|--------|---------|
|
||||
| reascript-generator | Created | ReaScriptGenerator class, command protocol, ReaScript API subset, Phase 2 pipeline steps |
|
||||
|
||||
New `reascript-generator` domain capability added to the system.
|
||||
|
||||
---
|
||||
|
||||
## Files Changed
|
||||
|
||||
| File | Change | Description |
|
||||
|------|--------|-------------|
|
||||
| `src/reaper_scripting/__init__.py` | Created | `ReaScriptGenerator` class — generates self-contained Python ReaScript files |
|
||||
| `src/reaper_scripting/commands.py` | Created | `ReaScriptCommand`, `ReaScriptResult` dataclasses + `write_command()`, `read_result()`, `ProtocolVersionError` |
|
||||
| `scripts/run_in_reaper.py` | Created | CLI entry point for Phase 2: generate script → write command JSON → poll result → print LUFS |
|
||||
| `tests/test_reaper_scripting.py` | Created | 16 unit tests (command protocol, generator output, error handling) |
|
||||
|
||||
---
|
||||
|
||||
## Tasks Completed
|
||||
|
||||
All 3 implementation phases per `tasks.md` — all complete. Phase 4 (integration test against live REAPER) marked manual/skipped.
|
||||
|
||||
**Phase 1 — Protocol Layer (1.1–1.4)**: `commands.py` with `ReaScriptCommand`, `ReaScriptResult`, `write_command()`, `read_result()`, `ProtocolVersionError`.
|
||||
|
||||
**Phase 2 — ReaScript Generator (2.1–2.8)**: `ReaScriptGenerator` in `__init__.py` generating self-contained Python ReaScript with hand-rolled JSON parser, API availability check, full Phase 2 pipeline, and error handling.
|
||||
|
||||
**Phase 3 — CLI Orchestration (3.1–3.7)**: `run_in_reaper.py` with argparse CLI, script path resolution via REAPER ResourcePath, command/result JSON round-trip, timeout handling, LUFS output files.
|
||||
|
||||
**Phase 4 — Integration Test (4.1–4.4)**: Manual testing against live REAPER — skipped in CI.
|
||||
|
||||
---
|
||||
|
||||
## Verification
|
||||
|
||||
- **Test result**: 110 tests pass (`pytest tests/ -q`)
|
||||
- **New tests**: 16/16 pass (`pytest tests/test_reaper_scripting.py -v`)
|
||||
- **Implementation**: `ReaScriptGenerator.generate()` writes valid Python; protocol round-trips correctly; `ProtocolVersionError` raised on version mismatch
|
||||
|
||||
---
|
||||
|
||||
## Architecture Decisions
|
||||
|
||||
| Decision | Choice | Rationale |
|
||||
|----------|--------|-----------|
|
||||
| JSON file protocol over python-reapy | `fl_control_command.json` / `fl_control_result.json` in REAPER ResourcePath | No network dependency; REAPER owns timing; JSON is human-readable for debugging |
|
||||
| Self-contained ReaScript (no `import json`) | Hand-rolled JSON parser via string splitting (~20 lines) | Maximum REAPER version compatibility; avoids import-time failures |
|
||||
| Separate `commands.py` for protocol | `ReaScriptCommand`, `ReaScriptResult` isolated from generator | Protocol is stable and testable in isolation |
|
||||
| `track_calibration` JSON array | Stateless interface for volume/pan/sends per track | Retry-friendly; command JSON valid for replay if REAPER crashes mid-calibration |
|
||||
|
||||
---
|
||||
|
||||
## ReaScript Hybrid Pipeline
|
||||
|
||||
```
|
||||
Phase 1 (offline, Python) Phase 2 (inside REAPER, ReaScript)
|
||||
───────────────────────── ─────────────────────────────────
|
||||
RPPBuilder.build() Main_openProject(rpp_path)
|
||||
│ │
|
||||
▼ ▼
|
||||
output/song.rpp TrackFX_GetCount + TrackFX_GetFXName
|
||||
→ fx_errors (missing plugins)
|
||||
│ │
|
||||
│ SetMediaTrackInfo_Value(VOLUME/PAN)
|
||||
│ CreateTrackSend for each send
|
||||
│ │
|
||||
│ ▼
|
||||
│ Main_RenderFile → output/song.wav
|
||||
│ │
|
||||
│ ▼
|
||||
│ CalcMediaSrcLoudness
|
||||
│ → integrated_lufs, short_term_lufs
|
||||
│ │
|
||||
│ ▼
|
||||
│ write result.json
|
||||
▼
|
||||
run_in_reaper.py
|
||||
→ generate phase2.py
|
||||
→ write command.json ──────────────────────────────►
|
||||
→ poll result.json ◄──────────────────────────────
|
||||
→ print LUFS, write fx_errors.json
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Archive Contents
|
||||
|
||||
- `proposal.md` ✅
|
||||
- `spec.md` ✅
|
||||
- `design.md` ✅
|
||||
- `tasks.md` ✅ (11/12 tasks complete — Phase 4 manual)
|
||||
|
||||
---
|
||||
|
||||
## SDD Cycle Complete
|
||||
|
||||
The change has been fully planned, implemented, verified, and archived. Ready for the next change.
|
||||
Reference in New Issue
Block a user