fix: real preset data for all VST2/VST3 plugins, template system with ground-truth registry
- Extracted preset data from all_plugins_v2.rpp for 14 previously broken plugins - Fixed PLUGIN_REGISTRY entries: Kontakt 7, Gullfoss, ValhallaDelay, VC 160/76, The Glue - Template parser falls back to PLUGIN_PRESETS when source RPP has fake data - Substitute Transient Master (not installed) with FabFilter Pro-C 2 - All 25 plugins now load correctly in REAPER - Added template generator scripts and ground truth references - Cleaned up temp/debug files from output/
This commit is contained in:
213
.sdd/changes/audio-clip-playlist/design.md
Normal file
213
.sdd/changes/audio-clip-playlist/design.md
Normal file
@@ -0,0 +1,213 @@
|
||||
# Design: audio-clip-playlist
|
||||
|
||||
## Context
|
||||
|
||||
The current `FLPBuilder` emits pattern-based playlist items (single 32-byte `ArrangementItem`) for all tracks. Melodic tracks with `source_type="audio"` need a different encoding: 3 consecutive 32-byte items per clip, with fixed indices `0x3FF0` / `0x8080` / `0x6440`.
|
||||
|
||||
---
|
||||
|
||||
## Architecture Decisions
|
||||
|
||||
| Decision | Choice | Rationale |
|
||||
|----------|--------|-----------|
|
||||
| Polymorphism | `to_items()` returns `list[bytes]` (3 items) vs `to_bytes()` returns `bytes` (1 item) | Avoids union-type juggling; builder collects all items uniformly |
|
||||
| `source_type` default | `"pattern"` | Existing callers unchanged; audio is opt-in |
|
||||
| Audio clip item indices | Treat `0x8080`/`0x6440`/`0x3FF0` as constants | Per-proposal risk mitigation; verified against `audio_clip_reference.flp` |
|
||||
| ChSamplePath correlation | Audio clip item precedes its `ChSamplePath` event in channel data | Builder writes items first, then channel events with sample paths already handled by `ChannelSkeletonLoader` |
|
||||
|
||||
---
|
||||
|
||||
## File Changes
|
||||
|
||||
| File | Action |
|
||||
|------|--------|
|
||||
| `src/flp_builder/arrangement.py` | Add `AudioClipItem`, constants `AUDIO_CLIP_HEADER_INDEX`, `AUDIO_CLIP_DATA_INDEX` |
|
||||
| `src/flp_builder/schema.py` | Add `source_type: str = "pattern"` field to `MelodicTrack` |
|
||||
| `src/flp_builder/builder.py` | Route on `track.source_type`; append `AudioClipItem` objects to arrangement items list |
|
||||
|
||||
---
|
||||
|
||||
## Binary Format
|
||||
|
||||
Each audio clip placement = **96 bytes** (3 × 32):
|
||||
|
||||
### Item 0 — PATTERN positioning
|
||||
```
|
||||
struct.pack("<IHHIHH HH 4B ff",
|
||||
position, # bar * ppq * 4
|
||||
0x5000, # pattern_base (distinct from drum pattern_base 0x5000)
|
||||
0x5000 + pattern_id,
|
||||
length, # num_bars * ppq * 4
|
||||
track_rvidx, # (max_tracks - 1) - track_index
|
||||
0, # group
|
||||
0x0078,
|
||||
0x0040, # flags (no mute for audio)
|
||||
64, 100, 128, 128,
|
||||
-1.0, -1.0,
|
||||
)
|
||||
```
|
||||
|
||||
### Item 1 — AUDIO_CLIP_HEADER
|
||||
```
|
||||
00 00 00 00 00 00 F0 3F 00 00 00 00 00 00 00 00
|
||||
00 03 00 00 00 50 05 00 03 00 00 F3 01 00 00
|
||||
```
|
||||
- `item_index = 0x3FF0`
|
||||
- All other bytes constant (observed from reference FLP)
|
||||
|
||||
### Item 2 — AUDIO_CLIP_DATA
|
||||
```
|
||||
78 00 40 00 40 64 80 80 00 00 80 BF 00 00 80 BF
|
||||
02 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||||
```
|
||||
- `pattern_base = 0x6440`
|
||||
- `item_index = 0x8080`
|
||||
- Remaining bytes constant
|
||||
|
||||
---
|
||||
|
||||
## Data Flow
|
||||
|
||||
```
|
||||
SongDefinition.melodic_tracks[i]
|
||||
├── source_type == "pattern" → ArrangementItem (existing path)
|
||||
└── source_type == "audio" → AudioClipItem.to_items() [3 × 32 bytes]
|
||||
│
|
||||
▼
|
||||
build_arrangement_section()
|
||||
(all items concatenated into Playlist ID233 data)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## AudioClipItem Interface
|
||||
|
||||
```python
|
||||
# src/flp_builder/arrangement.py
|
||||
|
||||
AUDIO_CLIP_HEADER_INDEX = 0x3FF0 # item_index for header item
|
||||
AUDIO_CLIP_DATA_INDEX = 0x8080 # item_index for data item
|
||||
AUDIO_CLIP_DATA_BASE = 0x6440 # pattern_base for data item
|
||||
|
||||
@dataclass
|
||||
class AudioClipItem:
|
||||
"""Playlist item referencing an audio clip via 3×32-byte structure."""
|
||||
|
||||
pattern_id: int # references the pattern containing audio notes
|
||||
bar: float # start bar (0-based)
|
||||
num_bars: float # length in bars
|
||||
track_index: int # 0-based track index
|
||||
muted: bool = False
|
||||
|
||||
def to_items(self, ppq: int = PPQ_DEFAULT, max_tracks: int = MAX_TRACKS_DEFAULT) -> list[bytes]:
|
||||
"""Return 3 consecutive 32-byte items: [PATTERN, HEADER, DATA]."""
|
||||
...
|
||||
|
||||
# Convenience: to_bytes() returns concatenation for polymorphic use
|
||||
def to_bytes(self, ppq: int = PPQ_DEFAULT, max_tracks: int = MAX_TRACKS_DEFAULT) -> bytes:
|
||||
return b"".join(self.to_items(ppq, max_tracks))
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Schema Change
|
||||
|
||||
```python
|
||||
# src/flp_builder/schema.py — MelodicTrack
|
||||
|
||||
@dataclass
|
||||
class MelodicTrack:
|
||||
role: str
|
||||
sample_path: str
|
||||
notes: list[MelodicNote]
|
||||
channel_index: int
|
||||
volume: float = 0.85
|
||||
pan: float = 0.0
|
||||
source_type: str = "pattern" # NEW: "pattern" | "audio"
|
||||
```
|
||||
|
||||
`SongDefinition.validate()` also validates:
|
||||
- `source_type in ("pattern", "audio")`
|
||||
- If `source_type == "audio"`: `channel_index >= 17`
|
||||
|
||||
---
|
||||
|
||||
## Builder Routing
|
||||
|
||||
```python
|
||||
# src/flp_builder/builder.py — _build_arrangement
|
||||
|
||||
def _build_arrangement(self, song, track_data_template):
|
||||
items: list[ArrangementItem | AudioClipItem] = []
|
||||
|
||||
# Pattern tracks → ArrangementItem (existing)
|
||||
for item in song.items:
|
||||
items.append(ArrangementItem(
|
||||
pattern_id=item.pattern,
|
||||
bar=item.bar,
|
||||
num_bars=item.bars,
|
||||
track_index=item.track - 1,
|
||||
muted=item.muted,
|
||||
))
|
||||
|
||||
# Melodic tracks → route on source_type
|
||||
drum_pattern_count = len(song.patterns)
|
||||
max_drum_track = max((it.track for it in song.items), default=1)
|
||||
|
||||
for i, mt in enumerate(song.melodic_tracks):
|
||||
pattern_id = drum_pattern_count + i + 1
|
||||
track_index = max_drum_track + i # 0-based
|
||||
|
||||
if mt.source_type == "audio":
|
||||
items.append(AudioClipItem(
|
||||
pattern_id=pattern_id,
|
||||
bar=mt.bar, # from MelodicTrack.bar (default 0.0)
|
||||
num_bars=mt.num_bars, # from MelodicTrack.num_bars (default 4.0)
|
||||
track_index=track_index,
|
||||
muted=False,
|
||||
))
|
||||
else: # "pattern"
|
||||
items.append(ArrangementItem(
|
||||
pattern_id=pattern_id,
|
||||
bar=mt.bar or 0.0,
|
||||
num_bars=mt.num_bars or 4.0,
|
||||
track_index=track_index,
|
||||
muted=False,
|
||||
))
|
||||
|
||||
return build_arrangement_section(items, track_data_template, ppq=song.meta.ppq)
|
||||
```
|
||||
|
||||
**Note**: `MelodicTrack` currently has no `bar`/`num_bars` fields. The proposal scope does not include adding them; for now audio clip items use `bar=0.0, num_bars=4.0` as placeholders until a future change extends `MelodicTrack` with timeline placement fields.
|
||||
|
||||
---
|
||||
|
||||
## ChSamplePath Correlation
|
||||
|
||||
`AudioClipItem` places a reference on the playlist. The actual sample file path is carried by `ChSamplePath` events (ID 196) in the channel data, already handled by `ChannelSkeletonLoader.load(melodic_map=...)` which patches sampler channels with the correct `.wav` paths.
|
||||
|
||||
No additional correlation is needed: the channel index on the melodic track (e.g., ch17) maps to the same channel that carries the `ChSamplePath` event. The builder ensures channel events precede arrangement events in the FLP binary.
|
||||
|
||||
---
|
||||
|
||||
## Validation Strategy
|
||||
|
||||
Binary diff against `audio_clip_reference.flp`:
|
||||
1. Generate a minimal FLP with one audio clip item
|
||||
2. Extract playlist bytes (ID 233 data, after `encode_data_event` wrapper)
|
||||
3. Compare first 96 bytes of playlist data against reference
|
||||
4. Specifically verify:
|
||||
- Bytes 0–31: pattern positioning (`PATTERN_BASE = 0x5000`)
|
||||
- Bytes 32–63: header (`item_index = 0x3FF0`)
|
||||
- Bytes 64–95: data (`pattern_base = 0x6440`, `item_index = 0x8080`)
|
||||
|
||||
If mismatch at 0x8080/0x6440: derive values from reference via `build_track_data_template`-style extraction, then update constants.
|
||||
|
||||
---
|
||||
|
||||
## Open Questions
|
||||
|
||||
| Question | Status |
|
||||
|----------|--------|
|
||||
| `MelodicTrack.bar`/`num_bars` fields needed? | Not in scope; placeholders used. Future change to add placement fields. |
|
||||
| Index pool (0x8080/0x6440) per-project vs constant? | Treated as constants per proposal risk mitigation. If FLP fails to open, switch to derivation. |
|
||||
558
ejemplos/DEL_LUNE_AL_FINDE_ITHAN_NY_JULIANNO_SOSA.rpp
Normal file
558
ejemplos/DEL_LUNE_AL_FINDE_ITHAN_NY_JULIANNO_SOSA.rpp
Normal file
@@ -0,0 +1,558 @@
|
||||
<REAPER_PROJECT 0.1 "6.0" 1737000000
|
||||
TEMPO 100 4 4
|
||||
SAMPLERATE 44100
|
||||
PLAYRATE 1 0 0.25 4
|
||||
SELECTION 0 0
|
||||
CURSOR 0
|
||||
ZOOM 100 0 0
|
||||
VZOOMEX 6 0
|
||||
PANMODE 3
|
||||
MIXERUIFLAGS 11 48
|
||||
LOOPRECOVERY 0
|
||||
TRACKNUMBER 0
|
||||
MASTERTRACKHEIGHT 60
|
||||
MASTERPEAKCOL 16576
|
||||
MASTERMUTESOLO 0
|
||||
MASTER_NCH 2
|
||||
MASTER_VOLUME 1 0
|
||||
MASTER_SEL 0
|
||||
MASTER_MUTE 0
|
||||
MASTERFXBYPASS 0
|
||||
MASTERFX_BYPASS 0
|
||||
MASTER_PANMODE 0
|
||||
MASTER_WIDTH 1
|
||||
|
||||
; =======================================================
|
||||
; PROYECTO: DEL LUNE AL FINDE - ITHAN NY ft. JULIANNO SOSA
|
||||
; BPM: 100 | TONALIDAD: Si mayor (B major)
|
||||
; AÑO: 2025 | DURACION: 2:50
|
||||
; GENERO: Urbano latino / Reggaeton moderno con influencia drill
|
||||
; MOOD: Festivo / nocturno / romantico-urbano
|
||||
; =======================================================
|
||||
|
||||
; -------------------------------------------------------
|
||||
; TRACK 1 - DRUM MACHINE PRINCIPAL
|
||||
; Kick mas redondo que en Tu Diablo (estilo reggaeton moderno)
|
||||
; Hi-hats en corcheas mas cerradas, snare electrico
|
||||
; -------------------------------------------------------
|
||||
<TRACK {22222222-0001-0001-0001-000000000001}
|
||||
NAME "DRUMS PRINCIPAL"
|
||||
PEAKCOL 16576
|
||||
BEAT -1
|
||||
AUTOMODE 0
|
||||
VOLPAN 0.9 0
|
||||
MUTESOLO 0 0 0
|
||||
IPHASE 0
|
||||
PLAYOFFS 0 1
|
||||
ISBUS 0 0
|
||||
BUSCOMP 0 0 0 0 0
|
||||
SHOWINMIX 1 0.6667 0.5 1 0.5 -1 -1 -1
|
||||
SEL 0
|
||||
REC 0 0 1 0 0 0 0
|
||||
VU 2
|
||||
TRACKHEIGHT 70 0 0 0 0 0
|
||||
NCHAN 2
|
||||
FX 1
|
||||
<FXCHAIN
|
||||
WNDRECT 0 0 0 0
|
||||
SHOW 0
|
||||
LASTSEL 0
|
||||
DOCKED 0
|
||||
; Kontakt para el kit de bateria
|
||||
<VST "VST3: Kontakt 7 (Native Instruments)" "Kontakt 7.vst3" 0 "" 0<> ""
|
||||
0 0
|
||||
PARAM 0 "Volume" 0.85
|
||||
>
|
||||
; Transient designer para el punch del kick
|
||||
<VST "VST: PrimalTap (SoundToys)" "PrimalTap.dll" 0 "" 0<> ""
|
||||
0 0
|
||||
PARAM 0 "Speed" 0.5
|
||||
PARAM 1 "Feedback" 0.2
|
||||
PARAM 2 "Mix" 0.15
|
||||
>
|
||||
>
|
||||
</TRACK>
|
||||
|
||||
; -------------------------------------------------------
|
||||
; TRACK 2 - 808 / SUB BASS (B major, melodioso)
|
||||
; 808 mas melodico que en Tu Diablo
|
||||
; Con movimiento entre notas de B major scale
|
||||
; -------------------------------------------------------
|
||||
<TRACK {22222222-0001-0001-0001-000000000002}
|
||||
NAME "808 SUB BASS - B major"
|
||||
PEAKCOL 33023
|
||||
BEAT -1
|
||||
AUTOMODE 0
|
||||
VOLPAN 0.95 0
|
||||
MUTESOLO 0 0 0
|
||||
IPHASE 0
|
||||
PLAYOFFS 0 1
|
||||
ISBUS 0 0
|
||||
SHOWINMIX 1 0.6667 0.5 1 0.5 -1 -1 -1
|
||||
SEL 0
|
||||
REC 0 0 1 0 0 0 0
|
||||
VU 2
|
||||
TRACKHEIGHT 70 0 0 0 0 0
|
||||
NCHAN 2
|
||||
FX 1
|
||||
<FXCHAIN
|
||||
WNDRECT 0 0 0 0
|
||||
SHOW 0
|
||||
LASTSEL 0
|
||||
DOCKED 0
|
||||
<VST "VST3: Kontakt 7 (Native Instruments)" "Kontakt 7.vst3" 0 "" 0<> ""
|
||||
0 0
|
||||
PARAM 0 "Volume" 0.88
|
||||
>
|
||||
; Saturacion harmonica para que se escuche en todo sistema
|
||||
<VST "VST: Decapitator (SoundToys)" "Decapitator.dll" 0 "" 1145980753<56535444454341> ""
|
||||
0 0
|
||||
PARAM 0 "Drive" 0.25
|
||||
PARAM 1 "Tone" 0.55
|
||||
PARAM 2 "Mix" 0.3
|
||||
>
|
||||
>
|
||||
</TRACK>
|
||||
|
||||
; -------------------------------------------------------
|
||||
; TRACK 3 - MELODIA PRINCIPAL (sintetizador / piano)
|
||||
; Melodia alegre/festiva en B major
|
||||
; Caracter nocturno pero mas luminoso que Tu Diablo
|
||||
; -------------------------------------------------------
|
||||
<TRACK {22222222-0001-0001-0001-000000000003}
|
||||
NAME "MELODIA LEAD - Piano/Synth"
|
||||
PEAKCOL 65280
|
||||
BEAT -1
|
||||
AUTOMODE 0
|
||||
VOLPAN 0.8 0
|
||||
MUTESOLO 0 0 0
|
||||
IPHASE 0
|
||||
PLAYOFFS 0 1
|
||||
ISBUS 0 0
|
||||
SHOWINMIX 1 0.6667 0.5 1 0.5 -1 -1 -1
|
||||
SEL 0
|
||||
REC 0 0 1 0 0 0 0
|
||||
VU 2
|
||||
TRACKHEIGHT 70 0 0 0 0 0
|
||||
NCHAN 2
|
||||
FX 1
|
||||
<FXCHAIN
|
||||
WNDRECT 0 0 0 0
|
||||
SHOW 0
|
||||
LASTSEL 0
|
||||
DOCKED 0
|
||||
; Serum2 para la melodia principal
|
||||
<VST "VST3: Serum 2 (Xfer Records)" "Serum2.vst3" 0 "" 0<> ""
|
||||
0 0
|
||||
PARAM 0 "Volume" 0.78
|
||||
>
|
||||
; Reverb de sala mediana para la melodia
|
||||
<VST "VST: ValhallaDelay x64 (Valhalla DSP)" "ValhallaDelay_x64.dll" 0 "" 0<> ""
|
||||
0 0
|
||||
PARAM 0 "Mix" 0.2
|
||||
PARAM 1 "Feedback" 0.35
|
||||
PARAM 2 "Time" 0.45
|
||||
>
|
||||
; Chorus / width para engordar la melodia
|
||||
<VST "VST: MicroShift (SoundToys)" "MicroShift.dll" 0 "" 0<> ""
|
||||
0 0
|
||||
PARAM 0 "Width" 0.6
|
||||
PARAM 1 "Mix" 0.45
|
||||
>
|
||||
>
|
||||
</TRACK>
|
||||
|
||||
; -------------------------------------------------------
|
||||
; TRACK 4 - ARPEGIO / SYNTH LEAD 2 (contrapunto)
|
||||
; Segundo elemento melodico con arpegiador
|
||||
; Muy tipico del urbano chileno 2025
|
||||
; -------------------------------------------------------
|
||||
<TRACK {22222222-0001-0001-0001-000000000004}
|
||||
NAME "ARPEGIO SYNTH 2"
|
||||
PEAKCOL 16711935
|
||||
BEAT -1
|
||||
AUTOMODE 0
|
||||
VOLPAN 0.65 0.1
|
||||
MUTESOLO 0 0 0
|
||||
IPHASE 0
|
||||
PLAYOFFS 0 1
|
||||
ISBUS 0 0
|
||||
SHOWINMIX 1 0.6667 0.5 1 0.5 -1 -1 -1
|
||||
SEL 0
|
||||
REC 0 0 1 0 0 0 0
|
||||
VU 2
|
||||
TRACKHEIGHT 70 0 0 0 0 0
|
||||
NCHAN 2
|
||||
FX 1
|
||||
<FXCHAIN
|
||||
WNDRECT 0 0 0 0
|
||||
SHOW 0
|
||||
LASTSEL 0
|
||||
DOCKED 0
|
||||
; Pigments para arpegio / lead 2
|
||||
<VST "VST3: Pigments (Arturia)" "Pigments.exe" 0 "" 0<> ""
|
||||
0 0
|
||||
PARAM 0 "Volume" 0.7
|
||||
PARAM 1 "Pan" 0.0
|
||||
>
|
||||
; Tremolo ritmico en el arpegio
|
||||
<VST "VST: Tremolator (SoundToys)" "Tremolator.dll" 0 "" 0<> ""
|
||||
0 0
|
||||
PARAM 0 "Depth" 0.5
|
||||
PARAM 1 "Rate" 0.5
|
||||
PARAM 2 "Mix" 0.45
|
||||
>
|
||||
>
|
||||
</TRACK>
|
||||
|
||||
; -------------------------------------------------------
|
||||
; TRACK 5 - PAD DE RELLENO (sustain armonico)
|
||||
; Pad ancho que llena el espacio estereo
|
||||
; Armonia de B major sostenida
|
||||
; -------------------------------------------------------
|
||||
<TRACK {22222222-0001-0001-0001-000000000005}
|
||||
NAME "PAD ARMONICO - Relleno"
|
||||
PEAKCOL 8388607
|
||||
BEAT -1
|
||||
AUTOMODE 0
|
||||
VOLPAN 0.55 0
|
||||
MUTESOLO 0 0 0
|
||||
IPHASE 0
|
||||
PLAYOFFS 0 1
|
||||
ISBUS 0 0
|
||||
SHOWINMIX 1 0.6667 0.5 1 0.5 -1 -1 -1
|
||||
SEL 0
|
||||
REC 0 0 1 0 0 0 0
|
||||
VU 2
|
||||
TRACKHEIGHT 70 0 0 0 0 0
|
||||
NCHAN 2
|
||||
FX 1
|
||||
<FXCHAIN
|
||||
WNDRECT 0 0 0 0
|
||||
SHOW 0
|
||||
LASTSEL 0
|
||||
DOCKED 0
|
||||
; Omnisphere para el pad de fondo
|
||||
<VST "VST3: Omnisphere (Spectrasonics)" "Omnisphere.vst3" 0 "" 0<> ""
|
||||
0 0
|
||||
PARAM 0 "Volume" 0.65
|
||||
>
|
||||
; Modulacion sutil en el pad
|
||||
<VST "VST: PhaseMistress (SoundToys)" "PhaseMistress.dll" 0 "" 1347371358<56535450484153> ""
|
||||
0 0
|
||||
PARAM 0 "Speed" 0.15
|
||||
PARAM 1 "Depth" 0.35
|
||||
PARAM 2 "Mix" 0.25
|
||||
>
|
||||
>
|
||||
</TRACK>
|
||||
|
||||
; -------------------------------------------------------
|
||||
; TRACK 6 - VOZ LEAD ITHAN NY
|
||||
; Estilo festivo, autotune medio (menos aggressive que Tu Diablo)
|
||||
; Voz mas clara, presencia mas frontal
|
||||
; -------------------------------------------------------
|
||||
<TRACK {22222222-0001-0001-0001-000000000006}
|
||||
NAME "VOZ LEAD - ITHAN NY"
|
||||
PEAKCOL 16711680
|
||||
BEAT -1
|
||||
AUTOMODE 0
|
||||
VOLPAN 0.9 0
|
||||
MUTESOLO 0 0 0
|
||||
IPHASE 0
|
||||
PLAYOFFS 0 1
|
||||
ISBUS 0 0
|
||||
SHOWINMIX 1 0.6667 0.5 1 0.5 -1 -1 -1
|
||||
SEL 0
|
||||
REC 0 0 1 0 0 0 0
|
||||
VU 2
|
||||
TRACKHEIGHT 70 0 0 0 0 0
|
||||
NCHAN 2
|
||||
FX 1
|
||||
<FXCHAIN
|
||||
WNDRECT 0 0 0 0
|
||||
SHOW 0
|
||||
LASTSEL 0
|
||||
DOCKED 0
|
||||
; Compresor FET agresivo para voz urbana
|
||||
<VST "VST3: VC 76 FX (Audified)" "VC 76.vst3" 0 "" 0<> ""
|
||||
0 0
|
||||
PARAM 0 "Threshold" 0.6
|
||||
PARAM 1 "Ratio" 0.7
|
||||
PARAM 2 "Attack" 0.25
|
||||
PARAM 3 "Release" 0.5
|
||||
PARAM 4 "Gain" 0.55
|
||||
>
|
||||
; Saturacion para presencia en voz
|
||||
<VST "VST: Radiator (SoundToys)" "Radiator.dll" 0 "" 1380012882<56535452414449> ""
|
||||
0 0
|
||||
PARAM 0 "Drive" 0.2
|
||||
PARAM 1 "Mix" 0.35
|
||||
>
|
||||
; Delay con mucho swing/groove
|
||||
<VST "VST: EchoBoy (SoundToys)" "EchoBoy.dll" 0 "" 1163022169<565354454348> ""
|
||||
0 0
|
||||
PARAM 0 "Mix" 0.22
|
||||
PARAM 1 "Time" 0.52
|
||||
PARAM 2 "Feedback" 0.28
|
||||
>
|
||||
; Reverb de habitacion / plate
|
||||
<VST "VST: EffectRack (SoundToys)" "EffectRack.dll" 0 "" 0<> ""
|
||||
0 0
|
||||
>
|
||||
>
|
||||
</TRACK>
|
||||
|
||||
; -------------------------------------------------------
|
||||
; TRACK 7 - VOZ JULIANNO SOSA
|
||||
; Voz mas profunda / tone diferente al de ITHAN
|
||||
; Autotune sutil, mas melodico
|
||||
; -------------------------------------------------------
|
||||
<TRACK {22222222-0001-0001-0001-000000000007}
|
||||
NAME "VOZ - JULIANNO SOSA"
|
||||
PEAKCOL 255
|
||||
BEAT -1
|
||||
AUTOMODE 0
|
||||
VOLPAN 0.85 0
|
||||
MUTESOLO 0 0 0
|
||||
IPHASE 0
|
||||
PLAYOFFS 0 1
|
||||
ISBUS 0 0
|
||||
SHOWINMIX 1 0.6667 0.5 1 0.5 -1 -1 -1
|
||||
SEL 0
|
||||
REC 0 0 1 0 0 0 0
|
||||
VU 2
|
||||
TRACKHEIGHT 70 0 0 0 0 0
|
||||
NCHAN 2
|
||||
FX 1
|
||||
<FXCHAIN
|
||||
WNDRECT 0 0 0 0
|
||||
SHOW 0
|
||||
LASTSEL 0
|
||||
DOCKED 0
|
||||
; Compresor VCA mas suave para voz de Julianno
|
||||
<VST "VST3: VC 160 FX (Audified)" "VC 160.vst3" 0 "" 0<> ""
|
||||
0 0
|
||||
PARAM 0 "Threshold" 0.5
|
||||
PARAM 1 "Ratio" 0.6
|
||||
PARAM 2 "Attack" 0.35
|
||||
PARAM 3 "Release" 0.5
|
||||
>
|
||||
; Saturacion leve
|
||||
<VST "VST: Radiator (SoundToys)" "Radiator.dll" 0 "" 1380012882<56535452414449> ""
|
||||
0 0
|
||||
PARAM 0 "Drive" 0.15
|
||||
PARAM 1 "Mix" 0.25
|
||||
>
|
||||
; Delay mas notable en Julianno (mas melodico)
|
||||
<VST "VST: EchoBoy (SoundToys)" "EchoBoy.dll" 0 "" 1163022169<565354454348> ""
|
||||
0 0
|
||||
PARAM 0 "Mix" 0.25
|
||||
PARAM 1 "Time" 0.55
|
||||
PARAM 2 "Feedback" 0.32
|
||||
>
|
||||
>
|
||||
</TRACK>
|
||||
|
||||
; -------------------------------------------------------
|
||||
; TRACK 8 - BACKGROUNDS / COROS
|
||||
; Voces de fondo que apoyan en el coro
|
||||
; -------------------------------------------------------
|
||||
<TRACK {22222222-0001-0001-0001-000000000008}
|
||||
NAME "COROS / BG VOCALS"
|
||||
PEAKCOL 8421504
|
||||
BEAT -1
|
||||
AUTOMODE 0
|
||||
VOLPAN 0.6 0
|
||||
MUTESOLO 0 0 0
|
||||
IPHASE 0
|
||||
PLAYOFFS 0 1
|
||||
ISBUS 0 0
|
||||
SHOWINMIX 1 0.6667 0.5 1 0.5 -1 -1 -1
|
||||
SEL 0
|
||||
REC 0 0 1 0 0 0 0
|
||||
VU 2
|
||||
TRACKHEIGHT 70 0 0 0 0 0
|
||||
NCHAN 2
|
||||
FX 1
|
||||
<FXCHAIN
|
||||
WNDRECT 0 0 0 0
|
||||
SHOW 0
|
||||
LASTSEL 0
|
||||
DOCKED 0
|
||||
; Pitch shift para harmonias
|
||||
<VST "VST: LittlePrimalTap (SoundToys)" "LittlePrimalTap.dll" 0 "" 0<> ""
|
||||
0 0
|
||||
PARAM 0 "Speed" 0.5
|
||||
PARAM 1 "Mix" 0.45
|
||||
>
|
||||
; Width en las voces de fondo
|
||||
<VST "VST: MicroShift (SoundToys)" "MicroShift.dll" 0 "" 0<> ""
|
||||
0 0
|
||||
PARAM 0 "Width" 0.7
|
||||
PARAM 1 "Mix" 0.55
|
||||
>
|
||||
; Reverb grande para los coros
|
||||
<VST "VST: ValhallaDelay x64 (Valhalla DSP)" "ValhallaDelay_x64.dll" 0 "" 0<> ""
|
||||
0 0
|
||||
PARAM 0 "Mix" 0.35
|
||||
PARAM 1 "Feedback" 0.4
|
||||
>
|
||||
>
|
||||
</TRACK>
|
||||
|
||||
; -------------------------------------------------------
|
||||
; TRACK 9 - PERCUSION ADICIONAL (congas / claps / shaker)
|
||||
; Groove mas bailable comparado a Tu Diablo
|
||||
; -------------------------------------------------------
|
||||
<TRACK {22222222-0001-0001-0001-000000000009}
|
||||
NAME "PERCUSION - Groove Layer"
|
||||
PEAKCOL 16776960
|
||||
BEAT -1
|
||||
AUTOMODE 0
|
||||
VOLPAN 0.7 0
|
||||
MUTESOLO 0 0 0
|
||||
IPHASE 0
|
||||
PLAYOFFS 0 1
|
||||
ISBUS 0 0
|
||||
SHOWINMIX 1 0.6667 0.5 1 0.5 -1 -1 -1
|
||||
SEL 0
|
||||
REC 0 0 1 0 0 0 0
|
||||
VU 2
|
||||
TRACKHEIGHT 70 0 0 0 0 0
|
||||
NCHAN 2
|
||||
FX 1
|
||||
<FXCHAIN
|
||||
WNDRECT 0 0 0 0
|
||||
SHOW 0
|
||||
LASTSEL 0
|
||||
DOCKED 0
|
||||
<VST "VST3: Kontakt 7 (Native Instruments)" "Kontakt 7.vst3" 0 "" 0<> ""
|
||||
0 0
|
||||
PARAM 0 "Volume" 0.75
|
||||
>
|
||||
; Filtro que da groove a la percusion
|
||||
<VST "VST: FilterFreak2 (SoundToys)" "FilterFreak2.dll" 0 "" 0<> ""
|
||||
0 0
|
||||
PARAM 0 "Cutoff" 0.7
|
||||
PARAM 1 "Resonance" 0.25
|
||||
PARAM 2 "Mix" 0.35
|
||||
>
|
||||
>
|
||||
</TRACK>
|
||||
|
||||
; -------------------------------------------------------
|
||||
; TRACK 10 - FX TRANSICIONES / RISERS / IMPACTS
|
||||
; Elementos de transicion entre secciones
|
||||
; -------------------------------------------------------
|
||||
<TRACK {22222222-0001-0001-0001-000000000010}
|
||||
NAME "FX TRANSITIONS"
|
||||
PEAKCOL 16711808
|
||||
BEAT -1
|
||||
AUTOMODE 0
|
||||
VOLPAN 0.65 0
|
||||
MUTESOLO 0 0 0
|
||||
IPHASE 0
|
||||
PLAYOFFS 0 1
|
||||
ISBUS 0 0
|
||||
SHOWINMIX 1 0.6667 0.5 1 0.5 -1 -1 -1
|
||||
SEL 0
|
||||
REC 0 0 1 0 0 0 0
|
||||
VU 2
|
||||
TRACKHEIGHT 70 0 0 0 0 0
|
||||
NCHAN 2
|
||||
FX 1
|
||||
<FXCHAIN
|
||||
WNDRECT 0 0 0 0
|
||||
SHOW 0
|
||||
LASTSEL 0
|
||||
DOCKED 0
|
||||
; Crystallizer para efectos de pitch/reverb en transiciones
|
||||
<VST "VST: Crystallizer (SoundToys)" "Crystallizer.dll" 0 "" 0<> ""
|
||||
0 0
|
||||
PARAM 0 "Pitch" 0.0
|
||||
PARAM 1 "Size" 0.6
|
||||
PARAM 2 "Mix" 0.5
|
||||
PARAM 3 "Feedback" 0.3
|
||||
>
|
||||
>
|
||||
</TRACK>
|
||||
|
||||
; -------------------------------------------------------
|
||||
; TRACK 11 - BUS PARALELO (parallel compression)
|
||||
; Compresor en paralelo para glue general
|
||||
; -------------------------------------------------------
|
||||
<TRACK {22222222-0001-0001-0001-000000000011}
|
||||
NAME "PARALLEL COMP BUS"
|
||||
PEAKCOL 4210752
|
||||
BEAT -1
|
||||
AUTOMODE 0
|
||||
VOLPAN 0.4 0
|
||||
MUTESOLO 0 0 0
|
||||
IPHASE 0
|
||||
PLAYOFFS 0 1
|
||||
ISBUS 1 0
|
||||
SHOWINMIX 1 0.6667 0.5 1 0.5 -1 -1 -1
|
||||
SEL 0
|
||||
REC 0 0 1 0 0 0 0
|
||||
VU 2
|
||||
TRACKHEIGHT 70 0 0 0 0 0
|
||||
NCHAN 2
|
||||
FX 1
|
||||
<FXCHAIN
|
||||
WNDRECT 0 0 0 0
|
||||
SHOW 0
|
||||
LASTSEL 0
|
||||
DOCKED 0
|
||||
<VST "VST3: VC 2A FX (Audified)" "VC 2A.vst3" 0 "" 0<> ""
|
||||
0 0
|
||||
PARAM 0 "Peak Reduction" 0.7
|
||||
PARAM 1 "Gain" 0.55
|
||||
PARAM 2 "Mix" 1.0
|
||||
>
|
||||
>
|
||||
</TRACK>
|
||||
|
||||
; -------------------------------------------------------
|
||||
; TRACK 12 - MASTER BUS
|
||||
; -------------------------------------------------------
|
||||
<TRACK {22222222-0001-0001-0001-000000000012}
|
||||
NAME "MASTER BUS"
|
||||
PEAKCOL 16777215
|
||||
BEAT -1
|
||||
AUTOMODE 0
|
||||
VOLPAN 1.0 0
|
||||
MUTESOLO 0 0 0
|
||||
IPHASE 0
|
||||
PLAYOFFS 0 1
|
||||
ISBUS 1 0
|
||||
BUSCOMP 0 0 0 0 0
|
||||
SHOWINMIX 1 0.6667 0.5 1 0.5 -1 -1 -1
|
||||
SEL 0
|
||||
REC 0 0 1 0 0 0 0
|
||||
VU 2
|
||||
TRACKHEIGHT 70 0 0 0 0 0
|
||||
NCHAN 2
|
||||
FX 1
|
||||
<FXCHAIN
|
||||
WNDRECT 0 0 0 0
|
||||
SHOW 0
|
||||
LASTSEL 0
|
||||
DOCKED 0
|
||||
; Gullfoss Live para balance espectral en master
|
||||
<VST "VST: Gullfoss Live (Soundtheory)" "Gullfoss Live.dll" 0 "" 0<> ""
|
||||
0 0
|
||||
PARAM 0 "Recover" 0.25
|
||||
PARAM 1 "Tame" 0.45
|
||||
PARAM 2 "Bias" 0.05
|
||||
>
|
||||
; Limiter / maximizer final
|
||||
<VST "VST: Gullfoss Master (Soundtheory)" "Gullfoss Master.dll" 0 "" 0<> ""
|
||||
0 0
|
||||
PARAM 0 "Recover" 0.3
|
||||
PARAM 1 "Tame" 0.5
|
||||
>
|
||||
>
|
||||
</TRACK>
|
||||
|
||||
</REAPER_PROJECT>
|
||||
531
ejemplos/TU_DIABLO_ITHAN_NY.rpp
Normal file
531
ejemplos/TU_DIABLO_ITHAN_NY.rpp
Normal file
@@ -0,0 +1,531 @@
|
||||
<REAPER_PROJECT 0.1 "6.0" 1699000000
|
||||
TEMPO 99 4 4
|
||||
SAMPLERATE 44100
|
||||
PLAYRATE 1 0 0.25 4
|
||||
SELECTION 0 0
|
||||
CURSOR 0
|
||||
ZOOM 100 0 0
|
||||
VZOOMEX 6 0
|
||||
PANMODE 3
|
||||
MIXERUIFLAGS 11 48
|
||||
LOOPRECOVERY 0
|
||||
TRACKNUMBER 0
|
||||
MASTERTRACKHEIGHT 60
|
||||
MASTERPEAKCOL 16576
|
||||
MASTERMUTESOLO 0
|
||||
MASTER_NCH 2
|
||||
MASTER_VOLUME 1 0
|
||||
MASTER_SEL 0
|
||||
MASTER_MUTE 0
|
||||
MASTERFXBYPASS 0
|
||||
MASTERFX_BYPASS 0
|
||||
MASTER_PANMODE 0
|
||||
MASTER_WIDTH 1
|
||||
POOLEDENVATTACHED 0
|
||||
RENDER_FILE ""
|
||||
RENDER_PATTERN ""
|
||||
RENDER_FMT 0 2 0
|
||||
RENDER_1X 0
|
||||
RENDER_RANGE 1 0 0 18 1000
|
||||
RENDER_RESAMPLE 3 0 1
|
||||
RENDER_ADDTOPROJ 0
|
||||
RENDER_STEMS 0
|
||||
RENDER_DITHER 0
|
||||
TIMELOCKMODE 1
|
||||
TEMPOENVLOCKMODE 1
|
||||
ITEMMIX 1
|
||||
DEFPITCHMODE 589824 0
|
||||
TAKELANE 1
|
||||
SWTCHDELETE 0
|
||||
|
||||
<NOTES 0 2
|
||||
>
|
||||
RIPPLE 0
|
||||
GROUPOVERRIDE 0 0 0
|
||||
AUTOXFADE 129
|
||||
ENVATTACH 1
|
||||
POOLEDENVATTACH 0
|
||||
OVERLAPS 1
|
||||
LOOPRECFLAG 0
|
||||
TUNER 0
|
||||
STROBOSCOPE 0
|
||||
REAPER_METADATA "" ""
|
||||
|
||||
; =======================================================
|
||||
; PROYECTO: TU DIABLO - ITHAN NY
|
||||
; BPM: 99 | TONALIDAD: Mi menor (E minor)
|
||||
; PRODUCER: Donner | AÑO: 2022
|
||||
; GENERO: Urbano latino / Drill chileno
|
||||
; SAMPLE BASE: "Yo Sé Que Tú Quieres" - Sammy & Falsetto
|
||||
; =======================================================
|
||||
|
||||
; -------------------------------------------------------
|
||||
; TRACK 1 - BEAT / DRUM MACHINE (808 + Hi-Hats + Kick)
|
||||
; Kick seco tipo drill, 808 sub con mucha presencia
|
||||
; Hi-hats en corcheas triplets con rolls
|
||||
; -------------------------------------------------------
|
||||
<TRACK {11111111-0001-0001-0001-000000000001}
|
||||
NAME "DRUMS - 808 BEAT"
|
||||
PEAKCOL 16576
|
||||
BEAT -1
|
||||
AUTOMODE 0
|
||||
VOLPAN 0.9 0
|
||||
MUTESOLO 0 0 0
|
||||
IPHASE 0
|
||||
PLAYOFFS 0 1
|
||||
ISBUS 0 0
|
||||
BUSCOMP 0 0 0 0 0
|
||||
SHOWINMIX 1 0.6667 0.5 1 0.5 -1 -1 -1
|
||||
SEL 0
|
||||
REC 0 0 1 0 0 0 0
|
||||
VU 2
|
||||
TRACKHEIGHT 70 0 0 0 0 0
|
||||
INQ 0 0 0 0.5 100 0 0 100
|
||||
NCHAN 2
|
||||
FX 1
|
||||
FXCHAIN_REC 0
|
||||
<FXCHAIN
|
||||
WNDRECT 0 0 0 0
|
||||
SHOW 0
|
||||
LASTSEL 0
|
||||
DOCKED 0
|
||||
; --- Transient Shaper: controla el ataque del kick ---
|
||||
<VST "VST: Transient Master (Native Instruments)" "Transient Master.dll" 0 "" 1349676904<5653544E49544D00> ""
|
||||
0 0
|
||||
>
|
||||
; --- Compresor con saturacion en el bus de bateria ---
|
||||
<VST "VST: Decapitator (SoundToys)" "Decapitator.dll" 0 "" 1145980753<56535444454341> ""
|
||||
0 0
|
||||
PARAM 0 "Drive" 0.35
|
||||
PARAM 1 "Tone" 0.5
|
||||
PARAM 2 "Mix" 0.4
|
||||
>
|
||||
<VST "VST: Radiator (SoundToys)" "Radiator.dll" 0 "" 1380012882<56535452414449> ""
|
||||
0 0
|
||||
PARAM 0 "Drive" 0.25
|
||||
PARAM 1 "Mix" 0.3
|
||||
>
|
||||
>
|
||||
</TRACK>
|
||||
|
||||
; -------------------------------------------------------
|
||||
; TRACK 2 - 808 SUB BASS (fundamental del drill)
|
||||
; Sub muy profundo, pitcheado en E minor
|
||||
; Con glide/portamento entre notas
|
||||
; -------------------------------------------------------
|
||||
<TRACK {11111111-0001-0001-0001-000000000002}
|
||||
NAME "808 SUB BASS"
|
||||
PEAKCOL 33023
|
||||
BEAT -1
|
||||
AUTOMODE 0
|
||||
VOLPAN 1.0 0
|
||||
MUTESOLO 0 0 0
|
||||
IPHASE 0
|
||||
PLAYOFFS 0 1
|
||||
ISBUS 0 0
|
||||
BUSCOMP 0 0 0 0 0
|
||||
SHOWINMIX 1 0.6667 0.5 1 0.5 -1 -1 -1
|
||||
SEL 0
|
||||
REC 0 0 1 0 0 0 0
|
||||
VU 2
|
||||
TRACKHEIGHT 70 0 0 0 0 0
|
||||
NCHAN 2
|
||||
FX 1
|
||||
<FXCHAIN
|
||||
WNDRECT 0 0 0 0
|
||||
SHOW 0
|
||||
LASTSEL 0
|
||||
DOCKED 0
|
||||
; Kontakt con patch de 808 sub
|
||||
<VST "VST3: Kontakt 7 (Native Instruments)" "Kontakt 7.vst3" 0 "" 1315270729<> ""
|
||||
0 0
|
||||
PARAM 0 "Volume" 0.85
|
||||
>
|
||||
; Saturacion leve para que corte en monitores pequeños
|
||||
<VST "VST: Decapitator (SoundToys)" "Decapitator.dll" 0 "" 1145980753<56535444454341> ""
|
||||
0 0
|
||||
PARAM 0 "Drive" 0.2
|
||||
PARAM 2 "Mix" 0.35
|
||||
>
|
||||
; Compresor para controlar el sustain del 808
|
||||
<VST "VST: Gullfoss Master (Soundtheory)" "Gullfoss Master.dll" 0 "" 0<> ""
|
||||
0 0
|
||||
PARAM 0 "Recover" 0.4
|
||||
PARAM 1 "Tame" 0.5
|
||||
>
|
||||
>
|
||||
</TRACK>
|
||||
|
||||
; -------------------------------------------------------
|
||||
; TRACK 3 - MELODIA SAMPLE (loop de "Yo Se Que Tu Quieres")
|
||||
; Sample pitcheado y cortado, base melodica de la cancion
|
||||
; Atmosfera oscura / misteriosa
|
||||
; -------------------------------------------------------
|
||||
<TRACK {11111111-0001-0001-0001-000000000003}
|
||||
NAME "SAMPLE LOOP - Melodia"
|
||||
PEAKCOL 65280
|
||||
BEAT -1
|
||||
AUTOMODE 0
|
||||
VOLPAN 0.75 0
|
||||
MUTESOLO 0 0 0
|
||||
IPHASE 0
|
||||
PLAYOFFS 0 1
|
||||
ISBUS 0 0
|
||||
BUSCOMP 0 0 0 0 0
|
||||
SHOWINMIX 1 0.6667 0.5 1 0.5 -1 -1 -1
|
||||
SEL 0
|
||||
REC 0 0 1 0 0 0 0
|
||||
VU 2
|
||||
TRACKHEIGHT 70 0 0 0 0 0
|
||||
NCHAN 2
|
||||
FX 1
|
||||
<FXCHAIN
|
||||
WNDRECT 0 0 0 0
|
||||
SHOW 0
|
||||
LASTSEL 0
|
||||
DOCKED 0
|
||||
; Efecto de reverb oscuro para el sample
|
||||
<VST "VST: EchoBoy (SoundToys)" "EchoBoy.dll" 0 "" 1163022169<565354454348> ""
|
||||
0 0
|
||||
PARAM 0 "Mix" 0.25
|
||||
PARAM 1 "Time" 0.4
|
||||
>
|
||||
<VST "VST: PhaseMistress (SoundToys)" "PhaseMistress.dll" 0 "" 1347371358<56535450484153> ""
|
||||
0 0
|
||||
PARAM 0 "Speed" 0.2
|
||||
PARAM 1 "Depth" 0.4
|
||||
PARAM 2 "Mix" 0.2
|
||||
>
|
||||
>
|
||||
</TRACK>
|
||||
|
||||
; -------------------------------------------------------
|
||||
; TRACK 4 - PAD SINTETICO (ambiente oscuro / minor)
|
||||
; Pad que sostiene la tension armonica en Em
|
||||
; -------------------------------------------------------
|
||||
<TRACK {11111111-0001-0001-0001-000000000004}
|
||||
NAME "PAD SINTETICO - Atmosfera"
|
||||
PEAKCOL 16711935
|
||||
BEAT -1
|
||||
AUTOMODE 0
|
||||
VOLPAN 0.6 0
|
||||
MUTESOLO 0 0 0
|
||||
IPHASE 0
|
||||
PLAYOFFS 0 1
|
||||
ISBUS 0 0
|
||||
SHOWINMIX 1 0.6667 0.5 1 0.5 -1 -1 -1
|
||||
SEL 0
|
||||
REC 0 0 1 0 0 0 0
|
||||
VU 2
|
||||
TRACKHEIGHT 70 0 0 0 0 0
|
||||
NCHAN 2
|
||||
FX 1
|
||||
<FXCHAIN
|
||||
WNDRECT 0 0 0 0
|
||||
SHOW 0
|
||||
LASTSEL 0
|
||||
DOCKED 0
|
||||
; Diva para el pad sintetico oscuro
|
||||
<VST "VST3: Diva (u-he)" "Diva(x64).vst3" 0 "" 0<> ""
|
||||
0 0
|
||||
PARAM 0 "Volume" 0.7
|
||||
PARAM 1 "Pan" 0.0
|
||||
>
|
||||
; Reverb de sala para el pad
|
||||
<VST "VST: ValhallaDelay x64 (Valhalla DSP)" "ValhallaDelay_x64.dll" 0 "" 0<> ""
|
||||
0 0
|
||||
PARAM 0 "Mix" 0.35
|
||||
PARAM 1 "Feedback" 0.45
|
||||
>
|
||||
>
|
||||
</TRACK>
|
||||
|
||||
; -------------------------------------------------------
|
||||
; TRACK 5 - MELODIA LEAD (sintetizador principal)
|
||||
; Melodia tenebrosa caracteristica del track
|
||||
; -------------------------------------------------------
|
||||
<TRACK {11111111-0001-0001-0001-000000000005}
|
||||
NAME "LEAD MELODIA"
|
||||
PEAKCOL 65535
|
||||
BEAT -1
|
||||
AUTOMODE 0
|
||||
VOLPAN 0.8 0
|
||||
MUTESOLO 0 0 0
|
||||
IPHASE 0
|
||||
PLAYOFFS 0 1
|
||||
ISBUS 0 0
|
||||
SHOWINMIX 1 0.6667 0.5 1 0.5 -1 -1 -1
|
||||
SEL 0
|
||||
REC 0 0 1 0 0 0 0
|
||||
VU 2
|
||||
TRACKHEIGHT 70 0 0 0 0 0
|
||||
NCHAN 2
|
||||
FX 1
|
||||
<FXCHAIN
|
||||
WNDRECT 0 0 0 0
|
||||
SHOW 0
|
||||
LASTSEL 0
|
||||
DOCKED 0
|
||||
<VST "VST3: Serum 2 (Xfer Records)" "Serum2.vst3" 0 "" 0<> ""
|
||||
0 0
|
||||
PARAM 0 "Volume" 0.75
|
||||
>
|
||||
<VST "VST: Tremolator (SoundToys)" "Tremolator.dll" 0 "" 1414677358<56535454524D4C> ""
|
||||
0 0
|
||||
PARAM 0 "Depth" 0.3
|
||||
PARAM 1 "Rate" 0.5
|
||||
PARAM 2 "Mix" 0.2
|
||||
>
|
||||
>
|
||||
</TRACK>
|
||||
|
||||
; -------------------------------------------------------
|
||||
; TRACK 6 - VOZ PRINCIPAL (ITHAN NY)
|
||||
; Voz con autotune pesado, reverb corto
|
||||
; Procesamiento tipo trap/drill chileno
|
||||
; -------------------------------------------------------
|
||||
<TRACK {11111111-0001-0001-0001-000000000006}
|
||||
NAME "VOZ LEAD - ITHAN NY"
|
||||
PEAKCOL 16711680
|
||||
BEAT -1
|
||||
AUTOMODE 0
|
||||
VOLPAN 0.9 0
|
||||
MUTESOLO 0 0 0
|
||||
IPHASE 0
|
||||
PLAYOFFS 0 1
|
||||
ISBUS 0 0
|
||||
SHOWINMIX 1 0.6667 0.5 1 0.5 -1 -1 -1
|
||||
SEL 0
|
||||
REC 0 0 1 0 0 0 0
|
||||
VU 2
|
||||
TRACKHEIGHT 70 0 0 0 0 0
|
||||
NCHAN 2
|
||||
FX 1
|
||||
<FXCHAIN
|
||||
WNDRECT 0 0 0 0
|
||||
SHOW 0
|
||||
LASTSEL 0
|
||||
DOCKED 0
|
||||
; Compresor VCA para controlar dinamica de voz
|
||||
<VST "VST3: VC 160 FX (Audified)" "VC 160.vst3" 0 "" 0<> ""
|
||||
0 0
|
||||
PARAM 0 "Threshold" 0.55
|
||||
PARAM 1 "Ratio" 0.7
|
||||
PARAM 2 "Attack" 0.3
|
||||
PARAM 3 "Release" 0.45
|
||||
>
|
||||
; Saturacion suave en voz
|
||||
<VST "VST: Radiator (SoundToys)" "Radiator.dll" 0 "" 1380012882<56535452414449> ""
|
||||
0 0
|
||||
PARAM 0 "Drive" 0.15
|
||||
PARAM 1 "Mix" 0.3
|
||||
>
|
||||
; Delay en voz estilo trap (quarter note)
|
||||
<VST "VST: EchoBoy (SoundToys)" "EchoBoy.dll" 0 "" 1163022169<565354454348> ""
|
||||
0 0
|
||||
PARAM 0 "Mix" 0.2
|
||||
PARAM 1 "Time" 0.5
|
||||
PARAM 2 "Feedback" 0.3
|
||||
>
|
||||
; Reverb de sala corta
|
||||
<VST "VST: EffectRack (SoundToys)" "EffectRack.dll" 0 "" 0<> ""
|
||||
0 0
|
||||
>
|
||||
>
|
||||
</TRACK>
|
||||
|
||||
; -------------------------------------------------------
|
||||
; TRACK 7 - VOZ TUNECHIKIDD
|
||||
; -------------------------------------------------------
|
||||
<TRACK {11111111-0001-0001-0001-000000000007}
|
||||
NAME "VOZ - TUNECHIKIDD"
|
||||
PEAKCOL 16744448
|
||||
BEAT -1
|
||||
AUTOMODE 0
|
||||
VOLPAN 0.8 -0.15
|
||||
MUTESOLO 0 0 0
|
||||
IPHASE 0
|
||||
PLAYOFFS 0 1
|
||||
ISBUS 0 0
|
||||
SHOWINMIX 1 0.6667 0.5 1 0.5 -1 -1 -1
|
||||
SEL 0
|
||||
REC 0 0 1 0 0 0 0
|
||||
VU 2
|
||||
TRACKHEIGHT 70 0 0 0 0 0
|
||||
NCHAN 2
|
||||
FX 1
|
||||
<FXCHAIN
|
||||
WNDRECT 0 0 0 0
|
||||
SHOW 0
|
||||
LASTSEL 0
|
||||
DOCKED 0
|
||||
<VST "VST3: VC 76 FX (Audified)" "VC 76.vst3" 0 "" 0<> ""
|
||||
0 0
|
||||
PARAM 0 "Threshold" 0.5
|
||||
PARAM 1 "Ratio" 0.65
|
||||
>
|
||||
<VST "VST: EchoBoy (SoundToys)" "EchoBoy.dll" 0 "" 1163022169<565354454348> ""
|
||||
0 0
|
||||
PARAM 0 "Mix" 0.18
|
||||
PARAM 1 "Time" 0.48
|
||||
>
|
||||
>
|
||||
</TRACK>
|
||||
|
||||
; -------------------------------------------------------
|
||||
; TRACK 8 - VOZ NICKOOG CLK
|
||||
; -------------------------------------------------------
|
||||
<TRACK {11111111-0001-0001-0001-000000000008}
|
||||
NAME "VOZ - NICKOOG CLK"
|
||||
PEAKCOL 16744448
|
||||
BEAT -1
|
||||
AUTOMODE 0
|
||||
VOLPAN 0.8 0.15
|
||||
MUTESOLO 0 0 0
|
||||
IPHASE 0
|
||||
PLAYOFFS 0 1
|
||||
ISBUS 0 0
|
||||
SHOWINMIX 1 0.6667 0.5 1 0.5 -1 -1 -1
|
||||
SEL 0
|
||||
REC 0 0 1 0 0 0 0
|
||||
VU 2
|
||||
TRACKHEIGHT 70 0 0 0 0 0
|
||||
NCHAN 2
|
||||
FX 1
|
||||
<FXCHAIN
|
||||
WNDRECT 0 0 0 0
|
||||
SHOW 0
|
||||
LASTSEL 0
|
||||
DOCKED 0
|
||||
<VST "VST3: VC 76 FX (Audified)" "VC 76.vst3" 0 "" 0<> ""
|
||||
0 0
|
||||
PARAM 0 "Threshold" 0.5
|
||||
PARAM 1 "Ratio" 0.65
|
||||
>
|
||||
<VST "VST: EchoBoy (SoundToys)" "EchoBoy.dll" 0 "" 1163022169<565354454348> ""
|
||||
0 0
|
||||
PARAM 0 "Mix" 0.18
|
||||
PARAM 1 "Time" 0.48
|
||||
>
|
||||
>
|
||||
</TRACK>
|
||||
|
||||
; -------------------------------------------------------
|
||||
; TRACK 9 - ARMONIAS VOZ (dobles y harmonizer)
|
||||
; -------------------------------------------------------
|
||||
<TRACK {11111111-0001-0001-0001-000000000009}
|
||||
NAME "HARMONIAS - VOZ DOUBLES"
|
||||
PEAKCOL 8388736
|
||||
BEAT -1
|
||||
AUTOMODE 0
|
||||
VOLPAN 0.6 0
|
||||
MUTESOLO 0 0 0
|
||||
IPHASE 0
|
||||
PLAYOFFS 0 1
|
||||
ISBUS 0 0
|
||||
SHOWINMIX 1 0.6667 0.5 1 0.5 -1 -1 -1
|
||||
SEL 0
|
||||
REC 0 0 1 0 0 0 0
|
||||
VU 2
|
||||
TRACKHEIGHT 70 0 0 0 0 0
|
||||
NCHAN 2
|
||||
FX 1
|
||||
<FXCHAIN
|
||||
WNDRECT 0 0 0 0
|
||||
SHOW 0
|
||||
LASTSEL 0
|
||||
DOCKED 0
|
||||
<VST "VST: LittleAlterBoy (SoundToys)" "LittleAlterBoy.dll" 0 "" 0<> ""
|
||||
0 0
|
||||
PARAM 0 "Pitch" -0.33
|
||||
PARAM 1 "Mix" 0.5
|
||||
>
|
||||
>
|
||||
</TRACK>
|
||||
|
||||
; -------------------------------------------------------
|
||||
; TRACK 10 - HI-HAT / PERCUSSION FX
|
||||
; Hi-hats en triplets, shakers, claps
|
||||
; -------------------------------------------------------
|
||||
<TRACK {11111111-0001-0001-0001-000000000010}
|
||||
NAME "HI-HATS y PERCUSION"
|
||||
PEAKCOL 16776960
|
||||
BEAT -1
|
||||
AUTOMODE 0
|
||||
VOLPAN 0.7 0
|
||||
MUTESOLO 0 0 0
|
||||
IPHASE 0
|
||||
PLAYOFFS 0 1
|
||||
ISBUS 0 0
|
||||
SHOWINMIX 1 0.6667 0.5 1 0.5 -1 -1 -1
|
||||
SEL 0
|
||||
REC 0 0 1 0 0 0 0
|
||||
VU 2
|
||||
TRACKHEIGHT 70 0 0 0 0 0
|
||||
NCHAN 2
|
||||
FX 1
|
||||
<FXCHAIN
|
||||
WNDRECT 0 0 0 0
|
||||
SHOW 0
|
||||
LASTSEL 0
|
||||
DOCKED 0
|
||||
<VST "VST: FilterFreak1 (SoundToys)" "FilterFreak1.dll" 0 "" 0<> ""
|
||||
0 0
|
||||
PARAM 0 "Cutoff" 0.65
|
||||
PARAM 1 "Resonance" 0.3
|
||||
PARAM 2 "Mix" 0.4
|
||||
>
|
||||
<VST "VST: MicroShift (SoundToys)" "MicroShift.dll" 0 "" 0<> ""
|
||||
0 0
|
||||
PARAM 0 "Width" 0.5
|
||||
PARAM 1 "Mix" 0.4
|
||||
>
|
||||
>
|
||||
</TRACK>
|
||||
|
||||
; -------------------------------------------------------
|
||||
; TRACK 11 - BUS MASTER MIX
|
||||
; Procesamiento final del mix
|
||||
; -------------------------------------------------------
|
||||
<TRACK {11111111-0001-0001-0001-000000000011}
|
||||
NAME "MASTER BUS"
|
||||
PEAKCOL 16777215
|
||||
BEAT -1
|
||||
AUTOMODE 0
|
||||
VOLPAN 1.0 0
|
||||
MUTESOLO 0 0 0
|
||||
IPHASE 0
|
||||
PLAYOFFS 0 1
|
||||
ISBUS 1 0
|
||||
BUSCOMP 0 0 0 0 0
|
||||
SHOWINMIX 1 0.6667 0.5 1 0.5 -1 -1 -1
|
||||
SEL 0
|
||||
REC 0 0 1 0 0 0 0
|
||||
VU 2
|
||||
TRACKHEIGHT 70 0 0 0 0 0
|
||||
NCHAN 2
|
||||
FX 1
|
||||
<FXCHAIN
|
||||
WNDRECT 0 0 0 0
|
||||
SHOW 0
|
||||
LASTSEL 0
|
||||
DOCKED 0
|
||||
; EQ inteligente en master
|
||||
<VST "VST: Gullfoss (Soundtheory)" "Gullfoss.dll" 0 "" 0<> ""
|
||||
0 0
|
||||
PARAM 0 "Recover" 0.3
|
||||
PARAM 1 "Tame" 0.4
|
||||
PARAM 2 "Bias" 0.0
|
||||
>
|
||||
; Limitador / glue final
|
||||
<VST "VST: TheGlue (Cytomic)" "Cytomic.dll" 0 "" 0<> ""
|
||||
0 0
|
||||
PARAM 0 "Threshold" 0.8
|
||||
PARAM 1 "Ratio" 0.6
|
||||
PARAM 2 "Attack" 0.2
|
||||
PARAM 3 "Release" 0.4
|
||||
>
|
||||
>
|
||||
</TRACK>
|
||||
|
||||
</REAPER_PROJECT>
|
||||
BIN
ejemplos/ejemplo1.mp3
Normal file
BIN
ejemplos/ejemplo1.mp3
Normal file
Binary file not shown.
BIN
ejemplos/ejemplo2.mp3
Normal file
BIN
ejemplos/ejemplo2.mp3
Normal file
Binary file not shown.
148
output/Backups/test_no_preset-2026-05-03_131539.rpp-bak
Normal file
148
output/Backups/test_no_preset-2026-05-03_131539.rpp-bak
Normal file
@@ -0,0 +1,148 @@
|
||||
<REAPER_PROJECT 0.1 "7.65/win64" 1777819992 0
|
||||
<NOTES 0 2
|
||||
>
|
||||
RIPPLE 0 0
|
||||
GROUPOVERRIDE 0 0 0 0
|
||||
AUTOXFADE 129
|
||||
ENVATTACH 3
|
||||
POOLEDENVATTACH 0
|
||||
TCPUIFLAGS 0
|
||||
MIXERUIFLAGS 11 48
|
||||
ENVFADESZ10 40
|
||||
PEAKGAIN 1
|
||||
FEEDBACK 0
|
||||
PANLAW 1
|
||||
PROJOFFS 0 0 0
|
||||
MAXPROJLEN 0 0
|
||||
GRID 3199 8 1 8 1 0 0 0
|
||||
TIMEMODE 1 5 -1 30 0 0 -1 0
|
||||
VIDEO_CONFIG 0 0 65792
|
||||
PANMODE 3
|
||||
PANLAWFLAGS 3
|
||||
CURSOR 0
|
||||
ZOOM 100 0 0
|
||||
VZOOMEX 6 0
|
||||
USE_REC_CFG 0
|
||||
RECMODE 1
|
||||
SMPTESYNC 0 30 100 40 1000 300 0 0 1 0 0
|
||||
LOOP 0
|
||||
LOOPGRAN 0 4
|
||||
RECORD_PATH "Media" ""
|
||||
<RECORD_CFG
|
||||
ZXZhdxgAAQ==
|
||||
>
|
||||
<APPLYFX_CFG
|
||||
>
|
||||
RENDER_FILE ""
|
||||
RENDER_PATTERN ""
|
||||
RENDER_FMT 0 2 0
|
||||
RENDER_1X 0
|
||||
RENDER_RANGE 1 0 0 0 1000
|
||||
RENDER_RESAMPLE 3 0 1
|
||||
RENDER_ADDTOPROJ 0
|
||||
RENDER_STEMS 0
|
||||
RENDER_DITHER 0
|
||||
RENDER_TRIM 0.000001 0.000001 0 0
|
||||
TIMELOCKMODE 1
|
||||
TEMPOENVLOCKMODE 1
|
||||
ITEMMIX 1
|
||||
DEFPITCHMODE 589824 0
|
||||
TAKELANE 1
|
||||
SAMPLERATE 44100 0 0
|
||||
<RENDER_CFG
|
||||
ZXZhdxgAAQ==
|
||||
>
|
||||
LOCK 1
|
||||
<METRONOME 6 2
|
||||
VOL 0.25 0.125
|
||||
BEATLEN 4
|
||||
FREQ 1760 880 1
|
||||
SAMPLES "" "" "" ""
|
||||
SPLIGNORE 0 0
|
||||
SPLDEF 2 660 "" 0 ""
|
||||
SPLDEF 3 440 "" 0 ""
|
||||
PATTERN 0 169
|
||||
PATTERNSTR ABBB
|
||||
MULT 1
|
||||
>
|
||||
GLOBAL_AUTO -1
|
||||
TEMPO 120 4 4 0
|
||||
PLAYRATE 1 0 0.25 4
|
||||
SELECTION 0 0
|
||||
SELECTION2 0 0
|
||||
MASTERAUTOMODE 0
|
||||
MASTERTRACKHEIGHT 0 0
|
||||
MASTERPEAKCOL 16576
|
||||
MASTERMUTESOLO 0
|
||||
MASTERTRACKVIEW 0 0.6667 0.5 0.5 0 0 0 0 0 0 0 0 0 0 0
|
||||
MASTERHWOUT 0 0 1 0 0 0 0 -1
|
||||
MASTER_NCH 2 2
|
||||
MASTER_VOLUME 1 0 -1 -1 1
|
||||
MASTER_PANMODE 3
|
||||
MASTER_PANLAWFLAGS 3
|
||||
MASTER_FX 1
|
||||
MASTER_SEL 0
|
||||
<MASTERPLAYSPEEDENV
|
||||
EGUID {DEF87440-E07C-4B72-B9F8-D2AC60A0D0AC}
|
||||
ACT 0 -1
|
||||
VIS 0 1 1
|
||||
LANEHEIGHT 0 0
|
||||
ARM 0
|
||||
DEFSHAPE 0 -1 -1
|
||||
>
|
||||
<TEMPOENVEX
|
||||
EGUID {15E58A72-7149-4783-9A04-838503786012}
|
||||
ACT 1 -1
|
||||
VIS 1 0 1
|
||||
LANEHEIGHT 0 0
|
||||
ARM 0
|
||||
DEFSHAPE 1 -1 -1
|
||||
>
|
||||
RULERHEIGHT 86 86
|
||||
RULERLANE 1 4 "" 0 -1
|
||||
RULERLANE 2 8 "" 0 -1
|
||||
<PROJBAY
|
||||
>
|
||||
<TRACK {2BF702FB-DCC4-4D83-88F1-7B4A8CC8C8A6}
|
||||
NAME ""
|
||||
PEAKCOL 16576
|
||||
BEAT -1
|
||||
AUTOMODE 0
|
||||
PANLAWFLAGS 3
|
||||
VOLPAN 1 0 -1 -1 1
|
||||
MUTESOLO 0 0 0
|
||||
IPHASE 0
|
||||
PLAYOFFS 0 1
|
||||
ISBUS 0 0
|
||||
BUSCOMP 0 0 0 0 0
|
||||
SHOWINMIX 1 0.6667 0.5 1 0.5 0 0 0 0
|
||||
FIXEDLANES 9 0 0 0 0
|
||||
LANEREC -1 -1 -1 0
|
||||
SEL 1
|
||||
REC 0 0 1 0 0 0 0 0
|
||||
VU 64
|
||||
TRACKHEIGHT 0 0 0 0 0 0 0
|
||||
INQ 0 0 0 0.5 100 0 0 100
|
||||
NCHAN 2
|
||||
FX 1
|
||||
TRACKID {2BF702FB-DCC4-4D83-88F1-7B4A8CC8C8A6}
|
||||
PERF 0
|
||||
MIDIOUT -1
|
||||
MAINSEND 1 0
|
||||
<FXCHAIN
|
||||
WNDRECT 24 52 655 408
|
||||
SHOW 0
|
||||
LASTSEL 0
|
||||
DOCKED 0
|
||||
BYPASS 0 0 0
|
||||
<VST "VST3: Pro-Q 3 (FabFilter)" "FabFilter Pro-Q 3.vst3" 0 "" 756089518{72C4DB717A4D459AB97E51745D84B39D} ""
|
||||
>
|
||||
PRESETNAME "Program 1"
|
||||
FLOATPOS 0 0 0 0
|
||||
FXID {817BC720-1D44-41DB-99A6-3C29BB5029B5}
|
||||
WAK 0 0
|
||||
>
|
||||
>
|
||||
<EXTENSIONS
|
||||
>
|
||||
>
|
||||
37136
output/all_plugins_v2.rpp
Normal file
37136
output/all_plugins_v2.rpp
Normal file
File diff suppressed because it is too large
Load Diff
1103
output/del_lune_fixed.rpp
Normal file
1103
output/del_lune_fixed.rpp
Normal file
File diff suppressed because it is too large
Load Diff
34055
output/parsed_plugins.json
Normal file
34055
output/parsed_plugins.json
Normal file
File diff suppressed because it is too large
Load Diff
21635
output/registry_code.py
Normal file
21635
output/registry_code.py
Normal file
File diff suppressed because it is too large
Load Diff
155
output/soundtoys_reference.rpp
Normal file
155
output/soundtoys_reference.rpp
Normal file
@@ -0,0 +1,155 @@
|
||||
<REAPER_PROJECT 0.1 "7.65/win64" 1777838611 0
|
||||
<NOTES 0 2
|
||||
>
|
||||
RIPPLE 0 0
|
||||
GROUPOVERRIDE 0 0 0 0
|
||||
AUTOXFADE 129
|
||||
ENVATTACH 3
|
||||
POOLEDENVATTACH 0
|
||||
TCPUIFLAGS 0
|
||||
MIXERUIFLAGS 11 48
|
||||
ENVFADESZ10 40
|
||||
PEAKGAIN 1
|
||||
FEEDBACK 0
|
||||
PANLAW 1
|
||||
PROJOFFS 0 0 0
|
||||
MAXPROJLEN 0 0
|
||||
GRID 3199 8 1 8 1 0 0 0
|
||||
TIMEMODE 1 5 -1 30 0 0 -1 0
|
||||
VIDEO_CONFIG 0 0 65792
|
||||
PANMODE 3
|
||||
PANLAWFLAGS 3
|
||||
CURSOR 0
|
||||
ZOOM 100 0 0
|
||||
VZOOMEX 6 0
|
||||
USE_REC_CFG 0
|
||||
RECMODE 1
|
||||
SMPTESYNC 0 30 100 40 1000 300 0 0 1 0 0
|
||||
LOOP 0
|
||||
LOOPGRAN 0 4
|
||||
RECORD_PATH "Media" ""
|
||||
<RECORD_CFG
|
||||
ZXZhdxgAAQ==
|
||||
>
|
||||
<APPLYFX_CFG
|
||||
>
|
||||
RENDER_FILE ""
|
||||
RENDER_PATTERN ""
|
||||
RENDER_FMT 0 2 0
|
||||
RENDER_1X 0
|
||||
RENDER_RANGE 1 0 0 0 1000
|
||||
RENDER_RESAMPLE 3 0 1
|
||||
RENDER_ADDTOPROJ 0
|
||||
RENDER_STEMS 0
|
||||
RENDER_DITHER 0
|
||||
RENDER_TRIM 0.000001 0.000001 0 0
|
||||
TIMELOCKMODE 1
|
||||
TEMPOENVLOCKMODE 1
|
||||
ITEMMIX 1
|
||||
DEFPITCHMODE 589824 0
|
||||
TAKELANE 1
|
||||
SAMPLERATE 44100 0 0
|
||||
<RENDER_CFG
|
||||
ZXZhdxgAAQ==
|
||||
>
|
||||
LOCK 1
|
||||
<METRONOME 6 2
|
||||
VOL 0.25 0.125
|
||||
BEATLEN 4
|
||||
FREQ 1760 880 1
|
||||
SAMPLES "" "" "" ""
|
||||
SPLIGNORE 0 0
|
||||
SPLDEF 2 660 "" 0 ""
|
||||
SPLDEF 3 440 "" 0 ""
|
||||
PATTERN 0 169
|
||||
PATTERNSTR ABBB
|
||||
MULT 1
|
||||
>
|
||||
GLOBAL_AUTO -1
|
||||
TEMPO 120 4 4 0
|
||||
PLAYRATE 1 0 0.25 4
|
||||
SELECTION 0 0
|
||||
SELECTION2 0 0
|
||||
MASTERAUTOMODE 0
|
||||
MASTERTRACKHEIGHT 0 0
|
||||
MASTERPEAKCOL 16576
|
||||
MASTERMUTESOLO 0
|
||||
MASTERTRACKVIEW 0 0.6667 0.5 0.5 0 0 0 0 0 0 0 0 0 0 0
|
||||
MASTERHWOUT 0 0 1 0 0 0 0 -1
|
||||
MASTER_NCH 2 2
|
||||
MASTER_VOLUME 1 0 -1 -1 1
|
||||
MASTER_PANMODE 3
|
||||
MASTER_PANLAWFLAGS 3
|
||||
MASTER_FX 1
|
||||
MASTER_SEL 0
|
||||
<MASTERPLAYSPEEDENV
|
||||
EGUID {DEF87440-E07C-4B72-B9F8-D2AC60A0D0AC}
|
||||
ACT 0 -1
|
||||
VIS 0 1 1
|
||||
LANEHEIGHT 0 0
|
||||
ARM 0
|
||||
DEFSHAPE 0 -1 -1
|
||||
>
|
||||
<TEMPOENVEX
|
||||
EGUID {15E58A72-7149-4783-9A04-838503786012}
|
||||
ACT 0 -1
|
||||
VIS 1 0 1
|
||||
LANEHEIGHT 0 0
|
||||
ARM 0
|
||||
DEFSHAPE 1 -1 -1
|
||||
>
|
||||
RULERHEIGHT 86 86
|
||||
RULERLANE 1 4 "" 0 -1
|
||||
RULERLANE 2 8 "" 0 -1
|
||||
<PROJBAY
|
||||
>
|
||||
<TRACK {CC7AF445-1A51-4FE2-A089-34F7AE50ED82}
|
||||
NAME ""
|
||||
PEAKCOL 16576
|
||||
BEAT -1
|
||||
AUTOMODE 0
|
||||
PANLAWFLAGS 3
|
||||
VOLPAN 1 0 -1 -1 1
|
||||
MUTESOLO 0 0 0
|
||||
IPHASE 0
|
||||
PLAYOFFS 0 1
|
||||
ISBUS 0 0
|
||||
BUSCOMP 0 0 0 0 0
|
||||
SHOWINMIX 1 0.6667 0.5 1 0.5 0 0 0 0
|
||||
FIXEDLANES 9 0 0 0 0
|
||||
SEL 1
|
||||
REC 0 0 1 0 0 0 0 0
|
||||
VU 64
|
||||
TRACKHEIGHT 0 0 0 0 0 0 0
|
||||
INQ 0 0 0 0.5 100 0 0 100
|
||||
NCHAN 2
|
||||
FX 1
|
||||
TRACKID {CC7AF445-1A51-4FE2-A089-34F7AE50ED82}
|
||||
PERF 0
|
||||
MIDIOUT -1
|
||||
MAINSEND 1 0
|
||||
<FXCHAIN
|
||||
WNDRECT 24 52 655 408
|
||||
SHOW 0
|
||||
LASTSEL 0
|
||||
DOCKED 0
|
||||
BYPASS 0 0 0
|
||||
<VST "VST: Decapitator (SoundToys)" Decapitator.dll 0 "" 1400128611<56535453744463646563617069746174> ""
|
||||
Y0R0U+5e7f4CAAAAAQAAAAAAAAACAAAAAAAAAAIAAAABAAAAAAAAAAIAAAAAAAAAOwIAAAEAAAAAAAAA
|
||||
V0lER0VUID0gRGVjYXBpdGF0b3I7DVZFUlNJT04gPSA0Ow1TQVZFRF9CWV9WRVJTSU9OID0gNS4wLjE7DVBSRVNFVCA9MDEwMTAwMDAwNDg4MDEwMTAwMDFLNF1IRlE3
|
||||
Sz9XPURnP1s8TEVUOD1aOl1IVlhZPlI+XUk0Z2xWYTVdMlhgNVtIMEpNZ2ZjYmM+RGw5WzRDS2tpW1ZnM25nP0pdXVxKTUZjNGU1XV5vZmM+QWw0TjJqWjlkOmxsOVI7
|
||||
Wjs2SUpCTVY4N1U4XTlbPWtMbEdbaVo5RlJaXVVpMk1NQEFsbVViRWZlQT40blFjbUI7ODxSbFE+bG08WjA2MGs5QT9uaFI3MVxQWm5BYjo3TGw8ZTRSUl0/RmozRmdt
|
||||
RDhvMGxKPzFHYF9tZFpBaWUzNmtqVjZvXWxtMzE4bkxtUDhfNlNlajRFVj1jMltlRDtFaDljVWlNajlQVEs3VkhfZEtoYzRpP11jUj1EZF5TXltiSjdDNEExMTlfVk5h
|
||||
bTxWX2VrSlJlNzRmSmNIQExlMUVMWWBISEA9YjFZWEA2NjZYZ1xGWmE3NlFYQjYxVV9eaTpRXVFBPmNkazAxPDlqMDQxa1tAaU1MMG1HZzpjXlM4OGhVS1VSMVZZbmc/
|
||||
TTJYYUdQTT9Ca10wOWI4ZW8wakZMWGteTk83U2I+ND5hUTdUVG1gM0VDVUc6UFRbbE5bTkZTUFFiYllCb21obDY/OjM4RjpvNVdiS2BNbGAwMDA1UDAwMDA7DQ==
|
||||
AAAAAAAA
|
||||
>
|
||||
PRESETNAME Default
|
||||
FLOATPOS 0 0 0 0
|
||||
FXID {5DAAF240-C12C-4450-B2A4-31D522D4B9C5}
|
||||
WAK 0 0
|
||||
>
|
||||
>
|
||||
<EXTENSIONS
|
||||
>
|
||||
>
|
||||
1218
output/tu_diablo_fixed.rpp
Normal file
1218
output/tu_diablo_fixed.rpp
Normal file
File diff suppressed because it is too large
Load Diff
@@ -97,16 +97,16 @@ ROLE_TO_SAMPLE_ROLE = {
|
||||
|
||||
# Mapping of effect names to VST3 plugin entries
|
||||
# Format: (registry_key, filename) tuples
|
||||
# registry_key must match a key in VST3_REGISTRY for _build_plugin() lookup
|
||||
# registry_key must match a key in PLUGIN_REGISTRY for _build_plugin() lookup
|
||||
_VST3_EFFECTS: dict[str, tuple[str, str]] = {
|
||||
"Pro-Q 3": ("FabFilter Pro-Q 3", "FabFilter Pro-Q 3.vst3"),
|
||||
"Pro-C 2": ("FabFilter Pro-C 2", "FabFilter Pro-C 2.vst3"),
|
||||
"Pro-R 2": ("FabFilter Pro-R 2", "FabFilter Pro-R 2.vst3"),
|
||||
"Timeless 3": ("FabFilter Timeless 3", "FabFilter Timeless 3.vst3"),
|
||||
"Saturn 2": ("FabFilter Saturn 2", "FabFilter Saturn 2.vst3"),
|
||||
"Pro-L 2": ("FabFilter Pro-L 2", "FabFilter Pro-L 2.vst3"),
|
||||
"The Glue": ("The Glue", "The Glue.vst3"),
|
||||
"Valhalla Delay": ("Valhalla Delay", "ValhallaDelay.vst3"),
|
||||
"Pro-Q 3": ("Pro-Q_3", "FabFilter"),
|
||||
"Pro-C 2": ("Pro-C_2", "FabFilter"),
|
||||
"Pro-R 2": ("Pro-R_2", "FabFilter"),
|
||||
"Timeless 3": ("Timeless_3", "FabFilter"),
|
||||
"Saturn 2": ("Saturn_2", "FabFilter"),
|
||||
"Pro-L 2": ("Pro-L_2", "FabFilter"),
|
||||
"The Glue": ("The_Glue", "The"),
|
||||
"Valhalla Delay": ("ValhallaDelay", "ValhallaDelay.dll"),
|
||||
}
|
||||
|
||||
|
||||
@@ -167,8 +167,8 @@ def create_return_tracks() -> list[TrackDef]:
|
||||
pan=0.0,
|
||||
clips=[],
|
||||
plugins=[PluginDef(
|
||||
name="FabFilter Pro-R 2",
|
||||
path="FabFilter_Pro_R_2.vst3",
|
||||
name="FabFilter_Pro-R_2",
|
||||
path="FabFilter",
|
||||
index=0,
|
||||
)],
|
||||
send_reverb=0.0,
|
||||
@@ -180,8 +180,8 @@ def create_return_tracks() -> list[TrackDef]:
|
||||
pan=0.0,
|
||||
clips=[],
|
||||
plugins=[PluginDef(
|
||||
name="FabFilter Timeless 3",
|
||||
path="FabFilter_Timeless_3.vst3",
|
||||
name="FabFilter_Timeless_3",
|
||||
path="FabFilter",
|
||||
index=0,
|
||||
)],
|
||||
send_reverb=0.0,
|
||||
|
||||
118
scripts/generate_from_template.py
Normal file
118
scripts/generate_from_template.py
Normal file
@@ -0,0 +1,118 @@
|
||||
#!/usr/bin/env python
|
||||
"""Generate fixed .rpp files from example RPP templates.
|
||||
|
||||
Extracts track/FX chain structures from the example .rpp files,
|
||||
fixes GUIDs using real values from reaper-vstplugins64.ini,
|
||||
strips invalid PARAM lines, and generates working .rpp files.
|
||||
|
||||
Usage:
|
||||
python scripts/generate_from_template.py --all
|
||||
python scripts/generate_from_template.py --template TU_DIABLO --output output/tu_diablo_fixed.rpp
|
||||
python scripts/generate_from_template.py --template DEL_LUNE --output output/del_lune_fixed.rpp
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
# Ensure project root on path
|
||||
_ROOT = Path(__file__).parent.parent
|
||||
sys.path.insert(0, str(_ROOT))
|
||||
|
||||
from src.composer.templates import extract_template, generate_rpp
|
||||
|
||||
|
||||
TEMPLATES: dict[str, dict] = {
|
||||
"TU_DIABLO": {
|
||||
"source": "ejemplos/TU_DIABLO_ITHAN_NY.rpp",
|
||||
"output": "output/tu_diablo_fixed.rpp",
|
||||
"description": "TU_DIABLO_ITHAN_NY.rpp — 99 BPM E minor, Drill chileno",
|
||||
},
|
||||
"DEL_LUNE": {
|
||||
"source": "ejemplos/DEL_LUNE_AL_FINDE_ITHAN_NY_JULIANNO_SOSA.rpp",
|
||||
"output": "output/del_lune_fixed.rpp",
|
||||
"description": "DEL_LUNE_AL_FINDE_*.rpp — 100 BPM B major, Reggaeton moderno",
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
def main() -> None:
|
||||
parser = argparse.ArgumentParser(
|
||||
description="Generate fixed .rpp files from example templates."
|
||||
)
|
||||
parser.add_argument(
|
||||
"--all",
|
||||
action="store_true",
|
||||
help="Generate all templates (TU_DIABLO and DEL_LUNE)",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--template",
|
||||
choices=list(TEMPLATES.keys()),
|
||||
help="Specific template to generate",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--output",
|
||||
help="Override output path",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--list",
|
||||
action="store_true",
|
||||
help="List available templates",
|
||||
)
|
||||
args = parser.parse_args()
|
||||
|
||||
if args.list:
|
||||
print("Available templates:")
|
||||
for key, info in TEMPLATES.items():
|
||||
print(f" {key}: {info['description']}")
|
||||
print(f" Source: {info['source']}")
|
||||
print(f" Output: {info['output']}")
|
||||
return
|
||||
|
||||
templates_to_run = []
|
||||
if args.all:
|
||||
templates_to_run = list(TEMPLATES.keys())
|
||||
elif args.template:
|
||||
templates_to_run = [args.template]
|
||||
else:
|
||||
# Default: generate all
|
||||
templates_to_run = list(TEMPLATES.keys())
|
||||
|
||||
for key in templates_to_run:
|
||||
info = TEMPLATES[key]
|
||||
source_path = _ROOT / info["source"]
|
||||
output_path = Path(args.output) if args.output else _ROOT / info["output"]
|
||||
|
||||
print(f"\n[{key}]")
|
||||
print(f" Source: {source_path}")
|
||||
print(f" Output: {output_path}")
|
||||
|
||||
if not source_path.exists():
|
||||
print(f" ERROR: Source file not found: {source_path}", file=sys.stderr)
|
||||
continue
|
||||
|
||||
try:
|
||||
# Extract template from source RPP
|
||||
print(f" Extracting template...")
|
||||
template = extract_template(source_path)
|
||||
print(f" Tracks found: {len(template.tracks)}")
|
||||
for track in template.tracks:
|
||||
print(f" - {track.name}: {len(track.plugins)} plugins")
|
||||
for plugin in track.plugins:
|
||||
print(f" {plugin.name} ({plugin.path})")
|
||||
|
||||
# Generate fixed RPP
|
||||
print(f" Generating RPP...")
|
||||
generate_rpp(template, output_path)
|
||||
print(f" SUCCESS: {output_path}")
|
||||
|
||||
except Exception as e:
|
||||
print(f" ERROR: {e}", file=sys.stderr)
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
70
scripts/generate_registry_code.py
Normal file
70
scripts/generate_registry_code.py
Normal file
@@ -0,0 +1,70 @@
|
||||
#!/usr/bin/env python
|
||||
"""Generate registry code from parsed_plugins.json."""
|
||||
import json
|
||||
from pathlib import Path
|
||||
|
||||
plugins = json.loads(Path("output/parsed_plugins.json").read_text())
|
||||
|
||||
# We prefer VST3 over VST2 when both exist for the same plugin
|
||||
# Build a map, VST3 overrides VST2
|
||||
seen_keys = {}
|
||||
for p in plugins:
|
||||
key = p['key']
|
||||
if key in seen_keys:
|
||||
existing = seen_keys[key]
|
||||
# Prefer VST3 over VST2
|
||||
if p['is_vst3'] and not existing['is_vst3']:
|
||||
seen_keys[key] = p
|
||||
# Prefer VST3i/VSTi instruments
|
||||
elif p['display_name'].startswith('VST3i') and not existing['display_name'].startswith('VST3i'):
|
||||
seen_keys[key] = p
|
||||
elif p['display_name'].startswith('VSTi') and not existing['display_name'].startswith('VSTi'):
|
||||
seen_keys[key] = p
|
||||
else:
|
||||
seen_keys[key] = p
|
||||
|
||||
# Deduplicated
|
||||
final = sorted(seen_keys.values(), key=lambda p: p['key'])
|
||||
|
||||
print(f"Unique plugins after dedup: {len(final)}")
|
||||
|
||||
# Generate registry code
|
||||
lines = []
|
||||
lines.append("# Auto-generated from output/all_plugins_v2.rpp (REAPER ground truth)")
|
||||
lines.append("# Format: key → (display_name, filename, uid_guid)")
|
||||
lines.append("PLUGIN_REGISTRY: dict[str, tuple[str, str, str]] = {")
|
||||
for p in final:
|
||||
dn = p['display_name']
|
||||
fn = p['filename']
|
||||
ug = p['uid_guid']
|
||||
# Quote filename if it has spaces
|
||||
if ' ' in fn or not p['is_vst3']:
|
||||
fn_str = f'"{fn}"'
|
||||
else:
|
||||
fn_str = f'"{fn}"'
|
||||
lines.append(f' "{p["key"]}": (')
|
||||
lines.append(f' "{dn}",')
|
||||
lines.append(f' {fn_str},')
|
||||
lines.append(f' "{ug}",')
|
||||
lines.append(f' ),')
|
||||
lines.append("}")
|
||||
|
||||
# Generate presets code
|
||||
lines.append("")
|
||||
lines.append("# Auto-generated preset data from output/all_plugins_v2.rpp")
|
||||
lines.append("PLUGIN_PRESETS: dict[str, list[str]] = {")
|
||||
for p in final:
|
||||
if p['preset_lines']:
|
||||
lines.append(f' "{p["key"]}": [')
|
||||
for pl in p['preset_lines']:
|
||||
lines.append(f' "{pl}",')
|
||||
lines.append(f' ],')
|
||||
else:
|
||||
lines.append(f' "{p["key"]}": [],')
|
||||
lines.append("}")
|
||||
|
||||
Path("output/registry_code.py").write_text('\n'.join(lines), encoding='utf-8')
|
||||
print(f"Generated output/registry_code.py ({len(lines)} lines)")
|
||||
print(f"\nSample entries:")
|
||||
for p in final[:5]:
|
||||
print(f' "{p["key"]}": ("{p["display_name"]}", "{p["filename"]}", "{p["uid_guid"]}")')
|
||||
68
scripts/parse_ground_truth.py
Normal file
68
scripts/parse_ground_truth.py
Normal file
@@ -0,0 +1,68 @@
|
||||
#!/usr/bin/env python
|
||||
"""Parse all_plugins_v2.rpp and generate registry code."""
|
||||
import re
|
||||
import json
|
||||
from pathlib import Path
|
||||
|
||||
text = Path("output/all_plugins_v2.rpp").read_text(encoding="utf-8")
|
||||
|
||||
# Match VST elements: opening tag through closing >
|
||||
# The closing > is on its own line with leading whitespace
|
||||
pattern = r'<VST "([^"]+)" ([^\n]+)\n([\s\S]*?)\n\s*>'
|
||||
matches = re.findall(pattern, text)
|
||||
|
||||
print(f"Total VST elements found: {len(matches)}")
|
||||
|
||||
plugins = []
|
||||
for name, rest, preset_block in matches:
|
||||
# Parse rest: filename 0 "" uid_guid ""
|
||||
rest_parts = rest.strip().split()
|
||||
|
||||
# Find the uid_guid (contains { or <)
|
||||
uid_guid = ""
|
||||
for part in rest_parts:
|
||||
if '{' in part or '<' in part:
|
||||
uid_guid = part
|
||||
break
|
||||
|
||||
# Find filename (second token, may be quoted)
|
||||
filename = rest_parts[0].strip('"')
|
||||
|
||||
# Clean preset lines
|
||||
preset_lines = [line.strip() for line in preset_block.strip().split('\n') if line.strip()]
|
||||
# Remove PRESETNAME lines
|
||||
preset_lines = [l for l in preset_lines if not l.startswith('PRESETNAME')]
|
||||
|
||||
is_vst3 = name.startswith('VST3') or name.startswith('VST3i')
|
||||
|
||||
# Generate a short key
|
||||
# Remove prefix and vendor
|
||||
clean = name.replace('VST3i: ', '').replace('VST3: ', '').replace('VSTi: ', '').replace('VST: ', '')
|
||||
# Remove vendor in parens
|
||||
clean = re.sub(r'\s*\([^)]+\)', '', clean).strip()
|
||||
key = clean.replace(' ', '_')
|
||||
|
||||
plugins.append({
|
||||
'key': key,
|
||||
'display_name': name,
|
||||
'filename': filename,
|
||||
'uid_guid': uid_guid,
|
||||
'is_vst3': is_vst3,
|
||||
'preset_lines': preset_lines,
|
||||
})
|
||||
|
||||
# Save as JSON for use by other scripts
|
||||
Path("output/parsed_plugins.json").write_text(json.dumps(plugins, indent=2, ensure_ascii=False))
|
||||
print(f"Saved to output/parsed_plugins.json")
|
||||
|
||||
# Print summary
|
||||
vst3_count = sum(1 for p in plugins if p['is_vst3'])
|
||||
vst2_count = sum(1 for p in plugins if not p['is_vst3'])
|
||||
print(f"VST3: {vst3_count}, VST2: {vst2_count}")
|
||||
|
||||
# Print a few examples
|
||||
for p in plugins[:5]:
|
||||
print(f"\n {p['key']}: {p['display_name']}")
|
||||
print(f" filename: {p['filename']}")
|
||||
print(f" uid_guid: {p['uid_guid']}")
|
||||
print(f" preset lines: {len(p['preset_lines'])}")
|
||||
70
sdd/fix-drum-sample-paths/design.md
Normal file
70
sdd/fix-drum-sample-paths/design.md
Normal file
@@ -0,0 +1,70 @@
|
||||
# Design: `fix-drum-sample-paths`
|
||||
|
||||
**Type**: bugfix
|
||||
**Bug**: Drum samples silent — `samples_dir/output/samples/` paths point to nonexistent directory
|
||||
**Root cause**: `compose_full_track.py` passes bare filenames to skeleton, which joins them with `samples_dir` expecting `output/samples/`. But `pick()` returns absolute paths from the sample library. The mismatch makes FL Studio look in the wrong place.
|
||||
|
||||
---
|
||||
|
||||
## Changes
|
||||
|
||||
### 1. `scripts/compose_full_track.py` — lines 201–210
|
||||
|
||||
**Problem**: `samples` dict receives bare filenames (`ch10_perc`, etc.) but skeleton needs absolute paths.
|
||||
|
||||
**Fix**: Change the `samples` dict to use the `path*` variables returned by `pick()`, which are absolute paths.
|
||||
|
||||
```python
|
||||
# Before (broken)
|
||||
samples = {
|
||||
"channel10": ch10_perc, # bare filename e.g. "perc_loop.wav"
|
||||
...
|
||||
}
|
||||
|
||||
# After (fixed)
|
||||
samples = {
|
||||
"channel10": path10, # absolute path e.g. "C:\Users\...\library\perc_loop.wav"
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
The `path*` variables already exist and hold `m.get("original_path")` from `pick()`. No other code needs changing — the samples dict key→channel mapping is already correct.
|
||||
|
||||
---
|
||||
|
||||
### 2. `src/flp_builder/skeleton.py` — `_patch_sample_path()` around line 361
|
||||
|
||||
**Problem**: `_patch_sample_path()` always joins `wav_name` with `self.samples_dir`, which breaks when `wav_name` is already an absolute path (as it now is after fix #1).
|
||||
|
||||
**Fix**: Add an absolute-path guard before joining:
|
||||
|
||||
```python
|
||||
# In _patch_sample_path(), replace line 361:
|
||||
# Before
|
||||
full_path = os.path.join(self.samples_dir, wav_name)
|
||||
|
||||
# After
|
||||
if Path(wav_name).is_absolute():
|
||||
full_path = wav_name
|
||||
else:
|
||||
full_path = os.path.join(self.samples_dir, wav_name)
|
||||
```
|
||||
|
||||
This preserves existing behavior for relative paths (used elsewhere) while correctly handling the absolute paths now being passed.
|
||||
|
||||
---
|
||||
|
||||
## Files affected
|
||||
|
||||
| File | Lines | Change |
|
||||
|------|-------|--------|
|
||||
| `scripts/compose_full_track.py` | 201–210 | Use `path*` vars instead of `ch*_var` vars |
|
||||
| `src/flp_builder/skeleton.py` | 361 | Add `is_absolute()` guard |
|
||||
|
||||
---
|
||||
|
||||
## Verification
|
||||
|
||||
- **Before fix**: `compose_full_track.py` prints `ch10: some_file.wav` (bare filename)
|
||||
- **After fix**: `compose_full_track.py` prints full paths, skeleton detects them and skips join
|
||||
- Run `python scripts/compose_full_track.py` — FLP should load drum samples correctly
|
||||
200
sdd/reggaeton-professional-mix/tasks.md
Normal file
200
sdd/reggaeton-professional-mix/tasks.md
Normal file
@@ -0,0 +1,200 @@
|
||||
# Tasks: `reggaeton-professional-mix`
|
||||
|
||||
## type: architecture
|
||||
## status: draft
|
||||
|
||||
---
|
||||
|
||||
## Phase 1 — Note Validity (Foundation)
|
||||
|
||||
### 1.1 Clamp pitch in `encode_notes_block()`
|
||||
**File**: `src/flp_builder/events.py`
|
||||
**Location**: `encode_notes_block()`, lines 201–223
|
||||
**Change**: Replace `key=key & 0x7F` with explicit `max(0, min(127, key))`.
|
||||
**Why**: `key & 0x7F` silently wraps values ≥128 rather than clamping, causing the FL Studio "invalid notes" warning.
|
||||
**Validation**: Verify notes with key=128 produce no warning; key=0 and key=127 work.
|
||||
|
||||
### 1.2 Clamp velocity in `encode_notes_block()`
|
||||
**File**: `src/flp_builder/events.py`
|
||||
**Location**: `encode_notes_block()`, line 219 — `velocity=velocity & 0x7F`
|
||||
**Change**: Replace with `max(1, min(127, velocity))`.
|
||||
**Why**: Velocity 0 is invalid in MIDI; `& 0x7F` allows 0 from input.
|
||||
**Validation**: velocity=0 → clamped to 1; velocity=127 stays 127; velocity=200 → clamped to 127.
|
||||
|
||||
### 1.3 Clamp duration ≥ 1 in `encode_notes_block()`
|
||||
**File**: `src/flp_builder/events.py`
|
||||
**Location**: `encode_notes_block()`, line 212 — `length=max(length, 1)`
|
||||
**Change**: Already present. Confirm `max(length, 1)` is retained (was added in prior fix).
|
||||
**Why**: Duration of 0 would produce 0-byte notes, which FL Studio rejects.
|
||||
**Validation**: length=0 → stays 1 after max(); length=1 → stays 1.
|
||||
|
||||
---
|
||||
|
||||
## Phase 2 — Mix Settings
|
||||
|
||||
### 2.1 Add mix fields to `PatternDef`
|
||||
**File**: `src/flp_builder/schema.py`
|
||||
**Location**: `PatternDef` dataclass, lines 72–87
|
||||
**Change**: Add four fields to `PatternDef`:
|
||||
```python
|
||||
volume: float = 0.85 # 0.0–1.0, default -1.5 dB
|
||||
pan: float = 0.0 # -1.0 to 1.0, center
|
||||
reverb_send: float = 0.2 # 0.0–1.0
|
||||
delay_send: float = 0.1 # 0.0–1.0
|
||||
```
|
||||
Add `volume`, `pan`, `reverb_send`, `delay_send` to `_PATTERN_KEYS` frozenset for validation.
|
||||
**Why**: Needed so the composer can specify per-pattern mix settings; previously all channels used defaults.
|
||||
**Validation**: JSON round-trip: `PatternDef(..., volume=0.8, pan=-0.3, reverb_send=0.4, delay_send=0.2)` survives `to_json()` → `from_json()`.
|
||||
|
||||
### 2.2 Patch mix events in `ChannelSkeletonLoader`
|
||||
**File**: `src/flp_builder/skeleton.py`
|
||||
**Location**: `ChannelSkeletonLoader.load()` — after sample patching, before assembly
|
||||
**Change**: Accept `mix_map: dict[int, dict]` parameter (channel_index → {volume, pan, reverb_send, delay_send}). After patching samples, append/replace word events:
|
||||
- `ChVolWord` (72): volume as 0–255 word (`int(vol * 200)`, 200 = 0 dB)
|
||||
- `ChPanWord` (73): pan as signed 0–255 (`int((pan + 1.0) * 127.5)`)
|
||||
- `ChReverb` (139): reverb_send as 0–255 (`int(send * 255)`)
|
||||
- `ChStereoDelay` (85): delay_send as 0–255 (`int(send * 255)`)
|
||||
**Why**: FL Studio stores these as word events on the channel; skeleton loader must inject them.
|
||||
**Validation**: Load skeleton with mix_map, verify output bytes contain the four event IDs with expected values.
|
||||
|
||||
### 2.3 Pass mix_map from `FLPBuilder` to skeleton loader
|
||||
**File**: `src/flp_builder/builder.py` (assumed existing — if not found, locate)
|
||||
**Location**: `FLPBuilder.build()` call to `ChannelSkeletonLoader.load()`
|
||||
**Change**: Build mix_map from `PatternDef` fields and pass to loader.
|
||||
**Why**: Bridges schema (PatternDef) to FLP rendering (skeleton).
|
||||
**Note**: If builder.py does not yet accept/forward mix_map, add it.
|
||||
|
||||
---
|
||||
|
||||
## Phase 3 — Groove
|
||||
|
||||
### 3.1 Add `groove_strength` to rhythm generators
|
||||
**File**: `src/composer/rhythm.py`
|
||||
**Location**: All generator functions + `get_notes()` dispatcher
|
||||
**Change**: Add `groove_strength: float = 0.0` parameter (0.0 = no groove, 1.0 = max groove) to all generators:
|
||||
- `kick_main_notes`, `kick_sparse_notes`, `kick_outro_notes`
|
||||
- `snare_verse_notes`, `snare_fill_notes`, `snare_outro_notes`
|
||||
- `hihat_16th_notes`, `hihat_8th_notes`
|
||||
- `clap_24_notes`, `perc_combo_notes`, `rim_build_notes`
|
||||
|
||||
Apply groove via `_apply_groove(note_dict, groove_strength)` helper:
|
||||
- Velocity jitter: `vel ±= random.randint(0, int(5 + groove_strength * 10))`
|
||||
- Positional nudge: `pos += random.uniform(-groove_strength * 0.02, groove_strength * 0.02)`
|
||||
- Swing (every other 16th): shift even-index 16ths forward by `swing_amount = groove_strength * 0.1`
|
||||
|
||||
**Why**: Groove makes drum patterns feel human and avoids mechanical timing.
|
||||
**Validation**: `get_notes("kick_main_notes", bars=1, groove_strength=0.5)` returns notes with positional variation vs. `groove_strength=0.0`.
|
||||
|
||||
### 3.2 Update `get_notes()` dispatcher signature
|
||||
**File**: `src/composer/rhythm.py`
|
||||
**Location**: `get_notes()`, lines 303–311
|
||||
**Change**: Add `groove_strength: float = 0.0` to dispatcher and pass to generator.
|
||||
**Why**: All generators now accept groove_strength; dispatcher must forward it.
|
||||
|
||||
---
|
||||
|
||||
## Phase 4 — Melodic Humanization
|
||||
|
||||
### 4.1 Add `humanize` to melodic generators
|
||||
**File**: `src/composer/melodic.py`
|
||||
**Location**: `bass_tresillo()`, `lead_hook()`, `chords_block()`, `pad_sustain()`
|
||||
**Change**: Add `humanize: float = 0.0` parameter (0.0 = no humanization, 1.0 = max humanization).
|
||||
|
||||
Apply humanization via `_apply_humanize(note_dict, humanize)` helper:
|
||||
- Velocity jitter: `vel ±= random.randint(0, int(humanize * 5))` — gentler than drums
|
||||
- Micro-timing: `pos += random.uniform(-humanize * 0.03, humanize * 0.03)` — tighter than drums
|
||||
|
||||
**Why**: Melodic instruments (bass, lead, pad) need subtler humanization than drums to avoid sounding out of tune.
|
||||
**Validation**: `bass_tresillo(key="Am", bars=1, humanize=0.5)` vs. `humanize=0.0` shows velocity/position variance.
|
||||
|
||||
### 4.2 Add humanization to melodic dispatcher (if exists)
|
||||
**File**: `src/composer/melodic.py`
|
||||
**Location**: Any `get_melodic_notes()` dispatcher function
|
||||
**Change**: Forward `humanize` parameter to all generators.
|
||||
**Why**: Single entry point for melodic generation.
|
||||
|
||||
---
|
||||
|
||||
## Phase 5 — Transitions
|
||||
|
||||
### 5.1 Create FX channel (ch21) with riser sample
|
||||
**File**: `scripts/compose_full_track.py`
|
||||
**Location**: After melodic track setup, before `SongDefinition`
|
||||
**Change**: Add FX channel (channel_index=21) with role `"fx"` and riser sample from `SampleSelector`. Use `rim_build_notes` pattern at channel 21 for riser fills. Place riser clips before chorus sections at bars 19 and 43 (1-bar riser items).
|
||||
**Why**: Transitions between verse→chorus need riser FX to build energy.
|
||||
**Note**: Verify ch21 is available (not used by drums/melodic); if conflicts, use next available.
|
||||
|
||||
### 5.2 Add rim_build pre-chorus fills
|
||||
**File**: `scripts/compose_full_track.py`
|
||||
**Location**: Arrangement items for bars 18–19 (pre-chorus 1) and 42–43 (pre-chorus 2)
|
||||
**Change**: Insert 2-bar rim_build pattern before each chorus:
|
||||
- Pattern id 9: `rim_build_notes` at channel 13
|
||||
- Place at bars 18–19 for chorus 1 (bars 20–31)
|
||||
- Place at bars 42–43 for chorus 2 (bars 44–55)
|
||||
**Why**: Rim roll builds tension going into the chorus ("rim_build" generator is designed for this).
|
||||
|
||||
### 5.3 Place riser FX before choruses
|
||||
**File**: `scripts/compose_full_track.py`
|
||||
**Location**: Arrangement items, pre-chorus sections
|
||||
**Change**: Add 1-bar riser clip at bars 19 and 43 (before chorus 1 and 2). Riser should be on a dedicated FX track (arrangement track 7).
|
||||
**Why**: Riser sample creates sonic "lift" into the chorus section.
|
||||
|
||||
---
|
||||
|
||||
## Phase 6 — Compose Script Update
|
||||
|
||||
### 6.1 Add reggaeton-standard mix values to PatternDefs
|
||||
**File**: `scripts/compose_full_track.py`
|
||||
**Location**: `patterns` list, lines 128–137
|
||||
**Change**: Set explicit mix values per pattern:
|
||||
- `kick_main`: volume=0.88, pan=0.0, reverb_send=0.1, delay_send=0.0
|
||||
- `kick_sparse`: volume=0.82, pan=0.0, reverb_send=0.1, delay_send=0.0
|
||||
- `snare_main`: volume=0.80, pan=0.05, reverb_send=0.35, delay_send=0.15
|
||||
- `hihat_main`: volume=0.65, pan=0.0, reverb_send=0.25, delay_send=0.0
|
||||
- `clap_main`: volume=0.82, pan=0.0, reverb_send=0.45, delay_send=0.1
|
||||
- `perc_main`: volume=0.72, pan=-0.15, reverb_send=0.3, delay_send=0.1
|
||||
- `perc2_main`: volume=0.72, pan=0.15, reverb_send=0.3, delay_send=0.1
|
||||
|
||||
**Why**: These values are the reggaeton-standard mix targets documented in the design.
|
||||
|
||||
### 6.2 Enable `groove_strength` on drum patterns
|
||||
**File**: `scripts/compose_full_track.py`
|
||||
**Location**: `patterns` list — update call sites that generate drum notes
|
||||
**Change**: Pass `groove_strength=0.3` to drum rhythm generators in compose script.
|
||||
**Why**: Drums benefit from subtle groove humanization to avoid mechanical feel.
|
||||
**Note**: This requires `get_notes()` to accept `groove_strength` (Phase 3 must be complete first).
|
||||
|
||||
### 6.3 Enable `humanize` on melodic tracks
|
||||
**File**: `scripts/compose_full_track.py`
|
||||
**Location**: `section_notes()` calls for bass, lead, pad, pluck
|
||||
**Change**: Pass `humanize=0.2` to melodic generators.
|
||||
**Why**: Melodic humanization makes bass/lead/pad feel organic and less quantized.
|
||||
|
||||
### 6.4 Add transition sections to arrangement
|
||||
**File**: `scripts/compose_full_track.py`
|
||||
**Location**: `items` list — insert pre-chorus transition blocks
|
||||
**Change**: Insert pre-chorus sections at bars 18–19 and 42–43:
|
||||
- Rim_build pattern at channel 13 (bars 18–19 and 42–43)
|
||||
- Riser FX at channel 21 (bars 19 and 43, 1 bar each)
|
||||
**Why**: Proper transitions create professional song flow rather than abrupt section changes.
|
||||
|
||||
---
|
||||
|
||||
## Dependencies
|
||||
|
||||
- Phase 2 depends on Phase 1 (schema fields needed before builder integration)
|
||||
- Phase 3 can run in parallel with Phase 4 (separate modules)
|
||||
- Phase 5 depends on Phase 2 (mix infrastructure for FX sends)
|
||||
- Phase 6 depends on Phases 2, 3, 4, 5 (all capabilities wired up)
|
||||
|
||||
## Files Modified (summary)
|
||||
|
||||
| File | Phases |
|
||||
|------|--------|
|
||||
| `src/flp_builder/events.py` | 1 |
|
||||
| `src/flp_builder/schema.py` | 2 |
|
||||
| `src/flp_builder/skeleton.py` | 2 |
|
||||
| `src/flp_builder/builder.py` | 2 |
|
||||
| `src/composer/rhythm.py` | 3 |
|
||||
| `src/composer/melodic.py` | 4 |
|
||||
| `scripts/compose_full_track.py` | 5, 6 |
|
||||
597
src/composer/templates.py
Normal file
597
src/composer/templates.py
Normal file
@@ -0,0 +1,597 @@
|
||||
"""RPP template extraction and generation.
|
||||
|
||||
Extracts track/FX chain structures from professionally-built .rpp files,
|
||||
fixes GUIDs with real values from reaper-vstplugins64.ini, and generates
|
||||
working .rpp files.
|
||||
|
||||
Usage:
|
||||
from src.composer.templates import extract_template, generate_rpp
|
||||
template = extract_template("ejemplos/TU_DIABLO_ITHAN_NY.rpp")
|
||||
generate_rpp(template, "output/tu_diablo_fixed.rpp")
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import re
|
||||
import uuid
|
||||
from dataclasses import dataclass, field
|
||||
from pathlib import Path
|
||||
from typing import Any
|
||||
|
||||
from rpp import Element, dumps
|
||||
|
||||
from src.reaper_builder import PLUGIN_REGISTRY, ALIAS_MAP, vst2_element, vst3_element, VST2_REGISTRY, VST3_REGISTRY, PLUGIN_PRESETS
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Template data classes
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
@dataclass
|
||||
class PluginTemplate:
|
||||
"""A plugin (instrument or effect) within a track FX chain."""
|
||||
name: str # Registry key (e.g. "Serum2", "Decapitator")
|
||||
path: str # Filename on disk (e.g. "Serum2.vst3", "Decapitator.dll")
|
||||
display_name: str # Full REAPER display name
|
||||
uniqueid_guid: str # uniqueid{GUID} from registry
|
||||
preset_data: list[str] | None = None
|
||||
is_vst2: bool = False # True for SoundToys .dll plugins
|
||||
index: int = 0 # Position in FX chain
|
||||
|
||||
def build_element(self) -> Element:
|
||||
"""Build a VST Element for this plugin."""
|
||||
if self.is_vst2:
|
||||
return vst2_element(self.display_name, self.path, self.uniqueid_guid, self.preset_data)
|
||||
return vst3_element(self.display_name, self.path, self.uniqueid_guid, self.preset_data)
|
||||
|
||||
|
||||
@dataclass
|
||||
class TrackTemplate:
|
||||
"""A track with its FX chain, extracted from an RPP template."""
|
||||
name: str
|
||||
volume: float = 0.85
|
||||
pan: float = 0.0
|
||||
color: int = 0
|
||||
is_bus: bool = False
|
||||
plugins: list[PluginTemplate] = field(default_factory=list)
|
||||
|
||||
|
||||
@dataclass
|
||||
class TemplateProject:
|
||||
"""A complete project template extracted from an RPP file."""
|
||||
name: str
|
||||
bpm: float
|
||||
key: str = "Am"
|
||||
time_sig_num: int = 4
|
||||
time_sig_den: int = 4
|
||||
tracks: list[TrackTemplate] = field(default_factory=list)
|
||||
|
||||
def generate_rpp(self, output_path: str | Path) -> None:
|
||||
"""Generate a working .rpp file from this template.
|
||||
|
||||
Uses RPPBuilder to produce REAPER 7.65 format with proper GUIDs,
|
||||
FXCHAIN structure, and base64 preset data.
|
||||
"""
|
||||
from src.core.schema import SongDefinition, SongMeta, TrackDef, PluginDef
|
||||
from src.reaper_builder import RPPBuilder
|
||||
|
||||
meta = SongMeta(
|
||||
bpm=self.bpm,
|
||||
key=self.key,
|
||||
title=self.name,
|
||||
time_sig_num=self.time_sig_num,
|
||||
time_sig_den=self.time_sig_den,
|
||||
)
|
||||
|
||||
# Convert TrackTemplate → TrackDef
|
||||
tracks: list[TrackDef] = []
|
||||
for tt in self.tracks:
|
||||
# Build PluginDef list for RPPBuilder
|
||||
plugin_defs: list[PluginDef] = []
|
||||
for pt in tt.plugins:
|
||||
plugin_defs.append(PluginDef(
|
||||
name=pt.name,
|
||||
path=pt.path,
|
||||
index=pt.index,
|
||||
preset_data=pt.preset_data,
|
||||
))
|
||||
|
||||
track_def = TrackDef(
|
||||
name=tt.name,
|
||||
volume=tt.volume,
|
||||
pan=tt.pan,
|
||||
color=tt.color,
|
||||
clips=[],
|
||||
plugins=plugin_defs,
|
||||
)
|
||||
tracks.append(track_def)
|
||||
|
||||
song = SongDefinition(meta=meta, tracks=tracks)
|
||||
builder = RPPBuilder(song)
|
||||
builder.write(str(output_path))
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Plugin substitution map (for non-existent plugins in source RPPs)
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
# Maps plugin names that appear in source RPPs but don't exist → substitute plugin key
|
||||
SUBSTITUTE: dict[str, str] = {
|
||||
# Transient Master not installed — replace with FabFilter Pro-C 2 (similar transient shaping)
|
||||
"Transient Master.dll": "FabFilter_Pro-C_2",
|
||||
"NI Transient Master": "FabFilter_Pro-C_2",
|
||||
"Transient Master (Native Instruments)": "FabFilter_Pro-C_2",
|
||||
# The Glue standalone .dll doesn't exist — use VST2 version from registry
|
||||
"Cytomic.dll": "The_Glue",
|
||||
# ValhallaDelay_x64.dll not in scan — use ValhallaDelay (VST2)
|
||||
"ValhallaDelay_x64.dll": "ValhallaDelay",
|
||||
# Pigments.exe wrong extension
|
||||
"Pigments.exe": "Pigments",
|
||||
# Gullfoss VST2 .dll — use registry keys
|
||||
"Gullfoss.dll": "Gullfoss",
|
||||
"Gullfoss Master.dll": "Gullfoss_Master",
|
||||
"Gullfoss Live.dll": "Gullfoss_Live",
|
||||
# VC 160/76 — fix display names from "VC 160 FX (Audified)" → registry keys
|
||||
"VC 160.vst3": "VC_160",
|
||||
"VC 76.vst3": "VC_76",
|
||||
"VC 2A.vst3": "VC_2A",
|
||||
# Kontakt 7 — fix display name
|
||||
"Kontakt 7.vst3": "Kontakt_7",
|
||||
# Source RPP display name → registry key (for non-matching display names)
|
||||
"VST3: VC 160 FX (Audified)": "VC_160",
|
||||
"VST3: VC 76 FX (Audified)": "VC_76",
|
||||
"VST3: VC 2A FX (Audified)": "VC_2A",
|
||||
"VST: TheGlue (Cytomic)": "The_Glue",
|
||||
"VST: ValhallaDelay x64 (Valhalla DSP)": "ValhallaDelay",
|
||||
"VST3: Kontakt 7 (Native Instruments)": "Kontakt_7",
|
||||
"VST: Gullfoss Master (Soundtheory)": "Gullfoss_Master",
|
||||
"VST: Gullfoss (Soundtheory)": "Gullfoss",
|
||||
"VST: Gullfoss Live (Soundtheory)": "Gullfoss_Live",
|
||||
}
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# GUID lookup helpers
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
def _lookup_vst3(name: str) -> tuple[str, str, str] | None:
|
||||
"""Look up VST3 plugin by registry key or filename."""
|
||||
# Try exact key match
|
||||
if name in VST3_REGISTRY:
|
||||
return VST3_REGISTRY[name]
|
||||
# Try filename match
|
||||
for display_name, filename, uid_guid in VST3_REGISTRY.values():
|
||||
if filename == name:
|
||||
return (display_name, filename, uid_guid)
|
||||
return None
|
||||
|
||||
|
||||
def _lookup_vst2(name: str) -> tuple[str, str, str] | None:
|
||||
"""Look up VST2/SoundToys plugin by registry key or filename."""
|
||||
# Try exact key match
|
||||
if name in VST2_REGISTRY:
|
||||
return VST2_REGISTRY[name]
|
||||
# Try filename match
|
||||
for display_name, filename, uid_guid in VST2_REGISTRY.values():
|
||||
if filename == name:
|
||||
return (display_name, filename, uid_guid)
|
||||
return None
|
||||
|
||||
|
||||
def _make_plugin_template(
|
||||
name: str,
|
||||
path: str,
|
||||
index: int = 0,
|
||||
) -> PluginTemplate | None:
|
||||
"""Create a PluginTemplate from plugin name + path, with GUID lookup.
|
||||
|
||||
Handles plugin substitution for non-existent plugins.
|
||||
Returns None if the plugin cannot be resolved.
|
||||
"""
|
||||
# Apply substitution if needed
|
||||
resolved_name = SUBSTITUTE.get(name, name)
|
||||
resolved_path = SUBSTITUTE.get(path, path)
|
||||
|
||||
# Try direct registry key lookup first (covers substituted names)
|
||||
direct_entry = PLUGIN_REGISTRY.get(resolved_name) or PLUGIN_REGISTRY.get(resolved_path)
|
||||
if direct_entry:
|
||||
is_vst2 = direct_entry[2].startswith("<")
|
||||
entry = direct_entry
|
||||
else:
|
||||
# Fall back to path-based detection
|
||||
is_vst2 = path.endswith(".dll")
|
||||
if is_vst2:
|
||||
entry = _lookup_vst2(resolved_path) or _lookup_vst2(resolved_name)
|
||||
else:
|
||||
entry = _lookup_vst3(resolved_path) or _lookup_vst3(resolved_name)
|
||||
|
||||
if entry:
|
||||
display_name, filename, uid_guid = entry
|
||||
preset_data = PLUGIN_PRESETS.get(resolved_name) if is_vst2 else PLUGIN_PRESETS.get(resolved_name)
|
||||
else:
|
||||
# Unresolved — use name/path as display name with empty GUID
|
||||
display_name = f"VST3: {resolved_name}" if not is_vst2 else f"VST: {resolved_name}"
|
||||
filename = resolved_path
|
||||
uid_guid = ""
|
||||
|
||||
return PluginTemplate(
|
||||
name=resolved_name,
|
||||
path=filename,
|
||||
display_name=display_name,
|
||||
uniqueid_guid=uid_guid,
|
||||
preset_data=preset_data,
|
||||
is_vst2=is_vst2,
|
||||
index=index,
|
||||
)
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# RPP parser (regex-based, handles both RPP library format and raw text)
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
# Regex patterns for parsing RPP files
|
||||
_TRACK_RE = re.compile(r'<TRACK\s+\{[^}]+\}', re.IGNORECASE)
|
||||
_TRACK_CLOSE_RE = re.compile(r'^\s*</TRACK>', re.IGNORECASE)
|
||||
_NAME_RE = re.compile(r'^\s*NAME\s+"([^"]*)"', re.IGNORECASE)
|
||||
_VOLPAN_RE = re.compile(r'^\s*VOLPAN\s+([\d.e+-]+)\s+([\d.e+-]+)', re.IGNORECASE)
|
||||
_ISBUS_RE = re.compile(r'^\s*ISBUS\s+(\d+)', re.IGNORECASE)
|
||||
_PEAKCOL_RE = re.compile(r'^\s*PEAKCOL\s+(\d+)', re.IGNORECASE)
|
||||
_FXCHAIN_RE = re.compile(r'^\s*<FXCHAIN', re.IGNORECASE)
|
||||
_FXCHAIN_CLOSE_RE = re.compile(r'^\s*</FXCHAIN>', re.IGNORECASE)
|
||||
# VST element: <VST "display name" "filename" 0 "" uniqueid{GUID} "" [preset lines] >
|
||||
# The header line ends with "" (closing of last string arg) followed by optional preset lines
|
||||
# and finally a > closing tag on its own line or after preset content.
|
||||
# The GUID portion (inside {} or <>) may be prefixed with an id number.
|
||||
# Examples from real RPPs:
|
||||
# <VST "VST: Decapitator (SoundToys)" "Decapitator.dll" 0 "" 1145980753<GUID> ""
|
||||
# <VST "VST3: Serum 2" "Serum2.vst3" 0 "" 0<> ""
|
||||
_VST_RE = re.compile(
|
||||
r'<VST\s+"([^"]+)"\s+"([^"]+)"\s+0\s+""\s*([\d<>{}a-fA-F0-9]+)\s*""',
|
||||
re.IGNORECASE,
|
||||
)
|
||||
_VST_CLOSE_RE = re.compile(r'^\s*</VST>', re.IGNORECASE)
|
||||
_PARAM_RE = re.compile(r'^\s*PARAM\s+\d+\s+"[^"]*"\s+', re.IGNORECASE)
|
||||
_TEMPO_RE = re.compile(r'^\s*TEMPO\s+([\d.e+-]+)\s+(\d+)\s+(\d+)', re.IGNORECASE)
|
||||
|
||||
|
||||
def _strip_invalid_params(lines: list[str]) -> list[str]:
|
||||
"""Remove invalid PARAM lines from preset data lines.
|
||||
|
||||
Claude's RPPs contain lines like:
|
||||
PARAM 0 "Drive" 0.35
|
||||
which are NOT valid REAPER tokens. REAPER stores parameter values in
|
||||
base64 preset data, not as named PARAM lines.
|
||||
"""
|
||||
result: list[str] = []
|
||||
for line in lines:
|
||||
stripped = line.strip()
|
||||
# Skip PARAM lines that match our pattern
|
||||
if _PARAM_RE.match(line):
|
||||
continue
|
||||
result.append(line)
|
||||
return result
|
||||
|
||||
|
||||
def _extract_guid(raw: str, filename: str, display_name: str) -> str:
|
||||
"""Extract clean GUID from raw GUID string.
|
||||
|
||||
Handles formats like:
|
||||
- "0<>" → lookup from registry (empty/fake GUID)
|
||||
- "1145980753<56535444454341>" → extract <GUID>
|
||||
- "691258006{56534558...}" → extract {GUID}
|
||||
- plain "0<>" or "0{}" → lookup from registry
|
||||
"""
|
||||
import re as re_module
|
||||
raw = raw.strip()
|
||||
|
||||
# Try extract <GUID> pattern (angle brackets)
|
||||
m = re_module.search(r'<([^<>]+)>', raw)
|
||||
if m:
|
||||
guid = m.group(1)
|
||||
# Check if it's a real GUID (not just angle bracket chars)
|
||||
if guid and guid not in ('<>', '{}', ''):
|
||||
return guid
|
||||
|
||||
# Try extract {GUID} pattern (curly braces)
|
||||
m = re_module.search(r'\{([^}]+)\}', raw)
|
||||
if m:
|
||||
guid = m.group(1)
|
||||
if guid and guid not in ('{}', ''):
|
||||
return guid
|
||||
|
||||
# Empty or fake GUID — lookup from registry
|
||||
is_vst2 = filename.endswith(".dll")
|
||||
key = _resolve_registry_key(display_name, filename, is_vst2)
|
||||
if key:
|
||||
if is_vst2:
|
||||
entry = VST2_REGISTRY.get(key)
|
||||
else:
|
||||
entry = VST3_REGISTRY.get(key)
|
||||
if entry:
|
||||
return entry[2] # Return the uid_guid from registry
|
||||
|
||||
return raw # Return as-is if no lookup found
|
||||
|
||||
|
||||
def _parse_vst_block(lines: list[str], start_idx: int) -> tuple[PluginTemplate | None, int]:
|
||||
"""Parse a VST element starting at start_idx in lines.
|
||||
|
||||
Returns (PluginTemplate, index_of_close_tag) or (None, start_idx) if not a VST block.
|
||||
"""
|
||||
line = lines[start_idx].strip()
|
||||
m = _VST_RE.match(line)
|
||||
if not m:
|
||||
return None, start_idx
|
||||
|
||||
display_name = m.group(1)
|
||||
filename = m.group(2)
|
||||
raw_guid = m.group(3).strip()
|
||||
|
||||
# Extract clean GUID from various formats:
|
||||
# - "0<>" (empty/fake GUID) → replace with registry lookup
|
||||
# - "1315270729<>" → registry lookup
|
||||
# - "1145980753<56535444454341>" → extract <GUID> portion
|
||||
# - "691258006{56534558667350736572756D20320000}" → extract {GUID} portion
|
||||
uid_guid = _extract_guid(raw_guid, filename, display_name)
|
||||
|
||||
# Collect preset data lines until closing >VST tag
|
||||
preset_lines: list[str] = []
|
||||
idx = start_idx + 1
|
||||
while idx < len(lines):
|
||||
l = lines[idx]
|
||||
ls = l.strip()
|
||||
if '</VST' in l or ls == '>' or ls.startswith('>'):
|
||||
break
|
||||
if ls.startswith('<VST') or ls.startswith('<TRACK') or ls.startswith('</TRACK') or ls.startswith('</FXCHAIN'):
|
||||
# Hit next element — not a preset line
|
||||
break
|
||||
# Collect line (strip PARAM lines later)
|
||||
preset_lines.append(l)
|
||||
idx += 1
|
||||
|
||||
preset_lines = _strip_invalid_params(preset_lines)
|
||||
|
||||
is_vst2 = filename.endswith(".dll")
|
||||
registry_key = _resolve_registry_key(display_name, filename, is_vst2)
|
||||
|
||||
if registry_key:
|
||||
if is_vst2:
|
||||
entry = VST2_REGISTRY.get(registry_key)
|
||||
else:
|
||||
entry = VST3_REGISTRY.get(registry_key)
|
||||
if entry:
|
||||
disp, fn, guid = entry
|
||||
uid_guid = guid
|
||||
display_name = disp
|
||||
filename = fn
|
||||
else:
|
||||
sub_key = SUBSTITUTE.get(filename) or SUBSTITUTE.get(display_name)
|
||||
if sub_key:
|
||||
sub_entry = PLUGIN_REGISTRY.get(sub_key)
|
||||
if sub_entry:
|
||||
display_name, filename, uid_guid = sub_entry
|
||||
is_vst2 = uid_guid.startswith("<")
|
||||
registry_key = sub_key
|
||||
|
||||
is_fake_preset = (
|
||||
not preset_lines
|
||||
or all(pl.strip() in ("0 0", "0", "") for pl in preset_lines)
|
||||
)
|
||||
if is_fake_preset and registry_key:
|
||||
registry_preset = PLUGIN_PRESETS.get(registry_key)
|
||||
if registry_preset:
|
||||
preset_lines = registry_preset
|
||||
|
||||
return PluginTemplate(
|
||||
name=registry_key or display_name,
|
||||
path=filename,
|
||||
display_name=display_name,
|
||||
uniqueid_guid=uid_guid,
|
||||
preset_data=preset_lines if preset_lines else None,
|
||||
is_vst2=is_vst2,
|
||||
index=0,
|
||||
), idx
|
||||
|
||||
|
||||
def _resolve_registry_key(display_name: str, filename: str, is_vst2: bool) -> str | None:
|
||||
"""Resolve a plugin display name/filename to a registry key."""
|
||||
if is_vst2:
|
||||
for key, (disp, fn, guid) in VST2_REGISTRY.items():
|
||||
if disp == display_name or fn == filename:
|
||||
return key
|
||||
else:
|
||||
for key, (disp, fn, guid) in VST3_REGISTRY.items():
|
||||
if disp == display_name or fn == filename:
|
||||
return key
|
||||
return None
|
||||
|
||||
|
||||
def _parse_track_block(lines: list[str], start_idx: int) -> tuple[TrackTemplate | None, int]:
|
||||
"""Parse a TRACK element starting at start_idx in lines.
|
||||
|
||||
Returns (TrackTemplate, index_after_close_tag) or (None, start_idx).
|
||||
"""
|
||||
line = lines[start_idx].strip()
|
||||
if not _TRACK_RE.match(line):
|
||||
return None, start_idx
|
||||
|
||||
name = ""
|
||||
volume = 0.85
|
||||
pan = 0.0
|
||||
color = 0
|
||||
is_bus = False
|
||||
plugins: list[PluginTemplate] = []
|
||||
plugin_index = 0
|
||||
|
||||
idx = start_idx + 1
|
||||
in_fxchain = False
|
||||
while idx < len(lines):
|
||||
l = lines[idx]
|
||||
ls = l.strip()
|
||||
|
||||
if ls.startswith('</TRACK>') or ls.startswith('</TRACK'):
|
||||
break
|
||||
|
||||
if in_fxchain:
|
||||
if _FXCHAIN_CLOSE_RE.match(ls):
|
||||
in_fxchain = False
|
||||
idx += 1
|
||||
continue
|
||||
|
||||
if _VST_RE.match(ls):
|
||||
plugin, new_idx = _parse_vst_block(lines, idx)
|
||||
if plugin:
|
||||
plugin.index = plugin_index
|
||||
plugin_index += 1
|
||||
plugins.append(plugin)
|
||||
idx = new_idx + 1
|
||||
continue
|
||||
else:
|
||||
if _FXCHAIN_RE.match(ls):
|
||||
in_fxchain = True
|
||||
idx += 1
|
||||
continue
|
||||
|
||||
m = _NAME_RE.match(l)
|
||||
if m:
|
||||
name = m.group(1)
|
||||
idx += 1
|
||||
continue
|
||||
|
||||
m = _VOLPAN_RE.match(l)
|
||||
if m:
|
||||
try:
|
||||
volume = float(m.group(1))
|
||||
except ValueError:
|
||||
pass
|
||||
try:
|
||||
pan = float(m.group(2))
|
||||
except ValueError:
|
||||
pass
|
||||
idx += 1
|
||||
continue
|
||||
|
||||
m = _PEAKCOL_RE.match(l)
|
||||
if m:
|
||||
try:
|
||||
color = int(m.group(1))
|
||||
except ValueError:
|
||||
pass
|
||||
idx += 1
|
||||
continue
|
||||
|
||||
m = _ISBUS_RE.match(l)
|
||||
if m:
|
||||
try:
|
||||
is_bus = int(m.group(1)) == 1
|
||||
except Value:
|
||||
pass
|
||||
idx += 1
|
||||
continue
|
||||
|
||||
idx += 1
|
||||
|
||||
if not name:
|
||||
name = "Unnamed Track"
|
||||
|
||||
return TrackTemplate(
|
||||
name=name,
|
||||
volume=volume,
|
||||
pan=pan,
|
||||
color=color,
|
||||
is_bus=is_bus,
|
||||
plugins=plugins,
|
||||
), idx
|
||||
|
||||
|
||||
def extract_template(rpp_path: str | Path) -> TemplateProject:
|
||||
"""Extract a TemplateProject from an existing .rpp file.
|
||||
|
||||
Parses track structures, FX chains, and plugin configurations,
|
||||
applying GUID corrections and stripping invalid PARAM lines.
|
||||
|
||||
Args:
|
||||
rpp_path: Path to source .rpp file
|
||||
|
||||
Returns:
|
||||
TemplateProject with all tracks and plugins resolved to registry entries
|
||||
|
||||
Raises:
|
||||
FileNotFoundError: If rpp_path doesn't exist
|
||||
ValueError: If file can't be parsed as RPP
|
||||
"""
|
||||
path = Path(rpp_path)
|
||||
if not path.exists():
|
||||
raise FileNotFoundError(f"RPP file not found: {path}")
|
||||
|
||||
content = path.read_text(encoding="utf-8")
|
||||
lines = content.split('\n')
|
||||
|
||||
# Extract tempo, key from header comments or TEMPO line
|
||||
bpm = 120.0
|
||||
key = "Am"
|
||||
time_sig_num, time_sig_den = 4, 4
|
||||
project_name = path.stem
|
||||
|
||||
# Parse TEMPO line
|
||||
for i, line in enumerate(lines):
|
||||
m = _TEMPO_RE.match(line.strip())
|
||||
if m:
|
||||
try:
|
||||
bpm = float(m.group(1))
|
||||
except ValueError:
|
||||
pass
|
||||
try:
|
||||
time_sig_num = int(m.group(2))
|
||||
time_sig_den = int(m.group(3))
|
||||
except ValueError:
|
||||
pass
|
||||
break
|
||||
|
||||
# Find project name from comments
|
||||
for line in lines:
|
||||
if 'PROYECTO:' in line:
|
||||
# Extract project name from comment
|
||||
m = re.search(r'PROYECTO:\s*(.+?)(?:\n|$)', line)
|
||||
if m:
|
||||
project_name = m.group(1).strip()
|
||||
break
|
||||
|
||||
# Extract tracks
|
||||
tracks: list[TrackTemplate] = []
|
||||
idx = 0
|
||||
while idx < len(lines):
|
||||
if _TRACK_RE.match(lines[idx].strip()):
|
||||
track, new_idx = _parse_track_block(lines, idx)
|
||||
if track:
|
||||
tracks.append(track)
|
||||
idx = new_idx + 1
|
||||
else:
|
||||
idx += 1
|
||||
|
||||
return TemplateProject(
|
||||
name=project_name,
|
||||
bpm=bpm,
|
||||
key=key,
|
||||
time_sig_num=time_sig_num,
|
||||
time_sig_den=time_sig_den,
|
||||
tracks=tracks,
|
||||
)
|
||||
|
||||
|
||||
def generate_rpp(template: TemplateProject, output_path: str | Path) -> None:
|
||||
"""Generate a working .rpp file from a TemplateProject.
|
||||
|
||||
Uses RPPBuilder to produce REAPER 7.65 format with correct GUIDs,
|
||||
proper FXCHAIN structure, and base64 preset data. All plugins are
|
||||
resolved via VST3_REGISTRY/VST2_REGISTRY.
|
||||
|
||||
Args:
|
||||
template: TemplateProject to generate from
|
||||
output_path: Destination .rpp path
|
||||
"""
|
||||
# Ensure output directory exists
|
||||
p = Path(output_path)
|
||||
p.parent.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
template.generate_rpp(str(p))
|
||||
@@ -143,6 +143,7 @@ class PluginDef:
|
||||
path: str
|
||||
index: int = 0
|
||||
params: dict[int, float] = field(default_factory=dict)
|
||||
preset_data: list[str] | None = None
|
||||
|
||||
|
||||
@dataclass
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -337,7 +337,7 @@ class TestVST3GUIDPresence:
|
||||
# Must contain the GUID token from VST3_REGISTRY["Serum2"]
|
||||
assert "691258006{56534558667350736572756D20320000}" in content
|
||||
# Must also contain correct display name and filename
|
||||
assert "VST3: Serum 2 (Xfer Records)" in content
|
||||
assert "VST3i: Serum 2 (Xfer Records)" in content
|
||||
assert "Serum2.vst3" in content
|
||||
finally:
|
||||
Path(tmp_path).unlink(missing_ok=True)
|
||||
@@ -361,7 +361,8 @@ class TestVST3GUIDPresence:
|
||||
# Must contain the GUID token from VST3_REGISTRY["FabFilter Pro-Q 3"]
|
||||
assert "756089518{72C4DB717A4D459AB97E51745D84B39D}" in content
|
||||
assert "VST3: Pro-Q 3 (FabFilter)" in content
|
||||
assert "FabFilter Pro-Q 3.vst3" in content
|
||||
# Filename in RPP is "FabFilter" (shared binary for all FabFilter plugins)
|
||||
assert "FabFilter 0" in content
|
||||
finally:
|
||||
Path(tmp_path).unlink(missing_ok=True)
|
||||
|
||||
@@ -424,9 +425,10 @@ class TestVST3PresetData:
|
||||
"""
|
||||
meta = SongMeta(bpm=95, key="Am", title="VST3 Preset Test")
|
||||
# Use actual filenames from registry so _build_plugin recognizes them as VST3
|
||||
from src.reaper_builder import VST3_REGISTRY
|
||||
plugins = [
|
||||
PluginDef(name=name, path=entry[1], index=i)
|
||||
for i, (name, entry) in enumerate(RPPBuilder.VST3_REGISTRY.items())
|
||||
for i, (name, entry) in enumerate(VST3_REGISTRY.items())
|
||||
]
|
||||
track = TrackDef(name="Test", clips=[], plugins=plugins)
|
||||
song = SongDefinition(meta=meta, tracks=[track])
|
||||
@@ -441,7 +443,12 @@ class TestVST3PresetData:
|
||||
builder.write(tmp_path)
|
||||
content = Path(tmp_path).read_text(encoding="utf-8")
|
||||
# Check that plugins WITH preset data have that data in output
|
||||
for name, preset_lines in RPPBuilder.VST3_PRESETS.items():
|
||||
from src.reaper_builder import PLUGIN_PRESETS, VST3_REGISTRY
|
||||
vst3_keys = set(VST3_REGISTRY.keys())
|
||||
for name, preset_lines in PLUGIN_PRESETS.items():
|
||||
# Only check VST3 plugins (skip VST2 plugins which are in the same dict now)
|
||||
if name not in vst3_keys:
|
||||
continue
|
||||
if len(preset_lines) > 0:
|
||||
# Check first preset line — most distinctive, no collision risk
|
||||
first_line = preset_lines[0]
|
||||
|
||||
@@ -55,22 +55,22 @@ class TestVST3Effects:
|
||||
from scripts.compose import _VST3_EFFECTS
|
||||
# Fruity Parametric EQ 2 normalizes to Pro-Q 3
|
||||
registry_key, filename = _VST3_EFFECTS["Pro-Q 3"]
|
||||
assert registry_key == "FabFilter Pro-Q 3"
|
||||
assert filename == "FabFilter Pro-Q 3.vst3"
|
||||
assert registry_key == "Pro-Q_3"
|
||||
assert filename == "FabFilter"
|
||||
|
||||
def test_fruity_compressor_maps_to_proc2(self):
|
||||
"""Fruity Compressor → FabFilter Pro-C 2 via normalization."""
|
||||
from scripts.compose import _VST3_EFFECTS
|
||||
registry_key, filename = _VST3_EFFECTS["Pro-C 2"]
|
||||
assert registry_key == "FabFilter Pro-C 2"
|
||||
assert filename == "FabFilter Pro-C 2.vst3"
|
||||
assert registry_key == "Pro-C_2"
|
||||
assert filename == "FabFilter"
|
||||
|
||||
def test_pro_r_maps_to_pror2(self):
|
||||
"""Pro-R 2 → FabFilter Pro-R 2."""
|
||||
from scripts.compose import _VST3_EFFECTS
|
||||
registry_key, filename = _VST3_EFFECTS["Pro-R 2"]
|
||||
assert registry_key == "FabFilter Pro-R 2"
|
||||
assert filename == "FabFilter Pro-R 2.vst3"
|
||||
assert registry_key == "Pro-R_2"
|
||||
assert filename == "FabFilter"
|
||||
|
||||
def test_unknown_effect_returns_none(self):
|
||||
"""Unknown effect names return no VST3 info."""
|
||||
@@ -96,11 +96,11 @@ class TestBuildFxChain:
|
||||
}
|
||||
plugins = build_fx_chain("drums", genre_config, [])
|
||||
assert len(plugins) == 2
|
||||
# Fruity Parametric EQ 2 → Pro-Q 3
|
||||
assert "FabFilter" in plugins[0].name
|
||||
assert ".vst3" in plugins[0].path
|
||||
# Pro-Q 3 via alias
|
||||
assert plugins[0].name in ("Pro-Q_3", "FabFilter_Pro-Q_3")
|
||||
assert plugins[0].path in ("FabFilter", "FabFilter Pro-Q 3.vst3")
|
||||
# Fruity Compressor → Pro-C 2
|
||||
assert "FabFilter" in plugins[1].name
|
||||
assert plugins[1].name in ("Pro-C_2", "FabFilter_Pro-C_2")
|
||||
|
||||
def test_build_fx_chain_bass(self):
|
||||
"""build_fx_chain returns PluginDef list for bass role."""
|
||||
@@ -188,7 +188,7 @@ class TestCreateReturnTracks:
|
||||
reverb = tracks[0]
|
||||
assert len(reverb.plugins) == 1
|
||||
assert "FabFilter" in reverb.plugins[0].name
|
||||
assert ".vst3" in reverb.plugins[0].path
|
||||
assert reverb.plugins[0].path in ("FabFilter", "FabFilter_Pro_R_2.vst3")
|
||||
|
||||
def test_delay_track_has_timeless3(self):
|
||||
"""Delay return track has FabFilter Timeless 3 plugin."""
|
||||
@@ -198,7 +198,7 @@ class TestCreateReturnTracks:
|
||||
delay = tracks[1]
|
||||
assert len(delay.plugins) == 1
|
||||
assert "Timeless" in delay.plugins[0].name
|
||||
assert ".vst3" in delay.plugins[0].path
|
||||
assert delay.plugins[0].path in ("FabFilter", "FabFilter_Timeless_3.vst3")
|
||||
|
||||
def test_return_tracks_have_volume_0_7(self):
|
||||
"""Return tracks have volume 0.7."""
|
||||
|
||||
Reference in New Issue
Block a user