HISE Logo Forum
    • Categories
    • Register
    • Login

    Broadcaster attachment design pattern

    Scheduled Pinned Locked Moved General Questions
    25 Posts 3 Posters 255 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.
    • OrvillainO
      Orvillain @d.healey
      last edited by Orvillain

      What I've got is working perfectly. I just think the code is a bit messy. It isn't just for envelopes, no. I'm doing the same pattern for a whole variety of areas in my synth.

      But the one example is:

          inline function addEngineAmpEnvListeners()
          {
              SharedData.broadcasters["Engine1AHDSRControl"].addListener("string", "metadata", function(param, value)
              {
                  BroadcasterCallbacks.controlLinkedAmpEnvParameter("Engine1", param, value);
              });
      
              SharedData.broadcasters["Engine2AHDSRControl"].addListener("string", "metadata", function(param, value)
              {
                  BroadcasterCallbacks.controlLinkedAmpEnvParameter("Engine2", param, value);
              });
      
              SharedData.broadcasters["Engine3AHDSRControl"].addListener("string", "metadata", function(param, value)
              {
                  BroadcasterCallbacks.controlLinkedAmpEnvParameter("Engine3", param, value);
              });
          }
      

      And the callback I'm attaching to this is:

      	inline function controlLinkedAmpEnvParameter(engineName, param, value)
      	{
      		local paramMap = {
      			"Monophonic": 0,
      			"Retrigger": 1,
      			"Attack": 2,
      			"AttackLevel": 3,
      			"Hold": 4,
      			"Decay": 5,
      			"Sustain": 6,
      			"Release": 7,
      			"AttackCurve": 8,
      			"DecayCurve": 9,
      			"EcoMode": 10,
      		};
      
      		local engine = SharedData.engines[engineName];
      		
      		for (mode in SharedData.modeMap)
      		{
      			local modeData = engine["modes"][mode];
      
      			local parts = param.getId().split("_");
      			local paramName = parts[parts.length - 1];
      			local target = modeData["ahdsrEnvObj"];
      			target.setAttribute(paramMap[paramName], value);
      		}
      	}
      

      It works splendidly. I just don't like that initial bit of code, because I'm repeating myself and specifying a different engine name each time.

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

        @Orvillain said in Broadcaster attachment design pattern:

        What I've got is working perfectly.

        Have you tested it in a compiled project?

        The way I handle this kind of thing is to make a controller script. Then I just connect the knobs to the controller using processor/parameter ID.

        Here's an example of an AHDSR controller that will work for any number of envelopes, you can add/remove envelopes and no change to the script is required, it's completely self contained.

        It avoids that repetition you've ran into and can be reused in many projects.

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

        OrvillainO 2 Replies Last reply Reply Quote 0
        • OrvillainO
          Orvillain @d.healey
          last edited by

          @d-healey said in Broadcaster attachment design pattern:

          Have you tested it in a compiled project?

          Yes. Works fine!

          1 Reply Last reply Reply Quote 0
          • OrvillainO
            Orvillain @d.healey
            last edited by Orvillain

            @d-healey said in Broadcaster attachment design pattern:

            The way I handle this kind of thing is to make a controller script. Then I just connect the knobs to the controller using processor/parameter ID.

            Here's an example of an AHDSR controller that will work for any number of envelopes, you can add/remove envelopes and no change to the script is required, it's completely self contained.

            It avoids that repetition you've ran into and can be reused in many projects.

            Without bludgeoning you with loads of code, it is hard to explain. But I'm essentially dynamically creating parameter groups based on their names. Then I create a broadcaster for each group. Then I attach the broadcaster to each parameter based on the broadcaster type that is desired, then I am adding the listener callbacks to the broadcaster.

            It is all very cool and modular. I just don't like this particular 3-engine manual duplicate approach, because if I want to move to 5 engines, then I need to do a bunch of manual work.

            I was hoping for a design pattern where I could call the right number of addListener commands, against the right number of broadcaster or parameter groups. I can't just run a loop and use local variables, because local variables aren't allowed in inline functions in this manner.

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

              @Orvillain Engine1AHDSRControl These are referring to AHDSR envelopes?

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

              OrvillainO 1 Reply Last reply Reply Quote 0
              • OrvillainO
                Orvillain @d.healey
                last edited by Orvillain

                @d-healey said in Broadcaster attachment design pattern:

                @Orvillain Engine1AHDSRControl These are referring to AHDSR envelopes?

                No, it refers to a broadcaster ID created in a previous step.

                I'm not going to post everything I'm doing, but imagine it more like this:

                    inline function addEngineLinkedFeatureListeners()
                    {
                        SharedData.broadcasters["ENGINE-NAME-HERE-FEATUREHERE"].addListener("string", "metadata", function(param, value)
                        {
                            BroadcasterCallbacks.controlLinkedFEATUREParameter(ENGINE-NAME-HERE, param, value);
                        });
                    }
                

                I want to do the above, where the engine name or identifier increments. But I can't do that with a for loop, because it complains about it not liking local variables.

                Engine1AHDSRControl is a broadcaster id. and depending on the number of engines, I automatically create these. So for 3 engines I get:

                Engine1AHDSRControl
                Engine2AHDSRControl
                Engine3AHDSRControl

                And if I change the number of engines, my code will dynamically create the right amount of parameters, the right amount of broadcasters, and the right amount of parameter/component groups, and then it will attach the correct broadcaster to the correct component group.

                Next step is to add the listener to the broadcaster, in a dynamic way.

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

                  @Orvillain This error?

                  Interface:! Engine3AHDSRControl: BroadcastersBuilder.js (291): Illegal iterator target

                  The error is being triggered only for Engine3 so that implies the for loop in general is fine, but there is a more specific issue.

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

                  OrvillainO 1 Reply Last reply Reply Quote 0
                  • OrvillainO
                    Orvillain @d.healey
                    last edited by

                    @d-healey Yeah, there's some underlying closure thing going on I think.

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

                      @Orvillain

                      for (engine in engines)
                      {
                          local capturedEngine = engine;
                      
                          Globals.broadcasters[engine + "AHDSRControl"].addListener("string", "metadata", function(param, value)
                          {
                              BroadcasterCallbacks.controlLinkedAmpEnvParameter(capturedEngine, param, value);
                          });
                      }
                      

                      Oh I just realised the issue - the function within your loop doesn't have access to local variables outside of the function. So you'll need to find another structure.

                      One workaround is to use a lambda variable, I try to avoid this because I find their use usually indicates a structural issue. But it's a quick and dirty fix.

                      function[capturedEngine](param, value)

                      Another suggestion is instead of using an array of strings and a for in loop. Just use a for loop that counts from 0 to the number of engines you have. Then you can just declare a NUM_ENGINES constant at the top of your script and use it whenever you need to know the number of engine you have.

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

                      OrvillainO 1 Reply Last reply Reply Quote 0
                      • OrvillainO
                        Orvillain @d.healey
                        last edited by

                        @d-healey said in Broadcaster attachment design pattern:

                        Another suggestion is instead of using an array of strings and a for in loop. Just use a for loop that counts from 0 to the number of engines you have. Then you can just declare a NUM_ENGINES constant at the top of your script and use it whenever you need to know the number of engine you have.

                        If I try that, for example (different feature area this time):

                        		for (i = 1; i < SharedData.engines.length; i++)
                                {
                                    SharedData.broadcasters["Engine" + i + "ModeControl"].addListener("string", "metadata", function(index)
                        		{
                        			BroadcasterCallbacks.setActiveModeForSlot("Engine" + i, index);
                        		});
                                }
                        

                        Then I get:

                        Interface:! BroadcastersBuilder.js (260): Can't reference local variables in nested function body {{SW50ZXJmYWNlfEJyb2FkY2FzdGVyc0J1aWxkZXIuanN8ODQ3MHwyNjB8NTc=}}
                        
                        
                        d.healeyD 1 Reply Last reply Reply Quote 0
                        • d.healeyD
                          d.healey @Orvillain
                          last edited by

                          @Orvillain The error is basically saying what I said.

                          You can't access a local variable declared outside of the function.

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

                          OrvillainO 1 Reply Last reply Reply Quote 0
                          • OrvillainO
                            Orvillain @d.healey
                            last edited by

                            @d-healey Indeed, indeed.

                            		for (engine in SharedData.engines)
                                    {
                                        local capturedEngine = engine;
                                        SharedData.broadcasters[capturedEngine + "ModeControl"].addListener("string", "metadata", function[capturedEngine](index)
                            		{
                            			BroadcasterCallbacks.setActiveModeForSlot(capturedEngine, index);
                            		});
                                    }
                            

                            This did seem to work however.

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

                              @Orvillain Yep that will do it, it's not the most elegant solution but that's what it's designed for.

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

                              OrvillainO 1 Reply Last reply Reply Quote 1
                              • OrvillainO
                                Orvillain @d.healey
                                last edited by

                                @d-healey More elegant than what I have right now I am thinking!

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

                                  @Orvillain Yep it will certainly help reduce that repetition

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

                                  OrvillainO 1 Reply Last reply Reply Quote 0
                                  • OrvillainO
                                    Orvillain @d.healey
                                    last edited by

                                    @d-healey Yeah, I think I can essentially boil down 11 functions down to 3 functions with this. Pretty cool, cheers!

                                    1 Reply Last reply Reply Quote 1
                                    • First post
                                      Last post

                                    21

                                    Online

                                    1.8k

                                    Users

                                    12.1k

                                    Topics

                                    105.5k

                                    Posts