ModPlug Central

OpenMPT => Development Corner => Topic started by: SimonG on July 24, 2014, 21:35:29

Title: libopenmpt emscripten port
Post by: SimonG on July 24, 2014, 21:35:29
Hi,
I just wanted to let you know, that I finally created a JavaScript port of libopenmpt with Emscripten.
Saga Musix, you may remember me from the ModArchive Forums (http://modarchive.org/forums/index.php?topic=3456.0) where I presented my earlier port of a different module player library.
I switched because it turned out that libopenmpt is much better suitable for connecting it with the WebAudioAPI.
Of course my JS port is still missing features, but is usable by now.
If you want to check is out: The code is hosted on Github (https://github.com/deskjet/chiptune2.js). You can also try it your browser on the demo page (http://deskjet.github.io/chiptune2.js/).
Let me know how you like it. :D
Title: Re: libopenmpt emscripten port
Post by: Saga Musix on July 24, 2014, 22:04:33
Nice work. Did you come across any problems while doing this, and how did you fix them? I remember that manx attempted an emscripten port a while back, and he ran into some problems where emscripted generated apparently buggy code, which made some floating point related test cases fail (module rendering still worked though, albeit slow).
Title: Re: libopenmpt emscripten port
Post by: manx on July 25, 2014, 06:29:00
I would be great if you can make your modifications to libopenmpt (if any) public and provide the build scripts you used for building with emscripten. I would really like to integrate this into the libopenmpt code base itself.
Which emscripten version did you use?
The problems I had been facing might have been related to the fact that the emscripten version in debian is rather old (the last version before the new fastcomp backend). Did you try running the testsuite with your port?
Anyway, a small bug report for your port: Audio playback seems to be somewhat broken for me. It plays about 1 second of audio and then stops. Hitting pause twice plays another second and stops again. This is Firefox 31 on Ubuntu 12.04.
Title: Re: libopenmpt emscripten port
Post by: manx on July 25, 2014, 06:42:58
Oh, I somehow missed your libopenmpt repository at github. So all your changes are already available. Great! :)
Title: Re: libopenmpt emscripten port
Post by: SimonG on July 25, 2014, 07:07:03
There were some issues, when I tried to run a small example, that was printing the audio to stdout in nodejs for testing. It was producing awkwardly distorded audio. It turned out, that nodejs somehow messed up the output and the libraray was working correctly.

manx, as you just found out, there is a libopenmpt repository. All my changes are in these two (https://github.com/deskjet/libopenmpt/commit/ce9c4946b9e758b100b14cf83218aa7b0e114319) commits (https://github.com/deskjet/libopenmpt/commit/3112e6e46dac90f06e27fabac2fa8e6170a02810). I only modified the build system.
The emscription version is  1.16.0 (commit 326078dbfd2d1b412546dffef81964c3d2ca125d). I compiled it myself quite a while ago, but it already uses the fastcomp backend. There is a good guide in the emscripten wiki (a quadcore cpu is reccommended ;)).
I haven't run the tests yet, but i'll try to do so.

I will also look into your bug, strangely it works for me in Firefox and Chrome. Unfortunateley I am stuck with Firefox 30, as my internet connection is broken and I'm online via my phone.

Update:
I ran the tests. The TestITCompression fails. This is what it tells me:
Test: test/test.cpp(88): TestITCompression:
Test: test/test.cpp(88): TestITCompression: FAIL
FAIL: Test: test/test.cpp(88): TestITCompression : '
TEST ERROR: exception: vector


TestLoadSaveFile fails too. This seems correct to me, as you can't do file io in regular javascript. The tests were run in nodejs.
Title: Re: libopenmpt emscripten port
Post by: manx on July 25, 2014, 14:51:27
Quote from: SimonG on July 25, 2014, 07:07:03
There were some issues, when I tried to run a small example, that was printing the audio to stdout in nodejs for testing. It was producing awkwardly distorded audio. It turned out, that nodejs somehow messed up the output and the libraray was working correctly.

I also remember problems getting nodejs to not garble the output, afair, I did not get stdout to work correctly with nodejs.

Quote from: SimonG on July 25, 2014, 07:07:03
The emscription version is  1.16.0 (commit 326078dbfd2d1b412546dffef81964c3d2ca125d). I compiled it myself quite a while ago, but it already uses the fastcomp backend. There is a good guide in the emscripten wiki (a quadcore cpu is reccommended ;)).

