Click here to Skip to main content
15,886,075 members
Articles / Web Development / HTML

Audio-Gallery-Suite (A complete audio gallery solution made with HTML5/CSS3/jQuery-JS/PHP/C#)

Rate me:
Please Sign up or sign in to vote.
4.99/5 (82 votes)
30 Apr 2013MIT31 min read 268.5K   6.3K   171  
Audio-Gallery-Suite is a complete audio gallery solution made with HTML5/CSS3/Jquery-JS/PHP-Ajax/C# that includes a web audio gallery and a software for managing the web audio gallery.
/*
 * CirclePlayer for the jPlayer Plugin (jQuery)
 * http://www.jplayer.org
 *
 * Copyright (c) 2009 - 2012 Happyworm Ltd
 * Dual licensed under the MIT and GPL licenses.
 *  - http://www.opensource.org/licenses/mit-license.php
 *  - http://www.gnu.org/copyleft/gpl.html
 *
 * Version: 1.0.1 (jPlayer 2.1.0+)
 * Date: 30th May 2011
 *
 * Author: Mark J Panaghiston @thepag
 *
 * CirclePlayer prototype developed by:
 * Mark Boas @maboa
 * Silvia Benvenuti @aulentina
 * Jussi Kalliokoski @quinirill
 *
 * Inspired by :
 * Neway @imneway http://imneway.net/ http://forrst.com/posts/Untitled-CPt
 * and
 * Liam McKay @liammckay http://dribbble.com/shots/50882-Purple-Play-Pause
 *
 * Standing on the shoulders of :
 * John Resig @jresig
 * Mark Panaghiston @thepag
 * Louis-Rémi Babé @Louis_Remi
 */


var CirclePlayer = function(jPlayerSelector, media, options) {
	var	self = this,

		defaults = {
			// solution: "flash, html", // For testing Flash with CSS3
			supplied: "m4a, oga",
			// Android 2.3 corrupts media element if preload:"none" is used.
			// preload: "none", // No point preloading metadata since no times are displayed. It helps keep the buffer state correct too.
			cssSelectorAncestor: "#cp_container_1",
			cssSelector: {
				play: ".cp-play",
				pause: ".cp-pause"
			}
		},

		cssSelector = {
			bufferHolder: ".cp-buffer-holder",
			buffer1: ".cp-buffer-1",
			buffer2: ".cp-buffer-2",
			progressHolder: ".cp-progress-holder",
			progress1: ".cp-progress-1",
			progress2: ".cp-progress-2",
			circleControl: ".cp-circle-control"
		};

	this.cssClass = {
		gt50: "cp-gt50",
		fallback: "cp-fallback"
	};

	this.spritePitch = 104;
	this.spriteRatio = 0.24; // Number of steps / 100

	this.player = $(jPlayerSelector);
	this.media = $.extend({}, media);
	this.options = $.extend(true, {}, defaults, options); // Deep copy

	this.cssTransforms = Modernizr.csstransforms;
	this.audio = {};
	this.dragging = false; // Indicates if the progressbar is being 'dragged'.

	this.eventNamespace = ".CirclePlayer"; // So the events can easily be removed in destroy.

	this.jq = {};
	$.each(cssSelector, function(entity, cssSel) {
		self.jq[entity] = $(self.options.cssSelectorAncestor + " " + cssSel);
	});

	this._initSolution();
	this._initPlayer();
};

CirclePlayer.prototype = {
	_createHtml: function() {
	},
	_initPlayer: function() {
		var self = this;
		this.player.jPlayer(this.options);

		this.player.bind($.jPlayer.event.ready + this.eventNamespace, function(event) {
			if(event.jPlayer.html.used && event.jPlayer.html.audio.available) {
				self.audio = $(this).data("jPlayer").htmlElement.audio;
			}
			$(this).jPlayer("setMedia", self.media);
			self._initCircleControl();
		});

		this.player.bind($.jPlayer.event.play + this.eventNamespace, function(event) {
			$(this).jPlayer("pauseOthers");
		});

		// This event fired as play time increments
		this.player.bind($.jPlayer.event.timeupdate + this.eventNamespace, function(event) {
			if (!self.dragging) {
				self._timeupdate(event.jPlayer.status.currentPercentAbsolute);
			}
		});

		// This event fired as buffered time increments
		this.player.bind($.jPlayer.event.progress + this.eventNamespace, function(event) {
			var percent = 0;
			if((typeof self.audio.buffered === "object") && (self.audio.buffered.length > 0)) {
				if(self.audio.duration > 0) {
					var bufferTime = 0;
					for(var i = 0; i < self.audio.buffered.length; i++) {
						bufferTime += self.audio.buffered.end(i) - self.audio.buffered.start(i);
						// console.log(i + " | start = " + self.audio.buffered.start(i) + " | end = " + self.audio.buffered.end(i) + " | bufferTime = " + bufferTime + " | duration = " + self.audio.duration);
					}
					percent = 100 * bufferTime / self.audio.duration;
				} // else the Metadata has not been read yet.
				// console.log("percent = " + percent);
			} else { // Fallback if buffered not supported
				// percent = event.jPlayer.status.seekPercent;
				percent = 0; // Cleans up the inital conditions on all browsers, since seekPercent defaults to 100 when object is undefined.
			}
			self._progress(percent); // Problem here at initial condition. Due to the Opera clause above of buffered.length > 0 above... Removing it means Opera's white buffer ring never shows like with polyfill.
			// Firefox 4 does not always give the final progress event when buffered = 100%
		});

		this.player.bind($.jPlayer.event.ended + this.eventNamespace, function(event) {
			self._resetSolution();
		});
	},
	_initSolution: function() {
		if (this.cssTransforms) {
			this.jq.progressHolder.show();
			this.jq.bufferHolder.show();
		}
		else {
			this.jq.progressHolder.addClass(this.cssClass.gt50).show();
			this.jq.progress1.addClass(this.cssClass.fallback);
			this.jq.progress2.hide();
			this.jq.bufferHolder.hide();
		}
		this._resetSolution();
	},
	_resetSolution: function() {
		if (this.cssTransforms) {
			this.jq.progressHolder.removeClass(this.cssClass.gt50);
			this.jq.progress1.css({'transform': 'rotate(0deg)'});
			this.jq.progress2.css({'transform': 'rotate(0deg)'}).hide();
		}
		else {
			this.jq.progress1.css('background-position', '0 ' + this.spritePitch + 'px');
		}
	},
	_initCircleControl: function() {
		var self = this;
		this.jq.circleControl.grab({
			onstart: function(){
				self.dragging = true;
			}, onmove: function(event){
				var pc = self._getArcPercent(event.position.x, event.position.y);
				self.player.jPlayer("playHead", pc).jPlayer("play");
				self._timeupdate(pc);
			}, onfinish: function(event){
				self.dragging = false;
				var pc = self._getArcPercent(event.position.x, event.position.y);
				self.player.jPlayer("playHead", pc).jPlayer("play");
			}
		});
	},
	_timeupdate: function(percent) {
		var degs = percent * 3.6+"deg";

		var spriteOffset = (Math.floor((Math.round(percent))*this.spriteRatio)-1)*-this.spritePitch;

		if (percent <= 50) {
			if (this.cssTransforms) {
				this.jq.progressHolder.removeClass(this.cssClass.gt50);
				this.jq.progress1.css({'transform': 'rotate(' + degs + ')'});
				this.jq.progress2.hide();
			} else { // fall back
				this.jq.progress1.css('background-position', '0 '+spriteOffset+'px');
			}
		} else if (percent <= 100) {
			if (this.cssTransforms) {
				this.jq.progressHolder.addClass(this.cssClass.gt50);
				this.jq.progress1.css({'transform': 'rotate(180deg)'});
				this.jq.progress2.css({'transform': 'rotate(' + degs + ')'});
				this.jq.progress2.show();
			} else { // fall back
				this.jq.progress1.css('background-position', '0 '+spriteOffset+'px');
			}
		}
	},
	_progress: function(percent) {
		var degs = percent * 3.6+"deg";

		if (this.cssTransforms) {
			if (percent <= 50) {
				this.jq.bufferHolder.removeClass(this.cssClass.gt50);
				this.jq.buffer1.css({'transform': 'rotate(' + degs + ')'});
				this.jq.buffer2.hide();
			} else if (percent <= 100) {
				this.jq.bufferHolder.addClass(this.cssClass.gt50);
				this.jq.buffer1.css({'transform': 'rotate(180deg)'});
				this.jq.buffer2.show();
				this.jq.buffer2.css({'transform': 'rotate(' + degs + ')'});
			}
		}
	},
	_getArcPercent: function(pageX, pageY) {
		var	offset	= this.jq.circleControl.offset(),
			x	= pageX - offset.left - this.jq.circleControl.width()/2,
			y	= pageY - offset.top - this.jq.circleControl.height()/2,
			theta	= Math.atan2(y,x);

		if (theta > -1 * Math.PI && theta < -0.5 * Math.PI) {
			theta = 2 * Math.PI + theta;
		}

		// theta is now value between -0.5PI and 1.5PI
		// ready to be normalized and applied

		return (theta + Math.PI / 2) / 2 * Math.PI * 10;
	},
	setMedia: function(media) {
		this.media = $.extend({}, media);
		this.player.jPlayer("setMedia", this.media);
	},
	play: function(time) {
		this.player.jPlayer("play", time);
	},
	pause: function(time) {
		this.player.jPlayer("pause", time);
	},
	destroy: function() {
		this.player.unbind(this.eventNamespace);
		this.player.jPlayer("destroy");
	}
};

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The MIT License


Written By
Software Developer Databorough India
India India
Currently working as software developer for Databorough India - Division of Fresche Legacy.

Developing for the open-source community and writing articles is my way of thanking the community. I have developed commercial as well as non-commercial/open-source projects for the web and windows as my work and hobby. Just trying very hard so that someday I could contribute a little for this world. I would like to send out my regards to all for your rating and comments because these comments keep me going. Thank you all.

Certifications:
Microsoft Certified Professional (Programming in C#)
Microsoft Certified Professional (Programming in HTML5 with JavaScript and CSS3)

Comments and Discussions