tone 15.5.47 → 15.5.49
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/clock/Clock.test.ts +29 -0
- package/Tone/core/clock/TickParam.ts +1 -1
- package/Tone/core/clock/TickSource.test.ts +13 -0
- package/Tone/core/clock/TickSource.ts +2 -3
- package/Tone/core/clock/Ticker.ts +1 -1
- package/Tone/core/context/Param.ts +1 -1
- package/Tone/core/context/ToneAudioBuffer.ts +5 -25
- package/Tone/core/util/StateTimeline.ts +1 -5
- package/Tone/core/util/Timeline.test.ts +56 -0
- package/Tone/core/util/Timeline.ts +22 -10
- package/Tone/core/util/TimelineValue.ts +1 -5
- package/Tone/core/worklet/SingleIOProcessor.worklet.ts +2 -2
- package/Tone/core/worklet/ToneAudioWorklet.ts +2 -4
- package/Tone/fromContext.ts +2 -2
- package/Tone/instrument/Sampler.ts +1 -1
- package/Tone/source/Noise.test.ts +6 -0
- package/Tone/source/Noise.ts +1 -3
- package/Tone/source/Source.test.ts +31 -0
- package/Tone/source/UserMedia.ts +4 -16
- package/Tone/source/buffer/Player.ts +1 -1
- package/Tone/version.ts +1 -1
- package/build/Tone.js +1 -1
- package/build/Tone.js.map +1 -1
- package/build/esm/core/clock/TickParam.js +1 -1
- package/build/esm/core/clock/TickParam.js.map +1 -1
- package/build/esm/core/clock/TickSource.js +2 -3
- package/build/esm/core/clock/TickSource.js.map +1 -1
- package/build/esm/core/clock/Ticker.js +2 -1
- package/build/esm/core/clock/Ticker.js.map +1 -1
- package/build/esm/core/context/Param.js +1 -1
- package/build/esm/core/context/Param.js.map +1 -1
- package/build/esm/core/context/ToneAudioBuffer.js +10 -30
- package/build/esm/core/context/ToneAudioBuffer.js.map +1 -1
- package/build/esm/core/util/StateTimeline.js +2 -6
- package/build/esm/core/util/StateTimeline.js.map +1 -1
- package/build/esm/core/util/Timeline.js +19 -10
- package/build/esm/core/util/Timeline.js.map +1 -1
- package/build/esm/core/util/TimelineValue.js +2 -6
- package/build/esm/core/util/TimelineValue.js.map +1 -1
- package/build/esm/core/worklet/SingleIOProcessor.worklet.d.ts +1 -1
- package/build/esm/core/worklet/SingleIOProcessor.worklet.js +2 -2
- package/build/esm/core/worklet/ToneAudioWorklet.js +3 -4
- package/build/esm/core/worklet/ToneAudioWorklet.js.map +1 -1
- package/build/esm/fromContext.js +2 -2
- package/build/esm/fromContext.js.map +1 -1
- package/build/esm/instrument/Sampler.js +2 -1
- package/build/esm/instrument/Sampler.js.map +1 -1
- package/build/esm/source/Noise.js +2 -3
- package/build/esm/source/Noise.js.map +1 -1
- package/build/esm/source/UserMedia.js +8 -19
- package/build/esm/source/UserMedia.js.map +1 -1
- package/build/esm/source/buffer/Player.js +1 -1
- package/build/esm/source/buffer/Player.js.map +1 -1
- package/build/esm/version.js +1 -1
- package/package.json +1 -1
|
@@ -413,6 +413,35 @@ describe("Clock", () => {
|
|
|
413
413
|
// the post-restart ticks from offset 40
|
|
414
414
|
expect(observedTicks).to.deep.equal([0, 1, 2, 40, 41]);
|
|
415
415
|
});
|
|
416
|
+
|
|
417
|
+
it("emits the stop event when stop and the following start happen at the same time within the stale window", async () => {
|
|
418
|
+
const events: Array<[string, number]> = [];
|
|
419
|
+
let restartTime = 0;
|
|
420
|
+
await Offline(() => {
|
|
421
|
+
const clock = new Clock(noOp, 200);
|
|
422
|
+
const boundLoop = (
|
|
423
|
+
clock as unknown as { _boundLoop: () => void }
|
|
424
|
+
)._boundLoop;
|
|
425
|
+
clock.on("stop", (time) => events.push(["stop", time]));
|
|
426
|
+
clock.on("start", (time) => events.push(["start", time]));
|
|
427
|
+
clock.start(0);
|
|
428
|
+
// Same staleness simulation as above. stop() and start() are
|
|
429
|
+
// scheduled at the same instant, as happens when both default
|
|
430
|
+
// to now() within one task: `transport.stop(); transport.start()`
|
|
431
|
+
clock.context.off("tick", boundLoop);
|
|
432
|
+
return atTime(0.02, (time) => {
|
|
433
|
+
restartTime = time;
|
|
434
|
+
clock.stop(time);
|
|
435
|
+
clock.start(time, 40);
|
|
436
|
+
clock.context.on("tick", boundLoop);
|
|
437
|
+
});
|
|
438
|
+
}, 0.03);
|
|
439
|
+
expect(events).to.deep.equal([
|
|
440
|
+
["start", 0],
|
|
441
|
+
["stop", restartTime],
|
|
442
|
+
["start", restartTime],
|
|
443
|
+
]);
|
|
444
|
+
});
|
|
416
445
|
});
|
|
417
446
|
|
|
418
447
|
context("Events", () => {
|
|
@@ -217,7 +217,7 @@ export class TickParam<
|
|
|
217
217
|
getTimeOfTick(tick: Ticks): Seconds {
|
|
218
218
|
const before = this._events.get(tick, "ticks");
|
|
219
219
|
const after = this._events.getAfter(tick, "ticks");
|
|
220
|
-
if (before
|
|
220
|
+
if (before?.ticks === tick) {
|
|
221
221
|
return before.time;
|
|
222
222
|
} else if (
|
|
223
223
|
before &&
|
|
@@ -76,6 +76,19 @@ describe("TickSource", () => {
|
|
|
76
76
|
}, 0.5);
|
|
77
77
|
});
|
|
78
78
|
|
|
79
|
+
it("reports the restart offset just after a stop and start at the same time", () => {
|
|
80
|
+
const source = new TickSource(3);
|
|
81
|
+
source.start(0);
|
|
82
|
+
source.stop(1);
|
|
83
|
+
source.start(1, 10);
|
|
84
|
+
expect(source.getTicksAtTime(1)).to.be.closeTo(10, 0.01);
|
|
85
|
+
// the first tick time of the restarted period is computed from the
|
|
86
|
+
// frequency integral and can land a rounding error after the start
|
|
87
|
+
expect(source.getTicksAtTime(1 + 1e-12)).to.be.closeTo(10, 0.01);
|
|
88
|
+
expect(source.getTicksAtTime(1.5)).to.be.closeTo(11.5, 0.01);
|
|
89
|
+
source.dispose();
|
|
90
|
+
});
|
|
91
|
+
|
|
79
92
|
it("ticks restart at 0 when started after stop", () => {
|
|
80
93
|
const source = new TickSource(3);
|
|
81
94
|
source.start(0).stop(1).start(2);
|
|
@@ -398,8 +398,7 @@ export class TickSource<
|
|
|
398
398
|
let lastStateEvent = this._state.get(startTime);
|
|
399
399
|
this._state.forEachBetween(startTime, endTime, (event) => {
|
|
400
400
|
if (
|
|
401
|
-
lastStateEvent &&
|
|
402
|
-
lastStateEvent.state === "started" &&
|
|
401
|
+
lastStateEvent?.state === "started" &&
|
|
403
402
|
event.state !== "started"
|
|
404
403
|
) {
|
|
405
404
|
this.forEachTickBetween(
|
|
@@ -413,7 +412,7 @@ export class TickSource<
|
|
|
413
412
|
|
|
414
413
|
let error: Error | null = null;
|
|
415
414
|
|
|
416
|
-
if (lastStateEvent
|
|
415
|
+
if (lastStateEvent?.state === "started") {
|
|
417
416
|
const maxStartTime = Math.max(lastStateEvent.time, startTime);
|
|
418
417
|
// Figure out how far past the last whole-tick boundary maxStartTime
|
|
419
418
|
// sits, so we can compute the time of the next tick at or after it.
|
|
@@ -618,7 +618,7 @@ export class Param<TypeName extends UnitName = "number">
|
|
|
618
618
|
param.setValueAtTime(this.getValueAtTime(now) as number, now);
|
|
619
619
|
// if the previous event was a curve, then set the rest of it
|
|
620
620
|
const previousEvent = this._events.get(now);
|
|
621
|
-
if (previousEvent
|
|
621
|
+
if (previousEvent?.type === "setTargetAtTime") {
|
|
622
622
|
// approx it until the next event with linear ramps
|
|
623
623
|
const nextEvent = this._events.getAfter(previousEvent.time);
|
|
624
624
|
// or for 2 seconds if there is no event
|
|
@@ -87,11 +87,7 @@ export class ToneAudioBuffer extends Tone {
|
|
|
87
87
|
* The sample rate of the AudioBuffer
|
|
88
88
|
*/
|
|
89
89
|
get sampleRate(): number {
|
|
90
|
-
|
|
91
|
-
return this._buffer.sampleRate;
|
|
92
|
-
} else {
|
|
93
|
-
return getContext().sampleRate;
|
|
94
|
-
}
|
|
90
|
+
return this._buffer?.sampleRate ?? getContext().sampleRate;
|
|
95
91
|
}
|
|
96
92
|
|
|
97
93
|
/**
|
|
@@ -233,11 +229,7 @@ export class ToneAudioBuffer extends Tone {
|
|
|
233
229
|
* @return The audio as a TypedArray
|
|
234
230
|
*/
|
|
235
231
|
getChannelData(channel: number): Float32Array {
|
|
236
|
-
|
|
237
|
-
return this._buffer.getChannelData(channel);
|
|
238
|
-
} else {
|
|
239
|
-
return new Float32Array(0);
|
|
240
|
-
}
|
|
232
|
+
return this._buffer?.getChannelData(channel) ?? new Float32Array(0);
|
|
241
233
|
}
|
|
242
234
|
|
|
243
235
|
/**
|
|
@@ -292,33 +284,21 @@ export class ToneAudioBuffer extends Tone {
|
|
|
292
284
|
* The duration of the buffer in seconds.
|
|
293
285
|
*/
|
|
294
286
|
get duration(): Seconds {
|
|
295
|
-
|
|
296
|
-
return this._buffer.duration;
|
|
297
|
-
} else {
|
|
298
|
-
return 0;
|
|
299
|
-
}
|
|
287
|
+
return this._buffer?.duration ?? 0;
|
|
300
288
|
}
|
|
301
289
|
|
|
302
290
|
/**
|
|
303
291
|
* The length of the buffer in samples
|
|
304
292
|
*/
|
|
305
293
|
get length(): Samples {
|
|
306
|
-
|
|
307
|
-
return this._buffer.length;
|
|
308
|
-
} else {
|
|
309
|
-
return 0;
|
|
310
|
-
}
|
|
294
|
+
return this._buffer?.length ?? 0;
|
|
311
295
|
}
|
|
312
296
|
|
|
313
297
|
/**
|
|
314
298
|
* The number of discrete audio channels. Returns 0 if no buffer is loaded.
|
|
315
299
|
*/
|
|
316
300
|
get numberOfChannels(): number {
|
|
317
|
-
|
|
318
|
-
return this._buffer.numberOfChannels;
|
|
319
|
-
} else {
|
|
320
|
-
return 0;
|
|
321
|
-
}
|
|
301
|
+
return this._buffer?.numberOfChannels ?? 0;
|
|
322
302
|
}
|
|
323
303
|
|
|
324
304
|
/**
|
|
@@ -38,11 +38,7 @@ export class StateTimeline<
|
|
|
38
38
|
*/
|
|
39
39
|
getValueAtTime(time: Seconds): PlaybackState {
|
|
40
40
|
const event = this.get(time);
|
|
41
|
-
|
|
42
|
-
return event.state;
|
|
43
|
-
} else {
|
|
44
|
-
return this._initial;
|
|
45
|
-
}
|
|
41
|
+
return event?.state ?? this._initial;
|
|
46
42
|
}
|
|
47
43
|
|
|
48
44
|
/**
|
|
@@ -604,5 +604,61 @@ describe("Timeline", () => {
|
|
|
604
604
|
expect(count).to.equal(0);
|
|
605
605
|
sched.dispose();
|
|
606
606
|
});
|
|
607
|
+
|
|
608
|
+
it("includes every event at the start time and excludes every event at the end time", () => {
|
|
609
|
+
const sched = new Timeline<{ time: number; id: string }>();
|
|
610
|
+
sched.add({ time: 0.1, id: "a" });
|
|
611
|
+
sched.add({ time: 0.2, id: "b" });
|
|
612
|
+
sched.add({ time: 0.2, id: "c" });
|
|
613
|
+
sched.add({ time: 0.3, id: "d" });
|
|
614
|
+
sched.add({ time: 0.3, id: "e" });
|
|
615
|
+
const visited = (start: number, end: number): string[] => {
|
|
616
|
+
const ids: string[] = [];
|
|
617
|
+
sched.forEachBetween(start, end, (event) => ids.push(event.id));
|
|
618
|
+
return ids;
|
|
619
|
+
};
|
|
620
|
+
expect(visited(0.1, 0.2)).to.deep.equal(["a"]);
|
|
621
|
+
expect(visited(0.2, 0.3)).to.deep.equal(["b", "c"]);
|
|
622
|
+
expect(visited(0.3, 0.4)).to.deep.equal(["d", "e"]);
|
|
623
|
+
expect(visited(0.15, 0.25)).to.deep.equal(["b", "c"]);
|
|
624
|
+
sched.dispose();
|
|
625
|
+
});
|
|
626
|
+
|
|
627
|
+
it("visits an event added at the boundary after the previous range was iterated", () => {
|
|
628
|
+
// two consecutive ranges [0.1, 0.2) and [0.2, 0.4); an event at 0.2
|
|
629
|
+
// is added between the two iterations, after another event at 0.2
|
|
630
|
+
const sched = new Timeline<{ time: number; id: string }>();
|
|
631
|
+
sched.add({ time: 0.1, id: "a" });
|
|
632
|
+
sched.add({ time: 0.2, id: "b" });
|
|
633
|
+
const ids: string[] = [];
|
|
634
|
+
sched.forEachBetween(0.1, 0.2, (event) => ids.push(event.id));
|
|
635
|
+
sched.add({ time: 0.2, id: "c" });
|
|
636
|
+
sched.forEachBetween(0.2, 0.4, (event) => ids.push(event.id));
|
|
637
|
+
expect(ids).to.deep.equal(["a", "b", "c"]);
|
|
638
|
+
sched.dispose();
|
|
639
|
+
});
|
|
640
|
+
|
|
641
|
+
it("includes events within rounding error of the start time", () => {
|
|
642
|
+
// _search compares times with an epsilon; the range bounds must too
|
|
643
|
+
const sched = new Timeline<{ time: number; id: string }>();
|
|
644
|
+
sched.add({ time: 0.1, id: "a" });
|
|
645
|
+
sched.add({ time: 0.2, id: "b" });
|
|
646
|
+
sched.add({ time: 0.2 + 1e-12, id: "c" });
|
|
647
|
+
const ids: string[] = [];
|
|
648
|
+
sched.forEachBetween(0.2, 0.3, (event) => ids.push(event.id));
|
|
649
|
+
expect(ids).to.deep.equal(["b", "c"]);
|
|
650
|
+
sched.dispose();
|
|
651
|
+
});
|
|
652
|
+
|
|
653
|
+
it("excludes the end time when the start time is before the first event", () => {
|
|
654
|
+
const sched = new Timeline<{ time: number; id: string }>();
|
|
655
|
+
sched.add({ time: 0.1, id: "a" });
|
|
656
|
+
sched.add({ time: 0.2, id: "b" });
|
|
657
|
+
sched.add({ time: 0.2, id: "c" });
|
|
658
|
+
const ids: string[] = [];
|
|
659
|
+
sched.forEachBetween(0, 0.2, (event) => ids.push(event.id));
|
|
660
|
+
expect(ids).to.deep.equal(["a"]);
|
|
661
|
+
sched.dispose();
|
|
662
|
+
});
|
|
607
663
|
});
|
|
608
664
|
});
|
|
@@ -387,20 +387,32 @@ export class Timeline<GenericEvent extends TimelineEvent> extends Tone {
|
|
|
387
387
|
endTime: number,
|
|
388
388
|
callback: (event: GenericEvent) => void
|
|
389
389
|
): this {
|
|
390
|
+
// _search compares times with an epsilon, so do the same here
|
|
390
391
|
let lowerBound = this._search(startTime);
|
|
391
392
|
let upperBound = this._search(endTime);
|
|
392
|
-
if (lowerBound
|
|
393
|
-
|
|
394
|
-
|
|
393
|
+
if (lowerBound === -1) {
|
|
394
|
+
// every event is after the start time
|
|
395
|
+
lowerBound = 0;
|
|
396
|
+
} else if (EQ(this._timeline[lowerBound].time, startTime)) {
|
|
397
|
+
// _search returns the last event at the start time,
|
|
398
|
+
// include every event at the start time
|
|
399
|
+
while (
|
|
400
|
+
lowerBound > 0 &&
|
|
401
|
+
EQ(this._timeline[lowerBound - 1].time, startTime)
|
|
402
|
+
) {
|
|
403
|
+
lowerBound -= 1;
|
|
395
404
|
}
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
this.
|
|
405
|
+
} else {
|
|
406
|
+
lowerBound += 1;
|
|
407
|
+
}
|
|
408
|
+
// exclusive of the end time
|
|
409
|
+
while (
|
|
410
|
+
upperBound >= 0 &&
|
|
411
|
+
EQ(this._timeline[upperBound].time, endTime)
|
|
412
|
+
) {
|
|
413
|
+
upperBound -= 1;
|
|
403
414
|
}
|
|
415
|
+
this._iterate(callback, lowerBound, upperBound);
|
|
404
416
|
return this;
|
|
405
417
|
}
|
|
406
418
|
|
|
@@ -48,10 +48,6 @@ export class TimelineValue<Type> extends Tone {
|
|
|
48
48
|
*/
|
|
49
49
|
get(time: Seconds): Type {
|
|
50
50
|
const event = this._timeline.get(time);
|
|
51
|
-
|
|
52
|
-
return event.value;
|
|
53
|
-
} else {
|
|
54
|
-
return this._initialValue;
|
|
55
|
-
}
|
|
51
|
+
return event?.value ?? this._initialValue;
|
|
56
52
|
}
|
|
57
53
|
}
|
|
@@ -58,11 +58,11 @@ export const singleIOProcess = /* javascript */ `
|
|
|
58
58
|
const input = inputs[0];
|
|
59
59
|
const output = outputs[0];
|
|
60
60
|
// get the parameter values
|
|
61
|
-
const channelCount = Math.max(input
|
|
61
|
+
const channelCount = Math.max(input?.length || 0, output.length);
|
|
62
62
|
for (let sample = 0; sample < this.blockSize; sample++) {
|
|
63
63
|
this.updateParams(parameters, sample);
|
|
64
64
|
for (let channel = 0; channel < channelCount; channel++) {
|
|
65
|
-
const inputSample = input
|
|
65
|
+
const inputSample = input?.length ? input[channel][sample] : 0;
|
|
66
66
|
output[channel][sample] = this.generate(inputSample, channel, this.params);
|
|
67
67
|
}
|
|
68
68
|
}
|
|
@@ -97,10 +97,8 @@ export abstract class ToneAudioWorklet<
|
|
|
97
97
|
dispose(): this {
|
|
98
98
|
super.dispose();
|
|
99
99
|
this._dummyGain.disconnect();
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
this._worklet.disconnect();
|
|
103
|
-
}
|
|
100
|
+
this._worklet?.port.postMessage("dispose");
|
|
101
|
+
this._worklet?.disconnect();
|
|
104
102
|
return this;
|
|
105
103
|
}
|
|
106
104
|
}
|
package/Tone/fromContext.ts
CHANGED
|
@@ -10,7 +10,7 @@ import { TimeClass } from "./core/type/Time.js";
|
|
|
10
10
|
import { TransportTimeClass } from "./core/type/TransportTime.js";
|
|
11
11
|
import { omitFromObject } from "./core/util/Defaults.js";
|
|
12
12
|
import { DrawInstance } from "./core/util/Draw.js";
|
|
13
|
-
import {
|
|
13
|
+
import { isFunction } from "./core/util/TypeCheck.js";
|
|
14
14
|
|
|
15
15
|
type ClassesWithoutSingletons = Omit<
|
|
16
16
|
typeof Classes,
|
|
@@ -48,7 +48,7 @@ export function fromContext(context: Context): ToneObject {
|
|
|
48
48
|
omitFromObject(Classes, ["Transport", "Destination", "Draw"])
|
|
49
49
|
).map((key) => {
|
|
50
50
|
const cls = Classes[key];
|
|
51
|
-
if (
|
|
51
|
+
if (isFunction(cls?.getDefaults)) {
|
|
52
52
|
classesWithContext[key] = class ToneFromContextNode extends cls {
|
|
53
53
|
get defaultContext(): Context {
|
|
54
54
|
return context;
|
|
@@ -264,7 +264,7 @@ export class Sampler extends Instrument<SamplerOptions> {
|
|
|
264
264
|
|
|
265
265
|
// remove it when it's done
|
|
266
266
|
source.onended = () => {
|
|
267
|
-
if (this._activeSources
|
|
267
|
+
if (this._activeSources?.has(midi)) {
|
|
268
268
|
const sources = this._activeSources.get(
|
|
269
269
|
midi
|
|
270
270
|
) as ToneBufferSource[];
|
|
@@ -31,6 +31,12 @@ describe("Noise", () => {
|
|
|
31
31
|
noise.dispose();
|
|
32
32
|
});
|
|
33
33
|
|
|
34
|
+
it("can be disposed while started", () => {
|
|
35
|
+
const noise = new Noise().toDestination();
|
|
36
|
+
noise.start();
|
|
37
|
+
noise.dispose();
|
|
38
|
+
});
|
|
39
|
+
|
|
34
40
|
it("can set the playbackRate in the constructor", () => {
|
|
35
41
|
const noise = new Noise({
|
|
36
42
|
playbackRate: 2,
|
package/Tone/source/Noise.ts
CHANGED
|
@@ -330,6 +330,37 @@ describe("Source", () => {
|
|
|
330
330
|
expect(output.getValueAtTime(0.5)).to.be.equal(0);
|
|
331
331
|
});
|
|
332
332
|
|
|
333
|
+
it("stops the playing source when the transport is stopped and restarted at the same time", async () => {
|
|
334
|
+
const output = await Offline(({ transport }) => {
|
|
335
|
+
const source = new Player(rampBuffer).toDestination();
|
|
336
|
+
source.sync().start(0);
|
|
337
|
+
const clock = (
|
|
338
|
+
transport as unknown as {
|
|
339
|
+
_clock: {
|
|
340
|
+
context: typeof transport.context;
|
|
341
|
+
_boundLoop: () => void;
|
|
342
|
+
};
|
|
343
|
+
}
|
|
344
|
+
)._clock;
|
|
345
|
+
transport.start(0);
|
|
346
|
+
// hold the clock loop back so that stop/start land ahead of
|
|
347
|
+
// _lastUpdate, as they do in a realtime context where both
|
|
348
|
+
// default to now() = currentTime + lookAhead
|
|
349
|
+
clock.context.off("tick", clock._boundLoop);
|
|
350
|
+
return atTime(0.2, (time) => {
|
|
351
|
+
transport.stop(time);
|
|
352
|
+
transport.start(time, 0.5);
|
|
353
|
+
clock.context.on("tick", clock._boundLoop);
|
|
354
|
+
});
|
|
355
|
+
}, 0.5);
|
|
356
|
+
// before the restart the ramp plays from 0
|
|
357
|
+
expect(output.getValueAtTime(0.1)).to.be.closeTo(0.1, 0.01);
|
|
358
|
+
// after the restart only the source started at offset 0.5 plays;
|
|
359
|
+
// if the first source were orphaned the two ramps would sum
|
|
360
|
+
expect(output.getValueAtTime(0.3)).to.be.closeTo(0.6, 0.01);
|
|
361
|
+
expect(output.getValueAtTime(0.4)).to.be.closeTo(0.7, 0.01);
|
|
362
|
+
});
|
|
363
|
+
|
|
333
364
|
it("gives the correct offset on time on start/stop events when started with an offset", async () => {
|
|
334
365
|
const output = await Offline(({ transport }) => {
|
|
335
366
|
const source = new Player(rampBuffer).toDestination();
|
package/Tone/source/UserMedia.ts
CHANGED
|
@@ -201,7 +201,7 @@ export class UserMedia extends ToneAudioNode<UserMediaOptions> {
|
|
|
201
201
|
* and "stopped" when the mic is closed.
|
|
202
202
|
*/
|
|
203
203
|
get state() {
|
|
204
|
-
return this._stream
|
|
204
|
+
return this._stream?.active ? "started" : "stopped";
|
|
205
205
|
}
|
|
206
206
|
|
|
207
207
|
/**
|
|
@@ -213,11 +213,7 @@ export class UserMedia extends ToneAudioNode<UserMediaOptions> {
|
|
|
213
213
|
* device is not open.
|
|
214
214
|
*/
|
|
215
215
|
get deviceId(): string | undefined {
|
|
216
|
-
|
|
217
|
-
return this._device.deviceId;
|
|
218
|
-
} else {
|
|
219
|
-
return undefined;
|
|
220
|
-
}
|
|
216
|
+
return this._device?.deviceId;
|
|
221
217
|
}
|
|
222
218
|
|
|
223
219
|
/**
|
|
@@ -226,11 +222,7 @@ export class UserMedia extends ToneAudioNode<UserMediaOptions> {
|
|
|
226
222
|
* Returns null when the device is not open.
|
|
227
223
|
*/
|
|
228
224
|
get groupId(): string | undefined {
|
|
229
|
-
|
|
230
|
-
return this._device.groupId;
|
|
231
|
-
} else {
|
|
232
|
-
return undefined;
|
|
233
|
-
}
|
|
225
|
+
return this._device?.groupId;
|
|
234
226
|
}
|
|
235
227
|
|
|
236
228
|
/**
|
|
@@ -239,11 +231,7 @@ export class UserMedia extends ToneAudioNode<UserMediaOptions> {
|
|
|
239
231
|
* because of permissions.
|
|
240
232
|
*/
|
|
241
233
|
get label(): string | undefined {
|
|
242
|
-
|
|
243
|
-
return this._device.label;
|
|
244
|
-
} else {
|
|
245
|
-
return undefined;
|
|
246
|
-
}
|
|
234
|
+
return this._device?.label;
|
|
247
235
|
}
|
|
248
236
|
|
|
249
237
|
/**
|
|
@@ -515,7 +515,7 @@ export class Player extends Source<PlayerOptions> {
|
|
|
515
515
|
|
|
516
516
|
// cancel the stop event since it's at a different time now
|
|
517
517
|
const stopEvent = this._state.getNextState("stopped", now);
|
|
518
|
-
if (stopEvent
|
|
518
|
+
if (stopEvent?.implicitEnd) {
|
|
519
519
|
this._state.cancel(stopEvent.time);
|
|
520
520
|
this._activeSources.forEach((source) => source.cancelStop());
|
|
521
521
|
|
package/Tone/version.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export const version: string = "15.5.
|
|
1
|
+
export const version: string = "15.5.49";
|