Debian has emscripten 1.10, which is totally ancient. I'm currently trying to build a current version. Will probably take some time :).

Quote from: SimonG on July 25, 2014, 07:07:03
I ran the tests. The TestITCompression fails. This is what it tells me:
Test: test/test.cpp(88): TestITCompression:
Test: test/test.cpp(88): TestITCompression: FAIL
FAIL: Test: test/test.cpp(88): TestITCompression : '
TEST ERROR: exception: vector


TestLoadSaveFile fails too. This seems correct to me, as you can't do file io in regular javascript. The tests were run in nodejs.

The it compression test (currently) also perform file i/o, so they fail probably for the same reason.
As you might have noticed, in -beta5, I added a basic Makefile.config.emscripten (which is not too different from the file you use).
The relevant part for getting the file i/o testcases to work is

EXESUFFIX=.js
SOSUFFIX=.js
RUNPREFIX=nodejs
TEST_LDFLAGS= --pre-js build/make/test-pre.js

and the contents of the build/make/test-pre.js file. This way, nodejs should allow the file i/o needed for the testcases.
Can you try rerunning the test cases that way?
Title: Re: libopenmpt emscripten port
Post by: manx on July 26, 2014, 09:22:32
Quote from: manx on July 25, 2014, 06:29:00
Anyway, a small bug report for your port: Audio playback seems to be somewhat broken for me. It plays about 1 second of audio and then stops. Hitting pause twice plays another second and stops again. This is Firefox 31 on Ubuntu 12.04.

Update: Works without problems on Firefox 31 on Mint17 (aka Ubuntu 14.04).
On Ubuntu 12.04, I am running pulseaudio with 96kHz instead of the default 48kHz which might or might not be relevant (I know nothing about the javascript WebAudio API).
Title: Re: libopenmpt emscripten port
Post by: manx on July 26, 2014, 09:46:42
Quote from: manx on July 25, 2014, 14:51:27
I'm currently trying to build a current version.

I successfully built emscripten 1.21 on Mint17 (Ubuntu 14.04).

manx@idefix ~/projects/openmpt/trunk-emscripten $ emcc --version
emcc (Emscripten GCC-like replacement) 1.21.0 (commit 06961a0ef6e3d8d92d5e36ff904262fefec62bec)
[...]
manx@idefix ~/projects/openmpt/trunk-emscripten $ nodejs --version
v0.10.25

After patching out a tiny test case which fails for unknown reasons with this version (see http://sourceforge.net/p/modplug/code/4190/ (http://sourceforge.net/p/modplug/code/4190/), it completely passes the test suite for me with nodejs on amd64.
The stock makefile (as of -beta5) also builds the final javascript file (libopenmpt.js) directly without the need to explicitely set the exported-to-javascript symbols via emcc commandline. This is done using symbol visibility. Thus, you can probably simplify your documentation a bit.
libopenmpt.js, built with the stock makefile, works as a drop-in replacement with your chiptune2.js just fine (i put it up at http://manx.datengang.de/openmpt/chiptune2.js-manx/ (http://manx.datengang.de/openmpt/chiptune2.js-manx/)).

In case you did not know (and dont want to grad the current version from our svn directly), there a snapshots available at http://buildbot.openmpt.org/builds/ (http://buildbot.openmpt.org/builds/), and in particular, http://buildbot.openmpt.org/builds/auto/src/libopenmpt-0.2.4191.tar.gz (http://buildbot.openmpt.org/builds/auto/src/libopenmpt-0.2.4191.tar.gz).

I think, I can consider emscripten a supported platform now (even though I would not be surprised if there are still some problems waiting to be found :) ).
Thanks for your work on chiptune.js and chiptune2.js. Working module playback in browsers without the need for flash or java is a big win! :)
Title: Re: libopenmpt emscripten port
Post by: SimonG on July 27, 2014, 20:10:59
Quote from: manx on July 26, 2014, 09:22:32
Update: Works without problems on Firefox 31 on Mint17 (aka Ubuntu 14.04).
On Ubuntu 12.04, I am running pulseaudio with 96kHz instead of the default 48kHz which might or might not be relevant (I know nothing about the javascript WebAudio API).
I can't reproduce the bug. Pulseaudio on my system (Fedora 20) doesn't seem to accept anything over 48kHz. But I can imagine that the browsers Web Audio API implementations behave buggy with non-standard audio configurations. Chrome even crashes if there is no audio sink selected in Pulseaudio.

