Files
reaper-control/docs/LLM_CONTEXT.md
renato97 7bcd8052a9 docs: LLM-ready documentation suite — LLM_CONTEXT.md, module deep-dives, JSON schemas, CLI reference
Complete documentation system for LLM consumption: primary LLM_CONTEXT.md
(27KB system overview), 4 module deep-dives (composer, reaper-builder,
reaper-scripting, calibrator), 2 JSON Schema draft-07 contracts, CLI
reference, and README correction (FL Studio -> REAPER identity).
2026-05-04 10:30:24 -03:00

545 lines
27 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# fl_control — LLM System Overview
> **About the name**: The directory is named `fl_control` for historical reasons, but the system generates **REAPER `.rpp` files**, not FL Studio `.flp` files. There is NO FL Studio support. The name has been retained for backward compatibility with repository URLs and CI/CD pipelines.
## What Is This?
`fl_control` is a Python system that generates complete **REAPER `.rpp` projects** from the command line. Given a key, BPM, and emotion, it composes a full reggaetón instrumental with drums, 808 bass, chord progressions (with voice leading), lead melodies (hook-based call-and-response), pads, percussion, and transition FX. The output is a valid `.rpp` file that REAPER opens directly, plus an auto-generated ReaScript (`.py`) for post-processing (plugin loading, mix calibration, rendering).
**Target**: REAPER (Windows, v7.x). **Format**: `.rpp` text files. **No DAW dependencies** beyond reading sample files from disk.
## Quick Start
```bash
# Install dependencies
pip install -r requirements.txt
# Generate a song (defaults: 95 BPM, Am key, romantic emotion)
python scripts/generate.py --bpm 95 --key Am --output output/song.rpp --seed 42
# Generate with validation
python scripts/generate.py --bpm 95 --key Dm --output output/song.rpp --seed 42 --validate
# Compose directly (more detailed output)
python scripts/compose.py --bpm 99 --key Am --emotion romantic --output output/song.rpp
```
Output: a ready-to-open `.rpp` file at the specified path.
## Architecture
```
┌───────────────────────────────────────┐
│ CLI Layer │
│ scripts/generate.py (thin wrapper) │
│ scripts/compose.py (full pipeline) │
│ scripts/run_in_reaper.py (ReaScript) │
└──────────────┬────────────────────────┘
┌──────────────────────┼──────────────────────┐
│ ▼ │
┌────────────────┴──────┐ ┌────────────────────┴──┐ ┌───────┴──────────┐
│ src/composer/ │ │ src/calibrator/ │ │ src/selector/ │
│ ┌──────────────────┐ │ │ ┌────────────────┐ │ │ SampleSelector │
│ │ chords.py │ │ │ │ Calibrator │ │ └────────────────┘
│ │ ChordEngine │ │ │ │ .apply() │ │
│ │ melody_engine.py │ │ │ │ presets.py │ └───────────────────┘
│ │ build_motif() │ │ │ │ VOLUME_PRESETS │
│ │ patterns.py │ │ │ │ PAN_PRESETS │ ┌──────────────────┐
│ │ rhythm.py │ │ │ │ SEND_PRESETS │ │ src/core/ │
│ │ templates.py │ │ │ └────────────────┘ │ schema.py │
│ └──────────────────┘ │ └─────────────────────────────┘ │ SongDefinition │
└───────────┬────────────┘ │ TrackDef │
│ │ ClipDef │
▼ │ MidiNote │
┌──────────────────────────┐ │ PluginDef │
│ SongDefinition │◄──────────────────────────────│ SectionDef │
│ ┌────────────────────┐ │ │ PatternDef │
│ │ meta: SongMeta │ │ │ Arrangement... │
│ │ tracks: [TrackDef] │ │ │ CCEvent │
│ │ patterns: [...] │ │ └──────────────────┘
│ │ sections: [...] │ │
│ │ master_plugins │ │
│ └────────────────────┘ │
└───────────┬──────────────┘
┌─────────┼─────────┐
▼ ▼ ▼
┌──────────────┐ ┌───────────────┐ ┌─────────────────┐
│ RPPBuilder │ │ ReaScriptGen │ │ Validator │
│ .write() → │ │ generate() → │ │ validate_rpp() │
│ song.rpp │ │ fl_control_ │ │ │
│ │ │ phase2.py │ │ │
└──────────────┘ └───────┬───────┘ └─────────────────┘
┌──────────────┐
│ REAPER │
│ opens .rpp │
│ runs script │
│ renders WAV │
└──────────────┘
```
**Pipeline**: CLI → compose `SongDefinition` → Calibrator.apply() (post-processing) → RPPBuilder.write() → `.rpp` file → ReaScriptGenerator.generate() → ReaScript → REAPER execution.
## Data Model
All types live in `src/core/schema.py`. Every entity is a Python dataclass.
### SongMeta
Song-level metadata.
| Field | Type | Default | Description |
|-------|------|---------|-------------|
| `bpm` | `float` | *(required)* | Tempo 20999 |
| `key` | `str` | *(required)* | Key string, e.g. `"Am"`, `"Dm"`, `"G"` |
| `title` | `str` | `""` | Song title |
| `ppq` | `int` | `960` | Ticks per quarter note (REAPER default) |
| `time_sig_num` | `int` | `4` | Time signature numerator |
| `time_sig_den` | `int` | `4` | Time signature denominator |
| `calibrate` | `bool` | `True` | Enable post-processing mix calibration |
### MidiNote
A single MIDI note event within a clip.
| Field | Type | Default | Description |
|-------|------|---------|-------------|
| `pitch` | `int` | *(required)* | MIDI note number 0127 (60 = middle C) |
| `start` | `float` | *(required)* | Start time in beats from item start |
| `duration` | `float` | *(required)* | Duration in beats |
| `velocity` | `int` | `64` | Velocity 0127 |
### CCEvent
A MIDI CC event within a clip.
| Field | Type | Default | Description |
|-------|------|---------|-------------|
| `controller` | `int` | *(required)* | CC number (e.g. 11 = Expression) |
| `time` | `float` | *(required)* | Position in beats from clip start |
| `value` | `int` | *(required)* | CC value 0127 |
### ClipDef
A clip placed on a track — either audio or MIDI.
| Field | Type | Default | Description |
|-------|------|---------|-------------|
| `position` | `float` | *(required)* | Start position in beats |
| `length` | `float` | *(required)* | Duration in beats |
| `name` | `str` | `""` | Display name |
| `audio_path` | `str \| None` | `None` | Absolute path to audio file (audio clips) |
| `midi_notes` | `list[MidiNote]` | `[]` | MIDI notes (MIDI clips) |
| `midi_cc` | `list[CCEvent]` | `[]` | MIDI CC events |
| `loop` | `bool` | `False` | Whether the audio clip loops |
| `fade_in` | `float` | `0.0` | Fade-in duration in seconds |
| `fade_out` | `float` | `0.0` | Fade-out duration in seconds |
| `vol_mult` | `float` | `1.0` | Volume multiplier applied at clip level |
Properties: `is_midi` → True when `midi_notes` is non-empty; `is_audio` → True when `audio_path` is not None.
### PluginDef
A VST plugin instance on a track.
| Field | Type | Default | Description |
|-------|------|---------|-------------|
| `name` | `str` | *(required)* | Display name (e.g. `"Serum 2"`) |
| `path` | `str` | *(required)* | Plugin path/identifier |
| `index` | `int` | `0` | Chain position (0 = first) |
| `params` | `dict[int, float]` | `{}` | Parameter index → value |
| `preset_data` | `list[str] \| None` | `None` | Base64 preset chunks |
| `role` | `str` | `""` | Track role for role-aware preset lookup |
| `builtin` | `bool` | `False` | True → deferred to ReaScript, not written to .rpp |
### TrackDef
A track in the REAPER project.
| Field | Type | Default | Description |
|-------|------|---------|-------------|
| `name` | `str` | *(required)* | Track display name |
| `volume` | `float` | `0.85` | 0.01.0 (maps to REAPER volume fader) |
| `pan` | `float` | `0.0` | -1.0 (left) to 1.0 (right) |
| `color` | `int` | `0` | REAPER color index 067 |
| `clips` | `list[ClipDef]` | `[]` | Audio/MIDI clips |
| `plugins` | `list[PluginDef]` | `[]` | VST plugins on this track |
| `send_reverb` | `float` | `0.0` | Reverb send level 0.01.0 |
| `send_delay` | `float` | `0.0` | Delay send level 0.01.0 |
| `send_level` | `dict[int, float]` | `{}` | Return track index → send level |
### SectionDef
A section in the song arrangement.
| Field | Type | Default | Description |
|-------|------|---------|-------------|
| `name` | `str` | *(required)* | Display name (e.g. `"intro"`, `"chorus"`) |
| `bars` | `int` | *(required)* | Length in bars |
| `energy` | `float` | `0.5` | Energy level 0.01.0 |
| `velocity_mult` | `float` | `1.0` | Velocity multiplier for all notes in section |
| `vol_mult` | `float` | `1.0` | Volume multiplier for tracks in section |
### PatternDef
A pattern definition with generator and variation axes.
| Field | Type | Default | Description |
|-------|------|---------|-------------|
| `id` | `int` | *(required)* | Unique pattern ID |
| `name` | `str` | *(required)* | Display name |
| `instrument` | `str` | *(required)* | Sample/instrument key |
| `channel` | `int` | *(required)* | MIDI channel |
| `bars` | `int` | *(required)* | Length in bars |
| `generator` | `str` | *(required)* | Generator function name |
| `velocity_mult` | `float` | `1.0` | Velocity multiplier 0.851.1 |
| `density` | `float` | `1.0` | Note density 0.01.0 |
### ArrangementItemDef
An item placed in the arrangement referencing a pattern on a track.
| Field | Type | Default | Description |
|-------|------|---------|-------------|
| `pattern` | `int` | *(required)* | Pattern ID |
| `bar` | `float` | *(required)* | Start position in bars |
| `bars` | `float` | *(required)* | Length in bars |
| `track` | `int` | *(required)* | Track index |
### ArrangementTrack
A track in the REAPER arrangement with index and display name.
| Field | Type | Default | Description |
|-------|------|---------|-------------|
| `index` | `int` | *(required)* | Track index |
| `name` | `str` | *(required)* | Display name |
### SongDefinition
Complete song definition — the source of truth for one `.rpp` file.
| Field | Type | Default | Description |
|-------|------|---------|-------------|
| `meta` | `SongMeta` | *(required)* | Song metadata |
| `tracks` | `list[TrackDef]` | `[]` | REAPER tracks with clips and plugins |
| `patterns` | `list[PatternDef]` | `[]` | Pattern definitions for arrangement |
| `items` | `list[ArrangementItemDef]` | `[]` | Arrangement items referencing patterns |
| `progression_name` | `str` | `"i-VII-VI-VII"` | Chord progression label |
| `section_template` | `str` | `"standard"` | Section template name |
| `samples` | `dict[str, str]` | `{}` | Sample file map (name → filename) |
| `sections` | `list[SectionDef]` | `[]` | Section definitions in playback order |
| `master_plugins` | `list[str]` | `[]` | Plugin registry keys for master FX chain |
Key methods:
- `validate()``list[str]` — returns list of validation errors (empty = valid)
- `length_beats` (property) → `float` — total length computed from all clips
- `to_json(indent=2)``str` — serialize to JSON via `dataclasses.asdict`
## Module Index
| Module | Location | Role |
|--------|----------|------|
| **schema** | `src/core/schema.py` | All dataclass definitions. Single source of truth for data model. |
| **composer** | `src/composer/` | Composition engine: chord progression, melody generation, rhythm patterns, drum analysis |
| **reaper_builder** | `src/reaper_builder/` | RPPBuilder: `.rpp` file generation from `SongDefinition`. Plugin registry (~97 entries). VST2/VST3 element builders. Headless render. |
| **reaper_scripting** | `src/reaper_scripting/` | ReaScript generation: self-contained Python scripts for REAPER post-processing |
| **calibrator** | `src/calibrator/` | Post-processing mix calibration: volume, pan, sends, master chain by track role |
| **selector** | `src/selector/` | Sample selection: scores samples by key compatibility, BPM proximity, character |
| **validator** | `src/validator/` | `.rpp` output validation |
| **CLI scripts** | `scripts/` | `compose.py` (full pipeline), `generate.py` (thin wrapper), `run_in_reaper.py` (ReaScript execution) |
### composer/ sub-modules
| File | Role |
|------|------|
| `chords.py` | `ChordEngine` — emotion-aware chord progressions with voice leading |
| `melody_engine.py` | `build_motif()`, `build_call_response()` — hook-based melody generation |
| `patterns.py` | Pattern weight tables extracted from real reggaetón tracks |
| `rhythm.py` | Dembow rhythm generators (classic, perreo, trápico) |
| `templates.py` | RPP template extraction and generation |
| `converters.py` | Conversion utilities |
| `variation.py` | Pattern variation logic |
| `melodic.py` | Melodic pattern generators |
| `drum_analyzer.py` | `DrumLoopAnalyzer` — transient detection for sidechain CC generation |
| `__init__.py` | Scale intervals, chord type tables, legacy pattern generators |
## Pipeline
The complete composition and build pipeline, step by step:
### Phase 1: Composition (`scripts/compose.py`)
1. **Parse CLI args**: `--bpm`, `--key`, `--emotion`, `--inversion`, `--seed`, `--no-calibrate`
2. **Load `SampleSelector`**: Reads `data/sample_index.json` for clap/snare/FX sample selection
3. **Build sections**: 9-section structure (intro → verse → pre-chorus → chorus → verse2 → chorus2 → bridge → final → outro), each with energy level and velocity/volume multipliers
4. **Build tracks** (in order):
- `Drumloop` — audio clips cycling between seco/filtrado variants per section
- `Perc` — percussion audio loops per section
- `808 Bass` — MIDI notes using proven i-iv-i-V harmonic pattern with CC11 sidechain ducking
- `Chords``ChordEngine.progression()` with voice leading; i-VII-VI-VII progression
- `Lead``build_motif("hook")` + `build_call_response()` via melody engine
- `Clap` — Short audio samples on dembow grid (beats 2.0, 3.5)
- `Transition FX` — Audio clips at section boundaries (risers, impacts, sweeps)
- `Pad` — Arpeggiated chord tones on eighth notes
- `Reverb` / `Delay` — Return tracks with Pro-R 2 and ValhallaDelay
5. **Wire sends**: Return track sends by role from `SEND_LEVELS`
6. **Assemble `SongDefinition`**: Meta + tracks + sections + master_plugins
7. **Calibrate** (unless `--no-calibrate`): `Calibrator.apply(song)` — role-based volume, pan, sends, master chain
### Phase 2: Build (`src/reaper_builder/RPPBuilder`)
1. `RPPBuilder(song, seed).write(path)` serializes to `.rpp`:
- Project header (static metadata from ground-truth `test_vst3.rpp`)
- Dynamic TEMPO line
- Master track with FX chain (Ozone 12 triplet or FabFilter fallback)
- Per-track TRACK elements with VOLPAN, AUXRECV (sends)
- Per-track FXCHAIN with VST elements (resolved from `PLUGIN_REGISTRY`)
- Per-clip ITEM elements with SOURCE (WAVE or MIDI with E-lines)
- Built-in plugins (Cockos) deferred to ReaScript insertion
### Phase 3: ReaScript (Phase 2B)
`scripts/run_in_reaper.py` generates a self-contained Python ReaScript that REAPER executes:
1. Reads `fl_control_command.json` (command file)
2. Opens the `.rpp` project
3. Executes action pipeline: `add_plugins``configure_fx_params``verify_fx``calibrate``render`
4. Writes `fl_control_result.json` (LUFS metrics, FX errors, plugin results)
### Validation
`SongDefinition.validate()` checks: BPM range (20999), key format (regex), unique track names, clips with neither audio nor MIDI.
## Plugin System
### PLUGIN_REGISTRY
Located in `src/reaper_builder/__init__.py` (~97 entries). Format:
```python
PLUGIN_REGISTRY: dict[str, tuple[str, str, str]] = {
"key": ("display_name", "filename", "uid_guid"),
}
```
- **key**: Short registry key (e.g. `"Serum_2"`, `"Pro-Q_3"`, `"Decapitator"`)
- **display_name**: Full REAPER display name (e.g. `"VST3i: Serum 2 (Xfer Records)"`)
- **filename**: File on disk (e.g. `"Serum2.vst3"`, `"Decapitator.dll"`)
- **uid_guid**: Unique identifier — VST2 uses `<GUID>`, VST3 uses `{GUID}`
### ALIAS_MAP
Backward compatibility mapping: old key names → new `PLUGIN_REGISTRY` keys. Example:
```python
ALIAS_MAP = {
"Serum2": "Serum_2",
"FabFilter Pro-Q 3": "Pro-Q_3",
"Valhalla Delay": "ValhallaDelay",
"Pro-Q 3": "Pro-Q_3",
}
```
FabFilter plugins map space-separated names to short VST3 keys. SoundToys plugins keep their underscore names.
### PLUGIN_PRESETS
Role-aware preset data. Format:
```python
PLUGIN_PRESETS: dict[tuple[str, str], list[str]] = {
("Pro-Q_3", ""): [chunk1, chunk2, ...], # default
("Serum_2", "bass"): [chunk1, chunk2, ...], # role-specific
}
```
Lookup chain: `(key, role)``(key, "")` (default) → `fallback``None`.
### REAPER_BUILTINS
Set of Cockos native plugin keys (ReaEQ, ReaComp, ReaVerb, etc.). Plugins matching this are deferred to ReaScript insertion (`TrackFX_AddByName`) rather than written to `.rpp` as VST elements.
### Plugin Lookup in RPPBuilder
```
PluginDef.name → ALIAS_MAP.get(name, name) → PLUGIN_REGISTRY.get(resolved)
┌───────────────┤
found│ │not found
▼ ▼
Build VST element Fallback: .dll
with display_name, with 19 param
filename, uid_guid slots
```
## ReaScript Protocol
### Overview
ReaScript is a self-contained Python file generated by `ReaScriptGenerator` that REAPER executes internally. It communicates via JSON files on disk:
```
fl_control_command.json ──read──► ReaScript ──write──► fl_control_result.json
```
### ReaScriptCommand
Defined in `src/reaper_scripting/commands.py`:
| Field | Type | Default | Description |
|-------|------|---------|-------------|
| `version` | `int` | `1` | Protocol version |
| `action` | `str \| list[str]` | `"calibrate"` | Single action or pipeline list |
| `rpp_path` | `str` | `""` | Path to `.rpp` file to open |
| `render_path` | `str` | `""` | Path for rendered WAV output |
| `timeout` | `int` | `120` | Polling timeout in seconds |
| `track_calibration` | `list[dict]` | `[]` | Volume/pan/send calibration per track |
| `plugins_to_add` | `list[dict]` | `[]` | `{"track_name": str, "fx_name": str, "params": {...}}` |
### ReaScriptResult
| Field | Type | Default | Description |
|-------|------|---------|-------------|
| `version` | `int` | `1` | Protocol version |
| `status` | `str` | `"ok"` | `"ok"`, `"error"`, or `"timeout"` |
| `message` | `str` | `""` | Error or status message |
| `lufs` | `float \| None` | `None` | Integrated LUFS |
| `integrated_lufs` | `float \| None` | `None` | Integrated LUFS reading |
| `short_term_lufs` | `float \| None` | `None` | Short-term LUFS |
| `fx_errors` | `list[dict]` | `[]` | FX verification errors |
| `tracks_verified` | `int` | `0` | Number of tracks verified |
| `added_plugins` | `list[dict]` | `[]` | `{"fx_name", "instance_id", "track_name", "status"}` |
### ProtocolVersionError
Raised by `read_result()` when result version doesn't match expected version.
### Key Functions
- `write_command(path, cmd)` — Serialize `ReaScriptCommand` to JSON file
- `read_result(path, expected_version=1)` — Deserialize `ReaScriptResult` from JSON file. Raises `ProtocolVersionError` on version mismatch.
### Known Actions
`add_plugins`, `configure_fx_params`, `verify_fx`, `calibrate`, `render`
### ReaScript JSON Parser
Since REAPER's internal Python has no `json` module, the ReaScript includes a hand-rolled JSON parser (~100 lines) that handles strings, integers, floats, booleans, nulls, nested objects, and arrays via string splitting.
## CLI Reference
### scripts/compose.py
Main composition pipeline. Builds a full reggaetón track from scratch.
| Flag | Type | Default | Description |
|------|------|---------|-------------|
| `--bpm` | `float` | `99` | Tempo |
| `--key` | `str` | `"Am"` | Musical key |
| `--output` | `str` | `"output/song.rpp"` | Output `.rpp` path |
| `--seed` | `int` | `None` | Random seed for determinism |
| `--emotion` | `str` | `"romantic"` | `romantic` / `dark` / `club` / `classic` |
| `--inversion` | `str` | `"root"` | `root` / `first` / `second` |
| `--no-calibrate` | `flag` | `False` | Skip post-processing mix calibration |
### scripts/generate.py
Thin wrapper around `compose.py`. Delegates via `sys.argv` manipulation.
| Flag | Type | Default | Description |
|------|------|---------|-------------|
| `--bpm` | `float` | `95` | Tempo |
| `--key` | `str` | `"Am"` | Musical key |
| `--output` | `str` | `"output/song.rpp"` | Output `.rpp` path |
| `--seed` | `int` | `42` | Random seed |
| `--emotion` | `str` | `"romantic"` | Chord emotion |
| `--inversion` | `str` | `"root"` | Chord inversion |
| `--validate` | `flag` | `False` | Run `validate_rpp_output()` after generation |
### scripts/run_in_reaper.py
ReaScript execution CLI. Generates and runs a Phase 2 ReaScript.
| Arg/Flag | Type | Default | Description |
|----------|------|---------|-------------|
| `rpp_path` | positional | *(required)* | Path to `.rpp` file |
| `--output`, `-o` | `str` | auto-derived | Rendered WAV output path |
| `--timeout` | `int` | `120` | Seconds to poll for result JSON |
| `--plugins-config` | `str` | `None` | JSON SongDefinition for deriving plugins_to_add |
| `--action` | `str` | `"calibrate"` | Space-separated action pipeline |
Example:
```bash
python scripts/run_in_reaper.py output/song.rpp --action "add_plugins calibrate render" --timeout 300
```
## Conventions
From `AGENTS.md`:
- **Python**: Type hints on all function signatures
- **Dataclasses**: Over dicts for structured data
- **Deterministic output**: Seed-based RNG (`random.Random(seed)`), no global random state
- **No bare except clauses**
- **Testing**: `pytest` only. Unit tests for all new functions. Integration tests for end-to-end flows.
- **Architecture**: Separate modules by concern (calibrator, composer, builder, selector, validator)
- **Post-processing**: Calibrator.apply() pattern — modify in-place after construction, not inline
- **Schema changes**: Must be backward-compatible (new fields get defaults)
- **SDD**: All changes follow spec-driven development pipeline (propose → spec → design → tasks → apply → verify)
## How to Extend
### Adding a New Track Role
1. Add role to `TRACK_ACTIVITY` in `scripts/compose.py` — define which sections it plays in
2. Add volume/presets to `src/calibrator/presets.py` (`VOLUME_PRESETS`, `PAN_PRESETS`, `SEND_PRESETS`)
3. Add FX chain to `FX_CHAINS` in `scripts/compose.py`
4. Write a `build_<role>_track()` function
5. Add the track to the `tracks` list in `main()`
6. Add calibration role mapping in `Calibrator._resolve_role()`
### Adding a New Plugin to the Registry
1. Scan the plugin in REAPER or extract from a ground-truth `.rpp`
2. Add entry to `PLUGIN_REGISTRY`: `"key": ("display_name", "filename", "uid_guid")`
3. If needed, add preset data to `_PRESETS_FLAT` with the key
4. Add aliases to `ALIAS_MAP` if there are alternate names
5. Use `make_plugin(registry_key, index, role)` to create `PluginDef` instances
### Adding a New CLI Flag
1. Add `parser.add_argument()` in `scripts/compose.py` (and `scripts/generate.py` if wrapping)
2. Thread the flag value through the composition pipeline
3. Pass to relevant builder/track functions
### Adding a New Emotion to ChordEngine
1. Add entry to `EMOTION_PROGRESSIONS` in `src/composer/chords.py`
2. Format: `"name": [(semitone_offset, quality), ...]` for a 4-chord loop
3. Add choice to `--emotion` argparse choices
## Known Limitations
- **Hardcoded paths**: Drumloop samples reference `C:\ProgramData\Ableton\...` paths. These must exist on the build machine or the pipeline will skip those clips.
- **Environment-specific registry**: `PLUGIN_REGISTRY` was generated from a specific REAPER/plugin installation. Different machines may have different plugin paths or GUIDs.
- **Windows only**: REAPER executable path in `render.py` defaults to `C:\Program Files\REAPER (x64)\reaper.exe`. The ReaScript REAPER API calls are Windows-specific.
- **No CI**: No automated test/validation pipeline. Tests run manually with `pytest`.
- **Single genre**: Only reggaetón is fully implemented. Other genres exist in `knowledge/` as JSON definitions but the main pipeline (`compose.py`) is hardcoded for reggaetón.
- **Sample library**: Requires pre-existing sample files in expected directories. No bundled samples.
- **ReaScript execution**: `run_in_reaper.py` generates scripts but does NOT automatically launch REAPER. REAPER must be running and monitoring the scripts directory, or the script must be executed manually from within REAPER's action list.
## Further Reading
- [CLI Reference](CLI.md) — Complete CLI documentation
- [Module: Composer](modules/composer.md) — Composition engine deep-dive
- [Module: Reaper Builder](modules/reaper-builder.md) — RPP format and plugin registry
- [Module: Reaper Scripting](modules/reaper-scripting.md) — ReaScript protocol
- [Module: Calibrator](modules/calibrator.md) — Mix calibration presets
- [JSON Schema: Song Definition](schemas/song-definition.json) — Data model schema
- [JSON Schema: ReaScript Protocol](schemas/reascript-protocol.json) — Command/result schema