feat(playground): add tiered synth parameter preset system

4 tiers of progressive complexity (Beginner 15 params → Expert 126),
13 presets total with per-param min/max/curve overrides that bias
distributions without clamping extremes. Preset dropdown in UI,
persisted to localStorage, supports ?preset= URL param.
This commit is contained in:
w1n5t0n 2026-03-23 00:50:56 +02:00
parent 4e32919494
commit 8a550361ea
5 changed files with 844 additions and 2 deletions

View file

@ -44,6 +44,7 @@ Key files: `js/nisps/` (ML core port), `js/ui/` (visualizer, joystick, controls)
|-------|-------|---------|--------|
| `tame` | 01 | 1 | Constrains synth output ranges toward safe limits |
| `spread` | 01 | 0.6 | Controls weight initialization, RL noise scaling, and weight decay (see below) |
| `preset` | preset id | _(none)_ | Auto-loads a synth parameter preset on first visit (e.g. `?preset=beginner-1`) |
#### `spread` — sigmoid saturation control
@ -76,6 +77,21 @@ The 126 synth parameters in `js/synth/param-map.js` were curated from the C15's
| PM shaper blend | 4 | Secondary routing params |
| FB Mix source selects | 4 | Discrete A/B selectors |
### Synth Presets
Presets (`js/synth/presets.js`) control which parameters the ML engine can modify, with unselected params muted at safe defaults. Each preset defines per-param `{ muted, fixedValue, min, max, curve }` — no training examples or model weights.
4 tiers of progressive complexity:
| Tier | Presets | Active params | What's exposed |
|------|---------|---------------|----------------|
| 1 (Beginner) | 1.11.4 | 15 | Basic ADSR, SVF cutoff/res, Shaper A drive/fold, output levels, reverb mix |
| 2 (Intermediate) | 2.12.4 | 40 | + Env B/C, filter FM, effects (reverb/echo/flanger), cabinet, stereo panning |
| 3 (Advanced) | 3.13.3 | ~95 | + Cross-oscillator PM, feedback mixer, dual shapers, comb/gap filters, ring mod |
| 4 (Expert) | 4.14.2 | 126 | Full engine |
Presets use `curve` values to bias parameter distributions (< 0.5 = spend more time low, > 0.5 = bias high) without clamping extremes. Users can tweak any preset via the group drawer after loading.
## Build System
This is an Arduino project targeting Raspberry Pi Pico. Build and upload using Arduino IDE or arduino-cli with the earlephilhower/pico board package.

View file

@ -28,6 +28,30 @@
<label>Vol <input type="range" id="quick-vol" min="0" max="1" step="0.01" value="0.5"></label>
<label>BPM <input type="range" id="quick-bpm" min="40" max="240" step="1" value="120"><span id="quick-bpm-val">120</span></label>
</div>
<select class="preset-select" id="synth-preset-select" title="Synth preset">
<option value="">Manual</option>
<optgroup label="Beginner">
<option value="beginner-1">1.1</option>
<option value="beginner-2">1.2</option>
<option value="beginner-3">1.3</option>
<option value="beginner-4">1.4</option>
</optgroup>
<optgroup label="Intermediate">
<option value="intermediate-1">2.1</option>
<option value="intermediate-2">2.2</option>
<option value="intermediate-3">2.3</option>
<option value="intermediate-4">2.4</option>
</optgroup>
<optgroup label="Advanced">
<option value="advanced-1">3.1</option>
<option value="advanced-2">3.2</option>
<option value="advanced-3">3.3</option>
</optgroup>
<optgroup label="Expert">
<option value="expert-1">4.1</option>
<option value="expert-2">4.2</option>
</optgroup>
</select>
</div>
<!-- Fullscreen flow field canvas -->
@ -226,6 +250,7 @@
<div class="help-section">
<h3>Synth Controls</h3>
<ul>
<li><strong>Presets</strong> &mdash; use the dropdown (top left, next to play) to choose a parameter preset. Lower tiers (1.x) expose fewer parameters for simpler exploration; higher tiers (3.x, 4.x) unlock cross-modulation, feedback, and the full engine. You can tweak any preset afterwards using the controls below.</li>
<li><strong>Hover any bar</strong> in the synth visualizer to see parameter name, current value, range, and curve</li>
<li><strong>Hover a group name</strong> (e.g. "Env A", "Osc B") at the top to open its control drawer:</li>
<ul>

View file

