beatbar.js | |
|---|---|
| globals: soundManager, key, window | function Beatbar() { |
| Private variables | var self = this,
sm = soundManager,
cursorLocation = 0, // current location of pointer in the bar
lastPageX = 0,
playerState,
PLAYING = 0,
STOPPED = 1,
PAUSED = 2,
lastUpdatedAt = 0,
location = window.location,
isWindowInFocus = true, // tracks the focus of player window
progressString = '~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~',
progressStringLength = progressString.length,
loadingString = progressString.replace(/~/gi,'='),
playControl = {
0: '~||~', // playing
1: '~(>~', // paused
2: '~(>~' // stopped
},
previousControl = '~~|<)~',
nextControl = '~(>|~~',
separator = '|',
playerStringLength = progressStringLength +
playControl[0].length +
previousControl.length +
nextControl.length +
separator.length,
screenWidth = $(document).width(),
delta = Math.floor(screenWidth/(playerStringLength*2)),
vu = '~~~~~~~~~~',
dummyPlayerString = previousControl +
playControl[0] +
nextControl +
separator +
progressString; |
| Configuration options | this.config = {
usePeakData: true,
cursorChar: 'O', // caracter for representing mouse position in beatbar
progressChar: 'o', // character for showing progress of the current song
playlist: []
};
|
| Contains the current sound object | this.sound = {};
|
| Contains all created sound objects | this.playlist = {};
|
| Bind events on document click, mousemove and other keyboard shortcuts | this.bindEvents = function() {
$(document).ready(function() {
$(document).click(self.clickHandler);
$(document).bind('mousemove',self.mouseMoveHandler);
$(window).resize(self.windowResizeHandler); |
| Don't render player if the window is not in focus | $(window).focus(function() {
isWindowInFocus = true;
}).blur(function() {
isWindowInFocus = false;
}); |
| Keybindings | key('n, j', function(){
self.playNext();
});
key('p, k', function(){
self.playPrevious();
});
key('space', function(){
self.togglePlay();
});
key('right', function(){
self.seekForward();
});
key('left', function(){
self.seekBackward();
});
key('home 0', function(){
self.seekToBeginning();
});
key('up', function(){
self.increaseVolume();
});
key('down', function(){
self.decreaseVolume();
});
});
};
|
| Click event handler Get the x coordinate of the click from event object translate it into URL string index according to the value of index perform different functions | this.clickHandler = function(e) {
var location = self.translatePointerLocation(e);
if (location > 2 && location < 5){
self.playPrevious();
} else if (location > 6 && location < 9){
self.togglePlay();
} else if (location > 10 && location < 14){
self.playNext();
} else if (location > 16) {
self.seekTo(location);
}
};
|
| Set screenWidth and delta when the window is resized | this.windowResizeHandler = function(e) {
screenWidth = $(document).width();
delta = Math.floor(screenWidth/(playerStringLength*2));
sm._writeDebug('Screen resized. New values:');
sm._writeDebug('screenWidth: ' + screenWidth);
sm._writeDebug('delta: '+ delta);
};
|
| Toggle play and pause for the current sound object | this.togglePlay = function() {
switch (playerState){
case PLAYING:
self.sound.pause();
break;
case PAUSED:
self.sound.resume();
break;
case STOPPED:
self.sound.play();
break;
default: |
| throw exception | sm._writeDebug('Something bad happened');
}
};
|
| Handler for progress section Translates the location into time in milliseconds then sets the position of current sound object to translated time Parameters: location (Integer) - index of character in the URL bar | this.seekTo = function(location) { |
| @todo due to integer division, the location is not calculated correctly | self.sound.setPosition(((location - 16.1)/progressStringLength)*self.sound.durationEstimate);
};
|
| Seeks the current sound object forward by specified time Parameters: seekBy (Integer) - time in milliseconds by which the sound should be seeked forward. Default 5000 | this.seekForward = function(seekBy){
seekBy = seekBy || 5000;
self.sound.setPosition(self.sound.position + seekBy);
};
|
| Seeks the current sound object forward by specified time Parameters: seekBy (Integer) - time in milliseconds by which the sound should be seeked backward. Default 5000 | this.seekBackward = function(seekBy){
seekBy = seekBy || 5000;
self.sound.setPosition(self.sound.position - seekBy);
};
|
| Seeks the position of current sound object to beginning of the sound | this.seekToBeginning = function(){
self.sound.setPosition(0);
};
|
| Increase the volume of current sound object by the specified amount on a scale of 0-100 Parameters: increaseBy (Integer) - volume to be increased by specified percentage | this.increaseVolume = function(increaseBy){
increaseBy = increaseBy || 10;
if (self.sound.volume <= 100 - increaseBy){
self.sound.setVolume(self.sound.volume + increaseBy);
}
};
|
| Decrease the volume of current sound object by the specified amount on a scale of 0-100 Parameters: decreaseBy (Integer) - volume to be decreased by specified percentage | this.decreaseVolume = function(decreaseBy){
decreaseBy = decreaseBy || 10;
if (self.sound.volume >= decreaseBy){
self.sound.setVolume(self.sound.volume - decreaseBy);
}
};
|
| handlers for sound events @todo refactor to use playState of soundObject @todo id3 data show | this.events = {
play: function(e) {
playerState = PLAYING;
self.renderPlayer();
},
stop: function(e) {
playerState = STOPPED;
self.renderPlayer();
},
pause: function(e) {
playerState = PAUSED;
self.renderPlayer();
},
resume: function(e) {
playerState = PLAYING;
self.renderPlayer();
},
finish: function(e) {
self.playNext();
self.renderPlayer();
}, |
| @todo throttle settings | whileloading: function(e) {
self.renderPlayer();
},
onload: function(e) {
if (self.sound.readyState == 2) { |
| failed to load | self.renderPlayer();
}
},
whileplaying: function(e) { |
| throttle for whileplaying calls | var d = new Date();
if (d - lastUpdatedAt > 50){
lastUpdatedAt = d;
self.renderPlayer();
}
},
id3: function(){
}
};
|
| Handle mouse move event | this.mouseMoveHandler = function(e) { |
| Dont excessively call renderPlayer on mousemove event lastPageX - cached mouse pointer position on last move and render | if (e.pageX > lastPageX + delta || e.pageX < lastPageX - delta) {
lastPageX = e.pageX; |
| change cursor location | cursorLocation = self.translatePointerLocation(e);
self.renderPlayer();
}
};
|
| Main method responsible for rendering the player in address bar | this.renderPlayer = function() {
if (!isWindowInFocus) {
return;
}
var controlString = self.renderControlString(),
errorMessage = 'Failed to load the sound. Security / 404 / Bad format',
playerString; |
| show error if there is a failure | if (self.sound.readyState == 2){
playerString = controlString + separator + '[' +
errorMessage + ']';
} else {
var progress = self.renderProgressString(),
timeString = self.renderTimeString(); |
| dont write vuString if usePeakData not supported | if (self.config.usePeakData) {
vuString = vu.slice(0, Math.floor(self.sound.peakData.left * 10));
} else {
vuString = '';
}
playerString = controlString + separator + progress + separator +
timeString + separator + vuString;
}
location.replace('#' + playerString.substr(0, cursorLocation) +
self.config.cursorChar +
playerString.substr(cursorLocation + self.config.cursorChar.length));
};
|
| Returns controls string | this.renderControlString = function() {
return previousControl + playControl[playerState] + nextControl;
};
|
| Returns progress string @todo rework the logic below | this.renderProgressString = function() {
var location = Math.floor((self.sound.position/self.sound.durationEstimate)*progressStringLength),
loaded = Math.floor((self.sound.bytesLoaded/self.sound.bytesTotal)*progressStringLength),
string = loadingString.substr(0,loaded) + progressString.substr(loaded);
return string.substr(0, location) +
self.config.progressChar +
string.substr(location + self.config.progressChar.length);
};
|
| Returns the remaining time string @todo cache time for one second | this.renderTimeString = function() {
var timeLeft = self.sound.durationEstimate - self.sound.position;
return '[-' + self.getTime(timeLeft) + ']';
};
|
| Translates mouse pointer location into player string cursor | this.translatePointerLocation = function(e) {
return Math.floor((e.pageX/screenWidth)*playerStringLength);
};
|
| create soudnManager sound object and returns it @todo refactor to use getSoundById() here | this.createSound = function(id, url) {
var thisSound; |
| if id exist in self.playlist, return the corresponding sound object already created | if (self.playlist[id]){
thisSound = self.playlist[id];
} else { |
| create sound | thisSound = sm.createSound({
id:'awesome'+id,
url:url,
onplay:self.events.play,
onstop:self.events.stop,
onpause:self.events.pause,
onresume:self.events.resume,
onfinish:self.events.finish,
whileloading:self.events.whileloading,
whileplaying:self.events.whileplaying,
onid3:self.events.id3,
onload:self.events.onload,
autoPlay: false
});
self.playlist[id] = thisSound;
}
return thisSound;
};
|
| Play the next sound object in the playlist and return it | this.playNext = function(){
var next;
if (self.playlist.currentlyPlaying + 1 >= self.config.playlist.length){
next = 0;
} else {
next = self.playlist.currentlyPlaying + 1;
}
return self.playById(next);
};
|
| Play the previous sound object in the playlist and return it | this.playPrevious = function(){ |
| get previous | var previous;
if (self.playlist.currentlyPlaying - 1 < 0){
previous = self.config.playlist.length - 1;
} else {
previous = self.playlist.currentlyPlaying - 1;
}
return self.playById(previous);
};
|
| Play the sound object with id as id Parameters: id (Integer) - playlist id of the sound object to be played | this.playById = function(id){
if (self.sound.sID) {
self.sound.stop();
self.sound.unload();
}
if (self.config.playlist[id]) {
self.playlist.currentlyPlaying = id;
self.sound = self.createSound(id, self.config.playlist[id]);
self.sound.play();
return self.sound;
}
};
|
| converts milliseconds into human readable form @todo variable names | this.getTime = function(milliseconds){
var seconds = Math.floor(milliseconds/1000),
minutes = Math.floor(seconds/60);
seconds = seconds - (minutes*60);
return minutes + ':' + (seconds < 10 ? '0' + seconds : seconds);
};
|
| Initialize the player | this.init = function (config) {
var sound;
if (config) {
$.extend(this.config, config);
}
|
| Check if flash version is greate than 9 if yes, then set sm.defaultOptions.usePeakData to true |
if (sm.flashVersion >= 9) {
sm.defaultOptions.usePeakData = this.config.usePeakData;
}
self.playById(0);
self.bindEvents();
};
}
|