Updated JavaScript Live API Tutorials

Adam Murray's icon


About 10 years ago I wrote a series of tutorials that walked people through using the Live API with JavaScript. A lot of people gave me very positive feedback on this (it might be the most popular thing I ever published online), but a lot of the content had become obsolete by the time Live 11 launched because of deprecations in the Live API to facilitate MPE support. I've been meaning to update it for years, but my priorities were in a different place for a long time. Because the old content was obsolete, I didn't even maintain the old website and you can only find the old tutorials on the web archive these days.

That's a real a shame, so I'm very happy to announce the tutorials have been resurrected and updated for Live 12! (Technically Live 11 or higher)

https://adammurray.link/max-for-live/js-in-live/

Just in time to be obsoleted by Max 9 and v8 too... lmao, nooooo 😭
It's ok, I'm on top of v8. There's info about my plans at the link above. v8 is great and I'm looking forward to it as the future of JavaScript in Max and Max for Live.

I'm open to any constructive feedback. Find a typo? Something looks wonky in your browser? Think a section is not clear enough, or too ELI5 and verbose? Did you try to generate a clip 37-times-the-age-of-the-universe in duration in the final tutorial and it crashed your computer? Let me know here. I hope this will be a good resource for everyone for years to come (especially once I add v8 content) and I'm happy to keep refining it.

Joshua Kit Clayton's icon

Thank you for sharing this amazing work, Adam!

Julien Bayle's icon

Very nice Adam, food for my students too !

Jan Andersson's icon

Excellent. I have been meaning to thank you for a very long time - and your post offers an excellent opportunity for doing that, Your original tutorial series really got me into Max/MSP JS coding - and now I am enjoying it on a daily basis. Thanks a lot for your effort and good work!

Jan Andersson's icon

Just a thought. V8 seems much faster than the ES5 engine. Do you think it is more suitable for "real-time" applications?

Adam Murray's icon

V8 seems much faster than the ES5 engine. Do you think it is more suitable for "real-time" applications?

If you're talking about real time MIDI processing, sure. I talk about that in one of the new tutorials. The old js object is generally fine for that too. JavaScript is good for sequencing in real time.

If you're talking about directly implementing synths and effects, long story short: No, but not because of speed. I think it is "fast enough" now.

It's an interesting question. I expect the V8 JavaScript engine can generate or process numbers at typical sampling rates (e.g. 44.1kHz) without much problem these days. I never checked because nobody builds synthesizers or audio effects in JavaScript. That's because JavaScript is "not the right tool for the job". The reason why is a pretty complex topic that gets into how computers and CPUs work and the fundamental differences between programming languages like JavaScript vs C++. I am nowhere close to an expert on these topics but I can share some thoughts.

I'd say it boils down to: JavaScript abstracts away too much to be well-suited for DSP work. Two of the big issues I see are:

(1) JavaScript doesn't really have a type system and every number is the same underlying floating point type. This might be ok for experimentation, but I'd say in a "serious" DSP project, types matter and you want control over whether you are using 32-bit floats vs 64-bit floats, and I believe there are various specialized algorithms that work with integers. Or for performance, you might need to use a single byte character type (a char in C/C++), but in JavaScript, you can't because everything is a string. These are just a couple examples. You can't get enough control over how data and objects are represented in JavaScript.

(2) No control over memory management. In DSP, you might be operating on large buffers of audio, or need algorithms that very quickly and efficiently process single samples. The way you call into functions and pass data around matters. In C++ you have control over whether data in memory is copied or moved, for example, which has big implications for performance and is really important in realtime programming. In C++ you can decide exactly when memory is freed. In JavaScript the garbage collector is a black box and might decide to "do it's thing" and eat up precious CPU needed by your DSP algorithm at any random time. Again, you have no control over any of this stuff in JavaScript, and it's a problem because it matters in DSP and real time programming.

So is it possible? Sure? Is it a good idea? Beyond a "proof of concept" experiment, no, it doesn't really make sense because there are much better options available.

For people who like JavaScript in Max/Max for Live because it helps them build big complex projects that would be a struggle as a "pure patch", I highly recommend checking out gen~ and codebox. It's the perfect bridge for people comfy with text-based programming languages to get into DSP programming. If you need help getting started with gen~, I'd recommend the "Generating Sound & Organizing Time" book. It doesn't use codebox, but it walks you through learning gen~, and then you can use everything you learn in a codebox if you feel more comfortable doing things that way. v8, gen~, and codebox are a powerful combo for building synths and effects with text-based programming languages in Max for Live.

