diff --git a/Tone/core/context/AudioContext.ts b/Tone/core/context/AudioContext.ts index 0f6dfb6c..7fdc1f0b 100644 --- a/Tone/core/context/AudioContext.ts +++ b/Tone/core/context/AudioContext.ts @@ -9,8 +9,8 @@ import { isDefined } from "../util/TypeCheck"; /** * Create a new AudioContext */ -export function createAudioContext(): AudioContext { - return new stdAudioContext() as unknown as AudioContext; +export function createAudioContext(options?: AudioContextOptions): AudioContext { + return new stdAudioContext(options) as unknown as AudioContext; } /** diff --git a/Tone/core/context/BaseContext.ts b/Tone/core/context/BaseContext.ts index f78be457..d178827a 100644 --- a/Tone/core/context/BaseContext.ts +++ b/Tone/core/context/BaseContext.ts @@ -8,7 +8,7 @@ type Transport = import("../clock/Transport").Transport; type Listener = import("./Listener").Listener; type BaseAudioContextSubset = import("./Context").BaseAudioContextSubset; -export type ContextLatencyHint = AudioContextLatencyCategory | "fastest"; +export type ContextLatencyHint = AudioContextLatencyCategory; export abstract class BaseContext extends Emitter<"statechange" | "tick"> implements BaseAudioContextSubset { diff --git a/Tone/core/context/Context.test.ts b/Tone/core/context/Context.test.ts index 8bbc30df..973f7156 100644 --- a/Tone/core/context/Context.test.ts +++ b/Tone/core/context/Context.test.ts @@ -43,6 +43,7 @@ describe("Context", () => { expect(ctx.createDelay()).to.be.have.property("delayTime"); expect(ctx).to.have.property("createConstantSource"); ctx.dispose(); + return ctx.close(); }); if (ONLINE_TESTING) { @@ -61,25 +62,28 @@ describe("Context", () => { expect(ctx.rawContext).has.property("destination"); expect(ctx.rawContext).has.property("sampleRate"); ctx.dispose(); + return ctx.close(); }); it("can be constructed with an options object", () => { const ctx = new Context({ clockSource: "timeout", - latencyHint: "fastest", + latencyHint: "playback", lookAhead: 0.2, }); expect(ctx.lookAhead).to.equal(0.2); - expect(ctx.latencyHint).to.equal("fastest"); + expect(ctx.latencyHint).to.equal("playback"); expect(ctx.clockSource).to.equal("timeout"); ctx.dispose(); + return ctx.close(); }); - + it("returns 'now' and 'immediate' time", () => { const ctx = new Context(); expect(ctx.now()).to.be.a("number"); expect(ctx.immediate()).to.be.a("number"); ctx.dispose(); + return ctx.close(); }); }); @@ -296,60 +300,6 @@ describe("Context", () => { }); }); - // context("Tone", () => { - - // it("has a context", () => { - // expect(Tone.context).to.exist; - // expect(Tone.context).to.be.instanceOf(Context); - // }); - - // it("can set a new context", () => { - // const originalContext = Tone.context; - // Tone.context = new Context(); - // return Tone.context.dispose().then(() => { - // Tone.context = originalContext; - // }); - // }); - - // it("has a consistent context after offline rendering", () => { - // const initialContext = Tone.context; - // const initialTransport = Tone.Transport; - // return Offline(() => { }).then(() => { - // expect(Tone.context).to.equal(initialContext); - // expect(Tone.Transport).to.equal(initialTransport); - // }); - // }); - - // it("invokes the resume promise", () => { - // return Tone.context.resume(); - // }); - - // it("invokes init when a new context is set", done => { - // this.timeout(200); - // const initFn = function(context) { - // expect(Tone.context).to.equal(context); - // Context.off("init", initFn); - // done(); - // }; - // Context.on("init", initFn); - // Tone.context = new Context(); - // }); - - // it("invokes close when a context is disposed", done => { - // this.timeout(200); - // const closeFn = function(context) { - // expect(context).to.be.instanceOf(Context); - // Context.off("close", closeFn); - // // set a new context - // Tone.context = new Context(); - // done(); - // }; - // Context.on("close", closeFn); - // Tone.context.dispose(); - // }); - - // }); - context("get/set", () => { let ctx; @@ -373,19 +323,6 @@ describe("Context", () => { expect(ctx.updateInterval).to.equal(0.05); }); - it("can set the latencyHint", () => { - ctx.latencyHint = "fastest"; - expect(ctx.latencyHint).to.equal("fastest"); - expect(ctx.lookAhead).to.be.closeTo(0.01, 0.05); - expect(ctx.updateInterval).to.be.closeTo(0.01, 0.05); - // test all other latency hints - const latencyHints = ["interactive", "playback", "balanced", 0.2]; - latencyHints.forEach(hint => { - ctx.latencyHint = hint; - expect(ctx.latencyHint).to.equal(hint); - }); - }); - it("gets a constant signal", () => { return ConstantOutput(context => { const bufferSrc = context.getConstant(1); diff --git a/Tone/core/context/Context.ts b/Tone/core/context/Context.ts index 41f206f4..1446bfa7 100644 --- a/Tone/core/context/Context.ts +++ b/Tone/core/context/Context.ts @@ -65,7 +65,7 @@ export class Context extends BaseContext { /** * The default latency hint */ - private _latencyHint: ContextLatencyHint | Seconds; + private _latencyHint!: ContextLatencyHint | Seconds; /** * An object containing all of the constants AudioBufferSourceNodes @@ -121,10 +121,10 @@ export class Context extends BaseContext { if (options.context) { this._context = options.context; } else { - this._context = createAudioContext(); + this._context = createAudioContext({ + latencyHint: options.latencyHint, + }); } - this._latencyHint = options.latencyHint; - this.lookAhead = options.lookAhead; this._ticker = new Ticker(this.emit.bind(this, "tick"), options.clockSource, options.updateInterval); this.on("tick", this._timeoutLoop.bind(this)); @@ -133,6 +133,9 @@ export class Context extends BaseContext { this._context.onstatechange = () => { this.emit("statechange", this.state); }; + + this._setLatencyHint(options.latencyHint); + this.lookAhead = options.lookAhead; } static getDefaults(): ContextOptions { @@ -375,13 +378,19 @@ export class Context extends BaseContext { * "playback" (prioritizes sustained playback), "balanced" (balances * latency and performance), and "fastest" (lowest latency, might glitch more often). * @example - * // set the latencyHint to prioritize smooth playback at the expensive of latency - * Tone.context.latencyHint = "playback"; + * // prioritize sustained playback + * const context = new Tone.Context({ latencyHint: "playback" }); + * // set this context as the global Context + * Tone.setContext(context); */ get latencyHint(): ContextLatencyHint | Seconds { return this._latencyHint; } - set latencyHint(hint: ContextLatencyHint | Seconds) { + + /** + * Update the lookAhead and updateInterval based on the latencyHint + */ + private _setLatencyHint(hint: ContextLatencyHint | Seconds): void { let lookAheadValue = 0; this._latencyHint = hint; if (isString(hint)) { @@ -390,14 +399,11 @@ export class Context extends BaseContext { lookAheadValue = 0.1; break; case "playback": - lookAheadValue = 0.8; + lookAheadValue = 0.5; break; case "balanced": lookAheadValue = 0.25; break; - case "fastest": - lookAheadValue = 0.01; - break; } } this.lookAhead = lookAheadValue; @@ -405,7 +411,7 @@ export class Context extends BaseContext { } /** - * The unwrapped AudioContext. + * The unwrapped AudioContext or OfflineAudioContext */ get rawContext(): AnyAudioContext { return this._context; diff --git a/package-lock.json b/package-lock.json index b579ec0e..a7b75b6b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "tone", - "version": "14.6.0", + "version": "14.7.0", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 2486181c..167e1ed4 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "tone", - "version": "14.6.0", + "version": "14.7.0", "description": "A Web Audio framework for making interactive music in the browser.", "main": "build/Tone.js", "module": "build/esm/index.js",