IIRC i just tried to clic on the Background scripts/Settings button. Then the “Plugin is loading …” message appeared.
OK. I can’t see that in the log, meaning that the plugin crashed before that. The very last log entry is that it starts the OnInit function for background script 2. What does that function do?
Log:
7e24746b-cfda-4a8c-946c-4994d44949ac
It seems that something is not working as expected with the port configuration actions in background scripts.
I have four background scripts. I have added an init event with ports action configuration to this four scripts, like this:
Background Script 1: (init) {outputport:GP1} {inputport:GP2}
Background Script 2: (init) {outputport:GP9} {inputport:GP10}
Background Script 3: (init) {outputport:GP5} {inputport:GP6}
Background Script 4: (init) {outputport:#none#} {inputport:#none#}
Steps to test this issue:
- I set manually all the ports of this four background scripts to ports GP11 and GP12
- I click the “Run(init)commands“ button of Global Settings/Background Scripts of every script
- The ports changes as expected. It is working well
- I set manually again all the ports of this four background scripts to ports GP11 and GP12
- I quit the Stream Deck editor
- I open again Stream Deck editor
- The ports of the background scripts remain GP11 and GP12, they have not changed according to the port change actions of their (init) events
Step 5,6 - Do you mean “Stream Deck editor” or “Stream Deck software”? Init commands are not run when you open the editor.
Here is the code for Background script 2:
/// <reference path="C:/Users/LPA/AppData/Roaming/Elgato/StreamDeck/Plugins/se.trevligaspel.midi.sdPlugin/ScriptJint/streamdeck-midi.d.ts" />
// ------------------------
// Control Change mapping (same style as sysExList)
// ------------------------
const ccList = [
// Decrease channel (-1) as compared to midiscript
[1, 27, "g_dev_on", 0], // Device On/Off
[2, 0, "g_t_img_idx", 1], // Selected Track : Index for selected track image, based on Mute, Solo or Arm status
[2, 1, "g_sb1_img_idx", 1], // Index for session box 1 track image
[2, 2, "g_sb2_img_idx", 1], // Index for session box 2 track image
[2, 3, "g_sb3_img_idx", 1], // Index for session box 3 track image
[2, 4, "g_sb4_img_idx", 1], // Index for session box 4 track image
[3, 0, "g_tb", 9], // Twister Bank
[3, 1, "g_sr", 9], // Session Record
[3, 2, "g_sa", 9], // Session Automation Record
[15, 0, "g_trackNum", 0], // Track Number
[15, 24, "g_sceneNum", 0] // Scene Number
];
// Fast lookup for CC
const ccMap = Object.fromEntries(
ccList.map(([ch, ctrl, name]) => [`${ch}_${ctrl}`, name])
);
// ------------------------
// Initialization
// -------------------------
function OnInit() {
ccList.forEach(([ch, ctrl, name, init]) => {
gvar.set(name, init ?? 0);
});
}
// ------------------------
// CC handler
// ------------------------
function OnControlChangeReceived(channel, control, value) {
//console.warn(`Received CC ${channel},${control},${value}`);
const key = `${channel}_${control}`;
const varName = ccMap[key];
if (!varName) {
//console.warn(`No variable mapped for CC ${channel},${control}`);
return;
}
//console.warn("BCC seting variable:" + varName + " from " + gvar.get(varName) + " to " + value);
gvar.set(varName, value);
}
I’m afraid that since OnInit() intializes some variables, it triggers things elsewhere.
If you haven’t reverted to the previous version yet, could you please change “level2” to “level3” in the EnableLogging.txt file and restart the Stream Deck software. Then we will have more details about the variable handling.
When I say “Stream Deck Editor” I mean the app “Elgato Stream Deck“. This:
I use the name “Stream Deck Editor” to differentiate it from “Stream Deck Device”.
Regarding the steps 5 and 6 posted before: you will get the same behaviour if you change steps 5 and 6 to this:
5. I unplug the usb cable from Stream Deck device
6. I plug the usb cable again to Stream Deck device
By the way, when the (init) events of the background scripts are executed?
I use the name “Stream Deck Editor” to differentiate it from “Stream Deck Device”.
For me, “Stream Deck Device” is of no interest. When you connect/disconnect a device, just about nothing happens; all buttons and dials remain loaded in the Stream Deck software, and you can still edit everything in the editor.
The important difference is “Stream Deck Editor” vs “Stream Deck Software”. If you open/close the editor (i.e., the window), nothing happens besides the window opening and closing. When you restart the Stream Deck software, “everything” happens.
By the way, when the (init) events of the background scripts are executed?
Init events are executed once, when the script is activated. This is:
- When the Stream Deck software starts, and the plugin is started (i.e., when the plugin is started, not when a button is loaded). Unless you manually perform one of the actions below, this is the only time they are executed.
- When you load a new script as a background script.
- When you check the checkbox to activate a background script.
- When you press the Run Init button.
could you please change “level2” to “level3” in the EnableLogging.txt file and restart the Stream Deck
Done with the new version.
Here is the log (Beginning removed due to post size limitation) :
2026-05-05 14:50:07.7363 12,40ms DEBUG 5 GenericMidi Constructor start [8f393df5fd0c4efc9a672c7c32bc7991 Row:1, Column:0, Device:Stream Deck +]
2026-05-05 14:50:07.7391 2,78ms DEBUG 5 Throttle ThrottleMode [ThrottleMode set to Unlimited]
2026-05-05 14:50:07.7391 0,06ms DEBUG 5 GlobalSettings Initialize [start]
2026-05-05 14:50:07.7392 0,10ms DEBUG 5 GlobalSettings FolderPath [PluginPath:'C:\Users\LPA\AppData\Roaming\Elgato\StreamDeck\Plugins\se.trevligaspel.midi.sdPlugin']
2026-05-05 14:50:07.7413 2,10ms DEBUG 5 GlobalSettings FolderPath [DocumentsPath:'C:\Users\LPA\Documents']
2026-05-05 14:50:07.7415 0,16ms DEBUG 5 GlobalSettings FolderPath [TrevligaSpelPath:'C:\Users\LPA\Documents\Trevliga Spel']
2026-05-05 14:50:07.7417 0,19ms DEBUG 5 GlobalSettings FolderPath [MusicPath:'C:\Users\LPA\Music']
2026-05-05 14:50:07.7420 0,38ms DEBUG 5 Test TestReplacePaths [Testing file path replacements]
2026-05-05 14:50:07.7483 6,21ms DEBUG 5 Test TestReplacePaths ['C\:Users\SomeUser\Documents\Somefile.xml' => 'C:\Users\LPA\Documents\Somefile.xml']
2026-05-05 14:50:07.7488 0,50ms DEBUG 5 Test TestReplacePaths ['C\:Users\SomeUser\Documents\Trevliga Spel\Somefile.xml' => 'C:\Users\LPA\Documents\Trevliga Spel\Somefile.xml']
2026-05-05 14:50:07.7489 0,09ms DEBUG 5 Test TestReplacePaths ['C:\NotTranslatedPath\Somefile.xml' unchanged]
2026-05-05 14:50:07.7491 0,22ms DEBUG 5 Test TestReplacePaths ['~/Documents/Somefile.xml' => 'C:\Users\LPA\Documents\Somefile.xml']
2026-05-05 14:50:07.7491 0,07ms DEBUG 5 Test TestReplacePaths ['~/Documents/Trevliga Spel/Somefile.xml' => 'C:\Users\LPA\Documents\Trevliga Spel\Somefile.xml']
2026-05-05 14:50:07.7492 0,06ms DEBUG 5 Test TestReplacePaths ['/Users/SomeUser/Documents/Somefile.xml' => 'C:\Users\LPA\Documents\Somefile.xml']
2026-05-05 14:50:07.7493 0,05ms DEBUG 5 Test TestReplacePaths ['/Users/SomeUser/Documents/Trevliga Spel/Somefile.xml' => 'C:\Users\LPA\Documents\Trevliga Spel\Somefile.xml']
2026-05-05 14:50:07.7493 0,09ms DEBUG 5 Test TestReplacePaths ['/NotTranslatedPath/Somefile.xml' => '\NotTranslatedPath\Somefile.xml']
2026-05-05 14:50:07.7496 0,25ms DEBUG 5 Test TestReplacePaths ['%documents%\Somefile.xml' => 'C:\Users\LPA\Documents\Somefile.xml']
2026-05-05 14:50:07.7497 0,10ms DEBUG 5 Test TestReplacePaths ['%documents%Somefile.xml' => 'C:\Users\LPA\Documents\Somefile.xml']
2026-05-05 14:50:07.7498 0,06ms DEBUG 5 Test TestReplacePaths ['%trevligaspel%\Somefile.xml' => 'C:\Users\LPA\Documents\Trevliga Spel\Somefile.xml']
2026-05-05 14:50:07.7498 0,02ms DEBUG 5 Test TestReplacePaths ['%trevligaspel%Somefile.xml' => 'C:\Users\LPA\Documents\Trevliga Spel\Somefile.xml']
2026-05-05 14:50:07.7498 0,04ms DEBUG 5 Test TestReplacePaths ['%plugin%\Somefile.xml' => 'C:\Users\LPA\AppData\Roaming\Elgato\StreamDeck\Plugins\se.trevligaspel.midi.sdPlugin\Somefile.xml']
2026-05-05 14:50:07.7498 0,03ms DEBUG 5 Test TestReplacePaths ['%plugin%Somefile.xml' => 'C:\Users\LPA\AppData\Roaming\Elgato\StreamDeck\Plugins\se.trevligaspel.midi.sdPlugin\Somefile.xml']
2026-05-05 14:50:07.7499 0,03ms DEBUG 5 Test TestReplacePaths ['%appdata%\Elgato\StreamDeck\Plugins\se.trevligaspel.midi.sdPlugin\Extras\Icons\Generic.png' => 'C:\Users\LPA\AppData\Roaming\Elgato\StreamDeck\Plugins\se.trevligaspel.midi.sdPlugin\Extras\Icons\Generic.png']
2026-05-05 14:50:07.7499 0,00ms DEBUG 5 Test TestReplacePaths [Testing file path replacements finished]
2026-05-05 14:50:07.7546 4,70ms DEBUG 5 Throttle ThrottleMode [ThrottleMode set to Unlimited]
2026-05-05 14:50:07.7584 3,85ms DEBUG 5 GlobalSettings DecipherJson [Global settings item count=70]
2026-05-05 14:50:07.7612 2,75ms DEBUG 5 GlobalSettings DecipherJson [GlobalSettings newsDisplayedForVersion(newsDisplayedForVersion): '' => '4.2.0.133']
2026-05-05 14:50:07.7613 0,16ms DEBUG 5 GlobalSettings DecipherJson [GlobalSettings VersionNumberAcknowledged(VersionNumberAcknowledged): '' => '3.12.1']
2026-05-05 14:50:07.7616 0,26ms DEBUG 5 GlobalSettings DecipherJson [GlobalSettings selectedMackieLayout(selectedMackieLayout): '' => 'Generic.xml']
2026-05-05 14:50:07.7650 3,42ms DEBUG 5 TSFile Initialize ['C:\Users\LPA\Documents\Trevliga Spel\StreamDeckMidiUserSettings.xml' not found]
2026-05-05 14:50:07.7653 0,29ms DEBUG 5 UserSettings CreateDocWatcher [C:\Users\LPA\Documents]
2026-05-05 14:50:07.7654 0,05ms DEBUG 7 TSFile CreateFileWatcher [File watcher created for 'C:\Users\LPA\Documents\Trevliga Spel\StreamDeckMidiUserSettings.xml']
2026-05-05 14:50:07.7654 0,03ms DEBUG 5 UserSettings CreateDocWatcher [File watcher created for 'C:\Users\LPA\Documents']
2026-05-05 14:50:07.7659 0,48ms DEBUG 5 MCUDevCtrl AttachToMCUPorts [New device nr(1), midiIn(No MIDI Input), midiOut(No MIDI Output), isExtender(False)]
2026-05-05 14:50:07.7679 2,00ms DEBUG 5 MCUDevCtrl AttachToMCUPorts [New device nr(2), midiIn(No MIDI Input), midiOut(No MIDI Output), isExtender(True)]
2026-05-05 14:50:07.7679 0,03ms DEBUG 5 MCUDevCtrl AttachToMCUPorts [New device nr(3), midiIn(No MIDI Input), midiOut(No MIDI Output), isExtender(True)]
2026-05-05 14:50:07.7679 0,01ms DEBUG 5 MCUDevCtrl AttachToMCUPorts [New device nr(4), midiIn(No MIDI Input), midiOut(No MIDI Output), isExtender(True)]
2026-05-05 14:50:07.7679 0,00ms DEBUG 5 MCUDevCtrl AttachToMCUPorts [New device nr(5), midiIn(No MIDI Input), midiOut(No MIDI Output), isExtender(True)]
2026-05-05 14:50:07.7679 0,00ms DEBUG 5 MCUDevCtrl AttachToMCUPorts [New device nr(6), midiIn(No MIDI Input), midiOut(No MIDI Output), isExtender(True)]
2026-05-05 14:50:07.7679 0,00ms DEBUG 5 MCUDevCtrl AttachToMCUPorts [New device nr(7), midiIn(No MIDI Input), midiOut(No MIDI Output), isExtender(True)]
2026-05-05 14:50:07.7679 0,00ms DEBUG 5 MCUDevCtrl AttachToMCUPorts [New device nr(8), midiIn(No MIDI Input), midiOut(No MIDI Output), isExtender(True)]
2026-05-05 14:50:07.7686 0,73ms DEBUG 5 GlobalSettings DecipherJson [GlobalSettings selectedScriptMidiOutPort(selectedScriptMidiOutPort): 'StreamDeck2Daw' => 'GlobalPort_1']
2026-05-05 14:50:07.7689 0,25ms DEBUG 5 GlobalSettings DecipherJson [GlobalSettings selectedScriptMidiInPort(selectedScriptMidiInPort): 'Daw2StreamDeck' => 'GlobalPort_2']
2026-05-05 14:50:07.7691 0,21ms DEBUG 5 GlobalSettings DecipherJson [GlobalSettings selectedDialDisplayType(selectedDialDisplayType): '' => 'horizontal']
2026-05-05 14:50:07.7693 0,16ms DEBUG 5 GlobalSettings DecipherJson [GlobalSettings selectedDialFaderType(selectedDialFaderType): '' => 'C:\Users\LPA\AppData\Roaming\Elgato\StreamDeck\Plugins\se.trevligaspel.midi.sdPlugin\Images\FaderSets\Dials\Blue\Fader.xml']
2026-05-05 14:50:07.7694 0,10ms DEBUG 5 GlobalSettings DecipherJson [GlobalSettings selectedDialVpotType(selectedDialVpotType): '' => 'C:\Users\LPA\Documents\Trevliga Spel\Designs\VPot\Black (Custom).xml']
2026-05-05 14:50:07.7698 0,43ms DEBUG 5 GlobalSettings DecipherJson [GlobalSettings selectedDialFrame(selectedDialFrame): '' => 'AT']
2026-05-05 14:50:07.7699 0,09ms DEBUG 5 GlobalSettings DecipherJson [GlobalSettings selectedDialMCUCommandType(selectedDialMCUCommandType): '' => 'Ch.1Pot']
2026-05-05 14:50:07.7700 0,08ms DEBUG 5 GlobalSettings DecipherJson [GlobalSettings selectedDialMCUFaderType(selectedDialMCUFaderType): '' => 'C:\Users\LPA\AppData\Roaming\Elgato\StreamDeck\Plugins\se.trevligaspel.midi.sdPlugin\Images\FaderSets\Dials\Gradient\Fader.xml']
2026-05-05 14:50:07.7702 0,22ms DEBUG 5 GlobalSettings DecipherJson [GlobalSettings selectedDialMCUVpotType(selectedDialMCUVpotType): '' => 'C:\Users\LPA\AppData\Roaming\Elgato\StreamDeck\Plugins\se.trevligaspel.midi.sdPlugin\VPot\Black\Black.xml']
2026-05-05 14:50:07.7717 1,46ms DEBUG 5 GlobalSettings DecipherJson [GlobalSettings keepSingleSectionOpen(keepSingleSectionOpen): 'True' => 'False']
2026-05-05 14:50:07.7741 2,46ms DEBUG 5 GlobalSettings DecipherJson [GlobalSettings showOnlyUsedPorts(showOnlyUsedPorts): 'False' => 'True']
2026-05-05 14:50:07.7744 0,28ms DEBUG 5 GlobalSettings DecipherJson [GlobalSettings showOnlyGlobalPorts(showOnlyGlobalPorts): 'False' => 'True']
2026-05-05 14:50:07.7746 0,21ms DEBUG 5 GlobalSettings DecipherJson [GlobalSettings keepSingleSectionOpenScript(keepSingleSectionOpenScript): 'True' => 'False']
2026-05-05 14:50:07.7747 0,13ms DEBUG 5 GlobalSettings DecipherJson [GlobalSettings LogID(LogID): '' => '565338e9-0d2d-4e9b-800a-c05f1fd103ee']
2026-05-05 14:50:07.7749 0,12ms DEBUG 5 GlobalSettings DecipherJson [GlobalSettings GS_SelectedTab(GS_SelectedTab): 'tab4' => 'tab1']
2026-05-05 14:50:07.7752 0,36ms DEBUG 5 GlobalSettings DecipherJson [GlobalSettings vW_Local(vW_Local): 'True' => 'False']
2026-05-05 14:50:07.7758 0,58ms DEBUG 5 GlobalSettings DecipherJson [GlobalSettings vW_NonrefGlobal(vW_NonrefGlobal): 'False' => 'True']
2026-05-05 14:50:07.7782 2,37ms DEBUG 5 GlobalSettings DecipherJson [GlobalSettings Keywords(Keywords): '' => '']
2026-05-05 14:50:07.7798 1,68ms DEBUG 5 Throttle ThrottleMode [ThrottleMode set to Unlimited]
2026-05-05 14:50:07.7813 1,42ms DEBUG 5 MidiController EnsureMidiTransport [changing transport, Unknown => WinRT]
2026-05-05 14:50:07.7816 0,31ms DEBUG 5 MidiController Stop [Stopping ConnectionThread]
2026-05-05 14:50:07.7816 0,02ms DEBUG 5 MidiController Stop [Done stopped=True]
2026-05-05 14:50:07.7975 15,91ms DEBUG 5 MidiFactory Create [Windows transport preflight. BaseDir='C:\Users\LPA\AppData\Roaming\Elgato\StreamDeck\Plugins\se.trevligaspel.midi.sdPlugin\PC\', Is64BitProcess=True]
2026-05-05 14:50:07.7979 0,44ms DEBUG 5 MidiFactory Resolver [Default ALC resolver hooked]
2026-05-05 14:50:07.8018 3,90ms DEBUG 5 MidiFactory Process [Process not elevated]
2026-05-05 14:50:07.8037 1,89ms DEBUG 5 MidiFactory Create [Loading 'WinRT.Transport.dll' via custom ALC.]
2026-05-05 14:50:07.8040 0,28ms DEBUG 5 MidiFactory Create [Loaded transport assembly: WinRT.Transport, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]
2026-05-05 14:50:07.8064 2,37ms DEBUG 5 MidiFactory Create [Creating instance: 'WinRT.Transport.WinRTTransport'.]
2026-05-05 14:50:07.8104 4,05ms DEBUG 5 MidiFactory Create [Probe: GetInputPorts()]
2026-05-05 14:50:07.9174 107,01ms DEBUG 5 MidiFactory Create [Probe OK]
2026-05-05 14:50:07.9178 0,37ms DEBUG 5 MidiFactory EnsureMidiTransport [requested=WinRT, actual=WinRT]
2026-05-05 14:50:08.0446 126,84ms DEBUG 5 MidiController EnsureMidiTransport [transportInstance=WinRT.Transport.WinRTTransport]
2026-05-05 14:50:08.0449 0,29ms DEBUG 5 MidiController EnsureMidiTransport [inputPorts='BMT 1','BMT 2','BMT 3','BMT 4','BMT 5','BMT 6','RME ARC','UCX Midi Port 1','UCX Midi Port 2']
2026-05-05 14:50:08.0450 0,07ms DEBUG 5 MidiController EnsureMidiTransport [outputPorts='BMT 1','BMT 2','BMT 3','BMT 4','BMT 5','BMT 6','RME ARC','Synthé. de table de sons Microsoft GS','UCX Midi Port 1','UCX Midi Port 2']
2026-05-05 14:50:08.0460 0,99ms DEBUG 5 MidiController HookTransportEvents [Done, transport WinRT.Transport.WinRTTransport]
2026-05-05 14:50:08.0463 0,35ms DEBUG 5 MidiController Start [Starting ConnectionThread]
2026-05-05 14:50:08.0466 0,28ms DEBUG 5 GlobalSettings ReadGlobalSettingsFile [file read]
2026-05-05 14:50:08.0473 0,72ms DEBUG 5 MidiStateCtrl SetSaveState [Save state set: SaveState=(False), SavePeriod=(60), maxAge=(24), filePath=(C:\Users\LPA\Documents\Trevliga Spel\StreamDeckMidiState.json)]
2026-05-05 14:50:08.0477 0,40ms DEBUG 16 MidiController HandleConnection [started]
2026-05-05 14:50:08.0487 0,99ms DEBUG 7 SDConnection SendAsync [Sending: {"event":"getGlobalSettings","context":"2f82f92cd71be55c0f9becd7c5a4937b"}]
2026-05-05 14:50:08.0494 0,71ms DEBUG 5 GlobalSettings Initialize [
(InOut:GlobalPort_2/GlobalPort_1/0)
(NOInOut:Daw2StreamDeck/StreamDeck2Daw/0/C4)
(PCInOut:Daw2StreamDeck/StreamDeck2Daw/0)
(MSCInOut:StreamDeck2Daw/0)
(SXInOut:StreamDeck2Daw)
(SCInOut:GlobalPort_2/GlobalPort_1)
(MCUInOut:No MIDI Input/No MIDI Output/1/Generic.xml)
(MCUs:(1:No MIDI Input/No MIDI Output/False/True),(2:No MIDI Input/No MIDI Output/True/True),(3:No MIDI Input/No MIDI Output/True/True),(4:No MIDI Input/No MIDI Output/True/True),(5:No MIDI Input/No MIDI Output/True/True),(6:No MIDI Input/No MIDI Output/True/True),(7:No MIDI Input/No MIDI Output/True/True),(8:No MIDI Input/No MIDI Output/True/True))
(Layout:Generic.xml)
(VPOTTime:700)(Art:)
(news:4.2.0.133)
(dial:horizontal/Fader.xml/Black (Custom).xml/AT/True/100
(BGScripts:(C:/Users/LPA/Documents/Trevliga Spel/JS/B_Common.js/GlobalPort_2/GlobalPort_1/True),(C:/Users/LPA/Documents/Trevliga Spel/JS/B_CC.js/GlobalPort_2/GlobalPort_1/True),(C:/Users/LPA/Documents/Trevliga Spel/JS/B_Sysex.js/GlobalPort_2/GlobalPort_1/True),(/No MIDI Input/No MIDI Output/False),(/No MIDI Input/No MIDI Output/False),(/No MIDI Input/No MIDI Output/False),(/No MIDI Input/No MIDI Output/False),(/No MIDI Input/No MIDI Output/False))
(InternalPorts:2)
(keepSSOpen:False)
(GlobalPorts:(GP1: BMT 4),(GP2: BMT 5),(GP3: Not used),(GP4: Not used),(GP5: Not used),(GP6: Not used),(GP7: Not used),(GP8: Not used),(GP9: Not used),(GP10: Not used),(GP11: Not used),(GP12: Not used),(GP13: Not used),(GP14: Not used),(GP15: Not used),(GP16: Not used),(GP17: Not used),(GP18: Not used),(GP19: Not used),(GP20: Not used),(GP21: Not used),(GP22: Not used),(GP23: Not used),(GP24: Not used),(GP25: Not used),(GP26: Not used),(GP27: Not used),(GP28: Not used),(GP29: Not used),(GP30: Not used),(False),(True)
(DialFrameColor:)
(DialMCUCommandType:Ch.1Pot)
(DialMCUFaderType:C:\Users\LPA\AppData\Roaming\Elgato\StreamDeck\Plugins\se.trevligaspel.midi.sdPlugin\Images\FaderSets\Dials\Gradient\Fader.xml)
(DialMCUVpotType:C:\Users\LPA\AppData\Roaming\Elgato\StreamDeck\Plugins\se.trevligaspel.midi.sdPlugin\VPot\Black\Black.xml)
(showOnlyUsedPorts:True)
(keepSingleSectionOpenScript:False)
(LogID:565338e9-0d2d-4e9b-800a-c05f1fd103ee)
(VariableWindow:False/True/True/True/True/False/False)
(VariableWindow_GS:True/True/False/True/True/False/False/True/False)
(Keywords:)
(MidiDriver:WinRT)
]
2026-05-05 14:50:08.0495 0,03ms DEBUG 5 GlobalSettings Initialize [end]
2026-05-05 14:50:08.0499 0,48ms DEBUG 5 OptionsCtrl Initialize
2026-05-05 14:50:08.0509 0,98ms DEBUG 5 OptionsCtrl HandleArticulationFile ['C:\Users\LPA\Documents\Trevliga Spel\ArticulationOptions.xml' not found]
2026-05-05 14:50:08.0511 0,17ms DEBUG 5 OptionsCtrl CreateTSFolderWatcher [C:\Users\LPA\Documents\Trevliga Spel]
2026-05-05 14:50:08.0513 0,21ms DEBUG 5 OptionsCtrl CreateDocumentsFolderWatcher [C:\Users\LPA\Documents]
2026-05-05 14:50:08.0522 0,90ms DEBUG 5 dBFileCtrl CreateTSFolderWatcher [C:\Users\LPA\Documents]
2026-05-05 14:50:08.0689 16,70ms DEBUG 5 dBFileCtrl CreateDocumentsFolderWatcher [C:\Users\LPA\Documents]
2026-05-05 14:50:08.0691 0,24ms DEBUG 5 dBFileCtrl Init [Elapsed:17,0099 ms]
2026-05-05 14:50:08.0703 1,14ms DEBUG 5 BgScriptCtrl Initialize []
2026-05-05 14:50:08.0708 0,48ms DEBUG 5 BgScriptCtrl GlblChanged []
2026-05-05 14:50:08.0723 1,50ms DEBUG 5 JavaScript Instance [BackgroundScript1 midiIn=(BMT 5), midiOut=(BMT 4), loadScriptFromFile=(True), scriptPath=(C:/Users/LPA/Documents/Trevliga Spel/JS/B_Common.js), isActive=(True)]
2026-05-05 14:50:08.1653 93,03ms DEBUG 16 MidiController ListMidiPorts [Input ports: 'BMT 1','BMT 2','BMT 3','BMT 4','BMT 5','BMT 6','RME ARC','UCX Midi Port 1','UCX Midi Port 2']
2026-05-05 14:50:08.1654 0,08ms DEBUG 16 MidiController ListMidiPorts [Output ports: 'BMT 1','BMT 2','BMT 3','BMT 4','BMT 5','BMT 6','RME ARC','Synthé. de table de sons Microsoft GS','UCX Midi Port 1','UCX Midi Port 2']
2026-05-05 14:50:08.1655 0,14ms DEBUG 16 MidiController HandleConnection [OutPort(BMT 1) existence changed -> True]
2026-05-05 14:50:08.1655 0,01ms DEBUG 16 MidiController HandleConnection [OutPort(BMT 2) existence changed -> True]
2026-05-05 14:50:08.1655 0,00ms DEBUG 16 MidiController HandleConnection [OutPort(BMT 3) existence changed -> True]
2026-05-05 14:50:08.1655 0,00ms DEBUG 16 MidiController HandleConnection [OutPort(BMT 4) existence changed -> True]
2026-05-05 14:50:08.1655 0,00ms DEBUG 16 MidiController HandleConnection [OutPort(BMT 5) existence changed -> True]
2026-05-05 14:50:08.1655 0,00ms DEBUG 16 MidiController HandleConnection [OutPort(BMT 6) existence changed -> True]
2026-05-05 14:50:08.1655 0,00ms DEBUG 16 MidiController HandleConnection [OutPort(RME ARC) existence changed -> True]
2026-05-05 14:50:08.1655 0,00ms DEBUG 16 MidiController HandleConnection [OutPort(Synthé. de table de sons Microsoft GS) existence changed -> True]
2026-05-05 14:50:08.1655 0,00ms DEBUG 16 MidiController HandleConnection [OutPort(UCX Midi Port 1) existence changed -> True]
2026-05-05 14:50:08.1655 0,01ms DEBUG 16 MidiController HandleConnection [OutPort(UCX Midi Port 2) existence changed -> True]
2026-05-05 14:50:08.1655 0,00ms DEBUG 16 MidiController HandleConnection [InPort(BMT 1) existence changed -> True]
2026-05-05 14:50:08.1655 0,00ms DEBUG 16 MidiController HandleConnection [InPort(BMT 2) existence changed -> True]
2026-05-05 14:50:08.1655 0,00ms DEBUG 16 MidiController HandleConnection [InPort(BMT 3) existence changed -> True]
2026-05-05 14:50:08.1655 0,00ms DEBUG 16 MidiController HandleConnection [InPort(BMT 4) existence changed -> True]
2026-05-05 14:50:08.1655 0,00ms DEBUG 16 MidiController HandleConnection [InPort(BMT 5) existence changed -> True]
2026-05-05 14:50:08.1656 0,00ms DEBUG 16 MidiController HandleConnection [InPort(BMT 6) existence changed -> True]
2026-05-05 14:50:08.1656 0,00ms DEBUG 16 MidiController HandleConnection [InPort(RME ARC) existence changed -> True]
2026-05-05 14:50:08.1656 0,00ms DEBUG 16 MidiController HandleConnection [InPort(UCX Midi Port 1) existence changed -> True]
2026-05-05 14:50:08.1656 0,00ms DEBUG 16 MidiController HandleConnection [InPort(UCX Midi Port 2) existence changed -> True]
2026-05-05 14:50:08.1698 4,19ms DEBUG 5 TimerCtrl Constructor [TimerController started]
2026-05-05 14:50:08.1707 0,97ms DEBUG 5 JavaScript ConnectMidi [BackgroundScript1 connecting (BMT 5/BMT 4)]
2026-05-05 14:50:08.1710 0,31ms DEBUG 5 Connection AttachToMidiPorts [BackgroundScript1 Attaching to ports 'BMT 5'/'BMT 4']
2026-05-05 14:50:08.1711 0,09ms DEBUG 5 MidiController AttachToMidiInput [BackgroundScript1 attached to InPort(BMT 5)]
2026-05-05 14:50:08.1712 0,07ms DEBUG 5 MidiController AttachToMidiOutput [BackgroundScript1 attached to OutPort(BMT 4)]
2026-05-05 14:50:08.1718 0,61ms DEBUG 5 Connection AttachToMidiEvents [BackgroundScript1 Attaching to events]
2026-05-05 14:50:08.1732 1,37ms DEBUG 5 Connection Instance [BackgroundScript1 Connection created]
2026-05-05 14:50:08.1742 1,04ms DEBUG 5 JavaScript ConnectMidi [BackgroundScript1 connected BMT 5/BMT 4]
2026-05-05 14:50:08.1747 0,50ms DEBUG 5 JavaScript LoadScriptFile [BackgroundScript1 Attaching to file 'C:/Users/LPA/Documents/Trevliga Spel/JS/B_Common.js']
2026-05-05 14:50:08.1748 0,08ms DEBUG 5 TSFile Initialize ['C:/Users/LPA/Documents/Trevliga Spel/JS/B_Common.js' found]
2026-05-05 14:50:08.1749 0,07ms DEBUG 13 TSFile CreateFileWatcher [File watcher created for 'C:/Users/LPA/Documents/Trevliga Spel/JS/B_Common.js']
2026-05-05 14:50:08.2025 27,65ms DEBUG 20 VariableCtrl SetVariable [global:g_dp set to %trevligaspel%/Designs/]
2026-05-05 14:50:08.2031 0,61ms DEBUG 20 JavaScript OnVariableChanged [SKIP no-handler ctx=(BackgroundScript1) var=(g_dp)]
2026-05-05 14:50:08.2033 0,11ms DEBUG 20 VariableCtrl SetVariable [global:g_lp set to %trevligaspel%/Layouts/]
2026-05-05 14:50:08.2033 0,01ms DEBUG 20 JavaScript OnVariableChanged [SKIP no-handler ctx=(BackgroundScript1) var=(g_lp)]
2026-05-05 14:50:08.2033 0,01ms DEBUG 20 VariableCtrl SetVariable [global:g_pp set to %trevligaspel%/Images/]
2026-05-05 14:50:08.2033 0,00ms DEBUG 20 JavaScript OnVariableChanged [SKIP no-handler ctx=(BackgroundScript1) var=(g_pp)]
2026-05-05 14:50:08.2081 4,86ms DEBUG 20 VariableCtrl SetVariable [global:styles set to System.Dynamic.ExpandoObject]
2026-05-05 14:50:08.2082 0,03ms DEBUG 20 JavaScript OnVariableChanged [SKIP no-handler ctx=(BackgroundScript1) var=(styles)]
2026-05-05 14:50:08.2082 0,08ms DEBUG 20 VariableCtrl SetVariable [global:g_autofold set to 0]
2026-05-05 14:50:08.2082 0,01ms DEBUG 20 JavaScript OnVariableChanged [SKIP no-handler ctx=(BackgroundScript1) var=(g_autofold)]
2026-05-05 14:50:08.2083 0,05ms DEBUG 20 VariableCtrl SetVariable [global:g_showclip set to False]
2026-05-05 14:50:08.2083 0,01ms DEBUG 20 JavaScript OnVariableChanged [SKIP no-handler ctx=(BackgroundScript1) var=(g_showClip)]
2026-05-05 14:50:08.2208 12,48ms DEBUG 11 VersionCtrl ReadSiteVersion [Found version (3.12)]
2026-05-05 14:50:08.2209 0,16ms DEBUG 11 VersionCtrl ReadSiteVersion [Found version (3.12), message(Version 3.12 is now available on Marketplace.)]
2026-05-05 14:50:08.2607 39,74ms DEBUG 20 MidiController Send_ControlChange [BackgroundScript1 message successfully sent: ControlChangeMessage, MidiIn:BMT 5, MidiOut:BMT 4, Channel:10, Control,:0, Value:127]
2026-05-05 14:50:08.2621 1,46ms DEBUG 20 MidiStateCtrl SaveMidiState [BackgroundScript1 Saving state for ControlChangeMessage, MidiIn:BMT 5, MidiOut:BMT 4, Channel:10, Control,:0, Value:127, time=05/05/2026 14:50:08]
2026-05-05 14:50:08.2803 18,20ms DEBUG 5 JavaScript Instance [BackgroundScript2 midiIn=(BMT 5), midiOut=(BMT 4), loadScriptFromFile=(True), scriptPath=(C:/Users/LPA/Documents/Trevliga Spel/JS/B_CC.js), isActive=(True)]
2026-05-05 14:50:08.2807 0,31ms DEBUG 5 JavaScript ConnectMidi [BackgroundScript2 connecting (BMT 5/BMT 4)]
2026-05-05 14:50:08.2807 0,01ms DEBUG 5 Connection AttachToMidiPorts [BackgroundScript2 Attaching to ports 'BMT 5'/'BMT 4']
2026-05-05 14:50:08.2807 0,04ms DEBUG 5 MidiController AttachToMidiInput [BackgroundScript2 attached to InPort(BMT 5)]
2026-05-05 14:50:08.2807 0,01ms DEBUG 5 MidiController AttachToMidiOutput [BackgroundScript2 attached to OutPort(BMT 4)]
2026-05-05 14:50:08.2807 0,00ms DEBUG 5 Connection AttachToMidiEvents [BackgroundScript2 Attaching to events]
2026-05-05 14:50:08.2815 0,79ms DEBUG 5 Connection Instance [BackgroundScript2 Connection created]
2026-05-05 14:50:08.2815 0,01ms DEBUG 5 JavaScript ConnectMidi [BackgroundScript2 connected BMT 5/BMT 4]
2026-05-05 14:50:08.2815 0,00ms DEBUG 5 JavaScript LoadScriptFile [BackgroundScript2 Attaching to file 'C:/Users/LPA/Documents/Trevliga Spel/JS/B_CC.js']
2026-05-05 14:50:08.2816 0,05ms DEBUG 5 TSFile Initialize ['C:/Users/LPA/Documents/Trevliga Spel/JS/B_CC.js' found]
2026-05-05 14:50:08.2817 0,08ms DEBUG 11 TSFile CreateFileWatcher [File watcher created for 'C:/Users/LPA/Documents/Trevliga Spel/JS/B_CC.js']
2026-05-05 14:50:08.3002 18,53ms DEBUG 5 JavaScript Instance [BackgroundScript3 midiIn=(BMT 5), midiOut=(BMT 4), loadScriptFromFile=(True), scriptPath=(C:/Users/LPA/Documents/Trevliga Spel/JS/B_Sysex.js), isActive=(True)]
2026-05-05 14:50:08.3003 0,14ms DEBUG 16 MidiController HandleConnection [InPort(BMT 5) opened]
2026-05-05 14:50:08.3003 0,02ms DEBUG 5 JavaScript ConnectMidi [BackgroundScript3 connecting (BMT 5/BMT 4)]
2026-05-05 14:50:08.3004 0,01ms DEBUG 5 Connection AttachToMidiPorts [BackgroundScript3 Attaching to ports 'BMT 5'/'BMT 4']
2026-05-05 14:50:08.3004 0,01ms DEBUG 5 MidiController AttachToMidiInput [BackgroundScript3 attached to InPort(BMT 5)]
2026-05-05 14:50:08.3004 0,00ms DEBUG 5 MidiController AttachToMidiOutput [BackgroundScript3 attached to OutPort(BMT 4)]
2026-05-05 14:50:08.3004 0,00ms DEBUG 5 Connection AttachToMidiEvents [BackgroundScript3 Attaching to events]
2026-05-05 14:50:08.3004 0,01ms DEBUG 5 Connection Instance [BackgroundScript3 Connection created]
2026-05-05 14:50:08.3004 0,01ms DEBUG 5 JavaScript ConnectMidi [BackgroundScript3 connected BMT 5/BMT 4]
2026-05-05 14:50:08.3004 0,00ms DEBUG 5 JavaScript LoadScriptFile [BackgroundScript3 Attaching to file 'C:/Users/LPA/Documents/Trevliga Spel/JS/B_Sysex.js']
2026-05-05 14:50:08.3004 0,05ms DEBUG 5 TSFile Initialize ['C:/Users/LPA/Documents/Trevliga Spel/JS/B_Sysex.js' found]
2026-05-05 14:50:08.3005 0,09ms DEBUG 17 TSFile CreateFileWatcher [File watcher created for 'C:/Users/LPA/Documents/Trevliga Spel/JS/B_Sysex.js']
2026-05-05 14:50:08.3008 0,27ms DEBUG 16 Connection PortexistenceChanged [BackgroundScript1 Input port 'BMT 5' existence changed to True]
2026-05-05 14:50:08.3010 0,22ms DEBUG 16 Connection PortexistenceChanged [BackgroundScript2 Input port 'BMT 5' existence changed to True]
2026-05-05 14:50:08.3073 6,30ms DEBUG 24 VariableCtrl SetVariable [global:g_pqb0 set to 0]
2026-05-05 14:50:08.3077 0,37ms DEBUG 24 JavaScript OnVariableChanged [CHAIN ctx=(BackgroundScript1) id=(c10682c6c414417593468b201b4ee8d5) chainCount=(1)]
2026-05-05 14:50:08.3112 3,56ms DEBUG 20 JavaScript InvokeAsync [BackgroundScript1 Calling 'OnGlobalVariableChanged' with args=(g_pqb0, 0)]
2026-05-05 14:50:08.3521 40,86ms DEBUG 7 JavaScript RunInitCommands [BackgroundScript2 start]
2026-05-05 14:50:08.3522 0,10ms DEBUG 22 JavaScript InvokeAsync [BackgroundScript2 Calling 'OnInit' with args=()]
2026-05-05 14:50:08.3553 3,10ms DEBUG 22 VariableCtrl SetVariable [global:g_dev_on set to 0]
2026-05-05 14:50:08.3554 0,10ms DEBUG 22 JavaScript OnVariableChanged [CHAIN ctx=(BackgroundScript1) id=(cffa7af1caf94d1684b743c5a266382e) chainCount=(1)]
I write again the steps 5 and 6:
- I quit the Stream Deck editor: it doesn’t mean that I close a window, it means that I quit the app (or I quit the software)
- I open again Stream Deck editor: it means that I launch the Stream Deck app that was quitted in the previous step (or I launch the software)
Here is the code for Background script 2
What does background script 1 look like?
What does background script 1 look like?
Here it is :
/// <reference path="C:/Users/LPA/AppData/Roaming/Elgato/StreamDeck/Plugins/se.trevligaspel.midi.sdPlugin/ScriptJint/streamdeck-midi.d.ts" />
// -----------------------------
// Hooks (Called BEFORE updates)
// -----------------------------
const NEW_DEVICE_MS = 150;
const ND_TIMER ="t_newDevice";
const VAR_MS = 25;
const VAR_TIMER ="t_varUpdate";
const PNAME_VAR = "g_pname";
const DEV_TYPE = {1: "Instrument", 2: "Audio Effect", 4: "Midi Effect"};
gvar.g_pqb0 = 0;
//
var l_preceived = false;
// New Device : Reinit Parameters Names after a delay if no parameters received
// Note : For showchain and toggle fold, device counters are resent without updating the parameters
function onNewDevice(map) {
l_preceived = false;
timer.restart(ND_TIMER, NEW_DEVICE_MS);
if (map.g_nbp == 0) { gvar.g_pname = []; } // Reset parameters names if no parameters
// Reset array staging buffers on new device
tempArrays[PNAME_VAR] = [];
// Variations
timer.restart(VAR_TIMER, VAR_MS);
}
// Parameters & variation
function OnTimerElapsed(tname, isGlobal, time) {
if (tname == ND_TIMER) { // Kill timer, update parameters names and set quarter bank even when not all parameters are received
timer.reset(ND_TIMER);
if (!l_preceived) gvar.set(PNAME_VAR, tempArrays[PNAME_VAR].slice()); // Flush incomplete array
setQuarterBank ();
gvar.g_pupdt = 1; gvar.g_pupdt = 0; // Trigger refresh
return;
}
if (tname == VAR_TIMER) { // No variation received (timer is killed otherwise)
timer.reset(VAR_TIMER);
gvar.g_vnum0 = 0;
gvar.g_max_var = 0;
setVarText(0, 0);
gvar.g_vupdt = 1; gvar.g_vupdt = 0; // Trigger refresh
}
}
function onSetParameters(array) {
// Bloc intermediate updates until # of parameters is reached
if (array.length < gvar.g_nbp) {return false;}
else { // Last parameters received
l_preceived = true;
}
}
function setQuarterBank () {
// Set parameters bank
gvar.g_nhb = Math.floor((gvar.g_nbp + 3) / 4); // Number of half banks
gvar.g_pqb0 = gvar.g_nbp == 0 ? 0 : 1; // // Current global half bank
const chainText = (gvar.g_dev_rack == 0 && gvar.g_dev_parent == 0)
? DEV_TYPE[gvar.g_dev_type] || "Unknown Device Type"
: "Ch. " + gvar.g_chnum0 + "/" + gvar.g_max_ch;
gvar.g_chaintext = chainText;
}
function onVarReceived(map) { // Called from the hook
// Update immediately, , as variations can be received alone
gvar.g_vnum0 = map.g_vnum0;
gvar.g_max_var = map.g_max_var;
setVarText(map.g_vnum0, map.g_max_var);
timer.reset(VAR_TIMER); // Kill Timer
gvar.g_vupdt = 1; gvar.g_vupdt = 0; // Trigger refresh
// No need to process
return false;
}
function setVarText(varNum, maxVar, ) {
gvar.g_vartext = (maxVar == 0
? "No variation"
: "Var. " + varNum + " / " + maxVar);
}
function onSetSessionBoxTrackName(array) {
// Bloc intermediate updates until 4th track
if (array.length < 4) {return false;}
}
function onClipMarkersReceived (map) {
// 3 values are received, each one split across 3 bytes for accomodating large numbers with Sysex byte limit (127)
const bytes = [map.b0, map.b1, map.b2, map.b3, map.b4, map.b5, map.b6, map.b7, map.b8];
const start_time = fromMidiBytes(bytes.slice(0, 3));
const end_time = fromMidiBytes(bytes.slice(3, 6));
const length = fromMidiBytes(bytes.slice(6, 9));
//console.warn ("[bSYSEX] Processing Clip Markers: Start=" + start_time + ", end=" + end_time+ ", length=" + length);
gvar.set("g_clstart", start_time);
gvar.set("g_clend", end_time);
gvar.set("g_cllen", length);
return false; // Block processing (gvar updating)
}
function fromMidiBytes(bytes) {
return Math.round(((bytes[0] << 14) | (bytes[1] << 7) | bytes[2]) / 1000);
}
// Example Hooks
/*
function sysExHookString(value) {// value = decoded string}
function sysExHookChunked(value) {// value = final string}
function sysExHookArray(array) {// array = array of values}
function sysExHookVector(map) {// map : {var1: 1, var2: 2, var3: 3}}
*/
// ===================================================================================
// SYSEX TYPES - SUMMARY
// ===================================================================================
// Each entry consists of prefix:p, and index, i and a configuration map (dictionnary).
// Each entry indicates how to process received Sysex messages with the byte layouts:
// noIndex : F0 p [slot] [control] payload F7
// indexed : F0 p i [slot] [control] payload F7
//
// Configuration maps are made of :
// 1/ type: A given type among the following :
// - String : Raw ascii conversion
// - Chunked : A string that arrive in several parts (chunks) with a 1st control byte first
// - Array : An array of string that arrive in slots 1st and chunks with a control byte 2nd
// - Vector : One or several numerical values directly fed from the sysex byte
//
// 2/ The global variable name: varName or (for vectors) a variable array (VarNames) in which to store the received content (payload).
// For arrays, varName will be fed as an array of received values.
//
// 3/ init: The initial value of the variable or (for vectors) and array of initial values
//
// 4/ hook: The name of a function to be called before variables are updated, for example to perform extra calulation of transformation.
// Variables are passed by reference to the hook, enabling transformation before update.
// A hook can return a "false" value, in which case the update of variables will be bypassed.
//
// All entries support both noIndex [p, {configuration}] and indexed [p, i, {configuration}] entries.
// A given prefix p must be used exclusively as either noIndex or indexed, never both
// For noIndex entries, the payload starts 1 byte after the prefix (offset = 1 base).
// For indexed entries, the payload starts 2 bytes after the prefix (offset = 2 base).
// The slot (for arrays) and control byte (for chunks) add +1 each to the base offset when present.
// The chunk control byte is made of two parts : 1st part; chunk nubmer, 2nd part: total number of chunks
//
// -------------------------------------------------------------------------------------------------
// type | ascii | noIndex layout | offset | indexed layout | offset
// -------------------------------------------------------------------------------------------------
// string | yes | p, text | 1 | p, i, text | 2
// chunked | yes | p, control, text | 2 | p, i, control, text | 3
// array | yes | p, slot, control, text | 3 | p, i, slot, control, text | 4
// vector | no | p, numerical values | 1 | p, i, numerical values | 2
// -------------------------------------------------------------------------------------------------
// Notes:
// - string and vector share the same offsets (no slot or control byte)
// - chunked noIndex offset (2) differs from indexed (3) by the index byte only
// - array is the only type carrying both slot AND control bytes, giving offset 3 (noIndex) and 4 (indexed)
// - ascii conversion (decode()) is used for string, chunked and array
// - vector values are raw numeric bytes, no conversion
// - vector can have only one entry to p^rocess a single variable
// ===================================================================================
const sysExList = [
[0, 0, { type: "string", varName: "g_xxxx", init: "_xxxx_" }], // F0 00 00 (Example)
[106, 0, { type: "chunked", varName: "g_tname_sel", init: "_track_" }], // F0 6A 00
[107, { type: "array", varName: "g_sbtname", init: ["_SB Track1_", "_SB Track2_",
"_SB Track3_", "_SB Track4_"], hook: onSetSessionBoxTrackName }], // F0 6B : Session Box Track Names
[107, 1, { type: "chunked", varName: "g_tname_sb1", init: "_mtrack1" }], // F0 6B 01
[107, 2, { type: "chunked", varName: "g_tname_sb2", init: "_mtrack2" }], // F0 6B 02
[107, 3, { type: "chunked", varName: "g_tname_sb3", init: "_mtrack3" }], // F0 6B 03
[107, 4, { type: "chunked", varName: "g_tname_sb4", init: "_mtrack4" }], // F0 6B 04
[108, 0, { type: "chunked", varName: "g_sname_sel", init: "_scene_" }], // F0 6C 00
[110, 0, { type: "chunked", varName: "g_dname_sel", init: "_device_" }], // F0 6E 00
[111, 0, { type: "chunked", varName: "g_dname_nav", init: "_deviceN_" }], // F0 6F 00
[112, { type: "vector", varNames: ["b0","b1","b2","b3","b4","b5","b6","b7","b8"],
init: [0,0,0,0,0,0,0,0,0], hook: onClipMarkersReceived }], // F0 70 Clip markers
[113, 0, { type: "chunked", varName: "g_cname_sel", init: "_clip_" }], // F0 71 00
[122, { type: "vector", varNames: ["g_vnum0", "g_max_var"],init: [0, 0], // F0 7A Variation Control
hook: onVarReceived}],
[123, { type: "array", varName: "g_pname",
init: Array(16).fill("_Parameter_"), hook: onSetParameters }], // F0 7B : Parameters Names
[92, 1, { type: "vector", varNames: ["g_tra", "g_trl", "g_trs"],init: [0, 0, 0]}], // F0 5C 01 Twister ring : Enabled, Linked, Synced
[92, 2, { type: "vector", varNames: ["g_mra", "g_mrl", "g_mrs"],init: [0, 0, 0]}], // F0 5C 02 MPK ring : Enabled, Linked, Synced
[109, { type: "vector", varNames: ["g_dev_pos", "g_dev_nbr", "g_dev_on_unused", // F0 6D (vector) : Device + Chain (if rack)
"g_dev_parent", "g_dev_type", "g_dev_rack", "g_chnum0", "g_max_ch", "g_nbp", "g_rnbr"],
init: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], hook: onNewDevice }]
];
// Lookup tables
const sysEx = {
noIndex: new Map(), // p → entry
indexed: new Map(), // "p:i" → entry
};
compileSysEx(sysExList);
// Builder
function compileSysEx(list) {
for (const entry of list) {
const [p, maybeI, cfg] = entry;
// [p, cfg]
if (cfg === undefined) {
sysEx.noIndex.set(p, maybeI);
continue;
}
// [p, i, cfg]
sysEx.indexed.set(`${p}:${maybeI}`, cfg);
}
}
// ------------------------
// STATE (stateless helper)
// ------------------------
let pendingChunk = {};
const pendingArray = {};
const tempArrays = {}; // staging buffers only, never authoritative
// ------------------------
// Initialization
// -------------------------
function onInit() {
sysExList.forEach((entry) => {
const isNoIndex = entry.length === 2;
const cfg = isNoIndex ? entry[1] : entry[2];
if (!cfg) return;
// ARRAY: always prepare buffer
if (cfg.type === "array") {
if (!cfg.varName) return;
tempArrays[cfg.varName] = [];
if (cfg.init !== undefined) {
gvar.set(cfg.varName, cfg.init);
}
return;
}
// Early exit for everything else
if (cfg.init === undefined) return;
// STRING
if (cfg.type === "string") {
if (!cfg.varName) return;
gvar.set(cfg.varName, cfg.init);
return;
}
// CHUNKED
if (cfg.type === "chunked") {
if (!cfg.varName) return;
gvar.set(cfg.varName, cfg.init);
return;
}
// VECTOR
if (cfg.type === "vector") {
if (!Array.isArray(cfg.varNames)) return;
cfg.varNames.forEach((varName, idx) => {
gvar.set(varName, cfg.init[idx]);
});
return;
}
});
}
// ------------------------
// Main handler
// ------------------------
function OnSysExReceived(sysexdata) {
const data = Array.from(sysexdata);
if (data.length < 3) return;
const p = data[0];
const i = data[1];
const entry = resolveEntry(p, i); // Returns { cfg, offset}}
if (!entry) return;
//console.warn ("[bSYSEX] Resolving entry p=", p, ", i=", i, ", cfg=", JSON.stringify(entry.cfg), ", offset=", entry.offset);
/*
const data2 = sysexdata;
console.warn("[RAW]", data2);
console.warn("[LENGTH]", data2.length);
console.warn("ENTRY OFFSET USED:", entry.offset);
console.warn("EXPECTED START BYTE:", data[entry.offset]);
console.warn("FULL SLICE:", data.slice(entry.offset));
*/
switch (entry.cfg.type) {
// --------------------
// VECTOR
// --------------------
case "vector": {
const raw = data.slice(entry.offset);
const values = raw[raw.length - 1] === 0xF7 ? raw.slice(0, -1) : raw;
// Check expected variables number versus message
if (values.length !== entry.cfg.varNames.length) {
//console.warn(`[BNames.js] prefix=${p}, index=${i} expected=${entry.cfg.varNames.length} received=${values.length}`);
return;
}
setVectorVars(entry.cfg.varNames, values, entry.cfg.hook);
return;
}
case "chunked": {
const control = data[entry.offset - 1]; // noIndex: data[1], indexed: data[2]
const part = control >> 4, total = control & 0x0F;
const text = decode(data, entry.offset);
if (total <= 0 || part <= 0 || part > total) {
//console.warn(`[BNames.js] prefix=${p}, index=${i} invalid chunk control byte , part=${part} total=${total}`);
}
// Init & accumulate
const key = entry.cfg.varName;
if (!pendingChunk[key]) pendingChunk[key] = "";
if (part === 1) pendingChunk[key] = text;
else pendingChunk[key] += text;
// Publish
if (part === total) {
setChunked(key, pendingChunk[key], entry.cfg.hook);
delete pendingChunk[key];
}
return;
}
// --------------------
// ARRAY (chunked)
// --------------------
case "array": {
const slot = data[entry.offset - 2]; // indexed: slot=data[2], noIndex: slot=data[1]
const control = data[entry.offset - 1]; // indexed: control=data[3], noIndex: control=data[2]
const part = control >> 4, total = control & 0x0F;
if (total <= 0 || part <= 0 || part > total) {
console.warn(`[BNames.js] prefix=${p}, index=${i} invalid array control byte , part=${part} total=${total}`);
}
const text = decode(data, entry.offset);
if (part === 1 && total > 1) {pendingArray[slot] = text; return;}
if (part > 1 && part < total) {pendingArray[slot] = (pendingArray[slot] || "") + text; return;}
if (part === total) {
setArray(entry.cfg.varName, slot, (pendingArray[slot] || "") + text, entry.cfg.hook);
delete pendingArray[slot];
return;
}
return;
}
// --------------------
// STRING
// --------------------
case "string": {
const text = decode(data, entry.offset);
setString(entry.cfg.varName, text, entry.cfg.hook);
return;
}
}
}
// ------------------------
// Decode
// ------------------------
function decode(data, offset) {
let end = data.length;
if (data[end - 1] === 0xF7) end--;
let text = "";
for (let i = offset; i < end; i++) {
text += String.fromCharCode(data[i]);
}
return text;
}
// ------------------------
// Entry resolution
// ------------------------
function resolveEntry(p, i) {
const indexedKey = `${p}:${i}`;
if (sysEx.noIndex.has(p)) {
const cfg = sysEx.noIndex.get(p);
const offset = cfg.type === "array" ? 3 : cfg.type === "chunked" ? 2 : 1;
return { cfg, offset };
}
if (sysEx.indexed.has(indexedKey)) {
const cfg = sysEx.indexed.get(indexedKey);
let offset;
if (cfg.type === "array") offset = 4; // p, i, slot, control, text
else if (cfg.type === "chunked") offset = 3; // p, i, control, text
else offset = 2; // p, i, values
return { cfg, offset };
}
return null;
}
// ------------------------
// Setters
// ------------------------
function setString(name, value, hook) {
if (hook) {const result = hook(value); if (result === false) return;}
//console.warn("[bSYSEX] Setting string variable: " + name + ", value=" + value);
gvar.set(name, value);
}
function setChunked(name, value, hook) {
// Result is undefined by default, processing will continue
if (hook) {const result = hook(value);if (result === false) return;}
//console.warn ("[bSYSEX] Setting chunked variable: " + name + ", value=" + value);
gvar.set(name, value);
}
function setArray(name, index, value, hook) {
if (!tempArrays[name]) {tempArrays[name] = [];}
tempArrays[name].push(value);
//console.warn ("[bSYSEX] Accumulating array variable: " + name + ", index=," + tempArrays[name].length + ", value=" + value);
// hook may block intermediate updates otherwise update is performed for each slot
if (hook) {const result = hook(tempArrays[name]);if (result === false) return;}
//console.warn ("[bSYSEX] Setting array variable: " + name + ", value=" + tempArrays[name]);
gvar.set(name, tempArrays[name].slice());
tempArrays[name] = [];
}
function setVectorVars(varNames, values, hook) {
const map = {}; // Buil a map to be accessed with map.name to get the value in the hook
for (let i = 0; i < varNames.length; i++) {map[varNames[i]] = values[i];}
// Result is undefined by default, processing will continue
if (hook) {const result = hook(map);if (result === false) return;}
//console.warn ("[bSYSEX] Setting vector variable: " + varNames + ", value=" + values);
for (let i = 0; i < varNames.length; i++) {gvar.set(varNames[i], values[i]);}
}
I’m struggling to understand why the latest version has caused these issues. I can’t recall having made any changes in the areas you report, so my current theory is that it is a timing error of some sort.
I can reproduce the issue reported by @jordikt, but haven’t found the cause yet. I’m unable to reproduce the issue reported by @thx538, but I haven’t had time to test with bg script 1 yet.
I apologize … what I posted just above is the the background script #3.
The background script #1 is this :
/// <reference path="C:/Users/LPA/AppData/Roaming/Elgato/StreamDeck/Plugins/se.trevligaspel.midi.sdPlugin/ScriptJint/streamdeck-midi.d.ts" />
// Environmental variables
gvar.g_dp = "%trevligaspel%/Designs/" // Design Path
gvar.g_lp = "%trevligaspel%/Layouts/" // Layout Path
gvar.g_pp = "%trevligaspel%/Images/" // Picture Path
//Colors
const BAR_COLOR_ACTIVE = "#B8A46E"; // Light Yellow
const BAR_COLOR_IDLE = "#A2B0A2"; // Ligh Green
const TEXT_COLOR_ACTIVE = "#B49541"; // Yellow
const TEXT_COLOR_IDLE = "Gray";
const TR_GRADIENT = "0:#ff0000,0.5:yellow,1:#00ff00";
const SC_GRADIENT = "0:#ff0000,0.5:red,1:#00ff00";
gvar.styles = {
track: { active: { color: "#8d4400", barbkg: "#af855e", font: { size: 20, weight: 600 } },
idle: { color: "#808080", barbkg: "#a9abb6", font: { size: 20, weight: 200 } } },
scene: { active: { color: "#4152b4", barbkg: "#707bac", font: { size: 20, weight: 600 } },
idle: { color: "#808080", barbkg: "#a9abb6", font: { size: 20, weight: 500 } } },
device: { active: { color: "#B46E41", barbkg: "#6eb893", font: { size: 20, weight: 600 } },
idle: { color: "#888888", barbkg: "#a9abb6", font: { size: 20, weight: 500 } } },
chain: { active: { color: "#296dda", barbkg: "#97befa", font: { size: 20, weight: 600 } },
select: { color: "#68a1fd", barbkg: "#97befa", font: { size: 20, weight: 600 } },
idle: { color: "#296dda", barbkg: "#a9abb6", font: { size: 20, weight: 500 } } },
var: { active: { color: "#B49541", barbkg: "#ccaf5f", font: { size: 20, weight: 600 } },
select: { color: "#dfab1c", barbkg: "#ccaf5f", font: { size: 20, weight: 600 } },
idle: { color: "#B49541", barbkg: "#a9abb6", font: { size: 20, weight: 500 } } },
clip: { name: { color: "#41b467", font: { size: 20, weight: 600 } },
markers: { color: "#ceb778", font: { size: 20, weight: 600 } },
barActive: { barbkg: "#ddbb5c" },
barInactive: { barbkg: "#a9abb6" } },
param: { title: { color: "#B49541", font: { size: 20, weight: 600 } },
text: { color: "#ebe6d8", font: { size: 20, weight: 500 } } }
};
function setObjStyle(obj, bar, key1, key2) {
const style = gvar.styles[key1]?.[key2];
if (!style) {
console.warn(`Unknown style: ${key1}.${key2}`);
return;
}
if (style.color && obj) {
obj.color = style.color;
}
if (style.font && obj) {
if (style.font.size !== undefined) obj.fontSize = style.font.size;
if (style.font.weight !== undefined) obj.fontWeight = style.font.weight;
}
if (bar && style.barbkg) {
bar.bar_bg_c = style.barbkg;
}
}
// Device Navigation
gvar.g_autofold = 0; // See DV_Nav_Dial
gvar.g_showClip = false; // Toggle Device / Clip View
function OnGlobalVariableChanged(name, value) {
// Let modules set a view switch via g_showClip
if (name == "g_showClip") {midi.sendCC(16, 111, (value) ? 0 : 127);}
}
// StreamDeck Connection
const DEVICE = "Stream Deck +";
midi.sendCC(11,0,127);
function OnDeviceConnected(DEVICE) {
console.warn("B ENV: Device " + DEVICE + " connected");
midi.sendCC(11,0,127);}
function OnDeviceDisconnected(DEVICE) {
console.warn("B ENV: Device " + DEVICE + " disconnected");
midi.sendCC(11,0,0);}
module.exports = {setObjStyle};
and I have only 3 background scripts.
I reverted to Version 4.2.0.133 for the moment.
Let me know if you need further testing.
Log ID:
f5c41eb3-b8b2-4aa6-b917-71d8c0cbaa66
Video:
Log should describe the behaviour shown in the video.
Everytime I restart the Stream Deck Software, the ports of the background scripts are configured to ports GP11 and GP12 (the ports that I manually put for testing).
Once the Stream Deck Software has been launched, I press the “Run(init)commands“ button of every background script. They are set to the correct ports.
But when the Stream Deck Software is quitted and launched again, the ports are restored to GP11 and GP12.
And also a little annoyance.
It seems that in javascript, in midi.sendCC the channel is is 1 based while it is 0 based in OnControlChangeReceived.
Am I correct ?
Do you think that should be changed while we are still in a beta ?
And also a little annoyance.
It seems that in javascript, inmidi.sendCCthe channel is is 1 based while it is 0 based inOnControlChangeReceived.
The intention has always been to keep it 1 based in JavaScript; I’ll check it.
I found the issue with the midiScript port settings in the (init) commands, and, as I suspected, it was a timing issue. The (init) commands worked as expected when started manually, but failed when started at plugin startup.
I have reordered things and added synchronization at plugin startup, which seems to solve the problem.
@thx538 , I am unable to reproduce your problem, but it is possible that it was caused by the same timing issue. Please try this version and see if your issue is resolved.
Breaking change: The channel reported in midi events is now 1-based.
The (init) commands worked as expected when started manually, but failed when started at plugin startup.
Version 4.2.0.203:
Confirmed that the (init) commands are working as expected in bg scripts.
Actions for chaging ports are working as expected in all scenarios.
Setting Midi ports to #none# is working as expected in all scenarios.
Please try this version and see if your issue is resolved.
Yes, it seems. I don’t see the “Plugin is loading …” window at startup anymore.
