diff --git a/About/README.md b/About/README.md new file mode 100644 index 0000000..ab1360e --- /dev/null +++ b/About/README.md @@ -0,0 +1,24 @@ +# About +This is an example project, generated by AntOS Development Kit + +## Howto + +1. Open the project.apj file with AntOSDK (simply double Click on it) +2. Modify the UI in *assets/scheme.html* +3. Modify application code in *coffees/main.coffee* +4. Modify CSS style in *css/main.css* +5. Other files need to be copied: put in to assets + +## Set up build target + +Click **Menu> Build > Build Option** or simply hit **ALT-Y** + +In the build options dialog, add or remove files that need to be +included into the build + +Click **Save** + +## Build application +* To build: **Menu > Build > Build** or **ALT-C** +* To build and run: **Menu > Build > Build and Run** or **CTRL-R** +* To release: **Menu > Build > Build release** or **ALT-P** \ No newline at end of file diff --git a/About/assets/scheme.html b/About/assets/scheme.html new file mode 100644 index 0000000..d057480 --- /dev/null +++ b/About/assets/scheme.html @@ -0,0 +1,5 @@ + + +
+
+
\ No newline at end of file diff --git a/About/build/debug/README.md b/About/build/debug/README.md new file mode 100644 index 0000000..ab1360e --- /dev/null +++ b/About/build/debug/README.md @@ -0,0 +1,24 @@ +# About +This is an example project, generated by AntOS Development Kit + +## Howto + +1. Open the project.apj file with AntOSDK (simply double Click on it) +2. Modify the UI in *assets/scheme.html* +3. Modify application code in *coffees/main.coffee* +4. Modify CSS style in *css/main.css* +5. Other files need to be copied: put in to assets + +## Set up build target + +Click **Menu> Build > Build Option** or simply hit **ALT-Y** + +In the build options dialog, add or remove files that need to be +included into the build + +Click **Save** + +## Build application +* To build: **Menu > Build > Build** or **ALT-C** +* To build and run: **Menu > Build > Build and Run** or **CTRL-R** +* To release: **Menu > Build > Build release** or **ALT-P** \ No newline at end of file diff --git a/About/build/debug/main.js b/About/build/debug/main.js new file mode 100644 index 0000000..e5e530c --- /dev/null +++ b/About/build/debug/main.js @@ -0,0 +1,28 @@ +(function() { + var About; + + About = class About extends this.OS.GUI.BaseApplication { + constructor(args) { + super("About", args); + } + + main() { + var me; + me = this; + this.container = this.find("container"); + return "os://README.md".asFileHandler().read(function(txt) { + var converter; + converter = new showdown.Converter(); + return ($(me.container)).html(converter.makeHtml(txt)); + }); + } + + }; + + About.singleton = true; + + About.dependencies = ["showdown.min"]; + + this.OS.register("About", About); + +}).call(this); diff --git a/About/build/debug/package.json b/About/build/debug/package.json new file mode 100644 index 0000000..ad725d0 --- /dev/null +++ b/About/build/debug/package.json @@ -0,0 +1,13 @@ +{ + "app":"About", + "name":"About", + "description":"AntOS about", + "info":{ + "author": "Xuan Sang LE", + "email": "xsang.le@gmail.com" + }, + "version":"0.0.1-a", + "category":"Other", + "iconclass":"fa fa-question-circle", + "mimes":["none"] +} \ No newline at end of file diff --git a/About/build/debug/scheme.html b/About/build/debug/scheme.html new file mode 100644 index 0000000..d057480 --- /dev/null +++ b/About/build/debug/scheme.html @@ -0,0 +1,5 @@ + + +
+
+
\ No newline at end of file diff --git a/About/coffees/main.coffee b/About/coffees/main.coffee new file mode 100644 index 0000000..5813eff --- /dev/null +++ b/About/coffees/main.coffee @@ -0,0 +1,14 @@ +class About extends this.OS.GUI.BaseApplication + constructor: ( args ) -> + super "About", args + + main: () -> + me = @ + @container = @find "container" + "os://README.md".asFileHandler().read (txt) -> + converter = new showdown.Converter() + ($ me.container).html converter.makeHtml txt + +About.singleton = true +About.dependencies = [ "showdown.min" ] +this.OS.register "About", About \ No newline at end of file diff --git a/About/package.json b/About/package.json new file mode 100644 index 0000000..ad725d0 --- /dev/null +++ b/About/package.json @@ -0,0 +1,13 @@ +{ + "app":"About", + "name":"About", + "description":"AntOS about", + "info":{ + "author": "Xuan Sang LE", + "email": "xsang.le@gmail.com" + }, + "version":"0.0.1-a", + "category":"Other", + "iconclass":"fa fa-question-circle", + "mimes":["none"] +} \ No newline at end of file diff --git a/About/project.apj b/About/project.apj new file mode 100644 index 0000000..75a722f --- /dev/null +++ b/About/project.apj @@ -0,0 +1,8 @@ +{ + "name": "About", + "root": "home://workspace/About", + "css": [], + "javascripts": [], + "coffees": ["coffees/main.coffee"], + "copies": ["assets/scheme.html", "package.json", "README.md"] +} \ No newline at end of file diff --git a/MediaPlayer/README.md b/MediaPlayer/README.md new file mode 100644 index 0000000..79b66d0 --- /dev/null +++ b/MediaPlayer/README.md @@ -0,0 +1,24 @@ +# MediaPlayer +This is an example project, generated by AntOS Development Kit + +## Howto + +1. Open the project.apj file with AntOSDK (simply double Click on it) +2. Modify the UI in *assets/scheme.html* +3. Modify application code in *coffees/main.coffee* +4. Modify CSS style in *css/main.css* +5. Other files need to be copied: put in to assets + +## Set up build target + +Click **Menu> Build > Build Option** or simply hit **ALT-Y** + +In the build options dialog, add or remove files that need to be +included into the build + +Click **Save** + +## Build application +* To build: **Menu > Build > Build** or **ALT-C** +* To build and run: **Menu > Build > Build and Run** or **CTRL-R** +* To release: **Menu > Build > Build release** or **ALT-P** \ No newline at end of file diff --git a/MediaPlayer/assets/scheme.html b/MediaPlayer/assets/scheme.html new file mode 100644 index 0000000..51bed82 --- /dev/null +++ b/MediaPlayer/assets/scheme.html @@ -0,0 +1,44 @@ + + + + +
+ +
+ + + +
+
+ +
+ +
+
+ + +
+ +
+ + + + + +
+ + + + + +
+
+
+ +
+ +
+
+
+
+
\ No newline at end of file diff --git a/MediaPlayer/build/debug/README.md b/MediaPlayer/build/debug/README.md new file mode 100644 index 0000000..79b66d0 --- /dev/null +++ b/MediaPlayer/build/debug/README.md @@ -0,0 +1,24 @@ +# MediaPlayer +This is an example project, generated by AntOS Development Kit + +## Howto + +1. Open the project.apj file with AntOSDK (simply double Click on it) +2. Modify the UI in *assets/scheme.html* +3. Modify application code in *coffees/main.coffee* +4. Modify CSS style in *css/main.css* +5. Other files need to be copied: put in to assets + +## Set up build target + +Click **Menu> Build > Build Option** or simply hit **ALT-Y** + +In the build options dialog, add or remove files that need to be +included into the build + +Click **Save** + +## Build application +* To build: **Menu > Build > Build** or **ALT-C** +* To build and run: **Menu > Build > Build and Run** or **CTRL-R** +* To release: **Menu > Build > Build release** or **ALT-P** \ No newline at end of file diff --git a/MediaPlayer/build/debug/main.css b/MediaPlayer/build/debug/main.css new file mode 100644 index 0000000..04dee5e --- /dev/null +++ b/MediaPlayer/build/debug/main.css @@ -0,0 +1,108 @@ + +afx-app-window[data-id="MediaPlayer"] afx-hbox.play-control afx-button button{ + border: 0; + font-size: 25px; + padding-top:9px; + background-color: transparent; +} +afx-app-window[data-id="MediaPlayer"] afx-hbox.play-control afx-switch[data-id="play-pause"]{ + padding-top:5px; +} +afx-app-window[data-id="MediaPlayer"] afx-hbox.play-control afx-switch[data-id="play-pause"] span::before{ + content: "\f144"; + font-size: 40px; +} +afx-app-window[data-id="MediaPlayer"] afx-hbox.play-control afx-switch[data-id="play-pause"] .swon::before{ + content: "\f28b"; +} +afx-app-window[data-id="MediaPlayer"] afx-label[data-id="play-time"] { + text-align: left; +} +afx-app-window[data-id="MediaPlayer"] afx-label[data-id="total-time"] { + text-align: right; +} +afx-app-window[data-id="MediaPlayer"] afx-label[data-id="song-name"] { + text-align: center; + display: inline; + overflow: hidden; +} +afx-app-window[data-id="MediaPlayer"] afx-slider .dragpoint { + width:12px; + height: 12px; +} +afx-app-window[data-id="MediaPlayer"] afx-slider[data-id="vol-control"] .progress { + background-color: #a6a6a6; +} +afx-app-window[data-id="MediaPlayer"] afx-hbox.play-control afx-switch[data-id="play-vol"] { + margin-top:10px; +} +afx-app-window[data-id="MediaPlayer"] afx-hbox.play-control afx-switch[data-id="play-vol"] span::before{ + content: "\f026"; + font-size: 19px; +} +afx-app-window[data-id="MediaPlayer"] afx-hbox.play-control afx-switch[data-id="play-vol"] .swon::before{ + content: "\f028"; +} +afx-app-window[data-id="MediaPlayer"] afx-hbox.play-control afx-switch[data-id="play-random"] span::before{ + content: "\f074"; + font-size: 16px; +} +afx-app-window[data-id="MediaPlayer"] afx-hbox.play-control afx-switch[data-id="play-random"] .swon::before{ + content: "\f074"; +} +afx-app-window[data-id="MediaPlayer"] afx-hbox.play-control afx-switch[data-id="play-random"] { + margin-top:10px; +} +afx-app-window[data-id="MediaPlayer"] afx-list-view[data-id="playlist"] { + border:1px solid #a6a6a6; +} +afx-app-window[data-id="MediaPlayer"] afx-button.ctlbtn button:active{ + background-color: transparent; + color:#2786F3; +} +afx-app-window[data-id="MediaPlayer"] .animation { + position: relative; +} + +afx-app-window[data-id="MediaPlayer"] .animation span{ + width:5px; + height: 5px; + bottom:18px; + position:absolute; + -webkit-animation: bodong 0.5s infinite ease; +} + +afx-app-window[data-id="MediaPlayer"] .animation span:first-child{ + left:10px; + -webkit-animation-delay:.3s; + background-color: red; +} + +afx-app-window[data-id="MediaPlayer"] .animation span:nth-child(2){ + left:17px; + -webkit-animation-delay:.4s; + background-color:orange ; +} +afx-app-window[data-id="MediaPlayer"] .animation span:nth-child(3){ + left:24px; + -webkit-animation-delay:.6s; + background-color: #2786F3; +} +afx-app-window[data-id="MediaPlayer"] .animation span:nth-child(4){ + left:31px; + -webkit-animation-delay:.8s; + background-color: chocolate; +} +afx-app-window[data-id="MediaPlayer"] .animation span:nth-child(5){ + left:38px; + -webkit-animation-delay:1s; + background-color: blue; +} + +@-webkit-keyframes bodong{ + 0%{height:5px; background:bule;} + 30%{height:15px; background:bule;} + 60%{height:20px; background:bule;} + 80%{height:15px; background:bule;} + 100%{height:5px; background:bule;} +} diff --git a/MediaPlayer/build/debug/main.js b/MediaPlayer/build/debug/main.js new file mode 100644 index 0000000..78483de --- /dev/null +++ b/MediaPlayer/build/debug/main.js @@ -0,0 +1,444 @@ +(function() { + var MediaPlayer; + + MediaPlayer = class MediaPlayer extends this.OS.GUI.BaseApplication { + constructor(args) { + super("MediaPlayer", args); + } + + main() { + var me; + me = this; + this.volsw = this.find("play-vol"); + this.volctl = this.find("vol-control"); + this.volsw.set("swon", true); + this.volctl.set("onchange", function(v) { + if (!(me.volsw.get("swon"))) { + return; + } + return Howler.volume((me.volctl.get("value")) / 100); + }); + this.volctl.set("value", 70); + this.playlist = this.find("playlist"); + this.playtime = this.find("play-time"); + this.songname = this.find("song-name"); + this.totaltime = this.find("total-time"); + this.playpause = this.find("play-pause"); + this.progress = this.find("play-slide"); + this.playran = this.find("play-random"); + this.history = []; + this.currsong = void 0; + this.timer = void 0; + this.animator = this.find("animation"); + this.volsw.set("onchange", function(e) { + if (!e.data) { + return Howler.volume(0); + } + return Howler.volume((me.volctl.get("value")) / 100); + }); + this.playlist.set("buttons", [ + { + text: "+", + onbtclick: function() { + return me.openDialog("FileDiaLog", + function(d, + n, + p, + f) { + if (f.type === "dir") { + return me.scanDir(f); + } + f.text = f.filename; + f.iconclass = "fa fa-music"; + return me.playlist.push(f, + true); + }, + "__(Select MP3 file or a folder)", + { + mimes: ["dir", + "audio/mpeg"] + }); + } + }, + { + text: "-", + onbtclick: function() { + var sel; + sel = me.playlist.get("selected"); + if (!sel) { + return; + } + if (sel === me.currsong) { + me.stop(); + } + return me.playlist.remove(sel, + true); + } + }, + { + text: "", + onbtclick: function() { + return me.openDialog("PromptDialog", + function(link) { + var data; + if (!(link && link !== "")) { + return; + } + data = { + text: link, + path: link, + iconclass: "fa fa-link", + broadcast: true + }; + return me.playlist.push(data, + true); + }, + "__(MP3 Radio broadcast)", + { + label: "Enter radio broadcast link" + }); + }, + iconclass: "fa fa-link" + }, + { + text: "", + iconclass: "fa fa-save", + onbtclick: function() { + var fp, + i, + len1, + playlist, + ref, + v; + playlist = []; + ref = me.playlist.get("items"); + for (i = 0, len1 = ref.length; i < len1; i++) { + v = ref[i]; + playlist.push({ + text: v.text, + path: v.path, + iconclass: v.iconclass, + broadcast: v.broadcast ? v.broadcast : false + }); + } + fp = "Untitled".asFileHandler(); + return me.openDialog("FileDiaLog", + function(d, + n, + p, + f) { + fp = `${d}/${n}`.asFileHandler(); + fp.cache = playlist; + return fp.write("object", + function(r) { + if (r.error) { + return me.error(__("Cannot save playlist: {0}", + r.error)); + } + return me.notify(__("Playlist saved")); + }); + }, + "__(Save Playlist)", + { + file: fp + }); + } + }, + { + text: "", + iconclass: "fa fa-folder", + onbtclick: function() { + return me.openDialog("FileDiaLog", + function(d, + n, + p, + f) { + return f.path.asFileHandler().read(function(d) { + me.stop(); + return me.playlist.set("items", + d); + }, + "json"); + }, + "__(Open Playlist)", + { + mimes: ["application/json"] + }); + } + } + ]); + this.playlist.set("onlistdbclick", function(e) { + if (!e) { + return; + } + e.data.index = e.idx; + return me.play(e.data); + }); + this.progress.set("onchange", function(s) { + return me.seek(s); + }); + this.playpause.set("onchange", function(e) { + return me.togglePlayPause(); + }); + (this.find("play-prev")).set("onbtclick", function() { + return me.prevSong(); + }); + (this.find("play-next")).set("onbtclick", function() { + return me.nextSong(); + }); + return $(this.animator).css("visibility", "hidden"); + } + + scanDir(f) { + var me; + me = this; + return f.path.asFileHandler().read(function(d) { + var i, len1, ref, results, v; + if (d.error) { + return me.error(__("Unable to read {0}", d.error)); + } + ref = d.result; + results = []; + for (i = 0, len1 = ref.length; i < len1; i++) { + v = ref[i]; + if (!(v.mime.match(/audio\/mpeg/))) { + continue; + } + v.iconclass = "fa fa-music"; + v.text = v.filename; + results.push(me.playlist.push(v, true)); + } + return results; + }); + } + + togglePlayPause() { + var sound; + if (!(this.currsong && this.currsong.howl)) { + return this.playpause.set("swon", false); + } + sound = this.currsong.howl; + if (sound.playing()) { + return sound.pause(); + } else { + return sound.play(); + } + } + + nextSong() { + var idx, len, sel; + idx = -1; + if (this.playran.get("swon")) { + idx = this.randomSong(); + } else { + len = (this.playlist.get("items")).length; + if (len > 0) { + idx = 0; + if (this.currsong) { + idx = this.currsong.index + 1; + } + if (idx >= len) { + idx = 0; + } + } + } + if (idx === -1) { + return; + } + if (history.length >= 10) { + this.history.pop(); + } + if (this.currsong) { + this.history.unshift(this.currsong.index); + } + this.playlist.set("selected", idx); + sel = this.playlist.get("selected"); + sel.index = idx; + return this.play(sel); + } + + prevSong() { + var idx, len, sel; + idx = -1; + if (this.playran.get("swon")) { + if (this.history.length > 0) { + idx = this.history.shift(); + } + } else { + len = (this.playlist.get("items")).length; + if (len > 0) { + if (this.currsong) { + idx = this.currsong.index - 1; + } + if (idx < 0) { + idx = 0; + } + } + } + if (idx === -1) { + return; + } + this.playlist.set("selected", idx); + sel = this.playlist.get("selected"); + sel.index = idx; + return this.play(sel); + } + + randomSong() { + var len; + len = (this.playlist.get("items")).length; + if (!(len > 0)) { + return -1; + } + return Math.floor(Math.random() * Math.floor(len)); + } + + play(file) { + var me, sound; + me = this; + this.stop(); + this.currsong = file; + sound = file.howl; + if (!sound) { + sound = file.howl = new Howl({ + src: [file.path.asFileHandler().getlink()], + preload: true, + buffer: true, + html5: true, // Force to HTML5 so that the audio can stream in (best for large files). + format: ['mp3', 'aac'], + onplay: function() { + var duration, func; + $(me.animator).css("visibility", "visible"); + //Display the duration. + me.playpause.set("swon", true); + console.log("play"); + me.songname.set("text", file.text); + duration = Math.round(sound.duration()); + if (duration !== 2e308) { + me.totaltime.set("text", me.formatDuration(duration)); + me.progress.set("max", duration); + } else { + me.totaltime.set("text", "--:--"); + me.progress.set("max", 0); + } + if (!file.broadcast) { + func = function() { + var seek; + if (sound.playing()) { + seek = Math.round(sound.seek()) || 0; + me.progress.set("value", seek); + me.playtime.set("text", me.formatDuration(seek)); + return me.timer = setTimeout((function() { + return func(); + }), 1000); + } + }; + return func(); + } else { + me.totaltime.set("text", "--:--"); + me.progress.set("value", me.progress.get("max")); + func = function() { + var seek; + if (sound.playing()) { + seek = Math.round(sound.seek()) || 0; + me.playtime.set("text", me.formatDuration(seek)); + return me.timer = setTimeout((function() { + return func(); + }), 1000); + } + }; + return func(); + } + }, + onload: function() { + // Start the wave animation. + console.log("load"); + $(me.animator).css("visibility", "hidden"); + if (!file.broadcast) { + return sound.play(); + } + }, + onend: function() { + // Stop the wave animation. + me.progress.set("value", 0); + if (me.timer) { + clearTimeout(me.timer); + } + me.playpause.set("swon", false); + $(me.animator).css("visibility", "hidden"); + return me.nextSong(); + }, + onpause: function() { + // Stop the wave animation. + console.log("pause"); + if (me.timer) { + clearTimeout(me.timer); + } + me.playpause.set("swon", false); + return $(me.animator).css("visibility", "hidden"); + }, + onstop: function() { + me.progress.set("value", 0); + if (me.timer) { + clearTimeout(me.timer); + } + me.playpause.set("swon", false); + $(me.animator).css("visibility", "hidden"); + return console.log("stop"); + } + }); + if (file.broadcast) { + sound.play(); + } + } else { + sound.play(); + } + return $(this.animator).css("visibility", "visible"); + } + + stop() { + if (this.currsong && this.currsong.howl) { + if (this.currsong.howl.playing()) { + return this.currsong.howl.stop(); + } + } + } + + seek(v) { + var sound; + if (!(this.currsong && this.currsong.howl && !this.currsong.broadcast)) { + return; + } + if (!((this.progress.get("max")) > 0)) { + return; + } + sound = this.currsong.howl; + return sound.seek(v); + } + + formatDuration(s) { + var min, sec; + min = Math.floor(s / 60); + sec = s % 60; + min = min < 10 ? `0${min}` : `${min}`; + sec = sec < 10 ? `0${sec}` : `${sec}`; + return `${min}:${sec}`; + } + + cleanup(evt) { + return this.stop(); + } + + }; + + // only one instance is allow + MediaPlayer.singleton = true; + + this.OS.register("MediaPlayer", MediaPlayer); + +}).call(this); + +/*! howler.js v2.0.9 | (c) 2013-2018, James Simpson of GoldFire Studios | MIT License | howlerjs.com */ +!function(){"use strict";var e=function(){this.init()};e.prototype={init:function(){var e=this||n;return e._counter=1e3,e._codecs={},e._howls=[],e._muted=!1,e._volume=1,e._canPlayEvent="canplaythrough",e._navigator="undefined"!=typeof window&&window.navigator?window.navigator:null,e.masterGain=null,e.noAudio=!1,e.usingWebAudio=!0,e.autoSuspend=!0,e.ctx=null,e.mobileAutoEnable=!0,e._setup(),e},volume:function(e){var t=this||n;if(e=parseFloat(e),t.ctx||_(),void 0!==e&&e>=0&&e<=1){if(t._volume=e,t._muted)return t;t.usingWebAudio&&t.masterGain.gain.setValueAtTime(e,n.ctx.currentTime);for(var o=0;o=0;t--)e._howls[t].unload();return e.usingWebAudio&&e.ctx&&void 0!==e.ctx.close&&(e.ctx.close(),e.ctx=null,_()),e},codecs:function(e){return(this||n)._codecs[e.replace(/^x-/,"")]},_setup:function(){var e=this||n;if(e.state=e.ctx?e.ctx.state||"running":"running",e._autoSuspend(),!e.usingWebAudio)if("undefined"!=typeof Audio)try{var t=new Audio;void 0===t.oncanplaythrough&&(e._canPlayEvent="canplay")}catch(n){e.noAudio=!0}else e.noAudio=!0;try{var t=new Audio;t.muted&&(e.noAudio=!0)}catch(e){}return e.noAudio||e._setupCodecs(),e},_setupCodecs:function(){var e=this||n,t=null;try{t="undefined"!=typeof Audio?new Audio:null}catch(n){return e}if(!t||"function"!=typeof t.canPlayType)return e;var o=t.canPlayType("audio/mpeg;").replace(/^no$/,""),r=e._navigator&&e._navigator.userAgent.match(/OPR\/([0-6].)/g),a=r&&parseInt(r[0].split("/")[1],10)<33;return e._codecs={mp3:!(a||!o&&!t.canPlayType("audio/mp3;").replace(/^no$/,"")),mpeg:!!o,opus:!!t.canPlayType('audio/ogg; codecs="opus"').replace(/^no$/,""),ogg:!!t.canPlayType('audio/ogg; codecs="vorbis"').replace(/^no$/,""),oga:!!t.canPlayType('audio/ogg; codecs="vorbis"').replace(/^no$/,""),wav:!!t.canPlayType('audio/wav; codecs="1"').replace(/^no$/,""),aac:!!t.canPlayType("audio/aac;").replace(/^no$/,""),caf:!!t.canPlayType("audio/x-caf;").replace(/^no$/,""),m4a:!!(t.canPlayType("audio/x-m4a;")||t.canPlayType("audio/m4a;")||t.canPlayType("audio/aac;")).replace(/^no$/,""),mp4:!!(t.canPlayType("audio/x-mp4;")||t.canPlayType("audio/mp4;")||t.canPlayType("audio/aac;")).replace(/^no$/,""),weba:!!t.canPlayType('audio/webm; codecs="vorbis"').replace(/^no$/,""),webm:!!t.canPlayType('audio/webm; codecs="vorbis"').replace(/^no$/,""),dolby:!!t.canPlayType('audio/mp4; codecs="ec-3"').replace(/^no$/,""),flac:!!(t.canPlayType("audio/x-flac;")||t.canPlayType("audio/flac;")).replace(/^no$/,"")},e},_enableMobileAudio:function(){var e=this||n,t=/iPhone|iPad|iPod|Android|BlackBerry|BB10|Silk|Mobi/i.test(e._navigator&&e._navigator.userAgent),o=!!("ontouchend"in window||e._navigator&&e._navigator.maxTouchPoints>0||e._navigator&&e._navigator.msMaxTouchPoints>0);if(!e._mobileEnabled&&e.ctx&&(t||o)){e._mobileEnabled=!1,e._mobileUnloaded||44100===e.ctx.sampleRate||(e._mobileUnloaded=!0,e.unload()),e._scratchBuffer=e.ctx.createBuffer(1,1,22050);var r=function(){n._autoResume();var t=e.ctx.createBufferSource();t.buffer=e._scratchBuffer,t.connect(e.ctx.destination),void 0===t.start?t.noteOn(0):t.start(0),"function"==typeof e.ctx.resume&&e.ctx.resume(),t.onended=function(){t.disconnect(0),e._mobileEnabled=!0,e.mobileAutoEnable=!1,document.removeEventListener("touchstart",r,!0),document.removeEventListener("touchend",r,!0)}};return document.addEventListener("touchstart",r,!0),document.addEventListener("touchend",r,!0),e}},_autoSuspend:function(){var e=this;if(e.autoSuspend&&e.ctx&&void 0!==e.ctx.suspend&&n.usingWebAudio){for(var t=0;t0?i._seek:o._sprite[e][0]/1e3),s=Math.max(0,(o._sprite[e][0]+o._sprite[e][1])/1e3-_),l=1e3*s/Math.abs(i._rate);i._paused=!1,i._ended=!1,i._sprite=e,i._seek=_,i._start=o._sprite[e][0]/1e3,i._stop=(o._sprite[e][0]+o._sprite[e][1])/1e3,i._loop=!(!i._loop&&!o._sprite[e][2]);var c=i._node;if(o._webAudio){var f=function(){o._refreshBuffer(i);var e=i._muted||o._muted?0:i._volume;c.gain.setValueAtTime(e,n.ctx.currentTime),i._playStart=n.ctx.currentTime,void 0===c.bufferSource.start?i._loop?c.bufferSource.noteGrainOn(0,_,86400):c.bufferSource.noteGrainOn(0,_,s):i._loop?c.bufferSource.start(0,_,86400):c.bufferSource.start(0,_,s),l!==1/0&&(o._endTimers[i._id]=setTimeout(o._ended.bind(o,i),l)),t||setTimeout(function(){o._emit("play",i._id)},0)};"running"===n.state?f():(o.once("resume",f),o._clearTimer(i._id))}else{var p=function(){c.currentTime=_,c.muted=i._muted||o._muted||n._muted||c.muted,c.volume=i._volume*n.volume(),c.playbackRate=i._rate;try{var r=c.play();if("undefined"!=typeof Promise&&r instanceof Promise){o._playLock=!0;var a=function(){o._playLock=!1,t||o._emit("play",i._id)};r.then(a,a)}else t||o._emit("play",i._id);if(c.paused)return void o._emit("playerror",i._id,"Playback was unable to start. This is most commonly an issue on mobile devices where playback was not within a user interaction.");"__default"!==e?o._endTimers[i._id]=setTimeout(o._ended.bind(o,i),l):(o._endTimers[i._id]=function(){o._ended(i),c.removeEventListener("ended",o._endTimers[i._id],!1)},c.addEventListener("ended",o._endTimers[i._id],!1))}catch(e){o._emit("playerror",i._id,e)}},m=window&&window.ejecta||!c.readyState&&n._navigator.isCocoonJS;if(c.readyState>=3||m)p();else{var v=function(){p(),c.removeEventListener(n._canPlayEvent,v,!1)};c.addEventListener(n._canPlayEvent,v,!1),o._clearTimer(i._id)}}return i._id},pause:function(e){var n=this;if("loaded"!==n._state||n._playLock)return n._queue.push({event:"pause",action:function(){n.pause(e)}}),n;for(var t=n._getSoundIds(e),o=0;o=0?t=parseInt(r[0],10):e=parseFloat(r[0])}else r.length>=2&&(e=parseFloat(r[0]),t=parseInt(r[1],10));var a;if(!(void 0!==e&&e>=0&&e<=1))return a=t?o._soundById(t):o._sounds[0],a?a._volume:0;if("loaded"!==o._state)return o._queue.push({event:"volume",action:function(){o.volume.apply(o,r)}}),o;void 0===t&&(o._volume=e),t=o._getSoundIds(t);for(var u=0;u0?o/_:o),l=Date.now();e._fadeTo=t,e._interval=setInterval(function(){var r=(Date.now()-l)/o;l=Date.now(),i+=d*r,i=Math.max(0,i),i=Math.min(1,i),i=Math.round(100*i)/100,u._webAudio?e._volume=i:u.volume(i,e._id,!0),a&&(u._volume=i),(tn&&i>=t)&&(clearInterval(e._interval),e._interval=null,e._fadeTo=null,u.volume(t,e._id),u._emit("fade",e._id))},s)},_stopFade:function(e){var t=this,o=t._soundById(e);return o&&o._interval&&(t._webAudio&&o._node.gain.cancelScheduledValues(n.ctx.currentTime),clearInterval(o._interval),o._interval=null,t.volume(o._fadeTo,e),o._fadeTo=null,t._emit("fade",e)),t},loop:function(){var e,n,t,o=this,r=arguments;if(0===r.length)return o._loop;if(1===r.length){if("boolean"!=typeof r[0])return!!(t=o._soundById(parseInt(r[0],10)))&&t._loop;e=r[0],o._loop=e}else 2===r.length&&(e=r[0],n=parseInt(r[1],10));for(var a=o._getSoundIds(n),u=0;u=0?t=parseInt(r[0],10):e=parseFloat(r[0])}else 2===r.length&&(e=parseFloat(r[0]),t=parseInt(r[1],10));var i;if("number"!=typeof e)return i=o._soundById(t),i?i._rate:o._rate;if("loaded"!==o._state)return o._queue.push({event:"rate",action:function(){o.rate.apply(o,r)}}),o;void 0===t&&(o._rate=e),t=o._getSoundIds(t);for(var d=0;d=0?t=parseInt(r[0],10):o._sounds.length&&(t=o._sounds[0]._id,e=parseFloat(r[0]))}else 2===r.length&&(e=parseFloat(r[0]),t=parseInt(r[1],10));if(void 0===t)return o;if("loaded"!==o._state)return o._queue.push({event:"seek",action:function(){o.seek.apply(o,r)}}),o;var i=o._soundById(t);if(i){if(!("number"==typeof e&&e>=0)){if(o._webAudio){var d=o.playing(t)?n.ctx.currentTime-i._playStart:0,_=i._rateSeek?i._rateSeek-i._seek:0;return i._seek+(_+d*Math.abs(i._rate))}return i._node.currentTime}var s=o.playing(t);if(s&&o.pause(t,!0),i._seek=e,i._ended=!1,o._clearTimer(t),s&&o.play(t,!0),!o._webAudio&&i._node&&(i._node.currentTime=e),s&&!o._webAudio){var l=function(){o._playLock?setTimeout(l,0):o._emit("seek",t)};setTimeout(l,0)}else o._emit("seek",t)}return o},playing:function(e){var n=this;if("number"==typeof e){var t=n._soundById(e);return!!t&&!t._paused}for(var o=0;o=0&&n._howls.splice(a,1)}var u=!0;for(o=0;o=0;a--)r[a].id&&r[a].id!==n&&"load"!==e||(setTimeout(function(e){e.call(this,n,t)}.bind(o,r[a].fn),0),r[a].once&&o.off(e,r[a].fn,r[a].id));return o._loadQueue(e),o},_loadQueue:function(e){var n=this;if(n._queue.length>0){var t=n._queue[0];t.event===e&&(n._queue.shift(),n._loadQueue()),e||t.action()}return n},_ended:function(e){var t=this,o=e._sprite;if(!t._webAudio&&e._node&&!e._node.paused&&!e._node.ended&&e._node.currentTime=0;o--){if(t<=n)return;e._sounds[o]._ended&&(e._webAudio&&e._sounds[o]._node&&e._sounds[o]._node.disconnect(0),e._sounds.splice(o,1),t--)}}},_getSoundIds:function(e){var n=this;if(void 0===e){for(var t=[],o=0;o0&&(r[t._src]=e,d(t,e))},function(){t._emit("loaderror",null,"Decoding audio data failed.")})},d=function(e,n){n&&!e._duration&&(e._duration=n.duration),0===Object.keys(e._sprite).length&&(e._sprite={__default:[0,1e3*e._duration]}),"loaded"!==e._state&&(e._state="loaded",e._emit("load"),e._loadQueue())},_=function(){try{"undefined"!=typeof AudioContext?n.ctx=new AudioContext:"undefined"!=typeof webkitAudioContext?n.ctx=new webkitAudioContext:n.usingWebAudio=!1}catch(e){n.usingWebAudio=!1}var e=/iP(hone|od|ad)/.test(n._navigator&&n._navigator.platform),t=n._navigator&&n._navigator.appVersion.match(/OS (\d+)_(\d+)_?(\d+)?/),o=t?parseInt(t[1],10):null;if(e&&o&&o<9){var r=/safari/.test(n._navigator&&n._navigator.userAgent.toLowerCase());(n._navigator&&n._navigator.standalone&&!r||n._navigator&&!n._navigator.standalone&&!r)&&(n.usingWebAudio=!1)}n.usingWebAudio&&(n.masterGain=void 0===n.ctx.createGain?n.ctx.createGainNode():n.ctx.createGain(),n.masterGain.gain.setValueAtTime(n._muted?0:1,n.ctx.currentTime),n.masterGain.connect(n.ctx.destination)),n._setup()};"function"==typeof define&&define.amd&&define([],function(){return{Howler:n,Howl:t}}),"undefined"!=typeof exports&&(exports.Howler=n,exports.Howl=t),"undefined"!=typeof window?(window.HowlerGlobal=e,window.Howler=n,window.Howl=t,window.Sound=o):"undefined"!=typeof global&&(global.HowlerGlobal=e,global.Howler=n,global.Howl=t,global.Sound=o)}(); +/*! Spatial Plugin */ +!function(){"use strict";HowlerGlobal.prototype._pos=[0,0,0],HowlerGlobal.prototype._orientation=[0,0,-1,0,1,0],HowlerGlobal.prototype.stereo=function(n){var e=this;if(!e.ctx||!e.ctx.listener)return e;for(var t=e._howls.length-1;t>=0;t--)e._howls[t].stereo(n);return e},HowlerGlobal.prototype.pos=function(n,e,t){var o=this;return o.ctx&&o.ctx.listener?(e="number"!=typeof e?o._pos[1]:e,t="number"!=typeof t?o._pos[2]:t,"number"!=typeof n?o._pos:(o._pos=[n,e,t],o.ctx.listener.setPosition(o._pos[0],o._pos[1],o._pos[2]),o)):o},HowlerGlobal.prototype.orientation=function(n,e,t,o,r,a){var i=this;if(!i.ctx||!i.ctx.listener)return i;var p=i._orientation;return e="number"!=typeof e?p[1]:e,t="number"!=typeof t?p[2]:t,o="number"!=typeof o?p[3]:o,r="number"!=typeof r?p[4]:r,a="number"!=typeof a?p[5]:a,"number"!=typeof n?p:(i._orientation=[n,e,t,o,r,a],i.ctx.listener.setOrientation(n,e,t,o,r,a),i)},Howl.prototype.init=function(n){return function(e){var t=this;return t._orientation=e.orientation||[1,0,0],t._stereo=e.stereo||null,t._pos=e.pos||null,t._pannerAttr={coneInnerAngle:void 0!==e.coneInnerAngle?e.coneInnerAngle:360,coneOuterAngle:void 0!==e.coneOuterAngle?e.coneOuterAngle:360,coneOuterGain:void 0!==e.coneOuterGain?e.coneOuterGain:0,distanceModel:void 0!==e.distanceModel?e.distanceModel:"inverse",maxDistance:void 0!==e.maxDistance?e.maxDistance:1e4,panningModel:void 0!==e.panningModel?e.panningModel:"HRTF",refDistance:void 0!==e.refDistance?e.refDistance:1,rolloffFactor:void 0!==e.rolloffFactor?e.rolloffFactor:1},t._onstereo=e.onstereo?[{fn:e.onstereo}]:[],t._onpos=e.onpos?[{fn:e.onpos}]:[],t._onorientation=e.onorientation?[{fn:e.onorientation}]:[],n.call(this,e)}}(Howl.prototype.init),Howl.prototype.stereo=function(e,t){var o=this;if(!o._webAudio)return o;if("loaded"!==o._state)return o._queue.push({event:"stereo",action:function(){o.stereo(e,t)}}),o;var r=void 0===Howler.ctx.createStereoPanner?"spatial":"stereo";if(void 0===t){if("number"!=typeof e)return o._stereo;o._stereo=e,o._pos=[e,0,0]}for(var a=o._getSoundIds(t),i=0;i + + + +
+ +
+ + + +
+
+ +
+ +
+
+ + +
+ +
+ + + + + +
+ + + + + +
+
+
+ +
+ +
+
+
+
+ \ No newline at end of file diff --git a/MediaPlayer/coffees/main.coffee b/MediaPlayer/coffees/main.coffee new file mode 100644 index 0000000..889f7fc --- /dev/null +++ b/MediaPlayer/coffees/main.coffee @@ -0,0 +1,262 @@ +class MediaPlayer extends this.OS.GUI.BaseApplication + constructor: ( args ) -> + super "MediaPlayer", args + + main: () -> + me = @ + @volsw = @find "play-vol" + @volctl = @find "vol-control" + @volsw.set "swon", true + @volctl.set "onchange", (v) -> + return unless (me.volsw.get "swon") + Howler.volume (me.volctl.get "value")/100 + @volctl.set "value", 70 + @playlist = @find "playlist" + @playtime = @find "play-time" + @songname = @find "song-name" + @totaltime = @find "total-time" + @playpause = @find "play-pause" + @progress = @find "play-slide" + @playran = @find "play-random" + @history = [] + @currsong = undefined + @timer = undefined + @animator = @find "animation" + + @volsw.set "onchange", (e) -> + return Howler.volume 0 if not e.data + Howler.volume (me.volctl.get "value")/100 + @playlist.set "buttons", [ + { + text: "+", + onbtclick: () -> + me.openDialog "FileDiaLog", (d,n,p,f) -> + return me.scanDir f if f.type is "dir" + f.text = f.filename + f.iconclass = "fa fa-music" + me.playlist.push f, true + , "__(Select MP3 file or a folder)" + , { mimes: ["dir", "audio/mpeg"] } + }, + { + text: "-", + onbtclick: () -> + sel = me.playlist.get "selected" + return unless sel + me.stop() if sel is me.currsong + me.playlist.remove sel, true + }, + { + text: "", + onbtclick: () -> + me.openDialog "PromptDialog", (link) -> + return unless link and link isnt "" + data = { + text: link, + path: link, + iconclass: "fa fa-link", + broadcast: true + } + me.playlist.push data, true + , "__(MP3 Radio broadcast)", { label:"Enter radio broadcast link" } + , iconclass: "fa fa-link" + }, + { + text:"", + iconclass: "fa fa-save", + onbtclick: () -> + playlist = [] + for v in me.playlist.get "items" + playlist.push { + text: v.text, + path: v.path, + iconclass: v.iconclass, + broadcast: if v.broadcast then v.broadcast else false + } + fp = "Untitled".asFileHandler() + me.openDialog "FileDiaLog", (d,n,p,f) -> + fp = "#{d}/#{n}".asFileHandler() + fp.cache = playlist + fp.write "object", (r) -> + return me.error __("Cannot save playlist: {0}", r.error) if r.error + me.notify __("Playlist saved") + , "__(Save Playlist)", { file: fp } + }, + { + text:"", + iconclass: "fa fa-folder", + onbtclick: () -> + me.openDialog "FileDiaLog", (d,n,p,f) -> + f.path.asFileHandler().read (d) -> + me.stop() + me.playlist.set "items", d + , "json" + , "__(Open Playlist)", { mimes: ["application/json"] } + } + ] + @playlist.set "onlistdbclick", (e) -> + return unless e + e.data.index = e.idx + me.play e.data + @progress.set "onchange", (s) -> + me.seek s + @playpause.set "onchange", (e) -> + me.togglePlayPause() + (@find "play-prev").set "onbtclick", () -> + me.prevSong() + (@find "play-next").set "onbtclick", () -> + me.nextSong() + $(@animator).css("visibility", "hidden") + scanDir: (f) -> + me = @ + f.path.asFileHandler().read (d) -> + return me.error __("Unable to read {0}", d.error) if d.error + for v in d.result when v.mime.match /audio\/mpeg/ + v.iconclass = "fa fa-music" + v.text = v.filename + me.playlist.push v, true + + + togglePlayPause: () -> + return @playpause.set "swon",false unless @currsong and @currsong.howl + sound = @currsong.howl + if sound.playing() + sound.pause() + else + sound.play() + + nextSong: () -> + idx = -1 + if (@playran.get "swon") + idx = @randomSong() + else + len = (@playlist.get "items").length + if len > 0 + idx = 0 + idx = @currsong.index + 1 if @currsong + idx = 0 if idx >= len + return if idx is -1 + @history.pop() if history.length >= 10 + @history.unshift @currsong.index if @currsong + @playlist.set "selected", idx + sel = @playlist.get "selected" + sel.index = idx + @play sel + + prevSong: () -> + idx = -1 + if (@playran.get "swon") + idx = @history.shift() if @history.length > 0 + else + len = (@playlist.get "items").length + if len > 0 + idx = @currsong.index - 1 if @currsong + idx = 0 if idx < 0 + return if idx is -1 + @playlist.set "selected", idx + sel = @playlist.get "selected" + sel.index = idx + @play sel + + randomSong: () -> + len = (@playlist.get "items").length + return -1 unless len > 0 + return Math.floor(Math.random() * Math.floor(len)) + + play: (file) -> + me = @ + @stop() + @currsong = file + sound = file.howl + if not sound + sound = file.howl = new Howl { + src: [ + file.path.asFileHandler().getlink() + ], + preload:true, + buffer: true, + html5: true, # Force to HTML5 so that the audio can stream in (best for large files). + format: ['mp3', 'aac'], + onplay: () -> + $(me.animator).css("visibility", "visible") + #Display the duration. + me.playpause.set "swon", true + console.log "play" + me.songname.set "text", file.text + duration = Math.round(sound.duration()) + if duration isnt Infinity + me.totaltime.set "text", me.formatDuration duration + me.progress.set "max", duration + else + me.totaltime.set "text", "--:--" + me.progress.set "max", 0 + if not file.broadcast + func = () -> + if sound.playing() + seek = Math.round(sound.seek()) || 0 + me.progress.set "value", seek + me.playtime.set "text", me.formatDuration seek + me.timer = setTimeout (() -> func()), 1000 + func() + else + me.totaltime.set "text", "--:--" + me.progress.set "value", (me.progress.get "max") + func = () -> + if sound.playing() + seek = Math.round(sound.seek()) || 0 + me.playtime.set "text", me.formatDuration seek + me.timer = setTimeout (() -> func()), 1000 + func() + onload: () -> + # Start the wave animation. + console.log "load" + $(me.animator).css("visibility", "hidden") + sound.play() if not file.broadcast + + onend: () -> + # Stop the wave animation. + me.progress.set "value", 0 + clearTimeout me.timer if me.timer + me.playpause.set "swon", false + $(me.animator).css("visibility", "hidden") + me.nextSong() + onpause: ()-> + # Stop the wave animation. + console.log "pause" + clearTimeout me.timer if me.timer + me.playpause.set "swon", false + $(me.animator).css("visibility", "hidden") + + onstop: () -> + me.progress.set "value", 0 + clearTimeout me.timer if me.timer + me.playpause.set "swon", false + $(me.animator).css("visibility", "hidden") + console.log "stop" + } + sound.play() if file.broadcast + else + sound.play() + $(@animator).css("visibility", "visible") + stop: () -> + if @currsong and @currsong.howl + @currsong.howl.stop() if @currsong.howl.playing() + + seek: (v) -> + return unless @currsong and @currsong.howl and not @currsong.broadcast + return unless (@progress.get "max") > 0 + sound = @currsong.howl + sound.seek(v) + + formatDuration: (s) -> + min = Math.floor(s/60) + sec = s % 60 + min = if min < 10 then "0#{min}" else "#{min}" + sec = if sec < 10 then "0#{sec}" else "#{sec}" + "#{min}:#{sec}" + + cleanup: (evt) -> + @stop() +# only one instance is allow +MediaPlayer.singleton = true +this.OS.register "MediaPlayer", MediaPlayer \ No newline at end of file diff --git a/MediaPlayer/css/main.css b/MediaPlayer/css/main.css new file mode 100644 index 0000000..a1ed196 --- /dev/null +++ b/MediaPlayer/css/main.css @@ -0,0 +1,107 @@ +afx-app-window[data-id="MediaPlayer"] afx-hbox.play-control afx-button button{ + border: 0; + font-size: 25px; + padding-top:9px; + background-color: transparent; +} +afx-app-window[data-id="MediaPlayer"] afx-hbox.play-control afx-switch[data-id="play-pause"]{ + padding-top:5px; +} +afx-app-window[data-id="MediaPlayer"] afx-hbox.play-control afx-switch[data-id="play-pause"] span::before{ + content: "\f144"; + font-size: 40px; +} +afx-app-window[data-id="MediaPlayer"] afx-hbox.play-control afx-switch[data-id="play-pause"] .swon::before{ + content: "\f28b"; +} +afx-app-window[data-id="MediaPlayer"] afx-label[data-id="play-time"] { + text-align: left; +} +afx-app-window[data-id="MediaPlayer"] afx-label[data-id="total-time"] { + text-align: right; +} +afx-app-window[data-id="MediaPlayer"] afx-label[data-id="song-name"] { + text-align: center; + display: inline; + overflow: hidden; +} +afx-app-window[data-id="MediaPlayer"] afx-slider .dragpoint { + width:12px; + height: 12px; +} +afx-app-window[data-id="MediaPlayer"] afx-slider[data-id="vol-control"] .progress { + background-color: #a6a6a6; +} +afx-app-window[data-id="MediaPlayer"] afx-hbox.play-control afx-switch[data-id="play-vol"] { + margin-top:10px; +} +afx-app-window[data-id="MediaPlayer"] afx-hbox.play-control afx-switch[data-id="play-vol"] span::before{ + content: "\f026"; + font-size: 19px; +} +afx-app-window[data-id="MediaPlayer"] afx-hbox.play-control afx-switch[data-id="play-vol"] .swon::before{ + content: "\f028"; +} +afx-app-window[data-id="MediaPlayer"] afx-hbox.play-control afx-switch[data-id="play-random"] span::before{ + content: "\f074"; + font-size: 16px; +} +afx-app-window[data-id="MediaPlayer"] afx-hbox.play-control afx-switch[data-id="play-random"] .swon::before{ + content: "\f074"; +} +afx-app-window[data-id="MediaPlayer"] afx-hbox.play-control afx-switch[data-id="play-random"] { + margin-top:10px; +} +afx-app-window[data-id="MediaPlayer"] afx-list-view[data-id="playlist"] { + border:1px solid #a6a6a6; +} +afx-app-window[data-id="MediaPlayer"] afx-button.ctlbtn button:active{ + background-color: transparent; + color:#2786F3; +} +afx-app-window[data-id="MediaPlayer"] .animation { + position: relative; +} + +afx-app-window[data-id="MediaPlayer"] .animation span{ + width:5px; + height: 5px; + bottom:18px; + position:absolute; + -webkit-animation: bodong 0.5s infinite ease; +} + +afx-app-window[data-id="MediaPlayer"] .animation span:first-child{ + left:10px; + -webkit-animation-delay:.3s; + background-color: red; +} + +afx-app-window[data-id="MediaPlayer"] .animation span:nth-child(2){ + left:17px; + -webkit-animation-delay:.4s; + background-color:orange ; +} +afx-app-window[data-id="MediaPlayer"] .animation span:nth-child(3){ + left:24px; + -webkit-animation-delay:.6s; + background-color: #2786F3; +} +afx-app-window[data-id="MediaPlayer"] .animation span:nth-child(4){ + left:31px; + -webkit-animation-delay:.8s; + background-color: chocolate; +} +afx-app-window[data-id="MediaPlayer"] .animation span:nth-child(5){ + left:38px; + -webkit-animation-delay:1s; + background-color: blue; +} + +@-webkit-keyframes bodong{ + 0%{height:5px; background:bule;} + 30%{height:15px; background:bule;} + 60%{height:20px; background:bule;} + 80%{height:15px; background:bule;} + 100%{height:5px; background:bule;} +} diff --git a/MediaPlayer/javascripts/howler.min.js b/MediaPlayer/javascripts/howler.min.js new file mode 100644 index 0000000..b6a1145 --- /dev/null +++ b/MediaPlayer/javascripts/howler.min.js @@ -0,0 +1,4 @@ +/*! howler.js v2.0.9 | (c) 2013-2018, James Simpson of GoldFire Studios | MIT License | howlerjs.com */ +!function(){"use strict";var e=function(){this.init()};e.prototype={init:function(){var e=this||n;return e._counter=1e3,e._codecs={},e._howls=[],e._muted=!1,e._volume=1,e._canPlayEvent="canplaythrough",e._navigator="undefined"!=typeof window&&window.navigator?window.navigator:null,e.masterGain=null,e.noAudio=!1,e.usingWebAudio=!0,e.autoSuspend=!0,e.ctx=null,e.mobileAutoEnable=!0,e._setup(),e},volume:function(e){var t=this||n;if(e=parseFloat(e),t.ctx||_(),void 0!==e&&e>=0&&e<=1){if(t._volume=e,t._muted)return t;t.usingWebAudio&&t.masterGain.gain.setValueAtTime(e,n.ctx.currentTime);for(var o=0;o=0;t--)e._howls[t].unload();return e.usingWebAudio&&e.ctx&&void 0!==e.ctx.close&&(e.ctx.close(),e.ctx=null,_()),e},codecs:function(e){return(this||n)._codecs[e.replace(/^x-/,"")]},_setup:function(){var e=this||n;if(e.state=e.ctx?e.ctx.state||"running":"running",e._autoSuspend(),!e.usingWebAudio)if("undefined"!=typeof Audio)try{var t=new Audio;void 0===t.oncanplaythrough&&(e._canPlayEvent="canplay")}catch(n){e.noAudio=!0}else e.noAudio=!0;try{var t=new Audio;t.muted&&(e.noAudio=!0)}catch(e){}return e.noAudio||e._setupCodecs(),e},_setupCodecs:function(){var e=this||n,t=null;try{t="undefined"!=typeof Audio?new Audio:null}catch(n){return e}if(!t||"function"!=typeof t.canPlayType)return e;var o=t.canPlayType("audio/mpeg;").replace(/^no$/,""),r=e._navigator&&e._navigator.userAgent.match(/OPR\/([0-6].)/g),a=r&&parseInt(r[0].split("/")[1],10)<33;return e._codecs={mp3:!(a||!o&&!t.canPlayType("audio/mp3;").replace(/^no$/,"")),mpeg:!!o,opus:!!t.canPlayType('audio/ogg; codecs="opus"').replace(/^no$/,""),ogg:!!t.canPlayType('audio/ogg; codecs="vorbis"').replace(/^no$/,""),oga:!!t.canPlayType('audio/ogg; codecs="vorbis"').replace(/^no$/,""),wav:!!t.canPlayType('audio/wav; codecs="1"').replace(/^no$/,""),aac:!!t.canPlayType("audio/aac;").replace(/^no$/,""),caf:!!t.canPlayType("audio/x-caf;").replace(/^no$/,""),m4a:!!(t.canPlayType("audio/x-m4a;")||t.canPlayType("audio/m4a;")||t.canPlayType("audio/aac;")).replace(/^no$/,""),mp4:!!(t.canPlayType("audio/x-mp4;")||t.canPlayType("audio/mp4;")||t.canPlayType("audio/aac;")).replace(/^no$/,""),weba:!!t.canPlayType('audio/webm; codecs="vorbis"').replace(/^no$/,""),webm:!!t.canPlayType('audio/webm; codecs="vorbis"').replace(/^no$/,""),dolby:!!t.canPlayType('audio/mp4; codecs="ec-3"').replace(/^no$/,""),flac:!!(t.canPlayType("audio/x-flac;")||t.canPlayType("audio/flac;")).replace(/^no$/,"")},e},_enableMobileAudio:function(){var e=this||n,t=/iPhone|iPad|iPod|Android|BlackBerry|BB10|Silk|Mobi/i.test(e._navigator&&e._navigator.userAgent),o=!!("ontouchend"in window||e._navigator&&e._navigator.maxTouchPoints>0||e._navigator&&e._navigator.msMaxTouchPoints>0);if(!e._mobileEnabled&&e.ctx&&(t||o)){e._mobileEnabled=!1,e._mobileUnloaded||44100===e.ctx.sampleRate||(e._mobileUnloaded=!0,e.unload()),e._scratchBuffer=e.ctx.createBuffer(1,1,22050);var r=function(){n._autoResume();var t=e.ctx.createBufferSource();t.buffer=e._scratchBuffer,t.connect(e.ctx.destination),void 0===t.start?t.noteOn(0):t.start(0),"function"==typeof e.ctx.resume&&e.ctx.resume(),t.onended=function(){t.disconnect(0),e._mobileEnabled=!0,e.mobileAutoEnable=!1,document.removeEventListener("touchstart",r,!0),document.removeEventListener("touchend",r,!0)}};return document.addEventListener("touchstart",r,!0),document.addEventListener("touchend",r,!0),e}},_autoSuspend:function(){var e=this;if(e.autoSuspend&&e.ctx&&void 0!==e.ctx.suspend&&n.usingWebAudio){for(var t=0;t0?i._seek:o._sprite[e][0]/1e3),s=Math.max(0,(o._sprite[e][0]+o._sprite[e][1])/1e3-_),l=1e3*s/Math.abs(i._rate);i._paused=!1,i._ended=!1,i._sprite=e,i._seek=_,i._start=o._sprite[e][0]/1e3,i._stop=(o._sprite[e][0]+o._sprite[e][1])/1e3,i._loop=!(!i._loop&&!o._sprite[e][2]);var c=i._node;if(o._webAudio){var f=function(){o._refreshBuffer(i);var e=i._muted||o._muted?0:i._volume;c.gain.setValueAtTime(e,n.ctx.currentTime),i._playStart=n.ctx.currentTime,void 0===c.bufferSource.start?i._loop?c.bufferSource.noteGrainOn(0,_,86400):c.bufferSource.noteGrainOn(0,_,s):i._loop?c.bufferSource.start(0,_,86400):c.bufferSource.start(0,_,s),l!==1/0&&(o._endTimers[i._id]=setTimeout(o._ended.bind(o,i),l)),t||setTimeout(function(){o._emit("play",i._id)},0)};"running"===n.state?f():(o.once("resume",f),o._clearTimer(i._id))}else{var p=function(){c.currentTime=_,c.muted=i._muted||o._muted||n._muted||c.muted,c.volume=i._volume*n.volume(),c.playbackRate=i._rate;try{var r=c.play();if("undefined"!=typeof Promise&&r instanceof Promise){o._playLock=!0;var a=function(){o._playLock=!1,t||o._emit("play",i._id)};r.then(a,a)}else t||o._emit("play",i._id);if(c.paused)return void o._emit("playerror",i._id,"Playback was unable to start. This is most commonly an issue on mobile devices where playback was not within a user interaction.");"__default"!==e?o._endTimers[i._id]=setTimeout(o._ended.bind(o,i),l):(o._endTimers[i._id]=function(){o._ended(i),c.removeEventListener("ended",o._endTimers[i._id],!1)},c.addEventListener("ended",o._endTimers[i._id],!1))}catch(e){o._emit("playerror",i._id,e)}},m=window&&window.ejecta||!c.readyState&&n._navigator.isCocoonJS;if(c.readyState>=3||m)p();else{var v=function(){p(),c.removeEventListener(n._canPlayEvent,v,!1)};c.addEventListener(n._canPlayEvent,v,!1),o._clearTimer(i._id)}}return i._id},pause:function(e){var n=this;if("loaded"!==n._state||n._playLock)return n._queue.push({event:"pause",action:function(){n.pause(e)}}),n;for(var t=n._getSoundIds(e),o=0;o=0?t=parseInt(r[0],10):e=parseFloat(r[0])}else r.length>=2&&(e=parseFloat(r[0]),t=parseInt(r[1],10));var a;if(!(void 0!==e&&e>=0&&e<=1))return a=t?o._soundById(t):o._sounds[0],a?a._volume:0;if("loaded"!==o._state)return o._queue.push({event:"volume",action:function(){o.volume.apply(o,r)}}),o;void 0===t&&(o._volume=e),t=o._getSoundIds(t);for(var u=0;u0?o/_:o),l=Date.now();e._fadeTo=t,e._interval=setInterval(function(){var r=(Date.now()-l)/o;l=Date.now(),i+=d*r,i=Math.max(0,i),i=Math.min(1,i),i=Math.round(100*i)/100,u._webAudio?e._volume=i:u.volume(i,e._id,!0),a&&(u._volume=i),(tn&&i>=t)&&(clearInterval(e._interval),e._interval=null,e._fadeTo=null,u.volume(t,e._id),u._emit("fade",e._id))},s)},_stopFade:function(e){var t=this,o=t._soundById(e);return o&&o._interval&&(t._webAudio&&o._node.gain.cancelScheduledValues(n.ctx.currentTime),clearInterval(o._interval),o._interval=null,t.volume(o._fadeTo,e),o._fadeTo=null,t._emit("fade",e)),t},loop:function(){var e,n,t,o=this,r=arguments;if(0===r.length)return o._loop;if(1===r.length){if("boolean"!=typeof r[0])return!!(t=o._soundById(parseInt(r[0],10)))&&t._loop;e=r[0],o._loop=e}else 2===r.length&&(e=r[0],n=parseInt(r[1],10));for(var a=o._getSoundIds(n),u=0;u=0?t=parseInt(r[0],10):e=parseFloat(r[0])}else 2===r.length&&(e=parseFloat(r[0]),t=parseInt(r[1],10));var i;if("number"!=typeof e)return i=o._soundById(t),i?i._rate:o._rate;if("loaded"!==o._state)return o._queue.push({event:"rate",action:function(){o.rate.apply(o,r)}}),o;void 0===t&&(o._rate=e),t=o._getSoundIds(t);for(var d=0;d=0?t=parseInt(r[0],10):o._sounds.length&&(t=o._sounds[0]._id,e=parseFloat(r[0]))}else 2===r.length&&(e=parseFloat(r[0]),t=parseInt(r[1],10));if(void 0===t)return o;if("loaded"!==o._state)return o._queue.push({event:"seek",action:function(){o.seek.apply(o,r)}}),o;var i=o._soundById(t);if(i){if(!("number"==typeof e&&e>=0)){if(o._webAudio){var d=o.playing(t)?n.ctx.currentTime-i._playStart:0,_=i._rateSeek?i._rateSeek-i._seek:0;return i._seek+(_+d*Math.abs(i._rate))}return i._node.currentTime}var s=o.playing(t);if(s&&o.pause(t,!0),i._seek=e,i._ended=!1,o._clearTimer(t),s&&o.play(t,!0),!o._webAudio&&i._node&&(i._node.currentTime=e),s&&!o._webAudio){var l=function(){o._playLock?setTimeout(l,0):o._emit("seek",t)};setTimeout(l,0)}else o._emit("seek",t)}return o},playing:function(e){var n=this;if("number"==typeof e){var t=n._soundById(e);return!!t&&!t._paused}for(var o=0;o=0&&n._howls.splice(a,1)}var u=!0;for(o=0;o=0;a--)r[a].id&&r[a].id!==n&&"load"!==e||(setTimeout(function(e){e.call(this,n,t)}.bind(o,r[a].fn),0),r[a].once&&o.off(e,r[a].fn,r[a].id));return o._loadQueue(e),o},_loadQueue:function(e){var n=this;if(n._queue.length>0){var t=n._queue[0];t.event===e&&(n._queue.shift(),n._loadQueue()),e||t.action()}return n},_ended:function(e){var t=this,o=e._sprite;if(!t._webAudio&&e._node&&!e._node.paused&&!e._node.ended&&e._node.currentTime=0;o--){if(t<=n)return;e._sounds[o]._ended&&(e._webAudio&&e._sounds[o]._node&&e._sounds[o]._node.disconnect(0),e._sounds.splice(o,1),t--)}}},_getSoundIds:function(e){var n=this;if(void 0===e){for(var t=[],o=0;o0&&(r[t._src]=e,d(t,e))},function(){t._emit("loaderror",null,"Decoding audio data failed.")})},d=function(e,n){n&&!e._duration&&(e._duration=n.duration),0===Object.keys(e._sprite).length&&(e._sprite={__default:[0,1e3*e._duration]}),"loaded"!==e._state&&(e._state="loaded",e._emit("load"),e._loadQueue())},_=function(){try{"undefined"!=typeof AudioContext?n.ctx=new AudioContext:"undefined"!=typeof webkitAudioContext?n.ctx=new webkitAudioContext:n.usingWebAudio=!1}catch(e){n.usingWebAudio=!1}var e=/iP(hone|od|ad)/.test(n._navigator&&n._navigator.platform),t=n._navigator&&n._navigator.appVersion.match(/OS (\d+)_(\d+)_?(\d+)?/),o=t?parseInt(t[1],10):null;if(e&&o&&o<9){var r=/safari/.test(n._navigator&&n._navigator.userAgent.toLowerCase());(n._navigator&&n._navigator.standalone&&!r||n._navigator&&!n._navigator.standalone&&!r)&&(n.usingWebAudio=!1)}n.usingWebAudio&&(n.masterGain=void 0===n.ctx.createGain?n.ctx.createGainNode():n.ctx.createGain(),n.masterGain.gain.setValueAtTime(n._muted?0:1,n.ctx.currentTime),n.masterGain.connect(n.ctx.destination)),n._setup()};"function"==typeof define&&define.amd&&define([],function(){return{Howler:n,Howl:t}}),"undefined"!=typeof exports&&(exports.Howler=n,exports.Howl=t),"undefined"!=typeof window?(window.HowlerGlobal=e,window.Howler=n,window.Howl=t,window.Sound=o):"undefined"!=typeof global&&(global.HowlerGlobal=e,global.Howler=n,global.Howl=t,global.Sound=o)}(); +/*! Spatial Plugin */ +!function(){"use strict";HowlerGlobal.prototype._pos=[0,0,0],HowlerGlobal.prototype._orientation=[0,0,-1,0,1,0],HowlerGlobal.prototype.stereo=function(n){var e=this;if(!e.ctx||!e.ctx.listener)return e;for(var t=e._howls.length-1;t>=0;t--)e._howls[t].stereo(n);return e},HowlerGlobal.prototype.pos=function(n,e,t){var o=this;return o.ctx&&o.ctx.listener?(e="number"!=typeof e?o._pos[1]:e,t="number"!=typeof t?o._pos[2]:t,"number"!=typeof n?o._pos:(o._pos=[n,e,t],o.ctx.listener.setPosition(o._pos[0],o._pos[1],o._pos[2]),o)):o},HowlerGlobal.prototype.orientation=function(n,e,t,o,r,a){var i=this;if(!i.ctx||!i.ctx.listener)return i;var p=i._orientation;return e="number"!=typeof e?p[1]:e,t="number"!=typeof t?p[2]:t,o="number"!=typeof o?p[3]:o,r="number"!=typeof r?p[4]:r,a="number"!=typeof a?p[5]:a,"number"!=typeof n?p:(i._orientation=[n,e,t,o,r,a],i.ctx.listener.setOrientation(n,e,t,o,r,a),i)},Howl.prototype.init=function(n){return function(e){var t=this;return t._orientation=e.orientation||[1,0,0],t._stereo=e.stereo||null,t._pos=e.pos||null,t._pannerAttr={coneInnerAngle:void 0!==e.coneInnerAngle?e.coneInnerAngle:360,coneOuterAngle:void 0!==e.coneOuterAngle?e.coneOuterAngle:360,coneOuterGain:void 0!==e.coneOuterGain?e.coneOuterGain:0,distanceModel:void 0!==e.distanceModel?e.distanceModel:"inverse",maxDistance:void 0!==e.maxDistance?e.maxDistance:1e4,panningModel:void 0!==e.panningModel?e.panningModel:"HRTF",refDistance:void 0!==e.refDistance?e.refDistance:1,rolloffFactor:void 0!==e.rolloffFactor?e.rolloffFactor:1},t._onstereo=e.onstereo?[{fn:e.onstereo}]:[],t._onpos=e.onpos?[{fn:e.onpos}]:[],t._onorientation=e.onorientation?[{fn:e.onorientation}]:[],n.call(this,e)}}(Howl.prototype.init),Howl.prototype.stereo=function(e,t){var o=this;if(!o._webAudio)return o;if("loaded"!==o._state)return o._queue.push({event:"stereo",action:function(){o.stereo(e,t)}}),o;var r=void 0===Howler.ctx.createStereoPanner?"spatial":"stereo";if(void 0===t){if("number"!=typeof e)return o._stereo;o._stereo=e,o._pos=[e,0,0]}for(var a=o._getSoundIds(t),i=0;i