1000 lines
No EOL
20 KiB
JavaScript
1000 lines
No EOL
20 KiB
JavaScript
/**
|
|
* jquery.cxassette.js v1.0.0
|
|
* http://www.codrops.com
|
|
*
|
|
* Licensed under the MIT license.
|
|
* http://www.opensource.org/licenses/mit-license.php
|
|
*
|
|
* Copyright 2012, Codrops
|
|
* http://www.codrops.com
|
|
*/
|
|
|
|
( function( window, $, undefined ) {
|
|
|
|
var aux = {
|
|
|
|
getSupportedType : function() {
|
|
|
|
var audio = document.createElement( 'audio' );
|
|
|
|
if ( audio.canPlayType('audio/mpeg;') ) {
|
|
|
|
return 'mp3';
|
|
|
|
}
|
|
else if ( audio.canPlayType('audio/ogg;') ) {
|
|
|
|
return 'ogg';
|
|
|
|
}
|
|
else {
|
|
|
|
return 'wav';
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
// Cassette obj
|
|
$.Cassette = function( options, element ) {
|
|
|
|
this.$el = $( element );
|
|
this._init( options );
|
|
|
|
};
|
|
|
|
$.Cassette.defaults = {
|
|
// song names. Assumes the path of each song is songs/name.filetype
|
|
songs : [ 'BlueDucks_FourFlossFiveSix', 'BlankKytt_ThursdaySnowReprise', 'BlueDucks_FlossSuffersFromGammaRadiation', 'BlankKyt_RSPN' ],
|
|
fallbackMessage : 'HTML5 audio not supported',
|
|
// initial sound volume
|
|
initialVolume : 0.7
|
|
};
|
|
|
|
$.Cassette.prototype = {
|
|
|
|
_init : function( options ) {
|
|
|
|
var _self = this;
|
|
|
|
// the options
|
|
this.options = $.extend( true, {}, $.Cassette.defaults, options );
|
|
|
|
// current side of the tape
|
|
this.currentSide = 1;
|
|
// current time of playing side
|
|
this.cntTime = 0;
|
|
// current sum of the duration of played songs
|
|
this.timeIterator = 0;
|
|
// used for rewind / forward
|
|
this.elapsed = 0.0;
|
|
// action performed
|
|
this.lastaction = '';
|
|
// if play / forward / rewind active..
|
|
this.isMoving = false;
|
|
|
|
this.$loader = this.$el.find( 'div.vc-loader' ).show();
|
|
|
|
// create cassette sides
|
|
$.when( this._createSides() ).done( function() {
|
|
|
|
_self.$loader.hide();
|
|
|
|
// create player
|
|
_self._createPlayer();
|
|
_self.sound = new $.Sound();
|
|
// load events
|
|
_self._loadEvents();
|
|
|
|
} );
|
|
|
|
},
|
|
_getSide : function() {
|
|
|
|
return ( this.currentSide === 1 ) ? {
|
|
current : this.side1,
|
|
reverse : this.side2
|
|
} : {
|
|
current : this.side2,
|
|
reverse : this.side1
|
|
};
|
|
|
|
},
|
|
// songs are distributed equally on both sides
|
|
_createSides : function() {
|
|
|
|
var playlistSide1 = [],
|
|
playlistSide2 = [],
|
|
_self = this,
|
|
cnt = 0;
|
|
|
|
return $.Deferred(
|
|
|
|
function( dfd ) {
|
|
|
|
for( var i = 0, len = _self.options.songs.length; i < len; ++i ) {
|
|
|
|
var song = new $.Song( _self.options.songs[i], i );
|
|
|
|
$.when( song.loadMetadata() ).done( function( song ) {
|
|
|
|
( song.id < len / 2 ) ? playlistSide1.push( song ) : playlistSide2.push( song );
|
|
|
|
++cnt;
|
|
|
|
if( cnt === len ) {
|
|
|
|
// two sides, each side with multiple songs
|
|
_self.side1 = new $.Side( 'side1', playlistSide1, 'start' ),
|
|
_self.side2 = new $.Side( 'side2', playlistSide2, 'end' );
|
|
|
|
dfd.resolve();
|
|
|
|
}
|
|
|
|
} );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
).promise();
|
|
|
|
},
|
|
_createPlayer : function() {
|
|
|
|
// create HTML5 audio element
|
|
this.$audioEl = $( '<audio id="audioElem"><span>' + this.options.fallbackMessage + '</span></audio>' );
|
|
this.$el.prepend( this.$audioEl );
|
|
|
|
this.audio = this.$audioEl.get(0);
|
|
|
|
// create custom controls
|
|
this._createControls();
|
|
|
|
this.$theTape = this.$el.find( 'div.vc-tape' );
|
|
this.$wheelLeft = this.$theTape.find( 'div.vc-tape-wheel-left' );
|
|
this.$wheelRight= this.$theTape.find( 'div.vc-tape-wheel-right' );
|
|
this.$tapeSideA = this.$theTape.find( 'div.vc-tape-side-a' ).show();
|
|
this.$tapeSideB = this.$theTape.find( 'div.vc-tape-side-b' );
|
|
|
|
},
|
|
_createControls : function() {
|
|
|
|
var _self = this;
|
|
|
|
this.$controls = $( '<ul class="vc-controls" style="display:none;"/>' );
|
|
|
|
this.$cPlay = $( '<li class="vc-control-play">Play<span></span></li>' );
|
|
this.$cRewind = $( '<li class="vc-control-rewind">Rew<span></span></li>' );
|
|
this.$cForward = $( '<li class="vc-control-fforward">FF<span></span></li>' );
|
|
this.$cStop = $( '<li class="vc-control-stop">Stop<span></span></li>' );
|
|
this.$cSwitch = $( '<li class="vc-control-switch">Switch<span></span></li>' );
|
|
|
|
this.$controls.append( this.$cPlay )
|
|
.append( this.$cRewind )
|
|
.append( this.$cForward )
|
|
.append( this.$cStop )
|
|
.append( this.$cSwitch )
|
|
.appendTo( this.$el );
|
|
|
|
this.$volume = $( '<div style="display:none;" class="vc-volume-wrap"><div class="vc-volume-control"><div class="vc-volume-knob"></div></div></div> ').appendTo( this.$el );
|
|
|
|
if (document.createElement('audio').canPlayType) {
|
|
|
|
if (!document.createElement('audio').canPlayType('audio/mpeg') && !document.createElement('audio').canPlayType('audio/ogg')) {
|
|
|
|
// TODO: flash fallback!
|
|
|
|
}
|
|
else {
|
|
|
|
this.$controls.show();
|
|
this.$volume.show();
|
|
this.$volume.find( 'div.vc-volume-knob' ).knobKnob({
|
|
snap : 10,
|
|
value: 359 * this.options.initialVolume,
|
|
turn : function( ratio ) {
|
|
|
|
_self._changeVolume( ratio );
|
|
|
|
}
|
|
});
|
|
|
|
this.audio.volume = this.options.initialVolume;
|
|
}
|
|
|
|
}
|
|
|
|
},
|
|
_loadEvents : function() {
|
|
|
|
var _self = this;
|
|
|
|
this.$cSwitch.on( 'mousedown', function( event ) {
|
|
|
|
_self._setButtonActive( $( this ) );
|
|
_self._switchSides();
|
|
|
|
} );
|
|
|
|
this.$cPlay.on( 'mousedown', function( event ) {
|
|
|
|
_self._setButtonActive( $( this ) );
|
|
_self._play();
|
|
|
|
} );
|
|
|
|
this.$cStop.on( 'mousedown', function( event ) {
|
|
|
|
_self._setButtonActive( $( this ) );
|
|
_self._stop();
|
|
|
|
} );
|
|
|
|
this.$cForward.on( 'mousedown', function( event ) {
|
|
|
|
_self._setButtonActive( $( this ) );
|
|
_self._forward();
|
|
|
|
} );
|
|
|
|
this.$cRewind.on( 'mousedown', function( event ) {
|
|
|
|
_self._setButtonActive( $( this ) );
|
|
_self._rewind();
|
|
|
|
} );
|
|
|
|
this.$audioEl.on( 'timeupdate', function( event ) {
|
|
|
|
_self.cntTime = _self.timeIterator + _self.audio.currentTime;
|
|
var wheelVal = _self._getWheelValues( _self.cntTime );
|
|
_self._updateWheelValue( wheelVal );
|
|
|
|
});
|
|
|
|
this.$audioEl.on( 'loadedmetadata', function( event ) {
|
|
|
|
});
|
|
|
|
this.$audioEl.on( 'ended', function( event ) {
|
|
|
|
_self.timeIterator += _self.audio.duration;
|
|
_self._play();
|
|
|
|
});
|
|
|
|
},
|
|
_setButtonActive : function( $button ) {
|
|
|
|
// TODO. Solve! For now:
|
|
$button.addClass( 'vc-control-pressed' );
|
|
|
|
setTimeout( function() {
|
|
|
|
$button.removeClass( 'vc-control-pressed' );
|
|
|
|
}, 100 );
|
|
|
|
},
|
|
_updateAction : function( action ) {
|
|
|
|
this.lastaction = action;
|
|
|
|
},
|
|
_prepare : function( song ) {
|
|
|
|
this._clear();
|
|
this.$audioEl.attr( 'src', song.getSource( aux.getSupportedType() ) );
|
|
|
|
},
|
|
_switchSides : function() {
|
|
|
|
if( this.isMoving ) {
|
|
|
|
alert( 'Please stop the player before switching sides.' );
|
|
return false;
|
|
|
|
}
|
|
|
|
this.sound.play( 'switch' );
|
|
|
|
var _self = this;
|
|
|
|
this.lastaction = '';
|
|
|
|
if( this.currentSide === 1 ) {
|
|
|
|
this.currentSide = 2;
|
|
|
|
this.$theTape.css( {
|
|
'-webkit-transform' : 'rotate3d(0, 1, 0, 180deg)',
|
|
'-moz-transform' : 'rotate3d(0, 1, 0, 180deg)',
|
|
'-o-transform' : 'rotate3d(0, 1, 0, 180deg)',
|
|
'-ms-transform' : 'rotate3d(0, 1, 0, 180deg)',
|
|
'transform' : 'rotate3d(0, 1, 0, 180deg)'
|
|
} );
|
|
|
|
setTimeout( function() {
|
|
|
|
_self.$tapeSideA.hide();
|
|
_self.$tapeSideB.show();
|
|
|
|
// update wheels
|
|
_self.cntTime = _self._getPosTime();
|
|
|
|
}, 200 );
|
|
|
|
}
|
|
else {
|
|
|
|
this.currentSide = 1;
|
|
|
|
this.$theTape.css( {
|
|
'-webkit-transform' : 'rotate3d(0, 1, 0, 0deg)',
|
|
'-moz-transform' : 'rotate3d(0, 1, 0, 0deg)',
|
|
'-o-transform' : 'rotate3d(0, 1, 0, 0deg)',
|
|
'-ms-transform' : 'rotate3d(0, 1, 0, 0deg)',
|
|
'transform' : 'rotate3d(0, 1, 0, 0deg)'
|
|
} );
|
|
|
|
setTimeout( function() {
|
|
|
|
_self.$tapeSideB.hide();
|
|
_self.$tapeSideA.show();
|
|
|
|
// update wheels
|
|
_self.cntTime = _self._getPosTime();
|
|
|
|
}, 200 );
|
|
|
|
}
|
|
|
|
},
|
|
_updateButtons : function( button ) {
|
|
|
|
var pressedClass = 'vc-control-active';
|
|
|
|
this.$cPlay.removeClass( pressedClass );
|
|
this.$cStop.removeClass( pressedClass );
|
|
this.$cRewind.removeClass( pressedClass );
|
|
this.$cForward.removeClass( pressedClass );
|
|
|
|
switch( button ) {
|
|
|
|
case 'play' : this.$cPlay.addClass( pressedClass ); break;
|
|
case 'rewind' : this.$cRewind.addClass( pressedClass ); break;
|
|
case 'forward' : this.$cForward.addClass( pressedClass ); break;
|
|
|
|
}
|
|
|
|
},
|
|
_changeVolume : function( ratio ) {
|
|
|
|
this.audio.volume = ratio;
|
|
|
|
},
|
|
_play : function() {
|
|
|
|
var _self = this;
|
|
|
|
this._updateButtons( 'play' );
|
|
|
|
$.when( this.sound.play( 'click' ) ).done( function() {
|
|
|
|
var data = _self._updateStatus();
|
|
|
|
if( data ) {
|
|
|
|
_self._prepare( _self._getSide().current.getSong( data.songIdx ) );
|
|
|
|
_self.$audioEl.on( 'canplay', function( event ) {
|
|
|
|
$( this ).off( 'canplay' );
|
|
|
|
_self.audio.currentTime = data.timeInSong;
|
|
_self.audio.play();
|
|
_self.isMoving = true;
|
|
|
|
_self._setWheelAnimation( '2s', 'play' );
|
|
|
|
});
|
|
|
|
}
|
|
|
|
} );
|
|
|
|
},
|
|
_updateStatus : function( buttons ) {
|
|
|
|
var posTime = this.cntTime;
|
|
|
|
// first stop
|
|
this._stop( true );
|
|
|
|
this._setSidesPosStatus( 'middle' );
|
|
|
|
// the current time to play is this.cntTime +/- [this.elapsed]
|
|
if( this.lastaction === 'forward' ) {
|
|
|
|
posTime += this.elapsed;
|
|
|
|
}
|
|
else if( this.lastaction === 'rewind' ) {
|
|
|
|
posTime -= this.elapsed;
|
|
|
|
}
|
|
|
|
// check if we have more songs to play on the current side..
|
|
if( posTime >= this._getSide().current.getDuration() ) {
|
|
|
|
this._stop( buttons );
|
|
this._setSidesPosStatus( 'end' );
|
|
return false;
|
|
|
|
}
|
|
|
|
this._resetElapsed();
|
|
|
|
// given this, we need to know which song is playing at this point in time,
|
|
// and from which point in time within the song we will play
|
|
var data = this._getSongInfoByTime( posTime );
|
|
|
|
// update cntTime
|
|
this.cntTime = posTime;
|
|
// update timeIterator
|
|
this.timeIterator = data.iterator;
|
|
|
|
return data;
|
|
|
|
},
|
|
_rewind : function() {
|
|
|
|
var _self = this,
|
|
action = 'rewind';
|
|
|
|
if( this._getSide().current.getPositionStatus() === 'start' ) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
this._updateButtons( action );
|
|
|
|
$.when( this.sound.play( 'click' ) ).done( function() {
|
|
|
|
_self._updateStatus( true );
|
|
_self.isMoving = true;
|
|
|
|
_self._updateAction( action );
|
|
_self.sound.play( 'rewind', true );
|
|
_self._setWheelAnimation( '0.5s', action );
|
|
_self._timer();
|
|
|
|
} );
|
|
|
|
},
|
|
_forward : function() {
|
|
|
|
var _self = this,
|
|
action = 'forward';
|
|
|
|
if( this._getSide().current.getPositionStatus() === 'end' ) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
this._updateButtons( action );
|
|
|
|
$.when( this.sound.play( 'click' ) ).done( function() {
|
|
|
|
_self._updateStatus( true );
|
|
_self.isMoving = true;
|
|
|
|
_self._updateAction( action );
|
|
_self.sound.play( 'fforward', true );
|
|
_self._setWheelAnimation( '0.5s', action );
|
|
_self._timer();
|
|
|
|
} );
|
|
|
|
},
|
|
_stop : function( buttons ) {
|
|
|
|
if( !buttons ) {
|
|
|
|
this._updateButtons( 'stop' );
|
|
this.sound.play( 'click' );
|
|
|
|
}
|
|
this.isMoving = false;
|
|
this._stopWheels();
|
|
this.audio.pause();
|
|
this._stopTimer();
|
|
|
|
},
|
|
_clear : function() {
|
|
|
|
this.$audioEl.children( 'source' ).remove();
|
|
|
|
},
|
|
_setSidesPosStatus : function( position ) {
|
|
|
|
this._getSide().current.setPositionStatus( position );
|
|
|
|
switch( position ) {
|
|
|
|
case 'middle' : this._getSide().reverse.setPositionStatus( position );break;
|
|
case 'start' : this._getSide().reverse.setPositionStatus( 'end' );break;
|
|
case 'end' : this._getSide().reverse.setPositionStatus( 'start' );break;
|
|
|
|
}
|
|
|
|
},
|
|
// given a point in time for the current side, returns the respective song of that side and the respective time within the song
|
|
_getSongInfoByTime : function( time ) {
|
|
|
|
var data = { songIdx : 0, timeInSong : 0 },
|
|
side = this._getSide().current,
|
|
playlist = side.getPlaylist(),
|
|
len = side.getPlaylistCount(),
|
|
cntTime = 0;
|
|
|
|
for( var i = 0; i < len; ++i ) {
|
|
|
|
var song = playlist[ i ],
|
|
duration = song.getDuration();
|
|
|
|
cntTime += duration;
|
|
|
|
if( cntTime > time ) {
|
|
|
|
data.songIdx = i;
|
|
data.timeInSong = time - ( cntTime - duration );
|
|
data.iterator = cntTime - duration;
|
|
|
|
return data;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return data;
|
|
|
|
},
|
|
_getWheelValues : function( x ) {
|
|
|
|
var T = this._getSide().current.getDuration(),
|
|
val = {
|
|
left : ( this.currentSide === 1 ) ? ( -70 / T ) * x + 70 : ( 70 / T ) * x,
|
|
right : ( this.currentSide === 1 ) ? ( 70 / T ) * x : ( -70 / T ) * x + 70
|
|
};
|
|
return val;
|
|
|
|
},
|
|
_getPosTime : function() {
|
|
|
|
var wleft = this.$wheelLeft.data( 'wheel' ),
|
|
wright = this.$wheelRight.data( 'wheel' );
|
|
|
|
if( wleft === undefined ) {
|
|
|
|
wleft = 70;
|
|
|
|
}
|
|
if( wright === undefined ) {
|
|
|
|
wright = 0;
|
|
|
|
}
|
|
|
|
var T = this._getSide().current.getDuration(),
|
|
posTime = this.currentSide === 2 ? ( T * wleft ) / 70 : ( T * wright ) / 70;
|
|
|
|
return posTime;
|
|
|
|
},
|
|
_updateWheelValue : function( wheelVal ) {
|
|
|
|
this.$wheelLeft.data( 'wheel', wheelVal.left ).css( { 'box-shadow' : '0 0 0 ' + wheelVal.left + 'px black' } );
|
|
this.$wheelRight.data( 'wheel', wheelVal.right ).css( { 'box-shadow' : '0 0 0 ' + wheelVal.right + 'px black' } );
|
|
|
|
},
|
|
_setWheelAnimation : function( speed, mode ) {
|
|
|
|
var _self = this, anim = '';
|
|
|
|
switch( this.currentSide ) {
|
|
|
|
case 1 :
|
|
if( mode === 'play' || mode === 'forward' ) {
|
|
anim = 'rotateLeft';
|
|
}
|
|
else if( mode === 'rewind' ) {
|
|
anim = 'rotateRight';
|
|
}
|
|
break;
|
|
case 2 :
|
|
if( mode === 'play' || mode === 'forward' ) {
|
|
anim = 'rotateRight';
|
|
}
|
|
else if( mode === 'rewind' ) {
|
|
anim = 'rotateLeft';
|
|
}
|
|
break;
|
|
|
|
}
|
|
|
|
var animStyle = {
|
|
'-webkit-animation' : anim + ' ' + speed + ' linear infinite forwards',
|
|
'-moz-animation' : anim + ' ' + speed + ' linear infinite forwards',
|
|
'-o-animation' : anim + ' ' + speed + ' linear infinite forwards',
|
|
'-ms-animation' : anim + ' ' + speed + ' linear infinite forwards',
|
|
'animation' : anim + ' ' + speed + ' linear infinite forwards'
|
|
};
|
|
|
|
setTimeout( function() {
|
|
|
|
_self.$wheelLeft.css(animStyle);
|
|
_self.$wheelRight.css(animStyle);
|
|
|
|
}, 0 );
|
|
|
|
},
|
|
_stopWheels : function() {
|
|
|
|
var wheelStyle = {
|
|
'-webkit-animation' : 'none',
|
|
'-moz-animation' : 'none',
|
|
'-o-animation' : 'none',
|
|
'-ms-animation' : 'none',
|
|
'animation' : 'none'
|
|
}
|
|
|
|
this.$wheelLeft.css( wheelStyle );
|
|
this.$wheelRight.css( wheelStyle );
|
|
|
|
},
|
|
// credits: http://www.sitepoint.com/creating-accurate-timers-in-javascript/
|
|
_timer : function() {
|
|
|
|
var _self = this,
|
|
start = new Date().getTime(),
|
|
time = 0;
|
|
|
|
this._resetElapsed();
|
|
|
|
this.isSeeking = true;
|
|
|
|
this._setSidesPosStatus( 'middle' );
|
|
|
|
if( this.isSeeking ) {
|
|
|
|
clearTimeout( this.timertimeout );
|
|
this.timertimeout = setTimeout( function() {
|
|
|
|
_self._timerinstance( start, time );
|
|
|
|
}, 100 );
|
|
|
|
}
|
|
|
|
},
|
|
_timerinstance : function( start, time ) {
|
|
|
|
var _self = this;
|
|
|
|
time += 100;
|
|
|
|
this.elapsed = Math.floor(time / 20) / 10;
|
|
|
|
if( Math.round( this.elapsed ) == this.elapsed ) {
|
|
|
|
this.elapsed += 0.0;
|
|
|
|
}
|
|
|
|
// stop if it reaches the end of the cassette / side
|
|
// or if it reaches the beginning
|
|
var posTime = this.cntTime;
|
|
|
|
if( this.lastaction === 'forward' ) {
|
|
|
|
posTime += this.elapsed;
|
|
|
|
}
|
|
else if( this.lastaction === 'rewind' ) {
|
|
|
|
posTime -= this.elapsed;
|
|
|
|
}
|
|
|
|
var wheelVal = this._getWheelValues( posTime );
|
|
this._updateWheelValue( wheelVal );
|
|
|
|
if( posTime >= this._getSide().current.getDuration() || posTime <= 0 ) {
|
|
|
|
this._stop();
|
|
( posTime <= 0) ? this.cntTime = 0 : this.cntTime = posTime;
|
|
this._resetElapsed();
|
|
( posTime <= 0) ? this._setSidesPosStatus( 'start' ) : this._setSidesPosStatus( 'end' );
|
|
return false;
|
|
|
|
}
|
|
|
|
var diff = (new Date().getTime() - start) - time;
|
|
|
|
if( this.isSeeking ) {
|
|
|
|
clearTimeout( this.timertimeout );
|
|
this.timertimeout = setTimeout( function() {
|
|
|
|
_self._timerinstance( start, time );
|
|
|
|
}, ( 100 - diff ) );
|
|
|
|
}
|
|
|
|
},
|
|
_stopTimer : function() {
|
|
|
|
clearTimeout( this.timertimeout );
|
|
this.isSeeking = false;
|
|
|
|
},
|
|
_resetElapsed : function() {
|
|
|
|
this.elapsed = 0.0;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
// Cassette side obj
|
|
$.Side = function( id, playlist, status ) {
|
|
|
|
// side's name / id
|
|
this.id = id;
|
|
// status is "start", "middle" or "end"
|
|
this.status = status;
|
|
// array of songs sorted by song id
|
|
this.playlist = playlist.sort( function( a, b ) {
|
|
|
|
var aid = a.id,
|
|
bid = b.id;
|
|
|
|
return ( ( aid < bid ) ? -1 : ( ( aid > bid ) ? 1 : 0 ) );
|
|
|
|
} );
|
|
// set playlist duration
|
|
this._setDuration();
|
|
// total number of songs
|
|
this.playlistCount = playlist.length;
|
|
|
|
};
|
|
|
|
$.Side.prototype = {
|
|
|
|
getSong : function( num ) {
|
|
|
|
return this.playlist[ num ];
|
|
|
|
},
|
|
getPlaylist : function() {
|
|
|
|
return this.playlist;
|
|
|
|
},
|
|
_setDuration : function() {
|
|
|
|
this.duration = 0;
|
|
|
|
for( var i = 0, len = this.playlist.length; i < len; ++i ) {
|
|
|
|
this.duration += this.playlist[ i ].duration;
|
|
|
|
}
|
|
|
|
},
|
|
getDuration : function() {
|
|
|
|
return this.duration;
|
|
|
|
},
|
|
getPlaylistCount : function() {
|
|
|
|
return this.playlistCount;
|
|
|
|
},
|
|
setPositionStatus : function( status ) {
|
|
|
|
this.status = status;
|
|
|
|
},
|
|
getPositionStatus : function() {
|
|
|
|
return this.status;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
// Song obj
|
|
$.Song = function( name, id ) {
|
|
|
|
this.id = id;
|
|
this.name = name;
|
|
this._init();
|
|
|
|
};
|
|
|
|
$.Song.prototype = {
|
|
|
|
_init : function() {
|
|
|
|
this.sources = {
|
|
mp3 : 'songs/' + this.name + '.mp3',
|
|
ogg : 'songs/' + this.name + '.ogg'
|
|
};
|
|
|
|
},
|
|
getSource : function( type ) {
|
|
|
|
return this.sources[type];
|
|
|
|
},
|
|
// load metadata to get the duration of the song
|
|
loadMetadata : function() {
|
|
|
|
var _self = this;
|
|
|
|
return $.Deferred(
|
|
|
|
function( dfd ) {
|
|
|
|
var $tmpAudio = $( '<audio/>' ),
|
|
songsrc = _self.getSource( aux.getSupportedType() );
|
|
|
|
$tmpAudio.attr( 'preload', 'auto' );
|
|
$tmpAudio.attr( 'src', songsrc );
|
|
|
|
$tmpAudio.on( 'loadedmetadata', function( event ) {
|
|
|
|
_self.duration = $tmpAudio.get(0).duration;
|
|
dfd.resolve( _self );
|
|
|
|
});
|
|
|
|
}
|
|
|
|
).promise();
|
|
|
|
},
|
|
getDuration : function() {
|
|
|
|
return this.duration;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
// Sound obj
|
|
$.Sound = function() {
|
|
|
|
this._init();
|
|
|
|
};
|
|
|
|
$.Sound.prototype = {
|
|
|
|
_init : function() {
|
|
|
|
this.$audio = $( '<audio/>' ).attr( 'preload', 'auto' );
|
|
|
|
},
|
|
getSource : function( type ) {
|
|
|
|
return 'sounds/' + this.action + '.' + type;
|
|
|
|
},
|
|
play : function( action, loop ) {
|
|
|
|
var _self = this;
|
|
return $.Deferred( function( dfd ) {
|
|
|
|
_self.action = action;
|
|
|
|
var soundsrc = _self.getSource( aux.getSupportedType() );
|
|
|
|
_self.$audio.attr( 'src', soundsrc );
|
|
if( loop ) {
|
|
|
|
_self.$audio.attr( 'loop', loop );
|
|
|
|
}
|
|
else {
|
|
|
|
_self.$audio.removeAttr( 'loop' );
|
|
|
|
}
|
|
|
|
_self.$audio.on( 'canplay', function( event ) {
|
|
|
|
// TODO: change timeout to ended event . ended event does not trigger for safari ?
|
|
setTimeout( function() {
|
|
|
|
dfd.resolve();
|
|
|
|
}, 500 );
|
|
$( this ).get(0).play();
|
|
|
|
});
|
|
|
|
});
|
|
|
|
}
|
|
|
|
};
|
|
|
|
var logError = function( message ) {
|
|
|
|
if ( window.console ) {
|
|
|
|
window.console.error( message );
|
|
|
|
}
|
|
|
|
};
|
|
|
|
$.fn.cassette = function( options ) {
|
|
|
|
if ( typeof options === 'string' ) {
|
|
|
|
var args = Array.prototype.slice.call( arguments, 1 );
|
|
|
|
this.each(function() {
|
|
|
|
var instance = $.data( this, 'cassette' );
|
|
|
|
if ( !instance ) {
|
|
|
|
logError( "cannot call methods on cassette prior to initialization; " +
|
|
"attempted to call method '" + options + "'" );
|
|
return;
|
|
|
|
}
|
|
|
|
if ( !$.isFunction( instance[options] ) || options.charAt(0) === "_" ) {
|
|
|
|
logError( "no such method '" + options + "' for cassette instance" );
|
|
return;
|
|
|
|
}
|
|
|
|
instance[ options ].apply( instance, args );
|
|
|
|
});
|
|
|
|
}
|
|
else {
|
|
|
|
this.each(function() {
|
|
|
|
var instance = $.data( this, 'cassette' );
|
|
if ( !instance ) {
|
|
$.data( this, 'cassette', new $.Cassette( options, this ) );
|
|
}
|
|
});
|
|
|
|
}
|
|
|
|
return this;
|
|
|
|
};
|
|
|
|
} )( window, jQuery ); |