Learn Hiragana and Katakana by fighting monsters in RPG battles.

Post feature Report RSS Audio In Flashcard Clash

How we keep Flashcard Clash tiny with archaic audio file formats so it can download super fast.

Posted by on

Since Flashcard Clash can be run in the browser, I've tried to keep it as tiny as possible so it can be downloaded quickly. Also keeping the size down allows me to bundle all the assets in with the game on mobile platforms like Android, so there's no ridiculous second download process once launching the game. Specifically with audio assets, there's two parts, music and sound effects.

MilkyTracker

The music is created by Juhani Junkala in a 'tracked' music format from the 90s called Extended Module or XM. Tracked music allows you to create instruments as sound samples (eg: a single drum hit) then reuse them throughout the song, as opposed to more regular music formats that just stores the final sound data directly (eg: multiple drum beats with a voice singing over it). This means that tracked music can be smaller than the regular formats, which is great for us.

Originally I was using libxm to playback the music, it was easy to add to the game and use, but it sounded too different from the output of MilkyTracker, the tool Juhani was using to create the music. This brings me to what seems to be a common issue with XM music, every piece of software I’ve tried seems to play it differently. I think this is due to there not really being a definitive description of the format since it is based off what people have inferred from digging through the output of FastTracker2, the original tool to create them.

Luckily for me, Miky Tracker is not closed source, and the licensing for their playback library is permissive enough to use in my game. So by using that, I can ensure that the songs will sound exactly as the musician intended. There was just a day of hacking on the library to rip out all the things I didn't need, create a simpler interface for the game to use, and to create a wrapper for the code as it is written in C++ and the game is written in C.

Bfxr

On the sound effects front, instead of using a normal format that stores sound waves like a WAV file, I've forced Juhani to use BFXR instead. BFXR lets you create parameters for sounds, so that they can be generated later by the game. Since we are only storing the parameters and not the actual sound, the asset size is much smaller (currently 28kb vs 2.5mb). While these sounds can be a bit simple, BFXR also allows us to layer them together which improves them somewhat, and since the game is going for an old school JRPG kind of feel that does not hurt either.

BFXR hasn't always been awesome tho, we've had a lot of trouble with it breaking files, and also being very specific about what it can load. I didn't even know that SVN changed the line endings of text files until BFXR files stopped loading after I committed them.

BFXR is also open source, but it was written in AS3, which is a different language from the game. It wook a while to copy the code to C and get it running, but hopefully that’s sorted now and I don't need to spend any more late nights trying to work out why a sound is borked.

We were originally generating the sound effects in real time as the game ran, but it turns out that was VERY slow, especially on the web version. I have since switched to generating the sounds when the game starts up and storing them for play back as needed. This works ok with 30 sounds, but in the future I’ll need to do something smarter to generate sounds as needed (eg: only generate sounds for a monster when you are loading into a battle with that monster).

Once all that's done we have simple waveform data we can pass off to whatever platform we are running on to play the sounds. Currently we are defaulting to 16bit signed ints, but I think I might try to change to float as that's the native format for web browsers and that will mean less data conversion so it will run faster.

Post a comment

Your comment will be anonymous unless you join the community. Or sign in with your social account: