@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
JavaScript
(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