diff options
| author | Jules Laplace <jules@okfoc.us> | 2016-09-11 15:49:18 -0400 |
|---|---|---|
| committer | Jules Laplace <jules@okfoc.us> | 2016-09-11 15:49:18 -0400 |
| commit | 642a0e99cfb4aeaa71cc1ac51739608ef6225b99 (patch) | |
| tree | 450d97fa941216306471f5a99f55c291f3e39bd0 | |
| parent | 5d18cc7380a076a0b02dff6ef47c85685d317d7e (diff) | |
js/vendor/StartAudioContext.js
| -rw-r--r-- | env.js | 12 | ||||
| -rw-r--r-- | index.html | 30 | ||||
| -rw-r--r-- | js/vendor/StartAudioContext.js | 180 |
3 files changed, 220 insertions, 2 deletions
@@ -23,6 +23,18 @@ var environment = (function(){ environment.ready = function(){ environment.build() environment.bind() + if (is_mobile) { + environment.request_audio_context() + } + } + environment.request_audio_context = function(){ + var element = $("<div>", {"id" : "MobileStart"}).appendTo("body") + var button = $("<div>").attr("id", "Button").text("Enter").appendTo(element) + StartAudioContext.setContext(Tone.context) + StartAudioContext.on(button) + StartAudioContext.onStarted(function(){ + element.remove() + }) } environment.build = function(){ environment.scale() @@ -11,6 +11,31 @@ circle { cursor: pointer } input[type=text] { width: 30px } #mobile_controls { display: none } .mobile #mobile_controls { display: inline } + +#MobileStart { + position: absolute; + width: 100%; + height: 100%; + z-index: 10000; + top: 0px; + left: 0px; + background-color: rgba(0, 0, 0, 0.8); +} +#MobileStart #Button { + position: absolute; + left: 50%; + top: 50%; + background-color: #7F33ED; + color: white; + font-family: monospace; + border-radius: 3px; + margin-top: -40px; + margin-left: -40px; + width: 80px; + height: 80px; + text-align: center; + line-height: 80px; } + </style> </head> <body class="loading"> @@ -53,13 +78,14 @@ input[type=text] { width: 30px } <script src="./js/vendor/oktween.js"></script> <script src="./js/vendor/util.js"></script> <script src="./js/vendor/wheel.js"></script> +<script src="./js/vendor/Tone.min.js"></script> +<script src="./js/vendor/intersect.js"></script> +<script src="./js/vendor/StartAudioContext.js"></script> <script src="./js/mx/mx.js"></script> <script src="./js/mx/mx.scene.js"></script> <script src="./js/mx/mx.followingOrbitCamera.js"></script> <script src="./js/lib/canvas_loader.js"></script> <script src="./js/lib/snapmx.js"></script> -<script src="./js/vendor/Tone.min.js"></script> -<script src="./js/vendor/intersect.js"></script> <script src="env.js"></script> <script src="./js/lib/app.js"></script> </html> diff --git a/js/vendor/StartAudioContext.js b/js/vendor/StartAudioContext.js new file mode 100644 index 0000000..905878a --- /dev/null +++ b/js/vendor/StartAudioContext.js @@ -0,0 +1,180 @@ +/** + * StartAudioContext.js + * @author Yotam Mann + * @license http://opensource.org/licenses/MIT MIT License + * @copyright 2016 Yotam Mann + */ +(function (root, factory) { + if (typeof define === "function" && define.amd) { + define([], factory); + } else if (typeof module === 'object' && module.exports) { + module.exports = factory(); + } else { + root.StartAudioContext = factory(); + } +}(this, function () { + + /** + * The StartAudioContext object + */ + var StartAudioContext = { + /** + * The audio context passed in by the user + * @type {AudioContext} + */ + context : null, + /** + * The TapListeners bound to the elements + * @type {Array} + * @private + */ + _tapListeners : [], + /** + * Callbacks to invoke when the audio context is started + * @type {Array} + * @private + */ + _onStarted : [], + }; + + + /** + * Set the context + * @param {AudioContext} ctx + * @returns {StartAudioContext} + */ + StartAudioContext.setContext = function(ctx){ + StartAudioContext.context = ctx; + return StartAudioContext; + }; + + /** + * Add a tap listener to the audio context + * @param {Array|Element|String|jQuery} element + * @returns {StartAudioContext} + */ + StartAudioContext.on = function(element){ + if (Array.isArray(element) || (NodeList && element instanceof NodeList)){ + for (var i = 0; i < element.length; i++){ + StartAudioContext.on(element[i]); + } + } else if (typeof element === "string"){ + StartAudioContext.on(document.querySelectorAll(element)); + } else if (element.jquery && typeof element.toArray === "function"){ + StartAudioContext.on(element.toArray()); + } else if (Element && element instanceof Element){ + //if it's an element, create a TapListener + var tap = new TapListener(element, onTap); + StartAudioContext._tapListeners.push(tap); + } + return StartAudioContext; + }; + + /** + * Bind a callback to when the audio context is started. + * @param {Function} cb + * @return {StartAudioContext} + */ + StartAudioContext.onStarted = function(cb){ + //if it's already started, invoke the callback + if (StartAudioContext.isStarted()){ + cb(); + } else { + StartAudioContext._onStarted.push(cb); + } + return StartAudioContext; + }; + + /** + * returns true if the context is started + * @return {Boolean} + */ + StartAudioContext.isStarted = function(){ + return (StartAudioContext.context !== null && StartAudioContext.context.state === "running"); + }; + + /** + * @class Listens for non-dragging tap ends on the given element + * @param {Element} element + * @internal + */ + var TapListener = function(element){ + + this._dragged = false; + + this._element = element; + + this._bindedMove = this._moved.bind(this); + this._bindedEnd = this._ended.bind(this); + + element.addEventListener("touchmove", this._bindedMove); + element.addEventListener("touchend", this._bindedEnd); + element.addEventListener("mouseup", this._bindedEnd); + }; + + /** + * drag move event + */ + TapListener.prototype._moved = function(e){ + this._dragged = true; + }; + + /** + * tap ended listener + */ + TapListener.prototype._ended = function(e){ + if (!this._dragged){ + onTap(); + } + this._dragged = false; + }; + + /** + * remove all the bound events + */ + TapListener.prototype.dispose = function(){ + this._element.removeEventListener("touchmove", this._bindedMove); + this._element.removeEventListener("touchend", this._bindedEnd); + this._element.removeEventListener("mouseup", this._bindedEnd); + this._bindedMove = null; + this._bindedEnd = null; + this._element = null; + }; + + /** + * Invoked the first time of the elements is tapped. + * Creates a silent oscillator when a non-dragging touchend + * event has been triggered. + */ + function onTap(){ + + //start the audio context with a silent oscillator + if (StartAudioContext.context && !StartAudioContext.isStarted()){ + var osc = StartAudioContext.context.createOscillator(); + var silent = StartAudioContext.context.createGain(); + silent.gain.value = 0; + osc.connect(silent); + silent.connect(StartAudioContext.context.destination); + var now = StartAudioContext.context.currentTime; + osc.start(now); + osc.stop(now+0.5); + } + + //dispose all the tap listeners + if (StartAudioContext._tapListeners){ + for (var i = 0; i < StartAudioContext._tapListeners.length; i++){ + StartAudioContext._tapListeners[i].dispose(); + } + StartAudioContext._tapListeners = null; + } + //the onstarted callbacks + if (StartAudioContext._onStarted){ + for (var j = 0; j < StartAudioContext._onStarted.length; j++){ + StartAudioContext._onStarted[j](); + } + StartAudioContext._onStarted = null; + } + } + + return StartAudioContext; +}));
\ No newline at end of file |
