Skip to content

Commit

Permalink
feat: latencyHint is now set in constructor
Browse files Browse the repository at this point in the history
BREAK: the latencyHint can only be set in the constructor, no longer settable after construction

addresses #658
  • Loading branch information
tambien committed May 12, 2020
1 parent 368a7f4 commit ba8e82b
Show file tree
Hide file tree
Showing 6 changed files with 30 additions and 87 deletions.
4 changes: 2 additions & 2 deletions Tone/core/context/AudioContext.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

/**
Expand Down
2 changes: 1 addition & 1 deletion Tone/core/context/BaseContext.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 {

Expand Down
77 changes: 7 additions & 70 deletions Tone/core/context/Context.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand All @@ -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();
});
});

Expand Down Expand Up @@ -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;
Expand All @@ -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);
Expand Down
30 changes: 18 additions & 12 deletions Tone/core/context/Context.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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));
Expand All @@ -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 {
Expand Down Expand Up @@ -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)) {
Expand All @@ -390,22 +399,19 @@ 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;
this.updateInterval = lookAheadValue / 2;
}

/**
* The unwrapped AudioContext.
* The unwrapped AudioContext or OfflineAudioContext
*/
get rawContext(): AnyAudioContext {
return this._context;
Expand Down
2 changes: 1 addition & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -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",
Expand Down

0 comments on commit ba8e82b

Please sign in to comment.