Quote from: manx on July 26, 2014, 09:46:42
I successfully built emscripten 1.21 on Mint17 (Ubuntu 14.04).


manx@idefix ~/projects/openmpt/trunk-emscripten $ emcc --version
emcc (Emscripten GCC-like replacement) 1.21.0 (commit 06961a0ef6e3d8d92d5e36ff904262fefec62bec)
[...]
manx@idefix ~/projects/openmpt/trunk-emscripten $ nodejs --version
v0.10.25

I think I should update my build some time. ;)

Quote from: manx on July 25, 2014, 14:51:27
After patching out a tiny test case which fails for unknown reasons with this version (see http://sourceforge.net/p/modplug/code/4190/ (http://sourceforge.net/p/modplug/code/4190/), it completely passes the test suite for me with nodejs on amd64.
The stock makefile (as of -beta5) also builds the final javascript file (libopenmpt.js) directly without the need to explicitely set the exported-to-javascript symbols via emcc commandline. This is done using symbol visibility. Thus, you can probably simplify your documentation a bit.
libopenmpt.js, built with the stock makefile, works as a drop-in replacement with your chiptune2.js just fine (i put it up at http://manx.datengang.de/openmpt/chiptune2.js-manx/ (http://manx.datengang.de/openmpt/chiptune2.js-manx/)).

In case you did not know (and dont want to grad the current version from our svn directly), there a snapshots available at http://buildbot.openmpt.org/builds/ (http://buildbot.openmpt.org/builds/), and in particular, http://buildbot.openmpt.org/builds/auto/src/libopenmpt-0.2.4191.tar.gz (http://buildbot.openmpt.org/builds/auto/src/libopenmpt-0.2.4191.tar.gz).
Great! This makes building nice and easy. I've updated my building instructions.

Quote from: manx on July 26, 2014, 09:46:42
I think, I can consider emscripten a supported platform now (even though I would not be surprised if there are still some problems waiting to be found :) ).
Thanks for your work on chiptune.js and chiptune2.js. Working module playback in browsers without the need for flash or java is a big win! :)
I am going to try and add more features to chiptune2.js and make it more robust. When I encounter problems I'll let you know.
Title: Re: libopenmpt emscripten port
Post by: manx on July 29, 2014, 08:05:25
Quote from: SimonG on July 27, 2014, 20:10:59
Quote from: manx on July 26, 2014, 09:22:32
Update: Works without problems on Firefox 31 on Mint17 (aka Ubuntu 14.04).
On Ubuntu 12.04, I am running pulseaudio with 96kHz instead of the default 48kHz which might or might not be relevant (I know nothing about the javascript WebAudio API).
I can't reproduce the bug. Pulseaudio on my system (Fedora 20) doesn't seem to accept anything over 48kHz. But I can imagine that the browsers Web Audio API implementations behave buggy with non-standard audio configurations. Chrome even crashes if there is no audio sink selected in Pulseaudio.

I can reproduce this on all 3 of my Ubuntu 12.04 boxes. It happens even when running pulseaudio in default configuration. It did not even work when using other sample rates in your player code.

