diff --git a/src/renderer/config-blocks/ElementName.svelte b/src/renderer/config-blocks/ElementName.svelte index b82533468..cfbf67953 100644 --- a/src/renderer/config-blocks/ElementName.svelte +++ b/src/renderer/config-blocks/ElementName.svelte @@ -71,7 +71,9 @@ function handleActionChange(data: ActionData) { const matches = data.script.match(information.valueRegex); - scriptValue = matches[1]; + if (matches && matches[1] !== undefined) { + scriptValue = matches[1]; + } } $: { diff --git a/src/renderer/config-blocks/MidiNRPN.svelte b/src/renderer/config-blocks/MidiNRPN.svelte index 7efd158d9..b29971c24 100644 --- a/src/renderer/config-blocks/MidiNRPN.svelte +++ b/src/renderer/config-blocks/MidiNRPN.svelte @@ -58,7 +58,7 @@ export let action: GridAction; const dispatch = createEventDispatcher(); - let event = action.parent as GridEvent; + let event: GridEvent; const validators = [ { @@ -93,49 +93,101 @@ }, ]; - let channel: string; - let msb: string; - let lsb: string; - let nrpnCC: string; - let value: string; - let hiRes: boolean; + let channel: string = ""; + let msb: string = ""; + let lsb: string = ""; + let nrpnCC: string = ""; + let value: string = ""; + let hiRes: boolean = false; + let lastParsedScript: string = ""; + let isInitialized: boolean = false; + + // Keep the parent event reference in sync with the current action + $: event = action.parent as GridEvent; + + $: if (action.short === "gmnp") { + if (!$action.invalid && $action.script !== lastParsedScript) { + handleActionChange($action); + } + } else { + // Reset state when this component instance is used for a non-MidiNRPN action + if (lastParsedScript !== "") { + channel = ""; + msb = ""; + lsb = ""; + nrpnCC = ""; + value = ""; + hiRes = false; + lastParsedScript = ""; + isInitialized = false; + } + } - $: if (!$action.invalid) { - handleActionChange($action); + function resetLocalState() { + channel = ""; + msb = ""; + lsb = ""; + nrpnCC = ""; + value = ""; + hiRes = false; } function handleActionChange(data: ActionData) { - // Extract all contents - const matches = []; - const regex = /gms\((.*?[^)])\)(?=\s|$)/g; - - let match; - while ((match = regex.exec(data.script)) !== null) { - matches.push(`gms(${match[1].trim()})`); // trim to remove any extra spaces + if (!data?.script) { + resetLocalState(); + lastParsedScript = ""; + isInitialized = false; + return; } - let midiLSB = []; - let midiMSB = []; + try { + // Extract all gms(...) calls (allowing no spaces between them) + const matches: string[] = []; + const regex = /gms\((.*?)\)/g; - for (let i = 0; i < matches.length; ++i) { - let part = Script.toSegments({ short: "gms", script: matches[i] }); - if (i % 2 === 0) { - midiMSB.push(part[3]); - } else { - midiLSB.push(part[3]); + let match; + while ((match = regex.exec(data.script)) !== null) { + matches.push(`gms(${match[1].trim()})`); // trim to remove any extra spaces } - } - value = midiMSB[1].split("//")[0]; - if (value.startsWith("(") && value.endsWith(")")) { - value = value.slice(1, -1); - } + const midiLSB: string[] = []; + const midiMSB: string[] = []; - channel = Script.toSegments({ short: "gms", script: matches[0] })[0]; - msb = midiMSB[0]; - lsb = midiLSB[0]; - nrpnCC = calculateNRPNCC(midiMSB[0], midiLSB[0]); - hiRes = midiLSB.length > 1 ? true : false; + for (let i = 0; i < matches.length; ++i) { + const part = Script.toSegments({ short: "gms", script: matches[i] }); + if (i % 2 === 0) { + midiMSB.push(part[3]); + } else { + midiLSB.push(part[3]); + } + } + + // Original parsing logic: value comes from the second MSB entry + let parsedValue = midiMSB[1].split("//")[0]; + if (parsedValue.startsWith("(") && parsedValue.endsWith(")")) { + parsedValue = parsedValue.slice(1, -1); + } + + const channelSegments = Script.toSegments({ + short: "gms", + script: matches[0], + }); + + channel = channelSegments[0]; + msb = midiMSB[0]; + lsb = midiLSB[0]; + value = parsedValue; + nrpnCC = calculateNRPNCC(midiMSB[0], midiLSB[0]); + hiRes = midiLSB.length > 1 ? true : false; + + lastParsedScript = data.script; + isInitialized = true; + } catch (err) { + // If parsing fails for any reason, fall back to a safe empty state + console.error("[MidiNRPN] Failed to parse script", err, data?.script); + resetLocalState(); + isInitialized = false; + } } function sendData() { @@ -154,9 +206,7 @@ }); } - $: handleHighResValueChange(hiRes); - - function handleHighResValueChange(hiRes: boolean) { + function handleHighResChange() { sendData(); dispatch("sync"); } @@ -196,7 +246,7 @@ suggestions[3] = [...localDefinitions]; } - $: if ($event) { + $: if (action.short === "gmnp" && $event) { renderSuggestions(); } @@ -355,7 +405,11 @@ postProcessor={GridScript.shortify} preProcessor={GridScript.humanize} /> - +
diff --git a/src/renderer/config-blocks/headers/MidiFourteenBitFace.svelte b/src/renderer/config-blocks/headers/MidiFourteenBitFace.svelte index 08ae7d8e4..0fd41eea0 100644 --- a/src/renderer/config-blocks/headers/MidiFourteenBitFace.svelte +++ b/src/renderer/config-blocks/headers/MidiFourteenBitFace.svelte @@ -18,8 +18,23 @@ } function handleActionChange(data: ActionData) { + if (!data?.script) { + scriptSegments = ["", "", ""]; + midiLSB = ""; + midiMSB = ""; + return; + } + const arr = data.script.split(" gms"); + // Expect at least two gms segments for a valid 14-bit style script + if (arr.length < 2) { + scriptSegments = ["", "", ""]; + midiLSB = ""; + midiMSB = ""; + return; + } + let lsb = whatsInParenthesis.exec(arr[0]); if (lsb !== null) { @@ -36,8 +51,20 @@ } } + // If we failed to extract LSB parameters, bail out safely + if (!midiLSB) { + scriptSegments = ["", "", ""]; + return; + } + let param_array = midiLSB.split(",").map((c) => c.trim()); + // Require at least 4 parameters: channel, status, base, value + if (param_array.length < 4 || !param_array[3]) { + scriptSegments = ["", "", ""]; + return; + } + let value = param_array[3].split("//").slice(0, -1).join("//"); let param_object = { diff --git a/src/renderer/main/panels/configuration/ActionList.svelte b/src/renderer/main/panels/configuration/ActionList.svelte index 5ebe639aa..ababe691a 100644 --- a/src/renderer/main/panels/configuration/ActionList.svelte +++ b/src/renderer/main/panels/configuration/ActionList.svelte @@ -170,7 +170,7 @@ in:fade|global={{ delay: 0 }} >
- {#key $latestComponentVersionKeys.get(action.short)} + {#key `${$latestComponentVersionKeys.get(action.short)}-${action.short}`}