tone 14.8.29 → 14.8.33

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.
Files changed (68) hide show
  1. package/Tone/component/dynamics/Limiter.ts +1 -1
  2. package/Tone/component/envelope/Envelope.ts +2 -2
  3. package/Tone/component/filter/FeedbackCombFilter.ts +2 -2
  4. package/Tone/core/clock/TickSource.ts +1 -1
  5. package/Tone/core/clock/Transport.test.ts +15 -0
  6. package/Tone/core/clock/Transport.ts +93 -30
  7. package/Tone/core/context/ToneWithContext.ts +2 -0
  8. package/Tone/core/type/Frequency.ts +8 -8
  9. package/Tone/core/util/Debug.ts +37 -4
  10. package/Tone/core/util/StateTimeline.ts +1 -1
  11. package/Tone/effect/AutoFilter.ts +1 -1
  12. package/Tone/effect/Chebyshev.ts +1 -1
  13. package/Tone/effect/Chorus.test.ts +11 -8
  14. package/Tone/effect/Chorus.ts +1 -1
  15. package/Tone/effect/MidSideEffect.ts +2 -2
  16. package/Tone/effect/StereoEffect.ts +2 -2
  17. package/Tone/effect/Tremolo.ts +1 -1
  18. package/Tone/effect/Vibrato.ts +1 -1
  19. package/Tone/event/Pattern.ts +1 -1
  20. package/Tone/instrument/Instrument.ts +13 -0
  21. package/Tone/instrument/NoiseSynth.ts +56 -17
  22. package/Tone/instrument/PolySynth.test.ts +81 -18
  23. package/Tone/instrument/PolySynth.ts +11 -1
  24. package/Tone/instrument/Sampler.test.ts +0 -1
  25. package/Tone/instrument/Sampler.ts +1 -1
  26. package/Tone/instrument/Synth.test.ts +63 -0
  27. package/Tone/source/oscillator/PWMOscillator.ts +1 -1
  28. package/Tone/source/oscillator/PulseOscillator.ts +1 -1
  29. package/Tone/version.ts +1 -1
  30. package/build/Tone.js +1 -1
  31. package/build/Tone.js.map +1 -1
  32. package/build/esm/component/dynamics/Limiter.js +0 -1
  33. package/build/esm/component/dynamics/Limiter.js.map +1 -1
  34. package/build/esm/component/envelope/Envelope.js.map +1 -1
  35. package/build/esm/component/filter/FeedbackCombFilter.js +0 -2
  36. package/build/esm/component/filter/FeedbackCombFilter.js.map +1 -1
  37. package/build/esm/core/clock/TickSource.js.map +1 -1
  38. package/build/esm/core/clock/Transport.js +17 -11
  39. package/build/esm/core/clock/Transport.js.map +1 -1
  40. package/build/esm/core/context/ToneWithContext.js +2 -0
  41. package/build/esm/core/context/ToneWithContext.js.map +1 -1
  42. package/build/esm/core/type/Frequency.js +8 -8
  43. package/build/esm/core/type/Frequency.js.map +1 -1
  44. package/build/esm/core/util/Debug.d.ts +9 -1
  45. package/build/esm/core/util/Debug.js +22 -1
  46. package/build/esm/core/util/Debug.js.map +1 -1
  47. package/build/esm/core/util/StateTimeline.d.ts +1 -1
  48. package/build/esm/core/util/StateTimeline.js.map +1 -1
  49. package/build/esm/effect/AutoFilter.js.map +1 -1
  50. package/build/esm/effect/Chebyshev.js.map +1 -1
  51. package/build/esm/effect/Chorus.js.map +1 -1
  52. package/build/esm/effect/Tremolo.js.map +1 -1
  53. package/build/esm/effect/Vibrato.js.map +1 -1
  54. package/build/esm/event/Pattern.js.map +1 -1
  55. package/build/esm/instrument/Instrument.d.ts +4 -0
  56. package/build/esm/instrument/Instrument.js +10 -0
  57. package/build/esm/instrument/Instrument.js.map +1 -1
  58. package/build/esm/instrument/NoiseSynth.d.ts +10 -0
  59. package/build/esm/instrument/NoiseSynth.js +14 -2
  60. package/build/esm/instrument/NoiseSynth.js.map +1 -1
  61. package/build/esm/instrument/PolySynth.d.ts +4 -0
  62. package/build/esm/instrument/PolySynth.js +8 -0
  63. package/build/esm/instrument/PolySynth.js.map +1 -1
  64. package/build/esm/instrument/Sampler.js.map +1 -1
  65. package/build/esm/source/oscillator/PulseOscillator.js.map +1 -1
  66. package/build/esm/version.js +1 -1
  67. package/docs/tone.json +1 -1
  68. package/package.json +32 -30
