UNPKG

@simbi/standardized-audio-context

Version:

A cross-browser implementation of the AudioContext which aims to closely follow the standard.

994 lines (832 loc) 593 kB
(function (global, factory) { typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('automation-events'), require('@babel/runtime/helpers/slicedToArray'), require('@babel/runtime/helpers/classCallCheck'), require('@babel/runtime/helpers/typeof'), require('@babel/runtime/helpers/defineProperty'), require('@babel/runtime/helpers/createClass'), require('@babel/runtime/helpers/inherits'), require('@babel/runtime/helpers/possibleConstructorReturn'), require('@babel/runtime/helpers/getPrototypeOf'), require('@babel/runtime/regenerator'), require('@babel/runtime/helpers/asyncToGenerator'), require('@babel/runtime/helpers/assertThisInitialized'), require('@babel/runtime/helpers/toConsumableArray'), require('@babel/runtime/helpers/objectWithoutProperties')) : typeof define === 'function' && define.amd ? define(['exports', 'automation-events', '@babel/runtime/helpers/slicedToArray', '@babel/runtime/helpers/classCallCheck', '@babel/runtime/helpers/typeof', '@babel/runtime/helpers/defineProperty', '@babel/runtime/helpers/createClass', '@babel/runtime/helpers/inherits', '@babel/runtime/helpers/possibleConstructorReturn', '@babel/runtime/helpers/getPrototypeOf', '@babel/runtime/regenerator', '@babel/runtime/helpers/asyncToGenerator', '@babel/runtime/helpers/assertThisInitialized', '@babel/runtime/helpers/toConsumableArray', '@babel/runtime/helpers/objectWithoutProperties'], factory) : (global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.standardizedAudioContext = {}, global.automationEvents, global._slicedToArray, global._classCallCheck, global._typeof, global._defineProperty, global._createClass, global._inherits, global._possibleConstructorReturn, global._getPrototypeOf, global._regeneratorRuntime, global._asyncToGenerator, global._assertThisInitialized, global._toConsumableArray, global._objectWithoutProperties)); }(this, (function (exports, automationEvents, _slicedToArray, _classCallCheck, _typeof, _defineProperty, _createClass, _inherits, _possibleConstructorReturn, _getPrototypeOf, _regeneratorRuntime, _asyncToGenerator, _assertThisInitialized, _toConsumableArray, _objectWithoutProperties) { 'use strict'; function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; } var _slicedToArray__default = /*#__PURE__*/_interopDefaultLegacy(_slicedToArray); var _classCallCheck__default = /*#__PURE__*/_interopDefaultLegacy(_classCallCheck); var _typeof__default = /*#__PURE__*/_interopDefaultLegacy(_typeof); var _defineProperty__default = /*#__PURE__*/_interopDefaultLegacy(_defineProperty); var _createClass__default = /*#__PURE__*/_interopDefaultLegacy(_createClass); var _inherits__default = /*#__PURE__*/_interopDefaultLegacy(_inherits); var _possibleConstructorReturn__default = /*#__PURE__*/_interopDefaultLegacy(_possibleConstructorReturn); var _getPrototypeOf__default = /*#__PURE__*/_interopDefaultLegacy(_getPrototypeOf); var _regeneratorRuntime__default = /*#__PURE__*/_interopDefaultLegacy(_regeneratorRuntime); var _asyncToGenerator__default = /*#__PURE__*/_interopDefaultLegacy(_asyncToGenerator); var _assertThisInitialized__default = /*#__PURE__*/_interopDefaultLegacy(_assertThisInitialized); var _toConsumableArray__default = /*#__PURE__*/_interopDefaultLegacy(_toConsumableArray); var _objectWithoutProperties__default = /*#__PURE__*/_interopDefaultLegacy(_objectWithoutProperties); var createAbortError = function createAbortError() { return new DOMException('', 'AbortError'); }; var createAddActiveInputConnectionToAudioNode = function createAddActiveInputConnectionToAudioNode(insertElementInSet) { return function (activeInputs, source, _ref, ignoreDuplicates) { var _ref2 = _slicedToArray__default['default'](_ref, 3), output = _ref2[0], input = _ref2[1], eventListener = _ref2[2]; insertElementInSet(activeInputs[input], [source, output, eventListener], function (activeInputConnection) { return activeInputConnection[0] === source && activeInputConnection[1] === output; }, ignoreDuplicates); }; }; var createAddAudioNodeConnections = function createAddAudioNodeConnections(audioNodeConnectionsStore) { return function (audioNode, audioNodeRenderer, nativeAudioNode) { var activeInputs = []; for (var i = 0; i < nativeAudioNode.numberOfInputs; i += 1) { activeInputs.push(new Set()); } audioNodeConnectionsStore.set(audioNode, { activeInputs: activeInputs, outputs: new Set(), passiveInputs: new WeakMap(), renderer: audioNodeRenderer }); }; }; var createAddAudioParamConnections = function createAddAudioParamConnections(audioParamConnectionsStore) { return function (audioParam, audioParamRenderer) { audioParamConnectionsStore.set(audioParam, { activeInputs: new Set(), passiveInputs: new WeakMap(), renderer: audioParamRenderer }); }; }; var ACTIVE_AUDIO_NODE_STORE = new WeakSet(); var AUDIO_NODE_CONNECTIONS_STORE = new WeakMap(); var AUDIO_NODE_STORE = new WeakMap(); var AUDIO_PARAM_CONNECTIONS_STORE = new WeakMap(); var AUDIO_PARAM_STORE = new WeakMap(); var CONTEXT_STORE = new WeakMap(); var EVENT_LISTENERS = new WeakMap(); var CYCLE_COUNTERS = new WeakMap(); // This clunky name is borrowed from the spec. :-) var NODE_NAME_TO_PROCESSOR_CONSTRUCTOR_MAPS = new WeakMap(); var NODE_TO_PROCESSOR_MAPS = new WeakMap(); var handler = { construct: function construct() { return handler; } }; var isConstructible = function isConstructible(constructible) { try { var proxy = new Proxy(constructible, handler); new proxy(); // tslint:disable-line:no-unused-expression } catch (_unused) { return false; } return true; }; /* * This massive regex tries to cover all the following cases. * * import './path'; * import defaultImport from './path'; * import { namedImport } from './path'; * import { namedImport as renamendImport } from './path'; * import * as namespaceImport from './path'; * import defaultImport, { namedImport } from './path'; * import defaultImport, { namedImport as renamendImport } from './path'; * import defaultImport, * as namespaceImport from './path'; */ var IMPORT_STATEMENT_REGEX = /^import(?:(?:[\s]+[\w]+|(?:[\s]+[\w]+[\s]*,)?[\s]*\{[\s]*[\w]+(?:[\s]+as[\s]+[\w]+)?(?:[\s]*,[\s]*[\w]+(?:[\s]+as[\s]+[\w]+)?)*[\s]*}|(?:[\s]+[\w]+[\s]*,)?[\s]*\*[\s]+as[\s]+[\w]+)[\s]+from)?(?:[\s]*)("([^"\\]|\\.)+"|'([^'\\]|\\.)+')(?:[\s]*);?/; // tslint:disable-line:max-line-length var splitImportStatements = function splitImportStatements(source, url) { var importStatements = []; var sourceWithoutImportStatements = source.replace(/^[\s]+/, ''); var result = sourceWithoutImportStatements.match(IMPORT_STATEMENT_REGEX); while (result !== null) { var unresolvedUrl = result[1].slice(1, -1); var importStatementWithResolvedUrl = result[0].replace(/([\s]+)?;?$/, '').replace(unresolvedUrl, new URL(unresolvedUrl, url).toString()); importStatements.push(importStatementWithResolvedUrl); sourceWithoutImportStatements = sourceWithoutImportStatements.slice(result[0].length).replace(/^[\s]+/, ''); result = sourceWithoutImportStatements.match(IMPORT_STATEMENT_REGEX); } return [importStatements.join(';'), sourceWithoutImportStatements]; }; var verifyParameterDescriptors = function verifyParameterDescriptors(parameterDescriptors) { if (parameterDescriptors !== undefined && !Array.isArray(parameterDescriptors)) { throw new TypeError('The parameterDescriptors property of given value for processorCtor is not an array.'); } }; var verifyProcessorCtor = function verifyProcessorCtor(processorCtor) { if (!isConstructible(processorCtor)) { throw new TypeError('The given value for processorCtor should be a constructor.'); } if (processorCtor.prototype === null || _typeof__default['default'](processorCtor.prototype) !== 'object') { throw new TypeError('The given value for processorCtor should have a prototype.'); } }; var createAddAudioWorkletModule = function createAddAudioWorkletModule(cacheTestResult, createNotSupportedError, evaluateSource, exposeCurrentFrameAndCurrentTime, fetchSource, getNativeContext, getOrCreateBackupOfflineAudioContext, isNativeOfflineAudioContext, ongoingRequests, resolvedRequests, testAudioWorkletProcessorPostMessageSupport, window) { return function (context, moduleURL) { var options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : { credentials: 'omit' }; var nativeContext = getNativeContext(context); var absoluteUrl = new URL(moduleURL, window.location.href).toString(); // Bug #59: Safari does not implement the audioWorklet property. if (nativeContext.audioWorklet !== undefined) { return Promise.all([fetchSource(moduleURL), Promise.resolve(cacheTestResult(testAudioWorkletProcessorPostMessageSupport, testAudioWorkletProcessorPostMessageSupport))]).then(function (_ref) { var _ref2 = _slicedToArray__default['default'](_ref, 2), source = _ref2[0], isSupportingPostMessage = _ref2[1]; var _splitImportStatement = splitImportStatements(source, absoluteUrl), _splitImportStatement2 = _slicedToArray__default['default'](_splitImportStatement, 2), importStatements = _splitImportStatement2[0], sourceWithoutImportStatements = _splitImportStatement2[1]; /* * Bug #179: Firefox does not allow to transfer any buffer which has been passed to the process() method as an argument. * * This is the unminified version of the code used below. * * ```js * class extends AudioWorkletProcessor { * * __buffers = new WeakSet(); * * constructor () { * super(); * * this.port.postMessage = ((postMessage) => { * return (message, transferables) => { * const filteredTransferables = (transferables) * ? transferables.filter((transferable) => !this.__buffers.has(transferable)) * : transferables; * * return postMessage.call(this.port, message, filteredTransferables); * }; * })(this.port.postMessage); * } * } * ``` */ var patchedSourceWithoutImportStatements = isSupportingPostMessage ? sourceWithoutImportStatements : sourceWithoutImportStatements.replace(/\s+extends\s+AudioWorkletProcessor\s*{/, " extends (class extends AudioWorkletProcessor {__b=new WeakSet();constructor(){super();(p=>p.postMessage=(q=>(m,t)=>q.call(p,m,t?t.filter(u=>!this.__b.has(u)):t))(p.postMessage))(this.port)}}){"); /* * Bug #170: Chrome and Edge do call process() with an array with empty channelData for each input if no input is connected. * * Bug #179: Firefox does not allow to transfer any buffer which has been passed to the process() method as an argument. * * This is the unminified version of the code used below: * * ```js * `${ importStatements }; * ((registerProcessor) => {${ sourceWithoutImportStatements } * })((name, processorCtor) => registerProcessor(name, class extends processorCtor { * * __collectBuffers = (array) => { * array.forEach((element) => this.__buffers.add(element.buffer)); * }; * * process (inputs, outputs, parameters) { * inputs.forEach(this.__collectBuffers); * outputs.forEach(this.__collectBuffers); * this.__collectBuffers(Object.values(parameters)); * * return super.process( * (inputs.map((input) => input.some((channelData) => channelData.length === 0)) ? [ ] : input), * outputs, * parameters * ); * } * * }))` * ``` */ var memberDefinition = isSupportingPostMessage ? '' : '__c = (a) => a.forEach(e=>this.__b.add(e.buffer));'; var bufferRegistration = isSupportingPostMessage ? '' : 'i.forEach(this.__c);o.forEach(this.__c);this.__c(Object.values(p));'; var wrappedSource = "".concat(importStatements, ";(registerProcessor=>{").concat(patchedSourceWithoutImportStatements, "\n})((n,p)=>registerProcessor(n,class extends p{").concat(memberDefinition, "process(i,o,p){").concat(bufferRegistration, "return super.process(i.map(j=>j.some(k=>k.length===0)?[]:j),o,p)}}))"); var blob = new Blob([wrappedSource], { type: 'application/javascript; charset=utf-8' }); var url = URL.createObjectURL(blob); return nativeContext.audioWorklet.addModule(url, options).then(function () { if (isNativeOfflineAudioContext(nativeContext)) { return; } // Bug #186: Chrome, Edge and Opera do not allow to create an AudioWorkletNode on a closed AudioContext. var backupOfflineAudioContext = getOrCreateBackupOfflineAudioContext(nativeContext); return backupOfflineAudioContext.audioWorklet.addModule(url, options); })["finally"](function () { return URL.revokeObjectURL(url); }); }); } var resolvedRequestsOfContext = resolvedRequests.get(context); if (resolvedRequestsOfContext !== undefined && resolvedRequestsOfContext.has(moduleURL)) { return Promise.resolve(); } var ongoingRequestsOfContext = ongoingRequests.get(context); if (ongoingRequestsOfContext !== undefined) { var promiseOfOngoingRequest = ongoingRequestsOfContext.get(moduleURL); if (promiseOfOngoingRequest !== undefined) { return promiseOfOngoingRequest; } } var promise = fetchSource(moduleURL).then(function (source) { var _splitImportStatement3 = splitImportStatements(source, absoluteUrl), _splitImportStatement4 = _slicedToArray__default['default'](_splitImportStatement3, 2), importStatements = _splitImportStatement4[0], sourceWithoutImportStatements = _splitImportStatement4[1]; /* * This is the unminified version of the code used below: * * ```js * ${ importStatements }; * ((a, b) => { * (a[b] = a[b] || [ ]).push( * (AudioWorkletProcessor, global, registerProcessor, sampleRate, self, window) => { * ${ sourceWithoutImportStatements } * } * ); * })(window, '_AWGS'); * ``` */ // tslint:disable-next-line:max-line-length var wrappedSource = "".concat(importStatements, ";((a,b)=>{(a[b]=a[b]||[]).push((AudioWorkletProcessor,global,registerProcessor,sampleRate,self,window)=>{").concat(sourceWithoutImportStatements, "\n})})(window,'_AWGS')"); // @todo Evaluating the given source code is a possible security problem. return evaluateSource(wrappedSource); }).then(function () { var evaluateAudioWorkletGlobalScope = window._AWGS.pop(); if (evaluateAudioWorkletGlobalScope === undefined) { // Bug #182 Chrome, Edge and Opera do throw an instance of a SyntaxError instead of a DOMException. throw new SyntaxError(); } exposeCurrentFrameAndCurrentTime(nativeContext.currentTime, nativeContext.sampleRate, function () { return evaluateAudioWorkletGlobalScope(function AudioWorkletProcessor() { _classCallCheck__default['default'](this, AudioWorkletProcessor); }, undefined, function (name, processorCtor) { if (name.trim() === '') { throw createNotSupportedError(); } var nodeNameToProcessorConstructorMap = NODE_NAME_TO_PROCESSOR_CONSTRUCTOR_MAPS.get(nativeContext); if (nodeNameToProcessorConstructorMap !== undefined) { if (nodeNameToProcessorConstructorMap.has(name)) { throw createNotSupportedError(); } verifyProcessorCtor(processorCtor); verifyParameterDescriptors(processorCtor.parameterDescriptors); nodeNameToProcessorConstructorMap.set(name, processorCtor); } else { verifyProcessorCtor(processorCtor); verifyParameterDescriptors(processorCtor.parameterDescriptors); NODE_NAME_TO_PROCESSOR_CONSTRUCTOR_MAPS.set(nativeContext, new Map([[name, processorCtor]])); } }, nativeContext.sampleRate, undefined, undefined); }); }); if (ongoingRequestsOfContext === undefined) { ongoingRequests.set(context, new Map([[moduleURL, promise]])); } else { ongoingRequestsOfContext.set(moduleURL, promise); } promise.then(function () { var rslvdRqstsFCntxt = resolvedRequests.get(context); if (rslvdRqstsFCntxt === undefined) { resolvedRequests.set(context, new Set([moduleURL])); } else { rslvdRqstsFCntxt.add(moduleURL); } })["finally"](function () { var ngngRqstsFCntxt = ongoingRequests.get(context); if (ngngRqstsFCntxt !== undefined) { ngngRqstsFCntxt["delete"](moduleURL); } }); return promise; }; }; var getValueForKey = function getValueForKey(map, key) { var value = map.get(key); if (value === undefined) { throw new Error('A value with the given key could not be found.'); } return value; }; var pickElementFromSet = function pickElementFromSet(set, predicate) { var matchingElements = Array.from(set).filter(predicate); if (matchingElements.length > 1) { throw Error('More than one element was found.'); } if (matchingElements.length === 0) { throw Error('No element was found.'); } var _matchingElements = _slicedToArray__default['default'](matchingElements, 1), matchingElement = _matchingElements[0]; set["delete"](matchingElement); return matchingElement; }; var deletePassiveInputConnectionToAudioNode = function deletePassiveInputConnectionToAudioNode(passiveInputs, source, output, input) { var passiveInputConnections = getValueForKey(passiveInputs, source); var matchingConnection = pickElementFromSet(passiveInputConnections, function (passiveInputConnection) { return passiveInputConnection[0] === output && passiveInputConnection[1] === input; }); if (passiveInputConnections.size === 0) { passiveInputs["delete"](source); } return matchingConnection; }; var getEventListenersOfAudioNode = function getEventListenersOfAudioNode(audioNode) { return getValueForKey(EVENT_LISTENERS, audioNode); }; var setInternalStateToActive = function setInternalStateToActive(audioNode) { if (ACTIVE_AUDIO_NODE_STORE.has(audioNode)) { throw new Error('The AudioNode is already stored.'); } ACTIVE_AUDIO_NODE_STORE.add(audioNode); getEventListenersOfAudioNode(audioNode).forEach(function (eventListener) { return eventListener(true); }); }; var isAudioWorkletNode = function isAudioWorkletNode(audioNode) { return 'port' in audioNode; }; var setInternalStateToPassive = function setInternalStateToPassive(audioNode) { if (!ACTIVE_AUDIO_NODE_STORE.has(audioNode)) { throw new Error('The AudioNode is not stored.'); } ACTIVE_AUDIO_NODE_STORE["delete"](audioNode); getEventListenersOfAudioNode(audioNode).forEach(function (eventListener) { return eventListener(false); }); }; var setInternalStateToPassiveWhenNecessary = function setInternalStateToPassiveWhenNecessary(audioNode, activeInputs) { if (!isAudioWorkletNode(audioNode) && activeInputs.every(function (connections) { return connections.size === 0; })) { setInternalStateToPassive(audioNode); } }; var createAddConnectionToAudioNode = function createAddConnectionToAudioNode(addActiveInputConnectionToAudioNode, addPassiveInputConnectionToAudioNode, connectNativeAudioNodeToNativeAudioNode, deleteActiveInputConnectionToAudioNode, disconnectNativeAudioNodeFromNativeAudioNode, getAudioNodeConnections, getAudioNodeTailTime, getEventListenersOfAudioNode, getNativeAudioNode, insertElementInSet, isActiveAudioNode, isPartOfACycle, isPassiveAudioNode) { return function (source, destination, output, input, isOffline) { var _getAudioNodeConnecti = getAudioNodeConnections(destination), activeInputs = _getAudioNodeConnecti.activeInputs, passiveInputs = _getAudioNodeConnecti.passiveInputs; var _getAudioNodeConnecti2 = getAudioNodeConnections(source), outputs = _getAudioNodeConnecti2.outputs; var eventListeners = getEventListenersOfAudioNode(source); var eventListener = function eventListener(isActive) { var nativeDestinationAudioNode = getNativeAudioNode(destination); var nativeSourceAudioNode = getNativeAudioNode(source); if (isActive) { var partialConnection = deletePassiveInputConnectionToAudioNode(passiveInputs, source, output, input); addActiveInputConnectionToAudioNode(activeInputs, source, partialConnection, false); if (!isOffline && !isPartOfACycle(source)) { connectNativeAudioNodeToNativeAudioNode(nativeSourceAudioNode, nativeDestinationAudioNode, output, input); } if (isPassiveAudioNode(destination)) { setInternalStateToActive(destination); } } else { var _partialConnection = deleteActiveInputConnectionToAudioNode(activeInputs, source, output, input); addPassiveInputConnectionToAudioNode(passiveInputs, input, _partialConnection, false); if (!isOffline && !isPartOfACycle(source)) { disconnectNativeAudioNodeFromNativeAudioNode(nativeSourceAudioNode, nativeDestinationAudioNode, output, input); } var tailTime = getAudioNodeTailTime(destination); if (tailTime === 0) { if (isActiveAudioNode(destination)) { setInternalStateToPassiveWhenNecessary(destination, activeInputs); } } else { setTimeout(function () { if (isActiveAudioNode(destination)) { setInternalStateToPassiveWhenNecessary(destination, activeInputs); } }, tailTime * 1000); } } }; if (insertElementInSet(outputs, [destination, output, input], function (outputConnection) { return outputConnection[0] === destination && outputConnection[1] === output && outputConnection[2] === input; }, true)) { eventListeners.add(eventListener); if (isActiveAudioNode(source)) { addActiveInputConnectionToAudioNode(activeInputs, source, [output, input, eventListener], true); } else { addPassiveInputConnectionToAudioNode(passiveInputs, input, [source, output, eventListener], true); } return true; } return false; }; }; var createAddPassiveInputConnectionToAudioNode = function createAddPassiveInputConnectionToAudioNode(insertElementInSet) { return function (passiveInputs, input, _ref, ignoreDuplicates) { var _ref2 = _slicedToArray__default['default'](_ref, 3), source = _ref2[0], output = _ref2[1], eventListener = _ref2[2]; var passiveInputConnections = passiveInputs.get(source); if (passiveInputConnections === undefined) { passiveInputs.set(source, new Set([[output, input, eventListener]])); } else { insertElementInSet(passiveInputConnections, [output, input, eventListener], function (passiveInputConnection) { return passiveInputConnection[0] === output && passiveInputConnection[1] === input; }, ignoreDuplicates); } }; }; var createAddSilentConnection = function createAddSilentConnection(createNativeGainNode) { return function (nativeContext, nativeAudioScheduledSourceNode) { var nativeGainNode = createNativeGainNode(nativeContext, { channelCount: 1, channelCountMode: 'explicit', channelInterpretation: 'discrete', gain: 0 }); nativeAudioScheduledSourceNode.connect(nativeGainNode).connect(nativeContext.destination); var disconnect = function disconnect() { nativeAudioScheduledSourceNode.removeEventListener('ended', disconnect); nativeAudioScheduledSourceNode.disconnect(nativeGainNode); nativeGainNode.disconnect(); }; nativeAudioScheduledSourceNode.addEventListener('ended', disconnect); }; }; var createAddUnrenderedAudioWorkletNode = function createAddUnrenderedAudioWorkletNode(getUnrenderedAudioWorkletNodes) { return function (nativeContext, audioWorkletNode) { getUnrenderedAudioWorkletNodes(nativeContext).add(audioWorkletNode); }; }; function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); keys.push.apply(keys, symbols); } return keys; } function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(Object(source), true).forEach(function (key) { _defineProperty__default['default'](target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; } function _createSuper(Derived) { var hasNativeReflectConstruct = _isNativeReflectConstruct(); return function _createSuperInternal() { var Super = _getPrototypeOf__default['default'](Derived), result; if (hasNativeReflectConstruct) { var NewTarget = _getPrototypeOf__default['default'](this).constructor; result = Reflect.construct(Super, arguments, NewTarget); } else { result = Super.apply(this, arguments); } return _possibleConstructorReturn__default['default'](this, result); }; } function _isNativeReflectConstruct() { if (typeof Reflect === "undefined" || !Reflect.construct) return false; if (Reflect.construct.sham) return false; if (typeof Proxy === "function") return true; try { Date.prototype.toString.call(Reflect.construct(Date, [], function () {})); return true; } catch (e) { return false; } } var DEFAULT_OPTIONS = { channelCount: 2, channelCountMode: 'max', channelInterpretation: 'speakers', fftSize: 2048, maxDecibels: -30, minDecibels: -100, smoothingTimeConstant: 0.8 }; var createAnalyserNodeConstructor = function createAnalyserNodeConstructor(audionNodeConstructor, createAnalyserNodeRenderer, createIndexSizeError, createNativeAnalyserNode, getNativeContext, isNativeOfflineAudioContext) { return /*#__PURE__*/function (_audionNodeConstructo) { _inherits__default['default'](AnalyserNode, _audionNodeConstructo); var _super = _createSuper(AnalyserNode); function AnalyserNode(context, options) { var _this; _classCallCheck__default['default'](this, AnalyserNode); var nativeContext = getNativeContext(context); var mergedOptions = _objectSpread(_objectSpread({}, DEFAULT_OPTIONS), options); var nativeAnalyserNode = createNativeAnalyserNode(nativeContext, mergedOptions); var analyserNodeRenderer = isNativeOfflineAudioContext(nativeContext) ? createAnalyserNodeRenderer() : null; _this = _super.call(this, context, false, nativeAnalyserNode, analyserNodeRenderer); _this._nativeAnalyserNode = nativeAnalyserNode; return _this; } _createClass__default['default'](AnalyserNode, [{ key: "getByteFrequencyData", value: function getByteFrequencyData(array) { this._nativeAnalyserNode.getByteFrequencyData(array); } }, { key: "getByteTimeDomainData", value: function getByteTimeDomainData(array) { this._nativeAnalyserNode.getByteTimeDomainData(array); } }, { key: "getFloatFrequencyData", value: function getFloatFrequencyData(array) { this._nativeAnalyserNode.getFloatFrequencyData(array); } }, { key: "getFloatTimeDomainData", value: function getFloatTimeDomainData(array) { this._nativeAnalyserNode.getFloatTimeDomainData(array); } }, { key: "fftSize", get: function get() { return this._nativeAnalyserNode.fftSize; }, set: function set(value) { this._nativeAnalyserNode.fftSize = value; } }, { key: "frequencyBinCount", get: function get() { return this._nativeAnalyserNode.frequencyBinCount; } }, { key: "maxDecibels", get: function get() { return this._nativeAnalyserNode.maxDecibels; }, set: function set(value) { // Bug #118: Safari does not throw an error if maxDecibels is not more than minDecibels. var maxDecibels = this._nativeAnalyserNode.maxDecibels; this._nativeAnalyserNode.maxDecibels = value; if (!(value > this._nativeAnalyserNode.minDecibels)) { this._nativeAnalyserNode.maxDecibels = maxDecibels; throw createIndexSizeError(); } } }, { key: "minDecibels", get: function get() { return this._nativeAnalyserNode.minDecibels; }, set: function set(value) { // Bug #118: Safari does not throw an error if maxDecibels is not more than minDecibels. var minDecibels = this._nativeAnalyserNode.minDecibels; this._nativeAnalyserNode.minDecibels = value; if (!(this._nativeAnalyserNode.maxDecibels > value)) { this._nativeAnalyserNode.minDecibels = minDecibels; throw createIndexSizeError(); } } }, { key: "smoothingTimeConstant", get: function get() { return this._nativeAnalyserNode.smoothingTimeConstant; }, set: function set(value) { this._nativeAnalyserNode.smoothingTimeConstant = value; } }]); return AnalyserNode; }(audionNodeConstructor); }; var isOwnedByContext = function isOwnedByContext(nativeAudioNode, nativeContext) { return nativeAudioNode.context === nativeContext; }; var createAnalyserNodeRendererFactory = function createAnalyserNodeRendererFactory(createNativeAnalyserNode, getNativeAudioNode, renderInputsOfAudioNode) { return function () { var renderedNativeAnalyserNodes = new WeakMap(); var createAnalyserNode = /*#__PURE__*/function () { var _ref = _asyncToGenerator__default['default']( /*#__PURE__*/_regeneratorRuntime__default['default'].mark(function _callee(proxy, nativeOfflineAudioContext, trace) { var nativeAnalyserNode, nativeAnalyserNodeIsOwnedByContext, options; return _regeneratorRuntime__default['default'].wrap(function _callee$(_context) { while (1) { switch (_context.prev = _context.next) { case 0: nativeAnalyserNode = getNativeAudioNode(proxy); // If the initially used nativeAnalyserNode was not constructed on the same OfflineAudioContext it needs to be created again. nativeAnalyserNodeIsOwnedByContext = isOwnedByContext(nativeAnalyserNode, nativeOfflineAudioContext); if (!nativeAnalyserNodeIsOwnedByContext) { options = { channelCount: nativeAnalyserNode.channelCount, channelCountMode: nativeAnalyserNode.channelCountMode, channelInterpretation: nativeAnalyserNode.channelInterpretation, fftSize: nativeAnalyserNode.fftSize, maxDecibels: nativeAnalyserNode.maxDecibels, minDecibels: nativeAnalyserNode.minDecibels, smoothingTimeConstant: nativeAnalyserNode.smoothingTimeConstant }; nativeAnalyserNode = createNativeAnalyserNode(nativeOfflineAudioContext, options); } renderedNativeAnalyserNodes.set(nativeOfflineAudioContext, nativeAnalyserNode); _context.next = 6; return renderInputsOfAudioNode(proxy, nativeOfflineAudioContext, nativeAnalyserNode, trace); case 6: return _context.abrupt("return", nativeAnalyserNode); case 7: case "end": return _context.stop(); } } }, _callee); })); return function createAnalyserNode(_x, _x2, _x3) { return _ref.apply(this, arguments); }; }(); return { render: function render(proxy, nativeOfflineAudioContext, trace) { var renderedNativeAnalyserNode = renderedNativeAnalyserNodes.get(nativeOfflineAudioContext); if (renderedNativeAnalyserNode !== undefined) { return Promise.resolve(renderedNativeAnalyserNode); } return createAnalyserNode(proxy, nativeOfflineAudioContext, trace); } }; }; }; var testAudioBufferCopyChannelMethodsOutOfBoundsSupport = function testAudioBufferCopyChannelMethodsOutOfBoundsSupport(nativeAudioBuffer) { try { nativeAudioBuffer.copyToChannel(new Float32Array(1), 0, -1); } catch (_unused) { return false; } return true; }; var createIndexSizeError = function createIndexSizeError() { return new DOMException('', 'IndexSizeError'); }; var wrapAudioBufferGetChannelDataMethod = function wrapAudioBufferGetChannelDataMethod(audioBuffer) { audioBuffer.getChannelData = function (getChannelData) { return function (channel) { try { return getChannelData.call(audioBuffer, channel); } catch (err) { if (err.code === 12) { throw createIndexSizeError(); } throw err; } }; }(audioBuffer.getChannelData); }; function ownKeys$1(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); keys.push.apply(keys, symbols); } return keys; } function _objectSpread$1(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys$1(Object(source), true).forEach(function (key) { _defineProperty__default['default'](target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys$1(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; } var DEFAULT_OPTIONS$1 = { numberOfChannels: 1 }; var createAudioBufferConstructor = function createAudioBufferConstructor(audioBufferStore, cacheTestResult, createNotSupportedError, nativeAudioBufferConstructor, nativeOfflineAudioContextConstructor, testNativeAudioBufferConstructorSupport, wrapAudioBufferCopyChannelMethods, wrapAudioBufferCopyChannelMethodsOutOfBounds) { var nativeOfflineAudioContext = null; return /*#__PURE__*/function () { function AudioBuffer(options) { _classCallCheck__default['default'](this, AudioBuffer); if (nativeOfflineAudioContextConstructor === null) { throw new Error('Missing the native OfflineAudioContext constructor.'); } var _DEFAULT_OPTIONS$opti = _objectSpread$1(_objectSpread$1({}, DEFAULT_OPTIONS$1), options), length = _DEFAULT_OPTIONS$opti.length, numberOfChannels = _DEFAULT_OPTIONS$opti.numberOfChannels, sampleRate = _DEFAULT_OPTIONS$opti.sampleRate; if (nativeOfflineAudioContext === null) { nativeOfflineAudioContext = new nativeOfflineAudioContextConstructor(1, 1, 44100); } /* * Bug #99: Firefox does not throw a NotSupportedError when the numberOfChannels is zero. But it only does it when using the * factory function. But since Firefox also supports the constructor everything should be fine. */ var audioBuffer = nativeAudioBufferConstructor !== null && cacheTestResult(testNativeAudioBufferConstructorSupport, testNativeAudioBufferConstructorSupport) ? new nativeAudioBufferConstructor({ length: length, numberOfChannels: numberOfChannels, sampleRate: sampleRate }) : nativeOfflineAudioContext.createBuffer(numberOfChannels, length, sampleRate); // Bug #99: Safari does not throw an error when the numberOfChannels is zero. if (audioBuffer.numberOfChannels === 0) { throw createNotSupportedError(); } // Bug #5: Safari does not support copyFromChannel() and copyToChannel(). // Bug #100: Safari does throw a wrong error when calling getChannelData() with an out-of-bounds value. if (typeof audioBuffer.copyFromChannel !== 'function') { wrapAudioBufferCopyChannelMethods(audioBuffer); wrapAudioBufferGetChannelDataMethod(audioBuffer); // Bug #157: Firefox does not allow the bufferOffset to be out-of-bounds. } else if (!cacheTestResult(testAudioBufferCopyChannelMethodsOutOfBoundsSupport, function () { return testAudioBufferCopyChannelMethodsOutOfBoundsSupport(audioBuffer); })) { wrapAudioBufferCopyChannelMethodsOutOfBounds(audioBuffer); } audioBufferStore.add(audioBuffer); /* * This does violate all good pratices but it is necessary to allow this AudioBuffer to be used with native * (Offline)AudioContexts. */ return audioBuffer; } _createClass__default['default'](AudioBuffer, null, [{ key: Symbol.hasInstance, value: function value(instance) { return instance !== null && _typeof__default['default'](instance) === 'object' && Object.getPrototypeOf(instance) === AudioBuffer.prototype || audioBufferStore.has(instance); } }]); return AudioBuffer; }(); }; var MOST_NEGATIVE_SINGLE_FLOAT = -3.4028234663852886e38; var MOST_POSITIVE_SINGLE_FLOAT = -MOST_NEGATIVE_SINGLE_FLOAT; var isActiveAudioNode = function isActiveAudioNode(audioNode) { return ACTIVE_AUDIO_NODE_STORE.has(audioNode); }; function ownKeys$2(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); keys.push.apply(keys, symbols); } return keys; } function _objectSpread$2(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys$2(Object(source), true).forEach(function (key) { _defineProperty__default['default'](target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys$2(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; } function _createSuper$1(Derived) { var hasNativeReflectConstruct = _isNativeReflectConstruct$1(); return function _createSuperInternal() { var Super = _getPrototypeOf__default['default'](Derived), result; if (hasNativeReflectConstruct) { var NewTarget = _getPrototypeOf__default['default'](this).constructor; result = Reflect.construct(Super, arguments, NewTarget); } else { result = Super.apply(this, arguments); } return _possibleConstructorReturn__default['default'](this, result); }; } function _isNativeReflectConstruct$1() { if (typeof Reflect === "undefined" || !Reflect.construct) return false; if (Reflect.construct.sham) return false; if (typeof Proxy === "function") return true; try { Date.prototype.toString.call(Reflect.construct(Date, [], function () {})); return true; } catch (e) { return false; } } var DEFAULT_OPTIONS$2 = { buffer: null, channelCount: 2, channelCountMode: 'max', channelInterpretation: 'speakers', // Bug #149: Safari does not yet support the detune AudioParam. loop: false, loopEnd: 0, loopStart: 0, playbackRate: 1 }; var createAudioBufferSourceNodeConstructor = function createAudioBufferSourceNodeConstructor(audioNodeConstructor, createAudioBufferSourceNodeRenderer, createAudioParam, createInvalidStateError, createNativeAudioBufferSourceNode, getNativeContext, isNativeOfflineAudioContext, wrapEventListener) { return /*#__PURE__*/function (_audioNodeConstructor) { _inherits__default['default'](AudioBufferSourceNode, _audioNodeConstructor); var _super = _createSuper$1(AudioBufferSourceNode); function AudioBufferSourceNode(context, options) { var _this; _classCallCheck__default['default'](this, AudioBufferSourceNode); var nativeContext = getNativeContext(context); var mergedOptions = _objectSpread$2(_objectSpread$2({}, DEFAULT_OPTIONS$2), options); var nativeAudioBufferSourceNode = createNativeAudioBufferSourceNode(nativeContext, mergedOptions); var isOffline = isNativeOfflineAudioContext(nativeContext); var audioBufferSourceNodeRenderer = isOffline ? createAudioBufferSourceNodeRenderer() : null; _this = _super.call(this, context, false, nativeAudioBufferSourceNode, audioBufferSourceNodeRenderer); _this._audioBufferSourceNodeRenderer = audioBufferSourceNodeRenderer; _this._isBufferNullified = false; _this._isBufferSet = mergedOptions.buffer !== null; _this._nativeAudioBufferSourceNode = nativeAudioBufferSourceNode; _this._onended = null; // Bug #73: Safari does not export the correct values for maxValue and minValue. _this._playbackRate = createAudioParam(_assertThisInitialized__default['default'](_this), isOffline, nativeAudioBufferSourceNode.playbackRate, MOST_POSITIVE_SINGLE_FLOAT, MOST_NEGATIVE_SINGLE_FLOAT); return _this; } _createClass__default['default'](AudioBufferSourceNode, [{ key: "start", value: function start() { var _this2 = this; var when = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 0; var offset = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0; var duration = arguments.length > 2 ? arguments[2] : undefined; this._nativeAudioBufferSourceNode.start(when, offset, duration); if (this._audioBufferSourceNodeRenderer !== null) { this._audioBufferSourceNodeRenderer.start = duration === undefined ? [when, offset] : [when, offset, duration]; } if (this.context.state !== 'closed') { setInternalStateToActive(this); var resetInternalStateToPassive = function resetInternalStateToPassive() { _this2._nativeAudioBufferSourceNode.removeEventListener('ended', resetInternalStateToPassive); if (isActiveAudioNode(_this2)) { setInternalStateToPassive(_this2); } }; this._nativeAudioBufferSourceNode.addEventListener('ended', resetInternalStateToPassive); } } }, { key: "stop", value: function stop() { var when = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 0; this._nativeAudioBufferSourceNode.stop(when); if (this._audioBufferSourceNodeRenderer !== null) { this._audioBufferSourceNodeRenderer.stop = when; } } }, { key: "buffer", get: function get() { if (this._isBufferNullified) { return null; } return this._nativeAudioBufferSourceNode.buffer; }, set: function set(value) { this._nativeAudioBufferSourceNode.buffer = value; // Bug #72: Only Chrome, Edge & Opera do not allow to reassign the buffer yet. if (value !== null) { if (this._isBufferSet) { throw createInvalidStateError(); } this._isBufferSet = true; } } }, { key: "loop", get: function get() { return this._nativeAudioBufferSourceNode.loop; }, set: function set(value) { this._nativeAudioBufferSourceNode.loop = value; } }, { key: "loopEnd", get: function get() { return this._nativeAudioBufferSourceNode.loopEnd; }, set: function set(value) { this._nativeAudioBufferSourceNode.loopEnd = value; } }, { key: "loopStart", get: function get() { return this._nativeAudioBufferSourceNode.loopStart; }, set: function set(value) { this._nativeAudioBufferSourceNode.loopStart = value; } }, { key: "onended", get: function get() { return this._onended; }, set: function set(value) { var wrappedListener = typeof value === 'function' ? wrapEventListener(this, value) : null; this._nativeAudioBufferSourceNode.onended = wrappedListener; var nativeOnEnded = this._nativeAudioBufferSourceNode.onended; this._onended = nativeOnEnded !== null && nativeOnEnded === wrappedListener ? value : nativeOnEnded; } }, { key: "playbackRate", get: function get() { return this._playbackRate; } }]); return AudioBufferSourceNode; }(audioNodeConstructor); }; var createAudioBufferSourceNodeRendererFactory = function createAudioBufferSourceNodeRendererFactory(connectAudioParam, createNativeAudioBufferSourceNode, getNativeAudioNode, renderAutomation, renderInputsOfAudioNode) { return function () { var renderedNativeAudioBufferSourceNodes = new WeakMap(); var start = null; var stop = null; var createAudioBufferSourceNode = /*#__PURE__*/function () { var _ref = _asyncToGenerator__default['default']( /*#__PURE__*/_regeneratorRuntime__default['default'].mark(function _callee(proxy, nativeOfflineAudioContext, trace) { var nativeAudioBufferSourceNode, nativeAudioBufferSourceNodeIsOwnedByContext, options, _nativeAudioBufferSou; return _regeneratorRuntime__default['default'].wrap(function _callee$(_context) { while (1) { switch (_context.prev = _context.next) { case 0: nativeAudioBufferSourceNode = getNativeAudioNode(proxy); /* * If the initially used nativeAudioBufferSourceNode was not constructed on the same OfflineAudioContext