Supercharge HiseScript with SNEX



  • So... if you're following the development of HISE in the last year you probably know that I am working on a JIT compiler for scriptnode called SNEX. This will allow just in time compilation of DSP networks which will remove the necessity of "freezing" the nodes in order to get reasonable performance.

    However I just realised that having a JIT compiler in a typed language might also come in handy in other occasions and I've played around with how to integrate it into the interpreted HiseScript. The benefits of this are obvious:

    • ridiculous performance enhancement (between 10x and 200x faster code execution)
    • strict typing
    • a proper object-oriented class model including data encapsulation and constructors

    The idea is that you can write SNEX code just like HiseScript code and call JIT compiled functions directly in HiseScript with a syntax as lean as

    snex.struct MyStruct
    {
        // Enter the SNEX world
        MyStruct(int initValue)
        {
            dataValue = initValue;
        }
    
        // a method with a strictly typed prototype
        int getDoubleDataValue()
        {
            return dataValue * 2;
        }
    
    private:
        int dataValue = 90;
    };
    
    // create a MyStruct object
    const var obj = snex.make<MyStruct>(5);
    
    // create another object
    const var obj2 = snex.make<MyStruct>(15);
    
    var x = obj.dataValue; // undefined! dataValue is private
    
    var y = obj.getDoubleDataValue(); // call a SNEX method just like a normal function
    
    var z = obj2.getDoubleDataValue(); // 30
    

    An early performance test using the same operations show these results:

    snex.struct MyClass
    {
        // span<T, Size> is a fixed sized array
        span<float, 44100> data;
    
        void process()
        {
            // a range-based loop over the entire array
            // (the & means "reference to" so you operate directly on the array)
            for(auto& s: data)
                s = Math.max(s > 0.5 ? (Math.random() + Math.sin(s)) : 2.0f, 50.0f);
        }
    };
    
    var obj = snex.make<MyClass>();
    
    // Measure the SNEX performance
    Console.start();
    obj.process();
    Console.stop();
    // Benchmark Result: 0.289 ms
    
    const var l = [];
    
    for(i = 0; i < 44100; i++)
        l.push(i);
    
    // Now measure the same operation as interpreted HiseScript
    Console.start();
    for(s in l)
        s = Math.max(s > 0.5 ? (Math.random() + Math.sin(s)) : 2.0, 50);
    Console.stop(); 
    // Benchmark Result: 17.718 ms
    

    HiseScript still remains superior for any kind of data processing (there are no Strings in SNEX), but it might be a significant increase for every real-time event processing (plus you can use it to write DSP code)...

    It's still in a very experimental stage and I have yet to check how it works with real-world examples, but it's pretty nice having a super-fast-mode in the scripting toolbox πŸ™‚



  • 😱 πŸ‘¨β€πŸ‘¨



  • Looks interesting, will we have access to it from within the standard MIDI callbacks or will it live in its own processor module?



  • Yes, you can call it like any other function in your script. Maybe I'll add an option to autoforward the MIDI callbacks directly to a given SNEX class so it reduces the (small) overhead of calling into HiseScript altogether, but this works already:

    snex.struct MyProcessor
    {
        int isFastNote()
        {
            // A small selection of API calls will be available in SNEX
            double thisTime = Engine.getUptime();
            int isFastNote = (thisTime - lastTime) < 0.5;
            lastTime = thisTime;
            return isFastNote;
        }
    
        double lastTime = 0.0;
    };
    
    const var obj = snex.make<MyProcessor>();
    
    function onNoteOn()
    {
        if(obj.isFastNote())
            Console.print("Fast Note");
    }
    


  • @Christoph-Hart said in Supercharge HiseScript with SNEX:

    snex.struct MyClass
    {
        // span<T, Size> is a fixed sized array
        span<float, 44100> data;
    
        void process()
        {
            // a range-based loop over the entire array
            // (the & means "reference to" so you operate directly on the array)
            for(auto& s: data)
                s = Math.max(s > 0.5 ? (Math.random() + Math.sin(s)) : 2.0f, 50.0f);
        }
    };
    

    So this is saturation by iterating over the 44100 sample buffer? I take it this does nothing to the audio until you call obj.process()?

    Either way DSP like this is 😍



  • Sounds great πŸ‘ πŸ‘ πŸ‘Œ



  • @iamlamprey said in Supercharge HiseScript with SNEX:

    So this is saturation by iterating over the 44100 sample buffer? I take it this does nothing to the audio until you call obj.process()?

    Either way DSP like this is 😍

    Oops I think it's actually just a random number generator for performance comparison.

    How would we apply an algo to a sample/block/buffer with this? AKA teach me how to DSP so I can forever leave JUCE in my rearview πŸ˜‚



  • So cool! Can’t wait to try it πŸ€“



  • @Christoph-Hart Anxious to to get this working, but it does not compiles on Mac 😞

    snex_ArrayTypes.h

    Screen Shot 2020-12-07 at 11.31.00 AM.png



  • Yeah itβ€˜s not commited yet, so you need a bit more patients (sooooon πŸ˜‰



  • @Christoph-Hart ok, just copy paste this

    git add .
    git commit -m "other DSP dev frameworks are death"
    git push


Log in to reply
 

17
Online

1.1k
Users

3.8k
Topics

33.3k
Posts