Callbacks and Broadcasters Executing on Init; Global Variable Space as a File
-
Am I the only person who is flummoxed by (and I know I keep bringing this up):
- Callbacks executes automatically on onInit().
- Broadcaster/Receivers execute on onInit().
- Global variables don't behave like variables; they're parameters written to a file which is reloaded every time you compile within HISE—except in the compiled version, where exactly the opposite happens.
…and you can't turn any of that off.
Maybe I'm not thinking about this stuff correctly, especially within the context of using HISE correctly?
Thanks.
Can we PLEASE have a forum category, "Bill Complains About HISE"?
-
@clevername27 said in Callbacks and Broadcasters Executing on Init; Global Variable Space as a File:
Callbacks executes automatically on onInit().
They execute after on init, and only for components that have saveInPreset enabled.
@clevername27 said in Callbacks and Broadcasters Executing on Init; Global Variable Space as a File:
Broadcaster/Receivers execute on onInit().
Yup. You can handle this with a flag - same with control callbacks.
@clevername27 said in Callbacks and Broadcasters Executing on Init; Global Variable Space as a File:
Global variables
Don't use them. I haven't found a single situation yet where I needed them.
-
@d-healey Thanks for your replies - if I could pls ask some follow-ups:
They execute after on init, and only for components that have saveInPreset enabled.
Is that always the case? I vaguely remember documenting a situation where threads were executing (twice) before onInit. Something to do with default presets. The part I remember clearly is that Chris promised me a t-shirt for it. (Still waiting, @Christoph-Hart. 🥹) . I seem to remember him asking if I could live with it, and I foolishly said yes—because I could put a conditional check at the top of all my callbacks, to see when they were being called. But then I discovered that determining this in every context was nontrivial, and maybe impossible. I've noticed some other weird things during onInit, such as things seemingly happening in random orders—I keep running the same code, and if I use Console.print to log the ordering, it seems to change each time I compile. (Someone else reported this as well.)
They execute after on init, and only for components that have saveInPreset enabled.
Is that always the case about Callbacks? I don't have any components with the preset flag enabled, but the callbacks seems to come a running, regardless. And I seem to remember cases were things were called before onInit(), but I don't remember what.
Yup. You can handle this with a flag - same with control callbacks.
Do you mean manually inserting a conditional check at the head of every callback and broadcast/receiver, or a flag in HISE?
Don't use them. I haven't found a single situation yet where I needed them.
True that, bad practice. How do you pass data between (for example) UI and real-time threads (without resorted to hacks, etc.)? I know you've touched on this before, and I shouldn't be asking. 🫢
Anyway, thanks again.
-
@clevername27 said in Callbacks and Broadcasters Executing on Init; Global Variable Space as a File:
Is that always the case? I vaguely remember documenting a situation where threads were executing (twice) before onInit. Something to do with default presets
I haven't used the default preset thing so that might change things but the usual behaviour is as I described.
@clevername27 said in Callbacks and Broadcasters Executing on Init; Global Variable Space as a File:
Is that always the case about Callbacks?
Yes, but if you can make a minimal snippet/project that shows otherwise I can investigate.
@clevername27 said in Callbacks and Broadcasters Executing on Init; Global Variable Space as a File:
Do you mean manually inserting a conditional check
Yes, in every place you don't want it to execute automatically.
@clevername27 said in Callbacks and Broadcasters Executing on Init; Global Variable Space as a File:
How do you pass data between (for example) UI and real-time threads
The same way I'd pass information between my UI and an effect - or any other HISE module. Either using processor/parameter ID or setAttribute.
There is also a cross module broadcaster but I haven't been able to make it work.
-
@d-healey said in Callbacks and Broadcasters Executing on Init; Global Variable Space as a File:
The same way I'd pass information between my UI and an effect - or any other HISE module. Either using processor/parameter ID or setAttribute.
The problem with this is that this is UI downwards only, so there is no way to pass a value to the peers of a module, or back up the chain - only downwards...
-
@Lindon Each of my modules works independently, the only time I pass information is when something the user changes on the GUI needs to change something in the module.
I have a round robin module, I have a legato module, I have a mixer module, etc none of these need to communicate with each other, but the GUI might need to communicate with them.
The only exception I can think of is things like the arpeggiator where I might want to see something it generates appear on the UI, for this I'd use a slider pack or table and link them via processor ID.
Can you give me a scenario where you want intercommunication between modules and there isn't another way of achieving your goal by making the modules independent?
-
@d-healey said in Callbacks and Broadcasters Executing on Init; Global Variable Space as a File:
Can you give me a scenario where you want intercommunication between modules and there isn't another way of achieving your goal by making the modules independent?
Sure.
I have a system with a global level arppegiator, I want the 4 voices to listen for the arp note arriving(easy enough to do with a script processor) and then for one of the voices, the "master voice", to make a decision about if its going to play the note...and to then tell the other 3 voices its decision....so they can join in - or not. -
@Lindon said in Callbacks and Broadcasters Executing on Init; Global Variable Space as a File:
I want the 4 voices
What do you mean by voice?
-
@d-healey sampler
-
@Lindon Ah I see the issue, because the encapsulated MIDI processors can't see each other. Could you put your master controller outside of the samplers' MIDI processor chain?
Can you give me an example of what circumstances the master will decide not to play a note?
-
@d-healey said in Callbacks and Broadcasters Executing on Init; Global Variable Space as a File:
@Lindon Ah I see the issue, because the encapsulated MIDI processors can't see each other. Could you put your master controller outside of the samplers' MIDI processor chain?
Can you give me an example of what circumstances the master will decide not to play a note?
Im sure I could, but you have the point - its occurred more than once in more than one instrument for me - essentially extending the playback systems is difficult in HISE given this limitation of encapsulated MIDI processors not being able to communicate with any modules not below them in the "chain of command"
So you are left with this "poor encapsulation" approach of designing a master processor....which is just moving globals into another spot...
-
@Lindon said in Callbacks and Broadcasters Executing on Init; Global Variable Space as a File:
Im sure I could,
Without an example I'm just guessing here so this may be totally wrong. Let's say the master decides it won't play a note if it's MIDI number 60. And it needs to communicate this to the other processors.
In this simple example I would say why not make all of the other processors independent so they all ignore note 60 without needing the master to tell them. Essentially they all share the same script as the master and you only have one script to maintain.
-
@d-healey said in Callbacks and Broadcasters Executing on Init; Global Variable Space as a File:
@Lindon said in Callbacks and Broadcasters Executing on Init; Global Variable Space as a File:
Im sure I could,
Without an example I'm just guessing here so this may be totally wrong. Let's say the master decides it won't play a note if it's MIDI number 60. And it needs to communicate this to the other processors.
In this simple example I would say why not make all of the other processors independent so they all ignore note 60 without needing the master to tell them. Essentially they all share the same script as the master and you only have one script to maintain.
okay - well how about we stop trying to fix the specific - because I just made it up - and try to focus on the generic problem?
-
@Lindon said in Callbacks and Broadcasters Executing on Init; Global Variable Space as a File:
on the generic problem?
I don't see a generic problem as such, I see a structural issue with your project - but it could be that that is the only way to structure your project and then there would be a generic problem. It's difficult to say without real examples to work with.
-
Is that always the case? I vaguely remember documenting a situation where threads were executing (twice) before onInit. Something to do with default presets
I haven't used the default preset thing so that might change things but the usual behaviour is as I described.
Wisely said; here's the thread: https://forum.hise.audio/topic/10723/preset-component-callbacks-triggering-twice-on-startup/11?_=1742336098253
Is that always the case about Callbacks?
I will investigate - it will take me a couple weeks, but I will get back to you.
Do you mean manually inserting a conditional check
Yes, in every place you don't want it to execute automatically.I appreciate your thoughts. For me, at least, that solution isn't tenable. I have far too many callbacks, and it has emerged, on my end, that I am unable to always tell if a callback is being called at startup—or even what means, when you get into the various preset handling systems. But overall (and this is a @Christoph-Hart thing, not you), to me it is an illogical and limiting design choice. I get why it's there, and I'm free to write my own HISE. I just think it's wrong, much like with the broadcasters.
How do you pass data between (for example) UI and real-time threads.
The same way I'd pass information between my UI and an effect - or any other HISE module. Either using processor/parameter ID or setAttribute.I thought about this, a lot. Because generally, I agree with you (and I teach my students as such) that global variables are to be eschewed (and because your code is so elegant). But there are legitimate usage cases for them. And more to the point—if the language says it supports global variables, then it should do that. At one point, @Christoph-Hart improved the handling of globals by introducing the Global object…but…and please let me know if I have this wrong…didn't fix them so they work properly.
Out-of-order execution during startup.
I have looked high and low for the screen-capture movies I made, but I don't think I was able to upload them because they were over 10MB, so I deleted them. I do remember that another user appeared to be having the same issue. I simply had to spend a couple weeks completely refactoring my code to get around that issue.
Anyway, thank you, as always, for giving thought to my questions.