Monday, May 26, 2014

SoundManager2, jquery, angular and the Hotline Miami OST - Part 1

Sound Manager 2
I haven't written anything in the last 30 days. I've been a busy and lazy (among other things). But I had to write these things down before I forget again. I'm planning to do this in 2 parts so it won't be that long to read.

Sound Manager 2
Sound Manager 2 is this JavaScript library simplify playing audio on a web page. Think embedded players like SoundCloud and such. It's pretty nifty with fail-over support for Mp3 via Flash if you somehow have a retarded web browser who can't play an HTML5 audio tag. The whole point is you end up with a single API to use to play audio files IF only it didn't have a few gotchas.

The SM2 Gotchas that got me in the ass
  • Read the requirements page closely. Don't do what I did and dove straight into the API and got hung up on a few issues (some Flash crap and arbitrary seeking) which could have been resolved quite easily and quickly if I have READ THE FUCKING REQUIREMENT'S PAGE a bit more closely. 
  • Variable Bitrate (VBR) MP3s bad, Constant Bitrate (CBR) MP3s good
  • HTTP 206 Header (Partial Content). If you are like me and got a soup nazi for web administrator, use curl or Fiddler and test your Apache because it might be turned off. We don't want a "No soup for you" incident.
Using SM2 and turning it into a Jquery plugin
SM2 can easily be used with Jquery and turn it into a plugin. The challenging parts are deciding on how to deal with the settings (and there are a lot of SM2 settings) and how to handle the sound objects.

For the setting, I decided to go with sensible defaults that can be overridden and use jquery's $.extend function to merge it. It more or less looks like:
// default settings
var settings = {
    autoplay: false,
    loop: false,
    playNextOnFinish: true,
    hideTrackDetailsAfterPlay: false, /* N (Number) seconds, or false (Boolean) to always show it */
    soundManagerMultiShot: false, /* let sounds "restart" or "chorus" when played multiple times..*/
    soundManagerStream: true,  /* allows playing before entire file has loaded (recommended) */
    soundManagerSwfURL: 'swf/', /* path (String), relative to your html page */
    soundManagerFlashVersion: 9,
    soundManagerDebug: false, /* displays the SM2 debug info into the page and in the console */
    soundManagerHandleFlashBlock: true,
    soundManagerPreferFlash: false,
    soundManagerHTML5Audio: true,
    soundManagerFlashLoadTimeout: 1000
};
    .
    .
    // jquery plugin
    $.fn.smsplayer = function(options){
      if(options){
         $.extend(settings, options); // Merge options to settings
      }
      return this.each(function (){
         ....
      }
    } 

Usage therefore would look like:


As for the Sound objects, I decided to to handle them in an array.

var tracks = [],trackIDs = [];
.
.
$("#player").find('#playlist li > a').each(function(i) {
  var soundID = 'sms_sound_' + i.toString();
      $(this).addClass(soundID);
      trackIDs.push(soundID);
      var sound = soundManager.createSound({
                  id: trackIDs[trackIDs.length - 1],
                  url: $(this).attr('href'),
                  whileplaying: function() {
                    Player.prototype.updateTime(this.position, this.durationEstimate);
                  },
                  whileloading: function() {
                    Player.prototype.updateLoading(this.bytesLoaded, this.bytesTotal);
                  },
                  onfinish: function(){
                    isPlaying = false;
                    $('#playlist .playing').removeClass('playing');
                        
                    if(settings.autoplay){
                       var nextSound = Player.prototype.getNextTrackFrom(trackIDs, this.id);
                       currentTrackID = nextSound;
                       $('.' + currentTrackID).parent().addClass('playing');
                       Player.prototype.playSound(nextSound);   
                    }
                         
                  }
       });
       tracks.push(sound);

I'm going to explain the Hotline Miami OST in part 2.