mirror of
https://github.com/Tonejs/Tone.js
synced 2024-12-26 11:33:09 +00:00
allow JSON.stringify(context)
This commit is contained in:
parent
bfa600399f
commit
16859ff2e2
4 changed files with 227 additions and 113 deletions
|
@ -8,63 +8,90 @@ type Transport = import("../clock/Transport").Transport;
|
|||
type Listener = import("./Listener").Listener;
|
||||
|
||||
// these are either not used in Tone.js or deprecated and not implemented.
|
||||
export type ExcludedFromBaseAudioContext = "onstatechange" | "addEventListener" | "removeEventListener" | "listener" | "dispatchEvent" | "audioWorklet" | "destination" | "createScriptProcessor";
|
||||
export type ExcludedFromBaseAudioContext =
|
||||
| "onstatechange"
|
||||
| "addEventListener"
|
||||
| "removeEventListener"
|
||||
| "listener"
|
||||
| "dispatchEvent"
|
||||
| "audioWorklet"
|
||||
| "destination"
|
||||
| "createScriptProcessor";
|
||||
|
||||
// the subset of the BaseAudioContext which Tone.Context implements.
|
||||
export type BaseAudioContextSubset = Omit<BaseAudioContext, ExcludedFromBaseAudioContext>;
|
||||
export type BaseAudioContextSubset = Omit<
|
||||
BaseAudioContext,
|
||||
ExcludedFromBaseAudioContext
|
||||
>;
|
||||
|
||||
export type ContextLatencyHint = AudioContextLatencyCategory;
|
||||
|
||||
export abstract class BaseContext extends Emitter<"statechange" | "tick"> implements BaseAudioContextSubset {
|
||||
|
||||
export abstract class BaseContext
|
||||
extends Emitter<"statechange" | "tick">
|
||||
implements BaseAudioContextSubset {
|
||||
//---------------------------
|
||||
// BASE AUDIO CONTEXT METHODS
|
||||
//---------------------------
|
||||
abstract createAnalyser(): AnalyserNode
|
||||
abstract createAnalyser(): AnalyserNode;
|
||||
|
||||
abstract createOscillator(): OscillatorNode
|
||||
abstract createOscillator(): OscillatorNode;
|
||||
|
||||
abstract createBufferSource(): AudioBufferSourceNode
|
||||
abstract createBufferSource(): AudioBufferSourceNode;
|
||||
|
||||
abstract createBiquadFilter(): BiquadFilterNode
|
||||
abstract createBiquadFilter(): BiquadFilterNode;
|
||||
|
||||
abstract createBuffer(_numberOfChannels: number, _length: number, _sampleRate: number): AudioBuffer
|
||||
abstract createBuffer(
|
||||
_numberOfChannels: number,
|
||||
_length: number,
|
||||
_sampleRate: number
|
||||
): AudioBuffer;
|
||||
|
||||
abstract createChannelMerger(_numberOfInputs?: number | undefined): ChannelMergerNode
|
||||
abstract createChannelMerger(
|
||||
_numberOfInputs?: number | undefined
|
||||
): ChannelMergerNode;
|
||||
|
||||
abstract createChannelSplitter(_numberOfOutputs?: number | undefined): ChannelSplitterNode
|
||||
abstract createChannelSplitter(
|
||||
_numberOfOutputs?: number | undefined
|
||||
): ChannelSplitterNode;
|
||||
|
||||
abstract createConstantSource(): ConstantSourceNode
|
||||
abstract createConstantSource(): ConstantSourceNode;
|
||||
|
||||
abstract createConvolver(): ConvolverNode
|
||||
abstract createConvolver(): ConvolverNode;
|
||||
|
||||
abstract createDelay(_maxDelayTime?: number | undefined): DelayNode
|
||||
abstract createDelay(_maxDelayTime?: number | undefined): DelayNode;
|
||||
|
||||
abstract createDynamicsCompressor(): DynamicsCompressorNode
|
||||
abstract createDynamicsCompressor(): DynamicsCompressorNode;
|
||||
|
||||
abstract createGain(): GainNode
|
||||
abstract createGain(): GainNode;
|
||||
|
||||
abstract createIIRFilter(_feedForward: number[] | Float32Array, _feedback: number[] | Float32Array): IIRFilterNode
|
||||
abstract createIIRFilter(
|
||||
_feedForward: number[] | Float32Array,
|
||||
_feedback: number[] | Float32Array
|
||||
): IIRFilterNode;
|
||||
|
||||
abstract createPanner(): PannerNode
|
||||
abstract createPanner(): PannerNode;
|
||||
|
||||
abstract createPeriodicWave(
|
||||
_real: number[] | Float32Array,
|
||||
_imag: number[] | Float32Array,
|
||||
_constraints?: PeriodicWaveConstraints | undefined,
|
||||
): PeriodicWave
|
||||
_constraints?: PeriodicWaveConstraints | undefined
|
||||
): PeriodicWave;
|
||||
|
||||
abstract createStereoPanner(): StereoPannerNode
|
||||
abstract createStereoPanner(): StereoPannerNode;
|
||||
|
||||
abstract createWaveShaper(): WaveShaperNode
|
||||
abstract createWaveShaper(): WaveShaperNode;
|
||||
|
||||
abstract createMediaStreamSource(_stream: MediaStream): MediaStreamAudioSourceNode
|
||||
|
||||
abstract createMediaElementSource(_element: HTMLMediaElement): MediaElementAudioSourceNode
|
||||
|
||||
abstract createMediaStreamDestination(): MediaStreamAudioDestinationNode
|
||||
abstract createMediaStreamSource(
|
||||
_stream: MediaStream
|
||||
): MediaStreamAudioSourceNode;
|
||||
|
||||
abstract decodeAudioData(_audioData: ArrayBuffer): Promise<AudioBuffer>
|
||||
abstract createMediaElementSource(
|
||||
_element: HTMLMediaElement
|
||||
): MediaElementAudioSourceNode;
|
||||
|
||||
abstract createMediaStreamDestination(): MediaStreamAudioDestinationNode;
|
||||
|
||||
abstract decodeAudioData(_audioData: ArrayBuffer): Promise<AudioBuffer>;
|
||||
|
||||
//---------------------------
|
||||
// TONE AUDIO CONTEXT METHODS
|
||||
|
@ -73,45 +100,56 @@ export abstract class BaseContext extends Emitter<"statechange" | "tick"> implem
|
|||
abstract createAudioWorkletNode(
|
||||
_name: string,
|
||||
_options?: Partial<AudioWorkletNodeOptions>
|
||||
): AudioWorkletNode
|
||||
): AudioWorkletNode;
|
||||
|
||||
abstract get rawContext(): AnyAudioContext
|
||||
abstract get rawContext(): AnyAudioContext;
|
||||
|
||||
abstract async addAudioWorkletModule(_url: string, _name: string): Promise<void>
|
||||
abstract async addAudioWorkletModule(
|
||||
_url: string,
|
||||
_name: string
|
||||
): Promise<void>;
|
||||
|
||||
abstract lookAhead: number;
|
||||
|
||||
abstract latencyHint: ContextLatencyHint | Seconds;
|
||||
|
||||
abstract resume(): Promise<void>
|
||||
abstract resume(): Promise<void>;
|
||||
|
||||
abstract setTimeout(_fn: (...args: any[]) => void, _timeout: Seconds): number
|
||||
abstract setTimeout(
|
||||
_fn: (...args: any[]) => void,
|
||||
_timeout: Seconds
|
||||
): number;
|
||||
|
||||
abstract clearTimeout(_id: number): this
|
||||
abstract clearTimeout(_id: number): this;
|
||||
|
||||
abstract setInterval(_fn: (...args: any[]) => void, _interval: Seconds): number
|
||||
abstract setInterval(
|
||||
_fn: (...args: any[]) => void,
|
||||
_interval: Seconds
|
||||
): number;
|
||||
|
||||
abstract clearInterval(_id: number): this
|
||||
abstract clearInterval(_id: number): this;
|
||||
|
||||
abstract getConstant(_val: number): AudioBufferSourceNode
|
||||
abstract getConstant(_val: number): AudioBufferSourceNode;
|
||||
|
||||
abstract get currentTime(): Seconds
|
||||
abstract get currentTime(): Seconds;
|
||||
|
||||
abstract get state(): AudioContextState
|
||||
abstract get state(): AudioContextState;
|
||||
|
||||
abstract get sampleRate(): number
|
||||
abstract get sampleRate(): number;
|
||||
|
||||
abstract get listener(): Listener
|
||||
abstract get listener(): Listener;
|
||||
|
||||
abstract get transport(): Transport
|
||||
abstract get transport(): Transport;
|
||||
|
||||
abstract get draw(): Draw
|
||||
abstract get draw(): Draw;
|
||||
|
||||
abstract get destination(): Destination
|
||||
abstract get destination(): Destination;
|
||||
|
||||
abstract now(): Seconds
|
||||
abstract now(): Seconds;
|
||||
|
||||
abstract immediate(): Seconds
|
||||
abstract immediate(): Seconds;
|
||||
|
||||
abstract toJSON(): Record<string, any>;
|
||||
|
||||
readonly isOffline: boolean = false;
|
||||
}
|
||||
|
|
|
@ -12,7 +12,6 @@ import { Draw } from "../util/Draw";
|
|||
import { connect } from "./ToneAudioNode";
|
||||
|
||||
describe("Context", () => {
|
||||
|
||||
it("creates and disposes the classes attached to the context", async () => {
|
||||
const ac = createAudioContext();
|
||||
const context = new Context(ac);
|
||||
|
@ -32,7 +31,6 @@ describe("Context", () => {
|
|||
});
|
||||
|
||||
context("AudioContext", () => {
|
||||
|
||||
it("extends the AudioContext methods", () => {
|
||||
const ctx = new Context(createAudioContext());
|
||||
expect(ctx).to.have.property("createGain");
|
||||
|
@ -46,8 +44,15 @@ describe("Context", () => {
|
|||
return ctx.close();
|
||||
});
|
||||
|
||||
it("can be stringified", () => {
|
||||
const ctx = new Context(createAudioContext());
|
||||
expect(JSON.stringify(ctx)).to.equal("{}");
|
||||
ctx.dispose();
|
||||
return ctx.close();
|
||||
});
|
||||
|
||||
if (ONLINE_TESTING) {
|
||||
it("clock is running", done => {
|
||||
it("clock is running", (done) => {
|
||||
const interval = setInterval(() => {
|
||||
if (getContext().currentTime > 0.5) {
|
||||
clearInterval(interval);
|
||||
|
@ -88,7 +93,6 @@ describe("Context", () => {
|
|||
});
|
||||
|
||||
context("state", () => {
|
||||
|
||||
it("can suspend and resume the state", async () => {
|
||||
const ac = createAudioContext();
|
||||
const context = new Context(ac);
|
||||
|
@ -105,14 +109,14 @@ describe("Context", () => {
|
|||
const ac = createAudioContext();
|
||||
const context = new Context(ac);
|
||||
let triggerChange = false;
|
||||
context.on("statechange", state => {
|
||||
context.on("statechange", (state) => {
|
||||
if (!triggerChange) {
|
||||
triggerChange = true;
|
||||
expect(state).to.equal("running");
|
||||
}
|
||||
});
|
||||
await context.resume();
|
||||
await new Promise(done => setTimeout(() => done(), 10));
|
||||
await new Promise((done) => setTimeout(() => done(), 10));
|
||||
expect(triggerChange).to.equal(true);
|
||||
context.dispose();
|
||||
return ac.close();
|
||||
|
@ -120,9 +124,7 @@ describe("Context", () => {
|
|||
});
|
||||
|
||||
if (ONLINE_TESTING) {
|
||||
|
||||
context("clockSource", () => {
|
||||
|
||||
let ctx;
|
||||
beforeEach(() => {
|
||||
ctx = new Context();
|
||||
|
@ -138,14 +140,14 @@ describe("Context", () => {
|
|||
expect(ctx.clockSource).to.equal("worker");
|
||||
});
|
||||
|
||||
it("provides callback", done => {
|
||||
it("provides callback", (done) => {
|
||||
expect(ctx.clockSource).to.equal("worker");
|
||||
ctx.setTimeout(() => {
|
||||
done();
|
||||
}, 0.1);
|
||||
});
|
||||
|
||||
it("can be set to 'timeout'", done => {
|
||||
it("can be set to 'timeout'", (done) => {
|
||||
ctx.clockSource = "timeout";
|
||||
expect(ctx.clockSource).to.equal("timeout");
|
||||
ctx.setTimeout(() => {
|
||||
|
@ -153,7 +155,7 @@ describe("Context", () => {
|
|||
}, 0.1);
|
||||
});
|
||||
|
||||
it("can be set to 'offline'", done => {
|
||||
it("can be set to 'offline'", (done) => {
|
||||
ctx.clockSource = "offline";
|
||||
expect(ctx.clockSource).to.equal("offline");
|
||||
// provides no callback
|
||||
|
@ -167,9 +169,7 @@ describe("Context", () => {
|
|||
});
|
||||
}
|
||||
context("setTimeout", () => {
|
||||
|
||||
if (ONLINE_TESTING) {
|
||||
|
||||
let ctx;
|
||||
beforeEach(() => {
|
||||
ctx = new Context();
|
||||
|
@ -181,19 +181,19 @@ describe("Context", () => {
|
|||
return ctx.close();
|
||||
});
|
||||
|
||||
it("can set a timeout", done => {
|
||||
it("can set a timeout", (done) => {
|
||||
ctx.setTimeout(() => {
|
||||
done();
|
||||
}, 0.1);
|
||||
});
|
||||
|
||||
it("returns an id", () => {
|
||||
expect(ctx.setTimeout(() => { }, 0.1)).to.be.a("number");
|
||||
expect(ctx.setTimeout(() => {}, 0.1)).to.be.a("number");
|
||||
// try clearing a random ID, shouldn't cause any errors
|
||||
ctx.clearTimeout(-2);
|
||||
});
|
||||
|
||||
it("timeout is not invoked when cancelled", done => {
|
||||
it("timeout is not invoked when cancelled", (done) => {
|
||||
const id = ctx.setTimeout(() => {
|
||||
throw new Error("shouldn't be invoked");
|
||||
}, 0.01);
|
||||
|
@ -203,7 +203,7 @@ describe("Context", () => {
|
|||
}, 0.02);
|
||||
});
|
||||
|
||||
it("order is maintained", done => {
|
||||
it("order is maintained", (done) => {
|
||||
let wasInvoked = false;
|
||||
ctx.setTimeout(() => {
|
||||
expect(wasInvoked).to.equal(true);
|
||||
|
@ -216,7 +216,7 @@ describe("Context", () => {
|
|||
}
|
||||
|
||||
it("is invoked in the offline context", () => {
|
||||
return Offline(context => {
|
||||
return Offline((context) => {
|
||||
const transport = new Transport({ context });
|
||||
transport.context.setTimeout(() => {
|
||||
expect(transport.now()).to.be.closeTo(0.01, 0.005);
|
||||
|
@ -226,9 +226,7 @@ describe("Context", () => {
|
|||
});
|
||||
|
||||
context("setInterval", () => {
|
||||
|
||||
if (ONLINE_TESTING) {
|
||||
|
||||
let ctx;
|
||||
beforeEach(() => {
|
||||
ctx = new Context();
|
||||
|
@ -240,19 +238,19 @@ describe("Context", () => {
|
|||
return ctx.close();
|
||||
});
|
||||
|
||||
it("can set an interval", done => {
|
||||
it("can set an interval", (done) => {
|
||||
ctx.setInterval(() => {
|
||||
done();
|
||||
}, 0.1);
|
||||
});
|
||||
|
||||
it("returns an id", () => {
|
||||
expect(ctx.setInterval(() => { }, 0.1)).to.be.a("number");
|
||||
expect(ctx.setInterval(() => {}, 0.1)).to.be.a("number");
|
||||
// try clearing a random ID, shouldn't cause any errors
|
||||
ctx.clearInterval(-2);
|
||||
});
|
||||
|
||||
it("timeout is not invoked when cancelled", done => {
|
||||
it("timeout is not invoked when cancelled", (done) => {
|
||||
const id = ctx.setInterval(() => {
|
||||
throw new Error("shouldn't be invoked");
|
||||
}, 0.01);
|
||||
|
@ -262,7 +260,7 @@ describe("Context", () => {
|
|||
}, 0.02);
|
||||
});
|
||||
|
||||
it("order is maintained", done => {
|
||||
it("order is maintained", (done) => {
|
||||
let wasInvoked = false;
|
||||
ctx.setInterval(() => {
|
||||
expect(wasInvoked).to.equal(true);
|
||||
|
@ -276,7 +274,7 @@ describe("Context", () => {
|
|||
|
||||
it("is invoked in the offline context", () => {
|
||||
let invocationCount = 0;
|
||||
return Offline(context => {
|
||||
return Offline((context) => {
|
||||
context.setInterval(() => {
|
||||
invocationCount++;
|
||||
}, 0.01);
|
||||
|
@ -287,10 +285,13 @@ describe("Context", () => {
|
|||
|
||||
it("is invoked in with the right interval", () => {
|
||||
let numberOfInvocations = 0;
|
||||
return Offline(context => {
|
||||
return Offline((context) => {
|
||||
let intervalTime = context.now();
|
||||
context.setInterval(() => {
|
||||
expect(context.now() - intervalTime).to.be.closeTo(0.01, 0.005);
|
||||
expect(context.now() - intervalTime).to.be.closeTo(
|
||||
0.01,
|
||||
0.005
|
||||
);
|
||||
intervalTime = context.now();
|
||||
numberOfInvocations++;
|
||||
}, 0.01);
|
||||
|
@ -301,7 +302,6 @@ describe("Context", () => {
|
|||
});
|
||||
|
||||
context("get/set", () => {
|
||||
|
||||
let ctx;
|
||||
beforeEach(() => {
|
||||
ctx = new Context();
|
||||
|
@ -324,7 +324,7 @@ describe("Context", () => {
|
|||
});
|
||||
|
||||
it("gets a constant signal", () => {
|
||||
return ConstantOutput(context => {
|
||||
return ConstantOutput((context) => {
|
||||
const bufferSrc = context.getConstant(1);
|
||||
connect(bufferSrc, context.destination);
|
||||
}, 1);
|
||||
|
@ -335,7 +335,6 @@ describe("Context", () => {
|
|||
const bufferB = ctx.getConstant(2);
|
||||
expect(bufferA).to.equal(bufferB);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
context("Methods", () => {
|
||||
|
|
|
@ -4,7 +4,11 @@ import { isAudioContext } from "../util/AdvancedTypeCheck";
|
|||
import { optionsFromArguments } from "../util/Defaults";
|
||||
import { Timeline } from "../util/Timeline";
|
||||
import { isDefined, isString } from "../util/TypeCheck";
|
||||
import { AnyAudioContext, createAudioContext, createAudioWorkletNode } from "./AudioContext";
|
||||
import {
|
||||
AnyAudioContext,
|
||||
createAudioContext,
|
||||
createAudioWorkletNode,
|
||||
} from "./AudioContext";
|
||||
import { closeContext, initializeContext } from "./ContextInitialization";
|
||||
import { BaseContext, ContextLatencyHint } from "./BaseContext";
|
||||
import { assert } from "../util/Debug";
|
||||
|
@ -33,7 +37,6 @@ export interface ContextTimeoutEvent {
|
|||
* @category Core
|
||||
*/
|
||||
export class Context extends BaseContext {
|
||||
|
||||
readonly name: string = "Context";
|
||||
|
||||
/**
|
||||
|
@ -107,7 +110,9 @@ export class Context extends BaseContext {
|
|||
constructor(options?: Partial<ContextOptions>);
|
||||
constructor() {
|
||||
super();
|
||||
const options = optionsFromArguments(Context.getDefaults(), arguments, ["context"]);
|
||||
const options = optionsFromArguments(Context.getDefaults(), arguments, [
|
||||
"context",
|
||||
]);
|
||||
|
||||
if (options.context) {
|
||||
this._context = options.context;
|
||||
|
@ -117,7 +122,11 @@ export class Context extends BaseContext {
|
|||
});
|
||||
}
|
||||
|
||||
this._ticker = new Ticker(this.emit.bind(this, "tick"), options.clockSource, options.updateInterval);
|
||||
this._ticker = new Ticker(
|
||||
this.emit.bind(this, "tick"),
|
||||
options.clockSource,
|
||||
options.updateInterval
|
||||
);
|
||||
this.on("tick", this._timeoutLoop.bind(this));
|
||||
|
||||
// fwd events from the context
|
||||
|
@ -166,13 +175,21 @@ export class Context extends BaseContext {
|
|||
createBiquadFilter(): BiquadFilterNode {
|
||||
return this._context.createBiquadFilter();
|
||||
}
|
||||
createBuffer(numberOfChannels: number, length: number, sampleRate: number): AudioBuffer {
|
||||
createBuffer(
|
||||
numberOfChannels: number,
|
||||
length: number,
|
||||
sampleRate: number
|
||||
): AudioBuffer {
|
||||
return this._context.createBuffer(numberOfChannels, length, sampleRate);
|
||||
}
|
||||
createChannelMerger(numberOfInputs?: number | undefined): ChannelMergerNode {
|
||||
createChannelMerger(
|
||||
numberOfInputs?: number | undefined
|
||||
): ChannelMergerNode {
|
||||
return this._context.createChannelMerger(numberOfInputs);
|
||||
}
|
||||
createChannelSplitter(numberOfOutputs?: number | undefined): ChannelSplitterNode {
|
||||
createChannelSplitter(
|
||||
numberOfOutputs?: number | undefined
|
||||
): ChannelSplitterNode {
|
||||
return this._context.createChannelSplitter(numberOfOutputs);
|
||||
}
|
||||
createConstantSource(): ConstantSourceNode {
|
||||
|
@ -190,7 +207,10 @@ export class Context extends BaseContext {
|
|||
createGain(): GainNode {
|
||||
return this._context.createGain();
|
||||
}
|
||||
createIIRFilter(feedForward: number[] | Float32Array, feedback: number[] | Float32Array): IIRFilterNode {
|
||||
createIIRFilter(
|
||||
feedForward: number[] | Float32Array,
|
||||
feedback: number[] | Float32Array
|
||||
): IIRFilterNode {
|
||||
// @ts-ignore
|
||||
return this._context.createIIRFilter(feedForward, feedback);
|
||||
}
|
||||
|
@ -200,7 +220,7 @@ export class Context extends BaseContext {
|
|||
createPeriodicWave(
|
||||
real: number[] | Float32Array,
|
||||
imag: number[] | Float32Array,
|
||||
constraints?: PeriodicWaveConstraints | undefined,
|
||||
constraints?: PeriodicWaveConstraints | undefined
|
||||
): PeriodicWave {
|
||||
return this._context.createPeriodicWave(real, imag, constraints);
|
||||
}
|
||||
|
@ -211,17 +231,28 @@ export class Context extends BaseContext {
|
|||
return this._context.createWaveShaper();
|
||||
}
|
||||
createMediaStreamSource(stream: MediaStream): MediaStreamAudioSourceNode {
|
||||
assert(isAudioContext(this._context), "Not available if OfflineAudioContext");
|
||||
assert(
|
||||
isAudioContext(this._context),
|
||||
"Not available if OfflineAudioContext"
|
||||
);
|
||||
const context = this._context as AudioContext;
|
||||
return context.createMediaStreamSource(stream);
|
||||
}
|
||||
createMediaElementSource(element: HTMLMediaElement): MediaElementAudioSourceNode {
|
||||
assert(isAudioContext(this._context), "Not available if OfflineAudioContext");
|
||||
createMediaElementSource(
|
||||
element: HTMLMediaElement
|
||||
): MediaElementAudioSourceNode {
|
||||
assert(
|
||||
isAudioContext(this._context),
|
||||
"Not available if OfflineAudioContext"
|
||||
);
|
||||
const context = this._context as AudioContext;
|
||||
return context.createMediaElementSource(element);
|
||||
}
|
||||
createMediaStreamDestination(): MediaStreamAudioDestinationNode {
|
||||
assert(isAudioContext(this._context), "Not available if OfflineAudioContext");
|
||||
assert(
|
||||
isAudioContext(this._context),
|
||||
"Not available if OfflineAudioContext"
|
||||
);
|
||||
const context = this._context as AudioContext;
|
||||
return context.createMediaStreamDestination();
|
||||
}
|
||||
|
@ -256,7 +287,10 @@ export class Context extends BaseContext {
|
|||
return this._listener;
|
||||
}
|
||||
set listener(l) {
|
||||
assert(!this._initialized, "The listener cannot be set after initialization.");
|
||||
assert(
|
||||
!this._initialized,
|
||||
"The listener cannot be set after initialization."
|
||||
);
|
||||
this._listener = l;
|
||||
}
|
||||
|
||||
|
@ -268,7 +302,10 @@ export class Context extends BaseContext {
|
|||
return this._transport;
|
||||
}
|
||||
set transport(t: Transport) {
|
||||
assert(!this._initialized, "The transport cannot be set after initialization.");
|
||||
assert(
|
||||
!this._initialized,
|
||||
"The transport cannot be set after initialization."
|
||||
);
|
||||
this._transport = t;
|
||||
}
|
||||
|
||||
|
@ -292,7 +329,10 @@ export class Context extends BaseContext {
|
|||
return this._destination;
|
||||
}
|
||||
set destination(d: Destination) {
|
||||
assert(!this._initialized, "The destination cannot be set after initialization.");
|
||||
assert(
|
||||
!this._initialized,
|
||||
"The destination cannot be set after initialization."
|
||||
);
|
||||
this._destination = d;
|
||||
}
|
||||
|
||||
|
@ -303,11 +343,11 @@ export class Context extends BaseContext {
|
|||
/**
|
||||
* Maps a module name to promise of the addModule method
|
||||
*/
|
||||
private _workletModules: Map<string, Promise<void>> = new Map()
|
||||
private _workletModules: Map<string, Promise<void>> = new Map();
|
||||
|
||||
/**
|
||||
* Create an audio worklet node from a name and options. The module
|
||||
* must first be loaded using [[addAudioWorkletModule]].
|
||||
* must first be loaded using [[addAudioWorkletModule]].
|
||||
*/
|
||||
createAudioWorkletNode(
|
||||
name: string,
|
||||
|
@ -322,9 +362,15 @@ export class Context extends BaseContext {
|
|||
* @param name The name of the module
|
||||
*/
|
||||
async addAudioWorkletModule(url: string, name: string): Promise<void> {
|
||||
assert(isDefined(this.rawContext.audioWorklet), "AudioWorkletNode is only available in a secure context (https or localhost)");
|
||||
assert(
|
||||
isDefined(this.rawContext.audioWorklet),
|
||||
"AudioWorkletNode is only available in a secure context (https or localhost)"
|
||||
);
|
||||
if (!this._workletModules.has(name)) {
|
||||
this._workletModules.set(name, this.rawContext.audioWorklet.addModule(url));
|
||||
this._workletModules.set(
|
||||
name,
|
||||
this.rawContext.audioWorklet.addModule(url)
|
||||
);
|
||||
}
|
||||
await this._workletModules.get(name);
|
||||
}
|
||||
|
@ -334,7 +380,7 @@ export class Context extends BaseContext {
|
|||
*/
|
||||
protected async workletsAreReady(): Promise<void> {
|
||||
const promises: Promise<void>[] = [];
|
||||
this._workletModules.forEach(promise => promises.push(promise));
|
||||
this._workletModules.forEach((promise) => promises.push(promise));
|
||||
await Promise.all(promises);
|
||||
}
|
||||
|
||||
|
@ -423,7 +469,7 @@ export class Context extends BaseContext {
|
|||
}
|
||||
|
||||
/**
|
||||
* The current audio context time without the [[lookAhead]].
|
||||
* The current audio context time without the [[lookAhead]].
|
||||
* In most cases it is better to use [[now]] instead of [[immediate]] since
|
||||
* with [[now]] the [[lookAhead]] is applied equally to _all_ components including internal components,
|
||||
* to making sure that everything is scheduled in sync. Mixing [[now]] and [[immediate]]
|
||||
|
@ -447,7 +493,7 @@ export class Context extends BaseContext {
|
|||
|
||||
/**
|
||||
* Close the context. Once closed, the context can no longer be used and
|
||||
* any AudioNodes created from the context will be silent.
|
||||
* any AudioNodes created from the context will be silent.
|
||||
*/
|
||||
async close(): Promise<void> {
|
||||
if (isAudioContext(this._context)) {
|
||||
|
@ -459,13 +505,17 @@ export class Context extends BaseContext {
|
|||
}
|
||||
|
||||
/**
|
||||
* **Internal** Generate a looped buffer at some constant value.
|
||||
* **Internal** Generate a looped buffer at some constant value.
|
||||
*/
|
||||
getConstant(val: number): AudioBufferSourceNode {
|
||||
if (this._constants.has(val)) {
|
||||
return this._constants.get(val) as AudioBufferSourceNode;
|
||||
} else {
|
||||
const buffer = this._context.createBuffer(1, 128, this._context.sampleRate);
|
||||
const buffer = this._context.createBuffer(
|
||||
1,
|
||||
128,
|
||||
this._context.sampleRate
|
||||
);
|
||||
const arr = buffer.getChannelData(0);
|
||||
for (let i = 0; i < arr.length; i++) {
|
||||
arr[i] = val;
|
||||
|
@ -488,7 +538,9 @@ export class Context extends BaseContext {
|
|||
super.dispose();
|
||||
this._ticker.dispose();
|
||||
this._timeouts.dispose();
|
||||
Object.keys(this._constants).map(val => this._constants[val].disconnect());
|
||||
Object.keys(this._constants).map((val) =>
|
||||
this._constants[val].disconnect()
|
||||
);
|
||||
return this;
|
||||
}
|
||||
|
||||
|
@ -536,7 +588,7 @@ export class Context extends BaseContext {
|
|||
* @param id The ID returned from setTimeout
|
||||
*/
|
||||
clearTimeout(id: number): this {
|
||||
this._timeouts.forEach(event => {
|
||||
this._timeouts.forEach((event) => {
|
||||
if (event.id === id) {
|
||||
this._timeouts.remove(event);
|
||||
}
|
||||
|
@ -573,4 +625,13 @@ export class Context extends BaseContext {
|
|||
intervalFn();
|
||||
return id;
|
||||
}
|
||||
|
||||
/*
|
||||
* This is a placeholder so that JSON.stringify does not throw an error
|
||||
* This matches what JSON.stringify(audioContext) returns on a native
|
||||
* audioContext instance.
|
||||
*/
|
||||
toJSON() {
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,7 +8,6 @@ type Transport = import("../clock/Transport").Transport;
|
|||
type Listener = import("./Listener").Listener;
|
||||
|
||||
export class DummyContext extends BaseContext {
|
||||
|
||||
//---------------------------
|
||||
// BASE AUDIO CONTEXT METHODS
|
||||
//---------------------------
|
||||
|
@ -28,15 +27,23 @@ export class DummyContext extends BaseContext {
|
|||
return {} as BiquadFilterNode;
|
||||
}
|
||||
|
||||
createBuffer(_numberOfChannels: number, _length: number, _sampleRate: number): AudioBuffer {
|
||||
createBuffer(
|
||||
_numberOfChannels: number,
|
||||
_length: number,
|
||||
_sampleRate: number
|
||||
): AudioBuffer {
|
||||
return {} as AudioBuffer;
|
||||
}
|
||||
|
||||
createChannelMerger(_numberOfInputs?: number | undefined): ChannelMergerNode {
|
||||
createChannelMerger(
|
||||
_numberOfInputs?: number | undefined
|
||||
): ChannelMergerNode {
|
||||
return {} as ChannelMergerNode;
|
||||
}
|
||||
|
||||
createChannelSplitter(_numberOfOutputs?: number | undefined): ChannelSplitterNode {
|
||||
createChannelSplitter(
|
||||
_numberOfOutputs?: number | undefined
|
||||
): ChannelSplitterNode {
|
||||
return {} as ChannelSplitterNode;
|
||||
}
|
||||
|
||||
|
@ -60,7 +67,10 @@ export class DummyContext extends BaseContext {
|
|||
return {} as GainNode;
|
||||
}
|
||||
|
||||
createIIRFilter(_feedForward: number[] | Float32Array, _feedback: number[] | Float32Array): IIRFilterNode {
|
||||
createIIRFilter(
|
||||
_feedForward: number[] | Float32Array,
|
||||
_feedback: number[] | Float32Array
|
||||
): IIRFilterNode {
|
||||
return {} as IIRFilterNode;
|
||||
}
|
||||
|
||||
|
@ -71,7 +81,7 @@ export class DummyContext extends BaseContext {
|
|||
createPeriodicWave(
|
||||
_real: number[] | Float32Array,
|
||||
_imag: number[] | Float32Array,
|
||||
_constraints?: PeriodicWaveConstraints | undefined,
|
||||
_constraints?: PeriodicWaveConstraints | undefined
|
||||
): PeriodicWave {
|
||||
return {} as PeriodicWave;
|
||||
}
|
||||
|
@ -88,10 +98,12 @@ export class DummyContext extends BaseContext {
|
|||
return {} as MediaStreamAudioSourceNode;
|
||||
}
|
||||
|
||||
createMediaElementSource(_element: HTMLMediaElement): MediaElementAudioSourceNode {
|
||||
createMediaElementSource(
|
||||
_element: HTMLMediaElement
|
||||
): MediaElementAudioSourceNode {
|
||||
return {} as MediaElementAudioSourceNode;
|
||||
}
|
||||
|
||||
|
||||
createMediaStreamDestination(): MediaStreamAudioDestinationNode {
|
||||
return {} as MediaStreamAudioDestinationNode;
|
||||
}
|
||||
|
@ -170,12 +182,12 @@ export class DummyContext extends BaseContext {
|
|||
get draw(): Draw {
|
||||
return {} as Draw;
|
||||
}
|
||||
set draw(_d) { }
|
||||
set draw(_d) {}
|
||||
|
||||
get destination(): Destination {
|
||||
return {} as Destination;
|
||||
}
|
||||
set destination(_d: Destination) { }
|
||||
set destination(_d: Destination) {}
|
||||
|
||||
now() {
|
||||
return 0;
|
||||
|
@ -185,5 +197,9 @@ export class DummyContext extends BaseContext {
|
|||
return 0;
|
||||
}
|
||||
|
||||
toJSON() {
|
||||
return {};
|
||||
}
|
||||
|
||||
readonly isOffline: boolean = false;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue