- section-energy: track activity matrix + volume/velocity multipliers per section - smart-chords: ChordEngine with voice leading, inversions, 4 emotion modes - hook-melody: melody engine with hook/stabs/smooth styles, call-and-response - mix-calibration: Calibrator module (LUFS volumes, HPF/LPF, stereo, sends, master) - transitions-fx: FX track with risers/impacts/sweeps at section boundaries - sidechain: MIDI CC11 bass ducking on kick hits via DrumLoopAnalyzer - presets-pack: role-aware plugin presets (Serum/Decapitator/Omnisphere per role) Full SDD pipeline (propose→spec→design→tasks→apply→verify) for all 7 changes. 302/302 tests passing.
4.0 KiB
Proposal: presets-pack
Intent
All plugins use the SAME flat preset regardless of track role (bass/lead/chords/pad) or genre context. A Serum_2 on a bass track gets the same sound as Serum_2 on a lead track. Professional reggaeton needs role-specific timbres: deep sine 808 for bass, detuned saw for lead, warm pad for chords, evolving texture for pad. Same for FX: Decapitator on drums needs aggressive drive, on bass needs subtle warmth.
Scope
In Scope
- Restructure
PLUGIN_PRESETSfrom flat{plugin: [chunks]}to role-aware{plugin: {role: [chunks]}} - Create role-specific presets for plugins used in multiple roles: Serum_2 (bass/lead), Omnisphere (chords/pad), Decapitator (drums/bass)
- Programmatically derive new presets by base64-decoding existing presets (Serum=JSON, SoundToys=key=value), modifying genre-specific parameters, re-encoding
- Update
make_plugin()incompose.pyand_build_plugin()in__init__.pyto resolve role-aware presets - Add fallback: if no role-specific preset exists, use existing default preset
Out of Scope
- Creating presets from scratch in REAPER (requires GUI — can't programmatically)
- ReaScript-based preset capture (Phase 2)
- Presets for all 113 plugins — only multi-role targets initially
- Pro-Q 3 reggaeton EQ curve (no decodable format available)
Capabilities
New Capabilities
presets-pack: Role-specific plugin preset resolution and preset data management
Modified Capabilities
None — existing plugin resolution unchanged; backward-compatible fallback to default preset.
Approach
Option B — Programmatic modification of decodable presets:
-
Serum_2: Decode base64 → JSON. Serum preset JSON has
component: "processor"block with oscillator/wavetable/filter data. Create variants by modifying oscillator type (sine for bass, saw for lead), filter cutoff, envelope settings. Re-encode. -
Decapitator (SoundToys): Decode base64 → key=value text (
WIDGET = Decapitator;...). Create "aggressive" (high Drive, Tone bright) for drums, "warm" (low Drive, Tone dark) for bass. Re-encode. -
Omnisphere: Decode base64 →
SynthMastertext block. Create "warm pad" variant with slow attack, filter modulation; "evolving texture" with movement/LFO. Re-encode.
No GUI or REAPER needed — pure Python string processing over decoded preset text.
Affected Areas
| Area | Impact | Description |
|---|---|---|
src/reaper_builder/__init__.py |
Modified | PLUGIN_PRESETS restructured; _build_plugin() accepts role param |
src/composer/templates.py |
Modified | _parse_vst_block(), make_plugin() resolution updated |
scripts/compose.py |
Modified | make_plugin() passes role; FX_CHAINS keys used for role |
src/core/schema.py |
Unchanged | PluginDef already has preset_data field |
Risks
| Risk | Likelihood | Mitigation |
|---|---|---|
| Modified preset crashes plugin on load | Low | Each variant derived from working ground-truth preset; only tweak known-safe params |
| Base64 decode/re-encode breaks binary integrity | Low | Round-trip test per plugin: decode → encode → bytes equal |
| Omnisphere text format undocumented | Med | Preserve structure, only modify known ATTRIBUTE values visible in decoded text |
Rollback Plan
Revert PLUGIN_PRESETS to flat dict. Remove role param from _build_plugin() and make_plugin(). Existing tests verify preset injection still works.
Dependencies
data/sample_index.json(independent — not affected)- Existing ground-truth presets in
PLUGIN_PRESETS(source material for variants)
Success Criteria
python scripts/compose.py --bpm 99 --key Amproduces .rpp where Serum_2 on bass track has different preset data than Serum_2 on lead track- 110 existing tests continue to pass (backward-compatible fallback)
- Round-trip test: decode → modify → encode produces valid base64 matching original length structure
- At least 3 (plugin, role) combinations have distinct preset variants