# 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 20–999 |
| `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 0–127 (60 = middle C) |
| `start` | `float` | *(required)* | Start time in beats from item start |
| `duration` | `float` | *(required)* | Duration in beats |
| `velocity` | `int` | `64` | Velocity 0–127 |

### 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 0–127 |

### 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.0–1.0 (maps to REAPER volume fader) |
| `pan` | `float` | `0.0` | -1.0 (left) to 1.0 (right) |
| `color` | `int` | `0` | REAPER color index 0–67 |
| `clips` | `list[ClipDef]` | `[]` | Audio/MIDI clips |
| `plugins` | `list[PluginDef]` | `[]` | VST plugins on this track |
| `send_reverb` | `float` | `0.0` | Reverb send level 0.0–1.0 |
| `send_delay` | `float` | `0.0` | Delay send level 0.0–1.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.0–1.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.85–1.1 |
| `density` | `float` | `1.0` | Note density 0.0–1.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 (20–999), 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
