tone 15.1.22 → 15.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/Tone/core/context/Context.ts +9 -7
- package/Tone/core/worklet/ToneAudioWorklet.ts +11 -1
- package/Tone/signal/ToneConstantSource.test.ts +63 -2
- package/Tone/signal/ToneConstantSource.ts +37 -6
- package/Tone/version.ts +1 -1
- package/build/Tone.js +1 -1
- package/build/Tone.js.map +1 -1
- package/build/esm/core/context/Context.d.ts +2 -2
- package/build/esm/core/context/Context.js +7 -7
- package/build/esm/core/context/Context.js.map +1 -1
- package/build/esm/core/worklet/ToneAudioWorklet.d.ts +1 -0
- package/build/esm/core/worklet/ToneAudioWorklet.js +7 -1
- package/build/esm/core/worklet/ToneAudioWorklet.js.map +1 -1
- package/build/esm/signal/ToneConstantSource.d.ts +5 -1
- package/build/esm/signal/ToneConstantSource.js +36 -7
- package/build/esm/signal/ToneConstantSource.js.map +1 -1
- package/build/esm/version.js +1 -1
- package/build/esm/version.js.map +1 -1
- package/package.json +1 -1
|
@@ -346,9 +346,9 @@ export class Context extends BaseContext {
|
|
|
346
346
|
//--------------------------------------------
|
|
347
347
|
|
|
348
348
|
/**
|
|
349
|
-
*
|
|
349
|
+
* A set of unsettled promises returned by the addModule method
|
|
350
350
|
*/
|
|
351
|
-
private
|
|
351
|
+
private _workletPromises = new Set<Promise<void>>();
|
|
352
352
|
|
|
353
353
|
/**
|
|
354
354
|
* Create an audio worklet node from a name and options. The module
|
|
@@ -370,17 +370,19 @@ export class Context extends BaseContext {
|
|
|
370
370
|
isDefined(this.rawContext.audioWorklet),
|
|
371
371
|
"AudioWorkletNode is only available in a secure context (https or localhost)"
|
|
372
372
|
);
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
373
|
+
const workletPromise = this.rawContext.audioWorklet.addModule(url);
|
|
374
|
+
|
|
375
|
+
this._workletPromises.add(workletPromise);
|
|
376
|
+
workletPromise.finally(() => this._workletPromises.delete(workletPromise));
|
|
377
|
+
|
|
378
|
+
return workletPromise;
|
|
377
379
|
}
|
|
378
380
|
|
|
379
381
|
/**
|
|
380
382
|
* Returns a promise which resolves when all of the worklets have been loaded on this context
|
|
381
383
|
*/
|
|
382
384
|
protected async workletsAreReady(): Promise<void> {
|
|
383
|
-
|
|
385
|
+
await Promise.all(this._workletPromises);
|
|
384
386
|
}
|
|
385
387
|
|
|
386
388
|
//---------------------------
|
|
@@ -59,7 +59,15 @@ export abstract class ToneAudioWorklet<
|
|
|
59
59
|
this._dummyParam = this._dummyGain.gain;
|
|
60
60
|
|
|
61
61
|
// Register the processor
|
|
62
|
-
|
|
62
|
+
let workletPromise = ToneAudioWorklet._workletPromises.get(this.context);
|
|
63
|
+
|
|
64
|
+
if (workletPromise === undefined) {
|
|
65
|
+
workletPromise = this.context.addAudioWorkletModule(blobUrl);
|
|
66
|
+
|
|
67
|
+
ToneAudioWorklet._workletPromises.set(this.context, workletPromise);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
workletPromise.then(() => {
|
|
63
71
|
// create the worklet when it's read
|
|
64
72
|
if (!this.disposed) {
|
|
65
73
|
this._worklet = this.context.createAudioWorkletNode(
|
|
@@ -73,6 +81,8 @@ export abstract class ToneAudioWorklet<
|
|
|
73
81
|
});
|
|
74
82
|
}
|
|
75
83
|
|
|
84
|
+
private static _workletPromises = new WeakMap<any, Promise<void>>();
|
|
85
|
+
|
|
76
86
|
dispose(): this {
|
|
77
87
|
super.dispose();
|
|
78
88
|
this._dummyGain.disconnect();
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { expect } from "chai";
|
|
2
2
|
import { BasicTests } from "../../test/helper/Basic.js";
|
|
3
|
-
import { CompareToFile } from "../../test/helper/CompareToFile.js";
|
|
4
3
|
import { Offline, whenBetween } from "../../test/helper/Offline.js";
|
|
5
4
|
import { ToneConstantSource } from "./ToneConstantSource.js";
|
|
5
|
+
import { Context } from "../core/context/Context.js";
|
|
6
6
|
|
|
7
7
|
describe("ToneConstantSource", () => {
|
|
8
8
|
BasicTests(ToneConstantSource);
|
|
@@ -36,7 +36,7 @@ describe("ToneConstantSource", () => {
|
|
|
36
36
|
source.stop("+0.3");
|
|
37
37
|
const now = source.now();
|
|
38
38
|
source.onended = () => {
|
|
39
|
-
expect(source.now() - now).to.be.
|
|
39
|
+
expect(source.now() - now).to.be.closeTo(0.3, 0.15);
|
|
40
40
|
source.dispose();
|
|
41
41
|
done();
|
|
42
42
|
};
|
|
@@ -186,4 +186,65 @@ describe("ToneConstantSource", () => {
|
|
|
186
186
|
}, 0.2);
|
|
187
187
|
});
|
|
188
188
|
});
|
|
189
|
+
|
|
190
|
+
context.only("Suspended AudioContext", () => {
|
|
191
|
+
it("does nothing when AudioContext returns to suspended", () => {
|
|
192
|
+
const context = new Context();
|
|
193
|
+
expect(context.state).to.equal("suspended");
|
|
194
|
+
|
|
195
|
+
const source = new ToneConstantSource({
|
|
196
|
+
context,
|
|
197
|
+
});
|
|
198
|
+
|
|
199
|
+
source.start(0);
|
|
200
|
+
|
|
201
|
+
context.dispose();
|
|
202
|
+
source.dispose();
|
|
203
|
+
});
|
|
204
|
+
|
|
205
|
+
it("starts when the audio context is resumed", async () => {
|
|
206
|
+
const context = new Context();
|
|
207
|
+
expect(context.state).to.equal("suspended");
|
|
208
|
+
|
|
209
|
+
const source = new ToneConstantSource({
|
|
210
|
+
context,
|
|
211
|
+
});
|
|
212
|
+
|
|
213
|
+
source.start(0);
|
|
214
|
+
|
|
215
|
+
await context.resume();
|
|
216
|
+
|
|
217
|
+
context.dispose();
|
|
218
|
+
source.dispose();
|
|
219
|
+
});
|
|
220
|
+
|
|
221
|
+
it("context can be suspended again", async () => {
|
|
222
|
+
const context = new Context();
|
|
223
|
+
expect(context.state).to.equal("suspended");
|
|
224
|
+
|
|
225
|
+
const source = new ToneConstantSource({
|
|
226
|
+
context,
|
|
227
|
+
});
|
|
228
|
+
|
|
229
|
+
source.start(0);
|
|
230
|
+
|
|
231
|
+
await context.resume();
|
|
232
|
+
|
|
233
|
+
source.stop(0.1);
|
|
234
|
+
|
|
235
|
+
await context.rawContext.suspend(0);
|
|
236
|
+
|
|
237
|
+
// wait for the context to be suspended
|
|
238
|
+
await new Promise<void>((resolve) =>
|
|
239
|
+
context.on("statechange", () => {
|
|
240
|
+
if (context.state === "suspended") {
|
|
241
|
+
resolve();
|
|
242
|
+
}
|
|
243
|
+
})
|
|
244
|
+
);
|
|
245
|
+
|
|
246
|
+
context.dispose();
|
|
247
|
+
source.dispose();
|
|
248
|
+
});
|
|
249
|
+
});
|
|
189
250
|
});
|
|
@@ -29,7 +29,7 @@ export class ToneConstantSource<
|
|
|
29
29
|
/**
|
|
30
30
|
* The signal generator
|
|
31
31
|
*/
|
|
32
|
-
private _source
|
|
32
|
+
private _source?: ConstantSourceNode;
|
|
33
33
|
|
|
34
34
|
/**
|
|
35
35
|
* The offset of the signal generator
|
|
@@ -49,12 +49,24 @@ export class ToneConstantSource<
|
|
|
49
49
|
);
|
|
50
50
|
super(options);
|
|
51
51
|
|
|
52
|
-
|
|
52
|
+
const isSuspended =
|
|
53
|
+
!this.context.isOffline && this.context.state !== "running";
|
|
54
|
+
|
|
55
|
+
if (!isSuspended) {
|
|
56
|
+
this._source = this.context.createConstantSource();
|
|
57
|
+
connect(this._source, this._gainNode);
|
|
58
|
+
} else {
|
|
59
|
+
this.context.on("statechange", this._contextStarted);
|
|
60
|
+
}
|
|
53
61
|
|
|
54
62
|
this.offset = new Param({
|
|
55
63
|
context: this.context,
|
|
56
64
|
convert: options.convert,
|
|
57
|
-
param:
|
|
65
|
+
param: isSuspended
|
|
66
|
+
? // placeholder param until the context is started
|
|
67
|
+
this.context.createGain().gain
|
|
68
|
+
: this._source?.offset,
|
|
69
|
+
swappable: isSuspended,
|
|
58
70
|
units: options.units,
|
|
59
71
|
value: options.offset,
|
|
60
72
|
minValue: options.minValue,
|
|
@@ -70,6 +82,21 @@ export class ToneConstantSource<
|
|
|
70
82
|
});
|
|
71
83
|
}
|
|
72
84
|
|
|
85
|
+
/**
|
|
86
|
+
* Once the context is started, kick off source.
|
|
87
|
+
*/
|
|
88
|
+
private readonly _contextStarted = (state: AudioContextState) => {
|
|
89
|
+
if (state !== "running") {
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
92
|
+
this._source = this.context.createConstantSource();
|
|
93
|
+
connect(this._source, this._gainNode);
|
|
94
|
+
this.offset.setParam(this._source.offset);
|
|
95
|
+
if (this.state === "started") {
|
|
96
|
+
this._source.start(0);
|
|
97
|
+
}
|
|
98
|
+
};
|
|
99
|
+
|
|
73
100
|
/**
|
|
74
101
|
* Start the source node at the given time
|
|
75
102
|
* @param time When to start the source
|
|
@@ -78,12 +105,15 @@ export class ToneConstantSource<
|
|
|
78
105
|
const computedTime = this.toSeconds(time);
|
|
79
106
|
this.log("start", computedTime);
|
|
80
107
|
this._startGain(computedTime);
|
|
81
|
-
this._source
|
|
108
|
+
this._source?.start(computedTime);
|
|
82
109
|
return this;
|
|
83
110
|
}
|
|
84
111
|
|
|
85
112
|
protected _stopSource(time?: Seconds): void {
|
|
86
|
-
this.
|
|
113
|
+
if (this.state === "stopped") {
|
|
114
|
+
return;
|
|
115
|
+
}
|
|
116
|
+
this._source?.stop(time);
|
|
87
117
|
}
|
|
88
118
|
|
|
89
119
|
dispose(): this {
|
|
@@ -91,8 +121,9 @@ export class ToneConstantSource<
|
|
|
91
121
|
if (this.state === "started") {
|
|
92
122
|
this.stop();
|
|
93
123
|
}
|
|
94
|
-
this._source
|
|
124
|
+
this._source?.disconnect();
|
|
95
125
|
this.offset.dispose();
|
|
126
|
+
this.context.off("statechange", this._contextStarted);
|
|
96
127
|
return this;
|
|
97
128
|
}
|
|
98
129
|
}
|
package/Tone/version.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export const version: string = "15.
|
|
1
|
+
export const version: string = "15.2.0";
|