If you want to do DSP in web-based JavaScript projects, RNBO (which can contain gen~ and codebox) is a great option for building synths, sequencers, etc that can run in web browsers. Then you can do all the UI and state management logic in JavaScript (optionally inside a full-fledged web framework like React), which really feels like a "sweet spot" for web developers for bridging all these technologies. I want to share a lot more about that approach on my website at some point.

To sum all of that up: JavaScript has a place in real time audio (and visual) applications, but not at the low-level number crunching core of the DSP (or graphics code). It can do a lot at the layers above that though, especially anything near the GUI.

Iain Duncan's icon

JavaScript is certainly fast enough to do real-time MIDI calculations, but both the JS and V8 object only run in the low priority thread, so you will always get a) extra latency as your messages get queued between threads, and b) timing slop if you are doing anything else in the UI thread. It may not be enough to matter, but it can be significant and noticeable if you are doing a lot on the machine.

Adam, your tutorials are really nice written! But I would recommend adding that detail.

Adam Murray's icon

Iain Duncan Nov 11, 2024, 8:02 AM

JavaScript is certainly fast enough to do real-time MIDI calculations, but both the JS and V8 object only run in the low priority thread, so you will always get a) extra latency as your messages get queued between threads, and b) timing slop if you are doing anything else in the UI thread. It may not be enough to matter, but it can be significant and noticeable if you are doing a lot on the machine.

Adam, your tutorials are really nice written! But I would recommend adding that detail.

Thanks Iain, this is a really good thing to call out.

I need to expand on "Limitations" and get into this topic. I generally think JavaScript in Live can be good enough for real-time MIDI processing, especially on a new-ish machine (and especially with v8, but even the old js object is pretty capable). However, it is subjective, it depends on so many factors, and as you point out: it is ultimately not consistently reliable.

I should probably warn against its use for live performance situations, at least not without very thorough testing. And I wouldn't recommend attempting to make a commercial product with JS in Live that does real-time processing. I'd like to understand how JS in Live is impacted if my system is under load. Maybe I can push Max or the computer too hard and this will help me make better recommendations.

Anyway, I've been thinking an ideal use case for JavaScript in Live is implementing MIDI Generators and Transformers. I haven't spent much time doing this, so I haven't written about it yet. I want to dig into this. It will be a good article to add to this series one day. It could be the recommended area of focus for "serious" JS in Live projects.

Iain Duncan's icon

Yeah, I think it's really important, because we see a lot of misguided comments online saying that there is bad latency or timing in Max or Max for Live across the board. When in reality, they have made some mistake in the patch where they don't realize they have crossed a thread boundary one or more times, and if they hadn't, things would have been fine.

As part of building Scheme for Max, I have done (and still do) extensive timing and latency tests to figure out exactly what we can do with what, and I continually see people making comments on line about Max's timing and threading that are really easy to disprove with a test, but that keep circulating years and years after they have been fixed.

Adam Murray's icon

As part of building Scheme for Max, I have done (and still do) extensive timing and latency tests to figure out exactly what we can do with what, and I continually see people making comments on line about Max's timing and threading that are really easy to disprove with a test

Do you have any patches or more details you could share about this, to give me ideas about how to approach it?

Iain Duncan's icon

Hi Adam, I'd be happy to share. I'm (just beginning) writing an e-book+code project, and also planning to overhaul and update the s4m docs this year for new releases. My contact info is on my github page if you want to get in touch.

Adam Murray's icon

Cool, thanks. I want to follow up on testing approaches, and I plan to get in touch later. It might be a while because I have a lot of other priorities.

For now, I added some words to my website that gives people more warning on the low priority thread issues with JS in Live. Looking again, I feel I failed to mention a point about latency on switching between threads, so the problems get worse if you add a bunch of separate JS objects to the signal chain. I would generally recommend consolidating what you want to do into as few JS/V8 objects as possible. Ah well, there's always one more thing to say. Next time I'm in there, I'll mention something.

Iain Duncan's icon

No problem, I'm around and happy to help!