Anyway, I rewrote your player code to use the callback based ScriptProcessorNode nstead of scheduling multiple consecutive AudioBufferSourceNodes using timestamps. This works just fine on all my linux boxes running firefox (did not yet check windows or chrome). Disclaimer: I have no experience with javascript, so I might be doing some stupid things there. I put the code up at github https://github.com/manxorist/chiptune2.js (https://github.com/manxorist/chiptune2.js). Feel free to merge this if you like it. The demo is at http://manx.datengang.de/openmpt/chiptune2.js-manx/ (http://manx.datengang.de/openmpt/chiptune2.js-manx/).
Title: Re: libopenmpt emscripten port
Post by: Saga Musix on July 29, 2014, 15:07:50
Nice work, I'm getting even better results performance-wise with manx' modifications, I think. At least I can recall experiencing far more dropouts in the other version.
Title: Re: libopenmpt emscripten port
Post by: SimonG on August 24, 2014, 20:01:00
Sorry for answering late. I'm have been very busy with lots other stuff and still will be for some more weeks.
Thank you for improving the player. Using the ScriptProcessorNode sounds like a good idea to me. I'm not an JavaScript expert either so I'm always open to new ideas.
I haven't checked your code yet. However I pulled your changes into my repository. If there are further improvements feel free the submit a pull request on Github.
Title: Re: libopenmpt emscripten port
Post by: Saga Musix on September 11, 2015, 23:53:59
I'm now using chiptune2.js + libopenmpt on both ModArchive (http://modarchive.org/) and s3m.it (https://s3m.it/) and it's working really great so far and is super easy to integrate. I can really recommend this combination to anyone needing module playback on their website.
Title: Re: libopenmpt emscripten port
Post by: RyanBram on August 15, 2016, 09:29:21
Dear OpenMPT developers and community,

With the current enhanced MIDI Importer, I am prepare to convert my whole collection of MIDI file to be used for my HTML5 games. But the current port of libopenmpt in Chiptine2.js has almost 2.5 mb in size which will bloating my distribution compared to my game assets. It also not very friendly for people with low bandwidth.

Can anybody show me if there is a workaround or options to resulting smaller emscripten port of libopenmpt? Maybe by omitting unused module formats, which in my case I plan to use only IT, MPTM, and MO3.

Thanks,
RyanBram
Title: Re: libopenmpt emscripten port
Post by: Saga Musix on August 15, 2016, 11:41:45
Why don't you use an actual javascript MIDI player rather than libopenmpt, which would be much more suitable for what you are trying to do, and most likely smaller as well? I know there are some MIDI players written in JavaScript, so you should definitely check them out.

To answer your question, though, removing supported module formats will only give you tiny gains in size - emscripten has a large overhead, and the answer is to always prepare a gzipped and optionally brotli-compressed version of libopenmpt. This will get the size down to 500kb, which is still a lot, but actually quite an OK size for the pile of code in there.
Title: Re: libopenmpt emscripten port
Post by: RyanBram on August 15, 2016, 13:36:03
Quote from: Saga Musix on August 15, 2016, 11:41:45
Why don't you use an actual javascript MIDI player rather than libopenmpt, which would be much more suitable for what you are trying to do, and most likely smaller as well? I know there are some MIDI players written in JavaScript, so you should definitely check them out.
I have some reason for not doing that:

1. Inconsistency of sound. I don't find any javascript that able to play sf2 format. Most MIDI Player js rely on underlying operating system sound banks which make my game sounds different in each platform (especially Android)

2. Bigger distribution size. Although if I found one, the combination of the MIDI Player js + sf2 + MIDI music files will be much bigger than combination of libopenmpt + mo3 music files which are almost as small as MIDI files

3. Harder to improve sound quality. In MIDI, quality of sounds depend on shared sound bank, while in MO3, I can "patch" the sample with higher quality in relative easier way. As someone who come from MIDI world, it may takes several more years for me to be able to create Module from stratch, therefore the current method for creating music is by creating in piano roll first, converting to MPTM, then replacing the sound banks with the higher quality and many other improvent in OpenMPT.

Anyway many thanks for the solutions. ;D
Title: Re: libopenmpt emscripten port
Post by: Saga Musix on August 15, 2016, 17:23:28
Quote1. Inconsistency of sound. I don't find any javascript that able to play sf2 format. Most MIDI Player js rely on underlying operating system sound banks which make my game sounds different in each platform (especially Android)
There is no underlying operating system a javascript MIDI player can be borrowing its samples from. You must have been looking for something different.
A 1-second Google search brought up this, which plays soundfonts but leaves the MIDI file decoding up to the user: https://www.npmjs.com/package/soundfont-player
I am sure someone built a full MIDI player based on it, or on some other source.

