My weekend hack: Write VST plugins in JavaScript

DSP, Plugin and Host development discussion.
RELATED
PRODUCTS

Post

AUTO-ADMIN: Non-MP3, WAV, OGG, SoundCloud, YouTube, Vimeo, Twitter and Facebook links in this post have been protected automatically. Once the member reaches 5 posts the links will function as normal.
Hi guys, this is something I put together over the long weekend - would love to hear any and all feedback! Right now it will create a universal OS X VST for you, but I think expanding to Windows wouldn't be too much harder, so I'll be doing that soon. Feel free to play with it as much as you like!

Here's the site: http://boomsk.com/ (http://boomsk.com/)

And here are a few more examples: http://boomsk.com/examples.html (http://boomsk.com/examples.html)

Cheers,
Bill.

Post

I'm on Windows only, so I can't try it, but out of curiousity, are you using some stock javascript engine or did you write your own? I assume you do end up with native code, right?

Post

Cool,i was just looking for a plugin that works in a similar fashion written in Java just yesterday but couldn't find it.I had an idea i quickly wanted to try.
Now i don't have a Mac so i'm looking forward to the Windows version. Thanks.

Post

Great idea! Nice for people who don't know C++ and just need some quick effect.

I noticed that the delay (the example code) uses quite a lot of CPU, considering how little it does...I'm not complaining, it's just something you might want to look into :wink:

Post

If you look at the JavaScript code, you'll notice that it works on a per-sample base. Also readHead is completely recalculated once for each sample frame.

Regardless of whether it's based on a JITC JavaScript implementation, this is damned inefficient.
"Until you spread your wings, you'll have no idea how far you can walk." Image

Post

For a task like realtime audio processing, one is normally concerned about things like running into denormals as a result of calculations which may cause abrupt inefficiencies that cause small glitches that are nevertheless audible (few other developers usually even heard of such problems), the idea of using a garbage collecting language that isn't even compiled sounds like a strange taste of intellectual curiosity. I guess this is one of "I did it because I can" kind of things.

On the other hand, if this has emerged from a real need, perhaps of quick prototyping, check out "Faust" http://en.wikipedia.org/wiki/FAUST_(pro ... _language)

Looks like it would take some time to learn though, so I'm not sure that's a very good idea either. Your prototype may take less time to finish in c++.
~stratum~

Post

stratum wrote:I guess this is one of "I did it because I can" kind of things.
I think that was implied by abstractbill when he said he threw it together over a long weekend. It's what it is, and if it works (I haven't tried it yet) that's cool!

I think an actual C compiler would make more sense though. (If you can understand enough JavaScript to code an effect, you can certainly understand enough C!) And I think it actually should call the process on a per-sample basis. The sample loop can be done by the framework, as it's the same every time. I also think 1 sample frame sized buffers are going to be very common in near future DAWs.

Post

I think that was implied by abstractbill when he said he threw it together over a long weekend. It's what it is, and if it works (I haven't tried it yet) that's cool!
I used to have such weekends. Nowadays I prefer going to somewhere outdoors with an old 4x4 (old ones are cheap). Long trips in nature are pretty cool and relaxing.. it even gives you some silent time to think about life in general and what you want to do. A friend of mine used to say swimming is similar.

Anyway.. javascript is cool and I guess it's easy compared to reading papers, and that may also be a relaxing hobby.
~stratum~

Post

Thanks for the feedback everyone!

I'll see what I can do about getting a Windows version up soon. Hopefully it won't take too long.

