HISE Logo Forum
    • Categories
    • Register
    • Login

    Broadcasters best practices

    Scheduled Pinned Locked Moved Solved Scripting
    53 Posts 6 Posters 3.3k Views
    Loading More Posts
    • Oldest to Newest
    • Newest to Oldest
    • Most Votes
    Reply
    • Reply as topic
    Log in to reply
    This topic has been deleted. Only users with topic management privileges can see it.
    • clevername27C
      clevername27 @d.healey
      last edited by clevername27

      @d-healey Since we're talking about function pointers, I'm guessing that if you don't clean up after a child panel is removed that you will crash (not when it's removed, but when called).

      1 Reply Last reply Reply Quote 0
      • d.healeyD
        d.healey @Christoph Hart
        last edited by d.healey

        @Christoph-Hart said in Broadcasters best practices:

        having listeners attach to at various places.

        Sure, but where do you declare the broadcasters?

        Let's say I have a namespace called Downloader and I have another namespace called Uninstaller.

        From the Uninstaller namespace I want to know if a download is in progress - because I don't want to be uninstalling things while other things are downloading.

        Do I create an isDownloading broadcaster within the Downloader namespace? - this would mean the Uninstaller namespace has to be "aware" of the Downloader namespace. Or do I create a middle-man namespace where the broadcaster is declared and let both the Downloader and Uninstaller namespaces talk to that? This would keep the namespaces independent of each other. Or is there another solution?

        Libre Wave - Freedom respecting instruments and effects
        My Patreon - HISE tutorials
        YouTube Channel - Public HISE tutorials

        A 1 Reply Last reply Reply Quote 0
        • A
          aaronventure @d.healey
          last edited by

          @d-healey The whole idea is that it's a sort of dynamic callback that you can add to from wherever.

          I have a control helper class that has its own value change broadcaster, which is attached to all controls by default.

          As I add functionality, if I want things to happen on value change, I just call .addListener and add a function. If I remove that class, no worries, the broadcaster is still there and all other classes are still benefiting from it.

          You just gotta watch the order of declarations.

          I first include my script library, then it's ColorPalette, TransportHandler, Animation, PaintRoutines, and then it's ControlHelpers.

          Getting on top of broadcasters would be my first suggestion to anyone doing code in HISE, as it's the class that makes it all come together.

          d.healeyD 1 Reply Last reply Reply Quote 1
          • A
            aaronventure @d.healey
            last edited by

            @d-healey said in Broadcasters best practices:

            Do I create an isDownloading broadcaster within the Downloader namespace? - this would mean the Uninstaller namespace has to be "aware" of the Downloader namespace. Or do I create a middle-man namespace where the broadcaster is declared and let both the Downloader and Uninstaller namespaces talk to that? This would keep the namespaces independent of each other. Or is there another solution?

            You declare the isDownloading broadcaster in your Downloader namespace. It simply sends out isDownloading to all of its listeners whenever the download changes. You can even pass that broadcaster object into the function for a callback.

            Then in your Uninstaller, you can check if it's defined, and if so, attach functionality to it. That way your modules are still independent but get "upgraded" if other modules are present.

            I don't know if broadcasters can be defined dynamically, but you can add listeners dynamically. So unless you have something important to do in on init, you can always add user functionality listeners with a delay (Content.callWithDelay) of 500ms or so, that way you don't really care about module import order as all base broadcasters will already be defined by then.

            1 Reply Last reply Reply Quote 1
            • d.healeyD
              d.healey @aaronventure
              last edited by d.healey

              @aaronventure said in Broadcasters best practices:

              The whole idea is that it's a sort of dynamic callback that you can add to from wherever.

              Yeah I know this, I've been using broadcasters since they were a thing, but I'm not happy with how intertwined my code becomes.

              @aaronventure said in Broadcasters best practices:

              You declare the isDownloading broadcaster in your Downloader namespace. It simply sends out isDownloading to all of its listeners whenever the download changes. You can even pass that broadcaster object into the function for a callback.

              Then in your Uninstaller, you can check if it's defined, and if so, attach functionality to it. That way your modules are still independent

              This is the part I'm missing. How is the Uninstaller independent of the Downloader in this scenario? It still needs to be aware that there is such a thing as a Downloader namespace, even if just to check that it exists.

              I think what I need is a script wide broadcaster handler. So I just say "Hey HISE, does a broadcaster with this ID exist? I don't care where it is, just tell me if it exists or not and give me a reference so I can listen to it". That would allow all scripts to be completely independent of each other. @Christoph-Hart This should be possible, no? Since the broadcaster map has this info.

              In my current project I have a namespace called Header which has a logo on it. When the logo is clicked I want an about page to popup. The about page is handled in an About namespace.

              What I've been struggling with is do I just put a callback in the Header namespace and call About.show() - which is a nasty solution. Do I create a middle-man broadcaster - which seems like over kill, or do I create a broadcaster in the Header namespace purely for the About namespace to listen to - which seems wierd.

              Libre Wave - Freedom respecting instruments and effects
              My Patreon - HISE tutorials
              YouTube Channel - Public HISE tutorials

              A d.healeyD 2 Replies Last reply Reply Quote 0
              • A
                aaronventure @d.healey
                last edited by aaronventure

                @d-healey said in Broadcasters best practices:

                What I've been struggling with is do I just put a callback in the Header namespace and call About.show() - which is a nasty solution. Do I create a middle-man broadcaster - which seems like over kill, or do I create a broadcaster in the Header namespace purely for the About namespace to listen to - which seems wierd.

                The header gets a mouse click broadcaster. About says if (isDefined(Header.clickBroadcaster)) Header.clickBroadcaster.addListener().

                If you don't want to worry about include order, call this with a delay, because it's user functionality.

                d.healeyD 1 Reply Last reply Reply Quote 0
                • d.healeyD
                  d.healey @aaronventure
                  last edited by

                  @aaronventure said in Broadcasters best practices:

                  About says if (isDefined(Header.clickBroadcaster))

                  Right this is the issue. I might as well just use About.show() in the button's callback in the Header than go to the trouble of creating a broadcaster.

                  Libre Wave - Freedom respecting instruments and effects
                  My Patreon - HISE tutorials
                  YouTube Channel - Public HISE tutorials

                  A 1 Reply Last reply Reply Quote 0
                  • d.healeyD
                    d.healey @d.healey
                    last edited by

                    @d-healey said in Broadcasters best practices:

                    I think what I need is a script wide broadcaster handler.

                    I guess this would be functionally the same as using a dedicated broadcaster namespace actually.

                    Libre Wave - Freedom respecting instruments and effects
                    My Patreon - HISE tutorials
                    YouTube Channel - Public HISE tutorials

                    1 Reply Last reply Reply Quote 0
                    • A
                      aaronventure @d.healey
                      last edited by

                      @d-healey But why? Your About namespace is a cool thing on its own, but if it's added to the same script that has the header, it'll pop up when the header is clicked.

                      The only thing you'll have to lock down is how you name your namespaces.

                      d.healeyD 1 Reply Last reply Reply Quote 0
                      • d.healeyD
                        d.healey @aaronventure
                        last edited by d.healey

                        @aaronventure But why should the about namespace know or care if there is a thing called Header? The only thing it needs to know is should it show the pop-up. And perhaps in the future I will want other triggers to show the About pop-up that aren't in the header.

                        I really like code to be as portable and self-contained as possible. It makes future extension and maintenance easier - usually.

                        Libre Wave - Freedom respecting instruments and effects
                        My Patreon - HISE tutorials
                        YouTube Channel - Public HISE tutorials

                        Christoph HartC 1 Reply Last reply Reply Quote 0
                        • Christoph HartC
                          Christoph Hart @d.healey
                          last edited by

                          @d-healey said in [Broadcasters

                          I really like code to be as portable and self-contained as possible. It makes future extension and maintenance easier - usually.

                          Makes sense but if you write two modules which need to listen to each otherโ€˜s broadcaster then they are not self-contained and blaming the broadcaster is just shooting the messenger - literally :)

                          d.healeyD 1 Reply Last reply Reply Quote 0
                          • d.healeyD
                            d.healey @Christoph Hart
                            last edited by d.healey

                            @Christoph-Hart Sure, but let's say both namespaces are aware of a third namespace called Broadcasters. They can both check if there is an isDownload, or showAboutPopup broadcaster there and do whatever they need to do. The implementation of the broadcaster is totally independent and is therefore easily transferred to other projects or used in different contexts.

                            If the Header is looking for a specific About namespace or vice versa then they are more coupled than if they are looking for a generic Broadcasters namespace.

                            I think what I'm closing in on is having a dedicated Broadcaster namespace. I'll have to play with it and see if I like the workflow.

                            Libre Wave - Freedom respecting instruments and effects
                            My Patreon - HISE tutorials
                            YouTube Channel - Public HISE tutorials

                            Christoph HartC 1 Reply Last reply Reply Quote 0
                            • Christoph HartC
                              Christoph Hart @d.healey
                              last edited by

                              @d-healey said in Broadcasters best practices:

                              I think what I'm closing in on is having a dedicated Broadcaster namespace. I'll have to play with it and see if I like the workflow.

                              Actually that's what I've been doing, a namespace called DataGlobal which houses reference arrays, broadcasters & constants that can be picked up by other scripts. I started out with local broadcasters and then decided to refactor it midway, so what I did was keep the old variable name and just point to the broadcaster defined in the DataGlobal namespace.

                              Before:

                              namespace Something
                              {
                              const var somethingBroadcaster = Engine.createBroadcaster({});
                              
                              somethingBroadcaster.addListener(...);
                              
                              }
                              

                              After:

                              namespace DataGlobal
                              {
                              const var somethingBroadcaster = Engine.createBroadcaster({});
                              }
                              
                              namespace Something
                              {
                              const var somethingBroadcaster = DataGlobal.somethingBroadcaster;
                              
                              // This line (and everything that uses it doesn't need to change).
                              somethingBroadcaster.addListener(...);
                              }
                              

                              You could even go as far as use the globally defined broadcaster (if it exists) or create a local one if you want to modularize the codebase even further:

                              namespace Something
                              {
                                  const var someBroadcaster = isDefined(DataGlobal.someBroadcaster) ?
                                                                  DataGlobal.someBroadcaster : 
                                                                  Engine.createBroadcaster({});
                              }
                              
                              O d.healeyD 2 Replies Last reply Reply Quote 2
                              • O
                                Orvillain @Christoph Hart
                                last edited by

                                Just to sorta blunder in and ask possibly a stupid question... namespaces are just containers for related functions and variables right? You can't actually instance a namespace IE: use it as a kind of class ?

                                Christoph HartC clevername27C 2 Replies Last reply Reply Quote 0
                                • Christoph HartC
                                  Christoph Hart @Orvillain
                                  last edited by

                                  Link Preview Image
                                  HISE | Docs

                                  favicon

                                  (docs.hise.dev)

                                  O 1 Reply Last reply Reply Quote 1
                                  • O
                                    Orvillain @Christoph Hart
                                    last edited by

                                    @Christoph-Hart

                                    Right I see. So an Object Factory is what I would want if I wanted to create a class.

                                    Christoph HartC 1 Reply Last reply Reply Quote 0
                                    • Christoph HartC
                                      Christoph Hart @Orvillain
                                      last edited by

                                      @Orvillain not really. A object factory creates a data structure with a densely packed memory layout that can be used for a neat implementation of MIDI logic, but it lacks most of the features that you would expect from a object-oriented class object (like methods or polymorphism).

                                      What are you trying to achieve?

                                      O 1 Reply Last reply Reply Quote 1
                                      • O
                                        Orvillain @Christoph Hart
                                        last edited by Orvillain

                                        @Christoph-Hart said in Broadcasters best practices:

                                        @Orvillain not really. A object factory creates a data structure with a densely packed memory layout that can be used for a neat implementation of MIDI logic, but it lacks most of the features that you would expect from a object-oriented class object (like methods or polymorphism).

                                        What are you trying to achieve?

                                        I'm mainly pondering what would be the cleanest way to create an object prototype and then instantiate however many of them I'd like - and each instance automatically creates the relevant DSP nodes, UI widgets, and various methods and callbacks required.

                                        In Python you'd do something like:

                                        class WhateverTheClassIsCalled(inheritance here)
                                        
                                        def __init__(self, and then any initialisation arguments here)
                                            self.blah = blah
                                        
                                        def do_a_thing(self, blahblahblah)
                                           thing_is_done = blahblahblah(bloo bloo bloo)
                                            return thing_is_done
                                        
                                        
                                        for i in range(0, 32):
                                           instance_var = WhateverTheClassIsCalled(blahblahblah, bloloooooloooo)
                                        

                                        That sort of thing. In Python it is fairly trivial to put together a class this way, and tbh, syntax aside it looks like the Factory Object approach might do the same sort of thing???

                                        BTW - the above is probably the best code I've ever written. :face_with_tears_of_joy:

                                        1 Reply Last reply Reply Quote 0
                                        • clevername27C
                                          clevername27 @Orvillain
                                          last edited by

                                          @Orvillain One cool thing about namespaces is that each comes with 32 high-speed reg variables.

                                          Christoph HartC 1 Reply Last reply Reply Quote 1
                                          • Christoph HartC
                                            Christoph Hart @clevername27
                                            last edited by Christoph Hart

                                            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();
                                            
                                            O 2 Replies Last reply Reply Quote 1
                                            • First post
                                              Last post

                                            46

                                            Online

                                            1.7k

                                            Users

                                            11.7k

                                            Topics

                                            102.2k

                                            Posts