MOD, XM playback

hello,

does anyone have any ideas how to play tracker files with OpenFL / Lime in a portable way?
i know how to play them with SDL2_mixer nativelly or with FLOD with Flash, but i don’t have much experience with haxe based frameworks.

thanks

Does SDL mixer have support out of the box, or does it require an another library?

it uses either libmodplug or libmikmod, which have snapshots in the SDL2_Mixer tree:
http://hg.libsdl.org/SDL_mixer/file/b28b41b93ba7/external

high level API:
http://jcatki.no-ip.org:8080/SDL_mixer/SDL_mixer_frame.html

There is ModPlayer by BadSector: https://github.com/badsector/fmp/blob/master/ModPlayer.hx
I modified it to play xm (not complete) and used it in Bakame: http://www.wieringsoftware.nl/flash/bakame/ my updated code for the modplayer is in http://www.wieringsoftware.nl/ld/HaxeBaseCode-1.7.zip

However, this requires dynamic sound generation with SampleDataEvent, which is currently not yet supported by openfl, currently only works for the Flash target.

@Wiering, yup, that would be one of the Flash candidates of a mod/xm player, i would guess.
but the FLOD library does have more supported formats. (EDIT: nvm).

@singmajesty: just tried NME via “haxelib install nme” and it appears that it does support tracker formats.

based on NME’s 06-Sound (sample project), Assets.getSound(“id”), must be used instead of Assets.getMusic(“id”) as the sound is not recognized as “music”.

tracker songs do play and it appears after doing an “ar t …” on their static library that it contains “libmodplug”.

on the other hand Lime does not recognize the files as valid asset and looking at the windows compiled dynamic library i don’t see any tracker related exports.

posted this at Lime’s github:

would be a great addition to OpenFL!

We had some serious issues in SDL_mixer in the past, during NME development, this was part of the motivation for moving to OpenAL, to fix the issues and also to have a more mature sound layer.

I’m guessing it would be possible to add support for MOD using OpenAL, still? If you think SDL_mixer is actually better all around than OpenAL for our sound support, also interested in hearing your input on the subject :slight_smile:

as i’m currently not aware of the entire picture,

i would go with SDL_Mixer; it has it’s issues but it’s all around a more self sustained library.
what were the SDL_Mixer issues that you have mentioned, BTW?

OpenAL is the more flexible “sound/audio layer”, but the problem with OpenAL is that it does not have API for format decoding, thus Lime needs to provide the decoding backend, like it already does here:
https://github.com/openfl/lime/tree/master/project/src/audio/format

now, there is also ALMixer, which is (supposedly) a better mixer than SDL_Mixer and decodes everything that SDL_Mixer does, but that’s due to the fact that’s it is based on SDL_Sound, which is the same decoder library used in SDL_Mixer:
https://bitbucket.org/ewing/almixer

the library is LGPL, and in their source code there is something called “SoundDecoder.h” which can be used instead of SDL_Sound (also LGPL), but again that’s just a localized set of decoders forked from SDL_Sound and the tracker format decoding hooks are missing for libmodplug and libmikmod.

so following the current idea of internal decoders in Lime - something in the lines of this has to be done for the tracker formats:
(SDL_Mixer, ver.2.0 is zlib license)
http://hg.libsdl.org/SDL_mixer/file/b28b41b93ba7/music_modplug.c
http://hg.libsdl.org/SDL_mixer/file/b28b41b93ba7/music_mod.c

here are the SDL_Sound decoders, but these are LGPL:
http://hg.icculus.org/icculus/SDL_sound/file/719dade41745/decoders/modplug.c
http://hg.icculus.org/icculus/SDL_sound/file/719dade41745/decoders/mikmod.c

of course, there is also the option to attempt to use OpenAL as the sound layer and SDL_Mixer as the loader / decoder, and while this is going to be easier for sound chunks, i think, it’s not going to be easy for the Music* API of SDL_Mixer.

perhaps others can provide more feedback. :slight_smile:

When we used SDL_mixer:

  • It was a pain to be able to build it all at the time. The number it dependencies it had was somewhat staggering, it would sometimes lead to runtime problems on client machines, particularly in Linux
  • At the time, doing simple things, such as checking the volume or position of a sound was either inconsistent or lead to crashing often, particularly on Windows
  • When I moved to SDL2, getting SDL_mixer working again was difficult and seemed unsupported
  • I felt that SDL_mixer has dubious licensing, such as the MP3 support, which requires licenses from Fraunhoffer
  • I wanted to unify audio support as much as possible, OpenAL support was possible on all native targets – Windows, Mac, Linux, iOS, Android, BlackBerry, Tizen – instead of only with the desktop.

I know that with SDL2, having SDL_mixer on mobile is more possible. In fact, Lime 2 is going to use SDL2 for iOS and Android forward (or that’s the plan) so I wonder how the performance might compare there, especially on Android, where OpenAL (and sound in general) has been a struggle (though a lot better than our previous woes with SoundPool and MediaPlayer).