@@ -7,7 +7,7 @@ import { readOnly } from "../../core/util/Interface";
7
7
 
8
8
  export interface LimiterOptions extends ToneAudioNodeOptions {
9
9
  threshold: Decibels;
10
- };
10
+ }
11
11
 
12
12
  /**
13
13
  * Limiter will limit the loudness of an incoming signal.
@@ -605,8 +605,8 @@ const EnvelopeCurves: EnvelopeCurveMap = (() => {
605
605
  In: cosineCurve,
606
606
  Out: reverseCurve(cosineCurve),
607
607
  },
608
- exponential: "exponential" as "exponential",
609
- linear: "linear" as "linear",
608
+ exponential: "exponential" as const,
609
+ linear: "linear" as const,
610
610
  ripple: {
611
611
  In: rippleCurve,
612
612
  Out: invertCurve(rippleCurve),
@@ -88,9 +88,9 @@ export class FeedbackCombFilter extends ToneAudioWorklet<FeedbackCombFilterOptio
88
88
 
89
89
  onReady(node: AudioWorkletNode) {
90
90
  connectSeries(this.input, node, this.output);
91
- const delayTime = node.parameters.get("delayTime") as AudioParam;;
91
+ const delayTime = node.parameters.get("delayTime") as AudioParam;
92
92
  this.delayTime.setParam(delayTime);
93
- const feedback = node.parameters.get("feedback") as AudioParam;;
93
+ const feedback = node.parameters.get("feedback") as AudioParam;
94
94
  this.resonance.setParam(feedback);
95
95
  }
96
96
 
@@ -66,7 +66,7 @@ export class TickSource<TypeName extends "bpm" | "hertz"> extends ToneWithContex
66
66
  static getDefaults(): TickSourceOptions {
67
67
  return Object.assign({
68
68
  frequency: 1,
69
- units: "hertz" as "hertz",
69
+ units: "hertz" as const,
70
70
  }, ToneWithContext.getDefaults());
71
71
  }
72
72
 
@@ -7,6 +7,8 @@ import { TransportTime } from "../type/TransportTime";
7
7
  import { Transport } from "./Transport";
8
8
  // importing for side affects
9
9
  import "../context/Destination";
10
+ import { warns } from "test/helper/Basic";
11
+ import { Synth } from "Tone/instrument/Synth";
10
12
 
11
13
  describe("Transport", () => {
12
14
 
@@ -546,6 +548,19 @@ describe("Transport", () => {
546
548
  });
547
549
  });
548
550
 
551
+ it("warns if the scheduled time was not used in the callback", async () => {
552
+ return Offline(({ transport }) => {
553
+ const synth = new Synth();
554
+ transport.schedule(() => {
555
+ warns(() => {
556
+ synth.triggerAttackRelease("C2", 0.1);
557
+ });
558
+ }, 0);
559
+ transport.start(0);
560
+ }, 0.3).then(() => {
561
+ });
562
+ });
563
+
549
564
  });
550
565
 
551
566
  context("scheduleRepeat", () => {
@@ -2,15 +2,29 @@ import { TimeClass } from "../../core/type/Time";
2
2
  import { PlaybackState } from "../../core/util/StateTimeline";
3
3
  import { TimelineValue } from "../../core/util/TimelineValue";
4
4
  import { Signal } from "../../signal/Signal";
5
- import { onContextClose, onContextInit } from "../context/ContextInitialization";
5
+ import {
6
+ onContextClose,
7
+ onContextInit,
8
+ } from "../context/ContextInitialization";
6
9
  import { Gain } from "../context/Gain";
7
- import { ToneWithContext, ToneWithContextOptions } from "../context/ToneWithContext";
10
+ import {
11
+ ToneWithContext,
12
+ ToneWithContextOptions,
13
+ } from "../context/ToneWithContext";
8
14
  import { TicksClass } from "../type/Ticks";
9
15
  import { TransportTimeClass } from "../type/TransportTime";
10
16
  import {
11
- BarsBeatsSixteenths, BPM, NormalRange, Seconds,
12
- Subdivision, Ticks, Time, TimeSignature, TransportTime
17
+ BarsBeatsSixteenths,
18
+ BPM,
19
+ NormalRange,
20
+ Seconds,
21
+ Subdivision,
22
+ Ticks,
23
+ Time,
24
+ TimeSignature,
25
+ TransportTime,
13
26
  } from "../type/Units";
27
+ import { enterScheduledCallback } from "../util/Debug";
14
28
  import { optionsFromArguments } from "../util/Defaults";
15
29
  import { Emitter } from "../util/Emitter";
16
30
  import { readOnly, writable } from "../util/Interface";
@@ -32,7 +46,14 @@ interface TransportOptions extends ToneWithContextOptions {
32
46
  ppq: number;
33
47
  }
34
48
 
35
- type TransportEventNames = "start" | "stop" | "pause" | "loop" | "loopEnd" | "loopStart" | "ticks";
49
+ type TransportEventNames =
50
+ | "start"
51
+ | "stop"
52
+ | "pause"
53
+ | "loop"
54
+ | "loopEnd"
55
+ | "loopStart"
56
+ | "ticks";
36
57
 
37
58
  interface SyncedSignalEvent {
38
59
  signal: Signal;
@@ -64,8 +85,9 @@ type TransportCallback = (time: Seconds) => void;
64
85
  * Tone.Transport.start();
65
86
  * @category Core
66
87
  */
