Getting error message "Execution timed-out"
-
This is indeed a bit tricky. The scripting engine expects all components to be created in the
onInit
callback (and that's how almost all other scripted interface system works) Removing this restriction might come with some side effects and will create a performance impact (remember the control callbacks might get called in the audio thread if the control is automated by a MIDI CC so it's not just graphics).Are you sure you can't solve this problem with a fixed pool of "preallocated" UI widgets that are created when the script is compiled? I could add the possibility to change the parent relationship between components dynamically as well as changing the mouse callback function and the paint routine function (the latter is already working), so you could simply create a bunch of empty and invisible panels and morph them into the thing you need on certain user events.
This should work for the FX rack system (unless you want to have an effect more than once, but this complicates things also on the DSP side).
-
This is an example of using a pool of preallocated Panels:
namespace PanelPool { const var POOL_SIZE = 256; inline function _createEmptyPanel(index) { local p = Content.addPanel("Panel" + index, 0, 0); p.set("visible", false); return p; } const var _emptyPanels = []; const var _panelUsed = []; _emptyPanels[POOL_SIZE] = 1; for(i = 0; i < POOL_SIZE; i++) { _emptyPanels[i] = _createEmptyPanel(i); _panelUsed[i] = false; } inline function newPanel(x, y) { local i; local p; for(i = 0; i < POOL_SIZE; i++) { if(!_panelUsed[i]) { _panelUsed[i] = true; p = _emptyPanels[i]; p.set("visible", true); p.set("x", x); p.set("y", y); return p; } } } inline function deletePanel(p) { local i = _emptyPanels.indexOf(p, 0, 0); _panelUsed[i] = false; p.set("visible", false); } } notePanels = []; notePanels[127] = 1; function onNoteOn() { notePanels[Message.getNoteNumber()] = PanelPool.newPanel(Message.getVelocity(), 0); } function onNoteOff() { PanelPool.deletePanel(notePanels[Message.getNoteNumber()]); } function onController() { } function onTimer() { } function onControl(number, value) { }
When you press a note, it "creates" a panel (and sets it's x-position to the velocity value) and if you release the note it "deletes" it.
-
Well, that's interesting.
Anyhow, I had to make FX rack system which can get the effect more than once. You can see those racks in BlueBeast. Each empty slot should be able to be replaced by any rack selected on runtime. And there may be same racks. So I had to make interface something heavy.
I guess it is the limit of script based sdk. It would be hard to manage multi thread processing logic with UI and audio thread dynamically.One more thing I want to ask.
Is it possible to make panel which can show stretched image according its size?
When we make iOS app or plugin or we make resizable stand-alone application, control images should be resized or stretched. And so we will definitely need such features, I think.Really appreciate for your kind answer and support.
Thanks.
-
I just pushed a commit that allows changing parent components dynamically:
In this example there is a button and a Panel. If you press a note, the button will be attached to the panel and if you release it, it will be back to default.
HiseSnippet 777.3ocsU82SSCDF951ZhTcDw3Gfl8WiDbrBnPzXD1jYlxFKVBwDiAuc8F6Bs20b8J3fvWI+r42.8tds1trAgZhMYY6ddeed2y812eLhyP3nHFGX73SlEhAFOwzcFULs6THgB5+dfwplCfQBL2VC0YVHLJB6ALLp9AEfwJ0.IO+5ccf9PJBmCA.mxHH7Qj.hHG866+IhueOnG9DRPAu2Y+9HFsKymEK0SUy1fPH5B343gPkaULAWRvWEALZat8Vs3W3L95CZ0p00imMXq66yQ.TLmiohSkzAFlF+V9XXdnGQv3tBn.KiY0NLuYtSYWQ0+0mRhHi8wpCN.WolzvftSI9dixRaQ.fQsQ4Iwp5j3yMGP7H+EOOY9zDC14LJlNMpLujpMmjbtKI0i46oBvcHOiBxqlVdqY5h3jPQtEk1dVJ5cnNsQPkeZXZIeMEIruDxsGAoXe62Z2kQExLbKnmWBTyFIe0XCam81cC61q+FqM2z9qez83gZNeyJiRDVIjPLWPvQ83r.kS47uotksciqHdhoMdssyNaW251znsYgvU2ptUAc0IVHXz4ElFqYC82xP2VKrIwTjfH8lQGxD3ioMW25FqUztojWyFgPU8SWVPHiJ+gjap9jzucg.LYxCJBKPVoUNy2Gy07m2ppYYoFRo0jFGLFy2Pd+8iwY9IqKlupx5gUUgz4sBNxn8oDwwg3zNjrr0BHSljAoHkeoJ5XxkoHPpa4PKVJCReWpJpScW5pHojd0zhWcJGPjkrOxL8PR9n3PIvhsDxFSlWrOTLe2pZBWpAYtdt9g9JsDQDyJNArDsvsWZKryxt2OP4tl4Hh.Mc45sxRzqLQ9+VuoCDqad3jIXjHWr0L68k+0oekPJelEKHzyG.EbxOjy9GFG3JWufvRkPkMvQp8AUT0V5ysUmUYFWL0qc1xhTiNpyFoFcxLBBfHN6LjthTMx8QIHRMQSVbshbCp7rsSVknR2Ax8.mgPpDwKjJe4L1pzL1tzL1ozLdYoY7pRyX2RyXu6ggZo6AwBVfts..9C9fgWB
Setting the mouse callbacks and changing the paint routine also works dynamically (just pass another function into
Panel.setMouseCallback()
. Let me know if this works out for you or if you need something else. -
OK I see. But even if you have the same racks multiple times, you should be able to use this approach. In this case, you would not need a dynamic amount of rack panels, but rather a pool of sliders and other UI elements that can be skinned and assigned to the panels dynamically. However this is the easy part, hooking it up to the callbacks and assigning them to control parameters in a performant way is a bit more complicated, but I'll think of something - maybe I add the possibility of connecting a callback function directly to the component so you can do something like:
const var slider = Content.addSlider("slider", x, y); slider.setControlCallback(inline function(value)) { Console.print(value); }
This also removes the necessarity of writing one big switch statement, however the function passed in must be an
inline function
, so it works without allocation.Resizing is already supported. You can pass a rectangle to the
g.drawImage
function and it will rescale the image. If you are using a retina display, it will use the full resolution (so the best practice for retina images is to load the full image and scale it by 50%). -
I got. Thanks for your good information.
And it would be better to make enable following things.
const var delayRack = createRack(FX_DELAY); // create fx rack with its id delayRack.setControlCallback(inline function(id/*child control of rack*/, value) { switch(id) { ... } });
-
Well, this is overly complicated because it needs to keep track of the parent relation ship. Having one function per element makes the control callback execution even faster than it is right now. There are still a lot ways to make this automatically (you can store inline functions in an array for each rack and pass it on to it's child components on creation etc).
-
Alright, I committed this feature:
const var Knob = Content.addKnob("Knob", 0, 0); inline function x(component, value) { // component == Knob Console.print(value); } Knob.setControlCallback(x);
setControlCallback
can be called at any time so you can implement the dynamic behaviour. There are some rules:Two Parameter
The inline function must have two parameters, the first being the component that caused the callback and the second the value (just like the
onControl
callback).No anonymous Inline functions
the argument for
setControllCallback
must be a inline function. However, there is nothing like a anonymous inline function, so this won't work:Knob.setControlCallback(inline function(c, value){ Console.print(value); });
Instead, you need to define the inline function up front and pass it to the callback with its name. But this should not be a real restriction as you might want to write all callbacks up front anyway.
Resetting the component
When a custom callback is set, the
onControl
callback of the script will not be executed if the respective component was moved. In order to restore this behaviour, simply passundefined
as parameter tosetControlCallback
Let me know if this works for you. You can group inline functions in arrays and pass them to arrays of knobs to automate things:
inline function p1(component, value) {Console.print("P1");}; inline function p2(component, value) {Console.print("P2");}; inline function p3(component, value) {Console.print("P3");}; inline function p4(component, value) {Console.print("P4");}; inline function p5(component, value) {Console.print("P5");}; inline function p6(component, value) {Console.print("P6");}; inline function p7(component, value) {Console.print("P7");}; // Some random combinations of callbacks const var pSet1 = [p1, p4, p6, p2]; const var pSet2 = [p3, p2, p7, p5]; const var knobs = []; knobs[0] = Content.addKnob("Knob1", 0, 0); knobs[1] = Content.addKnob("Knob2", 130, 0); knobs[2] = Content.addKnob("Knob3", 260, 0); knobs[3] = Content.addKnob("Knob4", 390, 0); const var ComboBox = Content.addComboBox("ComboBox", 550, 10); // [JSON ComboBox] Content.setPropertiesFromJSON("ComboBox", { "items": "Set 1\nSet 2" }); // [/JSON ComboBox] function onNoteOn() { } function onNoteOff() { } function onController() { } function onTimer() { } function onControl(number, value) { if(number == ComboBox) { local setToUse = value == 1 ? pSet1 : pSet2; for(i = 0; i < 4; i++) { knobs[i].setControlCallback(setToUse[i]); } } }
-
That looks sweet!
-
this is nice _ i'll definitely be using it....
-
NIEECE! thanks