I also like the licensing on SDL_mixer, being able to include it in a statically linked build would be nice, but I don’t want to take a step back in terms of robustness. Now, how Lime is set up now, it would be possible to support more than one audio implementation, but I don’t want to spread support too thin – the more we consolidate on a single implementation, the better things are across the board.

Just a few thoughts, thanks :slight_smile:

a lot of linux developers can relate to the dependencies and runtime issues.
for SDL_Mixer in particular those can be 10 or so, mostly because of the decoders.
but i think the only sane way to deploy a linux package (e.g. a game) would be to bundle every single library and dependency when building with RPATH if such are LGPLed or simply static link when possible.

i’m not sure you do the RPATH similar solution, but i’m sure you already do static linking.
i correspond with linux involved figures and they are now doing that as they are not really happy what has become of the linux ecosystem…and also Steam is doing it TMK.

ideally not a single not-so-common library should be fetched from the OS on runtime.

the best thing about SDL is that it’s open source and bug fixes can be pushed upstream.
but SDL_Mixer in particular is the most buggy library, they say…

i think it should be supported now.

overall the MP3 licensing as a whole is quite bad. it’s so bad that i think that game developers should consult a lawyer before using MP3 for their game :). for MP3, SDL_Mixer now uses SMPEG, which is LGPL and doesn’t play all MP3 i throw at it, but at least it’s something.

i would give it a shot, but i don’t think the performance would be that better.
they do advertise now SDL2 as a good solution for Android and iOS, but i don’t know if BlackBerry, Tizen are supported.

i think the worst thing about SDL_Mixer API wise is the Sound / Music separation. that’s mainly because of how some of the decoders work (e.g. those that were the reason for this thread - modplug etc.) and that’s why only a single Music instance can play at a time, which i think is not what an OpenFL user will expect at first.

a great solution here would have been if all libraries can decode in memory to PCM on “load time” and that stream can then be played by an unified mixer / channel API like flash does.

also, just to note i would love to contribute as i like the multiplatform challenge OpenFL is taking a lot, but my free time is usually very limited. perhaps eventually…

EDIT: fixed typos

Shouldn’t the implementation be on the haxe side for the XM player since it is dynamic music?

Just tried: http://www.tanjent.se/labs/tanjentxm.html and it is working well except on mobile (only tested android) and HTML5 (no support for SAMPLE_DATA yet I think?).

In the case of mobile I could hear a microsecond before it cut off so perhaps there is only a few fix in Lime (I guess?) to get it working.

Thanks Starburst, I didn’t know yet that SAMPLE_DATA was implemented for Windows, I had it commented out all the time!

Yes, it would be great to have this work on the other targets as well.

:slight_smile: Got it working on Android, turn out when lime_sound_channel_needs_data == true you need to feed the ByteArray immediately to lime_sound_channel_add_data with close to nothing in-between.

Here’s a proof of concept:

private static inline var FREQUENCY = 1000;

private static var lime_sound_channel_create_dynamic = Lib.load ("lime", "lime_sound_channel_create_dynamic", 2);
private static var lime_sound_channel_needs_data = Lib.load ("lime", "lime_sound_channel_needs_data", 1);
private static var lime_sound_channel_add_data = Lib.load ("lime", "lime_sound_channel_add_data", 2);
private static var lime_sound_channel_get_data_position = Lib.load ("lime", "lime_sound_channel_get_data_position", 1);

private var byte:ByteArray = null;
private var channel:Dynamic = null; 
private var iSin:Float = 0;

function test()
{
	byte = new ByteArray();
	byte.endian = Endian.LITTLE_ENDIAN;
	
	for ( i in 0...8192 ) 
	{
		var val = Math.sin( 2 * Math.PI * (iSin++) * FREQUENCY / 44100 );
		
		byte.writeFloat( val );
		byte.writeFloat( val );
	}
	
	channel = lime_sound_channel_create_dynamic (byte, null);
	
	addEventListener( Event.ENTER_FRAME, ef );
}

private function ef( event ):Void
{
	if ( lime_sound_channel_needs_data( channel ) )
	{
		lime_sound_channel_add_data (channel, byte);
		
		byte.position = 0;
		for ( i in 0...8192 ) 
		{
			var val = Math.sin( 2 * Math.PI * (iSin++) * FREQUENCY / 44100 );
			
			byte.writeFloat( val );
			byte.writeFloat( val );
		}
	}
}

If you move the loop before lime_sound_channel_add_data then it won’t works.

And here’s a patch to get it working on Android, didn’t test iOS: https://github.com/openfl/openfl/pull/488/files

Did you look any further into html5 support for tanjentxm?

I try tanjentxm but it only compile to flash not in windows target, is odd because it didint show any error, but the track dont play in windows target

hi! do you have any wonking repositorie of tanjent working on windows tarjet too?

Nah I don’t have any of that code anymore