67
- export class Transport extends ToneWithContext<TransportOptions> implements Emitter<TransportEventNames> {
68
-
88
+ export class Transport
89
+ extends ToneWithContext<TransportOptions>
90
+ implements Emitter<TransportEventNames> {
69
91
  readonly name: string = "Transport";
70
92
 
71
93
  //-------------------------------------
@@ -163,9 +185,11 @@ export class Transport extends ToneWithContext<TransportOptions> implements Emit
163
185
 
164
186
  constructor(options?: Partial<TransportOptions>);
165
187
  constructor() {
166
-
167
188
  super(optionsFromArguments(Transport.getDefaults(), arguments));
168
- const options = optionsFromArguments(Transport.getDefaults(), arguments);
189
+ const options = optionsFromArguments(
190
+ Transport.getDefaults(),
191
+ arguments
192
+ );
169
193
 
170
194
  // CLOCK/TEMPO
171
195
  this._ppq = options.ppq;
@@ -213,21 +237,34 @@ export class Transport extends ToneWithContext<TransportOptions> implements Emit
213
237
  this.emit("loopEnd", tickTime);
214
238
  this._clock.setTicksAtTime(this._loopStart, tickTime);
215
239
  ticks = this._loopStart;
216
- this.emit("loopStart", tickTime, this._clock.getSecondsAtTime(tickTime));
240
+ this.emit(
241
+ "loopStart",
242
+ tickTime,
243
+ this._clock.getSecondsAtTime(tickTime)
244
+ );
217
245
  this.emit("loop", tickTime);
218
246
  }
219
247
  }
220
248
  // handle swing
221
- if (this._swingAmount > 0 &&
249
+ if (
250
+ this._swingAmount > 0 &&
222
251
  ticks % this._ppq !== 0 && // not on a downbeat
223
- ticks % (this._swingTicks * 2) !== 0) {
252
+ ticks % (this._swingTicks * 2) !== 0
253
+ ) {
224
254
  // add some swing
225
- const progress = (ticks % (this._swingTicks * 2)) / (this._swingTicks * 2);
226
- const amount = Math.sin((progress) * Math.PI) * this._swingAmount;
227
- tickTime += new TicksClass(this.context, this._swingTicks * 2 / 3).toSeconds() * amount;
255
+ const progress =
256
+ (ticks % (this._swingTicks * 2)) / (this._swingTicks * 2);
257
+ const amount = Math.sin(progress * Math.PI) * this._swingAmount;
258
+ tickTime +=
259
+ new TicksClass(
260
+ this.context,
261
+ (this._swingTicks * 2) / 3
262
+ ).toSeconds() * amount;
228
263
  }
229
264
  // invoke the timeline events scheduled on this tick
230
- this._timeline.forEachAtTime(ticks, event => event.invoke(tickTime));
265
+ enterScheduledCallback(true);
266
+ this._timeline.forEachAtTime(ticks, (event) => event.invoke(tickTime));
267
+ enterScheduledCallback(false);
231
268
  }
232
269
 
233
270
  //-------------------------------------
@@ -246,7 +283,10 @@ export class Transport extends ToneWithContext<TransportOptions> implements Emit
246
283
  * console.log("measure 16!");
247
284
  * }, "16:0:0");
