Archive for January, 2011

h1

my “50cents” tips for a “working” cross-browser Audio implementation

January 27, 2011

Well, while working on Frank Jr. I got several headaches on the Audio Implementation, and more specifically in getting it working on all browsers (I mean Safari, Chrome and Opera, as they are the only I really care about), and I wanted here to give some  feedback on how I finally achieved it. These tips are based on both my own experience/investigation on this matter, and the information I collected from the internet (based on other people experience). Also, this article does not cover the basics of loading sounds, lots of website are already largely covering the subject (see the links at the end of this article) and also does not cover mobile browser specific “issues” (like iOS, Android).

So, let’s get started :

Tip #1 : the loading part

– use the ‘canplaythrough‘ event to ensure you sound is properly loaded (as this event is fired only when the browser determines that it can play through the whole audio without stopping) and don’t forget as well to make a call to “removeEventListener” to remove the notification (it might be not needed, but seems to be cleaner this way).

– use the ‘error‘ event to be notified on any problem when loading your sound (see next tip).

Tip #2 : don’t trust your hosting services

– As I was saying, I use the ‘error‘ event to be notified when a sound cannot be loaded. This can be very useful in case you have a shitty hosting service for you stuff (like me), giving you sometimes some timeout when loading resources. So in my case each time a error event pop-up, from the callback called by the ‘error‘ eventListener, I just call again the load() function of the corresponding Audio Element, giving me a very simple infinite & automatic retry mechanism :

soundLoadError: function(sound_id) {
this._audio_channels[sound_id][0].load();
},

The “audio_channels” being here an array containing a reference to all the Audio Object I created.

Tip #3: cloneNode is your friend

If you already played with the Audio Element, you should probably know that actually the best(?) way to overcome the single-channel limitation of the audio tag is to actually create copy of the same sounds, allowing to simultaneously play them when needed, which gives for a 4 channels sound somethings like this (in a simplified way) :

{
  _audio_channels[my_sound_id][1].src = "/sounds/bangbang.mp3";
  _audio_channels[my_sound_id][2].load();
  _audio_channels[my_sound_id][2].src = "/sounds/bangbang.mp3";
  _audio_channels[my_sound_id][2].load();  
  _audio_channels[my_sound_id][3].src = "/sounds/bangbang.mp3";   
  _audio_channels[my_sound_id][3].load();
  _audio_channels[my_sound_id][4].src = "/sounds/bangbang.mp3";
  _audio_channels[my_sound_id][4].load();
}

As you can see, this is for sure not bad (once used properly and using some function to avoid duplicating some code), but why do you have to manually do 4 times the same stuff when the browser can do it for you, and most of all why not wait for the first mp3 to be loaded before duplicating it ?  CloneNode is very usefull function that creates an exact copy of a specified node, in our case an Audio Element, so each time the sound I want to be on multiple channel is loaded I just need to do :

for(var channel=1;channel<sound_channel;channel++)
{
   audio_channels[sound_id][channel] = audio_channels[sound_id][0].cloneNode(true);
}

Isn’t life beautiful ? First I know that my mp3 is loaded, and then I don’t have to care again about the path, and the event to manage… CloneNode just take care of duplicating the sound on channel 0, and it’s just easier that way and working perfectly !

Tips 4 : don’t trust your browser

Some browser don’t really do stuff correctly, so here some adjustment to be done :

– On some browser when you reach the end of a sound, it’s better to force the value of the CurrentTime property to 0. And to give another hint, on Chrome, it’s even better to force the value to something different than 0 (like 0.01) as else sometimes the sound is not played.

  audio_channels[sound_id][channel].pause();
  audio_channels[sound_id][channel].currentTime = 0.01;

Then there is two ways of doing this :

1. just before playing a sound

2. or using a callback, once the “ended” event is fired. I personally prefer the second one, as anyway I use this event in my code to notify me when a sound is fully played.

That’s it !, I hope you’ll find this useful 🙂

And to finish, I’d like also to share with a very basic drumbox of course fully implemented in HMTL5 using the Audio Element. The used samples are not so terrific, and the loop algorithm (to play them) is not correct, but it was not the point here.


And to finish, some external links that I found useful when implementing all this :

Native Audio in the browser

Stories in Flight : HTML5 Audio and Javascript control

Everything you need to know about HTML5 Audio & Video

h1

Frank Jr. : another HTML5 experiment

January 12, 2011

Following my previous experience with my small Tapper remake in HTML5, I decided to push this to the next level and build my own game framework/engine.

“Frank Jr.” is today my very first real test (and playable game) with my own Javascript / HTML5 Game Library (jToolBox), on which I’ve been working since the last couple of months. This is of course still far from being a professional stuff (but guess what : I’m not a professional !), and although jToolBox still need a lot of work, I thought this was already good and fun enough to be shared with people, so here it is 🙂

To do a quick post-mortem on the project, I would say that the most difficult part was to have a working “cross-browser” implementation for the Audio Element. That part is the one that gave me the most hard time, and I’m planning to post an article about how to do this correctly within the next few days, so come back later if you are interested.

In the mean time, I’ll hope you’ll enjoy this little humble game 🙂