Files
pi-multifx-pedal/scripts/generate_channel_presets.py
shawn 42d0592856 Add factory presets for Keys, Vocals, and Backing Tracks channels
3 banks per channel (9 total, 36 presets):
- Keys: Piano & Electric (bank 21), Synth Pads & Leads (22), Organ & Vintage Keys (23)
- Vocals: Lead Vocals (24), Harmony & Backing (25), Vocal FX (26)
- Backing Tracks: Mix Ready (27), Click & Guide (28), Ambient Pads (29)

Appropriate FX chains per channel — de-esser, HPF/LPF, shimmer_reverb,
stereo_widener, rotary_speaker for vocals and keys; master bus chain
for backing tracks. No IR cab blocks on vocal/backing presets.

Generated by scripts/generate_channel_presets.py
2026-06-13 10:09:25 -04:00

716 lines
28 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/usr/bin/env python3
"""Generate factory presets for Keys, Vocals, and Backing Tracks channels.
Creates 3 banks × 4 presets per channel under presets/factory/<channel>/.
Bank numbers start at 21 for Keys, 24 for Vocals, 27 for Backing Tracks
to avoid collisions with the existing 0-20 factory bank range.
"""
import json
import os
import sys
FACTORY_DIR = os.path.join(
os.path.dirname(os.path.dirname(__file__)), "presets", "factory"
)
# ── IR path shortcuts ───────────────────────────────────────────────────
IR = {
"vintage": "~/.pedal/irs/vintage-1x12.wav",
"british": "~/.pedal/irs/british-4x12.wav",
"american": "~/.pedal/irs/american-2x12.wav",
"modern": "~/.pedal/irs/modern-4x12.wav",
"jazz": "~/.pedal/irs/jazz-1x15.wav",
"boutique": "~/.pedal/irs/boutique-1x12.wav",
"mini": "~/.pedal/irs/mini-1x8.wav",
"bass_thick": "~/.pedal/irs/bass-thick_classic.wav",
}
# ── Helper builders ────────────────────────────────────────────────────
def noise_gate(threshold=0.01):
return {"fx_type": "noise_gate", "enabled": True, "bypass": False,
"params": {"threshold": threshold}, "nam_model_path": "", "ir_file_path": ""}
def compressor(threshold=0.3, ratio=4.0, gain=0.8):
return {"fx_type": "compressor", "enabled": True, "bypass": False,
"params": {"threshold": threshold, "ratio": ratio, "gain": gain},
"nam_model_path": "", "ir_file_path": ""}
def boost(gain_db=6.0):
return {"fx_type": "boost", "enabled": True, "bypass": False,
"params": {"gain_db": gain_db}, "nam_model_path": "", "ir_file_path": ""}
def overdrive(drive=0.5, gain=0.7, tone=0.5):
return {"fx_type": "overdrive", "enabled": True, "bypass": False,
"params": {"drive": drive, "tone": tone, "gain": gain},
"nam_model_path": "", "ir_file_path": ""}
def eq(bass=0.5, mid=0.5, treble=0.5):
return {"fx_type": "eq", "enabled": True, "bypass": False,
"params": {"bass": bass, "mid": mid, "treble": treble},
"nam_model_path": "", "ir_file_path": ""}
def ir_cab(ir_path):
return {"fx_type": "ir_cab", "enabled": True, "bypass": False,
"params": {"wet": 1.0, "dry": 0.0},
"nam_model_path": "", "ir_file_path": ir_path}
def delay(time=400.0, feedback=0.3, mix=0.25):
return {"fx_type": "delay", "enabled": True, "bypass": False,
"params": {"time": time, "feedback": feedback, "mix": mix},
"nam_model_path": "", "ir_file_path": ""}
def reverb(decay=0.4, mix=0.25, subtype=""):
fx = {"fx_type": "reverb", "enabled": True, "bypass": False,
"nam_model_path": "", "ir_file_path": ""}
params = {"decay": decay, "mix": mix}
if subtype:
params["subtype"] = subtype
fx["params"] = params
return fx
def chorus(rate=0.35, depth=0.5, mix=0.3):
return {"fx_type": "chorus", "enabled": True, "bypass": False,
"params": {"rate": rate, "depth": depth, "mix": mix},
"nam_model_path": "", "ir_file_path": ""}
def phaser(rate=0.3, depth=0.5, feedback=0.3):
return {"fx_type": "phaser", "enabled": True, "bypass": False,
"params": {"rate": rate, "depth": depth, "feedback": feedback},
"nam_model_path": "", "ir_file_path": ""}
def tremolo(rate=3.0, depth=0.4):
return {"fx_type": "tremolo", "enabled": True, "bypass": False,
"params": {"rate": rate, "depth": depth},
"nam_model_path": "", "ir_file_path": ""}
def volume(level=0.85):
return {"fx_type": "volume", "enabled": True, "bypass": False,
"params": {"level": level}, "nam_model_path": "", "ir_file_path": ""}
def pitch_shifter(semitones=0, mix=0.5):
return {"fx_type": "pitch_shifter", "enabled": True, "bypass": False,
"params": {"semitones": semitones, "mix": mix},
"nam_model_path": "", "ir_file_path": ""}
def stereo_widener(width=0.5, mix=0.5):
return {"fx_type": "stereo_widener", "enabled": True, "bypass": False,
"params": {"width": width, "mix": mix},
"nam_model_path": "", "ir_file_path": ""}
def auto_pan(rate=0.3, depth=0.5):
return {"fx_type": "auto_pan", "enabled": True, "bypass": False,
"params": {"rate": rate, "depth": depth},
"nam_model_path": "", "ir_file_path": ""}
def high_pass_filter(cutoff=80.0):
return {"fx_type": "high_pass_filter", "enabled": True, "bypass": False,
"params": {"cutoff": cutoff},
"nam_model_path": "", "ir_file_path": ""}
def low_pass_filter(cutoff=8000.0):
return {"fx_type": "low_pass_filter", "enabled": True, "bypass": False,
"params": {"cutoff": cutoff},
"nam_model_path": "", "ir_file_path": ""}
def de_esser(threshold=0.5, reduction=0.4):
return {"fx_type": "de_esser", "enabled": True, "bypass": False,
"params": {"threshold": threshold, "reduction": reduction},
"nam_model_path": "", "ir_file_path": ""}
def shimmer_reverb(decay=0.6, mix=0.3):
return {"fx_type": "shimmer_reverb", "enabled": True, "bypass": False,
"params": {"decay": decay, "mix": mix},
"nam_model_path": "", "ir_file_path": ""}
def multi_tap_delay(time=400.0, feedback=0.3, mix=0.25, taps=3):
return {"fx_type": "multi_tap_delay", "enabled": True, "bypass": False,
"params": {"time": time, "feedback": feedback, "mix": mix, "taps": taps},
"nam_model_path": "", "ir_file_path": ""}
def rotary_speaker(rate=1.5, mix=0.4):
return {"fx_type": "rotary_speaker", "enabled": True, "bypass": False,
"params": {"rate": rate, "mix": mix},
"nam_model_path": "", "ir_file_path": ""}
def expander(threshold=0.2, ratio=2.0):
return {"fx_type": "expander", "enabled": True, "bypass": False,
"params": {"threshold": threshold, "ratio": ratio},
"nam_model_path": "", "ir_file_path": ""}
# ── Channel definitions ─────────────────────────────────────────────────
CHANNELS = [
{
"slug": "keys",
"label": "Keys",
"bank_start": 21,
"banks": [
{
"name": "Piano & Electric",
"presets": [
{
"name": "Grand Piano Clean",
"master_volume": 0.82,
"chain": [
noise_gate(0.005),
compressor(0.2, 5.0, 0.6),
eq(0.5, 0.5, 0.55),
reverb(0.35, 0.2, "hall"),
volume(0.85),
],
},
{
"name": "Warm Rhodes",
"master_volume": 0.8,
"chain": [
noise_gate(0.005),
compressor(0.25, 4.0, 0.65),
chorus(0.3, 0.4, 0.25),
eq(0.45, 0.55, 0.5),
reverb(0.4, 0.22, "hall"),
volume(0.82),
],
},
{
"name": "Wurli Punch",
"master_volume": 0.78,
"chain": [
noise_gate(0.008),
compressor(0.3, 4.5, 0.7),
tremolo(4.0, 0.3),
eq(0.55, 0.4, 0.6),
reverb(0.3, 0.18, "room"),
volume(0.8),
],
},
{
"name": "Stage EP Layer",
"master_volume": 0.82,
"chain": [
noise_gate(0.005),
compressor(0.2, 5.0, 0.55),
stereo_widener(0.4, 0.3),
eq(0.4, 0.5, 0.6),
chorus(0.25, 0.35, 0.2),
reverb(0.45, 0.28, "hall"),
volume(0.84),
],
},
],
},
{
"name": "Synth Pads & Leads",
"presets": [
{
"name": "Analog Pad",
"master_volume": 0.78,
"chain": [
noise_gate(0.005),
compressor(0.25, 4.5, 0.65),
stereo_widener(0.6, 0.4),
chorus(0.2, 0.45, 0.35),
auto_pan(0.15, 0.3),
reverb(0.55, 0.35, "hall"),
volume(0.8),
],
},
{
"name": "Brass Synth Lead",
"master_volume": 0.85,
"chain": [
noise_gate(0.01),
compressor(0.3, 3.5, 0.85),
boost(3.0),
eq(0.45, 0.35, 0.7),
delay(420, 0.25, 0.2),
reverb(0.4, 0.22, "hall"),
volume(0.88),
],
},
{
"name": "Arp Texture",
"master_volume": 0.76,
"chain": [
noise_gate(0.005),
compressor(0.2, 5.0, 0.55),
eq(0.4, 0.55, 0.65),
multi_tap_delay(300, 0.2, 0.3, 3),
reverb(0.5, 0.3, "hall"),
volume(0.78),
],
},
{
"name": "Wobble Bass Synth",
"master_volume": 0.72,
"chain": [
noise_gate(0.012),
compressor(0.35, 6.0, 0.6),
low_pass_filter(2000.0),
eq(0.65, 0.25, 0.4),
reverb(0.2, 0.1, "room"),
volume(0.74),
],
},
],
},
{
"name": "Organ & Vintage Keys",
"presets": [
{
"name": "B3 Rotary Slow",
"master_volume": 0.8,
"chain": [
noise_gate(0.005),
compressor(0.2, 4.5, 0.65),
rotary_speaker(0.8, 0.4),
eq(0.5, 0.5, 0.55),
reverb(0.3, 0.15, "room"),
volume(0.82),
],
},
{
"name": "B3 Rotary Fast",
"master_volume": 0.82,
"chain": [
noise_gate(0.005),
compressor(0.2, 4.5, 0.7),
rotary_speaker(5.0, 0.5),
eq(0.45, 0.55, 0.5),
reverb(0.25, 0.12, "room"),
volume(0.84),
],
},
{
"name": "Clavinet Funk",
"master_volume": 0.76,
"chain": [
noise_gate(0.008),
compressor(0.35, 5.0, 0.6),
eq(0.6, 0.3, 0.7),
phaser(0.2, 0.35, 0.2),
reverb(0.2, 0.1, "room"),
volume(0.78),
],
},
{
"name": "Vox Continental",
"master_volume": 0.82,
"chain": [
noise_gate(0.005),
compressor(0.25, 4.0, 0.65),
eq(0.5, 0.45, 0.6),
tremolo(3.5, 0.3),
reverb(0.35, 0.18, "hall"),
volume(0.84),
],
},
],
},
],
},
{
"slug": "vocals",
"label": "Vocals",
"bank_start": 24,
"banks": [
{
"name": "Lead Vocals",
"presets": [
{
"name": "Vocal Standard",
"master_volume": 0.82,
"chain": [
high_pass_filter(80.0),
de_esser(0.5, 0.35),
compressor(0.25, 4.0, 0.7),
eq(0.45, 0.55, 0.55),
reverb(0.35, 0.22, "hall"),
volume(0.85),
],
},
{
"name": "Warm Lead",
"master_volume": 0.85,
"chain": [
high_pass_filter(75.0),
de_esser(0.45, 0.4),
compressor(0.2, 4.5, 0.75),
eq(0.5, 0.5, 0.45),
reverb(0.4, 0.25, "hall"),
delay(380, 0.2, 0.15),
volume(0.88),
],
},
{
"name": "Big Ballad",
"master_volume": 0.84,
"chain": [
high_pass_filter(70.0),
de_esser(0.5, 0.3),
compressor(0.22, 5.0, 0.8),
eq(0.45, 0.5, 0.5),
shimmer_reverb(0.55, 0.3),
delay(450, 0.3, 0.2),
volume(0.86),
],
},
{
"name": "Dry & Present",
"master_volume": 0.82,
"chain": [
high_pass_filter(90.0),
de_esser(0.55, 0.35),
compressor(0.28, 3.5, 0.85),
eq(0.4, 0.6, 0.55),
expander(0.15, 1.5),
volume(0.84),
],
},
],
},
{
"name": "Harmony & Backing",
"presets": [
{
"name": "Airy Harmonies",
"master_volume": 0.78,
"chain": [
high_pass_filter(100.0),
de_esser(0.5, 0.3),
compressor(0.2, 4.0, 0.6),
eq(0.4, 0.5, 0.65),
stereo_widener(0.5, 0.35),
reverb(0.45, 0.25, "hall"),
volume(0.8),
],
},
{
"name": "Doubler Effect",
"master_volume": 0.8,
"chain": [
high_pass_filter(90.0),
compressor(0.25, 4.0, 0.65),
eq(0.45, 0.5, 0.55),
chorus(0.2, 0.3, 0.35),
delay(220, 0.05, 0.25),
reverb(0.3, 0.18, "room"),
volume(0.82),
],
},
{
"name": "Wide Backing Stack",
"master_volume": 0.76,
"chain": [
high_pass_filter(80.0),
de_esser(0.45, 0.35),
compressor(0.2, 4.5, 0.55),
eq(0.4, 0.55, 0.6),
stereo_widener(0.7, 0.4),
reverb(0.5, 0.28, "hall"),
volume(0.78),
],
},
{
"name": "Soft Pad Vox",
"master_volume": 0.74,
"chain": [
high_pass_filter(120.0),
compressor(0.2, 5.0, 0.5),
eq(0.4, 0.5, 0.6),
chorus(0.18, 0.25, 0.4),
shimmer_reverb(0.5, 0.35),
volume(0.76),
],
},
],
},
{
"name": "Vocal FX",
"presets": [
{
"name": "Slap Delay",
"master_volume": 0.82,
"chain": [
high_pass_filter(80.0),
de_esser(0.5, 0.3),
compressor(0.25, 4.0, 0.7),
eq(0.45, 0.5, 0.55),
delay(120, 0.15, 0.35),
reverb(0.25, 0.12, "room"),
volume(0.84),
],
},
{
"name": "Ping Pong Echo",
"master_volume": 0.8,
"chain": [
high_pass_filter(80.0),
de_esser(0.5, 0.3),
compressor(0.25, 4.0, 0.65),
eq(0.45, 0.5, 0.55),
delay(380, 0.35, 0.3),
reverb(0.3, 0.15, "hall"),
volume(0.82),
],
},
{
"name": "Shimmer Wash",
"master_volume": 0.78,
"chain": [
high_pass_filter(100.0),
de_esser(0.55, 0.25),
compressor(0.2, 4.0, 0.6),
eq(0.4, 0.5, 0.6),
shimmer_reverb(0.65, 0.35),
delay(500, 0.25, 0.2),
volume(0.8),
],
},
{
"name": "Radio Filter",
"master_volume": 0.76,
"chain": [
high_pass_filter(300.0),
low_pass_filter(3500.0),
compressor(0.3, 6.0, 0.65),
eq(0.3, 0.1, 0.2),
reverb(0.2, 0.08, "room"),
volume(0.78),
],
},
],
},
],
},
{
"slug": "backing_tracks",
"label": "Backing Tracks",
"bank_start": 27,
"banks": [
{
"name": "Mix Ready",
"presets": [
{
"name": "Stereo Master Bus",
"master_volume": 0.82,
"chain": [
high_pass_filter(30.0),
low_pass_filter(18000.0),
compressor(0.2, 4.0, 0.6),
eq(0.5, 0.5, 0.5),
stereo_widener(0.3, 0.25),
volume(0.85),
],
},
{
"name": "Kick & Bass Focus",
"master_volume": 0.8,
"chain": [
high_pass_filter(25.0),
compressor(0.25, 5.0, 0.55),
eq(0.65, 0.35, 0.45),
volume(0.82),
],
},
{
"name": "Full Mix Compressed",
"master_volume": 0.78,
"chain": [
high_pass_filter(30.0),
compressor(0.15, 6.0, 0.5),
eq(0.5, 0.5, 0.55),
multi_tap_delay(200, 0.08, 0.1, 2),
reverb(0.15, 0.08, "room"),
volume(0.8),
],
},
{
"name": "Transparent Mix",
"master_volume": 0.85,
"chain": [
high_pass_filter(25.0),
compressor(0.2, 3.5, 0.65),
eq(0.5, 0.5, 0.5),
stereo_widener(0.2, 0.15),
volume(0.88),
],
},
],
},
{
"name": "Click & Guide",
"presets": [
{
"name": "Click Track + Backing",
"master_volume": 0.78,
"chain": [
high_pass_filter(40.0),
compressor(0.3, 4.0, 0.55),
eq(0.5, 0.4, 0.6),
reverb(0.2, 0.08, "room"),
volume(0.8),
],
},
{
"name": "Guide Vox Monitor",
"master_volume": 0.8,
"chain": [
high_pass_filter(80.0),
de_esser(0.5, 0.3),
compressor(0.25, 4.0, 0.65),
eq(0.45, 0.5, 0.5),
reverb(0.3, 0.15, "room"),
volume(0.82),
],
},
{
"name": "Scratch Guitar Mix",
"master_volume": 0.76,
"chain": [
noise_gate(0.008),
compressor(0.3, 4.0, 0.6),
eq(0.5, 0.45, 0.55),
reverb(0.2, 0.1, "room"),
volume(0.78),
],
},
{
"name": "Stereo Reference",
"master_volume": 0.82,
"chain": [
high_pass_filter(25.0),
low_pass_filter(20000.0),
compressor(0.18, 4.5, 0.55),
eq(0.5, 0.5, 0.55),
stereo_widener(0.4, 0.25),
volume(0.84),
],
},
],
},
{
"name": "Ambient Pads",
"presets": [
{
"name": "Wash Pad",
"master_volume": 0.74,
"chain": [
noise_gate(0.005),
compressor(0.2, 5.0, 0.5),
eq(0.4, 0.55, 0.5),
chorus(0.15, 0.5, 0.4),
stereo_widener(0.6, 0.4),
shimmer_reverb(0.6, 0.35),
volume(0.76),
],
},
{
"name": "Texture Swell",
"master_volume": 0.72,
"chain": [
noise_gate(0.005),
expander(0.1, 3.0),
eq(0.4, 0.55, 0.55),
auto_pan(0.12, 0.35),
reverb(0.65, 0.4, "hall"),
volume(0.74),
],
},
{
"name": "Drone Bed",
"master_volume": 0.7,
"chain": [
noise_gate(0.005),
low_pass_filter(1000.0),
eq(0.55, 0.4, 0.35),
chorus(0.12, 0.4, 0.45),
reverb(0.7, 0.45, "hall"),
volume(0.72),
],
},
{
"name": "Cinematic Swell",
"master_volume": 0.76,
"chain": [
noise_gate(0.005),
compressor(0.15, 5.0, 0.5),
eq(0.4, 0.5, 0.6),
stereo_widener(0.7, 0.35),
shimmer_reverb(0.55, 0.4),
delay(600, 0.2, 0.15),
volume(0.78),
],
},
],
},
],
},
]
def generate():
"""Write all factory preset JSON files to presets/factory/<channel>/bank_N/."""
total_presets = 0
total_banks = 0
for channel in CHANNELS:
ch_dir = os.path.join(FACTORY_DIR, channel["slug"])
bn = channel["bank_start"]
for bank_idx, bank_def in enumerate(channel["banks"]):
bank_num = bn + bank_idx
bank_dir = os.path.join(ch_dir, f"bank_{bank_num}")
os.makedirs(bank_dir, exist_ok=True)
# bank.json
bank_meta = {
"number": bank_num,
"name": bank_def["name"],
"preset_count": len(bank_def["presets"]),
}
with open(os.path.join(bank_dir, "bank.json"), "w") as f:
json.dump(bank_meta, f, indent=2)
f.write("\n")
# presets
for prog, preset_data in enumerate(bank_def["presets"]):
preset_json = {
"name": preset_data["name"],
"bank": bank_num,
"program": prog,
"master_volume": preset_data["master_volume"],
"chain": preset_data["chain"],
"midi_mappings": {},
}
path = os.path.join(bank_dir, f"preset_{prog}.json")
with open(path, "w") as f:
json.dump(preset_json, f, indent=2)
f.write("\n")
total_presets += 1
total_banks += 1
print(f"{channel['label']}: {total_banks} banks so far, {total_presets} presets")
print(f"\n✅ Generated {total_presets} presets across {total_banks} banks in 3 channels:")
for channel in CHANNELS:
print(f" {channel['label']}: {len(channel['banks'])} banks × {len(channel['banks'][0]['presets'])} presets = {len(channel['banks']) * len(channel['banks'][0]['presets'])} presets")
if __name__ == "__main__":
# Guard against running from wrong cwd
if not os.path.isdir(FACTORY_DIR):
# Try resolving relative to the script location
script_dir = os.path.dirname(os.path.abspath(__file__))
FACTORY_DIR_ALT = os.path.join(
os.path.dirname(os.path.dirname(script_dir)), "presets", "factory"
)
if os.path.isdir(FACTORY_DIR_ALT):
FACTORY_DIR = FACTORY_DIR_ALT
else:
print(f"Error: factory directory not found at {FACTORY_DIR} or {FACTORY_DIR_ALT}")
sys.exit(1)
generate()