"use strict"; var __defProp = Object.defineProperty; var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value; var __publicField = (obj, key, value) => { __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value); return value; }; Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" }); const _MockBaseAudioContext = class extends EventTarget { constructor(state, sampleRate = _MockBaseAudioContext._sampleRateDefault) { super(); // Prevents direct modifications __publicField(this, "_state"); __publicField(this, "_sampleRate"); if (new.target === _MockBaseAudioContext) { throw new TypeError("Illegal constructor"); } if (!_MockBaseAudioContext._isValidSampleRateValue(sampleRate)) { const targetName = new.target.name.replace("Mock", ""); throw new Error(`Failed to construct '${targetName}': The sample rate provided (${sampleRate}) is outside the range [${_MockBaseAudioContext._sampleRateMin}, ${_MockBaseAudioContext._sampleRateMax}]`); } this._state = state; this._sampleRate = sampleRate; } static _isValidSampleRateValue(sampleRate) { if (!Number.isFinite(sampleRate) || typeof sampleRate !== "number") { return false; } return sampleRate >= _MockBaseAudioContext._sampleRateMin && sampleRate <= _MockBaseAudioContext._sampleRateMax; } // Max sample rate guaranteed by all user-agents https://developer.mozilla.org/en-US/docs/Web/API/AudioContext/AudioContext get currentTime() { return _MockBaseAudioContext._currentTimeDefault; } set currentTime(currentTime) { } // Prevents direct modifications get state() { return this._state; } set state(state) { } // Prevents direct modifications get sampleRate() { return this._sampleRate; } set sampleRate(sampleRate) { } // eslint-disable-next-line no-warning-comments // TODO: try this approach // protected _setState(state: AudioContextState): void { // this._state = state // this.dispatchEvent(new Event('statechange')) // } // eslint-disable-next-line no-warning-comments // TODO: test // public addEventListener(type: K, listener: (this: BaseAudioContext, ev: BaseAudioContextEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void { // super.addEventListener(type, listener, options) // } // eslint-disable-next-line no-warning-comments // TODO: test // public removeEventListener(type: K, listener: (this: BaseAudioContext, ev: BaseAudioContextEventMap[K]) => any, options?: boolean | EventListenerOptions): void { // super.removeEventListener(type, listener, options) // } }; let MockBaseAudioContext = _MockBaseAudioContext; __publicField(MockBaseAudioContext, "_currentTimeDefault", 0); __publicField(MockBaseAudioContext, "_sampleRateDefault", 44100); __publicField(MockBaseAudioContext, "_sampleRateMin", 8e3); // Min sample rate guaranteed by all user-agents https://developer.mozilla.org/en-US/docs/Web/API/AudioContext/AudioContext __publicField(MockBaseAudioContext, "_sampleRateMax", 96e3); const clamp = (value, min, max) => { if (min > max) { throw new TypeError(`min cannot be more than max, but received min: ${min}, max: ${max}`); } return Math.max(min, Math.min(value, max)); }; const _MockAudioContext = class extends MockBaseAudioContext { constructor(options) { const state = "running"; super(state, options?.sampleRate); // Prevents direct modifications __publicField(this, "_baseLatency"); __publicField(this, "_outputLatency"); const latencyHint = options?.latencyHint ?? _MockAudioContext._defaultLatencyHint; _MockAudioContext._validateLatencyHint(latencyHint); this._baseLatency = _MockAudioContext._getBaseLatencyForHint(latencyHint); this._outputLatency = _MockAudioContext._getOutputLatencyForHint(latencyHint); } static _validateLatencyHint(latencyHint) { if (typeof latencyHint === "number") { return; } if (latencyHint === "balanced" || latencyHint === "interactive" || latencyHint === "playback") { return; } throw new TypeError(`Failed to construct 'AudioContext': Failed to read the 'latencyHint' property from 'AudioContextOptions': The provided value ${latencyHint} is not a valid enum value of type AudioContextLatencyCategory.`); } static _getBaseLatencyForHint(latencyHint) { if (typeof latencyHint === "number") { return clamp(latencyHint, _MockAudioContext._baseLatencyMin, _MockAudioContext._baseLatencyMax); } if (latencyHint === "playback") { return _MockAudioContext._baseLatencyForPlaybackHint; } if (latencyHint === "balanced") { return _MockAudioContext._baseLatencyForBalancedHint; } return _MockAudioContext._baseLatencyForInteractiveHint; } static _getOutputLatencyForHint(latencyHint) { if (typeof latencyHint === "number") { return clamp(latencyHint * 2, _MockAudioContext._outputLatencyMin, _MockAudioContext._outputLatencyMax); } if (latencyHint === "playback") { return _MockAudioContext._outputLatencyForPlaybackHint; } if (latencyHint === "balanced") { return _MockAudioContext._outputLatencyForBalancedHint; } return _MockAudioContext._outputLatencyForInteractiveHint; } get baseLatency() { return this._baseLatency; } set baseLatency(baseLatency) { } // Prevents direct modifications get outputLatency() { return this._outputLatency; } set outputLatency(outputLatency) { } }; let MockAudioContext = _MockAudioContext; __publicField(MockAudioContext, "_defaultLatencyHint", "interactive"); __publicField(MockAudioContext, "_baseLatencyMin", 1e-4); __publicField(MockAudioContext, "_baseLatencyMax", 0.5); __publicField(MockAudioContext, "_outputLatencyMin", 2e-3); __publicField(MockAudioContext, "_outputLatencyMax", 0.9999); __publicField(MockAudioContext, "_baseLatencyForPlaybackHint", 0.025); __publicField(MockAudioContext, "_baseLatencyForBalancedHint", 0.011); __publicField(MockAudioContext, "_baseLatencyForInteractiveHint", 5e-3); __publicField(MockAudioContext, "_outputLatencyForPlaybackHint", 0.051); __publicField(MockAudioContext, "_outputLatencyForBalancedHint", 0.022); __publicField(MockAudioContext, "_outputLatencyForInteractiveHint", 9e-3); const _MockAudioNode = class { constructor(options) { // Prevent modifications __publicField(this, "_numberOfInputs"); __publicField(this, "_numberOfOutputs"); __publicField(this, "_context"); __publicField(this, "_channelCount"); __publicField(this, "_channelCountMode"); __publicField(this, "_channelInterpretation"); if (new.target === _MockAudioNode) { throw new TypeError("Illegal constructor"); } const mockTargetName = new.target.name; const targetName = mockTargetName.replace("Mock", ""); const context = options?.context; const numberOfInputs = options?.numberOfInputs; const numberOfOutputs = options?.numberOfOutputs; const channelCount = options?.channelCount ?? _MockAudioNode._channelCountDefault; const channelCountMode = options?.channelCountMode ?? _MockAudioNode._channelCountModeDefault; const channelInterpretation = options?.channelInterpretation ?? _MockAudioNode._channelInterpretationDefault; if (!(context instanceof BaseAudioContext)) { throw new TypeError(`Failed to construct '${targetName}': parameter 1 is not of type 'BaseAudioContext'`); } if (!_MockAudioNode._isValidChannelCount(channelCount)) { throw new TypeError(`Failed to construct '${targetName}': ${_MockAudioNode._getChannelCountErrorMessage(channelCount)}`); } if (!_MockAudioNode._isValidChannelCountMode(channelCountMode)) { throw new TypeError(`Failed to construct '${targetName}': Failed to read the 'channelCountMode' property from 'AudioNodeOptions': ${_MockAudioNode._getChannelCountModeErrorMessage(channelCountMode)}`); } if (!_MockAudioNode._isValidChannelInterpretation(channelInterpretation)) { throw new TypeError(`Failed to construct '${targetName}': Failed to read the 'channelInterpretation' property from 'AudioNodeOptions': ${_MockAudioNode._getChannelInterpretationErrorMessage(channelInterpretation)}`); } this._context = context; this._numberOfInputs = numberOfInputs; this._numberOfOutputs = numberOfOutputs; this._channelCount = channelCount; this._channelCountMode = channelCountMode; this._channelInterpretation = channelInterpretation; } get channelCount() { return this._channelCount; } set channelCount(channelCount) { if (!_MockAudioNode._isValidChannelCount(channelCount)) { throw new Error(`Failed to set the 'channelCount' property on 'AudioNode': ${_MockAudioNode._getChannelCountErrorMessage(channelCount)}`); } this._channelCount = channelCount; } get channelCountMode() { return this._channelCountMode; } set channelCountMode(channelCountMode) { if (!_MockAudioNode._isValidChannelCountMode(channelCountMode)) { console.warn(_MockAudioNode._getChannelCountModeErrorMessage(channelCountMode)); return; } this._channelCountMode = channelCountMode; } get channelInterpretation() { return this._channelInterpretation; } set channelInterpretation(channelInterpretation) { if (!_MockAudioNode._isValidChannelInterpretation(channelInterpretation)) { console.warn(_MockAudioNode._getChannelInterpretationErrorMessage(channelInterpretation)); return; } this._channelInterpretation = channelInterpretation; } static _isValidChannelCount(channelCount) { return !Number.isNaN(Number(channelCount)) && channelCount >= _MockAudioNode._channelCountMin && channelCount <= _MockAudioNode._channelCountMax; } static _isValidChannelCountMode(channelCountMode) { return channelCountMode === "clamped-max" || channelCountMode === "explicit" || channelCountMode === "max"; } static _isValidChannelInterpretation(channelInterpretation) { return channelInterpretation === "discrete" || channelInterpretation === "speakers"; } static _getChannelCountErrorMessage(channelCount) { return `The channel count provided (${channelCount}) is outside the range [${_MockAudioNode._channelCountMin}, ${_MockAudioNode._channelCountMax}]`; } static _getChannelCountModeErrorMessage(channelCountMode) { return `The provided value '${channelCountMode}' is not a valid enum value of type ChannelCountMode.`; } static _getChannelInterpretationErrorMessage(channelInterpretation) { return `The provided value '${channelInterpretation}' is not a valid enum value of type ChannelInterpretation.`; } get context() { return this._context; } set context(context) { } // Prevent modifications get numberOfInputs() { return this._numberOfInputs; } set numberOfInputs(numberOfInputs) { } // Prevent modifications get numberOfOutputs() { return this._numberOfOutputs; } set numberOfOutputs(numberOfOutputs) { } }; let MockAudioNode = _MockAudioNode; __publicField(MockAudioNode, "_channelCountDefault", 2); __publicField(MockAudioNode, "_channelCountMin", 1); __publicField(MockAudioNode, "_channelCountMax", 32); __publicField(MockAudioNode, "_channelCountModeDefault", "max"); __publicField(MockAudioNode, "_channelInterpretationDefault", "speakers"); class MockAudioParam { constructor(options) { __publicField(this, "_automationRate"); __publicField(this, "_value"); __publicField(this, "_defaultValue"); __publicField(this, "_minValue"); __publicField(this, "_maxValue"); if (new.target === MockAudioParam) { throw new TypeError("Illegal constructor"); } const automationRate = options?.automationRate; const defaultValue = options?.defaultValue; const minValue = options?.minValue; const maxValue = options?.maxValue; const value = options?.value ?? defaultValue; if (!MockAudioParam._isValidValue(value)) { throw new TypeError("The provided float value is non-finite"); } this._automationRate = automationRate; this._defaultValue = defaultValue; this._minValue = minValue; this._maxValue = maxValue; this._value = value; this.value = value; } get automationRate() { return this._automationRate; } set automationRate(automationRate) { if (!MockAudioParam._isValidAutomationRate(automationRate)) { console.warn(`The provided value '${automationRate}' is not a valid enum value of type AutomationRate.`); return; } this._automationRate = automationRate; } get value() { return this._value; } set value(value) { if (!MockAudioParam._isValidValue(value)) { throw new TypeError("Failed to set the 'value' property on 'AudioParam': The provided float value is non-finite."); } if (!this._isValueInRange(value)) { console.warn(`value ${value} outside nominal range [${this.minValue}, ${this.maxValue}]; value will be clamped`); this._value = clamp(value, this.minValue, this.maxValue); return; } this._value = value; } get defaultValue() { return this._defaultValue; } set defaultValue(defaultValue) { } // Prevent modifications get minValue() { return this._minValue; } set minValue(minValue) { } // Prevent modifications get maxValue() { return this._maxValue; } set maxValue(maxValue) { } // Prevent modifications static _isValidAutomationRate(automationRate) { return automationRate === "a-rate" || automationRate === "k-rate"; } static _isValidValue(value) { return Number.isFinite(value); } _isValueInRange(value) { return this.minValue <= value && value <= this.maxValue; } } class MockDelayTimeAudioParam extends MockAudioParam { constructor({ delayTime, maxDelayTime }) { super({ automationRate: "a-rate", defaultValue: 0, minValue: 0, maxValue: maxDelayTime, value: delayTime }); } } const _MockDelayNode = class extends MockAudioNode { constructor(context, options = {}) { const { channelCount, channelCountMode, channelInterpretation, delayTime = 0, maxDelayTime = 1 } = options; if (!Number.isFinite(maxDelayTime)) { throw new TypeError("Failed to construct 'DelayNode': Failed to read the 'maxDelayTime' property from 'DelayOptions': The provided double value is non-finite."); } if (maxDelayTime <= _MockDelayNode._maxDelayTimeMin || maxDelayTime >= _MockDelayNode._maxDelayTimeMax) { throw new Error(`Failed to construct 'DelayNode': The max delay time provided (${maxDelayTime}) is outside the range (${_MockDelayNode._maxDelayTimeMin}, ${_MockDelayNode._maxDelayTimeMax})`); } super({ numberOfInputs: 1, numberOfOutputs: 1, context, channelCount, channelCountMode, channelInterpretation }); // Prevents modifications __publicField(this, "_delayTime"); this._delayTime = new MockDelayTimeAudioParam({ delayTime, maxDelayTime }); } // https://chromium.googlesource.com/chromium/blink/+/refs/heads/main/Source/modules/webaudio/DelayNode.cpp#38 get delayTime() { return this._delayTime; } set delayTime(delayTime) { } }; let MockDelayNode = _MockDelayNode; __publicField(MockDelayNode, "_maxDelayTimeMin", 0); __publicField(MockDelayNode, "_maxDelayTimeMax", 180); class MockGainAudioParam extends MockAudioParam { constructor(gain) { super({ automationRate: "a-rate", defaultValue: 1, minValue: -34028234663852886e22, maxValue: 34028234663852886e22, value: gain }); } } class MockGainNode extends MockAudioNode { constructor(context, options = {}) { const { channelCount, channelCountMode, channelInterpretation, gain } = options; super({ numberOfInputs: 1, numberOfOutputs: 1, context, channelCount, channelCountMode, channelInterpretation }); // Prevents modifications __publicField(this, "_gain"); this._gain = new MockGainAudioParam(gain); } get gain() { return this._gain; } set gain(gain) { } } const _MockOfflineAudioContext = class extends MockBaseAudioContext { constructor(...args) { var __super = (...args) => { super(...args); __publicField(this, "_length"); }; const state = "suspended"; if (args.length === 1) { const contextOptions = args[0]; const numberOfChannels = contextOptions?.numberOfChannels ?? _MockOfflineAudioContext._numberOfChannelsDefault; const length = contextOptions?.length; const sampleRate = contextOptions?.sampleRate; _MockOfflineAudioContext._validateNumberOfChannels(numberOfChannels); _MockOfflineAudioContext._validateLength(length); _MockOfflineAudioContext._validateSampleRate(sampleRate); __super(state, sampleRate); this._length = length; return; } if (args.length >= 3) { const [numberOfChannels, length, sampleRate] = args; _MockOfflineAudioContext._validateNumberOfChannels(numberOfChannels); _MockOfflineAudioContext._validateLength(length); _MockOfflineAudioContext._validateSampleRate(sampleRate); __super(state, sampleRate); this._length = length; return; } if (!args.length) { throw new TypeError("Failed to construct 'OfflineAudioContext': 1 argument required, but only 0 present"); } throw new TypeError("Failed to construct 'OfflineAudioContext': Overload resolution failed."); } get length() { return this._length; } set length(length) { } static _validateNumberOfChannels(numberOfChannels) { if (!Number.isFinite(numberOfChannels) || numberOfChannels < _MockOfflineAudioContext._numberOfChannelsMin || numberOfChannels > _MockOfflineAudioContext._numberOfChannelsMax) { throw new Error(`Failed to construct 'OfflineAudioContext': The number of channels provided (${numberOfChannels}) is outside the range [${_MockOfflineAudioContext._numberOfChannelsMin}, ${_MockOfflineAudioContext._numberOfChannelsMax}]`); } } static _validateLength(length) { if (!Number.isFinite(length) || length < _MockOfflineAudioContext._lengthMin) { throw new Error(`Failed to construct 'OfflineAudioContext': The number of frames provided (${length}) is less than the minimum bound (${_MockOfflineAudioContext._lengthMin})`); } } static _validateSampleRate(sampleRate) { if (!MockBaseAudioContext._isValidSampleRateValue(sampleRate)) { throw new TypeError("Failed to construct 'OfflineAudioContext': The provided float value is non-finite"); } } }; let MockOfflineAudioContext = _MockOfflineAudioContext; // Prevents modifications __publicField(MockOfflineAudioContext, "_numberOfChannelsDefault", 1); __publicField(MockOfflineAudioContext, "_numberOfChannelsMin", 1); __publicField(MockOfflineAudioContext, "_numberOfChannelsMax", 32); __publicField(MockOfflineAudioContext, "_lengthMin", 1); const _MWAA = class { static mock() { if (_MWAA._isMocked) { throw new Error("[MWAA] already using mocked version of Web Audio API"); } _MWAA._mock("AudioContext", MockAudioContext, _MWAA._originalAudioContext); _MWAA._mock("AudioNode", MockAudioNode, _MWAA._originalAudioNode); _MWAA._mock("AudioParam", MockAudioParam, _MWAA._originalAudioParam); _MWAA._mock("BaseAudioContext", MockBaseAudioContext, _MWAA._originalBaseAudioContext); _MWAA._mock("DelayNode", MockDelayNode, _MWAA._originalDelayNode); _MWAA._mock("GainNode", MockGainNode, _MWAA._originalGainNode); _MWAA._mock("OfflineAudioContext", MockOfflineAudioContext, _MWAA._originalOfflineAudioContext); _MWAA._isMocked = true; } static unmock() { if (!_MWAA._isMocked) { throw new Error("[MWAA] already using the original version of Web Audio API"); } _MWAA._unmock("AudioContext", _MWAA._originalAudioContext); _MWAA._unmock("AudioNode", _MWAA._originalAudioNode); _MWAA._unmock("AudioParam", _MWAA._originalAudioParam); _MWAA._unmock("BaseAudioContext", _MWAA._originalBaseAudioContext); _MWAA._unmock("DelayNode", _MWAA._originalDelayNode); _MWAA._unmock("GainNode", _MWAA._originalGainNode); _MWAA._unmock("OfflineAudioContext", _MWAA._originalOfflineAudioContext); _MWAA._isMocked = false; } static _mock(name, mock, temp) { globalThis[name] = mock; } static _unmock(name, temp) { globalThis[name] = temp; } }; let MWAA = _MWAA; __publicField(MWAA, "_isMocked", false); __publicField(MWAA, "_originalAudioContext"); __publicField(MWAA, "_originalAudioNode"); __publicField(MWAA, "_originalAudioParam"); __publicField(MWAA, "_originalBaseAudioContext"); __publicField(MWAA, "_originalDelayNode"); __publicField(MWAA, "_originalGainNode"); __publicField(MWAA, "_originalOfflineAudioContext"); exports.MWAA = MWAA; //# sourceMappingURL=index.cjs.map