/**
* Ion.Sound
* version 3.0.7 Build 89
* © Denis Ineshin, 2016
*
* Project page: http://ionden.com/a/plugins/ion.sound/en.html
* GitHub page: https://github.com/IonDen/ion.sound
*
* Released under MIT licence:
* http://ionden.com/a/plugins/licence-en.html
*/
;(function (window, navigator, $, undefined) {
"use strict";
window.ion = window.ion || {};
if (ion.sound) {
return;
}
var warn = function (text) {
if (!text) text = "undefined";
if (window.console) {
if (console.warn && typeof console.warn === "function") {
console.warn(text);
} else if (console.log && typeof console.log === "function") {
console.log(text);
}
var d = $ && $("#debug");
if (d && d.length) {
var a = d.html();
d.html(a + text + '<br/>');
}
}
};
var extend = function (parent, child) {
var prop;
child = child || {};
for (prop in parent) {
if (parent.hasOwnProperty(prop)) {
child[prop] = parent[prop];
}
}
return child;
};
/**
* DISABLE for unsupported browsers
*/
if (typeof Audio !== "function" && typeof Audio !== "object") {
var func = function () {
warn("HTML5 Audio is not supported in this browser");
};
ion.sound = func;
ion.sound.play = func;
ion.sound.stop = func;
ion.sound.pause = func;
ion.sound.preload = func;
ion.sound.destroy = func;
func();
return;
}
/**
* CORE
* - creating sounds collection
* - public methods
*/
var is_iOS = /iPad|iPhone|iPod/.test(navigator.appVersion),
sounds_num = 0,
settings = {},
sounds = {},
i;
if (!settings.supported && is_iOS) {
settings.supported = ["mp3", "mp4", "aac"];
} else if (!settings.supported) {
settings.supported = ["mp3", "ogg", "mp4", "aac", "wav"];
}
var createSound = function (obj) {
var name = obj.alias || obj.name;
if (!sounds[name]) {
sounds[name] = new Sound(obj);
sounds[name].init();
}
};
ion.sound = function (options) {
extend(options, settings);
settings.path = settings.path || "";
settings.volume = settings.volume || 1;
settings.preload = settings.preload || false;
settings.multiplay = settings.multiplay || false;
settings.loop = settings.loop || false;
settings.sprite = settings.sprite || null;
settings.scope = settings.scope || null;
settings.ready_callback = settings.ready_callback || null;
settings.ended_callback = settings.ended_callback || null;
sounds_num = settings.sounds.length;
if (!sounds_num) {
warn("No sound-files provided!");
return;
}
for (i = 0; i < sounds_num; i++) {
createSound(settings.sounds[i]);
}
};
ion.sound.VERSION = "3.0.7";
ion.sound._method = function (method, name, options) {
if (name) {
sounds[name] && sounds[name][method](options);
} else {
for (i in sounds) {
if (!sounds.hasOwnProperty(i) || !sounds[i]) {
continue;
}
sounds[i][method](options);
}
}
};
ion.sound.preload = function (name, options) {
options = options || {};
extend({preload: true}, options);
ion.sound._method("init", name, options);
};
ion.sound.destroy = function (name) {
ion.sound._method("destroy", name);
if (name) {
sounds[name] = null;
} else {
for (i in sounds) {
if (!sounds.hasOwnProperty(i)) {
continue;
}
if (sounds[i]) {
sounds[i] = null;
}
}
}
};
ion.sound.play = function (name, options) {
ion.sound._method("play", name, options);
};
ion.sound.stop = function (name, options) {
ion.sound._method("stop", name, options);
};
ion.sound.pause = function (name, options) {
ion.sound._method("pause", name, options);
};
ion.sound.volume = function (name, options) {
ion.sound._method("volume", name, options);
};
if ($) {
$.ionSound = ion.sound;
}
/**
* Web Audio API core
* - for most advanced browsers
*/
var AudioContext = window.AudioContext || window.webkitAudioContext,
audio;
if (AudioContext) {
audio = new AudioContext();
}
var Sound = function (options) {
this.options = extend(settings);
delete this.options.sounds;
extend(options, this.options);
this.request = null;
this.streams = {};
this.result = {};
this.ext = 0;
this.url = "";
this.loaded = false;
this.decoded = false;
this.no_file = false;
this.autoplay = false;
};
Sound.prototype = {
init: function (options) {
if (options) {
extend(options, this.options);
}
if (this.options.preload) {
this.load();
}
},
destroy: function () {
var stream;
for (i in this.streams) {
stream = this.streams[i];
if (stream) {
stream.destroy();
stream = null;
}
}
this.streams = {};
this.result = null;
this.options.buffer = null;
this.options = null;
if (this.request) {
this.request.removeEventListener("load", this.ready.bind(this), false);
this.request.removeEventListener("error", this.error.bind(this), false);
this.request.abort();
this.request = null;
}
},
createUrl: function () {
var no_cache = new Date().valueOf();
this.url = this.options.path + encodeURIComponent(this.options.name) + "." + this.options.supported[this.ext] + "?" + no_cache;
},
load: function () {
if (this.no_file) {
warn("No sources for \"" + this.options.name + "\" sound :(");
return;
}
if (this.request) {
return;
}
this.createUrl();
this.request = new XMLHttpRequest();
this.request.open("GET", this.url, true);
this.request.responseType = "arraybuffer";
this.request.addEventListener("load", this.ready.bind(this), false);
this.request.addEventListener("error", this.error.bind(this), false);
this.request.send();
},
reload: function () {
this.ext++;
if (this.options.supported[this.ext]) {
this.load();
} else {
this.no_file = true;
warn("No sources for \"" + this.options.name + "\" sound :(");
}
},
ready: function (data) {
this.result = data.target;
if (this.result.readyState !== 4) {
this.reload();
return;
}
if (this.result.status !== 200 && this.result.status !== 0) {
warn(this.url + " was not found on server!");
this.reload();
return;
}
this.request.removeEventListener("load", this.ready.bind(this), false);
this.request.removeEventListener("error", this.error.bind(this), false);
this.request = null;
this.loaded = true;
//warn("Loaded: " + this.options.name + "." + settings.supported[this.ext]);
this.decode();
},
decode: function () {
if (!audio) {
return;
}
audio.decodeAudioData(this.result.response, this.setBuffer.bind(this), this.error.bind(this));
},
setBuffer: function (buffer) {
this.options.buffer = buffer;
this.decoded = true;
//warn("Decoded: " + this.options.name + "." + settings.supported[this.ext]);
var config = {
name: this.options.name,
alias: this.options.alias,
ext: this.options.supported[this.ext],
duration: this.options.buffer.duration
};
if (this.options.ready_callback && typeof this.options.ready_callback === "function") {
this.options.ready_callback.call(this.options.scope, config);
}
if (this.options.sprite) {
for (i in this.options.sprite) {
this.options.start = this.options.sprite[i][0];
this.options.end = this.options.sprite[i][1];
this.streams[i] = new Stream(this.options, i);
}
} else {
this.streams[0] = new Stream(this.options);
}
if (this.autoplay) {
this.autoplay = false;
this.play();
}
},
error: function () {
this.reload();
},
play: function (options) {
delete this.options.part;
if (options) {
extend(options, this.options);
}
if (!this.loaded) {
this.autoplay = true;
this.load();
return;
}
if (this.no_file || !this.decoded) {
return;
}
if (this.options.sprite) {
if (this.options.part) {
this.streams[this.options.part].play(this.options);
} else {
for (i in this.options.sprite) {
this.streams[i].play(this.options);
}
}
} else {
this.streams[0].play(this.options);
}
},
stop: function (options) {
if (this.options.sprite) {
if (options) {
this.streams[options.part].stop();
} else {
for (i in this.options.sprite) {
this.streams[i].stop();
}
}
} else {
this.streams[0].stop();
}
},
pause: function (options) {
if (this.options.sprite) {
if (options) {
this.streams[options.part].pause();
} else {
for (i in this.options.sprite) {
this.streams[i].pause();
}
}
} else {
this.streams[0].pause();
}
},
volume: function (options) {
var stream;
if (options) {
extend(options, this.options);
} else {
return;
}
if (this.options.sprite) {
if (this.options.part) {
stream = this.streams[this.options.part];
stream && stream.setVolume(this.options);
} else {
for (i in this.options.sprite) {
stream = this.streams[i];
stream && stream.setVolume(this.options);
}
}
} else {
stream = this.streams[0];
stream && stream.setVolume(this.options);
}
}
};
var Stream = function (options, sprite_part) {
this.alias = options.alias;
this.name = options.name;
this.sprite_part = sprite_part;
this.buffer = options.buffer;
this.start = options.start || 0;
this.end = options.end || this.buffer.duration;
this.multiplay = options.multiplay || false;
this.volume = options.volume || 1;
this.scope = options.scope;
this.ended_callback = options.ended_callback;
this.setLoop(options);
this.source = null;
this.gain = null;
this.playing = false;
this.paused = false;
this.time_started = 0;
this.time_ended = 0;
this.time_played = 0;
this.time_offset = 0;
};
Stream.prototype = {
destroy: function () {
this.stop();
this.buffer = null;
this.source = null;
this.gain && this.gain.disconnect();
this.source && this.source.disconnect();
this.gain = null;
this.source = null;
},
setLoop: function (options) {
if (options.loop === true) {
this.loop = 9999999;
} else if (typeof options.loop === "number") {
this.loop = +options.loop - 1;
} else {
this.loop = false;
}
},
update: function (options) {
this.setLoop(options);
if ("volume" in options) {
this.volume = options.volume;
}
},
play: function (options) {
if (options) {
this.update(options);
}
if (!this.multiplay && this.playing) {
return;
}
this.gain = audio.createGain();
this.source = audio.createBufferSource();
this.source.buffer = this.buffer;
this.source.connect(this.gain);
this.gain.connect(audio.destination);
this.gain.gain.value = this.volume;
this.source.onended = this.ended.bind(this);
this._play();
},
_play: function () {
var start,
end;
if (this.paused) {
start = this.start + this.time_offset;
end = this.end - this.time_offset;
} else {
start = this.start;
end = this.end;
}
if (end <= 0) {
this.clear();
return;
}
if (typeof this.source.start === "function") {
this.source.start(0, start, end);
} else {
this.source.noteOn(0, start, end);
}
this.playing = true;
this.paused = false;
this.time_started = new Date().valueOf();
},
stop: function () {
if (this.playing && this.source) {
if (typeof this.source.stop === "function") {
this.source.stop(0);
} else {
this.source.noteOff(0);
}
}
this.clear();
},
pause: function () {
if (this.paused) {
this.play();
return;
}
if (!this.playing) {
return;
}
this.source && this.source.stop(0);
this.paused = true;
},
ended: function () {
this.playing = false;
this.time_ended = new Date().valueOf();
this.time_played = (this.time_ended - this.time_started) / 1000;
this.time_offset += this.time_played;
if (this.time_offset >= this.end || this.end - this.time_offset < 0.015) {
this._ended();
this.clear();
if (this.loop) {
this.loop--;
this.play();
}
}
},
_ended: function () {
var config = {
name: this.name,
alias: this.alias,
part: this.sprite_part,
start: this.start,
duration: this.end
};
if (this.ended_callback && typeof this.ended_callback === "function") {
this.ended_callback.call(this.scope, config);
}
},
clear: function () {
this.time_played = 0;
this.time_offset = 0;
this.paused = false;
this.playing = false;
},
setVolume: function (options) {
this.volume = options.volume;
if (this.gain) {
this.gain.gain.value = this.volume;
}
}
};
if (audio) {
return;
}
/**
* Fallback for HTML5 audio
* - for not so modern browsers
*/
var checkSupport = function () {
var sound = new Audio(),
can_play_mp3 = sound.canPlayType('audio/mpeg'),
can_play_ogg = sound.canPlayType('audio/ogg'),
can_play_aac = sound.canPlayType('audio/mp4; codecs="mp4a.40.2"'),
item, i;
for (i = 0; i < settings.supported.length; i++) {
item = settings.supported[i];
if (!can_play_mp3 && item === "mp3") {
settings.supported.splice(i, 1);
}
if (!can_play_ogg && item === "ogg") {
settings.supported.splice(i, 1);
}
if (!can_play_aac && item === "aac") {
settings.supported.splice(i, 1);
}
if (!can_play_aac && item === "mp4") {
settings.supported.splice(i, 1);
}
}
sound = null;
};
checkSupport();
Sound.prototype = {
init: function (options) {
if (options) {
extend(options, this.options);
}
this.inited = true;
if (this.options.preload) {
this.load();
}
},
destroy: function () {
var stream;
for (i in this.streams) {
stream = this.streams[i];
if (stream) {
stream.destroy();
stream = null;
}
}
this.streams = {};
this.loaded = false;
this.inited = false;
},
load: function () {
var part;
this.options.preload = true;
this.options._ready = this.ready;
this.options._scope = this;
if (this.options.sprite) {
for (i in this.options.sprite) {
part = this.options.sprite[i];
this.options.start = part[0];
this.options.end = part[1];
this.streams[i] = new Stream(this.options, i);
}
} else {
this.streams[0] = new Stream(this.options);
}
},
ready: function (duration) {
if (this.loaded) {
return;
}
this.loaded = true;
var config = {
name: this.options.name,
alias: this.options.alias,
ext: this.options.supported[this.ext],
duration: duration
};
if (this.options.ready_callback && typeof this.options.ready_callback === "function") {
this.options.ready_callback.call(this.options.scope, config);
}
if (this.autoplay) {
this.autoplay = false;
this.play();
}
},
play: function (options) {
if (!this.inited) {
return;
}
delete this.options.part;
if (options) {
extend(options, this.options);
}
console.log(1);
if (!this.loaded) {
if (!this.options.preload) {
this.autoplay = true;
this.load();
} else {
this.autoplay = true;
}
return;
}
if (this.options.sprite) {
if (this.options.part) {
this.streams[this.options.part].play(this.options);
} else {
for (i in this.options.sprite) {
this.streams[i].play(this.options);
}
}
} else {
this.streams[0].play(this.options);
}
},
stop: function (options) {
if (!this.inited) {
return;
}
if (this.options.sprite) {
if (options) {
this.streams[options.part].stop();
} else {
for (i in this.options.sprite) {
this.streams[i].stop();
}
}
} else {
this.streams[0].stop();
}
},
pause: function (options) {
if (!this.inited) {
return;
}
if (this.options.sprite) {
if (options) {
this.streams[options.part].pause();
} else {
for (i in this.options.sprite) {
this.streams[i].pause();
}
}
} else {
this.streams[0].pause();
}
},
volume: function (options) {
var stream;
if (options) {
extend(options, this.options);
} else {
return;
}
if (this.options.sprite) {
if (this.options.part) {
stream = this.streams[this.options.part];
stream && stream.setVolume(this.options);
} else {
for (i in this.options.sprite) {
stream = this.streams[i];
stream && stream.setVolume(this.options);
}
}
} else {
stream = this.streams[0];
stream && stream.setVolume(this.options);
}
}
};
Stream = function (options, sprite_part) {
this.name = options.name;
this.alias = options.alias;
this.sprite_part = sprite_part;
this.multiplay = options.multiplay;
this.volume = options.volume;
this.preload = options.preload;
this.path = settings.path;
this.start = options.start || 0;
this.end = options.end || 0;
this.scope = options.scope;
this.ended_callback = options.ended_callback;
this._scope = options._scope;
this._ready = options._ready;
this.setLoop(options);
this.sound = null;
this.url = null;
this.loaded = false;
this.start_time = 0;
this.paused_time = 0;
this.played_time = 0;
this.init();
};
Stream.prototype = {
init: function () {
this.sound = new Audio();
this.sound.volume = this.volume;
this.createUrl();
this.sound.addEventListener("ended", this.ended.bind(this), false);
this.sound.addEventListener("canplaythrough", this.can_play_through.bind(this), false);
this.sound.addEventListener("timeupdate", this._update.bind(this), false);
this.load();
},
destroy: function () {
this.stop();
this.sound.removeEventListener("ended", this.ended.bind(this), false);
this.sound.removeEventListener("canplaythrough", this.can_play_through.bind(this), false);
this.sound.removeEventListener("timeupdate", this._update.bind(this), false);
this.sound = null;
this.loaded = false;
},
createUrl: function () {
var rand = new Date().valueOf();
this.url = this.path + encodeURIComponent(this.name) + "." + settings.supported[0] + "?" + rand;
},
can_play_through: function () {
if (this.preload) {
this.ready();
}
},
load: function () {
this.sound.src = this.url;
this.sound.preload = this.preload ? "auto" : "none";
if (this.preload) {
this.sound.load();
}
},
setLoop: function (options) {
if (options.loop === true) {
this.loop = 9999999;
} else if (typeof options.loop === "number") {
this.loop = +options.loop - 1;
} else {
this.loop = false;
}
},
update: function (options) {
this.setLoop(options);
if ("volume" in options) {
this.volume = options.volume;
}
},
ready: function () {
if (this.loaded || !this.sound) {
return;
}
this.loaded = true;
this._ready.call(this._scope, this.sound.duration);
if (!this.end) {
this.end = this.sound.duration;
}
},
play: function (options) {
if (options) {
this.update(options);
}
if (!this.multiplay && this.playing) {
return;
}
this._play();
},
_play: function () {
if (this.paused) {
this.paused = false;
} else {
try {
this.sound.currentTime = this.start;
} catch (e) {}
}
this.playing = true;
this.start_time = new Date().valueOf();
this.sound.volume = this.volume;
this.sound.play();
},
stop: function () {
if (!this.playing) {
return;
}
this.playing = false;
this.paused = false;
this.sound.pause();
this.clear();
try {
this.sound.currentTime = this.start;
} catch (e) {}
},
pause: function () {
if (this.paused) {
this._play();
} else {
this.playing = false;
this.paused = true;
this.sound.pause();
this.paused_time = new Date().valueOf();
this.played_time += this.paused_time - this.start_time;
}
},
_update: function () {
if (!this.start_time) {
return;
}
var current_time = new Date().valueOf(),
played_time = current_time - this.start_time,
played = (this.played_time + played_time) / 1000;
if (played >= this.end) {
if (this.playing) {
this.stop();
this._ended();
}
}
},
ended: function () {
if (this.playing) {
this.stop();
this._ended();
}
},
_ended: function () {
this.playing = false;
var config = {
name: this.name,
alias: this.alias,
part: this.sprite_part,
start: this.start,
duration: this.end
};
if (this.ended_callback && typeof this.ended_callback === "function") {
this.ended_callback.call(this.scope, config);
}
if (this.loop) {
setTimeout(this.looper.bind(this), 15);
}
},
looper: function () {
this.loop--;
this.play();
},
clear: function () {
this.start_time = 0;
this.played_time = 0;
this.paused_time = 0;
},
setVolume: function (options) {
this.volume = options.volume;
if (this.sound) {
this.sound.volume = this.volume;
}
}
};
} (window, navigator, window.jQuery || window.$));