Visibility and CPU
-
When a key I've assigned triggers my on note callback I have it make visible a few controls. I've noticed that the CPU usage at this point jumps up to 9-10%. Is this something I should be concerned about and is there any way to reduce it?
The function I'm using is below. I store the controls in an array, so cmbKs contains one combo box panel for selecting a key switch for each of the 5 articulations.
//Display the keyswitch and UACC assignments for the articulation (artIndex) inline function displayArticulationValues(artIndex) { //Hide all articulation controls for (i = 0; i < articulationNames.length; i++) { cmbKs[i].set("visible", false); cmbUacc[i].set("visible", false); sliAttack[i].set("visible", false); sliRelease[i].set("visible", false); lblAttackValue[i].set("visible", false); lblReleaseValue[i].set("visible", false); } //Show controls for artIndex if (cmbArt.getValue() != artIndex+1) cmbArt.setValue(artIndex+1); cmbKs[artIndex].set("visible", true); cmbUacc[artIndex].set("visible", true); sliAttack[artIndex].set("visible", true); sliRelease[artIndex].set("visible", true); lblAttackValue[artIndex].set("visible", true); lblReleaseValue[artIndex].set("visible", true); //Repaint controls cmbArt.repaint(); cmbKs[artIndex].repaint(); cmbUacc[artIndex].repaint(); sliAttack[artIndex].repaint(); sliRelease[artIndex].repaint(); }```
-
Yes. Never do anything GUI related in a MIDI callback with a non deferred script:
-
I'll have to play around with it because my script is doing some time critical stuff too with sending out CC message so I don't want to defer that
-
Can you put the time critical part into another ScriptProcessor? Encapsulation...
-
Yeah I think I'm going to setup a dedicated MIDI processing script
-
I'm hitting some issues trying to separate the MIDI stuff from the GUI because in a few places they seem too tied together. For example, when I move the mod-wheel I want to forward the data to another CC number while also setting the value of a slider to the the CC value. The complicated part is that the GUI is used to determine which CC number to forward the mod-wheel to and the value is scaled using a table. If I separate the MIDI processing to another script I would also have to duplicate parts of the GUI so the value is scaled appropriately and the correct CC number is used.
I'm thinking there may be a simpler way though. I could store the CC numbers in a global array but how could I pass the table values to another script?
-
Ah, I see, our old problem of inter script communication with non trivial UI widgets :)
There are multiple solutions:
Don't split the script and use a dedicated Timer object to implement a asynchronous update system:
/** The AsyncUpdater can be used to trigger a deferred UI update * from a MIDI callback. Just give it a (inline) function using setUpdateFunction() * and call triggerUpdate() to asynchronously launch the update function. */ namespace AsyncUpdater { /** set a function that will be executed asynchronously. */ inline function setUpdateFunction(f) { handleAsyncUpdate_ = f; } /** Call this to update your UI asynchronously. */ inline function triggerUpdate() { internalUpdater_.startTimer(30); } /** Internal stuff. */ const var internalUpdater_ = Engine.createTimerObject(); reg handleAsyncUpdate_; internalUpdater_.callback = function() { if(handleAsyncUpdate_) handleAsyncUpdate_(); else Console.print("No UI update function defined"); Console.print("UI Update"); this.stopTimer(); }; }; inline function myUpdateFunction() { Console.print("This is my update function"); for(i = 0; i < 10000; i++) // Something that takes long Math.sin(2.0); } AsyncUpdater.setUpdateFunction(myUpdateFunction);
The other solution would be to use the table from the CC modulator directly but that would most likely require a redesign of your architecture using one global CC modulator.
-
I like the async updater idea, I shall give it a go
-
Yep that system works perfectly, effectively allowing us to defer individual functions. I made a slight modification so that a parameter can be passed to the function and so that the function can be assigned and then the updater ran without having to call two functions. Is it okay for me to include this code in my HISE scripting framework on github (under a GPL license, copyright Christoph Hart) ?
namespace asyncUpdater { /** set a function that will be executed asynchronously. */ inline function setUpdateFunction(f, p) { handleAsyncUpdate_ = f; param_ = p; } /** Call this to update your UI asynchronously. */ inline function triggerUpdate() { internalUpdater_.startTimer(30); } inline function setFunctionAndUpdate(f, p) { handleAsyncUpdate_ = f; param_ = p; internalUpdater_.startTimer(30); } /** Internal stuff. */ const var internalUpdater_ = Engine.createTimerObject(); reg handleAsyncUpdate_; reg param_; //Parameter to be passed to function - set to null if not used internalUpdater_.callback = function() { if (handleAsyncUpdate_) { param_ == null ? handleAsyncUpdate_() : handleAsyncUpdate_(param_); Console.print("UI Updated"); } else { Console.print("No UI update function defined"); } this.stopTimer(); }; };
-
Every script snippet I post here in the forum can be considered as public domain, so you can rewrite them and use them in your GPL codebase without any issues.
However, I'd suggest to consider a more permissive license for basic functions like that and use the GPL license for scripts with real IP like your customised portamento script or your templated GUI.
This kind of dual licensing is pretty common (JUCE also offers their basic module under the ISC license and the GPL is just for the advanced stuff). HISE itself also uses different open source licenses for certain parts (eg. the HLAC codec is BSD licensed and the DSP module API is MIT licensed).
-
Yeah that makes sense, duly noted!