/*!
* @file Planeptune Loop Player Core
* @version 2025.05.25.021
* @author zefie <zefie@zefie.net>
* @copyright 2017-2021 Zefie Networks
* @license CC-BY-SA-4.0
*
* Minified using uglify-js v3.x
* For human readable version, see https://loops.planeptune.org/geshi/source/js/loopplayer.html5.core.js
*/
(function () {
"use strict";
// objects for days
var config = {
"autoplay": false,
"bootSeek": false,
"offline": false,
"debug": false,
"defaults": {
"autoplay": false,
"debug": false,
"initSeek": false,
"lossless": 0,
"forceformat": 0,
"fps": 60,
"seekopt": 0,
"rate": 100,
"volume": 50,
"audioconfig": "audio",
"ctxHue": {
"bar": {
"start": 260,
"end": 296,
"direction": 1
},
"mode": 0,
"modifier": 1,
"multiplier": 1.5
}
},
"detection": {
"codecs": null,
"microsoft": false,
"mobile": false
},
"effects": {
"slideSpeed": {
"wrapper": 150,
"content": 300
}
},
"availfps": { "values": [2, 5, 10, 15, 20, 25, 30, 45, 50, 60, 100, 120, 144, 165, 240] },
"forceFormat": 0,
"howl": {
"currentPart": 0,
"file": null,
"name": null,
"loading": false,
"mptest": false,
"numParts": 0,
"seeking": false
},
"initSeek": false,
"loop": null,
"lossless": 0,
"seekOffset": -500,
"seekopt": 0,
"siteURL": document.URL.substr(0, document.URL.lastIndexOf("?")) || document.URL.substr(0, document.URL.lastIndexOf("/")),
"toggles": {
"looper": {
"checked": false,
"seeking": false
},
"visualization": {
"enabled": true,
"configShown": false
},
"sliderSeeking": false,
"waveform": {
"enabled": true,
"seeking": false
}
},
"version": "2025.05.25.021",
"usingWebAudio": true,
"wavesurferMaxZoom": 500
},
media = {
"channels": null,
"codec": null,
"dataBuffer": null,
"duration": 0,
"external": {
"loop": null,
"flags": null
},
"rate": null,
"volume": null
},
obj = {
"conf": null,
"ctx": {
"analyzer": null,
"canvas": null,
"canvasContext": null,
"freqBufLen": null,
"freqData": null,
"hue": $.extend(true, {}, config.defaults.ctxHue),
"visual": {
"height": null,
"width": null
}
},
"flags": null,
"player": null,
"timing": {
"fps": {
"current": 0,
"last": 0
},
"timestamp": Math.round(Date.now() / 1000)
},
"wavesurfer": null
}
$(document).ready(function () {
console.log("loopplayer v"+config.version+" initializing")
console.log("welcome to debug land");
console.log("initializing variables");
config.detection.mobile = !(document.getElementById('playspeed') instanceof Object);
config.detection.microsoft = Howler.detectIE();
console.log("browser detect: mobile: " + config.detection.mobile + ", pre-chromium ms: " + config.detection.microsoft);
if (offline) {
console.log("nwjs offline mode");
config.offline = true;
}
config.loop = z_urlp("loop") || null;
config.autoplay = (typeof z_urlp("autoplay") !== "undefined") || config.defaults.autoplay;
config.initSeek = (typeof z_urlp("doseek") !== "undefined") || config.defaults.initSeek;
config.lossless = parseInt(z_urlp("lossless")) || config.defaults.lossless;
config.debug = z_urlp("debug") || config.defaults.debug;
config.forceFormat = parseInt(z_urlp("forceformat")) || config.defaults.forceformat;
media.volume = parseInt(z_urlp("volume")) || config.defaults.volume;
media.rate = parseInt(z_urlp("playspeed") * 100) || config.defaults.rate;
config.seekopt = parseInt(z_urlp("seekopt")) || config.defaults.seekopt;
obj.ctx.hue.bar.start = parseInt(z_urlp("starthue")) || config.defaults.ctxHue.bar.start;
obj.ctx.hue.bar.end = parseInt(z_urlp("endhue")) || config.defaults.ctxHue.bar.end;
obj.ctx.hue.mode = parseInt(z_urlp("huemode")) || config.defaults.ctxHue.mode;
config.toggles.visualization.enabled = (typeof z_urlp("novu") === "undefined" || z_urlp("novu") == 0)
config.toggles.waveform.enabled = (typeof z_urlp("nowf") === "undefined" || z_urlp("nowf") == 0)
config.url = z_urlp("config") || config.defaults.audioconfig;
config.url += ".conf.js";
media.external.loop = z_urlp("external") || null;
media.external.flags = z_urlp("externalflags") || null;
var webAudioParam = z_urlp("html5") || null;
if (webAudioParam) {
// force html5
config.usingWebAudio = false;
} else {
// browser detect
config.usingWebAudio = testWebAudio();
}
var lowendPC = z_urlp("lowend") || false;
if (config.detection.mobile || lowendPC) {
config.toggles.visualization.enabled = false;
config.toggles.waveform.enabled = false;
config.defaults.fps = 25;
}
if (lowendPC) {
config.defaults.fps = 5;
lowendPC = true;
}
if (!config.usingWebAudio) {
config.toggles.visualization.enabled = false;
config.toggles.waveform.enabled = false;
$("#vutoggle").remove();
$("#wftoggle").remove();
$("#letoggle").remove();
}
console.log("using webaudio: " + config.usingWebAudio);
config.fps = parseInt(z_urlp("fps")) || config.defaults.fps;
if (z_urlp("doloop") === "on") {
config.toggles.looper.checked = true;
}
if (parseFloat(getFormValue(0, "seek")) > 0 && config.initSeek) {
config.bootSeek = true;
}
config.detection.codecs = testCodecs();
console.log("sanity checking variables");
if (media.volume > 200) {
media.volume = 200;
}
if (media.volume < 0) {
media.volume = 1;
}
if (media.rate > 300) {
media.rate = 300;
}
if (media.rate < 0) {
media.rate = 10;
}
console.log("initializing form values");
var seekval = parseInt(z_urlp("seek")) || parseInt(z_urlp("samples")) || 0;
// try to be backwards compatible
if (parseInt(z_urlp("samples"))) {
switch (config.seekopt) {
case 1:
config.seekopt = 0;
seekval = (seekval / 44100) * 1000;
case 2:
config.seekopt = 1;
}
}
setFormValue(1, "doloop", config.toggles.looper.checked);
setFormValue(1, "lowend", lowendPC);
setFormValue(1, "novu", !config.toggles.visualization.enabled);
setFormValue(1, "nowf", !config.toggles.waveform.enabled);
setFormValue(0, "looper", parseInt(z_urlp("looper")) || "");
setFormValue(0, "seek", seekval);
setFormValue(0, "playspeed", (media.rate / 100));
setFormValue(0, "volume", media.volume);
setFormValue(2, "seekopt", config.seekopt);
console.log("loading loop config data");
$.ajaxSetup({
cache: false
});
$.getJSON({
url: config.url
}).done(function (data) {
obj.conf = data;
pageLoadStage2();
}).fail(function (obj, txt, err) {
console.log("a config file error was detected");
console.log(err);
var thehtml = "<strong>ERROR</strong><br>There was an error loading the audio config data.<br>";
thehtml += "Please reload the page to try again.<br> <br>If the issue persists, please contact zefie.<br>";
$("#playdata").html(thehtml);
$("#content_wrapper").slideDown(config.effects.slideSpeed.wrapper);
});
if (dm == "howler" || dm == "howler_testing") {
$("#notice").append("<button type=\"button\" id=\"howler_multipart\" class=\"darkform\">Howler Multipart Test</button><br><br>");
$("#howler_multipart").bind("click", function () {
loaderStage1("howler_multipart_test");
});
}
});
function getFormValue(t, n) {
switch (t) {
case 0:
return $("input[name=" + n + "]").val();
case 1:
return $("input[name=" + n + "]").prop("checked");
case 2:
return $("select[name=" + n + "]").prop("selectedIndex");
case 3:
return $("select[name=" + n + "]").val();
case 4:
return $("select[name=" + n + "]").length;
}
}
function setFormValue(t, n, v) {
switch (t) {
case 0:
return $("input[name=" + n + "]").val(v);
case 1:
return $("input[name=" + n + "]").prop("checked", v);
case 2:
return $("select[name=" + n + "]").prop("selectedIndex", v);
case 3:
return $("select[name=" + n + "]").val(v);
}
}
function pageLoadStage2() {
console.log("config loaded with " + Object.keys(obj.conf.loops).length + " loops");
$.ajaxSetup({
cache: true
});
console.log("populating menus");
$.each(config.availfps.values, function (i) {
$("#fpssel").append($("<option />").val(config.availfps.values[i]).text(config.availfps.values[i] + 'fps'));
if (config.fps && config.fps === config.availfps.values[i]) {
$("#fpssel option[value=\"" + config.availfps.values[i] + "\"]").prop("selected", true);
}
});
if (obj.conf.sortlist === true) {
obj.conf.loops.sort(function(a, b) {
return a.title.localeCompare(b.title);
});
}
$.each(obj.conf.loops, function (i) {
if (config.lossless === 2 && !obj.conf.loops[i].flags.lossless) {
return true;
}
$("#loopselect").append($("<option />").val(obj.conf.loops[i].name).text(obj.conf.loops[i].title));
if (config.loop && config.loop === obj.conf.loops[i].name) {
$("#loopselect option[value=\"" + obj.conf.loops[i].name + "\"]").prop("selected", true);
}
});
if (media.external.loop) {
$("#loopselect").append($("<option />").val("external").text("* External Loop"));
if (!config.loop || config.loop == "external") {
$("#loopselect option[value=\"external\"]").prop("selected", true);
}
}
console.log("initializing sliders");
$("#sseek").slider({
min: 0,
max: 0,
value: 0,
range: "min",
animate: true,
start: function (event, ui) {
config.toggles.sliderSeeking = true;
},
stop: function (event, ui) {
config.toggles.sliderSeeking = false;
setPos(ui.value);
}
});
$("#svol").slider({
min: 0,
max: 100,
value: media.volume,
range: "min",
animate: true,
slide: function (event, ui) {
setVolume(ui.value);
}
});
$("#splayspeed").slider({
min: 10,
max: 300,
value: media.rate,
range: "min",
animate: true,
slide: function (event, ui) {
setRate(ui.value);
}
});
if (config.detection.mobile) {
$(window).resize(function () {
setElementSize();
});
$(document).on("touchmove", function (event) {
event.preventDefault();
});
setElementSize();
}
if (!config.toggles.waveform.enabled) {
$("#wfzoom").remove();
}
console.log("initializing events");
if (!config.detection.mobile) {
if (!dm) {
$("#devnotice").html("Are you a developer? Check out the <a id=\"dbglink\" href=\"#\">debug</a> editions.");
$("#dbglink").bind("click", function () {
getSubmitURL("core");
});
} else {
$("#devnotice").html("You are in debug mode. You may choose from the following modes: ");
var dbgmodes = ["core", "howler", "production"];
for (var i = 0; i < dbgmodes.length; i++) {
var dbgmode = dbgmodes[i];
$("#devnotice").append("[ <a id=\"dbglink_" + dbgmode + "\" href=\"#\">" + dbgmode + "</a> ] ");
$("#dbglink_" + dbgmode).bind("click", function () {
getSubmitURL(this.id.replace("dbglink_", ""));
});
}
$("#devnotice").append("<br>Also, be sure to check out the source code <a href=\"/source/\">available here</a> in human readable format.</a>");
}
$("#devnotice").append("<span style=\"float: right\">v" + config.version + "</span>");
}
$("#submitbutton").bind("click", function () {
getSubmitURL();
return false;
});
$("#resetbutton").bind("click", function () {
clearURLParams();
return false;
});
$("#fpssel").bind("change", function () {
if (obj.fps) {
var val = getFormValue(3, "fps");
setFPS(parseInt(val.replace("fps", "")), obj.fps.isPlaying);
}
});
$("#vol, #svol").bind("wheel", function (e) {
wheelTrigger("volume", e.originalEvent.deltaY, e.ctrlKey);
return false;
});
$("#playspeed, #splayspeed, .speedbutton").bind("wheel", function (e) {
wheelTrigger("rate", e.originalEvent.deltaY, e.ctrlKey);
return false;
});
$("#visualization").bind("wheel", function (e) {
wheelTrigger("vishue", e.originalEvent.deltaY, e.ctrlKey);
updateVUConf();
return false;
});
$("#visualization").bind("click", function (e) {
if (obj.ctx.hue.mode == 0) {
obj.ctx.hue.mode = 1;
} else {
obj.ctx.hue.mode = 0;
}
updateVUConf();
});
$("#visualization").bind("dblclick", function (e) {
toggleVUConf();
});
$("#sseek, #seek, #seekbutton").bind("wheel", function (e) {
wheelTrigger("seek", e.originalEvent.deltaY, e.ctrlKey);
return false;
});
$("#seekopt").bind("wheel", function (e) {
wheelTrigger("seekopt", e.originalEvent.deltaY, e.ctrlKey);
return false;
});
$("#loadbutton").bind("click", function () {
loaderStage1(getFormValue(3, 'loop'));
return false;
});
$("#loopselect").bind("change", function () {
loaderStage1(getFormValue(3, 'loop'));
});
$("#seekopt").bind("change", function () {
switchSeekDisplay();
});
$("#playpause1, #playpause2").bind("click", function () {
doPlayPause();
return false;
});
$("#speedreset").bind("click", function () {
setRateB(1);
return false;
});
$("#lowend").bind("change", function () {
if (getFormValue(1, "lowend")) {
setFormValue(2, "fps", 0);
setFormValue(1, "novu", true);
$("#novu").trigger("change");
setFormValue(1, "nowf", true);
$("#nowf").trigger("change");
} else {
setFormValue(1, "novu", false);
$("#novu").trigger("change");
setFormValue(1, "nowf", false);
$("#nowf").trigger("change");
setFormValue(2, "fps", 8);
}
$("#fpssel").trigger("change");
});
$("#novu").bind("change", function () {
if (getFormValue(1, "lowend") && !getFormValue(1, "novu")) {
setFormValue(1, "lowend", false);
}
if (getFormValue(1, "novu")) {
config.toggles.visualization.enabled = false;
$("#visualization").empty();
$("#visualization").hide();
} else {
config.toggles.visualization.enabled = true;
if (obj.player) {
if (obj.player.playing()) {
$("#visualization").css("height", $("#playdata").height() + "px");
$("#visualization").show();
setupVU();
}
}
}
});
$("#nowf").bind("change", function () {
if (getFormValue(1, "lowend") && !getFormValue(1, "nowf")) {
setFormValue(1, "lowend", false);
}
if (getFormValue(1, "nowf")) {
config.toggles.waveform.enabled = false;
if (obj.wavesurfer) {
obj.wavesurfer.stop();
obj.wavesurfer.destroy();
$("#wfzoom").hide();
$("#waveform").hide();
$("#waveform").empty();
}
} else {
config.toggles.waveform.enabled = true;
if (obj.player) {
if (obj.player.playing()) {
$("#waveform").show();
setupWaveform();
}
}
}
});
$("#wfzoom").bind("click", function () {
toggleWFZoom();
return false;
});
$("#speedset").bind("click", function () {
setRateB(getFormValue(0, 'playspeed'));
return false;
});
$("#seek, #looper").bind("keypress", function () {
return catchEnter(event, doSeek);
});
$("#vol").bind("keypress", function () {
return catchEnter(event, setVolumeC);
});
$("#playspeed").bind("keypress", function () {
return catchEnter(event, setRateC);
});
$("#seekbutton").bind("click", function () {
doSeek();
return false;
});
$("#seekbutton2").bind("click", function () {
setSeekData();
return false;
});
if (config.detection.microsoft) {
console.log("microsoft browser detected, show warning");
if (config.detection.mobile) {
$("#notice").append("Mobile IE? Your browser will likely have a gap in the loops.<br><br>");
} else if (config.detection.microsoft < 18) {
if (config.detection.microsoft >= 14) {
$("#notice").append("Gap in your loop? Update to the latest version of Microsoft Edge!<br><br>");
} else {
$("#notice").append("This browser (Internet Explorer " + config.detection.microsoft + ") is not fully supported. Some features may not be available or work correctly.<br><br>");
}
}
}
if (!config.usingWebAudio) {
$("#notice").append("Running in HTML5 compatiblity mode, many features are unavailable in this mode.<br><br>");
}
console.log("initialization complete, showing user interface");
console.log("--------------");
$("#content_wrapper").slideDown(config.effects.slideSpeed.wrapper, 'swing', function () {
$("#content").slideDown(config.effects.slideSpeed.content);
});
if (config.toggles.visualization.enabled) {
$("#visualization").css("height", $("#playdata").height() + "px");
}
playbackStopped();
if (config.autoplay && getFormValue(3, "loop")) {
console.log("autoplay specified, initiate loading...");
loaderStage1(getFormValue(3, "loop"));
}
}
function checkHueSanity(v) {
if (v < 0 || v > 360) {
return false;
} else {
return true;
}
}
function updateVUConf() {
if (config.toggles.visualization.enabled) {
setFormValue(0, "starthue", obj.ctx.hue.bar.start);
setFormValue(0, "endhue", obj.ctx.hue.bar.end);
setFormValue(2, "huemode", obj.ctx.hue.mode);
}
}
function applyVUConf() {
if (config.toggles.visualization.enabled) {
if (checkHueSanity(parseInt(getFormValue(0, "starthue")))) {
obj.ctx.hue.bar.start = parseInt(getFormValue(0, "starthue"));
}
if (checkHueSanity(parseInt(getFormValue(0, "endhue")))) {
obj.ctx.hue.bar.end = parseInt(getFormValue(0, "endhue"));
}
obj.ctx.hue.mode = getFormValue(2, "huemode");
updateVUConf();
if (obj.ctx.hue.mode == 0) {
obj.ctx.hue.bar.direction = 0;
}
}
}
function toggleVUConf() {
if (config.toggles.visualization.enabled) {
if (!config.toggles.visualization.configShown) {
var thehtml = '<div id="vuconfig">';
thehtml += 'Bar Hue: <span class="bracket">[</span>Start: <input id="starthue" name="starthue" class="smallform darkform"><span class="bracket">]</span>';
thehtml += '<span class="bracket">[</span>End: <input id="endhue" name="endhue" class="smallform darkform"><span class="bracket">]</span><br>';
thehtml += '<span class="bracket">[</span>Mode: <select id="huemode" name="huemode" class="darkform"><span class="bracket">]</span>';
thehtml += '<option value="0">Repeat</option>';
thehtml += '<option value="1">Single</option>';
thehtml += '</select><span class="bracket">]</span></div>';
$("#settings").append(thehtml);
$("#starthue, #endhue").bind("keypress", function () {
return catchEnter(event, applyVUConf);
});
$("#huemode").bind("change", function () {
applyVUConf();
});
updateVUConf();
config.toggles.visualization.configShown = true;
} else {
$("#vuconfig").remove();
config.toggles.visualization.configShown = false;
}
}
}
function WFZoom(zoom) {
if (zoom <= 0) {
obj.wavesurfer.zoom(0);
$("#wfzoom").text("Zoom In");
} else {
obj.wavesurfer.zoom(zoom);
$("#wfzoom").text("Zoom Out");
}
}
function toggleWFZoom() {
if (obj.wavesurfer && config.toggles.waveform.enabled) {
if ($("#wfzoom").text() == "Zoom Out") {
WFZoom(0);
} else {
WFZoom(config.wavesurferMaxZoom);
}
}
}
function setElementSize() {
var width = (window.innerWidth > 0) ? window.innerWidth : screen.width;
$("#loopselect").css("width", width - 95 + "px");
$("#sseek").css("width", width - 100 + "px");
$("#svol").css("width", width - 100 + "px");
$("#splayspeed").css("width", width - 100 + "px");
window.scrollTo(0, 0);
}
function wheelTrigger(e, d, c) {
if (d < 0) {
d = 1;
} else {
d = 0;
}
var valchg;
switch (e) {
case "volume":
var valchg = 1;
if (c) {
valchg = 5;
}
if (d) {
valchg = parseInt(getFormValue(0, "volume")) + valchg;
if (valchg <= 100) {
setVolumeB(valchg);
}
} else {
valchg = parseInt(getFormValue(0, "volume")) - valchg;
if (valchg >= 0) {
setVolumeB(valchg);
}
}
break;
case "rate":
var valchg = 0.01;
if (c) {
valchg = 0.10;
}
if (d) {
valchg = roundNumber(parseFloat(getFormValue(0, "playspeed")) + valchg, 2);
if (valchg <= 3) {
setRateB(valchg);
}
} else {
valchg = roundNumber(parseFloat(getFormValue(0, "playspeed")) - valchg, 2);
if (valchg >= 0.10) {
setRateB(valchg);
}
}
break;
case "seek":
if (d) {
scrollSeek(c, 1);
} else {
scrollSeek(c, 0);
}
break;
case "wfzoom": {
if (obj.wavesurfer && config.toggles.waveform.enabled) {
var valchg = 50;
if (c) {
valchg = 100;
}
if (d) {
var newval = obj.wavesurfer.params.minPxPerSec + valchg;
if (newval >= config.wavesurferMaxZoom) {
newval = config.wavesurferMaxZoom;
$("#wfzoom").text("Zoom Out");
}
if (obj.wavesurfer.params.minPxPerSec != newval) {
obj.wavesurfer.zoom(newval);
}
} else {
var newval = obj.wavesurfer.params.minPxPerSec - valchg;
if (newval <= 0) {
newval = 0;
$("#wfzoom").text("Zoom In");
}
if (obj.wavesurfer.params.minPxPerSec != newval) {
obj.wavesurfer.zoom(newval);
}
}
}
break;
}
case "vishue":
var valchg = 2;
if (c) {
valchg = 10;
}
if (d) {
if (checkHueSanity(obj.ctx.hue.bar.start + valchg) &&
checkHueSanity(obj.ctx.hue.bar.end + valchg)) {
obj.ctx.hue.bar.start += valchg;
obj.ctx.hue.bar.end += valchg;
}
} else {
if (checkHueSanity(obj.ctx.hue.bar.start - valchg) &&
checkHueSanity(obj.ctx.hue.bar.end - valchg)) {
obj.ctx.hue.bar.start -= valchg;
obj.ctx.hue.bar.end -= valchg;
}
}
break;
case "seekopt":
if (d) {
if (getFormValue(2, "seekopt") > 0) {
setFormValue(2, "seekopt", getFormValue(2, "seekopt") - 1);
} else {
setFormValue(2, "seekopt", getFormValue(4, "seekopt") - 1);
}
} else {
if (getFormValue(2, "seekopt") < getFormValue(4, "seekopt") - 1) {
setFormValue(2, "seekopt", getFormValue(2, "seekopt") + 1);
} else {
setFormValue(2, "seekopt", 0);
}
}
switchSeekDisplay();
break;
}
}
function scrollSeek(c, d) {
if (obj.player) {
var seekOffset = 250;
if (c) {
seekOffset = 1000
};
if (obj.player.playing()) {
var currpos = (obj.player.seek(obj.player._sounds[0]._id) * 1000);
if (d) {
if (currpos + seekOffset <= media.duration) {
setSeekMs(currpos + seekOffset);
} else {
setSeekMs(media.duration);
}
} else {
if (currpos - seekOffset >= 0) {
setSeekMs(currpos - seekOffset);
}
}
setSeekData();
}
}
}
function getVars(f) {
var result = false;
if (media.external.flags && config.debug) {
console.log("overriding flags with externalflags...");
result = getExternalFlags(media.external.flags);
} else {
$.each(obj.conf.loops, function (i) {
if (obj.conf.loops[i].name === f) {
result = obj.conf.loops[i].flags;
}
});
}
return result;
}
function setMediaCodec(ext) {
switch (ext) {
case "webm":
media.codec = "audio/webm";
break;
case "opus":
media.codec = "audio/ogg; codecs=opus";
break;
case "m4a":
media.codec = "audio/mp4";
break;
case "mp3":
media.codec = "audio/mp3";
break;
case "wav":
media.codec = "audio/wav";
break;
case "flac":
media.codec = "audio/flac";
break;
}
if (media.codec === null) {
console.log("Unsupported media type");
return false;
}
if (config.forceFormat) {
console.log("forcing codec " + media.codec);
} else {
console.log("chose codec " + media.codec + " as best match for this browser");
}
return true;
}
function checkMediaSupported(mime) {
var ext = mime.split("/")[1];
if (ext.substr(0, 5) == "x-ms-") {
ext = ext.substr(5);
}
if (ext.substr(0, 2) == "x-") {
ext = ext.substr(2);
}
return config.detection.codecs[ext];
}
function showFriendlyError(httperr) {
switch (httperr) {
case 401:
return "Authorization Required";
case 403:
return "Access Denied";
case 500:
return "Internal Server Error (Remote End)";
default:
return null;
}
}
function getRemoteMediaType(url) {
var req = new XMLHttpRequest();
req.open('HEAD', url);
req.onload = function (e) {
if (e.target.status != 200) {
$("#playdata").html("<strong>Error loading remote file...</strong><br>The remote server reported error " + e.target.status + "...<br>" + showFriendlyError(e.target.status) + "<br><br><br><br>");
config.howl.loading = false;
} else {
media.codec = this.getResponseHeader('content-type');
remoteLoaderStage();
}
}
req.onerror = function (e) {
$("#playdata").html("<strong>Error loading remote file...</strong><br>This is likely because the remote server<br>has not authorized us via CORS<br>to access this file in our script.<br><br>");
config.howl.loading = false;
}
req.send();
}
function remoteLoaderStage() {
console.log("entering remoteLoaderStage");
if (!checkMediaSupported(media.codec)) {
$("#playdata").html("<strong>Error playing remote file...</strong><br>Your browser does not appear to<br>support the format of the external file provided.<br><br><br>");
config.howl.loading = false;
return false;
}
if (media.external.flags) {
obj.flags = getExternalFlags(media.external.flags);
}
getDataFile(media.external.loop);
return true;
}
function getExternalFlags(flags) {
var extflag = flags.split(":");
var extobj = {};
for (var i = 0; i < extflag.length; i++) {
switch (extflag[i]) {
case "duration":
if (i + 1 < extflag.length) {
extobj.duration = parseInt(extflag[i + 1]);
}
break;
case "loop":
if (i + 1 < extflag.length) {
extobj.loop = parseInt(extflag[i + 1]);
}
break;
case "start":
if (i + 1 < extflag.length) {
extobj.start = parseInt(extflag[i + 1]);
}
break;
}
}
return extobj;
}
function loaderStage1(loopname) {
if (config.toggles.waveform.enabled) {
$("#waveform").hide();
}
if (config.toggles.visualization.enabled) {
$("#visualization").hide();
}
if (config.detection.mobile) {
window.scrollTo(0, 0);
}
console.log("entering loaderStage1 for " + loopname);
config.howl.mptest = false;
config.howl.currentPart = 1;
if (loopname === "howler_multipart_test") {
loopname = "music_loop_001";
$("#loopselect option[value=\"" + loopname + "\"]").prop("selected", true);
config.howl.mptest = true;
}
media.duration = 0;
media.codec = null;
obj.flags = {};
var fileURL = null;
if (!config.howl.loading) {
config.howl.loading = true;
if (obj.player) {
obj.player.stop();
obj.player.unload();
obj.player = null;
}
var fileExt;
if (media.external.loop && loopname == "external") {
fileURL = media.external.loop;
getRemoteMediaType(fileURL);
return false;
} else {
config.howl.name = loopname;
obj.flags = getVars(config.howl.name);
if (obj.flags.file) {
config.howl.file = obj.flags.file;
} else {
config.howl.file = loopname;
}
if (typeof obj.flags.ext !== 'undefined') {
console.log("forced extension: "+obj.flags.ext+"...");
fileExt = obj.flags.ext;
fileURL = config.siteURL + obj.conf.audioPath + config.howl.file + "." + fileExt;
setMediaCodec(fileExt);
getDataFile(fileURL);
return true;
} else {
console.log("searching for most optimal file...");
findFile().then(function (fileRes) {
if (typeof fileRes !== 'undefined') {
fileURL = fileRes[0];
fileExt = fileRes[1];
}
if (typeof fileURL !== 'undefined' && typeof fileExt !== 'undefined') {
setMediaCodec(fileExt);
getDataFile(fileURL);
return true;
} else {
$("#playdata").html("<strong>Error playing file...</strong><br>Your browser does not appear to<br>support any of our available formats for this loop.<br><br><br><br>");
config.howl.loading = false;
return false;
}
});
}
}
}
config.howl.loading = false;
return false;
}
function findFile(blacklist) {
return new Promise(function (resolve, reject) {
blacklist = typeof blacklist !== 'undefined' ? blacklist : {};
var fileExt, fileURL;
if ((config.lossless == 1 || config.lossless == 2) && obj.flags.lossless) {
if (config.detection.codecs.flac && (!config.forceFormat || config.forceFormat == 4) && !("flac" in blacklist) && !fileExt) {
fileExt = "flac";
}
if (config.detection.codecs.wav && (!config.forceFormat || config.forceFormat == 5) && !("wav" in blacklist) && !fileExt) {
fileExt = "wav";
}
}
if (config.lossless != 2) {
if (config.detection.codecs.opus && (!config.forceFormat || config.forceFormat == 1) && !("opus" in blacklist) && !fileExt) {
fileExt = "opus";
}
if (config.detection.codecs.webm && (!config.forceFormat || config.forceFormat == 1) && !("webm" in blacklist) && !fileExt) {
fileExt = "webm";
}
if (config.detection.codecs.m4a && (!config.forceFormat || config.forceFormat == 2) && !("m4a" in blacklist) && !fileExt) {
fileExt = "m4a";
}
if (config.detection.codecs.mp3 && (!config.forceFormat || config.forceFormat == 3) && !("mp3" in blacklist) && !fileExt) {
fileExt = "mp3";
}
}
if (config.siteURL && config.howl.file && fileExt) {
fileURL = config.siteURL + obj.conf.audioPath + config.howl.file + "." + fileExt;
if (obj.flags.timestamp) {
var epoch = (new Date(obj.flags.timestamp).getTime() / 1000);
fileURL += "?_ts=" + epoch;
}
UrlExists(fileURL).then(function (result) {
console.log(fileExt + " media found");
resolve(Array(fileURL, fileExt));
}).catch(function (err) {
console.log(fileExt + " media does not exist, continue searching...");
blacklist[fileExt] = true;
findFile(blacklist).then(function (res) {
resolve(res);
}).catch(function (res) {
reject(res);
});
});
} else {
reject(Array(undefined, undefined));
}
});
}
function UrlExists(url) {
if (typeof offlineFileExists === "function") {
return new Promise(function (resolve, reject) {
if (offlineFileExists(url))
resolve(true);
else
reject(false)
});
} else {
return new Promise(function (resolve, reject) {
var http = new XMLHttpRequest();
http.open('HEAD', url, true);
http.onload = function (e) {
if (http.status != 404) {
resolve(true);
} else {
reject(false);
}
}
http.error = function (e) {
reject(false);
}
http.send();
});
}
}
function loaderStage2() {
console.log("entering loaderStage2");
if (!obj.flags.duration) {
console.log("duration var not defined, calculating full file length. result may create gap");
var howlInitializers = {
autoplay: false,
loop: false,
onload: loaderStageFinal,
onloaderror: howlError
}
if (config.usingWebAudio) {
howlInitializers.html5 = false;
howlInitializers.arraybuffer = media.dataBuffer;
howlInitializers.contenttype = media.codec;
} else {
var dataUri = "data:" + media.codec + ";base64," + base64ArrayBuffer(media.dataBuffer);
howlInitializers.html5 = true;
howlInitializers.src = [dataUri];
}
obj.player = new Howl(howlInitializers);
} else {
loaderStageFinal();
}
}
function loaderStageFinal() {
console.log("entering loaderStageFinal");
if (obj.player) {
media.duration = Math.round(obj.player._duration * 1000);
console.log("calculated result: " + media.duration + "ms");
obj.player.unload();
obj.player = null;
}
console.log("contents of the file flags object:");
console.log(obj.flags);
var howlSprite;
var nextSprite = "part2";
var start = 0;
if (obj.flags.loop) {
if (obj.flags.duration) {
media.duration = obj.flags.duration;
}
var loopms = obj.flags.loop;
if (obj.flags.start) {
start = obj.flags.start;
}
if (start == loopms) {
howlSprite = {
part1: [start, (media.duration - start)]
};
nextSprite = null;
} else {
howlSprite = {
part1: [start, loopms],
part2: [loopms, (media.duration - loopms)]
};
}
} else {
if (obj.flags.duration) {
media.duration = obj.flags.duration;
}
if (obj.flags.start) {
start = obj.flags.start;
}
nextSprite = null;
howlSprite = {
part1: [start, media.duration]
};
}
if (config.howl.mptest) {
var partLen = 9146;
howlSprite = {
part1: [0, partLen],
part2: [partLen, partLen],
part3: [partLen * 2, partLen],
part4: [partLen * 3, partLen],
part5: [partLen * 4, partLen],
part6: [partLen * 5, partLen],
part7: [partLen * 6, partLen],
part8: [partLen * 7, partLen],
part9: [partLen * 8, partLen],
part10: [partLen * 9, (media.duration - (partLen * 9))]
};
}
config.howl.numParts = Object.keys(howlSprite).length;
console.log("contents of the howl sprite object we built (" + config.howl.numParts + " parts):");
console.log(howlSprite);
$("#sseek").slider("value", 0);
$("#sseek").slider("option", "max", 0);
var howlInitializers = {
autoplay: false,
loop: true,
sprite: howlSprite,
nextsprite: nextSprite,
onspritechange: spriteChanged,
onload: loadComplete,
onseek: getplaydata,
onplay: playbackStarted,
onstop: playbackStopped,
onloaderror: howlError,
rate: (media.rate / 100),
volume: (media.volume / 100)
}
if (config.usingWebAudio) {
howlInitializers.html5 = false;
howlInitializers.arraybuffer = media.dataBuffer;
howlInitializers.contenttype = media.codec;
} else {
var dataUri = "data:" + media.codec + ";base64," + base64ArrayBuffer(media.dataBuffer);
howlInitializers.html5 = true;
howlInitializers.src = [dataUri];
}
console.log("contents of the howl initialization object:");
console.log(howlInitializers);
obj.player = new Howl(howlInitializers);
}
function howlError() {
$("#playdata").html("<strong>Error playing file...</strong><br>There was an internal error decoding this file.<br>The file is unusable.<br><br><br>");
config.howl.loading = false;
}
function loadComplete() {
if (obj.player) {
if (config.usingWebAudio) {
media.channels = obj.player._decoded.numberOfChannels;
}
if (config.toggles.waveform.enabled && config.usingWebAudio) {
setupWaveform();
}
if (config.toggles.visualization.enabled && config.usingWebAudio) {
setupVU();
}
$("#sseek").slider("option", "max", media.duration);
obj.player.play("part" + config.howl.currentPart);
debugPartPlayback();
}
}
function setupVU() {
if (obj.player) {
if (obj.ctx.canvas) {
$("#ctxCanvas").remove();
}
obj.ctx.visual.width = Math.round($("#visualization").innerWidth());
obj.ctx.visual.height = Math.round($("#visualization").innerHeight());
obj.ctx.analyzer = Howler.ctx.createAnalyser();
obj.ctx.analyzer.minDecibels = -76;
obj.ctx.analyzer.maxDecibels = -20;
obj.ctx.analyzer.smoothingTimeConstant = 0.75;
obj.ctx.analyzer.fftSize = 1024;
obj.player._sounds[0]._node.connect(obj.ctx.analyzer);
$('<canvas>').attr({
id: 'ctxCanvas',
width: obj.ctx.visual.width + 'px',
height: obj.ctx.visual.height + 'px'
}).appendTo("#visualization");
obj.ctx.canvas = document.getElementById("ctxCanvas");
obj.ctx.canvasContext = obj.ctx.canvas.getContext("2d");
$("#visualization").show();
renderVUFrame();
}
}
function renderVUFrame() {
var x = 0;
var bufferLength = obj.ctx.analyzer.frequencyBinCount;
var dataArray = new Uint8Array(bufferLength);
obj.ctx.analyzer.getByteFrequencyData(dataArray);
obj.ctx.canvasContext.clearRect(0, 0, obj.ctx.canvas.width, obj.ctx.canvas.height);
var barWidth = (obj.ctx.canvas.width / bufferLength) * obj.ctx.hue.multiplier;
var barHue = obj.ctx.hue.bar.start;
var barHueMod = obj.ctx.hue.modifier;
if (obj.ctx.hue.mode == 1) {
barHueMod = ((obj.ctx.hue.bar.end - obj.ctx.hue.bar.start) / obj.ctx.analyzer.fftSize);
}
for (var i = 0; i < bufferLength; i = i + obj.ctx.hue.multiplier) {
var barHeightPercent = ((dataArray[parseInt(i)] / 255) * 100);
var barHeight = ((barHeightPercent / 100) * obj.ctx.visual.height);
switch (obj.ctx.hue.mode) {
case 0:
if (obj.ctx.hue.bar.start < obj.ctx.hue.bar.end) {
if (obj.ctx.hue.bar.direction == 1) {
barHue += barHueMod;
if (barHue >= obj.ctx.hue.bar.end) {
obj.ctx.hue.bar.direction = 0;
}
} else {
barHue -= barHueMod;
if (barHue <= obj.ctx.hue.bar.start) {
obj.ctx.hue.bar.direction = 1;
}
}
} else {
if (obj.ctx.hue.bar.direction == 1) {
barHue -= barHueMod;
if (barHue <= obj.ctx.hue.bar.end) {
obj.ctx.hue.bar.direction = 0;
}
} else {
barHue += barHueMod;
if (barHue >= obj.ctx.hue.bar.start) {
obj.ctx.hue.bar.direction = 1;
}
}
}
break;
case 1:
barHue += barHueMod;
break;
}
obj.ctx.canvasContext.fillStyle = 'hsl(' + barHue + ', 100%, 65%)';
obj.ctx.canvasContext.fillRect(x, obj.ctx.canvas.height - barHeight, barWidth, barHeight);
x += barWidth + 1;
}
}
function setupWaveform() {
if (obj.player) {
console.log("binding click event for waveform");
$("#waveform").on('click', function () {
config.toggles.waveform.seeking = true;
});
$("#waveform").on('wheel', function (e) {
if (e.shiftKey) {
wheelTrigger("wfzoom", e.originalEvent.deltaY, e.ctrlKey);
} else {
wheelTrigger("seek", e.originalEvent.deltaY, e.ctrlKey);
}
return false;
});
if (obj.wavesurfer) {
obj.wavesurfer.destroy();
obj.wavesurfer = null;
}
var stereo,
wfheight;
if (media.channels == 2) {
stereo = true;
wfheight = ($("#waveform").height() / 2) + 1;
} else {
stereo = false;
wfheight = $("#waveform").height() + 1;
}
console.log("creating wavesurfer object");
obj.wavesurfer = WaveSurfer.create({
audioContext: Howler.ctx,
height: wfheight,
container: '#waveform',
waveColor: '#959',
progressColor: 'purple',
cursorColor: '#999',
autoCenter: true,
splitChannels: stereo,
hideScrollbar: true,
minPxPerSec: config.wavesurferMaxZoom
});
obj.wavesurfer.on('seek', function (v) {
if (config.toggles.waveform.seeking) {
var newpos = (obj.wavesurfer.backend.buffer.duration * v) * 1000;
if (newpos <= media.duration) {
setPos(newpos, true);
}
config.toggles.waveform.seeking = false;
}
});
obj.wavesurfer.on('backend-created', function () {
if (obj.wavesurfer.backend.buffer) {
obj.wavesurfer.drawBuffer();
}
});
obj.wavesurfer.on('ready', function () {
WFZoom(obj.wavesurfer.params.minPxPerSec);
});
obj.wavesurfer.on('redraw', function () {
$("#wfzoom").show();
$("#waveform").show();
});
console.log("loading media buffer into obj.wavesurfer");
if (!obj.wavesurfer.isDestroyed) {
obj.wavesurfer.loadDecodedBuffer(obj.player._decoded);
}
}
}
function debugPartPlayback() {
var logstr = "playing audio segment part " + config.howl.currentPart;
var nextpart = obj.player._nextsprite;
if (nextpart) {
nextpart = nextpart.replace("part", "");
logstr += ", next part is " + nextpart;
} else {
logstr += ", this is the final part";
}
console.log(logstr);
}
function playbackStarted() {
if (obj.player) {
config.howl.loading = false;
$("#playpause1").hide();
$("#playpause2").show();
if (obj.fps) {
if (!obj.fps.isPlaying) {
obj.fps.start();
}
} else {
obj.fps = new FpsCtrl(config.fps, getplaydata);
obj.fps.start();
}
if (config.toggles.visualization.enabled) {
setupVU();
}
}
}
function doPlayPause() {
if (obj.player) {
if (obj.player.playing()) {
$("#playpause1").show();
$("#playpause2").hide();
obj.player.pause();
if (obj.fps) {
if (obj.fps.isPlaying) {
obj.fps.pause();
}
}
} else {
$("#playpause1").hide();
$("#playpause2").show();
obj.player.play();
if (obj.fps) {
if (!obj.fps.isPlaying) {
obj.fps.start();
}
}
}
} else {
loaderStage1(getFormValue(3, "loop"));
}
}
function playbackStopped() {
if (obj.fps) {
if (obj.player) {
if ((obj.fps.isPlaying || obj.player.playing()) && !config.howl.seeking) {
obj.fps.pause();
}
} else {
obj.fps.pause();
}
}
var thehtml = "<strong>Please select a file...</strong><br>or click play to begin...";
if (!config.detection.mobile) {
thehtml += "<br> <br> <br> <br>";
}
$("#playdata").html(thehtml);
}
function spriteChanged() {
if (!config.howl.seeking) {
if (config.howl.currentPart <= config.howl.numParts) {
config.howl.currentPart = parseInt(obj.player._sounds[0]._sprite.replace("part", ""));
if ((config.howl.currentPart + 1) <= config.howl.numParts) {
obj.player._nextsprite = "part" + (config.howl.currentPart + 1);
} else {
if (config.howl.mptest) {
obj.player._nextsprite = "part5";
} else {
obj.player._nextsprite = null;
}
}
debugPartPlayback();
}
}
}
function setPos(pos, updateSeekData) {
if (typeof updateSeekData == "undefined" || updateSeekData === null) {
updateSeekData = true;
}
if (obj.player) {
if (config.howl.currentPart != config.howl.numParts) {
config.howl.currentPart = config.howl.numParts;
var wasPlaying = obj.player.playing();
obj.player.stop();
if (config.howl.mptest) {
obj.player._nextsprite = "part5";
} else {
obj.player._nextsprite = null;
}
if (wasPlaying) {
obj.player.play("part" + config.howl.currentPart);
} else {
obj.player._sounds[0]._sprite = "part" + config.howl.currentPart;
}
debugPartPlayback();
}
config.howl.seeking = true;
$("#sseek").slider("value", pos);
obj.player.seek(pos / 1000, obj.player._sounds[0]._id);
config.howl.seeking = false;
}
if (updateSeekData) {
setTimeout(function () {
setSeekData(-250);
}, 250);
}
}
function setVolume(vol) {
media.volume = vol;
setFormValue(0, "volume", vol);
if (obj.player) {
obj.player.volume(vol / 100);
}
}
function setVolumeB(vol) {
setVolume(vol);
$("#svol").slider("value", vol);
}
function setVolumeC() {
var vol = getFormValue(0, "volume");
setVolume(vol);
$("#svol").slider("value", vol);
}
function setRate(rate) {
setFormValue(0, "playspeed", rate / 100);
media.rate = rate;
if (obj.player) {
obj.player.rate(rate / 100, obj.player._sounds[0]._id);
}
}
function setRateB(rate) {
$("#splayspeed").slider("value", rate * 100);
setRate(rate * 100);
}
function setRateC() {
setRateB(getFormValue(0, "playspeed"));
}
function roundNumber(num, dec, exact) {
var numtxt = num + "";
numtxt = numtxt.split(".")[0];
var expectedlen = ((numtxt.length + 1) + dec);
var result = Math.round(num * Math.pow(10, dec)) / Math.pow(10, dec);
var restxt = result + "";
if (exact === true) {
while (restxt.length != expectedlen) {
if (restxt.length == numtxt.length) {
restxt = restxt + ".";
} else {
restxt = restxt + "0";
}
}
return restxt;
}
return result;
}
function setSeekMs(v) {
setPos(v, false);
}
function setSeekPercentage(v, u) {
if (!u) {
u = false;
}
if (v > 100 || v < 0) {
v = 0;
}
var percentageEstMs = Math.round((media.duration * v) / 100);
if (percentageEstMs >= media.duration) {
percentageEstMs = media.duration - 1;
}
setPos(percentageEstMs, u);
}
function doSeek() {
switch (getFormValue(2, "seekopt")) {
case 0:
setSeekMs(getFormValue(0, "seek"));
break;
case 1:
setSeekPercentage(getFormValue(0, "seek"));
break;
}
}
function setSeekData(offset) {
if (obj.player) {
var currentpos = obj.player.seek(obj.player._sounds[0]._id);
var currms = Math.round((currentpos * 1000) + 500);
if (!offset) {
offset = 0;
}
offset = (offset + config.seekOffset);
setFormValue(1, "doloop", false);
switch (getFormValue(2, "seekopt")) {
case 0:
setFormValue(0, "seek", currms + offset);
break;
case 1:
setFormValue(0, "seek", roundNumber(((currms + offset) / media.duration * 100), 2, true));
break;
}
}
}
function switchSeekDisplay() {
if (obj.player) {
var currval = parseFloat(getFormValue(0, "seek"));
if (Number.isNaN(currval)) {
currval = 0;
}
if (media.duration) {
switch (config.seekopt) {
case 0:
switch (getFormValue(2, "seekopt")) {
case 1:
setFormValue(0, "seek", roundNumber(currval / media.duration * 100, 2, true));
break;
}
break;
case 1:
switch (getFormValue(2, "seekopt")) {
case 0:
setFormValue(0, "seek", Math.round((media.duration * currval) / 100));
break;
}
break;
}
config.seekopt = getFormValue(2, "seekopt")
} else {
setFormValue(2, "seekopt", config.seekopt);
}
}
}
function catchEnter(e, functionCallback) {
if (window.event && window.event.keyCode === 13) {
functionCallback();
return false;
}
if (e && e.keyCode === 13) {
functionCallback();
return false;
}
return true;
}
function getplaydata() {
if (obj.player) {
if (obj.player.playing()) {
if (config.toggles.visualization.enabled) {
renderVUFrame();
}
var currentpos = obj.player.seek(obj.player._sounds[0]._id);
if (!config.toggles.sliderSeeking) {
$("#sseek").slider("value", (currentpos * 1000));
}
var currms = Math.round(currentpos * 1000);
var percent = currms / media.duration * 100;
var seconds = Math.floor(currentpos);
var currmin = Math.floor(seconds / 60);
var currsec = seconds % 60;
var currmsec = currms - (seconds * 1000);
var totalms = Math.round(media.duration);
var totalsecs = Math.floor(media.duration / 1000);
var totalmin = Math.floor(totalsecs / 60);
var totalsec = totalsecs % 60;
var totalmsec = Math.round(totalms - (totalsecs * 1000), 3)
if (currms > 0 && config.bootSeek) {
config.bootSeek = false;
doSeek();
}
if (seconds % 60 < 10) {
currsec = "0" + currsec;
}
if (totalsecs % 60 < 10) {
totalsec = "0" + totalsec;
}
if (currmsec < 10) {
currmsec = "00" + currmsec
} else if (currmsec < 100) {
currmsec = "0" + currmsec
}
if (totalmsec < 10) {
totalmsec = "00" + totalmsec
} else if (totalmsec < 100) {
totalmsec = "0" + totalmsec
}
var oldts = obj.timing.timestamp;
obj.timing.timestamp = Math.round(new Date().getTime() / 1000);
if (oldts === obj.timing.timestamp) {
obj.timing.fps.current++;
} else {
obj.timing.fps.last = obj.timing.fps.current;
obj.timing.fps.current = 0;
}
if (getFormValue(1, "doloop") === true) {
if (!Number.isNaN(getFormValue(0, "looper"))) {
var looper = Number(getFormValue(0, "looper"));
var seek = Number(getFormValue(0, "seek"));
config.seekopt = getFormValue(2, "seekopt")
if (looper >= seek && config.toggles.looper.seeking === false) {
config.toggles.looper.seeking = true;
switch (config.seekopt) {
case 0:
if (currms >= looper) {
setSeekMs(seek);
}
break;
case 1:
if (percent >= looper) {
setSeekPercentage(seek);
}
break;
}
} else {
config.toggles.looper.seeking = false;
}
}
}
var thehtml = "<strong>Playback Information</strong><br>";
if (!config.detection.mobile) {
// Detect playback mode and codec
thehtml += "Mode: ";
if (obj.player._webAudio) {
thehtml += "WebAudio";
} else {
if (obj.player._html5) {
thehtml += "HTML5";
} else {
thehtml += "Unknown";
}
}
thehtml += " - Codec: " + getPlayingCodec() + "<br>";
}
thehtml += "Current Position: " + currmin + ":" + currsec + "." + currmsec+ " of " + totalmin + ":" + totalsec + "." + totalmsec + " (" + roundNumber(percent, 2, true) + "%)";
if (!config.detection.mobile) {
thehtml += "<br>";
thehtml += "Current FPS: " + (obj.timing.fps.last + 1) + " (" + Math.round(1000 / (obj.timing.fps.last + 1)) + "ms per frame)<br>";
}
$("#playdata").html(thehtml);
if (!config.toggles.waveform.seeking && obj.wavesurfer && config.toggles.waveform.enabled) {
var offsetpos = ((currms / 1000) / obj.wavesurfer.backend.buffer.duration);
var offset = percent - offsetpos;
var newpos = percent - offset;
if (newpos < 0) newpos = 0;
if (newpos > 1) newpos = 1;
obj.wavesurfer.seekTo(newpos);
obj.wavesurfer.drawer.recenter(newpos);
}
}
}
}
function getPlayingCodec() {
switch (media.codec) {
case "audio/webm":
return "Xiph Vorbis (webm)";
case "audio/ogg":
case "audio/x-ogg":
return "Xiph Vorbis (ogg)";
case "audio/ogg; codecs=opus":
return "Xiph Opus";
case "audio/mp4":
case "audio/m4a":
return "Apple AAC";
case "audio/mp3":
case "audio/mpeg":
return "MPEG (Layer 1/2/3)";
case "audio/wav":
case "audio/x-wav":
return "PCM S16LE";
case "audio/flac":
case "audio/x-flac":
return "FLAC";
}
return false;
}
function setReloadText() {
$("#playdata").html("<strong>Reloading with configured URL...</strong><br><br><br><br><br>");
}
function clearURLParams() {
setReloadText();
$("#content").slideUp(config.effects.slideSpeed.content, 'swing', function () {
var targeturl = location.href;
if (location.href.indexOf("?")) {
targeturl = location.href.split("?")[0];
}
targeturl += "?loop=" + getFormValue(3, "loop");
if (z_urlp("external") && getFormValue(3, "loop") == "external") {
targeturl += "&external=" + z_urlp("external");
if (z_urlp("externalflags")) {
targeturl += "&externalflags=" + z_urlp("externalflags");
}
}
if (z_urlp("debug")) {
targeturl += "&debug=" + z_urlp("debug");
}
$("#content_wrapper").slideUp(config.effects.slideSpeed.wrapper, 'swing', function () {
window.location.href = targeturl;
});
});
}
function getSubmitURL(debug) {
setReloadText();
$("#content").slideUp(config.effects.slideSpeed.content, 'swing', function () {
var x = document.getElementById("loopselect");
var filename = x.options[x.options.selectedIndex].value;
var split = filename.indexOf(",");
var splitary;
if (split > 0) {
splitary = filename.split(",");
x.options[x.options.selectedIndex].value = splitary[0];
}
// purge existing form fields that are set to their default values
if (getFormValue(2, "seekopt") == config.defaults.seekopt) {
$("#seekopt").remove();
}
if (getFormValue(3, "fps").replace("fps", "") == config.defaults.fps) {
$("#fpssel").remove();
}
if (getFormValue(0, "playspeed") == (config.defaults.rate / 100)) {
$("#playspeed").remove();
}
if (getFormValue(0, "volume") == config.defaults.volume) {
$("#vol").remove();
}
if (getFormValue(0, "seek") == "0" || getFormValue(0, "seek") == "") {
$("#seek").remove();
}
if (getFormValue(0, "looper") == "0" || getFormValue(0, "looper") == "") {
$("#looper").remove();
}
if (!getFormValue(1, "doloop")) {
$("#doloop").remove();
}
if (!getFormValue(1, "lowend")) {
$("#lowend").remove();
}
if (!getFormValue(1, "novu")) {
$("#novu").remove();
}
if (!getFormValue(1, "nowf")) {
$("#nowf").remove();
}
// check for variables that are not part of the main form and inject them if they exist
var checkMissingParams = ["config", "debug", "mobile", "doseek", "lossless", "autoplay", "forceformat", "hue", "external", "externalflags"];
for (var i = 0; i < checkMissingParams.length; i++) {
var pval = z_urlp(checkMissingParams[i]);
if (pval) {
$("#mainform").append("<input id=\"form_" + checkMissingParams[i] + "\" type=\"hidden\" name=\"" + checkMissingParams[i] + "\" value=\"" + pval + "\">");
}
}
// custom checks
if (obj.ctx.hue.bar.start != config.defaults.ctxHue.bar.start) {
if (!$("#form_starthue").val()) {
$("#mainform").append("<input id=\"form_starthue\" type=\"hidden\" name=\"starthue\" value=\"" + obj.ctx.hue.bar.start + "\">");
} else {
setFormValue(0, "starthue", obj.ctx.hue.bar.start);
}
}
if (obj.ctx.hue.bar.end != config.defaults.ctxHue.bar.end) {
if (!$("#form_endhue").val()) {
$("#mainform").append("<input id=\"form_endhue\" type=\"hidden\" name=\"endhue\" value=\"" + obj.ctx.hue.bar.end + "\">");
} else {
setFormValue(0, "endhue", obj.ctx.hue.bar.end);
}
}
if (obj.ctx.hue.mode != config.defaults.ctxHue.mode) {
if (!$("#form_huemode").val()) {
$("#mainform").append("<input id=\"form_huemode\" type=\"hidden\" name=\"huemode\" value=\"" + obj.ctx.hue.mode + "\">");
} else {
setFormValue(0, "huemode", obj.ctx.hue.mode);
}
}
if (debug) {
$("#form_debug").remove();
if (debug != "production") {
$("#mainform").append("<input id=\"form_debug\" type=\"hidden\" name=\"debug\" value=\"" + debug + "\">");
}
}
$("#content_wrapper").slideUp(config.effects.slideSpeed.wrapper, 'swing', function () {
$("#mainform").submit();
});
});
return false;
}
function updateProgress(evt) {
if (evt.lengthComputable) {
var thehtml = "<strong>Downloading media...</strong><br>";
var percentComplete = (evt.loaded / evt.total) * 100;
thehtml += friendlyBytes(evt.loaded) + " of " + friendlyBytes(evt.total) + " bytes (" + roundNumber(percentComplete, 1, true) + "%)";
if (!config.detection.mobile) {
thehtml += "<br> <br> <br> <br>";
} else {
if (percentComplete == 100) {
thehtml += "<br>Complete. Tap anywhere to begin playback.";
}
}
$("#playdata").html(thehtml);
}
}
function getDataFile(url) {
var req = new XMLHttpRequest();
req.onprogress = updateProgress;
req.open("GET", url, true);
req.responseType = "arraybuffer";
if (config.detection.microsoft == 11) {
req.onload = function (e) {
httpComplete(e.currentTarget.response);
}
} else {
req.onreadystatechange = function (e) {
if (req.readyState == 4) {
httpComplete(e.currentTarget.response);
}
}
}
req.send();
}
function httpComplete(data) {
media.dataBuffer = data;
loaderStage2();
}
function base64ArrayBuffer(arrayBuffer) {
var base64 = "",
encodings = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/",
bytes = new Uint8Array(arrayBuffer),
byteLength = bytes.byteLength,
byteRemainder = byteLength % 3,
mainLength = byteLength - byteRemainder,
a,
b,
c,
d,
chunk;
// Main loop deals with bytes in chunks of 3
for (var i = 0; i < mainLength; i = i + 3) {
// Combine the three bytes into a single integer
chunk = (bytes[i] << 16) | (bytes[i + 1] << 8) | bytes[i + 2];
// Use bitmasks to extract 6-bit segments from the triplet
a = (chunk & 16515072) >> 18; // 16515072 = (2^6 - 1) << 18
b = (chunk & 258048) >> 12; // 258048 = (2^6 - 1) << 12
c = (chunk & 4032) >> 6; // 4032 = (2^6 - 1) << 6
d = chunk & 63; // 63 = 2^6 - 1
// Convert the raw binary segments to the appropriate ASCII encoding
base64 += encodings[a] + encodings[b] + encodings[c] + encodings[d];
}
// Deal with the remaining bytes and padding
if (byteRemainder == 1) {
chunk = bytes[mainLength];
a = (chunk & 252) >> 2; // 252 = (2^6 - 1) << 2
// Set the 4 least significant bits to zero
b = (chunk & 3) << 4; // 3 = 2^2 - 1
base64 += encodings[a] + encodings[b] + "==";
} else if (byteRemainder == 2) {
chunk = (bytes[mainLength] << 8) | bytes[mainLength + 1];
a = (chunk & 64512) >> 10; // 64512 = (2^6 - 1) << 10
b = (chunk & 1008) >> 4; // 1008 = (2^6 - 1) << 4
// Set the 2 least significant bits to zero
c = (chunk & 15) << 2; // 15 = 2^4 - 1
base64 += encodings[a] + encodings[b] + encodings[c] + "=";
}
return base64;
}
function base64ToArrayBuffer(base64) {
var binary_string = window.atob(base64);
var len = binary_string.length;
var bytes = new Uint8Array(len);
for (var i = 0; i < len; i++) {
bytes[i] = binary_string.charCodeAt(i);
}
return bytes.buffer;
}
function testCodecs() {
var result = Howler._setupCodecs();
var codecs = result._codecs;
result.unload();
return codecs;
}
function friendlyBytes(size) {
if (size > 1073741824) {
return roundNumber((size / 1073741824), 2, true) + "GB";
}
if (size > 1048576) {
return roundNumber((size / 1048576), 2, true) + "MB";
}
if (size > 1024) {
return roundNumber((size / 1024), 2, true) + "KB";
}
return size + "B";
}
function setFPS(fps, restart) {
if (obj.fps) {
if (restart) {
obj.fps.pause();
}
obj.fps.frameRate(fps);
if (restart) {
obj.fps.start();
}
}
}
function FpsCtrl(fps, callback) {
var delay = 1000 / fps,
time = null,
frame = -1,
tref;
function loop(timestamp) {
if (time === null)
time = timestamp;
var seg = Math.floor((timestamp - time) / delay);
if (seg > frame) {
frame = seg;
callback({
time: timestamp,
frame: frame
})
}
tref = requestAnimationFrame(loop)
}
this.isPlaying = false;
this.frameRate = function (newfps) {
if (!arguments.length)
return fps;
fps = newfps;
delay = 1000 / fps;
frame = -1;
time = null;
};
this.start = function () {
if (!this.isPlaying) {
this.isPlaying = true;
tref = requestAnimationFrame(loop);
}
};
this.pause = function () {
if (this.isPlaying) {
cancelAnimationFrame(tref);
this.isPlaying = false;
time = null;
frame = -1;
}
};
}
function testWebAudio() {
var textContext;
try {
if (typeof AudioContext !== 'undefined') {
textContext = new AudioContext();
} else if (typeof webkitAudioContext !== 'undefined') {
textContext = new webkitAudioContext();
} else {
return false;
}
textContext = null;
return true;
} catch (e) {
return false;
}
}
})();