Quote2. Bigger distribution size. Although if I found one, the combination of the MIDI Player js + sf2 + MIDI music files will be much bigger than combination of libopenmpt + mo3 music files which are almost as small as MIDI files
That is wrong. If you spend the time removing unused samples from module files, you can just as well spend the time removing unused instrument from your SF2 file. In fact, if several MIDI files use the same instruments, the soundfont approach is smaller. There are also ways to compress sf2 or sfz soundfonts.

Quote3. Harder to improve sound quality. In MIDI, quality of sounds depend on shared sound bank, while in MO3, I can "patch" the sample with higher quality in relative easier way.
Soundfont editors are a thing.
Title: Re: libopenmpt emscripten port
Post by: manx on August 15, 2016, 18:12:30
Staying on the original topic here, the only thing that can be reasonably removed and actually gain something is MO3 support because we can skip the Ogg Vorbis and MP3 decoders in that case. I'm not sure how much is saved, but my guess would be some about 100kB.
However, that's not useful in your case because you want MO3 support.
There are also other module playback libraries that work when compiled with emscripten. The most popular example being libxmp. However, libxmp does not support MO3 either.
libxmp is smaller than libopenmpt though. There are various reasons for that (a big contributing factor is the fact that libopenmpt is written in C++ while libxmp is written n C, which requires the whole C++ standard library to be included in the emscripten build). In any case, neither this nor any other contributing factor are likely (or possible at all) to change in libopenmpt.
Title: Re: libopenmpt emscripten port
Post by: Saga Musix on August 15, 2016, 18:32:17
QuoteStaying on the original topic here, the only thing that can be reasonably removed and actually gain something is MO3 support because we can skip the Ogg Vorbis and MP3 decoders in that case. I'm not sure how much is saved, but my guess would be some about 100kB.
Even less if we're talking about the compressed version - if I recall correctly, adding the MP3 / Vorbis decoders was about 50kB of overhead or so in the gzipped version.
Title: Re: libopenmpt emscripten port
Post by: RyanBram on August 18, 2016, 07:39:02
Many thanks for the solutions Manx and Saga.
No matter what the reasons, I have my own personal interest for creating game with tracker music. Maybe it is just because I don't really like separation of notes with its sounds. And the 1-second Google from Saga doesn't bring me to sf2 player, because the js player actually needs an sf2 to be extracted (https://github.com/gleitz/midi-js-soundfonts) with ruby based script extractor to become many parts of mp3 files.
At the end, with your answers, I think it is better to stay with libopenmpt instead of using another library, such as libxmp.

Out of curiosity, I read in previous topic that emscripten is categorized as supported platform. Does it mean that there is a plan someday to distribute libopenmpt.js s precompiled binary alongside openmpt123.exe, xmp-openmpt.dll, and in_openmpt.dll?

Sorry for any inconvenience.
Title: Re: libopenmpt emscripten port
Post by: manx on August 18, 2016, 07:51:37
Quote from: RyanBram on August 18, 2016, 07:39:02
Out of curiosity, I read in previous topic that emscripten is categorized as supported platform. Does it mean that there is a plan someday to distribute libopenmpt.js s precompiled binary alongside openmpt123.exe, xmp-openmpt.dll, and in_openmpt.dll?

This will probably happen in the near future (some weeks), yes. But that version will not have MP3 support, and thereby no MO3 support, due to legal reasons. We could maybe include a Vorbis-only MO3 decoder though, but AFAIK this will be a bit more work.
Title: Re: libopenmpt emscripten port
Post by: manx on August 19, 2016, 14:00:09
Quote from: RyanBram on August 18, 2016, 07:39:02
Out of curiosity, I read in previous topic that emscripten is categorized as supported platform. Does it mean that there is a plan someday to distribute libopenmpt.js s precompiled binary alongside openmpt123.exe, xmp-openmpt.dll, and in_openmpt.dll?

https://buildbot.openmpt.org/builds/auto/libopenmpt-bin.js/ (https://buildbot.openmpt.org/builds/auto/libopenmpt-bin.js/)
I think, Vorbis-only MO3 should work.
Title: Re: libopenmpt emscripten port
Post by: RyanBram on August 21, 2016, 02:40:04
Hi, Manx. :)

