Pro Tip : Javascript main() initialize section

Posted by DusX on 7 May 2015 | Comments

Tags: , , , ,

What this blog post shows you is how to create a Initialization within a Javascript actor in Isadora. By re-defining the Main function within the Main function. I also include a nice little method of adding simple debugging within your JS code inside Isadora.

** Although this method offers a clean way of defining variables outside the main() function. It is often easiest to define variables in the outer most scope to treat them as Global. EG: "myGlobal = 6;" as the very first line of code (outside any functions) would set a global called myGlobal equal to 6.

So, during the early development of Isadora version 2, the new Javascript functionality was added.
At this time... I wanted a way to test the speed of Javascript in Isadora compared to the speed of other native C++ actors.
The solution chosen was to recreate the functionality of the 'Smoother' actor in Javascript.
Here is the code I used:

function debug(printString){
    if (DebugMode){
        print(printString + "\n");  //requires newline to be inserted
    }
}

function main(){
    // DO setup here ***********************************************************
    DebugMode = false;
    var lastInputValue; // last received at input
    var smoothingConstant; // float 0.0 -> 1.0 represents smoothness

    var feedbackTriger = arguments[3];

    var state = 0;

    var lastOutputValue; // last sent value
    var newValue; // used to calc new smooth value
    var LastTime = new Date();

    lastInputValue = arguments[0];  // first input must be the value in.
    smoothingConstant = arguments[1];  // second input must be 0->1.0

    //main function for loop ***********************************************************
    main = function(){
        lastInputValue = arguments[0];  // first input must be the value in.
        smoothingConstant = arguments[1];  // second input must be 0->1.0
        var pulse = 1000 / arguments[2]; // sent in HZ converted to MS

        // check time
        var NewTime = new Date();
        debug("Diff val= " + (NewTime.getTime() - LastTime.getTime()) + " pulse= " + pulse +"\n\n\n");

        if ((NewTime.getTime() - LastTime.getTime()) > pulse){
            newValue = ((lastInputValue - lastOutputValue) * smoothingConstant) + lastOutputValue;
            LastTime = new Date();

            debug("INSIDE AND RUNNING \n");

            var tempdiff = Math.abs(lastInputValue - lastOutputValue);
            //  debug("diff = " + tempdiff + "\n\n\n");

            if (tempdiff > 0.00005){  // if (newValue != lastOutputValue){
                // debug("State val= 0 \n");
                state = 0;
                lastOutputValue = newValue;
                out = [newValue, state]
                return newValue;
            }else{
                if (state == 0){ // make this happen once
                    // since diff is low.. set to final value eg: input val
                    lastOutputValue = lastInputValue;
                    state = 100;
                    out = [lastInputValue, state]
                    return out;
                }
            }
        }
    };

    lastOutputValue = lastInputValue;
    var out = lastOutputValue;
    return out; // return from INIT state
};

 

The first thing you see is a little extra... the 'debug' function definition, this little function allows you to add a simple function call to your script anytime you want to output some text for debugging. It also includes a quick test to determine if debugging is 'ON'.  The main() function starts with a Local Variable that defines the 'DebugMode', simply true or false. Later in the code you can see calls to debug(); that pass some constructed string to the function.
There print() outputs the string to be viewed in the 'Monitor' (Windows/Show Monitor) in Isadora. Dead simple debugging, simply add you debug messages in this way as you build your Javascript functionality and set the DebugMode to false when you no longer need the output in Monitor. Of course you can just use print() anywhere in your code rather if you prefer.. although you can't turn it off ;)

DXjs smooth1OK.. that hopefully is useful to a few of you... it wasn't meant for this post... but its in the code so I thought I would quickly cover it.


NOW, the main() function.

Hopefully my code comments make this clear, but what happens here is that within Isadora on enterscene (assuming the actor gets input on enter scene, otherwise on the first input received by the Javascript actor) the main() function is called.
First thing is setting the DebugMode variable, and the code continues thru to set a number of local variables.
Next you will see a local variable named 'main' being set to a function definition ?
What is happening is that we are re-assigning the main() function call to this new function. But we don't call it yet.
After setting main to the function, we continue with some code that finally outputs a value from the Javascript actor.

Now that main() has been redefined, when the next input arrives (in the case of this code, arguments[3] is a trigger.. this is another little trick for another time) the new main() function is called. Only the code inside the new function is run.. the setup code at the beginning and the bit at the end are not run again.
This is great, it allows you to write an Initialization section within your actors code that will be run the first time the actor processes the code.
There may be other ways to use Javascript closures to accomplish the same and/or other effects, but this simple structure has worked for nearly all my Javascript actors so far.

I hope that was helpful.

PS: the Javascript Code in Isadora runs FAST.

But not as fast as the native C++ code....
however you would need to add hundreds of running copies of this actor to a patch to see Javascript cause a slow down.