From c8d11dff2c582a3e75d9308801c9081eb8562fec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Piquemal?= Date: Tue, 13 Dec 2016 14:27:39 +0200 Subject: [PATCH] demos fixed ios fixes #9 --- demos/beatSequence.html | 1 + demos/beatSequence.js | 2 +- demos/js/AudioContextMonkeyPatch.js | 182 ++++++++++++++++++++++++++++ demos/js/common.js | 7 ++ demos/tempoChange.html | 1 + demos/tempoChange.js | 2 +- 6 files changed, 193 insertions(+), 2 deletions(-) create mode 100644 demos/js/AudioContextMonkeyPatch.js diff --git a/demos/beatSequence.html b/demos/beatSequence.html index cdaa6e4..d2b31be 100644 --- a/demos/beatSequence.html +++ b/demos/beatSequence.html @@ -2,6 +2,7 @@ WAAClock examples + diff --git a/demos/beatSequence.js b/demos/beatSequence.js index 20ab5de..0a26c2c 100644 --- a/demos/beatSequence.js +++ b/demos/beatSequence.js @@ -8,7 +8,7 @@ var soundBank = {} , barDur = signature * beatDur , clock, context, uiEvent -$('#startButton').click(function() { +startWebAudioOnPress($('#startButton'), function() { context = new AudioContext() clock = new WAAClock(context, {toleranceEarly: 0.1}) clock.start() diff --git a/demos/js/AudioContextMonkeyPatch.js b/demos/js/AudioContextMonkeyPatch.js new file mode 100644 index 0000000..8e5ed0c --- /dev/null +++ b/demos/js/AudioContextMonkeyPatch.js @@ -0,0 +1,182 @@ +/* Copyright 2013 Chris Wilson + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +/* + +This monkeypatch library is intended to be included in projects that are +written to the proper AudioContext spec (instead of webkitAudioContext), +and that use the new naming and proper bits of the Web Audio API (e.g. +using BufferSourceNode.start() instead of BufferSourceNode.noteOn()), but may +have to run on systems that only support the deprecated bits. + +This library should be harmless to include if the browser supports +unprefixed "AudioContext", and/or if it supports the new names. + +The patches this library handles: +if window.AudioContext is unsupported, it will be aliased to webkitAudioContext(). +if AudioBufferSourceNode.start() is unimplemented, it will be routed to noteOn() or +noteGrainOn(), depending on parameters. + +The following aliases only take effect if the new names are not already in place: + +AudioBufferSourceNode.stop() is aliased to noteOff() +AudioContext.createGain() is aliased to createGainNode() +AudioContext.createDelay() is aliased to createDelayNode() +AudioContext.createScriptProcessor() is aliased to createJavaScriptNode() +AudioContext.createPeriodicWave() is aliased to createWaveTable() +OscillatorNode.start() is aliased to noteOn() +OscillatorNode.stop() is aliased to noteOff() +OscillatorNode.setPeriodicWave() is aliased to setWaveTable() +AudioParam.setTargetAtTime() is aliased to setTargetValueAtTime() + +This library does NOT patch the enumerated type changes, as it is +recommended in the specification that implementations support both integer +and string types for AudioPannerNode.panningModel, AudioPannerNode.distanceModel +BiquadFilterNode.type and OscillatorNode.type. + +*/ +(function (global, exports, perf) { + 'use strict'; + + function fixSetTarget(param) { + if (!param) // if NYI, just return + return; + if (!param.setTargetAtTime) + param.setTargetAtTime = param.setTargetValueAtTime; + } + + if (window.hasOwnProperty('webkitAudioContext') && + !window.hasOwnProperty('AudioContext')) { + window.AudioContext = webkitAudioContext; + + if (!AudioContext.prototype.hasOwnProperty('createGain')) + AudioContext.prototype.createGain = AudioContext.prototype.createGainNode; + if (!AudioContext.prototype.hasOwnProperty('createDelay')) + AudioContext.prototype.createDelay = AudioContext.prototype.createDelayNode; + if (!AudioContext.prototype.hasOwnProperty('createScriptProcessor')) + AudioContext.prototype.createScriptProcessor = AudioContext.prototype.createJavaScriptNode; + if (!AudioContext.prototype.hasOwnProperty('createPeriodicWave')) + AudioContext.prototype.createPeriodicWave = AudioContext.prototype.createWaveTable; + + + AudioContext.prototype.internal_createGain = AudioContext.prototype.createGain; + AudioContext.prototype.createGain = function() { + var node = this.internal_createGain(); + fixSetTarget(node.gain); + return node; + }; + + AudioContext.prototype.internal_createDelay = AudioContext.prototype.createDelay; + AudioContext.prototype.createDelay = function(maxDelayTime) { + var node = maxDelayTime ? this.internal_createDelay(maxDelayTime) : this.internal_createDelay(); + fixSetTarget(node.delayTime); + return node; + }; + + AudioContext.prototype.internal_createBufferSource = AudioContext.prototype.createBufferSource; + AudioContext.prototype.createBufferSource = function() { + var node = this.internal_createBufferSource(); + if (!node.start) { + node.start = function ( when, offset, duration ) { + if ( offset || duration ) + this.noteGrainOn( when || 0, offset, duration ); + else + this.noteOn( when || 0 ); + }; + } else { + node.internal_start = node.start; + node.start = function( when, offset, duration ) { + if( typeof duration !== 'undefined' ) + node.internal_start( when || 0, offset, duration ); + else + node.internal_start( when || 0, offset || 0 ); + }; + } + if (!node.stop) { + node.stop = function ( when ) { + this.noteOff( when || 0 ); + }; + } else { + node.internal_stop = node.stop; + node.stop = function( when ) { + node.internal_stop( when || 0 ); + }; + } + fixSetTarget(node.playbackRate); + return node; + }; + + AudioContext.prototype.internal_createDynamicsCompressor = AudioContext.prototype.createDynamicsCompressor; + AudioContext.prototype.createDynamicsCompressor = function() { + var node = this.internal_createDynamicsCompressor(); + fixSetTarget(node.threshold); + fixSetTarget(node.knee); + fixSetTarget(node.ratio); + fixSetTarget(node.reduction); + fixSetTarget(node.attack); + fixSetTarget(node.release); + return node; + }; + + AudioContext.prototype.internal_createBiquadFilter = AudioContext.prototype.createBiquadFilter; + AudioContext.prototype.createBiquadFilter = function() { + var node = this.internal_createBiquadFilter(); + fixSetTarget(node.frequency); + fixSetTarget(node.detune); + fixSetTarget(node.Q); + fixSetTarget(node.gain); + return node; + }; + + if (AudioContext.prototype.hasOwnProperty( 'createOscillator' )) { + AudioContext.prototype.internal_createOscillator = AudioContext.prototype.createOscillator; + AudioContext.prototype.createOscillator = function() { + var node = this.internal_createOscillator(); + if (!node.start) { + node.start = function ( when ) { + this.noteOn( when || 0 ); + }; + } else { + node.internal_start = node.start; + node.start = function ( when ) { + node.internal_start( when || 0); + }; + } + if (!node.stop) { + node.stop = function ( when ) { + this.noteOff( when || 0 ); + }; + } else { + node.internal_stop = node.stop; + node.stop = function( when ) { + node.internal_stop( when || 0 ); + }; + } + if (!node.setPeriodicWave) + node.setPeriodicWave = node.setWaveTable; + fixSetTarget(node.frequency); + fixSetTarget(node.detune); + return node; + }; + } + } + + if (window.hasOwnProperty('webkitOfflineAudioContext') && + !window.hasOwnProperty('OfflineAudioContext')) { + window.OfflineAudioContext = webkitOfflineAudioContext; + } + +}(window)); + diff --git a/demos/js/common.js b/demos/js/common.js index 5fe066b..1cf5daf 100644 --- a/demos/js/common.js +++ b/demos/js/common.js @@ -13,6 +13,13 @@ $(function() { }, 'text') }) +var startWebAudioOnPress = function(startButton, onPressed) { + // starting in iOS9, audio will only be unmuted if the context is created on "touchend". + var is_iOS = /iPad|iPhone|iPod/.test(navigator.platform) + , eventType = is_iOS ? 'touchend' : 'click' + startButton.on(eventType, onPressed) +} + // Parsing the query params var QUERY = {} location.search.slice(1).split('&').forEach(function(el) { diff --git a/demos/tempoChange.html b/demos/tempoChange.html index 743c4d8..442c1c6 100644 --- a/demos/tempoChange.html +++ b/demos/tempoChange.html @@ -2,6 +2,7 @@ WAAClock examples + diff --git a/demos/tempoChange.js b/demos/tempoChange.js index 9000097..2b46f4c 100644 --- a/demos/tempoChange.js +++ b/demos/tempoChange.js @@ -10,7 +10,7 @@ var setTempo = function(newTempo) { currentTempo = newTempo } -$('#startButton').click(function() { +startWebAudioOnPress($('#startButton'), function() { context = new AudioContext() clock = new WAAClock(context)