Broadcasters best practices
-
I just tried using the broadcaster wizard for the first time. I selected
ComponentVisibility
in the second screen, this is what it gave meconst var showAboutBroadcaster = Engine.createBroadcaster({ "id": "showAboutBroadcaster", "args": ["component", "isVisible"], "tags": [] }); // attach to event Type showAboutBroadcaster.attachToComponentProperties(["pnlAboutContainer"], "Temp"); // attach first listener showAboutBroadcaster.addComponentPropertyListener(["pnlAboutContainer"], ["visible"], "temp", function(index, component, isVisible){ return isVisible; });
This gives an error
argument amount mismatch: 2, Expected: 3
I changed it to
attachToComponentVisibility
and the issue is resolved. -
@Christoph-Hart said in Broadcasters best practices:
You can do this kind of simple object oriented stuff by creating a JSON object and attaching functions as member, which will then access the JSON properties through the
this.property
syntax:// This as close as you'll get to object oriented programming in HISE Script function createInstance(valueToUse) { var prototype = { create: function() { // Access properties of the "class" object with this Console.print(this.value); }, value: valueToUse // store the "constructor argument" as "class member" }; return prototype; } // And now let's add polymorphism: function createSubClassInstance(valueToUse) { var prototype = createInstance(valueToUse); prototype.create = function() { Console.print(this.value + ": SUBCLASS"); }; return prototype; } // Create two instances of the "class" var x1 = createInstance(90); var x2 = createInstance(120); var x3 = createSubClassInstance(500); // call the method of each instance x1.create(); x2.create(); x3.create();
So just looking at this. I think I get it, and I can see how this would help me. For example here is what I have so far:
function Sampler(id) { var sampler = { connectComponents: function() { this.pad = Content.getComponent("panel_" + this.id); this.sampler = Synth.getChildSynth("sampler_" + this.id); this.processor = Synth.getAudioSampleProcessor("sampler_" + this.id); this.sequencer = undefined; }, populateLayers: function() { for (i = 0; i < layer_count; i++) { this.layers[i] = { 'audiofile': this.processor.getAudioFile(i), 'ui_parameters': {}, 'loop_panel': Content.getComponent("loopdragger_" + this.id), 'waveform_panel': Content.getComponent("waveform_" + this.id), }; } }, connectCallbacks: function() { this.pad.setFileDropCallback("Drop Only", "*.wav", load_sample); }, id: id, layers: {}, }; return sampler; }
It'll get more interesting when I actually write a function to check if a component exists, and if it doesn't, create it.
-
@d-healey said in Broadcasters best practices:
I just tried using the broadcaster wizard for the first time. I selected
ComponentVisibility
in the second screen, this is what it gave meconst var showAboutBroadcaster = Engine.createBroadcaster({ "id": "showAboutBroadcaster", "args": ["component", "isVisible"], "tags": [] }); // attach to event Type showAboutBroadcaster.attachToComponentProperties(["pnlAboutContainer"], "Temp"); // attach first listener showAboutBroadcaster.addComponentPropertyListener(["pnlAboutContainer"], ["visible"], "temp", function(index, component, isVisible){ return isVisible; });
This gives an error
argument amount mismatch: 2, Expected: 3
I changed it to
attachToComponentVisibility
and the issue is resolved.Any ideas about this one Christoph? Is it a bug or did I use the wrong settings in the wizard?
-
@d-healey your function prototype is correct, now just make the arguments for the broadcaster match, i. e. add index to the args
-
@aaronventure This is auto-generated by the broadcaster wizard - and it doesn't work, therefore I think it's a bug. It should be using attachToComponentVisibility, but it isn't.
-
@d-healey ah gotcha
-
-
This is confusing
I had no idea what was wanted here, but it's a string (must have quotes)
I tried to add multiple events to the EQ broadcaster and the output was
"BandAdded, BandRemoved, BandSelected"
which doesn't work. It should be["BandAdded", "BandRemoved", "BandSelected"]
-
@d-healey said in Broadcasters best practices:
I had no idea what was wanted here, but it's a string (must have quotes)
You can pass any object into the addCallback() function which will be assigned as this object in the executed function:
const var list = [1, 2, 3]; bc.addCallback(list, "something", function() { for(n in this) Console.print(n); // 1, 2, 3 });
In this case you would just enter
list
into the This Object field.The other issues you mentioned are fixed now.
-
@Christoph-Hart Ah ok that makes sense, thanks
-
@d-healey said in Broadcasters best practices:
@Christoph-Hart Ah ok that makes sense, thanks
does this mean you are investigating Broadcasters with a view to doing a video on it? (fingers crossed here...)
-
@Lindon I've been using them since they were a thing. I'll make a broadcaster video for this weekend
-
@d-healey If you find any UX hurdles during the making of the video, let me know then I'll clean it up.
-
Can broadcasters be defined as
global
? I might have finally found a use case for a global variable.In my project I have a few MIDI processors that do things when the user changes articulation. My current method of handling this is each of the scripts has a knob to keep track of the current articulation. And when the articulation is changed all these knobs are updated and their callbacks triggered.
I'm thinking though it might be nice to just have a global articulation watcher instead of these knobs. That way the scripts will be more independent - which is the opposite of my usual argument against globals :)
-
@d-healey said in Broadcasters best practices:
Can broadcasters be defined as global?
Well I thought this was working, but then a user noticed a bug. If in the DAW the track with the plugin is duplicated the broadcaster behaviour seems to break. Are globals shared between plugin instances somehow?
-
@d-healey ooh boy. Does it affect other globals as well?
-
@aaronventure This is the only global I'm using so haven't tested it with others
-
@aaronventure no globals are used per instance. The only relevant thing that I know that is shared is the timer thread so if you have multiple instances with busy timers you might experience UI freezes.
-
@Christoph-Hart No timer here just a global broadcaster. When I remove that code and implement the same functionality without the global the problem goes away. I'll see if I can make an isolated example.
-
@d-healey yup an isolated example would be useful, I wouldn't know why it should behave like that but maybe I missed something, it's definitely not supposed to do so.
-
I managed to isolate it.
HiseSnippet 1189.3oc6W01ahaDDdMINWs6KpQs+.b8mLRnbP50qU8TTIPRphtKIniznVkdJZwdAVk06hrWRgFgz8Sq+j5+f1Y7KXycNMTTuuU9.hcl4YlYmclmcoWjxmEGqhHFVWNeBiX7Il8mK0i6NlxkjSOhXrq4fHEMvmFqYQWxh0jNymPiiYADCis9QzLCqsIIe9yenCUPk9rBQDxUJtO6U7PttPZu1ujKDmPCXWxCKY8yZepuR1UITSgTZKyljIT+aoiXmSQypYRL143.tVE0WS0rXhw1cTAy6OV8axT6uhGyGHX3hVj9fiREehRDfYLJkzcLWDzKeqGS.uzqnPrUZg3KMOiGvWJunf74IJbJPTtdXTa0zaqURuVkSulkRuJRoZkRosSSocM66GwmnKzf4yGadpDNZFRgxd4TI0VRseslYWEXgTuWH8V1IQvhkH7ddylMbfup+Ba6QB0.pvYzMkNwicNv49EnxUjtW37N9fpiki3R1d9QLX+1ov.O66ssb4AteuiKZpaCXIMZTLH3ZWtLfMy8M1Kvn9zm9UNClp0JYrMb3GqcFnkfqyS5QL8gBQWU3DkDVG64B5cQjCUQNdyb3RDQcaqY6EyzHrHknKUHF.8NdJInLSH.xxlKEPJ6LbpzWyURmxF34mGlFN2QESY0su2x15cCTZjtBM.DevANKgkDAK9PGuT3vBqJpb.bYvgwyk9mAGjP+s20fm2Kotbwvhrn9a.Gt.1oEI64JM6BoWcr.CpbdWUCGVotrMn.NZpRMNFF8OAzSNMb.KpnrjZHzatZCu4C2vWddzO8vsjgJ4oRt9hIL4CMkRx5Hv40rrBLUmLZ7YYiFcRZjHbXBXGSnj1jjjuv7PMx5ho0RLas1X1eMvzWvCXQIXdh4KkpAKCTAYI4mN8HplBaQircKTAlvhzbr3ZbD6NfLMkMvx7HV7sZ0jjxQVCC76GqfLaY7d60smWD7yaSVe2z5Acyu7uwM6+Pt4szUbySdzJ4C3m+PzNjGDHX8Twbrit7kUv73j97emUVVHcVoyi1j0kE9KxjVbuPqJYiutlYJI2czHmkzv.cWx0tHY2JW634tzF2TxRmag8aFQI9yRLkzf.rX34hxca3.L6HuNtB4qdMUBDMfv8a3zpj72mwD0TPYVAiYICphxz1ZYViA3PsNhCT7LuBwImZ4HR33PRSd7QrgPrB7pfzrdhmqhME13uhCqk.GVx0MNhrkPU3dd.dIDSScWzX4lvKgqE3xAWZkWIRYzS07hb49iw5VfGJAuvZw+SFuJYrwZP3siIVKy46LM1btNiRzB67XwaVdrlm+iMalGdymJXpfpW8gf3qeyTfTKkm2wNcIP4Lubf9O60gqaJtqYOt1eb04XsJxQ7gme.xwr2T+olGObHyWWjfaadxO+g4AzjWqlp4xQmQAxGrO37og8g+VgOChtTxD37A7p.DZx5l4sH8g2lkr3ufOYJagqMxT1JWIIj5GotwOs+Ge09GkHAxIYxeXwx7LbsSE2zCWKwuw2eUW8d.2eSA90aJvmso.+lME3y2Tfe6lB76dbf3svGNUqBSGaHjy5cbBakgwwRJzAlzsR9a.HSuTJ.
So the buttons in the Interface script send a message to the broadcaster with the index of the button that was pressed. In the second script processor, there is a listener on the broadcaster. The listener gets the value that was passed, updates the knob value in the script processor and calls the .changed function on the knob. In the knob's callback it sets the value of the knob on the Interface script to this value.
Now interestingly - if I don't use the .changed callback in the second script and instead put all the functionality in the listener then it works.
I've been testing this as an expansion in Rhapsody so I didn't have to keep recompiling, I haven't actually tested it as a plugin...
To recreate the issue, add the plugin to a track, click the buttons and you'll see the knob on the UI match the index of the button that was clicked. Then duplicate the track, open the plugin UI on the new instance, click the button and the knob value doesn't update.