refactor: migrate from FL Studio to REAPER with rpp library

Replace FL Studio binary .flp output with REAPER text-based .rpp output
using the rpp Python library (Perlence/rpp).

- Add core/schema.py: DAW-agnostic data types (SongDefinition, TrackDef,
  ClipDef, MidiNote, PluginDef)
- Add reaper_builder/: RPP file generation via rpp.Element + headless
  render via reaper.exe CLI
- Add composer/converters.py: bridge rhythm.py/melodic.py note dicts
  to core.schema MidiNote objects
- Rewrite scripts/compose.py: real generator pipeline with --render flag
- Delete src/flp_builder/, src/scanner/, mcp/, flstudio-mcp/, old scripts
- Add 40 passing tests (schema, builder, converters, compose, render)
This commit is contained in:
renato97
2026-05-03 09:13:35 -03:00
parent 1e2316a5a4
commit af6d61c8a1
47 changed files with 1589 additions and 4990 deletions

View File

@@ -4,6 +4,8 @@ All generators return list[dict] with format {pos, len, key, vel}.
Designed to feed MelodicTrack notes in SongDefinition.
"""
import random
# ---------------------------------------------------------------------------
# Scale definitions
# ---------------------------------------------------------------------------
@@ -52,6 +54,18 @@ def _clamp_vel(v: int) -> int:
return max(1, min(127, v))
def _apply_humanize(notes, humanize):
"""Apply humanization (velocity jitter + position nudge) to note list."""
if humanize <= 0:
return notes
jitter = humanize * 5
nudge = humanize * 0.03
for n in notes:
n["vel"] = _clamp_vel(int(n["vel"] + random.uniform(-jitter, jitter)))
n["pos"] = max(0, n["pos"] + random.uniform(-nudge, nudge))
return notes
# ---------------------------------------------------------------------------
# Bass: tresillo
# ---------------------------------------------------------------------------
@@ -61,6 +75,7 @@ def bass_tresillo(
bars: int,
octave: int = 3,
velocity_mult: float = 1.0,
humanize: float = 0.0,
) -> list[dict]:
"""Reggaeton tresillo bass pattern.
@@ -90,7 +105,7 @@ def bass_tresillo(
vel = _clamp_vel(int(vel * velocity_mult))
notes.append({"pos": o + pos, "len": 0.25, "key": key_note, "vel": vel})
return notes
return _apply_humanize(notes, humanize)
# ---------------------------------------------------------------------------
@@ -103,6 +118,7 @@ def lead_hook(
octave: int = 5,
density: float = 0.6,
velocity_mult: float = 1.0,
humanize: float = 0.0,
) -> list[dict]:
"""Simple melodic hook over 4-8 bars.
@@ -154,7 +170,7 @@ def lead_hook(
else:
pos += 0.5
return notes
return _apply_humanize(notes, humanize)
# ---------------------------------------------------------------------------
@@ -166,6 +182,7 @@ def chords_block(
bars: int,
octave: int = 4,
velocity_mult: float = 1.0,
humanize: float = 0.0,
) -> list[dict]:
"""Blocked chords every 2 beats (half-bar).
@@ -231,7 +248,7 @@ def chords_block(
"vel": vel,
})
return notes
return _apply_humanize(notes, humanize)
# ---------------------------------------------------------------------------
@@ -243,6 +260,7 @@ def pad_sustain(
bars: int,
octave: int = 4,
velocity_mult: float = 1.0,
humanize: float = 0.0,
) -> list[dict]:
"""Long sustained pad notes, one per bar.