Thanks for the great news.
I have tested the precompiled libopenmpt.js by buildbot. The result is most of OpenMPT supported format are work out of the box, the only exception are vorbis encoded MO3 and lossless MO3.
I tested by replacing libopenmpt.js in Chiptune2.js github master with one from buildbot.
Title: Re: libopenmpt emscripten port
Post by: Saga Musix on August 21, 2016, 23:49:11
Quote from: manx on August 19, 2016, 14:00:09I think, Vorbis-only MO3 should work.
MPT_ENABLE_MO3_BUILTIN (and MPT_WITH_STBVORBIS) is not defined by default, so currently no MO3 support gets compiled at all.
Title: Re: libopenmpt emscripten port
Post by: manx on August 22, 2016, 14:24:37
Quote from: Saga Musix on August 21, 2016, 23:49:11
Quote from: manx on August 19, 2016, 14:00:09I think, Vorbis-only MO3 should work.
MPT_ENABLE_MO3_BUILTIN (and MPT_WITH_STBVORBIS) is not defined by default, so currently no MO3 support gets compiled at all.
As far as I can see, MPT_WITH_STBVORBIS is enabled by default, but MPT_ENABLE_MO3_BUILTIN is not, because no MP3 decoder is enabled.
I don't know if we actually want to change or support that. It would result in systems having no MP3 decoder and no Un4seen unmo3 actually getting MO3 support via the internal MO3 decoder, but it will only be able to successfully decode some MO3 files. Other files would get loader warnings of course, but I would prefer to not even try the internal decoder unless it can decode all the possible sample formats. The testing matrix is already complicated enough in that area.
Title: Re: libopenmpt emscripten port
Post by: Saga Musix on August 22, 2016, 14:34:01
Right, I remember that we briefly discussed this and I agree that the default should be either full or no support. If someone wants partial MO3 support, they should compile their own version.
Title: Re: libopenmpt emscripten port
Post by: manx on August 22, 2016, 14:36:49
I should tune the build system to not include stb_vorbis in Emscripten builds by default though, as it's totally useless.
Title: Re: libopenmpt emscripten port
Post by: RyanBram on June 15, 2017, 01:39:23
Quote from: manx on August 18, 2016, 07:51:37
... But that version will not have MP3 support, and thereby no MO3 support, due to legal reasons. ...

Hi.
MP3 patent has expired now. Is it possible for OpenMPT developers to re-consider the inclusion of complete MO3 support in emscripten version of libopenmpt?

Thanks.

News:
https://www.theregister.co.uk/2017/05/16/mp3_dies_nobody_noticed/
Title: Re: libopenmpt emscripten port
Post by: manx on June 15, 2017, 05:33:15
Quote from: RyanBram on June 15, 2017, 01:39:23
Quote from: manx on August 18, 2016, 07:51:37
... But that version will not have MP3 support, and thereby no MO3 support, due to legal reasons. ...
MP3 patent has expired now. Is it possible for OpenMPT developers to re-consider the inclusion of complete MO3 support in emscripten version of libopenmpt?

libopenmpt has had MP3 support when built with emscripten for quite a while now. It is not enabled by default though.

We generally support both libmpg123 and minimp3 for MP3 sample support, but only minimp3 is tested with emscripten and has support in the Makefile build system. For simplicity and ease of use reasons, we statically link everything into a single library with emscripten. minimp3 (and also libmpg123) are LGPL licensed, which means, in the case of static linking, the whole resulting compiled binary (and thus also the used source code) would also be subject to LGPL licensing. As libopenmpt is BSD3 licensed, we do not want to have a default build configuration effectively change the license to LGPL, which is why we do not enable MP3 sample support for emscripten by default.

If you do not mind the license implications, you can just use make CONFIG=emscripten USE_MINIMP3=1 (works for both, libopenmpt 0.2 and libopenmpt 0.3). For libopenmpt 0.2 you have to download minimp3 yourself and put it into include/minimp3/ (I am considering actually shipping it in the next 0.2 release), for libopempt 0.3 it is already included.

libopenmpt 0.3 also has MO3 support enabled even without having MP3 sample support enabled (will just not load the MP3 encoded samples in this case, Vorbis encoded sample or uncompressed sample will work just fine). libopenmpt 0.2 automatically disables also Vorbis support (and I think also MO3 support completely, but I do not remember exactly (I can look it up if desired)), if not MP3 support is enabled.