memlnaut-nisps/playground/js/midi/midi-cc-map.js
w1n5t0n 6f1107bae2 feat(playground): engine-aware heatmap + MIDI CC storage on engine switch (meml-qaa)
- Add rebuildHeatmap(paramMeta): resets rawParamValues/_lastSentParams and rebuilds
  #heatmap-cells from engine paramMeta; colors from SYNTH_PARAM_COLORS for C15,
  _colorFromGroup() hash for other engines
- Replace static SYNTH_PARAM_NAMES/COLORS lookups in buildHeatmap, setHeatmapValue,
  and showParamPopup with activeEngine.paramMeta[index] lookups
- Scope MIDI CC localStorage key per engine via midiCCStorageKey()
- Add reloadMidiCCMap() helper; called in setActiveEngine() after engine switch
- loadCCMap/saveCCMap in midi-cc-map.js accept optional key parameter
2026-04-03 17:55:39 +01:00

108 lines
3.5 KiB
JavaScript

// MIDI CC Map — user-defined CC parameter definitions
// Each param maps one MLP output to a MIDI CC message.
const STORAGE_KEY = 'nisps-midi-cc-map';
// Scoped key used when an engine ID is provided (avoids collision between engines).
// Falls back to STORAGE_KEY for legacy/unknown callers.
// Default starter set — common CC numbers
const DEFAULT_CC_MAP = [
{ name: 'Cutoff', cc: 74, channel: 1, min: 0, max: 1, curve: 0.5, muted: false, fixedValue: 0.5 },
{ name: 'Resonance', cc: 71, channel: 1, min: 0, max: 1, curve: 0.5, muted: false, fixedValue: 0.5 },
{ name: 'Attack', cc: 73, channel: 1, min: 0, max: 1, curve: 0.5, muted: false, fixedValue: 0.5 },
{ name: 'Release', cc: 72, channel: 1, min: 0, max: 1, curve: 0.5, muted: false, fixedValue: 0.5 },
{ name: 'Mod Wheel', cc: 1, channel: 1, min: 0, max: 1, curve: 0.5, muted: false, fixedValue: 0.5 },
{ name: 'Volume', cc: 7, channel: 1, min: 0, max: 1, curve: 0.5, muted: false, fixedValue: 0.5 },
{ name: 'Pan', cc: 10, channel: 1, min: 0, max: 1, curve: 0.5, muted: false, fixedValue: 0.5 },
{ name: 'Expression',cc: 11, channel: 1, min: 0, max: 1, curve: 0.5, muted: false, fixedValue: 0.5 },
];
// Well-known CC names for auto-labeling
const CC_NAMES = {
1: 'Mod Wheel', 2: 'Breath', 5: 'Portamento Time', 7: 'Volume', 10: 'Pan',
11: 'Expression', 64: 'Sustain', 65: 'Portamento', 66: 'Sostenuto',
67: 'Soft Pedal', 70: 'Sound Variation', 71: 'Resonance', 72: 'Release',
73: 'Attack', 74: 'Cutoff', 75: 'Decay', 76: 'Vib Rate', 77: 'Vib Depth',
78: 'Vib Delay', 91: 'Reverb', 92: 'Tremolo', 93: 'Chorus', 94: 'Detune',
95: 'Phaser',
};
/**
* Create a fresh CC param with defaults.
* @param {number} [cc=74] — CC number
* @param {number} [channel=1] — MIDI channel 1-16
* @returns {object} CC param definition
*/
export function createCCParam(cc = 74, channel = 1) {
return {
name: CC_NAMES[cc] || `CC ${cc}`,
cc,
channel,
min: 0,
max: 1,
curve: 0.5,
muted: false,
fixedValue: 0.5,
};
}
/**
* Load CC map from localStorage, or return default.
* @param {string} [key] — optional storage key (default: STORAGE_KEY)
* @returns {Array} CC param definitions
*/
export function loadCCMap(key = STORAGE_KEY) {
try {
const raw = localStorage.getItem(key);
if (raw) {
const saved = JSON.parse(raw);
if (Array.isArray(saved) && saved.length > 0) return saved;
}
} catch (e) {
console.warn('[MIDI CC] Failed to load map:', e);
}
return DEFAULT_CC_MAP.map(p => ({ ...p }));
}
/**
* Save CC map to localStorage.
* @param {Array} ccMap
* @param {string} [key] — optional storage key (default: STORAGE_KEY)
*/
export function saveCCMap(ccMap, key = STORAGE_KEY) {
try {
localStorage.setItem(key, JSON.stringify(ccMap));
} catch (e) {
console.warn('[MIDI CC] Failed to save map:', e);
}
}
/**
* Export CC map as JSON string (for sharing).
* @param {Array} ccMap
* @returns {string}
*/
export function exportCCMap(ccMap) {
return JSON.stringify(ccMap, null, 2);
}
/**
* Import CC map from JSON string.
* @param {string} json
* @returns {Array|null} parsed map or null on failure
*/
export function importCCMap(json) {
try {
const parsed = JSON.parse(json);
if (!Array.isArray(parsed) || parsed.length === 0) return null;
// Validate shape
for (const p of parsed) {
if (typeof p.cc !== 'number' || typeof p.channel !== 'number') return null;
}
return parsed;
} catch (e) {
return null;
}
}
export { CC_NAMES, DEFAULT_CC_MAP };