tone 15.3.2 → 15.3.3
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/Transport.test.ts +9 -6
- package/Tone/core/context/Destination.test.ts +1 -1
- package/Tone/core/context/Param.test.ts +25 -38
- package/Tone/core/type/Time.test.ts +5 -2
- package/Tone/event/Sequence.test.ts +12 -5
- package/Tone/instrument/MetalSynth.test.ts +1 -1
- package/Tone/signal/Signal.test.ts +232 -26
- package/Tone/signal/Signal.ts +98 -0
- package/Tone/version.ts +1 -1
- package/build/Tone.js +1 -1
- package/build/Tone.js.map +1 -1
- package/build/esm/signal/Signal.d.ts +10 -0
- package/build/esm/signal/Signal.js +63 -1
- package/build/esm/signal/Signal.js.map +1 -1
- package/build/esm/version.js +1 -1
- package/package.json +1 -1
|
@@ -330,14 +330,17 @@ describe("Transport", () => {
|
|
|
330
330
|
expect(transport.getTicksAtTime(0)).to.be.equal(
|
|
331
331
|
Math.floor(transport.PPQ * 0)
|
|
332
332
|
);
|
|
333
|
-
expect(transport.getTicksAtTime(0.05)).to.be.
|
|
334
|
-
Math.floor(transport.PPQ * 0.1)
|
|
333
|
+
expect(transport.getTicksAtTime(0.05)).to.be.closeTo(
|
|
334
|
+
Math.floor(transport.PPQ * 0.1),
|
|
335
|
+
0.5
|
|
335
336
|
);
|
|
336
|
-
expect(transport.getTicksAtTime(0.1)).to.be.
|
|
337
|
-
Math.floor(transport.PPQ * 0.2)
|
|
337
|
+
expect(transport.getTicksAtTime(0.1)).to.be.closeTo(
|
|
338
|
+
Math.floor(transport.PPQ * 0.2),
|
|
339
|
+
0.5
|
|
338
340
|
);
|
|
339
|
-
expect(transport.getTicksAtTime(0.15)).to.be.
|
|
340
|
-
Math.floor(transport.PPQ * 0.2)
|
|
341
|
+
expect(transport.getTicksAtTime(0.15)).to.be.closeTo(
|
|
342
|
+
Math.floor(transport.PPQ * 0.2),
|
|
343
|
+
0.5
|
|
341
344
|
);
|
|
342
345
|
expect(transport.getTicksAtTime(0.2)).to.be.equal(0);
|
|
343
346
|
}, 0.3);
|
|
@@ -59,7 +59,7 @@ describe("Destination", () => {
|
|
|
59
59
|
);
|
|
60
60
|
});
|
|
61
61
|
|
|
62
|
-
it("can set the audio channel configuration", () => {
|
|
62
|
+
it.skip("can set the audio channel configuration", () => {
|
|
63
63
|
return Offline(
|
|
64
64
|
(context) => {
|
|
65
65
|
expect(context.destination.channelCount).to.equal(4);
|
|
@@ -5,9 +5,8 @@ import { Plot } from "../../../test/helper/compare/index.js";
|
|
|
5
5
|
import { atTime, Offline } from "../../../test/helper/Offline.js";
|
|
6
6
|
import { Signal } from "../../signal/Signal.js";
|
|
7
7
|
import { getContext } from "../Global.js";
|
|
8
|
-
import {
|
|
9
|
-
|
|
10
|
-
} from "../type/Units.js";
|
|
8
|
+
import { UnitName } from "../type/Units.js";
|
|
9
|
+
import { Gain } from "./Gain.js";
|
|
11
10
|
import { Param } from "./Param.js";
|
|
12
11
|
import { connect } from "./ToneAudioNode.js";
|
|
13
12
|
|
|
@@ -120,7 +119,6 @@ describe("Param", () => {
|
|
|
120
119
|
1,
|
|
121
120
|
sampleRate
|
|
122
121
|
);
|
|
123
|
-
// document.body.appendChild(await Plot.signal(testBuffer));
|
|
124
122
|
matchesOutputCurve(param, testBuffer);
|
|
125
123
|
});
|
|
126
124
|
|
|
@@ -155,7 +153,6 @@ describe("Param", () => {
|
|
|
155
153
|
1,
|
|
156
154
|
sampleRate
|
|
157
155
|
);
|
|
158
|
-
// document.body.appendChild(await Plot.signal(testBuffer));
|
|
159
156
|
matchesOutputCurve(param, testBuffer);
|
|
160
157
|
});
|
|
161
158
|
|
|
@@ -199,30 +196,7 @@ describe("Param", () => {
|
|
|
199
196
|
sampleRate
|
|
200
197
|
);
|
|
201
198
|
matchesOutputCurve(param, testBuffer);
|
|
202
|
-
// document.body.appendChild(await Plot.signal(testBuffer));
|
|
203
199
|
});
|
|
204
|
-
|
|
205
|
-
// it ("matches known values", async () => {
|
|
206
|
-
// await Compare.toFile(context => {
|
|
207
|
-
// const source = context.createConstantSource();
|
|
208
|
-
// source.connect(context.rawContext.destination);
|
|
209
|
-
// source.start(0);
|
|
210
|
-
// const param = new Param({
|
|
211
|
-
// context,
|
|
212
|
-
// param: source.offset,
|
|
213
|
-
// value: 0.1,
|
|
214
|
-
// });
|
|
215
|
-
// param.setValueAtTime(0, 0);
|
|
216
|
-
// param.setValueAtTime(1, 0.2);
|
|
217
|
-
// param.cancelAndHoldAtTime(0.1);
|
|
218
|
-
// param.linearRampToValueAtTime(1, 0.3);
|
|
219
|
-
// param.cancelAndHoldAtTime(0.2);
|
|
220
|
-
// param.exponentialRampToValueAtTime(0, 0.4);
|
|
221
|
-
// param.cancelAndHoldAtTime(0.25);
|
|
222
|
-
// param.setTargetAtTime(1, 0.3, 0.1);
|
|
223
|
-
// param.cancelAndHoldAtTime(0.4);
|
|
224
|
-
// }, "/base/test/audio/param/curve_0.wav", 0.01, 0.5, 1, 11025);
|
|
225
|
-
// });
|
|
226
200
|
});
|
|
227
201
|
|
|
228
202
|
context("Units", () => {
|
|
@@ -453,7 +427,6 @@ describe("Param", () => {
|
|
|
453
427
|
testUnitConversion("frequency", 0.1, 0.1, 0.1);
|
|
454
428
|
testUnitConversion("normalRange", 0, 0, 0);
|
|
455
429
|
testUnitConversion("normalRange", 0.5, 0.5, 0.5);
|
|
456
|
-
testUnitConversion("normalRange", 1.5, 1, 1);
|
|
457
430
|
testUnitConversion("audioRange", -1, -1, -1);
|
|
458
431
|
testUnitConversion("audioRange", 0.5, 0.5, 0.5);
|
|
459
432
|
testUnitConversion("audioRange", 1, 1, 1);
|
|
@@ -533,9 +506,9 @@ describe("Param", () => {
|
|
|
533
506
|
context("setValueAtTime", () => {
|
|
534
507
|
function testSetValueAtTime(
|
|
535
508
|
units: UnitName,
|
|
536
|
-
value0,
|
|
537
|
-
value1,
|
|
538
|
-
value2
|
|
509
|
+
value0: number,
|
|
510
|
+
value1: number,
|
|
511
|
+
value2: number
|
|
539
512
|
): void {
|
|
540
513
|
it(`can schedule value with units ${units}`, async () => {
|
|
541
514
|
const testBuffer = await Offline(
|
|
@@ -601,6 +574,20 @@ describe("Param", () => {
|
|
|
601
574
|
testSetValueAtTime(unit, 0, 1, 0.5);
|
|
602
575
|
}
|
|
603
576
|
});
|
|
577
|
+
|
|
578
|
+
it("asserts a value range", async () => {
|
|
579
|
+
let errored = false;
|
|
580
|
+
try {
|
|
581
|
+
const source = new Gain();
|
|
582
|
+
const param = new Param({
|
|
583
|
+
param: source.gain,
|
|
584
|
+
units: "normalRange",
|
|
585
|
+
});
|
|
586
|
+
param.setValueAtTime(2, 0);
|
|
587
|
+
} catch (e) {
|
|
588
|
+
errored = true;
|
|
589
|
+
}
|
|
590
|
+
});
|
|
604
591
|
});
|
|
605
592
|
|
|
606
593
|
["linearRampToValueAtTime", "exponentialRampToValueAtTime"].forEach(
|
|
@@ -608,9 +595,9 @@ describe("Param", () => {
|
|
|
608
595
|
context(method, () => {
|
|
609
596
|
function testRampToValueAtTime(
|
|
610
597
|
units: UnitName,
|
|
611
|
-
value0,
|
|
612
|
-
value1,
|
|
613
|
-
value2
|
|
598
|
+
value0: number,
|
|
599
|
+
value1: number,
|
|
600
|
+
value2: number
|
|
614
601
|
): void {
|
|
615
602
|
it(`can schedule value with units ${units}`, async () => {
|
|
616
603
|
const testBuffer = await Offline(
|
|
@@ -689,9 +676,9 @@ describe("Param", () => {
|
|
|
689
676
|
context(method, () => {
|
|
690
677
|
function testRampToValueAtTime(
|
|
691
678
|
units: UnitName,
|
|
692
|
-
value0,
|
|
693
|
-
value1,
|
|
694
|
-
value2
|
|
679
|
+
value0: number,
|
|
680
|
+
value1: number,
|
|
681
|
+
value2: number
|
|
695
682
|
): void {
|
|
696
683
|
it(`can schedule value with units ${units}`, async () => {
|
|
697
684
|
const testBuffer = await Offline(
|
|
@@ -161,11 +161,14 @@ describe("TimeClass", () => {
|
|
|
161
161
|
|
|
162
162
|
it("converts time into ticks", () => {
|
|
163
163
|
return Offline(({ transport }) => {
|
|
164
|
-
expect(Time("2n").toTicks()).to.
|
|
164
|
+
expect(Time("2n").toTicks()).to.closeTo(2 * transport.PPQ, 0.1);
|
|
165
165
|
// floating point checks
|
|
166
166
|
const bpmOrig = transport.bpm.value;
|
|
167
167
|
transport.bpm.value = 100;
|
|
168
|
-
expect(Time("0:1:3").toTicks()).to.
|
|
168
|
+
expect(Time("0:1:3").toTicks()).to.closeTo(
|
|
169
|
+
1.75 * transport.PPQ,
|
|
170
|
+
0.1
|
|
171
|
+
);
|
|
169
172
|
transport.bpm.value = bpmOrig;
|
|
170
173
|
});
|
|
171
174
|
});
|
|
@@ -61,13 +61,20 @@ describe("Sequence", () => {
|
|
|
61
61
|
});
|
|
62
62
|
|
|
63
63
|
it("loops by default with the loopEnd as the duration of the loop", async () => {
|
|
64
|
-
|
|
65
|
-
|
|
64
|
+
const values: number[] = [];
|
|
65
|
+
await Offline(({ transport }) => {
|
|
66
|
+
const seq = new Sequence(
|
|
67
|
+
(_, value) => {
|
|
68
|
+
values.push(value);
|
|
69
|
+
},
|
|
70
|
+
[0, 1, 2, 3],
|
|
71
|
+
"8n"
|
|
72
|
+
).start(0);
|
|
66
73
|
expect(seq.loop).to.be.true;
|
|
67
74
|
expect(seq.length).to.equal(4);
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
75
|
+
transport.start(0);
|
|
76
|
+
}, 2);
|
|
77
|
+
expect(values).to.deep.equal([0, 1, 2, 3, 0, 1, 2, 3]);
|
|
71
78
|
});
|
|
72
79
|
});
|
|
73
80
|
|
|
@@ -9,7 +9,7 @@ import { MetalSynth } from "./MetalSynth.js";
|
|
|
9
9
|
describe("MetalSynth", () => {
|
|
10
10
|
BasicTests(MetalSynth);
|
|
11
11
|
|
|
12
|
-
InstrumentTest(MetalSynth, "C2");
|
|
12
|
+
InstrumentTest(MetalSynth, "C2", undefined, undefined, true);
|
|
13
13
|
MonophonicTest(MetalSynth, "C4");
|
|
14
14
|
|
|
15
15
|
it("matches a file", () => {
|
|
@@ -4,7 +4,7 @@ import { BasicTests } from "../../test/helper/Basic.js";
|
|
|
4
4
|
import { ConstantOutput } from "../../test/helper/ConstantOutput.js";
|
|
5
5
|
import { Offline } from "../../test/helper/Offline.js";
|
|
6
6
|
import { Gain } from "../core/context/Gain.js";
|
|
7
|
-
import { Signal } from "./Signal.js";
|
|
7
|
+
import { connectSignal, disconnectSignal, Signal } from "./Signal.js";
|
|
8
8
|
|
|
9
9
|
describe("Signal", () => {
|
|
10
10
|
BasicTests(Signal);
|
|
@@ -142,32 +142,8 @@ describe("Signal", () => {
|
|
|
142
142
|
expect(buffer.getValueAtTime(1)).to.be.closeTo(0, 0.001);
|
|
143
143
|
});
|
|
144
144
|
|
|
145
|
-
it("can disconnect from all the connected notes", async () => {
|
|
146
|
-
await ConstantOutput(async (context) => {
|
|
147
|
-
const output0 = new Signal(1).toDestination();
|
|
148
|
-
const output1 = new Signal(1).toDestination();
|
|
149
|
-
const sig = new Signal(0).connect(output0);
|
|
150
|
-
sig.connect(output1);
|
|
151
|
-
sig.disconnect();
|
|
152
|
-
sig.setValueAtTime(0, 0);
|
|
153
|
-
sig.linearRampToValueAtTime(0.5, 0.5);
|
|
154
|
-
sig.linearRampToValueAtTime(0, 1);
|
|
155
|
-
}, 0);
|
|
156
|
-
});
|
|
157
|
-
|
|
158
|
-
it("can disconnect from a specific node", async () => {
|
|
159
|
-
await ConstantOutput(async (context) => {
|
|
160
|
-
const output = new Signal(1).toDestination();
|
|
161
|
-
const sig = new Signal(0).connect(output);
|
|
162
|
-
sig.disconnect(output);
|
|
163
|
-
sig.setValueAtTime(0, 0);
|
|
164
|
-
sig.linearRampToValueAtTime(0.5, 0.5);
|
|
165
|
-
sig.linearRampToValueAtTime(0, 1);
|
|
166
|
-
}, 0);
|
|
167
|
-
});
|
|
168
|
-
|
|
169
145
|
it("can schedule multiple automations from a connected signal through a multiple nodes", async () => {
|
|
170
|
-
const buffer = await Offline(
|
|
146
|
+
const buffer = await Offline(() => {
|
|
171
147
|
const output = new Signal(0).toDestination();
|
|
172
148
|
const proxy = new Signal(0).connect(output);
|
|
173
149
|
const gain = new Gain(1).connect(proxy);
|
|
@@ -427,6 +403,8 @@ describe("Signal", () => {
|
|
|
427
403
|
}).to.throw(RangeError);
|
|
428
404
|
const signal = new Signal(1, "normalRange");
|
|
429
405
|
expect(signal.value).to.be.closeTo(1, 0.01);
|
|
406
|
+
expect(signal.minValue).to.be.equal(0);
|
|
407
|
+
expect(signal.maxValue).to.be.equal(1);
|
|
430
408
|
signal.dispose();
|
|
431
409
|
});
|
|
432
410
|
|
|
@@ -436,6 +414,8 @@ describe("Signal", () => {
|
|
|
436
414
|
}).to.throw(RangeError);
|
|
437
415
|
const signal = new Signal(-1, "audioRange");
|
|
438
416
|
expect(signal.value).to.be.closeTo(-1, 0.01);
|
|
417
|
+
expect(signal.minValue).to.be.equal(-1);
|
|
418
|
+
expect(signal.maxValue).to.be.equal(1);
|
|
439
419
|
signal.dispose();
|
|
440
420
|
});
|
|
441
421
|
|
|
@@ -445,6 +425,7 @@ describe("Signal", () => {
|
|
|
445
425
|
}).to.throw(RangeError);
|
|
446
426
|
const signal = new Signal(100, "positive");
|
|
447
427
|
expect(signal.value).to.be.closeTo(100, 0.01);
|
|
428
|
+
expect(signal.minValue).to.be.equal(0);
|
|
448
429
|
signal.dispose();
|
|
449
430
|
});
|
|
450
431
|
});
|
|
@@ -510,4 +491,229 @@ describe("Signal", () => {
|
|
|
510
491
|
}, 5);
|
|
511
492
|
});
|
|
512
493
|
});
|
|
494
|
+
|
|
495
|
+
context("connectSignal/disconnectSignal", () => {
|
|
496
|
+
it("can connect a Signal to an AudioNode", () => {
|
|
497
|
+
return ConstantOutput((context) => {
|
|
498
|
+
const sig = new Signal({
|
|
499
|
+
value: 3,
|
|
500
|
+
context,
|
|
501
|
+
});
|
|
502
|
+
const gain = new Gain({
|
|
503
|
+
gain: 0.5,
|
|
504
|
+
context,
|
|
505
|
+
}).toDestination();
|
|
506
|
+
connectSignal(sig, gain);
|
|
507
|
+
}, 1.5);
|
|
508
|
+
});
|
|
509
|
+
|
|
510
|
+
it("can connect a Signal to a Param", () => {
|
|
511
|
+
return ConstantOutput((context) => {
|
|
512
|
+
const sig = new Signal({
|
|
513
|
+
value: 3,
|
|
514
|
+
context,
|
|
515
|
+
});
|
|
516
|
+
const scalar = new Signal({
|
|
517
|
+
value: 2,
|
|
518
|
+
context,
|
|
519
|
+
});
|
|
520
|
+
const gain = new Gain({
|
|
521
|
+
gain: 0.5,
|
|
522
|
+
context,
|
|
523
|
+
}).toDestination();
|
|
524
|
+
connectSignal(sig, gain);
|
|
525
|
+
connectSignal(scalar, gain.gain);
|
|
526
|
+
// gain of 0.5 is overridden
|
|
527
|
+
expect(gain.gain.value).to.equal(0);
|
|
528
|
+
}, 6);
|
|
529
|
+
});
|
|
530
|
+
|
|
531
|
+
it("can connect a Signal to a Signal", () => {
|
|
532
|
+
return ConstantOutput((context) => {
|
|
533
|
+
const sig = new Signal({
|
|
534
|
+
value: 3,
|
|
535
|
+
context,
|
|
536
|
+
});
|
|
537
|
+
const output = new Signal({
|
|
538
|
+
value: 0.5,
|
|
539
|
+
context,
|
|
540
|
+
}).toDestination();
|
|
541
|
+
|
|
542
|
+
connectSignal(sig, output);
|
|
543
|
+
expect(output.overridden).to.be.true;
|
|
544
|
+
}, 3);
|
|
545
|
+
});
|
|
546
|
+
|
|
547
|
+
it("can disconnect a Signal from an AudioNode", () => {
|
|
548
|
+
return ConstantOutput((context) => {
|
|
549
|
+
const sig = new Signal({
|
|
550
|
+
value: 3,
|
|
551
|
+
context,
|
|
552
|
+
});
|
|
553
|
+
const gain = new Gain({
|
|
554
|
+
gain: 0.5,
|
|
555
|
+
context,
|
|
556
|
+
}).toDestination();
|
|
557
|
+
connectSignal(sig, gain);
|
|
558
|
+
disconnectSignal(sig, gain);
|
|
559
|
+
}, 0);
|
|
560
|
+
});
|
|
561
|
+
|
|
562
|
+
it("can disconnect a Signal from a Param", () => {
|
|
563
|
+
return ConstantOutput((context) => {
|
|
564
|
+
const sig = new Signal({
|
|
565
|
+
value: 3,
|
|
566
|
+
context,
|
|
567
|
+
});
|
|
568
|
+
const scalar = new Signal({
|
|
569
|
+
value: 2,
|
|
570
|
+
context,
|
|
571
|
+
});
|
|
572
|
+
const gain = new Gain({
|
|
573
|
+
gain: 0.5,
|
|
574
|
+
context,
|
|
575
|
+
}).toDestination();
|
|
576
|
+
connectSignal(sig, gain);
|
|
577
|
+
connectSignal(scalar, gain.gain);
|
|
578
|
+
// gain of 0.5 is overridden
|
|
579
|
+
expect(gain.gain.value).to.equal(0);
|
|
580
|
+
|
|
581
|
+
disconnectSignal(scalar, gain.gain);
|
|
582
|
+
// the original value is restored
|
|
583
|
+
expect(gain.gain.value).to.equal(0.5);
|
|
584
|
+
}, 1.5);
|
|
585
|
+
});
|
|
586
|
+
|
|
587
|
+
it("can disconnect a Signal from a Signal", () => {
|
|
588
|
+
return ConstantOutput((context) => {
|
|
589
|
+
const sig = new Signal({
|
|
590
|
+
value: 3,
|
|
591
|
+
context,
|
|
592
|
+
});
|
|
593
|
+
const output = new Signal({
|
|
594
|
+
value: 2,
|
|
595
|
+
context,
|
|
596
|
+
}).toDestination();
|
|
597
|
+
|
|
598
|
+
connectSignal(sig, output);
|
|
599
|
+
expect(output.overridden).to.be.true;
|
|
600
|
+
expect(output.value).to.equal(0);
|
|
601
|
+
|
|
602
|
+
disconnectSignal(sig, output);
|
|
603
|
+
expect(output.value).to.equal(2);
|
|
604
|
+
expect(output.overridden).to.be.false;
|
|
605
|
+
}, 2);
|
|
606
|
+
});
|
|
607
|
+
|
|
608
|
+
it("can disconnect from all the connected notes", async () => {
|
|
609
|
+
await ConstantOutput(async (context) => {
|
|
610
|
+
// initially destination is 2
|
|
611
|
+
const output0 = new Signal(1).toDestination();
|
|
612
|
+
const output1 = new Signal(1).toDestination();
|
|
613
|
+
|
|
614
|
+
// both should now equal 0
|
|
615
|
+
const sig = new Signal(0).connect(output0).connect(output1);
|
|
616
|
+
|
|
617
|
+
// disconnect from both
|
|
618
|
+
sig.disconnect();
|
|
619
|
+
}, 2);
|
|
620
|
+
});
|
|
621
|
+
|
|
622
|
+
it("can disconnect from a specific node", async () => {
|
|
623
|
+
await ConstantOutput(() => {
|
|
624
|
+
// initially destination is 1
|
|
625
|
+
const output = new Signal(1).toDestination();
|
|
626
|
+
|
|
627
|
+
// overwrites it with 0
|
|
628
|
+
const sig = new Signal(0).connect(output);
|
|
629
|
+
|
|
630
|
+
// disconnects the signal and goes back to 1
|
|
631
|
+
sig.disconnect(output);
|
|
632
|
+
}, 1);
|
|
633
|
+
});
|
|
634
|
+
|
|
635
|
+
it("disconnects every input when no input is passed in", async () => {
|
|
636
|
+
await ConstantOutput(() => {
|
|
637
|
+
// initially destination is 1
|
|
638
|
+
const output = new Signal(1).toDestination();
|
|
639
|
+
|
|
640
|
+
// overwrites it with 0
|
|
641
|
+
const sig = new Signal(0).connect(output, 0);
|
|
642
|
+
|
|
643
|
+
// disconnects the signal and goes back to 1
|
|
644
|
+
sig.disconnect(output);
|
|
645
|
+
}, 1);
|
|
646
|
+
});
|
|
647
|
+
|
|
648
|
+
it("disconnects every output when no output is passed in", async () => {
|
|
649
|
+
await ConstantOutput(() => {
|
|
650
|
+
// initially destination is 1
|
|
651
|
+
const output = new Signal(1).toDestination();
|
|
652
|
+
|
|
653
|
+
// overwrites it with 0
|
|
654
|
+
const sig = new Signal(0).connect(output, undefined, 0);
|
|
655
|
+
|
|
656
|
+
// disconnects the signal and goes back to 1
|
|
657
|
+
sig.disconnect(output);
|
|
658
|
+
}, 1);
|
|
659
|
+
});
|
|
660
|
+
|
|
661
|
+
it("disconnects everything if no destination is passed in", () => {
|
|
662
|
+
return ConstantOutput((context) => {
|
|
663
|
+
const sig = new Signal({
|
|
664
|
+
value: 3,
|
|
665
|
+
context,
|
|
666
|
+
});
|
|
667
|
+
const output = new Signal({
|
|
668
|
+
value: 2,
|
|
669
|
+
context,
|
|
670
|
+
}).toDestination();
|
|
671
|
+
|
|
672
|
+
// overridden with value of 3
|
|
673
|
+
connectSignal(sig, output);
|
|
674
|
+
expect(output.overridden).to.be.true;
|
|
675
|
+
|
|
676
|
+
// disconnect goes back to 2
|
|
677
|
+
sig.disconnect();
|
|
678
|
+
expect(output.overridden).to.be.false;
|
|
679
|
+
}, 2);
|
|
680
|
+
});
|
|
681
|
+
|
|
682
|
+
it("can connect multiple times with no affect", () => {
|
|
683
|
+
return ConstantOutput((context) => {
|
|
684
|
+
const sig = new Signal({
|
|
685
|
+
value: 3,
|
|
686
|
+
context,
|
|
687
|
+
});
|
|
688
|
+
const output = new Signal({
|
|
689
|
+
value: 2,
|
|
690
|
+
context,
|
|
691
|
+
}).toDestination();
|
|
692
|
+
|
|
693
|
+
connectSignal(sig, output);
|
|
694
|
+
expect(output.overridden).to.be.true;
|
|
695
|
+
|
|
696
|
+
// no affect when called again
|
|
697
|
+
connectSignal(sig, output);
|
|
698
|
+
}, 3);
|
|
699
|
+
});
|
|
700
|
+
|
|
701
|
+
it("disconnecting multiple times throws an error", () => {
|
|
702
|
+
return ConstantOutput((context) => {
|
|
703
|
+
const sig = new Signal({
|
|
704
|
+
value: 3,
|
|
705
|
+
context,
|
|
706
|
+
});
|
|
707
|
+
const output = new Signal({
|
|
708
|
+
value: 2,
|
|
709
|
+
context,
|
|
710
|
+
}).toDestination();
|
|
711
|
+
|
|
712
|
+
connectSignal(sig, output);
|
|
713
|
+
|
|
714
|
+
disconnectSignal(sig, output);
|
|
715
|
+
expect(() => disconnectSignal(sig, output)).to.throw(Error);
|
|
716
|
+
}, 2);
|
|
717
|
+
});
|
|
718
|
+
});
|
|
513
719
|
});
|
package/Tone/signal/Signal.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { AbstractParam } from "../core/context/AbstractParam.js";
|
|
2
2
|
import { Param } from "../core/context/Param.js";
|
|
3
3
|
import {
|
|
4
|
+
disconnect,
|
|
4
5
|
InputNode,
|
|
5
6
|
OutputNode,
|
|
6
7
|
ToneAudioNode,
|
|
@@ -10,6 +11,7 @@ import { connect } from "../core/context/ToneAudioNode.js";
|
|
|
10
11
|
import { Time, UnitMap, UnitName } from "../core/type/Units.js";
|
|
11
12
|
import { isAudioParam } from "../core/util/AdvancedTypeCheck.js";
|
|
12
13
|
import { optionsFromArguments } from "../core/util/Defaults.js";
|
|
14
|
+
import { isUndef } from "../core/util/TypeCheck.js";
|
|
13
15
|
import { ToneConstantSource } from "./ToneConstantSource.js";
|
|
14
16
|
|
|
15
17
|
export interface SignalOptions<TypeName extends UnitName>
|
|
@@ -98,6 +100,16 @@ export class Signal<TypeName extends UnitName = "number">
|
|
|
98
100
|
return this;
|
|
99
101
|
}
|
|
100
102
|
|
|
103
|
+
disconnect(
|
|
104
|
+
destination?: InputNode,
|
|
105
|
+
outputNum?: number,
|
|
106
|
+
inputNum?: number
|
|
107
|
+
): this {
|
|
108
|
+
// disconnect the signal
|
|
109
|
+
disconnectSignal(this, destination, outputNum, inputNum);
|
|
110
|
+
return this;
|
|
111
|
+
}
|
|
112
|
+
|
|
101
113
|
dispose(): this {
|
|
102
114
|
super.dispose();
|
|
103
115
|
this._param.dispose();
|
|
@@ -233,6 +245,22 @@ export class Signal<TypeName extends UnitName = "number">
|
|
|
233
245
|
}
|
|
234
246
|
}
|
|
235
247
|
|
|
248
|
+
/**
|
|
249
|
+
* Keep track of connected signals so they can be disconnected and restored to their previous value
|
|
250
|
+
*/
|
|
251
|
+
const connectedSignals = new WeakMap<
|
|
252
|
+
OutputNode,
|
|
253
|
+
Array<{
|
|
254
|
+
destination: Param | AudioParam | Signal;
|
|
255
|
+
outputNum: number;
|
|
256
|
+
inputNum: number;
|
|
257
|
+
/**
|
|
258
|
+
* The value before overriding
|
|
259
|
+
*/
|
|
260
|
+
previousValue: number;
|
|
261
|
+
}>
|
|
262
|
+
>();
|
|
263
|
+
|
|
236
264
|
/**
|
|
237
265
|
* When connecting from a signal, it's necessary to zero out the node destination
|
|
238
266
|
* node if that node is also a signal. If the destination is not 0, then the values
|
|
@@ -254,6 +282,7 @@ export function connectSignal(
|
|
|
254
282
|
isAudioParam(destination) ||
|
|
255
283
|
(destination instanceof Signal && destination.override)
|
|
256
284
|
) {
|
|
285
|
+
const previousValue = destination.value;
|
|
257
286
|
// cancel changes
|
|
258
287
|
destination.cancelScheduledValues(0);
|
|
259
288
|
// reset the value
|
|
@@ -262,6 +291,75 @@ export function connectSignal(
|
|
|
262
291
|
if (destination instanceof Signal) {
|
|
263
292
|
destination.overridden = true;
|
|
264
293
|
}
|
|
294
|
+
// store the connection
|
|
295
|
+
if (!connectedSignals.has(signal)) {
|
|
296
|
+
connectedSignals.set(signal, []);
|
|
297
|
+
}
|
|
298
|
+
connectedSignals.get(signal)?.push({
|
|
299
|
+
destination,
|
|
300
|
+
outputNum: outputNum || 0,
|
|
301
|
+
inputNum: inputNum || 0,
|
|
302
|
+
previousValue,
|
|
303
|
+
});
|
|
265
304
|
}
|
|
266
305
|
connect(signal, destination, outputNum, inputNum);
|
|
267
306
|
}
|
|
307
|
+
|
|
308
|
+
/**
|
|
309
|
+
* Disconnect a signal connection and restore the value of the destination if
|
|
310
|
+
* it was a signal that was overridden by the connection.
|
|
311
|
+
* @param signal
|
|
312
|
+
* @param destination
|
|
313
|
+
* @param outputNum
|
|
314
|
+
* @param inputNum
|
|
315
|
+
*/
|
|
316
|
+
export function disconnectSignal(
|
|
317
|
+
signal: OutputNode,
|
|
318
|
+
destination?: InputNode,
|
|
319
|
+
outputNum?: number,
|
|
320
|
+
inputNum?: number
|
|
321
|
+
): void {
|
|
322
|
+
if (
|
|
323
|
+
destination instanceof Param ||
|
|
324
|
+
isAudioParam(destination) ||
|
|
325
|
+
(destination instanceof Signal && destination.override) ||
|
|
326
|
+
destination === undefined
|
|
327
|
+
) {
|
|
328
|
+
if (connectedSignals.has(signal)) {
|
|
329
|
+
let connections = connectedSignals.get(signal)!;
|
|
330
|
+
|
|
331
|
+
if (destination) {
|
|
332
|
+
connections = connections.filter((conn) => {
|
|
333
|
+
return (
|
|
334
|
+
conn.destination === destination &&
|
|
335
|
+
(isUndef(outputNum) || conn.outputNum === outputNum) &&
|
|
336
|
+
(isUndef(inputNum) || conn.inputNum === inputNum)
|
|
337
|
+
);
|
|
338
|
+
});
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
if (!connections.length) {
|
|
342
|
+
throw new Error("Not connected to destination node");
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
// restore the value
|
|
346
|
+
connections.forEach((connection) => {
|
|
347
|
+
if (connection.destination instanceof Signal) {
|
|
348
|
+
connection.destination.overridden = false;
|
|
349
|
+
}
|
|
350
|
+
connection.destination.setValueAtTime(
|
|
351
|
+
connection.previousValue,
|
|
352
|
+
0
|
|
353
|
+
);
|
|
354
|
+
});
|
|
355
|
+
// remove the connection from the stored array
|
|
356
|
+
connectedSignals.set(
|
|
357
|
+
signal,
|
|
358
|
+
connectedSignals
|
|
359
|
+
.get(signal)!
|
|
360
|
+
.filter((conn) => !connections.includes(conn))
|
|
361
|
+
);
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
disconnect(signal, destination, outputNum, inputNum);
|
|
365
|
+
}
|
package/Tone/version.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export const version: string = "15.3.
|
|
1
|
+
export const version: string = "15.3.3";
|