feat(playground): expand C15 param map from 20 to 126 synth parameters
Control all sonically meaningful C15 parameters through NISPS ML outputs. Excludes hardware routing, macros, scale/tuning, key tracking, velocity, envelope mod depths, discrete switches, and dangerous volume/pitch params. - Expand param-map.js with 126 curated params grouped by synthesis section - Widen MLP architecture from [3,10,10,14,20] to [3,32,48,64,126] - Add ParamDisplay.rebuild() for mode-dependent bar count (20 visual, 126 synth) - Add scrollable compact layout for synth mode param bars - Pad visual presets and old saves to 126 outputs for backward compatibility
This commit is contained in:
parent
6f6a334529
commit
24e3e9665e
4 changed files with 301 additions and 52 deletions
|
|
@ -397,11 +397,36 @@ html, body {
|
|||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.param-container.synth-mode {
|
||||
max-height: 50vh;
|
||||
overflow-y: auto;
|
||||
scrollbar-width: thin;
|
||||
scrollbar-color: #444 #1a1a1a;
|
||||
}
|
||||
|
||||
.param-container.synth-mode .param-row {
|
||||
height: 16px;
|
||||
}
|
||||
|
||||
.param-container.synth-mode .param-label {
|
||||
width: 72px;
|
||||
width: 82px;
|
||||
font-size: 9px;
|
||||
color: #886644;
|
||||
}
|
||||
|
||||
.param-container.synth-mode .param-track {
|
||||
height: 6px;
|
||||
}
|
||||
|
||||
.param-container.synth-mode .param-value {
|
||||
font-size: 8px;
|
||||
min-width: 24px;
|
||||
}
|
||||
|
||||
.param-container.synth-mode.draggable .param-track {
|
||||
height: 10px;
|
||||
}
|
||||
|
||||
.param-track {
|
||||
flex: 1;
|
||||
height: 8px;
|
||||
|
|
|
|||
|
|
@ -11,7 +11,9 @@ import { Arpeggiator } from './synth/arpeggiator.js';
|
|||
import { SYNTH_PARAM_MAP, SYNTH_PARAM_NAMES, SYNTH_PARAM_COLORS } from './synth/param-map.js';
|
||||
|
||||
const N_INPUTS = 2;
|
||||
const N_OUTPUTS = 20;
|
||||
const N_VISUAL_OUTPUTS = 20;
|
||||
const N_SYNTH_OUTPUTS = SYNTH_PARAM_MAP.length; // 126
|
||||
const N_OUTPUTS = N_SYNTH_OUTPUTS; // MLP always produces full output; visual uses first 20
|
||||
|
||||
// Visual mode param display config
|
||||
const VISUAL_PARAM_NAMES = ['Flow', 'Scale', 'Speed', 'Hue', 'Spread', 'Size', 'Trail', 'Turb', 'Attract', 'Radius', 'DispRate', 'DispAmt', 'Lifetime', 'Respawn', 'Advection', 'Inertia', 'Drag', 'Repulse', 'RepCnt', 'RepRate'];
|
||||
|
|
@ -43,7 +45,7 @@ let arpeggiator = null;
|
|||
|
||||
// --- Init ---
|
||||
function init() {
|
||||
iml = new IML(N_INPUTS, N_OUTPUTS, [10, 10, 14], 1000, 1.0, 0.00001);
|
||||
iml = new IML(N_INPUTS, N_OUTPUTS, [32, 48, 64], 1000, 1.0, 0.00001);
|
||||
iml.setLogger(msg => console.log('[NISPS]', msg));
|
||||
|
||||
// Visualizer
|
||||
|
|
@ -65,8 +67,8 @@ function init() {
|
|||
},
|
||||
});
|
||||
|
||||
// Parameter display
|
||||
paramDisplay = new ParamDisplay(document.getElementById('param-display'), N_OUTPUTS);
|
||||
// Parameter display (start in visual mode with 20 params)
|
||||
paramDisplay = new ParamDisplay(document.getElementById('param-display'), N_VISUAL_OUTPUTS);
|
||||
|
||||
// Controls
|
||||
controls = new Controls(document.getElementById('controls-container'), {
|
||||
|
|
@ -181,8 +183,9 @@ function setOutputMode(mode) {
|
|||
modeBadge.classList.add('synth');
|
||||
paramContainer.classList.add('synth-mode');
|
||||
|
||||
// Rebuild param display with synth labels/colors
|
||||
paramDisplay.setNamesAndColors(SYNTH_PARAM_NAMES, SYNTH_PARAM_COLORS);
|
||||
// Rebuild param display with all synth params
|
||||
paramDisplay.rebuild(N_SYNTH_OUTPUTS, SYNTH_PARAM_NAMES, SYNTH_PARAM_COLORS);
|
||||
paramDisplay.setDraggable(learningMode === 'examples');
|
||||
} else {
|
||||
synthControls.classList.add('hidden');
|
||||
visualInfo.classList.remove('hidden');
|
||||
|
|
@ -191,8 +194,9 @@ function setOutputMode(mode) {
|
|||
modeBadge.classList.remove('synth');
|
||||
paramContainer.classList.remove('synth-mode');
|
||||
|
||||
// Restore visual param labels/colors
|
||||
paramDisplay.setNamesAndColors(VISUAL_PARAM_NAMES, VISUAL_PARAM_COLORS);
|
||||
// Rebuild param display with visual params (first 20)
|
||||
paramDisplay.rebuild(N_VISUAL_OUTPUTS, VISUAL_PARAM_NAMES, VISUAL_PARAM_COLORS);
|
||||
paramDisplay.setDraggable(learningMode === 'examples');
|
||||
}
|
||||
|
||||
// Re-run inference and route outputs
|
||||
|
|
@ -438,26 +442,33 @@ function setVisualExpanded(expanded) {
|
|||
}
|
||||
|
||||
// --- Presets ---
|
||||
// Pad a 20-element visual preset array to N_OUTPUTS with 0.5 defaults
|
||||
function padPreset(values20) {
|
||||
const padded = new Array(N_OUTPUTS).fill(0.5);
|
||||
for (let i = 0; i < values20.length; i++) padded[i] = values20[i];
|
||||
return padded;
|
||||
}
|
||||
|
||||
window.loadPreset = function(name) {
|
||||
iml.clearDataset();
|
||||
|
||||
if (name === 'calm-to-chaotic') {
|
||||
// Bottom-left: slow, smooth, cool; top-right: fast, turbulent, warm
|
||||
iml.addExample([0.1, 0.9], [0.25, 0.3, 0.1, 0.55, 0.2, 0.3, 0.02, 0.05, 0.9, 0.45, 0.25, 0.2, 0.9, 0.0, 0.0, 0.2, 0.05, 0.0, 0.0, 0.2]);
|
||||
iml.addExample([0.9, 0.1], [0.75, 0.7, 0.9, 0.05, 0.8, 0.7, 0.9, 0.95, 0.3, 0.2, 0.85, 0.7, 0.25, 0.55, 1.0, 0.92, 0.02, 0.95, 0.8, 0.85]);
|
||||
iml.addExample([0.5, 0.5], [0.5, 0.5, 0.5, 0.3, 0.5, 0.5, 0.4, 0.5, 0.7, 0.6, 0.5, 0.45, 0.55, 0.9, 0.5, 0.65, 0.08, 0.45, 0.4, 0.5]);
|
||||
iml.addExample([0.1, 0.9], padPreset([0.25, 0.3, 0.1, 0.55, 0.2, 0.3, 0.02, 0.05, 0.9, 0.45, 0.25, 0.2, 0.9, 0.0, 0.0, 0.2, 0.05, 0.0, 0.0, 0.2]));
|
||||
iml.addExample([0.9, 0.1], padPreset([0.75, 0.7, 0.9, 0.05, 0.8, 0.7, 0.9, 0.95, 0.3, 0.2, 0.85, 0.7, 0.25, 0.55, 1.0, 0.92, 0.02, 0.95, 0.8, 0.85]));
|
||||
iml.addExample([0.5, 0.5], padPreset([0.5, 0.5, 0.5, 0.3, 0.5, 0.5, 0.4, 0.5, 0.7, 0.6, 0.5, 0.45, 0.55, 0.9, 0.5, 0.65, 0.08, 0.45, 0.4, 0.5]));
|
||||
} else if (name === 'rainbow-sweep') {
|
||||
// Left to right sweeps through hues
|
||||
iml.addExample([0.0, 0.5], [0.5, 0.5, 0.4, 0.0, 0.3, 0.4, 0.05, 0.3, 0.8, 0.55, 0.4, 0.3, 0.8, 0.0, 0.0, 0.45, 0.08, 0.2, 0.25, 0.45]);
|
||||
iml.addExample([0.5, 0.5], [0.5, 0.5, 0.4, 0.5, 0.3, 0.4, 0.05, 0.3, 0.8, 0.55, 0.55, 0.35, 0.7, 0.0, 0.4, 0.45, 0.08, 0.45, 0.4, 0.6]);
|
||||
iml.addExample([1.0, 0.5], [0.5, 0.5, 0.4, 1.0, 0.3, 0.4, 0.05, 0.3, 0.8, 0.55, 0.75, 0.45, 0.6, 0.0, 0.8, 0.45, 0.08, 0.7, 0.55, 0.75]);
|
||||
iml.addExample([0.0, 0.5], padPreset([0.5, 0.5, 0.4, 0.0, 0.3, 0.4, 0.05, 0.3, 0.8, 0.55, 0.4, 0.3, 0.8, 0.0, 0.0, 0.45, 0.08, 0.2, 0.25, 0.45]));
|
||||
iml.addExample([0.5, 0.5], padPreset([0.5, 0.5, 0.4, 0.5, 0.3, 0.4, 0.05, 0.3, 0.8, 0.55, 0.55, 0.35, 0.7, 0.0, 0.4, 0.45, 0.08, 0.45, 0.4, 0.6]));
|
||||
iml.addExample([1.0, 0.5], padPreset([0.5, 0.5, 0.4, 1.0, 0.3, 0.4, 0.05, 0.3, 0.8, 0.55, 0.75, 0.45, 0.6, 0.0, 0.8, 0.45, 0.08, 0.7, 0.55, 0.75]));
|
||||
} else if (name === 'vortex') {
|
||||
// Center: tight spiral, edges: wide flow
|
||||
iml.addExample([0.5, 0.5], [0.0, 0.8, 0.8, 0.6, 0.1, 0.15, 0.02, 1.0, 1.0, 0.3, 0.95, 0.85, 0.25, 1.0, 0.5, 0.95, 0.01, 1.0, 1.0, 1.0]);
|
||||
iml.addExample([0.0, 0.0], [0.5, 0.2, 0.3, 0.8, 0.9, 0.6, 0.08, 0.1, 0.35, 0.8, 0.25, 0.15, 0.8, 0.5, 0.2, 0.35, 0.2, 0.15, 0.2, 0.25]);
|
||||
iml.addExample([1.0, 1.0], [0.5, 0.2, 0.3, 0.2, 0.9, 0.6, 0.08, 0.1, 0.35, 0.8, 0.25, 0.15, 0.8, 0.5, 0.8, 0.35, 0.2, 0.15, 0.2, 0.25]);
|
||||
iml.addExample([0.0, 1.0], [0.3, 0.4, 0.5, 0.4, 0.5, 0.4, 0.05, 0.5, 0.65, 0.5, 0.55, 0.45, 0.45, 0.2, 0.4, 0.7, 0.1, 0.5, 0.4, 0.55]);
|
||||
iml.addExample([1.0, 0.0], [0.7, 0.4, 0.5, 0.0, 0.5, 0.4, 0.05, 0.5, 0.65, 0.5, 0.55, 0.45, 0.45, 0.2, 0.9, 0.7, 0.1, 0.5, 0.4, 0.55]);
|
||||
iml.addExample([0.5, 0.5], padPreset([0.0, 0.8, 0.8, 0.6, 0.1, 0.15, 0.02, 1.0, 1.0, 0.3, 0.95, 0.85, 0.25, 1.0, 0.5, 0.95, 0.01, 1.0, 1.0, 1.0]));
|
||||
iml.addExample([0.0, 0.0], padPreset([0.5, 0.2, 0.3, 0.8, 0.9, 0.6, 0.08, 0.1, 0.35, 0.8, 0.25, 0.15, 0.8, 0.5, 0.2, 0.35, 0.2, 0.15, 0.2, 0.25]));
|
||||
iml.addExample([1.0, 1.0], padPreset([0.5, 0.2, 0.3, 0.2, 0.9, 0.6, 0.08, 0.1, 0.35, 0.8, 0.25, 0.15, 0.8, 0.5, 0.8, 0.35, 0.2, 0.15, 0.2, 0.25]));
|
||||
iml.addExample([0.0, 1.0], padPreset([0.3, 0.4, 0.5, 0.4, 0.5, 0.4, 0.05, 0.5, 0.65, 0.5, 0.55, 0.45, 0.45, 0.2, 0.4, 0.7, 0.1, 0.5, 0.4, 0.55]));
|
||||
iml.addExample([1.0, 0.0], padPreset([0.7, 0.4, 0.5, 0.0, 0.5, 0.4, 0.05, 0.5, 0.65, 0.5, 0.55, 0.45, 0.45, 0.2, 0.9, 0.7, 0.1, 0.5, 0.4, 0.55]));
|
||||
}
|
||||
|
||||
const loss = trainModel();
|
||||
|
|
@ -485,7 +496,12 @@ function loadState() {
|
|||
const data = JSON.parse(localStorage.getItem('nisps-playground'));
|
||||
if (data && data.features && data.features.length > 0) {
|
||||
for (let i = 0; i < data.features.length; i++) {
|
||||
iml.addExample(data.features[i], data.labels[i]);
|
||||
// Pad old saves (20 outputs) to current N_OUTPUTS with 0.5 defaults
|
||||
const labels = data.labels[i];
|
||||
if (labels.length < N_OUTPUTS) {
|
||||
while (labels.length < N_OUTPUTS) labels.push(0.5);
|
||||
}
|
||||
iml.addExample(data.features[i], labels);
|
||||
}
|
||||
trainModel();
|
||||
const outputs = iml.getOutputs();
|
||||
|
|
|
|||
|
|
@ -1,38 +1,237 @@
|
|||
// Maps 20 NISPS outputs (0-1) to curated C15 synth parameters
|
||||
// Each entry: { id, name, label, defaultValue, bipolar }
|
||||
// Chosen for maximum sonic impact and exploration potential
|
||||
// Maps NISPS outputs (0-1) to curated C15 synth parameters
|
||||
// 126 params: all sonically meaningful continuous parameters
|
||||
// Excludes: hardware routing, macros, scale/tuning, key tracking, velocity,
|
||||
// envelope modulation depths, discrete switches, dangerous volume/pitch controls
|
||||
//
|
||||
// Grouped by synthesis section for readability:
|
||||
// Envelopes (20) → Oscillators (10) → Shapers (12) → Filters (25) →
|
||||
// Feedback Mixer (9) → Output Mixer (14) → Cabinet (8) →
|
||||
// Flanger (13) → Echo (7) → Reverb (6) → Unison (3) → Mono (1)
|
||||
|
||||
export const SYNTH_PARAM_MAP = [
|
||||
{ id: 60, name: 'Osc_A_PM_Self', label: 'OscA Self-PM', defaultValue: 0.00, bipolar: true },
|
||||
{ id: 64, name: 'Osc_A_PM_B', label: 'OscA PM-B', defaultValue: 0.00, bipolar: true },
|
||||
{ id: 90, name: 'Osc_B_PM_Self', label: 'OscB Self-PM', defaultValue: 0.00, bipolar: true },
|
||||
{ id: 94, name: 'Osc_B_PM_A', label: 'OscB PM-A', defaultValue: 0.00, bipolar: true },
|
||||
{ id: 71, name: 'Shp_A_Drive', label: 'ShpA Drive', defaultValue: 0.20, bipolar: false },
|
||||
{ id: 74, name: 'Shp_A_Fold', label: 'ShpA Fold', defaultValue: 0.50, bipolar: false },
|
||||
{ id: 101, name: 'Shp_B_Drive', label: 'ShpB Drive', defaultValue: 0.20, bipolar: false },
|
||||
{ id: 140, name: 'SV_Flt_Cut', label: 'SVF Cutoff', defaultValue: 0.50, bipolar: false },
|
||||
{ id: 144, name: 'SV_Flt_Res', label: 'SVF Reso', defaultValue: 0.50, bipolar: false },
|
||||
{ id: 148, name: 'SV_Flt_Spread', label: 'SVF Spread', defaultValue: 0.20, bipolar: true },
|
||||
{ id: 115, name: 'Comb_Flt_Pitch', label: 'Comb Pitch', defaultValue: 0.50, bipolar: false },
|
||||
{ id: 119, name: 'Comb_Flt_Decay', label: 'Comb Decay', defaultValue: 0.00, bipolar: true },
|
||||
{ id: 127, name: 'Comb_Flt_AP_Res', label: 'Comb AP Res', defaultValue: 0.50, bipolar: false },
|
||||
{ id: 235, name: 'Reverb_Size', label: 'Reverb Size', defaultValue: 0.33, bipolar: false },
|
||||
{ id: 238, name: 'Reverb_Color', label: 'Reverb Color', defaultValue: 0.50, bipolar: false },
|
||||
{ id: 225, name: 'Echo_Time', label: 'Echo Time', defaultValue: 0.43, bipolar: false },
|
||||
{ id: 229, name: 'Echo_Feedback', label: 'Echo FB', defaultValue: 0.50, bipolar: false },
|
||||
{ id: 219, name: 'Flanger_Feedback', label: 'Flanger FB', defaultValue: 0.00, bipolar: true },
|
||||
{ id: 169, name: 'Out_Mix_A_Lvl', label: 'Out A Level', defaultValue: 0.75, bipolar: true },
|
||||
{ id: 172, name: 'Out_Mix_B_Lvl', label: 'Out B Level', defaultValue: 0.00, bipolar: true },
|
||||
// --- Envelope A (7) ---
|
||||
{ id: 0, name: 'Env_A_Att', label: 'EnvA Att', defaultValue: 0, bipolar: false },
|
||||
{ id: 2, name: 'Env_A_Dec_1', label: 'EnvA Dec1', defaultValue: 0.59, bipolar: false },
|
||||
{ id: 4, name: 'Env_A_BP', label: 'EnvA BP', defaultValue: 0.5, bipolar: false },
|
||||
{ id: 6, name: 'Env_A_Dec_2', label: 'EnvA Dec2', defaultValue: 0.79, bipolar: false },
|
||||
{ id: 8, name: 'Env_A_Sus', label: 'EnvA Sus', defaultValue: 0, bipolar: false },
|
||||
{ id: 10, name: 'Env_A_Rel', label: 'EnvA Rel', defaultValue: 0.53, bipolar: false },
|
||||
{ id: 12, name: 'Env_A_Gain', label: 'EnvA Gain', defaultValue: 0, bipolar: true },
|
||||
|
||||
// --- Envelope B (7) ---
|
||||
{ id: 19, name: 'Env_B_Att', label: 'EnvB Att', defaultValue: 0, bipolar: false },
|
||||
{ id: 21, name: 'Env_B_Dec_1', label: 'EnvB Dec1', defaultValue: 0.59, bipolar: false },
|
||||
{ id: 23, name: 'Env_B_BP', label: 'EnvB BP', defaultValue: 0.5, bipolar: false },
|
||||
{ id: 25, name: 'Env_B_Dec_2', label: 'EnvB Dec2', defaultValue: 0.79, bipolar: false },
|
||||
{ id: 27, name: 'Env_B_Sus', label: 'EnvB Sus', defaultValue: 0, bipolar: false },
|
||||
{ id: 29, name: 'Env_B_Rel', label: 'EnvB Rel', defaultValue: 0.53, bipolar: false },
|
||||
{ id: 31, name: 'Env_B_Gain', label: 'EnvB Gain', defaultValue: 0, bipolar: true },
|
||||
|
||||
// --- Envelope C (6) ---
|
||||
{ id: 38, name: 'Env_C_Att', label: 'EnvC Att', defaultValue: 0, bipolar: false },
|
||||
{ id: 40, name: 'Env_C_Dec_1', label: 'EnvC Dec1', defaultValue: 0.59, bipolar: false },
|
||||
{ id: 42, name: 'Env_C_BP', label: 'EnvC BP', defaultValue: 0.5, bipolar: true },
|
||||
{ id: 44, name: 'Env_C_Dec_2', label: 'EnvC Dec2', defaultValue: 0.79, bipolar: false },
|
||||
{ id: 46, name: 'Env_C_Rel', label: 'EnvC Rel', defaultValue: 0.53, bipolar: false },
|
||||
{ id: 297, name: 'Env_C_Sus', label: 'EnvC Sus', defaultValue: 0, bipolar: true },
|
||||
|
||||
// --- Oscillator A (5) ---
|
||||
{ id: 57, name: 'Osc_A_Fluct', label: 'OscA Fluct', defaultValue: 0, bipolar: false },
|
||||
{ id: 60, name: 'Osc_A_PM_Self', label: 'OscA PM-Self', defaultValue: 0, bipolar: true },
|
||||
{ id: 64, name: 'Osc_A_PM_B', label: 'OscA PM-B', defaultValue: 0, bipolar: true },
|
||||
{ id: 68, name: 'Osc_A_PM_FB', label: 'OscA PM-FB', defaultValue: 0, bipolar: true },
|
||||
{ id: 301, name: 'Osc_A_Phase', label: 'OscA Phase', defaultValue: 0, bipolar: true },
|
||||
|
||||
// --- Oscillator B (5) ---
|
||||
{ id: 87, name: 'Osc_B_Fluct', label: 'OscB Fluct', defaultValue: 0, bipolar: false },
|
||||
{ id: 90, name: 'Osc_B_PM_Self', label: 'OscB PM-Self', defaultValue: 0, bipolar: true },
|
||||
{ id: 94, name: 'Osc_B_PM_A', label: 'OscB PM-A', defaultValue: 0, bipolar: true },
|
||||
{ id: 98, name: 'Osc_B_PM_FB', label: 'OscB PM-FB', defaultValue: 0, bipolar: true },
|
||||
{ id: 302, name: 'Osc_B_Phase', label: 'OscB Phase', defaultValue: 0, bipolar: true },
|
||||
|
||||
// --- Shaper A (6) ---
|
||||
{ id: 71, name: 'Shp_A_Drive', label: 'ShpA Drive', defaultValue: 0.2, bipolar: false },
|
||||
{ id: 74, name: 'Shp_A_Fold', label: 'ShpA Fold', defaultValue: 0.5, bipolar: false },
|
||||
{ id: 75, name: 'Shp_A_Asym', label: 'ShpA Asym', defaultValue: 0, bipolar: false },
|
||||
{ id: 76, name: 'Shp_A_Mix', label: 'ShpA Mix', defaultValue: 0, bipolar: true },
|
||||
{ id: 78, name: 'Shp_A_FB_Mix', label: 'ShpA FB Mix', defaultValue: 0, bipolar: false },
|
||||
{ id: 81, name: 'Shp_A_Ring_Mod', label: 'ShpA Ring', defaultValue: 0, bipolar: false },
|
||||
|
||||
// --- Shaper B (6) ---
|
||||
{ id: 101, name: 'Shp_B_Drive', label: 'ShpB Drive', defaultValue: 0.2, bipolar: false },
|
||||
{ id: 104, name: 'Shp_B_Fold', label: 'ShpB Fold', defaultValue: 0.5, bipolar: false },
|
||||
{ id: 105, name: 'Shp_B_Asym', label: 'ShpB Asym', defaultValue: 0, bipolar: false },
|
||||
{ id: 106, name: 'Shp_B_Mix', label: 'ShpB Mix', defaultValue: 0, bipolar: true },
|
||||
{ id: 108, name: 'Shp_B_FB_Mix', label: 'ShpB FB Mix', defaultValue: 0, bipolar: false },
|
||||
{ id: 111, name: 'Shp_B_Ring_Mod', label: 'ShpB Ring', defaultValue: 0, bipolar: false },
|
||||
|
||||
// --- Comb Filter (9) ---
|
||||
{ id: 113, name: 'Comb_Flt_In_A_B', label: 'Comb In A/B', defaultValue: 0, bipolar: false },
|
||||
{ id: 115, name: 'Comb_Flt_Pitch', label: 'Comb Pitch', defaultValue: 0.5, bipolar: false },
|
||||
{ id: 119, name: 'Comb_Flt_Decay', label: 'Comb Decay', defaultValue: 0, bipolar: true },
|
||||
{ id: 123, name: 'Comb_Flt_AP_Tune', label: 'Comb AP Tune', defaultValue: 1, bipolar: false },
|
||||
{ id: 127, name: 'Comb_Flt_AP_Res', label: 'Comb AP Res', defaultValue: 0.5, bipolar: false },
|
||||
{ id: 129, name: 'Comb_Flt_LP_Tune', label: 'Comb LP Tune', defaultValue: 1, bipolar: false },
|
||||
{ id: 133, name: 'Comb_Flt_PM', label: 'Comb PM', defaultValue: 0, bipolar: true },
|
||||
{ id: 135, name: 'Comb_Flt_PM_A_B', label: 'Comb PM A/B', defaultValue: 0, bipolar: false },
|
||||
|
||||
// --- State Variable Filter (9) ---
|
||||
{ id: 136, name: 'SV_Flt_In_A_B', label: 'SVF In A/B', defaultValue: 0, bipolar: false },
|
||||
{ id: 138, name: 'SV_Flt_Comb_Mix', label: 'SVF CombMix', defaultValue: 0, bipolar: true },
|
||||
{ id: 140, name: 'SV_Flt_Cut', label: 'SVF Cutoff', defaultValue: 0.5, bipolar: false },
|
||||
{ id: 144, name: 'SV_Flt_Res', label: 'SVF Reso', defaultValue: 0.5, bipolar: false },
|
||||
{ id: 148, name: 'SV_Flt_Spread', label: 'SVF Spread', defaultValue: 0.2, bipolar: true },
|
||||
{ id: 150, name: 'SV_Flt_LBH', label: 'SVF L/B/H', defaultValue: 0, bipolar: false },
|
||||
{ id: 152, name: 'SV_Flt_Par', label: 'SVF Par', defaultValue: 0, bipolar: true },
|
||||
{ id: 153, name: 'SV_Flt_FM', label: 'SVF FM', defaultValue: 0, bipolar: true },
|
||||
{ id: 155, name: 'SV_Flt_FM_A_B', label: 'SVF FM A/B', defaultValue: 0, bipolar: false },
|
||||
|
||||
// --- Gap Filter (6) ---
|
||||
{ id: 201, name: 'Gap_Flt_Center', label: 'Gap Center', defaultValue: 0.5, bipolar: false },
|
||||
{ id: 203, name: 'Gap_Flt_Stereo', label: 'Gap Stereo', defaultValue: 0, bipolar: true },
|
||||
{ id: 204, name: 'Gap_Flt_Gap', label: 'Gap Width', defaultValue: 0.125, bipolar: false },
|
||||
{ id: 206, name: 'Gap_Flt_Res', label: 'Gap Res', defaultValue: 0.5, bipolar: false },
|
||||
{ id: 207, name: 'Gap_Flt_Bal', label: 'Gap Bal', defaultValue: 0, bipolar: true },
|
||||
{ id: 209, name: 'Gap_Flt_Mix', label: 'Gap Mix', defaultValue: 0, bipolar: true },
|
||||
|
||||
// --- Feedback Mixer (9) ---
|
||||
{ id: 156, name: 'FB_Mix_Comb', label: 'FB Comb', defaultValue: 0, bipolar: true },
|
||||
{ id: 158, name: 'FB_Mix_SVF', label: 'FB SVF', defaultValue: 0, bipolar: true },
|
||||
{ id: 160, name: 'FB_Mix_FX', label: 'FB FX', defaultValue: 0, bipolar: true },
|
||||
{ id: 162, name: 'FB_Mix_Rvb', label: 'FB Reverb', defaultValue: 0.5, bipolar: false },
|
||||
{ id: 164, name: 'FB_Mix_Drive', label: 'FB Drive', defaultValue: 0.286, bipolar: false },
|
||||
{ id: 166, name: 'FB_Mix_Fold', label: 'FB Fold', defaultValue: 0.5, bipolar: false },
|
||||
{ id: 167, name: 'FB_Mix_Asym', label: 'FB Asym', defaultValue: 0, bipolar: false },
|
||||
{ id: 299, name: 'FB_Mix_Lvl', label: 'FB Level', defaultValue: 0.38, bipolar: false },
|
||||
{ id: 346, name: 'FB_Mix_Osc', label: 'FB Osc', defaultValue: 0, bipolar: true },
|
||||
|
||||
// --- Output Mixer (14) ---
|
||||
{ id: 169, name: 'Out_Mix_A_Lvl', label: 'Out A Lvl', defaultValue: 0.75, bipolar: true },
|
||||
{ id: 171, name: 'Out_Mix_A_Pan', label: 'Out A Pan', defaultValue: 0, bipolar: true },
|
||||
{ id: 172, name: 'Out_Mix_B_Lvl', label: 'Out B Lvl', defaultValue: 0, bipolar: true },
|
||||
{ id: 174, name: 'Out_Mix_B_Pan', label: 'Out B Pan', defaultValue: 0, bipolar: true },
|
||||
{ id: 175, name: 'Out_Mix_Comb_Lvl', label: 'Out Comb Lvl', defaultValue: 0, bipolar: true },
|
||||
{ id: 177, name: 'Out_Mix_Comb_Pan', label: 'Out Comb Pan', defaultValue: 0, bipolar: true },
|
||||
{ id: 178, name: 'Out_Mix_SVF_Lvl', label: 'Out SVF Lvl', defaultValue: 0, bipolar: true },
|
||||
{ id: 180, name: 'Out_Mix_SVF_Pan', label: 'Out SVF Pan', defaultValue: 0, bipolar: true },
|
||||
{ id: 181, name: 'Out_Mix_Drive', label: 'Out Drive', defaultValue: 0, bipolar: false },
|
||||
{ id: 183, name: 'Out_Mix_Fold', label: 'Out Fold', defaultValue: 0.5, bipolar: false },
|
||||
{ id: 184, name: 'Out_Mix_Asym', label: 'Out Asym', defaultValue: 0, bipolar: false },
|
||||
{ id: 185, name: 'Out_Mix_Lvl', label: 'Out Level', defaultValue: 0.38, bipolar: false },
|
||||
{ id: 187, name: 'Out_Mix_Key_Pan', label: 'Out KeyPan', defaultValue: 0, bipolar: false },
|
||||
{ id: 362, name: 'Out_Mix_To_FX', label: 'Out ToFX', defaultValue: 0, bipolar: false },
|
||||
|
||||
// --- Cabinet (8) ---
|
||||
{ id: 188, name: 'Cabinet_Drive', label: 'Cab Drive', defaultValue: 0.4, bipolar: false },
|
||||
{ id: 190, name: 'Cabinet_Fold', label: 'Cab Fold', defaultValue: 0.25, bipolar: false },
|
||||
{ id: 191, name: 'Cabinet_Asym', label: 'Cab Asym', defaultValue: 0.25, bipolar: false },
|
||||
{ id: 192, name: 'Cabinet_Tilt', label: 'Cab Tilt', defaultValue: 0.5, bipolar: true },
|
||||
{ id: 194, name: 'Cabinet_Hi_Cut', label: 'Cab HiCut', defaultValue: 0.625, bipolar: false },
|
||||
{ id: 196, name: 'Cabinet_Lo_Cut', label: 'Cab LoCut', defaultValue: 0.125, bipolar: false },
|
||||
{ id: 197, name: 'Cabinet_Cab_Lvl', label: 'Cab Level', defaultValue: 0.72, bipolar: false },
|
||||
{ id: 199, name: 'Cabinet_Mix', label: 'Cab Mix', defaultValue: 0, bipolar: false },
|
||||
|
||||
// --- Flanger (13) ---
|
||||
{ id: 211, name: 'Flanger_Time_Mod', label: 'Flng TimeMod', defaultValue: 0, bipolar: true },
|
||||
{ id: 213, name: 'Flanger_Phase', label: 'Flng Phase', defaultValue: 0.5, bipolar: false },
|
||||
{ id: 214, name: 'Flanger_Rate', label: 'Flng Rate', defaultValue: 0.317, bipolar: false },
|
||||
{ id: 216, name: 'Flanger_Time', label: 'Flng Time', defaultValue: 0.317, bipolar: false },
|
||||
{ id: 218, name: 'Flanger_Stereo', label: 'Flng Stereo', defaultValue: 0, bipolar: true },
|
||||
{ id: 219, name: 'Flanger_Feedback', label: 'Flng FB', defaultValue: 0, bipolar: true },
|
||||
{ id: 221, name: 'Flanger_Cross_FB', label: 'Flng XFB', defaultValue: 0.5, bipolar: true },
|
||||
{ id: 222, name: 'Flanger_Hi_Cut', label: 'Flng HiCut', defaultValue: 0.75, bipolar: false },
|
||||
{ id: 223, name: 'Flanger_Mix', label: 'Flng Mix', defaultValue: 0, bipolar: true },
|
||||
{ id: 307, name: 'Flanger_Envelope', label: 'Flng Env', defaultValue: 0, bipolar: false },
|
||||
{ id: 308, name: 'Flanger_AP_Mod', label: 'Flng AP Mod', defaultValue: 0, bipolar: true },
|
||||
{ id: 310, name: 'Flanger_AP_Tune', label: 'Flng AP Tune', defaultValue: 1, bipolar: false },
|
||||
{ id: 389, name: 'Flanger_Tremolo', label: 'Flng Trem', defaultValue: 0, bipolar: false },
|
||||
|
||||
// --- Echo (7) ---
|
||||
{ id: 225, name: 'Echo_Time', label: 'Echo Time', defaultValue: 0.433, bipolar: false },
|
||||
{ id: 227, name: 'Echo_Stereo', label: 'Echo Stereo', defaultValue: 0, bipolar: true },
|
||||
{ id: 229, name: 'Echo_Feedback', label: 'Echo FB', defaultValue: 0.5, bipolar: false },
|
||||
{ id: 231, name: 'Echo_Cross_FB', label: 'Echo XFB', defaultValue: 0.5, bipolar: false },
|
||||
{ id: 232, name: 'Echo_Hi_Cut', label: 'Echo HiCut', defaultValue: 0.75, bipolar: false },
|
||||
{ id: 233, name: 'Echo_Mix', label: 'Echo Mix', defaultValue: 0, bipolar: false },
|
||||
{ id: 342, name: 'Echo_Send', label: 'Echo Send', defaultValue: 1, bipolar: false },
|
||||
|
||||
// --- Reverb (6) ---
|
||||
{ id: 235, name: 'Reverb_Size', label: 'Verb Size', defaultValue: 0.33, bipolar: false },
|
||||
{ id: 237, name: 'Reverb_Pre_Dly', label: 'Verb PreDly', defaultValue: 0.33, bipolar: false },
|
||||
{ id: 238, name: 'Reverb_Color', label: 'Verb Color', defaultValue: 0.5, bipolar: false },
|
||||
{ id: 240, name: 'Reverb_Chorus', label: 'Verb Chorus', defaultValue: 0.25, bipolar: false },
|
||||
{ id: 241, name: 'Reverb_Mix', label: 'Verb Mix', defaultValue: 0, bipolar: false },
|
||||
{ id: 344, name: 'Reverb_Send', label: 'Verb Send', defaultValue: 1, bipolar: false },
|
||||
|
||||
// --- Unison (3) ---
|
||||
{ id: 250, name: 'Unison_Detune', label: 'Uni Detune', defaultValue: 0.004, bipolar: false },
|
||||
{ id: 252, name: 'Unison_Phase', label: 'Uni Phase', defaultValue: 0, bipolar: false },
|
||||
{ id: 253, name: 'Unison_Pan', label: 'Uni Pan', defaultValue: 0, bipolar: false },
|
||||
|
||||
// --- Mono (1) ---
|
||||
{ id: 367, name: 'Mono_Grp_Glide', label: 'Mono Glide', defaultValue: 0, bipolar: false },
|
||||
];
|
||||
|
||||
// Parameter display names for the param bar UI
|
||||
export const SYNTH_PARAM_NAMES = SYNTH_PARAM_MAP.map(p => p.label);
|
||||
|
||||
// Colors for synth mode param bars (warm/synth palette)
|
||||
export const SYNTH_PARAM_COLORS = [
|
||||
'#ff6b35', '#ff9a3c', '#e85d04', '#ffb703',
|
||||
'#fb5607', '#ff006e', '#8338ec', '#3a86ff',
|
||||
'#06d6a0', '#118ab2', '#073b4c', '#ef476f',
|
||||
'#ffd166', '#06d6a0', '#118ab2', '#8ecae6',
|
||||
'#219ebc', '#ffb4a2', '#e5989b', '#b5838d',
|
||||
];
|
||||
// Generate colors by group using HSL for visual distinction
|
||||
// Each synthesis section gets a hue range, params within get varying lightness
|
||||
function generateParamColors() {
|
||||
// Group hues: envelope=warm red, osc=orange, shaper=magenta, comb=cyan,
|
||||
// svf=blue, gap=teal, fb=purple, out=green, cab=brown, flanger=pink,
|
||||
// echo=sky, reverb=lavender, unison=lime, mono=gold
|
||||
const groupColors = [
|
||||
// Envelope A (7) - warm red
|
||||
...hslRange(0, 75, 55, 7),
|
||||
// Envelope B (7) - coral
|
||||
...hslRange(15, 75, 55, 7),
|
||||
// Envelope C (6) - salmon
|
||||
...hslRange(30, 70, 55, 6),
|
||||
// Oscillator A (5) - orange
|
||||
...hslRange(35, 85, 55, 5),
|
||||
// Oscillator B (5) - amber
|
||||
...hslRange(45, 85, 55, 5),
|
||||
// Shaper A (6) - magenta
|
||||
...hslRange(320, 75, 55, 6),
|
||||
// Shaper B (6) - rose
|
||||
...hslRange(340, 70, 55, 6),
|
||||
// Comb Filter (9) - cyan
|
||||
...hslRange(180, 70, 50, 9, true),
|
||||
// State Variable Filter (9) - blue
|
||||
...hslRange(210, 75, 55, 9, true),
|
||||
// Gap Filter (6) - teal
|
||||
...hslRange(165, 65, 50, 6),
|
||||
// Feedback Mixer (9) - purple
|
||||
...hslRange(270, 65, 55, 9, true),
|
||||
// Output Mixer (14) - green
|
||||
...hslRange(130, 65, 50, 14, true),
|
||||
// Cabinet (8) - brown/earth
|
||||
...hslRange(25, 55, 50, 8),
|
||||
// Flanger (13) - pink
|
||||
...hslRange(300, 60, 60, 13, true),
|
||||
// Echo (7) - sky blue
|
||||
...hslRange(195, 70, 55, 7),
|
||||
// Reverb (6) - lavender
|
||||
...hslRange(255, 55, 65, 6),
|
||||
// Unison (3) - lime
|
||||
...hslRange(90, 70, 50, 3),
|
||||
// Mono (1) - gold
|
||||
...hslRange(50, 80, 55, 1),
|
||||
];
|
||||
return groupColors;
|
||||
}
|
||||
|
||||
function hslRange(hue, sat, lightBase, count, varyHue = false) {
|
||||
const colors = [];
|
||||
for (let i = 0; i < count; i++) {
|
||||
const t = count > 1 ? i / (count - 1) : 0;
|
||||
const l = lightBase + (t - 0.5) * 16;
|
||||
const h = varyHue ? hue + (t - 0.5) * 15 : hue;
|
||||
const s = sat;
|
||||
colors.push(`hsl(${Math.round(h)}, ${Math.round(s)}%, ${Math.round(l)}%)`);
|
||||
}
|
||||
return colors;
|
||||
}
|
||||
|
||||
export const SYNTH_PARAM_COLORS = generateParamColors();
|
||||
|
|
|
|||
|
|
@ -121,4 +121,13 @@ export class ParamDisplay {
|
|||
this.bars[i].fill.style.background = this.paramColors[i] || '#888';
|
||||
}
|
||||
}
|
||||
|
||||
rebuild(numParams, names, colors) {
|
||||
this.numParams = numParams;
|
||||
this.values = new Array(numParams).fill(0.5);
|
||||
this.paramNames = names || DEFAULT_PARAM_NAMES;
|
||||
this.paramColors = colors || DEFAULT_PARAM_COLORS;
|
||||
this.activeBar = -1;
|
||||
this.build();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue