Suggestion: rewrite file format handlers in Rust
See original GitHub issueHi @jhalme, first I want to say thank you for an incredibly nice little thing here. 😄 And thanks for making it FOSS!
I guess I’m feeling a bit nostalgic right now, recorded an .avi
of an old MSDOS intro I made 20 years ago and put up on YouTube the other day. And now I’m looking into making a web port of this intro, just for the sake of it…
I integrated the player in my web app quite easily, using this code (documenting this since it might help others who also want to integrate the player into their intros/whatever). Only the files below are needed if you don’t want the UI; no jQuery etc is necessary.
<script src="webaudio-mod-player/utils.js" type="text/javascript"></script>
<script src="webaudio-mod-player/player.js" type="text/javascript"></script>
<script src="webaudio-mod-player/pt.js" type="text/javascript"></script>
And then in a button event handler I kick it live like this:
window.module = new Modplayer();
window.module.setrepeat(true);
// Because the file gets loaded asynchronously, we need to wait until it's ready before we
// start playing the mod file.
window.module.onReady = () => {
window.module.play();
// ...start my animation etc, which is handled by some Rust code.
}
window.module.load("music.mod");
This all works quite well, and the performance is satisfying (only tested on Chrome on desktop yet.) With the https://mod.haxor.fi/ player, I noted some files (probably more complex ones) were stuttering when I played them on my iPhone - like you write on the web page, the Javascript runtimes can very greatly in speed.
I think we should consider rewriting the inner loops here in Rust, targetting WebAssembly. As you probably already know, webassembly is supported in all the bigger browsers these days and it’s providing a lot better performance than JavaScript will ever be able to deliver, because of its compiled and statically typed nature.
So, I think we should think about this. Maybe this is something you have already thought about? Or what do you think? This demo from hellorust.com is what inspired me to start playing around a bit with WebAssembly and Rust, and it’s actually really fun and works well. You have to use a nightly Rust compiler at the moment (webassembly is not supported by the stable releases yet) but apart from that, it works pretty much flawlessly and provides a really nice & capable platform for “low-level web stuff” - which .mod
playing happens to be.
If you have a particular file handler (S3M? XM?) that is more performance-demanding than the others, this could perhaps be a suitable candidate for trying this idea out.
All in all, thanks for a great tool now already! 👍
Issue Analytics
- State:
- Created 6 years ago
- Reactions:1
- Comments:6 (2 by maintainers)
Top GitHub Comments
Hello, and thank you for the kind words - I really appreciate it! 😃
I am aware of the performance issue, and it actually seems be more frequent on desktop Chrome in comparison to macOS Safari or Firefox Quantum. Some XM modules with a large number of channels are especially prone to it, although the stuttering seems to always occur at particular positions in the song. As you also mentioned, I think that it is due to the heavy inner loop in the software mixing and interpolation code. It becomes even more apparent when switching the audio output sample rate from 44/48kHz to 96kHz.
Currently, Firefox seems to be the browser least affected by the issue. It seems that different browsers might have different priorities for the thread running Web Audio ScriptProcessorNode.onaudioprocess -callbacks.
As it turns out, I too had been thinking about converting the mixing code into using WebAssembly, although my plan was to use a language more familiar to me - plain old C. 😃 It’s more of a gut feeling at the moment, but I think that converting the channel loop inside
.mix
on each player into WebAssembly would provide a marked improvement in performance.As soon as I have some more time to work on this project, I’ll start looking a bit closer into experimenting with this - perhaps even before continuing with .IT player code.
That’s an excellent analysis and comparison - thank you!
The lack of interpolation and volume ramping makes the Protracker mixing code perform reasonably well, but ST3 and FT2 mixing hits the CPU quite hard. Ping-pong looping in FT2 code also has lots of branches and nested contexts, so it could definitely use some improvement.
Some XM modules seem to be especially prone to stuttering. These two, for example:
https://mod.haxor.fi/Hunz/clone_it.xm https://mod.haxor.fi/Mystical/system_override.xm
Intrestingly, the stuttering seems to always occur at the same position within the module - for clone_it.xm, it is just before position 0x0a. I noticed that at least on Chrome, the heap usage goes absolutely bananas right at that position:
So using Webassembly for the mixing code may also help in providing finer control over memory allocation and when GC is allowed to run.