What's all this JIT stuff

  • I'm seeing this in the commits recently, is this related to C++ API or JS?

  • It's a big new feature that I am working on right now. Basically its a embedded C compiler that generates terribly fast machine code that can be used to write new DSP algorithms with almost native C++ speed. You can then call it from Javascript. This is the last missing piece to make the scripting environment really awesome 🙂

  • Oh 🙂 I see what you're doing. You're turning it up to 11!

  • Its about 95% faster than a Javascript loop so It's rather 11.5 🙂

  • Alright, I started to migrate this into HISE and it is real fun. I made some tests using a additive synthesizer with 6 harmonics and 6 low pass filters that smooth out the amplitudes.

    Check out the CPU usage of the three different engines (native C++, NativeJIT and Javascript):


    As you can see it's 17% JS vs 2,2% NativeJIT vs 0.9% C++. While it's not 100% there, it definitely allows writing DSP algorithms without compiling!

    The Javascript Code

    /** NativeJIT Example Script
    *    Drop this into a ScriptFX Processor and compare the performance between the different engines.
    *    The example algorithm is a additive sine wave generator with 6 sinewaves and simple LP smoothing
    *    of the amplitudes to reduce clicking.
    *    You can use the SliderPack to draw the harmonic structure and switch between the different engines
    *    (they should sound the same)
    // Loads the "Example.cpp" file in the script folder and creates a NativeJIT compiler called "Example"
    // Compile and create an object from the given source code 
    // The globals in the C code become local to this instance and you can access them via "c.global"
    const var c = Example.createModule();
    // Loads a compiled DSP module with the same functionality
    const var cppMod = Libraries.load("core").createModule("additive_synth");
    // The variables for the Javascript version
    reg b = Buffer.create(6);
    reg lastValues = Buffer.create(6);
    reg uptime = 0.0;
    reg uptimeDelta = 0.03;
    reg a = 0.999;
    reg invA = 1.0 - a;
    // GUI Stuff...
    const var SliderPack = Content.addSliderPack("SliderPack", 10, 10);
    // [JSON SliderPack]
    Content.setPropertiesFromJSON("SliderPack", {
      "width": 240,
      "sliderAmount": 6
    // [/JSON SliderPack]
    const var Engine = Content.addComboBox("Engine", 271, 9);
    // [JSON Engine]
    Content.setPropertiesFromJSON("Engine", {
      "items": "Off\nJavascript\nNativeJIT\nCompiled C++"
    // [/JSON Engine]
    function prepareToPlay(sampleRate, blockSize)
        // Needed for DSP Modules...
        cppMod.prepareToPlay(sampleRate, blockSize);
    function processBlock(channels)
        local e = Engine.getValue();
        if(e == 3)
            // Calling the c.processBlock method iterates the buffer
            // and calls the defined process(float input) function for
            // each sample
            channels[0] >> channels[1];
        else if (e == 2)
            // The same code in slow Javascript
            local a0, a1, a2, a3, a4, a5;
            local v0, v1, v2, v3, v4, v5;
            for(s in channels[0])
                a0 = (lastValues[0]*a + b[0]*invA);
                a1 = (lastValues[1]*a + b[1]*invA);
                a2 = (lastValues[2]*a + b[2]*invA);
                a3 = (lastValues[3]*a + b[3]*invA);
                a4 = (lastValues[4]*a + b[4]*invA);
                a5 = (lastValues[5]*a + b[5]*i);
                v0 = a0 * Math.sin(uptime);
                v1 = a1 * Math.sin(2.0*uptime);
                v2 = a2 * Math.sin(3.0*uptime);
                v3 = a3 * Math.sin(4.0*uptime);
                v4 = a4 * Math.sin(5.0*uptime);
                v5 = a5 * Math.sin(6.0*uptime);
                lastValues[0] = a0;
                lastValues[1] = a1;
                lastValues[2] = a2;
                lastValues[3] = a3;
                lastValues[4] = a4;
                lastValues[5] = a5;
                uptime += uptimeDelta;
                s = v0+v1+v2+v3+v4+v5;
            channels[0] >> channels[1];
        else if (e == 4)
            // give the native C++ module the buffer to calculate
    function onControl(number, value)
        if(number == SliderPack)
            // Set global values of NativeJIT modules directly
            // as if they were a Javascript Object!
            c.b[value] = SliderPack.getSliderValueAt(value);
            // Use the parameter API to set the overtones
            cppMod.setParameter(value, SliderPack.getSliderValueAt(value));
            // set the buffer value for the given overtone for JS
            b[value] = SliderPack.getSliderValueAt(value);

    The NativeJIT code

    This is how the NativeJIT code looks like. It's plain old C with the addition of the Buffer type.

    /** The NativeJIT code for the additive synthesiser. */
    double uptime = 0.0;
    double uptimeDelta = 0.03;
    // Buffer is a custom type which correlates to the Buffer type in Javascript
    // Treat them like a float array (there is a buffer overrun protection)
    Buffer b(6);
    Buffer lastValues(6);
    float a = 0.999f;
    float invA = 0.001f;
    float process(float input)
        const float uptimeFloat = (float)uptime;
        const float a0 = (lastValues[0]*a + b[0]*invA);
        const float a1 = (lastValues[1]*a + b[1]*invA);
        const float a2 = (lastValues[2]*a + b[2]*invA);
        const float a3 = (lastValues[3]*a + b[3]*invA);
        const float a4 = (lastValues[4]*a + b[4]*invA);
        const float a5 = (lastValues[5]*a + b[5]*invA);
        const float v0 = a0 * sinf(uptimeFloat);
        const float v1 = a1 * sinf(2.0f*uptimeFloat);
        const float v2 = a2 * sinf(3.0f*uptimeFloat);
        const float v3 = a3 * sinf(4.0f*uptimeFloat);
        const float v4 = a4 * sinf(5.0f*uptimeFloat);
        const float v5 = a5 * sinf(6.0f*uptimeFloat);
        lastValues[0] = a0;
        lastValues[1] = a1;
        lastValues[2] = a2;
        lastValues[3] = a3;
        lastValues[4] = a4;
        lastValues[5] = a5;
        uptime += uptimeDelta;
        return v0+v1+v2+v3+v4+v5;

    Note: This feature is not yet committed so you won't be able to check this out (I remove this hint when it's in the codebase).

  • Looks exciting, I'm going to have to relearn C 😛 so what sort of things will this be useful for?

  • You can use this to script custom modulators, effects or synths. It's a bit like Reapers JSFX but embedded into HISE (I have to make performance tests between those two).

    Especially the effect section in HISE is a bit underpopulated so this might come in handy there.

    I will be using it to prototype DSP modules which will then be hardcoded into HISE. There are yet some drawbacks (only x64 support, no "real" branching, no iOS support)

  • Aha now I get it!

Log in to reply