248
285
  */
249
- schedule(callback: TransportCallback, time: TransportTime | TransportTimeClass): number {
286
+ schedule(
287
+ callback: TransportCallback,
288
+ time: TransportTime | TransportTimeClass
289
+ ): number {
250
290
  const event = new TransportEvent(this, {
251
291
  callback,
252
292
  time: new TransportTimeClass(this.context, time).toTicks(),
@@ -274,7 +314,7 @@ export class Transport extends ToneWithContext<TransportOptions> implements Emit
274
314
  callback: TransportCallback,
275
315
  interval: Time | TimeClass,
276
316
  startTime?: TransportTime | TransportTimeClass,
277
- duration: Time = Infinity,
317
+ duration: Time = Infinity
278
318
  ): number {
279
319
  const event = new TransportRepeatEvent(this, {
280
320
  callback,
@@ -293,7 +333,10 @@ export class Transport extends ToneWithContext<TransportOptions> implements Emit
293
333
  * @param time The time the callback should be invoked.
294
334
  * @returns The ID of the scheduled event.
295
335
  */
296
- scheduleOnce(callback: TransportCallback, time: TransportTime | TransportTimeClass): number {
336
+ scheduleOnce(
337
+ callback: TransportCallback,
338
+ time: TransportTime | TransportTimeClass
339
+ ): number {
297
340
  const event = new TransportEvent(this, {
298
341
  callback,
299
342
  once: true,
@@ -338,8 +381,12 @@ export class Transport extends ToneWithContext<TransportOptions> implements Emit
338
381
  */
339
382
  cancel(after: TransportTime = 0): this {
340
383
  const computedAfter = this.toTicks(after);
341
- this._timeline.forEachFrom(computedAfter, event => this.clear(event.id));
342
- this._repeatedEvents.forEachFrom(computedAfter, event => this.clear(event.id));
384
+ this._timeline.forEachFrom(computedAfter, (event) =>
385
+ this.clear(event.id)
386
+ );
387
+ this._repeatedEvents.forEachFrom(computedAfter, (event) =>
388
+ this.clear(event.id)
389
+ );
343
390
  return this;
344
391
  }
345
392
 
@@ -381,6 +428,8 @@ export class Transport extends ToneWithContext<TransportOptions> implements Emit
381
428
  * Tone.Transport.start("+1", "4:0:0");
382
429
  */
383
430
  start(time?: Time, offset?: TransportTime): this {
431
+ // start the context
432
+ this.context.resume();
384
433
  let offsetTicks;
385
434
  if (isDefined(offset)) {
386
435
  offsetTicks = this.toTicks(offset);
@@ -486,7 +535,10 @@ export class Transport extends ToneWithContext<TransportOptions> implements Emit
486
535
  * Tone.Transport.setLoopPoints(0, "1m");
487
536
  * Tone.Transport.loop = true;
488
537
  */
489
- setLoopPoints(startPosition: TransportTime, endPosition: TransportTime): this {
538
+ setLoopPoints(
539
+ startPosition: TransportTime,
540
+ endPosition: TransportTime
541
+ ): this {
490
542
  this.loopStart = startPosition;
491
543
  this.loopEnd = endPosition;
492
544
  return this;
@@ -550,7 +602,9 @@ export class Transport extends ToneWithContext<TransportOptions> implements Emit
550
602
  if (this.loop) {
551
603
  const now = this.now();
552
604
  const ticks = this._clock.getTicksAtTime(now);
553
- return (ticks - this._loopStart) / (this._loopEnd - this._loopStart);
605
+ return (
606
+ (ticks - this._loopStart) / (this._loopEnd - this._loopStart)
607
+ );
554
608
  } else {
555
609
  return 0;
556
610
  }
@@ -626,7 +680,7 @@ export class Transport extends ToneWithContext<TransportOptions> implements Emit
626
680
  * @return The context time of the next subdivision.
627
681
  * @example
628
682
  * // the transport must be started, otherwise returns 0
629
- * Tone.Transport.start();
683
+ * Tone.Transport.start();
630
684
  * Tone.Transport.nextSubdivision("4n");
631
685
  */
632
686
  nextSubdivision(subdivision?: Time): Seconds {
@@ -638,7 +692,7 @@ export class Transport extends ToneWithContext<TransportOptions> implements Emit
638
692
  const now = this.now();
639
693
  // the remainder of the current ticks and the subdivision
640
694
  const transportPos = this.getTicksAtTime(now);
641
- const remainingTicks = subdivision - transportPos % subdivision;
695
+ const remainingTicks = subdivision - (transportPos % subdivision);
642
696
  return this._clock.nextTickTime(remainingTicks, now);
643
697
  }
644
698
  }
@@ -710,9 +764,18 @@ export class Transport extends ToneWithContext<TransportOptions> implements Emit
710
764
  // EMITTER MIXIN TO SATISFY COMPILER
711
765
  //-------------------------------------
712
766
 
713
- on!: (event: TransportEventNames, callback: (...args: any[]) => void) => this;
714
- once!: (event: TransportEventNames, callback: (...args: any[]) => void) => this;
715
- off!: (event: TransportEventNames, callback?: ((...args: any[]) => void) | undefined) => this;
767
+ on!: (
768
+ event: TransportEventNames,
769
+ callback: (...args: any[]) => void
770
+ ) => this;
771
+ once!: (
772
+ event: TransportEventNames,
773
+ callback: (...args: any[]) => void
774
+ ) => this;
775
+ off!: (
776
+ event: TransportEventNames,
777
+ callback?: ((...args: any[]) => void) | undefined
778
+ ) => this;
716
779
  emit!: (event: any, ...args: any[]) => this;
717
780
  }
718
781
 
@@ -722,10 +785,10 @@ Emitter.mixin(Transport);
722
785
  // INITIALIZATION
723
786
  //-------------------------------------
724
787
 
725
- onContextInit(context => {
788
+ onContextInit((context) => {
726
789
  context.transport = new Transport({ context });
727
790
  });
728
791
 
729
- onContextClose(context => {
792
+ onContextClose((context) => {
730
793
  context.transport.dispose();
731
794
  });
@@ -4,6 +4,7 @@ import { FrequencyClass } from "../type/Frequency";
4
4
  import { TimeClass } from "../type/Time";
5
5
  import { TransportTimeClass } from "../type/TransportTime";
6
6
  import { Frequency, Hertz, Seconds, Ticks, Time } from "../type/Units";
7
+ import { assertUsedScheduleTime } from "../util/Debug";
7
8
  import { getDefaultsFromInstance, optionsFromArguments } from "../util/Defaults";
8
9
  import { RecursivePartial } from "../util/Interface";
9
10
  import { isArray, isBoolean, isDefined, isNumber, isString, isUndef } from "../util/TypeCheck";
@@ -104,6 +105,7 @@ export abstract class ToneWithContext<Options extends ToneWithContextOptions> ex
104
105
  * Tone.getTransport().bpm.rampTo(60, 30);
105
106
  */
106
107
  toSeconds(time?: Time): Seconds {
108
+ assertUsedScheduleTime(time);
107
109
  return new TimeClass(this.context, time).toSeconds();
108
110
  }
109
111
 
@@ -50,7 +50,7 @@ export class FrequencyClass<Type extends number = Hertz> extends TimeClass<Type,
50
50
  },
51
51
  },
52
52
  note: {
53
- regexp: /^([a-g]{1}(?:b|#|x|bb)?)(-?[0-9]+)/i,
53
+ regexp: /^([a-g]{1}(?:b|#|##|x|bb|###|#x|x#|bbb)?)(-?[0-9]+)/i,
54
54
  method(pitch, octave): number {
55
55
  const index = noteToScaleIndex[pitch.toLowerCase()];
56
56
  const noteNumber = index + (parseInt(octave, 10) + 1) * 12;
@@ -219,13 +219,13 @@ export class FrequencyClass<Type extends number = Hertz> extends TimeClass<Type,
219
219
  * @hidden
220
220
  */
221
221
  const noteToScaleIndex = {
222
- cbb: -2, cb: -1, c: 0, "c#": 1, cx: 2,
223
- dbb: 0, db: 1, d: 2, "d#": 3, dx: 4,
224
- ebb: 2, eb: 3, e: 4, "e#": 5, ex: 6,
225
- fbb: 3, fb: 4, f: 5, "f#": 6, fx: 7,
226
- gbb: 5, gb: 6, g: 7, "g#": 8, gx: 9,
227
- abb: 7, ab: 8, a: 9, "a#": 10, ax: 11,
228
- bbb: 9, bb: 10, b: 11, "b#": 12, bx: 13,
222
+ cbbb: -3, cbb: -2, cb: -1, c: 0, "c#": 1, cx: 2, "c##": 2, "c###": 3, "cx#": 3, "c#x": 3,
223
+ dbbb: -1, dbb: 0, db: 1, d: 2, "d#": 3, dx: 4, "d##": 4, "d###": 5, "dx#": 5, "d#x": 5,
224
+ ebbb: 1, ebb: 2, eb: 3, e: 4, "e#": 5, ex: 6, "e##": 6, "e###": 7, "ex#": 7, "e#x": 7,
225
+ fbbb: 2, fbb: 3, fb: 4, f: 5, "f#": 6, fx: 7, "f##": 7, "f###": 8, "fx#": 8, "f#x": 8,
226
+ gbbb: 4, gbb: 5, gb: 6, g: 7, "g#": 8, gx: 9, "g##": 9, "g###": 10, "gx#": 10, "g#x": 10,
227
+ abbb: 6, abb: 7, ab: 8, a: 9, "a#": 10, ax: 11, "a##": 11, "a###": 12, "ax#": 12, "a#x": 12,
228
+ bbbb: 8, bbb: 9, bb: 10, b: 11, "b#": 12, bx: 13, "b##": 13, "b###": 14, "bx#": 14, "b#x": 14,
229
229
  };
230
230
 
231
231
  /**
@@ -1,3 +1,5 @@
1
+ import { isUndef } from "./TypeCheck";
2
+
1
3
  /**
2
4
  * Assert that the statement is true, otherwise invoke the error.
3
5
  * @param statement
@@ -14,17 +16,48 @@ export function assert(statement: boolean, error: string): asserts statement {
14
16
  */
15
17
  export function assertRange(value: number, gte: number, lte = Infinity): void {
16
18
  if (!(gte <= value && value <= lte)) {
17
- throw new RangeError(`Value must be within [${gte}, ${lte}], got: ${value}`);
19
+ throw new RangeError(
20
+ `Value must be within [${gte}, ${lte}], got: ${value}`
21
+ );
18
22
  }
19
23
  }
20
24
 
21
25
  /**
22
- * Make sure that the given value is within the range
26
+ * Warn if the context is not running.
23
27
  */
24
- export function assertContextRunning(context: import("../context/BaseContext").BaseContext): void {
28
+ export function assertContextRunning(
29
+ context: import("../context/BaseContext").BaseContext
30
+ ): void {
25
31
  // add a warning if the context is not started
26
32
  if (!context.isOffline && context.state !== "running") {
27
- warn("The AudioContext is \"suspended\". Invoke Tone.start() from a user action to start the audio.");
33
+ warn(
34
+ "The AudioContext is \"suspended\". Invoke Tone.start() from a user action to start the audio."
35
+ );
36
+ }
37
+ }
38
+
39
+ /**
40
+ * If it is currently inside a scheduled callback
41
+ */
42
+ let isInsideScheduledCallback = false;
43
+ let printedScheduledWarning = false;
44
+
45
+ /**
46
+ * Notify that the following block of code is occurring inside a Transport callback.
47
+ */
48
+ export function enterScheduledCallback(insideCallback: boolean): void {
49
+ isInsideScheduledCallback = insideCallback;
50
+ }
51
+
52
+ /**
53
+ * Make sure that a time was passed into
54
+ */
55
+ export function assertUsedScheduleTime(
56
+ time?: import("../type/Units").Time
57
+ ): void {
58
+ if (isUndef(time) && isInsideScheduledCallback && !printedScheduledWarning) {
59
+ printedScheduledWarning = true;
60
+ warn("Events scheduled inside of scheduled callbacks should use the passed in scheduling time. See https://github.com/Tonejs/Tone.js/wiki/Accurate-Timing");
28
61
  }
29
62
  }
30
63
 
@@ -13,7 +13,7 @@ export interface StateTimelineEvent extends TimelineEvent {
13
13
  * A Timeline State. Provides the methods: `setStateAtTime("state", time)` and `getValueAtTime(time)`
14
14
  * @param initial The initial state of the StateTimeline. Defaults to `undefined`
15
15
  */
16
- export class StateTimeline<AdditionalOptions extends {} = {}> extends Timeline<StateTimelineEvent & AdditionalOptions> {
16
+ export class StateTimeline<AdditionalOptions extends Record<string, any> = Record<string, any>> extends Timeline<StateTimelineEvent & AdditionalOptions> {
17
17
 
18
18
  readonly name: string = "StateTimeline";
19
19
 
@@ -64,7 +64,7 @@ export class AutoFilter extends LFOEffect<AutoFilterOptions> {
64
64
  baseFrequency: 200,
65
65
  octaves: 2.6,
66
66
  filter: {
67
- type: "lowpass" as "lowpass",
67
+ type: "lowpass" as const,
68
68
  rolloff: -12 as -12,
69
69
  Q: 1,
70
70
  }
@@ -61,7 +61,7 @@ export class Chebyshev extends Effect<ChebyshevOptions> {
61
61
  static getDefaults(): ChebyshevOptions {
62
62
  return Object.assign(Effect.getDefaults(), {
63
63
  order: 1,
64
- oversample: "none" as "none"
64
+ oversample: "none" as const
65
65
  });
66
66
  }
67
67
 
@@ -7,25 +7,29 @@ import { Oscillator } from "Tone/source";
7
7
  import { Offline } from "test/helper/Offline";
8
8
 
9
9
  describe("Chorus", () => {
10
-
11
10
  BasicTests(Chorus);
12
11
  EffectTests(Chorus);
13
12
 
14
13
  it("matches a file", () => {
15
- return CompareToFile(() => {
16
- const chorus = new Chorus().toDestination().start();
17
- const osc = new Oscillator(220, "sawtooth").connect(chorus).start();
18
- }, "chorus.wav", 0.1);
14
+ return CompareToFile(
15
+ () => {
16
+ const chorus = new Chorus().toDestination().start();
17
+ const osc = new Oscillator(220, "sawtooth")
18
+ .connect(chorus)
19
+ .start();
20
+ },
21
+ "chorus.wav",
22
+ 0.25
23
+ );
19
24
  });
20
25
 
21
26
  context("API", () => {
22
-
23
27
  it("can pass in options in the constructor", () => {
24
28
  const chorus = new Chorus({
25
29
  frequency: 2,
26
30
  delayTime: 1,
27
31
  depth: 0.4,
28
- spread: 90
32
+ spread: 90,
29
33
  });
30
34
  expect(chorus.frequency.value).to.be.closeTo(2, 0.01);
31
35
  expect(chorus.delayTime).to.be.closeTo(1, 0.01);
@@ -84,4 +88,3 @@ describe("Chorus", () => {
84
88
  });
85
89
  });
86
90
  });
87
-
@@ -118,7 +118,7 @@ export class Chorus extends StereoFeedbackEffect<ChorusOptions> {
118
118
  frequency: 1.5,
119
119
  delayTime: 3.5,
120
120
  depth: 0.7,
121
- type: "sine" as "sine",
121
+ type: "sine" as const,
122
122
  spread: 180,
123
123
  feedback: 0,
124
124
  wet: 0.5,
@@ -68,14 +68,14 @@ export abstract class MidSideEffect<Options extends MidSideEffectOptions> extend
68
68
  /**
69
69
  * Connect the mid chain of the effect
70
70
  */
71
- protected connectEffectMid(...nodes: OutputNode[]): void{
71
+ protected connectEffectMid(...nodes: OutputNode[]): void {
72
72
  this._midSend.chain(...nodes, this._midReturn);
73
73
  }
74
74
 
75
75
  /**
76
76
  * Connect the side chain of the effect
77
77
  */
78
- protected connectEffectSide(...nodes: OutputNode[]): void{
78
+ protected connectEffectSide(...nodes: OutputNode[]): void {
79
79
  this._sideSend.chain(...nodes, this._sideReturn);
80
80
  }
81
81
 
@@ -68,7 +68,7 @@ export class StereoEffect<Options extends StereoEffectOptions> extends ToneAudio
68
68
  /**
69
69
  * Connect the left part of the effect
70
70
  */
71
- protected connectEffectLeft(...nodes: OutputNode[]): void{
71
+ protected connectEffectLeft(...nodes: OutputNode[]): void {
72
72
  this._split.connect(nodes[0], 0, 0);
73
73
  connectSeries(...nodes);
74
74
  connect(nodes[nodes.length-1], this._merge, 0, 0);
@@ -77,7 +77,7 @@ export class StereoEffect<Options extends StereoEffectOptions> extends ToneAudio
77
77
  /**
78
78
  * Connect the right part of the effect
79
79
  */
80
- protected connectEffectRight(...nodes: OutputNode[]): void{
80
+ protected connectEffectRight(...nodes: OutputNode[]): void {
81
81
  this._split.connect(nodes[0], 1, 0);
82
82
  connectSeries(...nodes);
83
83
  connect(nodes[nodes.length-1], this._merge, 0, 1);
@@ -111,7 +111,7 @@ export class Tremolo extends StereoEffect<TremoloOptions> {
111
111
  static getDefaults(): TremoloOptions {
112
112
  return Object.assign(StereoEffect.getDefaults(), {
113
113
  frequency: 10,
114
- type: "sine" as "sine",
114
+ type: "sine" as const,
115
115
  depth: 0.5,
116
116
  spread: 180,
117
117
  });
@@ -79,7 +79,7 @@ export class Vibrato extends Effect<VibratoOptions> {
79
79
  maxDelay: 0.005,
80
80
  frequency: 5,
81
81
  depth: 0.1,
82
- type: "sine" as "sine"
82
+ type: "sine" as const
83
83
  });
84
84
  }
85
85
 
@@ -73,7 +73,7 @@ export class Pattern<ValueType> extends Loop<PatternOptions<ValueType>> {
73
73
 
74
74
  static getDefaults(): PatternOptions<any> {
75
75
  return Object.assign(Loop.getDefaults(), {
76
- pattern: "up" as "up",
76
+ pattern: "up" as const,
77
77
  values: [],
78
78
  callback: noOp,
79
79
  });
@@ -83,6 +83,10 @@ export abstract class Instrument<Options extends InstrumentOptions> extends Tone
83
83
  if (this._syncState()) {
84
84
  this._syncMethod("triggerAttack", 1);
85
85
  this._syncMethod("triggerRelease", 0);
86
+
87
+ this.context.transport.on("stop", this._syncedRelease);
88
+ this.context.transport.on("pause", this._syncedRelease);
89
+ this.context.transport.on("loopEnd", this._syncedRelease);
86
90
  }
87
91
  return this;
88
92
  }
@@ -126,6 +130,10 @@ export abstract class Instrument<Options extends InstrumentOptions> extends Tone
126
130
  this._synced = false;
127
131
  this.triggerAttack = this._original_triggerAttack;
128
132
  this.triggerRelease = this._original_triggerRelease;
133
+
134
+ this.context.transport.off("stop", this._syncedRelease);
135
+ this.context.transport.off("pause", this._syncedRelease);
136
+ this.context.transport.off("loopEnd", this._syncedRelease);
129
137
  }
130
138
  return this;
131
139
  }
@@ -166,6 +174,11 @@ export abstract class Instrument<Options extends InstrumentOptions> extends Tone
166
174
  abstract triggerRelease(...args: any[]): this;
167
175
  private _original_triggerRelease = this.triggerRelease;
168
176
 
177
+ /**
178
+ * The release which is scheduled to the timeline.
179
+ */
180
+ protected _syncedRelease = (time: number) => this._original_triggerRelease(time);
181
+
169
182
  /**
170
183
  * clean up
171
184
  * @returns {Instrument} this