@ -822,6 +822,45 @@ html, body {
display: flex;
}
/* Synth preset dropdown */
.preset-select {
margin-left: 8px;
height: 36px;
padding: 0 10px;
border-radius: 18px;
border: 1px solid rgba(255, 255, 255, 0.08);
background: rgba(13, 13, 13, 0.65);
backdrop-filter: blur(16px);
-webkit-backdrop-filter: blur(16px);
color: var(--text);
font-family: inherit;
font-size: 11px;
cursor: pointer;
transition: background 0.15s, border-color 0.15s;
appearance: none;
-webkit-appearance: none;
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='6'%3E%3Cpath d='M0 0l5 6 5-6z' fill='%23888'/%3E%3C/svg%3E");
background-repeat: no-repeat;
background-position: right 8px center;
padding-right: 24px;
min-width: 0;
max-width: 160px;
text-overflow: ellipsis;
}
.preset-select:hover,
.preset-select:focus {
border-color: rgba(255, 255, 255, 0.15);
background-color: rgba(255, 255, 255, 0.06);
outline: none;
}
.preset-select option,
.preset-select optgroup {
background: #1a1a1a;
color: var(--text);
}
/* ---- Utility ---- */
.hidden {
display: none !important;

View file

@ -8,6 +8,7 @@ import { Arpeggiator } from './synth/arpeggiator.js';
import { MIDIInput } from './synth/midi-input.js';
import { SYNTH_PARAM_MAP, SYNTH_PARAM_NAMES, SYNTH_PARAM_COLORS, applyCurve, applyGroupOverride } from './synth/param-map.js';
import { GamepadInput } from './ui/gamepad.js';
import { SYNTH_PRESETS, PRESET_TIERS } from './synth/presets.js';
// ---- Constants ----
const N_INPUTS = 2;
@ -128,9 +129,13 @@ const SYNTH_SECTIONS = [
// Defaults are seeded from safeMin/safeMax in SYNTH_PARAM_MAP, scaled by the
// ?tame URL parameter (0 = unconstrained, 1 = full safe limits).
// localStorage overrides on load.
// Module-level tame so applyPreset() can use it
const _urlTame = parseFloat(new URLSearchParams(window.location.search).get('tame') ?? '1');
const tameLevel = isNaN(_urlTame) ? 1 : Math.max(0, Math.min(1, _urlTame));
const groupOverrides = (() => {
const urlTame = parseFloat(new URLSearchParams(window.location.search).get('tame') ?? '1');
const t = isNaN(urlTame) ? 1 : Math.max(0, Math.min(1, urlTame));
const t = tameLevel;
let flatIdx = 0;
return SYNTH_SECTIONS.map(sec => ({
curve: 0.5,
@ -150,6 +155,13 @@ const groupOverrides = (() => {
}));
})();
// Lookup: param name -> flat index (for preset application)
const paramNameToIndex = new Map();
SYNTH_PARAM_MAP.forEach((p, i) => paramNameToIndex.set(p.name, i));
// Currently active synth preset id (null = no preset / manual)
let activeSynthPresetId = null;
// Build a flat lookup: paramIndex -> { sectionIndex, localIndex }
const paramToSection = [];
{
@ -188,6 +200,93 @@ function isParamMuted(paramIndex) {
return groupOverrides[mapping.si].params[mapping.li].muted;
}
// ---- Synth Preset Application ----
/**
* Apply a synth preset by id.
* Sets groupOverrides (muted/active, min/max/curve/fixedValue) for all 126 params,
* re-routes outputs, saves state, and updates the UI dropdown.
*/
function applyPreset(presetId) {
const preset = SYNTH_PRESETS.find(p => p.id === presetId);
if (!preset) {
console.warn(`[NISPS] Unknown preset: ${presetId}`);
return;
}
const t = tameLevel;
const allActive = preset.active === null; // null = all params active (Tier 4)
const activeSet = allActive ? null : new Set(preset.active);
const overrides = preset.overrides || {};
const mutedOv = preset.mutedOverrides || {};
for (let i = 0; i < N_SYNTH_OUTPUTS; i++) {
const param = SYNTH_PARAM_MAP[i];
const mapping = paramToSection[i];
if (!mapping) continue;
const gp = groupOverrides[mapping.si].params[mapping.li];
const paramName = param.name;
// Tame-derived defaults for this param
const safeMin = param.safeMin ?? 0;
const safeMax = param.safeMax ?? 1;
const tameMin = safeMin * t;
const tameMax = 1 - (1 - safeMax) * t;
const isActive = allActive || activeSet.has(paramName);
if (isActive) {
gp.muted = false;
const ov = overrides[paramName];
if (ov) {
gp.min = ov.min !== undefined ? ov.min : tameMin;
gp.max = ov.max !== undefined ? ov.max : tameMax;
gp.curve = ov.curve !== undefined ? ov.curve : 0.5;
gp.fixedValue = ov.fixedValue !== undefined ? ov.fixedValue : param.defaultValue;
} else {
gp.min = tameMin;
gp.max = tameMax;
gp.curve = 0.5;
gp.fixedValue = param.defaultValue;
}
} else {
gp.muted = true;
const mov = mutedOv[paramName];
gp.fixedValue = (mov && mov.fixedValue !== undefined) ? mov.fixedValue : param.defaultValue;
// Keep tame-derived ranges for manual unmuting
gp.min = tameMin;
gp.max = tameMax;
gp.curve = 0.5;
}
}
// Apply group curves
for (let si = 0; si < SYNTH_SECTIONS.length; si++) {
const gc = preset.groupCurves || {};
const secName = SYNTH_SECTIONS[si].name;
groupOverrides[si].curve = (gc[secName] !== undefined) ? gc[secName] : 0.5;
}
activeSynthPresetId = presetId;
// Close the group drawer if open
hideGroupDrawer();
// Re-route outputs through updated overrides
if (iml) {
routeOutputs(iml.getOutputs());
}
// Update the preset dropdown
const $presetSelect = document.getElementById('synth-preset-select');
if ($presetSelect) $presetSelect.value = presetId;
// Save to storage
saveState();
console.log(`[NISPS] Applied synth preset: ${preset.name}`);
}
// ---- SynthVisualizer class ----
class SynthVisualizer {
constructor(canvas) {
@ -648,6 +747,19 @@ function init() {
// Restore saved state (if any)
loadState();
// Wire synth preset selector
wireSynthPresets();
// Check URL ?preset param (overrides localStorage)
const urlPreset = urlParams.get('preset');
if (urlPreset && SYNTH_PRESETS.some(p => p.id === urlPreset)) {
applyPreset(urlPreset);
} else if (activeSynthPresetId) {
// Restored from localStorage — sync the dropdown
const $ps = document.getElementById('synth-preset-select');
if ($ps) $ps.value = activeSynthPresetId;
}
// Initial inference
iml.setInput(0, joyX);
iml.setInput(1, joyY);
@ -1438,6 +1550,22 @@ function wireKeyboard() {
}
// ---- Quick play controls ----
// ---- Synth Preset Selector ----
function wireSynthPresets() {
const $select = document.getElementById('synth-preset-select');
if (!$select) return;
$select.addEventListener('change', () => {
const val = $select.value;
if (val === '') {
// "Manual" selected — clear preset tracking but don't change overrides
activeSynthPresetId = null;
saveState();
} else {
applyPreset(val);
}
});
}
function wireQuickPlayControls() {
const quickPlay = document.getElementById('quick-play');
const quickPlayIcon = document.getElementById('quick-play-icon');
@ -1879,6 +2007,7 @@ function saveState() {
joyX,
joyY,
groupOverrides,
synthPresetId: activeSynthPresetId,
};
localStorage.setItem(STORAGE_KEY, JSON.stringify(state));
} catch (e) {
@ -1924,6 +2053,11 @@ function loadState() {
}
}
// Restore synth preset id (just track it, don't re-apply — groupOverrides already restored above)
if (typeof state.synthPresetId === 'string') {
activeSynthPresetId = state.synthPresetId;
}
// Restore output mode
if (state.outputMode && state.outputMode !== outputMode) {
setOutputMode(state.outputMode);

View file

@ -0,0 +1,628 @@
// Synth presets for NISPS playground
// Each preset defines which of the 126 C15 params are active (ML-controlled)
// and which are muted at safe defaults. Organized in 4 tiers of complexity.
export const SYNTH_PRESETS = [
// ======================================================================
// TIER 1 — Beginner (15 active params)
// ======================================================================
{
id: 'beginner-1',
name: '1.1',
tier: 1,
description: 'Mellow filtered tones with slow attack and long reverb tail',
active: [
'Env_A_Att', 'Env_A_Dec_1', 'Env_A_Sus', 'Env_A_Rel',
'Osc_A_Fluct', 'Osc_B_Fluct',
'Shp_A_Drive', 'Shp_A_Fold',
'SV_Flt_Cut', 'SV_Flt_Res', 'SV_Flt_LBH',
'Out_Mix_A_Lvl', 'Out_Mix_SVF_Lvl', 'Out_Mix_Lvl',
'Reverb_Mix',
],
overrides: {
'Env_A_Att': { min: 0.2, max: 0.7, curve: 0.6 },
'Env_A_Dec_1': { min: 0.3, max: 0.8, curve: 0.55 },
'Env_A_Sus': { min: 0.3, max: 0.8, curve: 0.6 },
'Env_A_Rel': { min: 0.3, max: 0.65, curve: 0.55 },
'Osc_A_Fluct': { min: 0.0, max: 0.3, curve: 0.35 },
'Osc_B_Fluct': { min: 0.0, max: 0.3, curve: 0.35 },
'Shp_A_Drive': { min: 0.05, max: 0.35, curve: 0.35 },
'Shp_A_Fold': { min: 0.3, max: 0.7, curve: 0.45 },
'SV_Flt_Cut': { min: 0.15, max: 0.55, curve: 0.35 },
'SV_Flt_Res': { min: 0.2, max: 0.6, curve: 0.4 },
'SV_Flt_LBH': { min: 0.0, max: 0.4, curve: 0.35 },
'Out_Mix_A_Lvl': { min: 0.4, max: 0.85, curve: 0.55 },
'Out_Mix_SVF_Lvl': { min: 0.3, max: 0.8, curve: 0.55 },
'Out_Mix_Lvl': { min: 0.25, max: 0.6, curve: 0.45 },
'Reverb_Mix': { min: 0.15, max: 0.55, curve: 0.4 },
},
mutedOverrides: {},
groupCurves: {},
},
{
id: 'beginner-2',
name: '1.2',
tier: 1,
description: 'Snappy attack, crisp shaper, filter biased high',
active: [
'Env_A_Att', 'Env_A_Dec_1', 'Env_A_Sus', 'Env_A_Rel',
'Osc_A_Fluct', 'Osc_B_Fluct',
'Shp_A_Drive', 'Shp_A_Fold',
'SV_Flt_Cut', 'SV_Flt_Res', 'SV_Flt_LBH',
'Out_Mix_A_Lvl', 'Out_Mix_SVF_Lvl', 'Out_Mix_Lvl',
'Reverb_Mix',
],
overrides: {
'Env_A_Att': { min: 0.0, max: 0.1, curve: 0.3 },
'Env_A_Dec_1': { min: 0.15, max: 0.5, curve: 0.35 },
'Env_A_Sus': { min: 0.0, max: 0.4, curve: 0.4 },
'Env_A_Rel': { min: 0.15, max: 0.45, curve: 0.4 },
'Osc_A_Fluct': { min: 0.0, max: 0.2, curve: 0.35 },
'Osc_B_Fluct': { min: 0.0, max: 0.2, curve: 0.35 },
'Shp_A_Drive': { min: 0.15, max: 0.55, curve: 0.6 },
'Shp_A_Fold': { min: 0.2, max: 0.8, curve: 0.55 },
'SV_Flt_Cut': { min: 0.5, max: 0.95, curve: 0.65 },
'SV_Flt_Res': { min: 0.3, max: 0.7, curve: 0.55 },
'SV_Flt_LBH': { min: 0.4, max: 1.0, curve: 0.6 },
'Out_Mix_A_Lvl': { min: 0.4, max: 0.85, curve: 0.55 },
'Out_Mix_SVF_Lvl': { min: 0.35, max: 0.8, curve: 0.55 },
'Out_Mix_Lvl': { min: 0.2, max: 0.55, curve: 0.45 },
'Reverb_Mix': { min: 0.0, max: 0.25, curve: 0.35 },
},
mutedOverrides: {},
groupCurves: {},
},
{
id: 'beginner-3',
name: '1.3',
tier: 1,
description: 'Slow attack, high sustain, wide filter sweep, deep reverb',
active: [
'Env_A_Att', 'Env_A_Dec_1', 'Env_A_Sus', 'Env_A_Rel',
'Osc_A_Fluct', 'Osc_B_Fluct',
'Shp_A_Drive', 'Shp_A_Fold',
'SV_Flt_Cut', 'SV_Flt_Res', 'SV_Flt_LBH',
'Out_Mix_A_Lvl', 'Out_Mix_SVF_Lvl', 'Out_Mix_Lvl',
'Reverb_Mix',
],
overrides: {
'Env_A_Att': { min: 0.3, max: 0.85, curve: 0.6 },
'Env_A_Dec_1': { min: 0.4, max: 0.9, curve: 0.6 },
'Env_A_Sus': { min: 0.5, max: 1.0, curve: 0.6 },
'Env_A_Rel': { min: 0.35, max: 0.7, curve: 0.55 },
'Osc_A_Fluct': { min: 0.0, max: 0.4, curve: 0.35 },
'Osc_B_Fluct': { min: 0.0, max: 0.4, curve: 0.35 },
'Shp_A_Drive': { min: 0.0, max: 0.25, curve: 0.3 },
'Shp_A_Fold': { min: 0.4, max: 0.65, curve: 0.45 },
'SV_Flt_Cut': { min: 0.1, max: 0.85, curve: 0.45 },
'SV_Flt_Res': { min: 0.15, max: 0.55, curve: 0.4 },
'SV_Flt_LBH': { min: 0.0, max: 0.6, curve: 0.4 },
'Out_Mix_A_Lvl': { min: 0.45, max: 0.85, curve: 0.55 },
'Out_Mix_SVF_Lvl': { min: 0.4, max: 0.85, curve: 0.55 },
'Out_Mix_Lvl': { min: 0.2, max: 0.55, curve: 0.45 },
'Reverb_Mix': { min: 0.2, max: 0.65, curve: 0.45 },
},
mutedOverrides: {},
groupCurves: {},
},
{
id: 'beginner-4',
name: '1.4',
tier: 1,
description: 'Zero attack, fast decay, low sustain, bright filter with steep curve',
active: [
'Env_A_Att', 'Env_A_Dec_1', 'Env_A_Sus', 'Env_A_Rel',
'Osc_A_Fluct', 'Osc_B_Fluct',
'Shp_A_Drive', 'Shp_A_Fold',
'SV_Flt_Cut', 'SV_Flt_Res', 'SV_Flt_LBH',
'Out_Mix_A_Lvl', 'Out_Mix_SVF_Lvl', 'Out_Mix_Lvl',
'Reverb_Mix',
],
overrides: {
'Env_A_Att': { min: 0.0, max: 0.02, curve: 0.3 },
'Env_A_Dec_1': { min: 0.1, max: 0.4, curve: 0.35 },
'Env_A_Sus': { min: 0.0, max: 0.15, curve: 0.3 },
'Env_A_Rel': { min: 0.1, max: 0.35, curve: 0.4 },
'Osc_A_Fluct': { min: 0.0, max: 0.15, curve: 0.3 },
'Osc_B_Fluct': { min: 0.0, max: 0.15, curve: 0.3 },
'Shp_A_Drive': { min: 0.1, max: 0.45, curve: 0.55 },
'Shp_A_Fold': { min: 0.3, max: 0.75, curve: 0.55 },
'SV_Flt_Cut': { min: 0.55, max: 1.0, curve: 0.65 },
'SV_Flt_Res': { min: 0.25, max: 0.65, curve: 0.6 },
'SV_Flt_LBH': { min: 0.3, max: 0.8, curve: 0.55 },
'Out_Mix_A_Lvl': { min: 0.4, max: 0.85, curve: 0.55 },
'Out_Mix_SVF_Lvl': { min: 0.35, max: 0.8, curve: 0.55 },
'Out_Mix_Lvl': { min: 0.2, max: 0.55, curve: 0.45 },
'Reverb_Mix': { min: 0.0, max: 0.3, curve: 0.3 },
},
mutedOverrides: {},
groupCurves: {},
},
// ======================================================================
// TIER 2 — Intermediate (adds 25 params → 40 total)
// ======================================================================
{
id: 'intermediate-1',
name: '2.1',
tier: 2,
description: 'Lush reverb and echo, wide stereo spread, gentle cabinet warmth',
active: [
// Tier 1 base
'Env_A_Att', 'Env_A_Dec_1', 'Env_A_Sus', 'Env_A_Rel',
'Osc_A_Fluct', 'Osc_B_Fluct',
'Shp_A_Drive', 'Shp_A_Fold',
'SV_Flt_Cut', 'SV_Flt_Res', 'SV_Flt_LBH',
'Out_Mix_A_Lvl', 'Out_Mix_SVF_Lvl', 'Out_Mix_Lvl',
'Reverb_Mix',
// Tier 2 additions
'Env_A_BP', 'Env_A_Dec_2', 'Env_A_Gain',
'Env_B_Att', 'Env_B_Dec_1', 'Env_B_Sus', 'Env_B_Rel',
'Env_C_Att', 'Env_C_Dec_1',
'Shp_A_Asym', 'Shp_A_Mix',
'SV_Flt_FM', 'SV_Flt_Spread',
'Out_Mix_A_Pan', 'Out_Mix_To_FX',
'Reverb_Size', 'Reverb_Color',
'Echo_Mix', 'Echo_Time',
'Flanger_Mix', 'Flanger_Time', 'Flanger_Rate',
'Cabinet_Drive', 'Cabinet_Tilt', 'Cabinet_Mix',
],
overrides: {
'Env_A_Att': { min: 0.15, max: 0.6, curve: 0.55 },
'Env_A_Dec_1': { min: 0.3, max: 0.8, curve: 0.55 },
'Env_A_Sus': { min: 0.3, max: 0.8, curve: 0.6 },
'Env_A_Rel': { min: 0.3, max: 0.65, curve: 0.55 },
'SV_Flt_Cut': { min: 0.2, max: 0.75, curve: 0.45 },
'SV_Flt_Spread': { min: 0.2, max: 0.8, curve: 0.6 },
'Out_Mix_A_Pan': { min: 0.2, max: 0.8, curve: 0.5 },
'Out_Mix_To_FX': { min: 0.2, max: 0.7, curve: 0.55 },
'Reverb_Size': { min: 0.25, max: 0.65, curve: 0.6 },
'Reverb_Color': { min: 0.3, max: 0.7, curve: 0.45 },
'Reverb_Mix': { min: 0.15, max: 0.6, curve: 0.45 },
'Echo_Mix': { min: 0.1, max: 0.5, curve: 0.4 },
'Echo_Time': { min: 0.2, max: 0.7, curve: 0.55 },
'Flanger_Mix': { min: 0.0, max: 0.3, curve: 0.35 },
'Flanger_Time': { min: 0.2, max: 0.6, curve: 0.45 },
'Flanger_Rate': { min: 0.1, max: 0.4, curve: 0.4 },
'Cabinet_Drive': { min: 0.1, max: 0.35, curve: 0.35 },
'Cabinet_Tilt': { min: 0.3, max: 0.7, curve: 0.45 },
'Cabinet_Mix': { min: 0.1, max: 0.5, curve: 0.4 },
'Out_Mix_Lvl': { min: 0.2, max: 0.55, curve: 0.45 },
},
mutedOverrides: {},
groupCurves: {},
},
{
id: 'intermediate-2',
name: '2.2',
tier: 2,
description: 'Short envelopes, echo with rhythmic timing, flanger movement',
active: [
'Env_A_Att', 'Env_A_Dec_1', 'Env_A_Sus', 'Env_A_Rel',
'Osc_A_Fluct', 'Osc_B_Fluct',
'Shp_A_Drive', 'Shp_A_Fold',
'SV_Flt_Cut', 'SV_Flt_Res', 'SV_Flt_LBH',
'Out_Mix_A_Lvl', 'Out_Mix_SVF_Lvl', 'Out_Mix_Lvl',
'Reverb_Mix',
'Env_A_BP', 'Env_A_Dec_2', 'Env_A_Gain',
'Env_B_Att', 'Env_B_Dec_1', 'Env_B_Sus', 'Env_B_Rel',
'Env_C_Att', 'Env_C_Dec_1',
'Shp_A_Asym', 'Shp_A_Mix',
'SV_Flt_FM', 'SV_Flt_Spread',
'Out_Mix_A_Pan', 'Out_Mix_To_FX',
'Reverb_Size', 'Reverb_Color',
'Echo_Mix', 'Echo_Time',
'Flanger_Mix', 'Flanger_Time', 'Flanger_Rate',
'Cabinet_Drive', 'Cabinet_Tilt', 'Cabinet_Mix',
],
overrides: {
'Env_A_Att': { min: 0.0, max: 0.08, curve: 0.3 },
'Env_A_Dec_1': { min: 0.1, max: 0.4, curve: 0.35 },
'Env_A_Sus': { min: 0.0, max: 0.25, curve: 0.3 },
'Env_A_Rel': { min: 0.1, max: 0.35, curve: 0.35 },
'Env_B_Att': { min: 0.0, max: 0.05, curve: 0.3 },
'Env_B_Dec_1': { min: 0.1, max: 0.35, curve: 0.35 },
'SV_Flt_Cut': { min: 0.3, max: 0.9, curve: 0.55 },
'SV_Flt_FM': { min: 0.3, max: 0.7, curve: 0.45 },
'Echo_Mix': { min: 0.15, max: 0.55, curve: 0.45 },
'Echo_Time': { min: 0.15, max: 0.6, curve: 0.35 },
'Flanger_Mix': { min: 0.1, max: 0.5, curve: 0.4 },
'Flanger_Time': { min: 0.1, max: 0.5, curve: 0.45 },
'Flanger_Rate': { min: 0.2, max: 0.7, curve: 0.45 },
'Cabinet_Drive': { min: 0.15, max: 0.45, curve: 0.55 },
'Out_Mix_To_FX': { min: 0.25, max: 0.7, curve: 0.55 },
'Out_Mix_Lvl': { min: 0.2, max: 0.55, curve: 0.45 },
'Reverb_Mix': { min: 0.0, max: 0.2, curve: 0.3 },
},
mutedOverrides: {},
groupCurves: {},
},
{
id: 'intermediate-3',
name: '2.3',
tier: 2,
description: 'Long envelope times, filter FM, slow flanger, lush reverb',
active: [
'Env_A_Att', 'Env_A_Dec_1', 'Env_A_Sus', 'Env_A_Rel',
'Osc_A_Fluct', 'Osc_B_Fluct',
'Shp_A_Drive', 'Shp_A_Fold',
'SV_Flt_Cut', 'SV_Flt_Res', 'SV_Flt_LBH',
'Out_Mix_A_Lvl', 'Out_Mix_SVF_Lvl', 'Out_Mix_Lvl',
'Reverb_Mix',
'Env_A_BP', 'Env_A_Dec_2', 'Env_A_Gain',
'Env_B_Att', 'Env_B_Dec_1', 'Env_B_Sus', 'Env_B_Rel',
'Env_C_Att', 'Env_C_Dec_1',
'Shp_A_Asym', 'Shp_A_Mix',
'SV_Flt_FM', 'SV_Flt_Spread',
'Out_Mix_A_Pan', 'Out_Mix_To_FX',
'Reverb_Size', 'Reverb_Color',
'Echo_Mix', 'Echo_Time',
'Flanger_Mix', 'Flanger_Time', 'Flanger_Rate',
'Cabinet_Drive', 'Cabinet_Tilt', 'Cabinet_Mix',
],
overrides: {
'Env_A_Att': { min: 0.3, max: 0.85, curve: 0.6 },
'Env_A_Dec_1': { min: 0.5, max: 0.9, curve: 0.6 },
'Env_A_Dec_2': { min: 0.5, max: 0.85, curve: 0.6 },
'Env_A_Sus': { min: 0.4, max: 0.9, curve: 0.6 },
'Env_A_Rel': { min: 0.35, max: 0.65, curve: 0.55 },
'Env_B_Att': { min: 0.2, max: 0.7, curve: 0.6 },
'Env_B_Dec_1': { min: 0.4, max: 0.85, curve: 0.6 },
'Env_B_Sus': { min: 0.3, max: 0.8, curve: 0.55 },
'Env_C_Att': { min: 0.2, max: 0.6, curve: 0.55 },
'SV_Flt_Cut': { min: 0.15, max: 0.8, curve: 0.4 },
'SV_Flt_FM': { min: 0.25, max: 0.75, curve: 0.45 },
'SV_Flt_Spread': { min: 0.2, max: 0.7, curve: 0.55 },
'Reverb_Size': { min: 0.3, max: 0.65, curve: 0.55 },
'Reverb_Color': { min: 0.3, max: 0.7, curve: 0.45 },
'Reverb_Mix': { min: 0.2, max: 0.6, curve: 0.45 },
'Echo_Mix': { min: 0.05, max: 0.35, curve: 0.35 },
'Flanger_Mix': { min: 0.05, max: 0.35, curve: 0.35 },
'Flanger_Rate': { min: 0.05, max: 0.25, curve: 0.35 },
'Flanger_Time': { min: 0.2, max: 0.6, curve: 0.45 },
'Out_Mix_To_FX': { min: 0.2, max: 0.6, curve: 0.5 },
'Out_Mix_Lvl': { min: 0.2, max: 0.55, curve: 0.45 },
'Cabinet_Mix': { min: 0.1, max: 0.4, curve: 0.35 },
},
mutedOverrides: {},
groupCurves: {},
},
{
id: 'intermediate-4',
name: '2.4',
tier: 2,
description: 'Cabinet drive pushed, asymmetric shaper, compressed envelope, dry',
active: [
'Env_A_Att', 'Env_A_Dec_1', 'Env_A_Sus', 'Env_A_Rel',
'Osc_A_Fluct', 'Osc_B_Fluct',
'Shp_A_Drive', 'Shp_A_Fold',
'SV_Flt_Cut', 'SV_Flt_Res', 'SV_Flt_LBH',
'Out_Mix_A_Lvl', 'Out_Mix_SVF_Lvl', 'Out_Mix_Lvl',
'Reverb_Mix',
'Env_A_BP', 'Env_A_Dec_2', 'Env_A_Gain',
'Env_B_Att', 'Env_B_Dec_1', 'Env_B_Sus', 'Env_B_Rel',
'Env_C_Att', 'Env_C_Dec_1',
'Shp_A_Asym', 'Shp_A_Mix',
'SV_Flt_FM', 'SV_Flt_Spread',
'Out_Mix_A_Pan', 'Out_Mix_To_FX',
'Reverb_Size', 'Reverb_Color',
'Echo_Mix', 'Echo_Time',
'Flanger_Mix', 'Flanger_Time', 'Flanger_Rate',
'Cabinet_Drive', 'Cabinet_Tilt', 'Cabinet_Mix',
],
overrides: {
'Env_A_Att': { min: 0.0, max: 0.1, curve: 0.3 },
'Env_A_Dec_1': { min: 0.15, max: 0.5, curve: 0.4 },
'Env_A_Sus': { min: 0.1, max: 0.5, curve: 0.45 },
'Env_A_Rel': { min: 0.15, max: 0.4, curve: 0.4 },
'Shp_A_Drive': { min: 0.2, max: 0.55, curve: 0.6 },
'Shp_A_Fold': { min: 0.2, max: 0.8, curve: 0.55 },
'Shp_A_Asym': { min: 0.1, max: 0.7, curve: 0.6 },
'Shp_A_Mix': { min: 0.2, max: 0.8, curve: 0.55 },
'SV_Flt_Cut': { min: 0.25, max: 0.8, curve: 0.55 },
'SV_Flt_Res': { min: 0.3, max: 0.75, curve: 0.55 },
'Cabinet_Drive': { min: 0.3, max: 0.58, curve: 0.6 },
'Cabinet_Tilt': { min: 0.2, max: 0.65, curve: 0.55 },
'Cabinet_Mix': { min: 0.3, max: 0.8, curve: 0.6 },
'Out_Mix_Lvl': { min: 0.2, max: 0.5, curve: 0.45 },
'Reverb_Mix': { min: 0.0, max: 0.15, curve: 0.3 },
'Echo_Mix': { min: 0.0, max: 0.15, curve: 0.3 },
'Flanger_Mix': { min: 0.0, max: 0.1, curve: 0.3 },
},
mutedOverrides: {},
groupCurves: {},
},
// ======================================================================
// TIER 3 — Advanced (adds 55 params → 95 total)
// ======================================================================
{
id: 'advanced-1',
name: '3.1',
tier: 3,
description: 'Cross-oscillator PM, ring modulation, comb filter resonance, clean effects',
active: [
// Tier 1
'Env_A_Att', 'Env_A_Dec_1', 'Env_A_Sus', 'Env_A_Rel',
'Osc_A_Fluct', 'Osc_B_Fluct',
'Shp_A_Drive', 'Shp_A_Fold',
'SV_Flt_Cut', 'SV_Flt_Res', 'SV_Flt_LBH',
'Out_Mix_A_Lvl', 'Out_Mix_SVF_Lvl', 'Out_Mix_Lvl',
'Reverb_Mix',
// Tier 2
'Env_A_BP', 'Env_A_Dec_2', 'Env_A_Gain',
'Env_B_Att', 'Env_B_Dec_1', 'Env_B_Sus', 'Env_B_Rel',
'Env_C_Att', 'Env_C_Dec_1',
'Shp_A_Asym', 'Shp_A_Mix',
'SV_Flt_FM', 'SV_Flt_Spread',
'Out_Mix_A_Pan', 'Out_Mix_To_FX',
'Reverb_Size', 'Reverb_Color',
'Echo_Mix', 'Echo_Time',
'Flanger_Mix', 'Flanger_Time', 'Flanger_Rate',
'Cabinet_Drive', 'Cabinet_Tilt', 'Cabinet_Mix',
// Tier 3 additions
'Env_B_BP', 'Env_B_Dec_2', 'Env_B_Gain',
'Env_C_BP', 'Env_C_Dec_2', 'Env_C_Rel', 'Env_C_Sus',
'Osc_A_PM_Self', 'Osc_A_PM_B', 'Osc_A_PM_FB', 'Osc_A_Phase',
'Osc_B_PM_Self', 'Osc_B_PM_A', 'Osc_B_PM_FB', 'Osc_B_Phase',
'Shp_A_FB_Mix', 'Shp_A_Ring_Mod',
'Shp_B_Drive', 'Shp_B_Fold', 'Shp_B_Asym', 'Shp_B_Mix', 'Shp_B_FB_Mix', 'Shp_B_Ring_Mod',
'Comb_Flt_Pitch', 'Comb_Flt_Decay', 'Comb_Flt_In_A_B', 'Comb_Flt_AP_Res', 'Comb_Flt_PM',
'SV_Flt_In_A_B', 'SV_Flt_Comb_Mix', 'SV_Flt_Par', 'SV_Flt_FM_A_B',
'Gap_Flt_Center', 'Gap_Flt_Gap', 'Gap_Flt_Res', 'Gap_Flt_Mix',
'FB_Mix_Comb', 'FB_Mix_SVF', 'FB_Mix_FX', 'FB_Mix_Osc', 'FB_Mix_Lvl', 'FB_Mix_Drive',
'Out_Mix_B_Lvl', 'Out_Mix_B_Pan', 'Out_Mix_Comb_Lvl',
'Flanger_Feedback', 'Flanger_Stereo', 'Flanger_Phase',
'Echo_Feedback', 'Echo_Stereo',
'Reverb_Pre_Dly', 'Reverb_Chorus',
'Cabinet_Fold', 'Cabinet_Asym', 'Cabinet_Hi_Cut', 'Cabinet_Lo_Cut', 'Cabinet_Cab_Lvl',
'Unison_Detune',
],
overrides: {
'Env_A_Att': { min: 0.0, max: 0.05, curve: 0.3 },
'Env_A_Dec_1': { min: 0.2, max: 0.6, curve: 0.35 },
'Env_A_Sus': { min: 0.0, max: 0.2, curve: 0.3 },
'Env_A_Rel': { min: 0.2, max: 0.55, curve: 0.4 },
'Osc_A_PM_Self': { min: 0.3, max: 0.7, curve: 0.4 },
'Osc_A_PM_B': { min: 0.25, max: 0.7, curve: 0.4 },
'Osc_A_PM_FB': { min: 0.3, max: 0.65, curve: 0.4 },
'Osc_B_PM_Self': { min: 0.3, max: 0.7, curve: 0.4 },
'Osc_B_PM_A': { min: 0.25, max: 0.7, curve: 0.4 },
'Osc_B_PM_FB': { min: 0.3, max: 0.65, curve: 0.4 },
'Shp_A_Ring_Mod': { min: 0.0, max: 0.5, curve: 0.35 },
'Shp_B_Ring_Mod': { min: 0.0, max: 0.5, curve: 0.35 },
'Comb_Flt_Pitch': { min: 0.3, max: 0.7, curve: 0.45 },
'Comb_Flt_Decay': { min: 0.3, max: 0.7, curve: 0.4 },
'Comb_Flt_AP_Res': { min: 0.2, max: 0.65, curve: 0.4 },
'SV_Flt_Cut': { min: 0.3, max: 0.85, curve: 0.55 },
'Reverb_Mix': { min: 0.15, max: 0.5, curve: 0.4 },
'Reverb_Size': { min: 0.2, max: 0.55, curve: 0.45 },
'Reverb_Chorus': { min: 0.1, max: 0.5, curve: 0.4 },
'Echo_Mix': { min: 0.0, max: 0.25, curve: 0.35 },
'Flanger_Mix': { min: 0.0, max: 0.2, curve: 0.3 },
'FB_Mix_Lvl': { min: 0.1, max: 0.4, curve: 0.4 },
'FB_Mix_Drive': { min: 0.1, max: 0.3, curve: 0.35 },
'Out_Mix_Lvl': { min: 0.2, max: 0.55, curve: 0.45 },
'Out_Mix_B_Lvl': { min: 0.15, max: 0.6, curve: 0.45 },
},
mutedOverrides: {},
groupCurves: {},
},
{
id: 'advanced-2',
name: '3.2',
tier: 3,
description: 'Feedback mixer active, dual shapers, gap filter, gritty cabinet',
active: [
// Tier 1
'Env_A_Att', 'Env_A_Dec_1', 'Env_A_Sus', 'Env_A_Rel',
'Osc_A_Fluct', 'Osc_B_Fluct',
'Shp_A_Drive', 'Shp_A_Fold',
'SV_Flt_Cut', 'SV_Flt_Res', 'SV_Flt_LBH',
'Out_Mix_A_Lvl', 'Out_Mix_SVF_Lvl', 'Out_Mix_Lvl',
'Reverb_Mix',
// Tier 2
'Env_A_BP', 'Env_A_Dec_2', 'Env_A_Gain',
'Env_B_Att', 'Env_B_Dec_1', 'Env_B_Sus', 'Env_B_Rel',
'Env_C_Att', 'Env_C_Dec_1',
'Shp_A_Asym', 'Shp_A_Mix',
'SV_Flt_FM', 'SV_Flt_Spread',
'Out_Mix_A_Pan', 'Out_Mix_To_FX',
'Reverb_Size', 'Reverb_Color',
'Echo_Mix', 'Echo_Time',
'Flanger_Mix', 'Flanger_Time', 'Flanger_Rate',
'Cabinet_Drive', 'Cabinet_Tilt', 'Cabinet_Mix',
// Tier 3 additions
'Env_B_BP', 'Env_B_Dec_2', 'Env_B_Gain',
'Env_C_BP', 'Env_C_Dec_2', 'Env_C_Rel', 'Env_C_Sus',
'Osc_A_PM_Self', 'Osc_A_PM_B', 'Osc_A_PM_FB', 'Osc_A_Phase',
'Osc_B_PM_Self', 'Osc_B_PM_A', 'Osc_B_PM_FB', 'Osc_B_Phase',
'Shp_A_FB_Mix', 'Shp_A_Ring_Mod',
'Shp_B_Drive', 'Shp_B_Fold', 'Shp_B_Asym', 'Shp_B_Mix', 'Shp_B_FB_Mix', 'Shp_B_Ring_Mod',
'Comb_Flt_Pitch', 'Comb_Flt_Decay', 'Comb_Flt_In_A_B', 'Comb_Flt_AP_Res', 'Comb_Flt_PM',
'SV_Flt_In_A_B', 'SV_Flt_Comb_Mix', 'SV_Flt_Par', 'SV_Flt_FM_A_B',
'Gap_Flt_Center', 'Gap_Flt_Gap', 'Gap_Flt_Res', 'Gap_Flt_Mix',
'FB_Mix_Comb', 'FB_Mix_SVF', 'FB_Mix_FX', 'FB_Mix_Osc', 'FB_Mix_Lvl', 'FB_Mix_Drive',
'Out_Mix_B_Lvl', 'Out_Mix_B_Pan', 'Out_Mix_Comb_Lvl',
'Flanger_Feedback', 'Flanger_Stereo', 'Flanger_Phase',
'Echo_Feedback', 'Echo_Stereo',
'Reverb_Pre_Dly', 'Reverb_Chorus',
'Cabinet_Fold', 'Cabinet_Asym', 'Cabinet_Hi_Cut', 'Cabinet_Lo_Cut', 'Cabinet_Cab_Lvl',
'Unison_Detune',
],
overrides: {
'Env_A_Att': { min: 0.0, max: 0.15, curve: 0.3 },
'Env_A_Dec_1': { min: 0.2, max: 0.6, curve: 0.4 },
'Env_A_Sus': { min: 0.1, max: 0.5, curve: 0.45 },
'Shp_A_Drive': { min: 0.2, max: 0.55, curve: 0.6 },
'Shp_A_Asym': { min: 0.1, max: 0.65, curve: 0.6 },
'Shp_B_Drive': { min: 0.15, max: 0.55, curve: 0.6 },
'Shp_B_Asym': { min: 0.1, max: 0.6, curve: 0.55 },
'Shp_B_FB_Mix': { min: 0.1, max: 0.5, curve: 0.4 },
'Gap_Flt_Center': { min: 0.2, max: 0.8, curve: 0.45 },
'Gap_Flt_Gap': { min: 0.05, max: 0.4, curve: 0.35 },
'Gap_Flt_Res': { min: 0.2, max: 0.7, curve: 0.45 },
'Gap_Flt_Mix': { min: 0.2, max: 0.7, curve: 0.45 },
'FB_Mix_Comb': { min: 0.3, max: 0.65, curve: 0.45 },
'FB_Mix_SVF': { min: 0.3, max: 0.65, curve: 0.45 },
'FB_Mix_FX': { min: 0.3, max: 0.6, curve: 0.4 },
'FB_Mix_Osc': { min: 0.3, max: 0.6, curve: 0.4 },
'FB_Mix_Lvl': { min: 0.2, max: 0.5, curve: 0.4 },
'FB_Mix_Drive': { min: 0.15, max: 0.38, curve: 0.4 },
'Cabinet_Drive': { min: 0.3, max: 0.58, curve: 0.6 },
'Cabinet_Fold': { min: 0.15, max: 0.5, curve: 0.55 },
'Cabinet_Asym': { min: 0.1, max: 0.5, curve: 0.55 },
'Cabinet_Mix': { min: 0.3, max: 0.75, curve: 0.6 },
'Out_Mix_Lvl': { min: 0.18, max: 0.5, curve: 0.45 },
'Reverb_Mix': { min: 0.0, max: 0.25, curve: 0.3 },
'Echo_Mix': { min: 0.0, max: 0.2, curve: 0.3 },
},
mutedOverrides: {},
groupCurves: {},
},
{
id: 'advanced-3',
name: '3.3',
tier: 3,
description: 'Both oscillators through both filters, stereo panning, full effects',
active: [
// Tier 1
'Env_A_Att', 'Env_A_Dec_1', 'Env_A_Sus', 'Env_A_Rel',
'Osc_A_Fluct', 'Osc_B_Fluct',
'Shp_A_Drive', 'Shp_A_Fold',
'SV_Flt_Cut', 'SV_Flt_Res', 'SV_Flt_LBH',
'Out_Mix_A_Lvl', 'Out_Mix_SVF_Lvl', 'Out_Mix_Lvl',
'Reverb_Mix',
// Tier 2
'Env_A_BP', 'Env_A_Dec_2', 'Env_A_Gain',
'Env_B_Att', 'Env_B_Dec_1', 'Env_B_Sus', 'Env_B_Rel',
'Env_C_Att', 'Env_C_Dec_1',
'Shp_A_Asym', 'Shp_A_Mix',
'SV_Flt_FM', 'SV_Flt_Spread',
'Out_Mix_A_Pan', 'Out_Mix_To_FX',
'Reverb_Size', 'Reverb_Color',
'Echo_Mix', 'Echo_Time',
'Flanger_Mix', 'Flanger_Time', 'Flanger_Rate',
'Cabinet_Drive', 'Cabinet_Tilt', 'Cabinet_Mix',
// Tier 3 additions
'Env_B_BP', 'Env_B_Dec_2', 'Env_B_Gain',
'Env_C_BP', 'Env_C_Dec_2', 'Env_C_Rel', 'Env_C_Sus',
'Osc_A_PM_Self', 'Osc_A_PM_B', 'Osc_A_PM_FB', 'Osc_A_Phase',
'Osc_B_PM_Self', 'Osc_B_PM_A', 'Osc_B_PM_FB', 'Osc_B_Phase',
'Shp_A_FB_Mix', 'Shp_A_Ring_Mod',
'Shp_B_Drive', 'Shp_B_Fold', 'Shp_B_Asym', 'Shp_B_Mix', 'Shp_B_FB_Mix', 'Shp_B_Ring_Mod',
'Comb_Flt_Pitch', 'Comb_Flt_Decay', 'Comb_Flt_In_A_B', 'Comb_Flt_AP_Res', 'Comb_Flt_PM',
'SV_Flt_In_A_B', 'SV_Flt_Comb_Mix', 'SV_Flt_Par', 'SV_Flt_FM_A_B',
'Gap_Flt_Center', 'Gap_Flt_Gap', 'Gap_Flt_Res', 'Gap_Flt_Mix',
'FB_Mix_Comb', 'FB_Mix_SVF', 'FB_Mix_FX', 'FB_Mix_Osc', 'FB_Mix_Lvl', 'FB_Mix_Drive',
'Out_Mix_B_Lvl', 'Out_Mix_B_Pan', 'Out_Mix_Comb_Lvl',
'Flanger_Feedback', 'Flanger_Stereo', 'Flanger_Phase',
'Echo_Feedback', 'Echo_Stereo',
'Reverb_Pre_Dly', 'Reverb_Chorus',
'Cabinet_Fold', 'Cabinet_Asym', 'Cabinet_Hi_Cut', 'Cabinet_Lo_Cut', 'Cabinet_Cab_Lvl',
'Unison_Detune',
],
overrides: {
'Env_A_Att': { min: 0.05, max: 0.5, curve: 0.45 },
'Env_B_Att': { min: 0.05, max: 0.5, curve: 0.45 },
'Osc_A_PM_B': { min: 0.2, max: 0.65, curve: 0.45 },
'Osc_B_PM_A': { min: 0.2, max: 0.65, curve: 0.45 },
'SV_Flt_In_A_B': { min: 0.2, max: 0.8, curve: 0.5 },
'Comb_Flt_In_A_B': { min: 0.2, max: 0.8, curve: 0.5 },
'Out_Mix_A_Lvl': { min: 0.3, max: 0.8, curve: 0.55 },
'Out_Mix_B_Lvl': { min: 0.3, max: 0.8, curve: 0.55 },
'Out_Mix_A_Pan': { min: 0.15, max: 0.45, curve: 0.4 },
'Out_Mix_B_Pan': { min: 0.55, max: 0.85, curve: 0.6 },
'Out_Mix_Comb_Lvl': { min: 0.15, max: 0.6, curve: 0.45 },
'Out_Mix_Lvl': { min: 0.18, max: 0.5, curve: 0.45 },
'SV_Flt_Cut': { min: 0.15, max: 0.85, curve: 0.45 },
'SV_Flt_Spread': { min: 0.15, max: 0.75, curve: 0.55 },
'Flanger_Stereo': { min: 0.2, max: 0.8, curve: 0.6 },
'Echo_Stereo': { min: 0.2, max: 0.8, curve: 0.6 },
'Reverb_Mix': { min: 0.1, max: 0.5, curve: 0.4 },
'Echo_Mix': { min: 0.05, max: 0.4, curve: 0.4 },
'Flanger_Mix': { min: 0.05, max: 0.35, curve: 0.35 },
'Unison_Detune': { min: 0.0, max: 0.3, curve: 0.3 },
'FB_Mix_Lvl': { min: 0.15, max: 0.45, curve: 0.4 },
},
mutedOverrides: {},
groupCurves: {},
},
// ======================================================================
// TIER 4 — Expert (all 126 params active)
// ======================================================================
{
id: 'expert-1',
name: '4.1',
tier: 4,
description: 'All parameters active with conservative tame-derived ranges',
active: null, // null means ALL params active
overrides: {
// Use tame-derived defaults for everything (no per-param overrides)
},
mutedOverrides: {},
groupCurves: {},
},
{
id: 'expert-2',
name: '4.2',
tier: 4,
description: 'All parameters active with wider ranges for extreme exploration',
active: null, // all active
overrides: {
// Push ranges wider than tame defaults — halve the tame constraint
'Osc_A_PM_Self': { min: 0.1, max: 0.9, curve: 0.45 },
'Osc_A_PM_B': { min: 0.1, max: 0.9, curve: 0.45 },
'Osc_A_PM_FB': { min: 0.15, max: 0.85, curve: 0.45 },
'Osc_B_PM_Self': { min: 0.1, max: 0.9, curve: 0.45 },
'Osc_B_PM_A': { min: 0.1, max: 0.9, curve: 0.45 },
'Osc_B_PM_FB': { min: 0.15, max: 0.85, curve: 0.45 },
'Shp_A_Drive': { min: 0.0, max: 0.8, curve: 0.55 },
'Shp_B_Drive': { min: 0.0, max: 0.8, curve: 0.55 },
'Shp_A_FB_Mix': { min: 0.0, max: 0.85, curve: 0.45 },
'Shp_B_FB_Mix': { min: 0.0, max: 0.85, curve: 0.45 },
'Comb_Flt_Decay': { min: 0.15, max: 0.85, curve: 0.45 },
'Comb_Flt_AP_Res': { min: 0.0, max: 0.9, curve: 0.4 },
'Comb_Flt_PM': { min: 0.15, max: 0.85, curve: 0.45 },
'SV_Flt_Res': { min: 0.0, max: 0.9, curve: 0.4 },
'SV_Flt_FM': { min: 0.1, max: 0.9, curve: 0.45 },
'Gap_Flt_Res': { min: 0.0, max: 0.9, curve: 0.4 },
'FB_Mix_Comb': { min: 0.15, max: 0.85, curve: 0.45 },
'FB_Mix_SVF': { min: 0.15, max: 0.85, curve: 0.45 },
'FB_Mix_FX': { min: 0.15, max: 0.85, curve: 0.45 },
'FB_Mix_Osc': { min: 0.15, max: 0.85, curve: 0.45 },
'FB_Mix_Lvl': { min: 0.0, max: 0.65, curve: 0.4 },
'FB_Mix_Drive': { min: 0.0, max: 0.5, curve: 0.4 },
'Out_Mix_Lvl': { min: 0.1, max: 0.8, curve: 0.45 },
'Out_Mix_Drive': { min: 0.0, max: 0.65, curve: 0.55 },
'Cabinet_Drive': { min: 0.0, max: 0.75, curve: 0.55 },
'Flanger_Feedback':{ min: 0.1, max: 0.9, curve: 0.45 },
'Flanger_Cross_FB':{ min: 0.15, max: 0.85, curve: 0.45 },
'Echo_Feedback': { min: 0.0, max: 0.85, curve: 0.4 },
'Echo_Mix': { min: 0.0, max: 0.8, curve: 0.4 },
'Reverb_Size': { min: 0.0, max: 0.8, curve: 0.45 },
'Reverb_Mix': { min: 0.0, max: 0.8, curve: 0.4 },
'Reverb_Send': { min: 0.0, max: 1.0, curve: 0.5 },
},
mutedOverrides: {},
groupCurves: {},
},
];
// Tier metadata for UI grouping
export const PRESET_TIERS = [
{ tier: 1, label: 'Beginner' },
{ tier: 2, label: 'Intermediate' },
{ tier: 3, label: 'Advanced' },
{ tier: 4, label: 'Expert' },
];