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 :)
-
:couple_with_heart_man_man:
-
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
-
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