The JavaScript engine is Spidermonkey (from Mozilla). It's a decent JIT - actually faster than both V8 and JavaScriptCore in the testing I did a while back. So yeah, it *is* compiled, and we do wind up with native code in the end, strictly speaking ;) I'm actually not *too* worried about efficiency - as AdmiralQuality pointed out, the framework could easily pull out your code from the function and do the loop automatically for you (it doesn't right now, but it would be really easy).

Anyway, yeah it was a weekend hack mostly, but I'm not sure it's a complete dead-end just yet. I'm going to keep going with it and see if I can't make it into something useful. JavaScript seems like a good choice to me, because:

- Using JS means we could audition your effect in the web browser itself, making the development cycle a lot faster
- There are many more JavaScript than c++ programmers
- People are working hard on making JS engines more efficient

Please keep the feedback coming if you have more, it's great to have some thoughtful replies to my post!

Thanks,
Bill.

Post

AdmiralQuality wrote:And I think it actually should call the process on a per-sample basis. The sample loop can be done by the framework, as it's the same every time. I also think 1 sample frame sized buffers are going to be very common in near future DAWs.
Agreed, but still... things that only change whenever a parameter changes (such as the offset between the buffer read and write pointers in a delay) should not be recalculated upon each sample. Look at the current JavaScript sample code from the web site:

Code: Select all

var bufferLen = 5 * 96000;  // a reasonable maximum
var leftBuffer = new Float64Array(bufferLen);
var rightBuffer = new Float64Array(bufferLen);
var writeHead = 0;

function processAudio(input, output, params) {
    leftBuffer[writeHead % bufferLen] = input[left];
    rightBuffer[writeHead % bufferLen] = input[right];
    var readHead = ((Math.round(writeHead - (params.delay * params.sampleRate))) + bufferLen) % bufferLen;
    output[left] = input[left] * (1 - params.wet) + leftBuffer[readHead] * params.wet;
    output[right] = input[right] * (1 - params.wet) + rightBuffer[readHead] * params.wet;
    writeHead++;
}
readHead is a local variable that's recalculated each time, although it should be easy to move it into a global variable (like writeHead), simply increment it like writeHead in processAudio(), and only recalculate the difference to writeHead whenever one of the parameters changes. This, of course, would require either a costly "if delay or sampleRate changed, recalculate difference", which would defeat the purpose of saving CPU cycles, or another exposed function like setParameter() in which the new offset would be calculated (much better solution).

Other areas that might benefit of a little redesign, depending on the JIT compilers' capabilities:

.) "writeHead % bufferLen" is calculated twice for no reason;
should be done at the bottom as "writehead = (writeHead + 1) % bufferLen;"
Depending on how clever the JIT compiler is, this might save some CPU cycles.

.) input[left], input[right], params.wet could be read into local variables at the start of the function so that they don't need to be fetched twice. OTOH, this might be bad because of the garbage collector; I don't know...


Oh, and one more remark that I just can't keep to myself...
abstractbill wrote:- There are many more JavaScript than c++ programmers
That may be the case, but doesn't make JavaScript a good language for realtime audio processing.
MIDI processing, for example, would be a better area to show its strengths.
"Until you spread your wings, you'll have no idea how far you can walk." Image

Post

arakula wrote:.) "writeHead % bufferLen" is calculated twice for no reason;
should be done at the bottom as "writehead = (writeHead + 1) % bufferLen;"
Depending on how clever the JIT compiler is, this might save some CPU cycles.
I'd never ever rely on the optimizations supposedly done by a compiler. I'm a strong supporter of making code as efficient as humanly possible.
abstractbill wrote:- There are many more JavaScript than c++ programmers
Really?? That's a scary development... Would you know of any published figures to support that statement?
We are the KVR collective. Resistance is futile. You will be assimilated. Image
My MusicCalc is served over https!!

Post

Really?? That's a scary development... Would you know of any published figures to support that statement?
C++ is notorious for things that it never deserved to be criticized about, so I'm not surprized that such a comment may be made without any published figures.
The only thing I dislike about C++ is that code completion software never seems to work right for c++. Intellisense, Visualassist, etc all are crap compared to the way visual studio works with C#, but with C++ it leaves a lot to be desired. Other IDE's are not different, often worse. Returning back to the comment about that there are more javascript programmers than there are c++ programmers, it may be true or false, but in the end it doesn't matter. For example I know c++ but that doesn't mean I have a very cool idea about a vst plugin that will shake the market.:)
~stratum~

Post

Actually... I wouldn't want to use JavaScript for the dsp part, but for the UI, it would definitely make sense to follow what's being done in the gaming industry, and use a scripting engine for all non-realtime code. Given that a plugin consists of 80%-90% UI code, this could be a real time saver.

Post

Heh, yeah forget what I said about there being more JS programmers - I have no data to back it up, it's only a hunch. The more interesting observation might be that the *overlap* between c++ and JavaScript programmers is likely to be quite small, and my idea is to open up plugin development to people who haven't been able to do it before. With that in mind, the JavaScript code is written to be readable first and foremost, with all considerations of efficiency quite firmly punted ;)

Having said that, I just loaded up a couple of dozen instances of the basic echo plugin into Ableton on my puny little macbook air. They all run at the same time, with the cpu still at under 50% and without any artifacts that I can hear. Although the code is written to be readable, there's nothing in it that should cause GC to happen - the SpiderMonkey JIT represents numbers as doubles, and Float64Arrays as very lightweight wrappers around arrays of doubles.

Big Tick, yes I've definitely been thinking along these lines too :)

Post

At the rate javascript is going, if there aren't already many more JS programmers than C++ programmers there surely soon will be.

But I agree that doing DSP in JS just doesn't make that much sense. There is already such a glut of plugins on the market that nobody is going to use anything that's 10x slower than a similar C++ implementation.

However, doing UI with JS does make sense. You could also build your core DSP components in C++ and then expose a JS interface that lets you assemble them into processing graphs, sorta like Max/MSP but with a textual programming language. In fact, IIRC you can do this in Max with JS already.

Post Reply

Return to “DSP and Plugin Development”