HISE Logo Forum
    • Categories
    • Register
    • Login

    FR: Global variables scripting API

    Scheduled Pinned Locked Moved Feature Requests
    16 Posts 3 Posters 2.8k 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.
    • Christoph HartC
      Christoph Hart
      last edited by

      @1g2fhobs:

      Would you be able to have global functions as well?

      Well, anything that can be saved in a var on the script side will be saved as global variable engine-wide, so theoretically functions will work too. But I can imagine it will get messy quite quickly (What if you call a function that references a variable from another script and the script was deleted?).

      1 Reply Last reply Reply Quote 0
      • E
        elanhickler
        last edited by

        If a function references a variable from a script that was deleted, then surely you just throw an error "variable is undefined"

        What would the code look like to create a global function, is it like this?

        function myGlobalFunction (a,b) { return a * b; }
        Engine.setGlobal("myGlobalFunction", myGlobalFunction);
        
        myLocalFunction = Engine.getGlobal("myGlobalFunction");
        
        var multiplied = myLocalFunction(3,2);
        
        

        Seems like includes would be better for this.

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

          So, I implemented this and how I expected, the function storage comes with some quirks. Consider this example:

          Script 1:

          var faultyVariable = 25;
          
          var x = function()
          {
          	Console.print(faultyVariable);
          };
          
          Engine.setGlobal(0, x);
          
          

          Script 2:

          var x = Engine.getGlobal(0);
          
          x();
          

          The console output is undefined. This is because the function uses a variable defined in Script 1, but not in Script 2. If I however, add

          var faultyVariable = 27;
          

          in the second script (before the function call of course), it will print this value (so the global function looks in the local scope). This can lead to pretty unpredictable behaviour where functions do work in one script but not in the next, so I would suggest removing function storage from the global variable container.

          Also, the variables are clones before they are saved into the global container. This is needed because if you create an array, save it as global and then delete the script processor, the array contains dangling pointers to deleted elements and this will result in a crash.
          There are a few drawbacks because of this:

          • interface objects can't be stored (and controlled from another script, but there is the API call Synth.setParameter() for this functionality.
          • saving an array is slower because it has to be duplicated - but I strongly recommend not saving an array in one of the time critical callbacks anyway…
          1 Reply Last reply Reply Quote 0
          • E
            elanhickler
            last edited by

            referring to globals by number is going to be difficult for large projects.

            the coder will have to create include variables to refer to global numbers

            include:

            mynamespace.ColorEnum = {
                myGlobal : 0,
                myOtherGlobal : 1,
                anotherGlobal: 2
            }
            
            

            first script processor:

            include("theAbove.js");
            Engine.setGlobal(mynamespace.myGlobal, a * b + c / e - f );
            
            

            another script processor:

            include("theAbove.js");
            var output = Engine.getGlobal(mynamespace.myGlobal, a * b + c / e - f );
            
            

            Seems like a lot to do a simple thing. I think a use-case for global variables would be when you want to take a knob value and do a calculation ONCE, and send that calculation to other knobs or values/parameters in other scripts.

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

              @3kbojkje:

              If a function references a variable from a script that was deleted, then surely you just throw an error "variable is undefined"

              This is the default behaviour - a crash only occures when storing an interface widget as global variable and then deleting the script.
              However this really leads to unpredictable mess behaviour and would be a cause of many irritations and bugs. Consider this example:

              var velocity = 0;
              
              var calculateStuff = function()
              {
                  Synth.setParameter(12, velocity);
              }
              
              function onNoteOn()
              {
                  velocity = Message.getVelocity();
              }
              
              

              You can't use this function in another script without knowing that it needs a variable called 'velocity' and the variable needs to be updated every noteOn. This is a heavy violation of the encapsulation principle that is the main reason for functions.

              @3kbojkje:

              Seems like includes would be better for this.

              Yes indeed. I think limiting global variables to values and arrays only is the least complicated thing to do.

              About the index vs named identifier stuff for global access, I will make some performance tests, but the snippet you wrote does not look too complicated to me (especially in combination with the include functionality). But I think you have the syntax wrong. This example works:

              // This stuff can be outsourced to an external enum file
              var globals = {};
              globals.BUTTON_VALUE = 4;
              
              Engine.setGlobal(globals.BUTTON_VALUE, 55);
              Engine.getGlobal(globals.BUTTON_VALUE);
              
              
              1 Reply Last reply Reply Quote 0
              • E
                elanhickler
                last edited by

                the include file:
                Edit: So this would all be built into the API. In this case, the developer only has to do the globals.BUTTON_VALUE part. –>

                function global(arguments) 
                {
                    if (arguments.length == 1) Engine.getGlobal(arguments[0]);
                    else Engine.setGlobal(arguments[0],arguments[1]);
                };
                var globals = {};
                globals.BUTTON_VALUE = 4;
                
                
                // get
                var local_button_value = global(BUTTON_VALUE);
                
                // set
                global(BUTTON_VALUE, some_formula);
                
                

                Is there any (feasible) way you can make Engine.SetGlobal() and Engine.GetGlobal() something that happens in the background so the developer can just focus on referring to global variables by their variable name? The above code is my attempt to do that.

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

                  OK I added another way of handling global variables:

                  Globals.x = 5;
                  
                  Console.print(Globals.x); // 5 in every script
                  
                  

                  It can't be simpler than that. 'Globals' is a object that is hold by the engine and their properties ( = every variable that is stored in it) are reference counted. You can use this system like normal variables (so everything from functions to objects and script interface widgets can be stored here. However because it uses reference counting, deleting a script processor with widget saved into the global storage does not delete the widget (not until the global property is overwritten or cleared).

                  But as always: with great power comes great responsibility (it is a little bit like the getter/setter paradigm vs. direct access). I think I keep both styles for now (the overhead is negible) and everybody can use the system he prefers.

                  1 Reply Last reply Reply Quote 0
                  • E
                    elanhickler
                    last edited by

                    sweet, perfect!

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

                      And I added Autocomplete support for this style. Pressing Escape shows "Globals" under the API classes and if you press Escape again, you'll see all global properties with their current value (just like the local properties).

                      Also the variables are shown in the variable watch window (with the prefix 'Globals.')

                      Kind of starting to like this too :)

                      1 Reply Last reply Reply Quote 0
                      • E
                        elanhickler
                        last edited by

                        :o :D

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

                        42

                        Online

                        1.7k

                        Users

                        11.7k

                        Topics

                        101.9k

                        Posts